diff --git a/modules/billing/admin_config.php b/modules/billing/admin_config.php
index b57ae4ec..d143a368 100644
--- a/modules/billing/admin_config.php
+++ b/modules/billing/admin_config.php
@@ -626,15 +626,16 @@ rsort($bakFiles); // newest first
// Gather diagnostics data
$diag_mode = $cfgVals['paypal_mode'] ?? 'sandbox';
$diag_is_sandbox = $diag_mode !== 'live';
- $diag_sb_id_set = $cfgVals['paypal_sandbox_client_id'] !== '';
- $diag_sb_sec_set = $cfgVals['paypal_sandbox_client_secret'] !== '';
- $diag_sb_wh_set = $cfgVals['paypal_sandbox_webhook_id'] !== '';
- $diag_lv_id_set = $cfgVals['paypal_live_client_id'] !== '';
- $diag_lv_sec_set = $cfgVals['paypal_live_client_secret'] !== '';
- $diag_lv_wh_set = $cfgVals['paypal_live_webhook_id'] !== '';
- $diag_wh_path = $cfgVals['paypal_webhook_path'] ?? '/paypal/webhook.php';
+ $diag_sb_id_set = ($cfgVals['paypal_sandbox_client_id'] ?? '') !== '';
+ $diag_sb_sec_set = ($cfgVals['paypal_sandbox_client_secret'] ?? '') !== '';
+ $diag_sb_wh_set = ($cfgVals['paypal_sandbox_webhook_id'] ?? '') !== '';
+ $diag_lv_id_set = ($cfgVals['paypal_live_client_id'] ?? '') !== '';
+ $diag_lv_sec_set = ($cfgVals['paypal_live_client_secret'] ?? '') !== '';
+ $diag_lv_wh_set = ($cfgVals['paypal_live_webhook_id'] ?? '') !== '';
+ $diag_wh_path = '/' . ltrim((string)($cfgVals['paypal_webhook_path'] ?? '/paypal/webhook.php'), '/');
$diag_wh_full_url = $computedWebhookUrl;
- $diag_wh_file = __DIR__ . ltrim($diag_wh_path, '/');
+ // Correct disk path: billing module root + separator + webhook path (no leading slash)
+ $diag_wh_file = rtrim(__DIR__, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . ltrim($diag_wh_path, '/\\');
$diag_wh_exists = file_exists($diag_wh_file);
// Active mode credential check
@@ -645,65 +646,214 @@ rsort($bakFiles); // newest first
function diag_badge(bool $ok, string $yes = 'Yes', string $no = 'No'): string {
$cls = $ok ? 'background:#d4edda;color:#155724;border:1px solid #c3e6cb;' : 'background:#f8d7da;color:#721c24;border:1px solid #f5c6cb;';
$label = $ok ? $yes : $no;
- return '' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '';
+ return '' . htmlspecialchars($label, ENT_QUOTES, 'UTF-8') . '';
}
- // Last webhook events
+ // Last webhook events + recent PayPal errors
$diag_recent_events = [];
+ $diag_recent_errors = [];
+ $diag_errors_warning = '';
try {
$port_int = intval($db_port ?? 3306) ?: 3306;
$diag_db = @mysqli_connect($db_host ?? 'localhost', $db_user ?? '', $db_pass ?? '', $db_name ?? '', $port_int);
if ($diag_db) {
$pfx_diag = $table_prefix ?? 'gsp_';
+ mysqli_set_charset($diag_db, 'utf8mb4');
+
$res = @mysqli_query($diag_db, "SELECT paypal_event_id, event_type, processing_status, created_at FROM `{$pfx_diag}billing_paypal_webhook_events` ORDER BY id DESC LIMIT 5");
if ($res) {
while ($row = mysqli_fetch_assoc($res)) {
$diag_recent_events[] = $row;
}
}
+
+ // Recent PayPal errors — use BillingRepository for safe table creation
+ require_once __DIR__ . '/classes/BillingRepository.php';
+ $diag_repo = new BillingRepository($diag_db, $pfx_diag);
+ if ($diag_repo->ensureBillingPaypalErrorsTable()) {
+ $diag_recent_errors = $diag_repo->getRecentPaypalErrors(10);
+ } else {
+ $diag_errors_warning = 'Could not create billing_paypal_errors table. Check DB permissions.';
+ }
+
mysqli_close($diag_db);
}
} catch (Throwable $e) {
- // non-fatal
+ $diag_errors_warning = 'Diagnostics DB query failed: ' . htmlspecialchars($e->getMessage(), ENT_QUOTES, 'UTF-8');
}
?>
+
PayPal Diagnostics
-
- | Current mode | |
- | Active Client ID configured | |
- | Active Client Secret configured | |
- | Active Webhook ID configured | |
- | Sandbox credentials | ID: Secret: Webhook ID: |
- | Live credentials | ID: Secret: Webhook ID: |
- | Webhook path | |
- | Full public webhook URL | |
- | Webhook file exists on disk | |
-
+
+
+
+
+
+ Self-Check Results:
+ • Mode:
+ • Active Client ID:
+ • Active Client Secret:
+ • Active Webhook ID:
+ • Webhook file: —
+ • Logs directory:
+ • Data directory:
+ • Config file:
+
+
+
+
+
+
Current mode
+
+
+
+ test
+
+ live
+
+
+
+
+
+
+
+
+
Active Client Secret
+
+
+
+
+
+
+
+
+
Sandbox Client Secret
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Full public webhook URL
+
+
+
+
+
+
Webhook file on disk
+
+
+
-
Recent Webhook Events
-
-
- | PayPal Event ID |
- Type |
- Status |
- Received |
+ Recent Webhook Events
+
+
+
+ | PayPal Event ID |
+ Type |
+ Status |
+ Received |
-
- |
- |
- |
- |
+
+ |
+ |
+ |
+ |
-
+
+
No webhook events recorded yet. Events will appear here after PayPal delivers the first webhook to .
+
+ Recent PayPal Errors
+
+
+
+ No PayPal errors logged yet.
+
+
+
+
+ | Time | Context | Error Code | Message |
+ Debug ID | Order ID | User |
+
+
+
+
+ |
+ |
+ |
+ |
+ |
+ |
+ |
+
+
+
+
+
+