isAdmin($user_id); if (!$isAdmin) { echo "

Access Denied: Admin privileges required.

"; return; } // ------------------------------------------------------------------- // Handle "Retry Provisioning" for a single order // ------------------------------------------------------------------- if (isset($_POST['retry_provision_order']) && !empty($_POST['retry_order_id'])) { $retry_id = intval($_POST['retry_order_id']); require_once __DIR__ . '/create_servers.php'; $retryResult = billing_invoke_provision([ 'order_ids' => [$retry_id], 'user_id' => $user_id, 'is_admin' => true, ]); if (!empty($retryResult['provisioned_count'])) { echo "

Retry provisioning succeeded for order #{$retry_id}.

"; } elseif (!empty($retryResult['output'])) { echo "

Retry provisioning for order #{$retry_id} did not succeed. See details below.

" . "
" . htmlspecialchars($retryResult['output']) . "
"; } else { echo "

Retry provisioning for order #{$retry_id}: no result returned. Check server logs.

"; } } // Handle bulk actions if (isset($_POST['bulk_action']) && isset($_POST['selected_orders'])) { $action = $_POST['bulk_action']; $selected = $_POST['selected_orders']; foreach ((array)$selected as $order_id) { $order_id = $db->realEscapeSingle($order_id); switch ($action) { case 'provision': // Redirect to provision page for each order header("Location: home.php?m=billing&p=provision_servers&order_id=".$order_id); exit; break; case 'expire': $db->query("UPDATE `{$db_prefix}billing_orders` SET status='Expired' WHERE order_id=".$order_id); break; case 'activate': $db->query("UPDATE `{$db_prefix}billing_orders` SET status='Active' WHERE order_id=".$order_id); break; case 'invoice': $db->query("UPDATE `{$db_prefix}billing_orders` SET status='Invoiced' WHERE order_id=".$order_id); break; } } echo "

Bulk action completed for ".count((array)$selected)." order(s).

"; } // Get filter parameters $status_filter = isset($_GET['status']) ? $_GET['status'] : 'all'; $search = isset($_GET['search']) ? $_GET['search'] : ''; echo "

Manage All Orders (Admin)

"; // Filter form echo "
"; echo ""; echo ""; echo "Status: "; echo "Search: "; echo ""; echo "
"; // Build query $query = "SELECT o.*, s.service_name, u.users_login, u.users_email FROM `{$db_prefix}billing_orders` o LEFT JOIN `{$db_prefix}billing_services` s ON o.service_id = s.service_id LEFT JOIN `{$db_prefix}users` u ON o.user_id = u.user_id WHERE 1=1"; if ($status_filter != 'all') { $query .= " AND o.status = '".$db->realEscapeSingle($status_filter)."'"; } if (!empty($search)) { $search_escaped = $db->realEscapeSingle($search); $query .= " AND (o.order_id LIKE '%".$search_escaped."%' OR o.home_name LIKE '%".$search_escaped."%' OR u.users_login LIKE '%".$search_escaped."%' OR u.users_email LIKE '%".$search_escaped."%')"; } $query .= " ORDER BY o.order_date DESC"; $orders = $db->resultQuery($query); if (empty($orders)) { echo "

No orders found matching your filters.

"; return; } // Pre-fetch provisioning error counts per order for display $errorCounts = []; $errCountRows = $db->resultQuery( "SELECT billing_order_id, COUNT(*) AS cnt FROM `{$db_prefix}billing_provisioning_errors` GROUP BY billing_order_id" ); foreach ((array)$errCountRows as $ecr) { $errorCounts[intval($ecr['billing_order_id'])] = intval($ecr['cnt']); } echo "
"; echo "
"; echo "With selected: "; echo " "; echo ""; echo "
"; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; foreach ((array)$orders as $order) { $status_class = ''; switch ($order['status']) { case 'Active': $status_class = 'label-success'; break; case 'Invoiced': $status_class = 'label-warning'; break; case 'Expired': $status_class = 'label-danger'; break; default: $status_class = 'label-info'; } $oid = intval($order['order_id']); $errCount = $errorCounts[$oid] ?? 0; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; // Collapsible provisioning error rows if ($errCount > 0) { echo ""; echo ""; } } echo "
Order IDUsernameServer NameGame ServicePlayersPriceDurationStatusOrder DateEnd DateHome IDActions
".$oid."".htmlspecialchars($order['users_login'] ?? '')."
".htmlspecialchars($order['users_email'] ?? '')."
".htmlspecialchars($order['home_name'] ?? '')."".htmlspecialchars($order['service_name'] ?? '')."".$order['max_players']."$".number_format($order['price'], 2)."".$order['qty']." ".$order['invoice_duration']."(s)".$order['status'].""; if ($errCount > 0) { echo " " . $errCount . " error(s)"; } echo "".date('Y-m-d H:i', strtotime($order['order_date']))."".($order['end_date'] ? date('Y-m-d', strtotime($order['end_date'])) : 'N/A')."".($order['home_id'] ? $order['home_id'] : 'N/A').""; if ($order['status'] == 'Active' && !$order['home_id']) { echo "Provision "; // Retry provisioning button (inline POST form) echo ""; echo ""; echo ""; echo ""; echo " "; } if ($order['status'] == 'Active' && $order['home_id']) { echo "View Server "; } if ($errCount > 0) { echo "Errors "; } echo "Details"; echo "
"; echo ""; // JavaScript for checkbox toggle and error panel echo ""; // Summary stats $stats = $db->resultQuery( "SELECT status, COUNT(*) as count, SUM(price) as total FROM `{$db_prefix}billing_orders` GROUP BY status" ); echo "
"; echo "

Order Statistics

"; echo ""; echo ""; foreach ((array)$stats as $stat) { echo ""; echo ""; echo ""; echo ""; echo ""; } echo "
StatusCountTotal Value
".$stat['status']."".$stat['count']."$".number_format($stat['total'], 2)."
"; echo "
"; // Orphaned home_id diagnostics ————————————————————————————————————————— // Find billing_orders rows where home_id != 0 but no matching gsp_server_homes // record exists. These indicate provisioning failures or stale data, and they // are the reason the game monitor may show "No expiration date found". $orphans = $db->resultQuery( "SELECT o.order_id, o.user_id, o.home_name, o.home_id, o.status, o.end_date FROM `{$db_prefix}billing_orders` o LEFT JOIN `{$db_prefix}server_homes` sh ON sh.home_id = o.home_id WHERE o.home_id != '0' AND o.home_id != '' AND sh.home_id IS NULL ORDER BY o.order_id ASC" ); echo "
"; echo "

Orphaned home_id Diagnostics

"; echo "

Billing orders that reference a home_id which no longer exists in server_homes. "; echo "These orders will not show an expiration date on the game monitor. "; echo "Reset home_id to 0 and use the Retry Provisioning button to re-provision them. "; echo "Run normalize_billing_order_status.sql to standardize any legacy status values.

"; if (empty($orphans)) { echo "

✓ No orphaned billing orders found.

"; } else { echo ""; echo ""; foreach ($orphans as $row) { echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; } echo "
Order IDUser IDServer Namehome_id (missing)StatusEnd Date
".intval($row['order_id'])."".intval($row['user_id'])."".htmlspecialchars($row['home_name'] ?? '')."".htmlspecialchars($row['home_id'] ?? '')."".htmlspecialchars($row['status'] ?? '')."".htmlspecialchars($row['end_date'] ?? 'NULL')."
"; } echo "
"; // Recent provisioning errors (all orders) ———————————————————————————— $recentErrors = $db->resultQuery( "SELECT e.*, o.home_name, u.users_login FROM `{$db_prefix}billing_provisioning_errors` e LEFT JOIN `{$db_prefix}billing_orders` o ON o.order_id = e.billing_order_id LEFT JOIN `{$db_prefix}users` u ON u.user_id = e.user_id ORDER BY e.created_at DESC LIMIT 50" ); echo "
"; echo "

Recent Provisioning Errors

"; if (empty($recentErrors)) { echo "

✓ No provisioning errors recorded.

"; } else { echo ""; echo ""; foreach ($recentErrors as $er) { echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; } echo "
TimeOrder IDUserServer NameRemote SrvIP IDPortModMessage
".htmlspecialchars($er['created_at'])."".intval($er['billing_order_id'])."".htmlspecialchars($er['users_login'] ?? ('uid:'.intval($er['user_id'])))."".htmlspecialchars($er['home_name'] ?? '')."".intval($er['remote_server_id'])."".intval($er['ip_id'])."".intval($er['attempted_port'])."".intval($er['mod_cfg_id'])."".htmlspecialchars($er['failure_message'])."
"; } echo "
"; } ?>