diff --git a/modules/billing/admin.php b/modules/billing/admin.php index 0dadc653..b08e4690 100644 --- a/modules/billing/admin.php +++ b/modules/billing/admin.php @@ -21,7 +21,7 @@ function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }

Admin Dashboard

Welcome to the admin area. From here you can manage servers, payments, and site settings.

-
+
Manage Servers & Services Invoice History Edit Site Config diff --git a/modules/billing/cart.php b/modules/billing/cart.php index 893e9523..a4798f0b 100644 --- a/modules/billing/cart.php +++ b/modules/billing/cart.php @@ -58,7 +58,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['create_free_for'])) $orderId = (int)$_POST['create_free_for']; if ($orderId > 0) { // load order to verify ownership/price - $stmt = $db->prepare("SELECT user_id, price, status, qty, invoice_duration FROM ogp_billing_orders WHERE order_id = ? LIMIT 1"); + $stmt = $db->prepare("SELECT user_id, price, status, qty, invoice_duration FROM " . $table_prefix . "billing_orders WHERE order_id = ? LIMIT 1"); if ($stmt) { $stmt->bind_param('i', $orderId); $stmt->execute(); @@ -106,15 +106,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['create_free_for'])) $finish_date = date('Y-m-d H:i:s'); } - // Check if finish_date column exists - $finish_col_exists = false; - $col_check = mysqli_query($db, "SHOW COLUMNS FROM ogp_billing_orders LIKE 'finish_date'"); - if ($col_check && mysqli_num_rows($col_check) > 0) $finish_col_exists = true; + // Check if finish_date column exists (use table prefix) + $finish_col_exists = false; + $col_check = mysqli_query($db, "SHOW COLUMNS FROM " . $table_prefix . "billing_orders LIKE 'finish_date'"); + if ($col_check && mysqli_num_rows($col_check) > 0) $finish_col_exists = true; // Perform update and log results. Use prepared statements when available and fallback to direct query on error. $updated_rows = 0; if ($finish_col_exists) { - $upd = $db->prepare("UPDATE ogp_billing_orders SET status = 'paid', finish_date = ? WHERE order_id = ? LIMIT 1"); + $upd = $db->prepare("UPDATE " . $table_prefix . "billing_orders SET status = 'paid', finish_date = ? WHERE order_id = ? LIMIT 1"); if ($upd) { $upd->bind_param('si', $finish_date, $orderId); $ok = $upd->execute(); @@ -124,13 +124,13 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['create_free_for'])) } else { // fallback $safe_fd = mysqli_real_escape_string($db, $finish_date); - $q = "UPDATE ogp_billing_orders SET status = 'paid', finish_date = '$safe_fd' WHERE order_id = " . intval($orderId) . " LIMIT 1"; + $q = "UPDATE " . $table_prefix . "billing_orders SET status = 'paid', finish_date = '$safe_fd' WHERE order_id = " . intval($orderId) . " LIMIT 1"; $resq = mysqli_query($db, $q); if (!$resq) site_log_warn('free_create_update_failed_query', ['error'=>mysqli_error($db), 'sql'=>$q]); else $updated_rows = mysqli_affected_rows($db); } } else { - $upd = $db->prepare("UPDATE ogp_billing_orders SET status = 'paid' WHERE order_id = ? LIMIT 1"); + $upd = $db->prepare("UPDATE " . $table_prefix . "billing_orders SET status = 'paid' WHERE order_id = ? LIMIT 1"); if ($upd) { $upd->bind_param('i', $orderId); $ok = $upd->execute(); @@ -138,7 +138,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && !empty($_POST['create_free_for'])) $updated_rows = $upd->affected_rows; $upd->close(); } else { - $q = "UPDATE ogp_billing_orders SET status = 'paid' WHERE order_id = " . intval($orderId) . " LIMIT 1"; + $q = "UPDATE " . $table_prefix . "billing_orders SET status = 'paid' WHERE order_id = " . intval($orderId) . " LIMIT 1"; $resq = mysqli_query($db, $q); if (!$resq) site_log_warn('free_create_update_failed_query', ['error'=>mysqli_error($db), 'sql'=>$q]); else $updated_rows = mysqli_affected_rows($db); @@ -248,20 +248,28 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_single'])) { $stmt->bind_param("ii", $order_id, $user_id); $stmt->execute(); $stmt->bind_result($status); - if ($stmt->fetch() && strtolower($status) === 'renew') { - $stmt->close(); - // Set status to 'expired' if currently 'renew' - $update = $db->prepare("UPDATE ogp_billing_orders SET status = 'expired' WHERE order_id = ? AND user_id = ?"); - $update->bind_param("ii", $order_id, $user_id); - $update->execute(); - $update->close(); + if ($stmt->fetch() && strtolower($status) === 'renew') { + $stmt->close(); + // If user removes a renewal from their cart, revert the order back to 'installed' + $update = $db->prepare("UPDATE ogp_billing_orders SET status = 'installed' WHERE order_id = ? AND user_id = ?"); + $update->bind_param("ii", $order_id, $user_id); + $update->execute(); + // Log revert action to panel logger + if (isset($db) && method_exists($db, 'logger')) { + $db->logger("USER-CART: User " . intval($user_id) . " reverted renew for order " . intval($order_id)); + } + $update->close(); } else { $stmt->close(); // Otherwise, delete the order $delete = $db->prepare("DELETE FROM ogp_billing_orders WHERE order_id = ? AND user_id = ?"); $delete->bind_param("ii", $order_id, $user_id); - $delete->execute(); - $delete->close(); + $delete->execute(); + // Log deletion to panel logger + if (isset($db) && method_exists($db, 'logger')) { + $db->logger("USER-CART: User " . intval($user_id) . " deleted order " . intval($order_id)); + } + $delete->close(); } } } @@ -318,6 +326,15 @@ if ($db){ $ + isset($row['home_id']) ? (string)$row['home_id'] : ('order'.$row['order_id']), + 'amount' => number_format($rowtotal, 2, '.', ''), + 'order_id' => intval($row['order_id']) + ]; + ?> -
Admin: force-create a paid record for testing.
+
Admin: force-create a paid record for testing.
@@ -401,6 +418,11 @@ $invoiceId = 'INV-' . date('Ymd-His') . '-' . bin2hex(random_bytes(3)); // A short custom reference derived from your line items (<= 127 chars for PayPal) $customHash = substr(strtoupper(sha1(json_encode($invoice))), 0, 16); $customId = "INVREF-$customHash"; +// If the cart contains a single order, set custom_id to the numeric order id so webhooks +// can match the order directly (payment_success matches numeric custom -> order_id). +if (is_array($invoice) && count($invoice) === 1 && !empty($invoice[0]['order_id'])) { + $customId = (string) intval($invoice[0]['order_id']); +} // Text on the PayPal side $description = 'Game server order (' . count($lineItems) . ' item' . (count($lineItems)===1?'': 's') . ')'; diff --git a/modules/billing/cron-shop.php b/modules/billing/cron-shop.php index c26d981d..b9103ac2 100644 --- a/modules/billing/cron-shop.php +++ b/modules/billing/cron-shop.php @@ -20,6 +20,19 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * + * + +Complete Status Flow: +in-cart - User added to cart, not yet paid +renew - Renewal order in cart +paid - Payment received, awaiting server creation +installed - ✅ Active/Running (server provisioned and operational) +invoiced - Invoice generated, payment due (7 days before expiration) +suspended - Server stopped, payment overdue +deleted - Server permanently removed (7 days after suspension) +expired - Order has expired +unknown - Error/undefined state */ chdir(realpath(dirname(__FILE__))); /* Change to the current file path */ @@ -68,7 +81,16 @@ else foreach($user_homes as $user_home) { - $user_id = $user_home['user_id']; + // Developer note: + // In future we may want to change the renewal/invoice strategy so that a + // new order record is created for the renewal (leaving the original order + // intact) instead of mutating the existing order's status/finish_date. + // Creating a separate renewal order gives a clearer, immutable purchase + // history and simplifies auditing. For now this cron job continues to + // update the existing order (change status/finish_date) as implemented + // below. + + $user_id = $user_home['user_id']; $home_id = $user_home['home_id']; diff --git a/modules/billing/css/header.css b/modules/billing/css/header.css index af64f4df..610e7418 100644 --- a/modules/billing/css/header.css +++ b/modules/billing/css/header.css @@ -90,6 +90,21 @@ input, textarea, select, button { color: #fff; background: #11141f; border: 1px #gsw-site a.gsw-btn:hover, #gsw-site button.gsw-btn:hover{transform:translateY(-2px);color:#fff !important;text-decoration:none;} +/* Renew button: slightly smaller but matching gradient, used on My Account cards */ +#gsw-site .renew-btn, #gsw-site a.renew-btn, #gsw-site button.renew-btn{ + display:inline-block; + padding:8px 14px; + background:linear-gradient(135deg,#f59e0b 0%,#ef4444 100%) !important; + color:#fff !important; + text-decoration:none; + border-radius:8px; + font-weight:700; + transition:transform 0.12s; + border:none; + cursor:pointer; +} +#gsw-site .renew-btn:hover, #gsw-site a.renew-btn:hover, #gsw-site button.renew-btn:hover{transform:translateY(-2px);} + #gsw-site .gsw-btn-secondary, #gsw-site a.gsw-btn-secondary{display:inline-block;padding:10px 16px;background:rgba(255,255,255,0.06);color:#fff !important;text-decoration:none;border-radius:8px;border:1px solid rgba(255,255,255,0.06);cursor:pointer;} #gsw-site .gsw-btn-secondary:hover, @@ -152,3 +167,135 @@ input, textarea, select, button { color: #fff; background: #11141f; border: 1px .ml-8{margin-left:8px} .flex-row-gap{display:flex;gap:8px;align-items:center} +/* Account page styles */ +.account-container{max-width:1000px;margin:20px auto;padding:20px} +.account-section{background:rgba(0,0,0,0.25);padding:20px;border-radius:8px;margin-bottom:20px} +.account-section h2{margin:0 0 15px 0;font-size:1.3rem;color:#fff;border-bottom:2px solid rgba(255,255,255,0.1);padding-bottom:10px} +.account-info-grid{display:grid;grid-template-columns:1fr 1fr;gap:15px;margin-bottom:15px} +.account-info-item{padding:10px;background:rgba(255,255,255,0.03);border-radius:6px} +.account-info-label{font-weight:600;color:rgba(255,255,255,0.7);font-size:0.9rem;margin-bottom:5px} +.account-info-value{color:#fff;font-size:1rem} +.account-edit-summary{cursor:pointer;color:#667eea;font-weight:600;margin-top:10px} + +/* Form styles */ +.form-group{margin-bottom:15px} +.form-group label{display:block;margin-bottom:5px;color:#fff;font-weight:500} +.form-group input{width:100%;padding:10px;border:1px solid rgba(255,255,255,0.1);border-radius:6px;background:rgba(0,0,0,0.3);color:#fff} + +/* Alert messages */ +.alert{padding:12px 16px;border-radius:8px;margin-bottom:20px;font-size:0.95rem} +.alert-error{background-color:rgba(255,0,0,0.2);border:1px solid rgba(255,0,0,0.3);color:#ffcccc} +.alert-success{background-color:rgba(0,255,0,0.2);border:1px solid rgba(0,255,0,0.3);color:#ccffcc} + +/* Server item cards */ +.server-item{background:rgba(255,255,255,0.03);padding:15px;border-radius:6px;margin-bottom:10px;border-left:3px solid #667eea} +.server-name{font-size:1.1rem;font-weight:600;color:#fff;margin-bottom:8px} +.server-details{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:10px;margin-top:10px} +.server-detail{font-size:0.9rem} +.server-detail-label{color:rgba(255,255,255,0.6)} +.server-detail-value{color:#fff;font-weight:500} + +/* Invoice items */ +.invoice-item{background:rgba(255,255,255,0.03);padding:12px 15px;border-radius:6px;margin-bottom:8px;display:flex;justify-content:space-between;align-items:center} +.invoice-id{font-weight:600;color:#fff} +.invoice-amount{color:#10b981;font-weight:600} +.invoice-status{padding:4px 10px;border-radius:4px;font-size:0.85rem;font-weight:600} +.invoice-status-paid{background:rgba(16,185,129,0.2);color:#10b981} +.invoice-status-pending{background:rgba(245,158,11,0.2);color:#f59e0b} +.invoice-date{color:rgba(255,255,255,0.6);font-size:0.9rem} + +/* Login placeholder for non-logged-in users */ +.login-placeholder{padding:12px;background:rgba(255,255,255,0.03);border-radius:8px;color:#fff} +.login-placeholder a{color:#cfe6ff;text-decoration:underline} + +/* No data state */ +.no-data{text-align:center;padding:30px;color:rgba(255,255,255,0.6)} + +/* Service description text */ +.service-desc{color:gray;width:230px} +.service-desc-wide{color:gray;width:280px} +.service-textarea{resize:none;width:230px;height:132px} + +/* Admin helpers */ +.admin-note{font-size:11px;color:#666;margin-top:4px} +.admin-flex-wrap{display:flex;gap:12px;flex-wrap:wrap;margin-top:12px} + +@media (max-width:768px){ + .account-info-grid{grid-template-columns:1fr} +} + +/* Server status and utility classes */ +#gsw-site .text-success { + color: #10b981 !important; + font-weight: 600 !important; +} + +#gsw-site .text-danger { + color: #ef4444 !important; + font-weight: 600 !important; +} + +#gsw-site .text-muted { + color: rgba(255,255,255,0.7) !important; +} + +#gsw-site .text-center { + text-align: center !important; +} + +#gsw-site .mb-20 { + margin-bottom: 20px !important; +} + +#gsw-site .server-notes { + padding-left: 40px !important; + font-size: 0.9rem !important; + color: rgba(255,255,255,0.7) !important; +} + +/* Status badges */ +#gsw-site .status-badge { + display: inline-block; + padding: 4px 12px; + border-radius: 12px; + font-size: 0.85rem; + font-weight: 600; + text-transform: uppercase; +} + +#gsw-site .status-online { + background-color: rgba(16, 185, 129, 0.2); + color: #10b981; +} + +#gsw-site .status-offline { + background-color: rgba(239, 68, 68, 0.2); + color: #ef4444; +} + +#gsw-site .status-maintenance { + background-color: rgba(251, 191, 36, 0.2); + color: #fbbf24; +} + +#gsw-site .status-unknown { + background-color: rgba(156, 163, 175, 0.2); + color: #9ca3af; +} + +/* Form radio labels in renewal page */ +#gsw-site .form-group label { + display: block; + margin-bottom: 10px; + cursor: pointer; + padding: 12px; + border: 2px solid #e1e8ed; + border-radius: 8px; + background: rgba(255,255,255,0.05); + transition: background 0.2s ease; +} + +#gsw-site .form-group label:hover { + background: rgba(255,255,255,0.1); +} + diff --git a/modules/billing/site.zip b/modules/billing/files.zip similarity index 98% rename from modules/billing/site.zip rename to modules/billing/files.zip index 4c360fbb..e5dccf60 100644 Binary files a/modules/billing/site.zip and b/modules/billing/files.zip differ diff --git a/modules/billing/includes/config.inc.php b/modules/billing/includes/config.inc.php deleted file mode 100644 index 4401518c..00000000 --- a/modules/billing/includes/config.inc.php +++ /dev/null @@ -1,35 +0,0 @@ - diff --git a/modules/billing/includes/menu.php b/modules/billing/includes/menu.php index 0ad4b635..a8c6d168 100644 --- a/modules/billing/includes/menu.php +++ b/modules/billing/includes/menu.php @@ -71,16 +71,12 @@ if ($is_logged_in) {
- - - + Logout - - Login
@@ -90,8 +86,8 @@ if ($is_logged_in) { Home Game Servers - My Account - My Servers + + My Account Cart 0) echo ' ' . intval($cart_count) . ''; ?> - - Login - - - Register Admin diff --git a/modules/billing/my_account.php b/modules/billing/my_account.php index 0e2656e5..31863b3d 100644 --- a/modules/billing/my_account.php +++ b/modules/billing/my_account.php @@ -4,186 +4,28 @@ My Account - GameServers.World - b before a + if ($bId === null) return -1; // a has id -> a before b + return $bId - $aId; // numeric desc + } + + // Fallback: newest timestamp first return strtotime($b['ts'] ?? 0) - strtotime($a['ts'] ?? 0); }); @@ -325,7 +197,15 @@ $previous_invoices = array_filter($invoices, function($inv) { ?> -
+ +
+
+ My Account + Logout +
+ + +
@@ -359,8 +239,8 @@ $previous_invoices = array_filter($invoices, function($inv) {
- Edit Account Information -
+ +
@@ -404,6 +284,7 @@ $previous_invoices = array_filter($invoices, function($inv) { +
+ + Renew +

You don't have any game servers yet.

- Browse Game Servers + Browse Game Servers
diff --git a/modules/billing/my_servers.php b/modules/billing/my_servers.php index d8bd8afd..dde6182d 100644 --- a/modules/billing/my_servers.php +++ b/modules/billing/my_servers.php @@ -39,15 +39,9 @@ $query = "SELECT gc.game_name, o.order_id, o.status, - o.created_at, o.invoice_duration, - DATE_ADD(o.created_at, INTERVAL - CASE - WHEN o.invoice_duration = 'month' THEN 30 - WHEN o.invoice_duration = 'year' THEN 365 - ELSE 30 - END DAY - ) as expiration_date, + -- use finish_date as the expiration marker (set when order is paid/created) + o.finish_date AS expiration_date, bs.service_name, bs.price_monthly FROM ogp_home h @@ -100,7 +94,7 @@ $result = mysqli_query($db, $query); - Renew + Renew N/A @@ -110,9 +104,9 @@ $result = mysqli_query($db, $query); -
+

You don't have any game servers yet.

- Browse Game Servers + Browse Game Servers
@@ -122,17 +116,6 @@ $result = mysqli_query($db, $query); mysqli_close($db); ?> - - diff --git a/modules/billing/order.php b/modules/billing/order.php index 9f169362..365a5318 100644 --- a/modules/billing/order.php +++ b/modules/billing/order.php @@ -287,8 +287,8 @@ if ($row['price_monthly'] == 0.0) { ?> - -
Please login to order
+ + diff --git a/modules/billing/renew_server.php b/modules/billing/renew_server.php index 0b5ddb40..96c3b37b 100644 --- a/modules/billing/renew_server.php +++ b/modules/billing/renew_server.php @@ -1,3 +1,138 @@ + 0) { + $_SESSION['website_user_id'] = $user_id; + } + } +} + +// Always accept order_id from GET (link-based) or POST (form) +$order_id = intval($_REQUEST['order_id'] ?? 0); +// Allow optional duration override via ?duration=year +$duration = (isset($_REQUEST['duration']) && $_REQUEST['duration'] === 'year') ? 'year' : 'month'; + +$redirect_to = 'cart.php'; + +if ($order_id <= 0 || $user_id <= 0) { + header('Location: ' . $redirect_to); + exit; +} + +// Fetch order and verify ownership +$stmt = $db->prepare('SELECT order_id, user_id, service_id, qty, invoice_duration, price, home_id FROM ogp_billing_orders WHERE order_id = ? LIMIT 1'); +if (!$stmt) { + header('Location: ' . $redirect_to); + exit; +} +$stmt->bind_param('i', $order_id); +$stmt->execute(); +$res = $stmt->get_result(); +if (!$res || $res->num_rows === 0) { + $stmt->close(); + header('Location: ' . $redirect_to); + exit; +} +$order = $res->fetch_assoc(); +$stmt->close(); + +if (intval($order['user_id']) !== intval($user_id)) { + // Not the owner — silently redirect + header('Location: ' . $redirect_to); + exit; +} + +// Determine price for selected duration by looking up service prices +$service_id = intval($order['service_id'] ?? 0); +$price_val = floatval($order['price'] ?? 0.0); +if ($service_id > 0) { + $sstmt = $db->prepare('SELECT price_monthly, price_year FROM ogp_billing_services WHERE service_id = ? LIMIT 1'); + if ($sstmt) { + $sstmt->bind_param('i', $service_id); + $sstmt->execute(); + $sres = $sstmt->get_result(); + if ($sres && $sres->num_rows > 0) { + $srow = $sres->fetch_assoc(); + if ($duration === 'year' && !empty($srow['price_year']) && floatval($srow['price_year']) > 0) { + $price_val = floatval($srow['price_year']); + } else { + $price_val = floatval($srow['price_monthly']); + } + } + $sstmt->close(); + } +} + +// Update order: set status='renew', invoice_duration, qty, price +$new_status = 'renew'; +$qty = 1; +$price_formatted = number_format($price_val, 2, '.', ''); + $upd = $db->prepare('UPDATE ogp_billing_orders SET status = ?, invoice_duration = ?, qty = ?, price = ? WHERE order_id = ? AND user_id = ? LIMIT 1'); +if ($upd) { + // types: status (s), invoice_duration (s), qty (i), price (d), order_id (i), user_id (i) + $upd->bind_param('ssiddi', $new_status, $duration, $qty, $price_formatted, $order_id, $user_id); + $ok = $upd->execute(); + $affected = $upd->affected_rows; + $upd->close(); + if ($ok && $affected > 0) { + // Insert a row into ogp_logger if table exists (best-effort) + $client_ip = $_SERVER['REMOTE_ADDR'] ?? ''; + $msg = "USER-RENEW: User {$user_id} marked order {$order_id} as renew"; + // Try insert into ogp_logger table + $escaped_msg = mysqli_real_escape_string($db, $msg); + $escaped_ip = mysqli_real_escape_string($db, $client_ip); + // Determine logger table name (best-effort). Try standard name then any table that ends with 'logger'. + $logger_table = null; + $check = mysqli_query($db, "SHOW TABLES LIKE 'ogp_logger'"); + if ($check && mysqli_num_rows($check) > 0) { + $logger_table = 'ogp_logger'; + } else { + $reslt = mysqli_query($db, "SHOW TABLES LIKE '%logger'"); + if ($reslt && mysqli_num_rows($reslt) > 0) { + $row = mysqli_fetch_row($reslt); + $logger_table = $row[0]; + } + } + if ($logger_table) { + $dt = date('Y-m-d H:i:s'); + $ins = "INSERT INTO `" . $logger_table . "` (`date`, `user_id`, `ip`, `message`) VALUES ('{$dt}', " . intval($user_id) . ", '{$escaped_ip}', '{$escaped_msg}')"; + @mysqli_query($db, $ins); + } + } +} + +// Done — redirect back silently +header('Location: ' . $redirect_to); +exit; + +?> @@ -6,65 +141,41 @@ Renew Server - GameServers.World -

Invalid order ID.

'; - include(__DIR__ . '/includes/footer.php'); - exit; -} - -// Fetch order details -$query = "SELECT o.*, bs.service_name, bs.price_monthly, bs.price_year - FROM ogp_billing_orders o - LEFT JOIN ogp_billing_services bs ON o.service_id = bs.service_id - WHERE o.order_id = $order_id AND o.user_id = $user_id - LIMIT 1"; -$result = mysqli_query($db, $query); - -if (!$result || mysqli_num_rows($result) === 0) { - echo '

Order not found or you do not have permission to renew this server.

'; - mysqli_close($db); - include(__DIR__ . '/includes/footer.php'); - exit; -} - -$order = mysqli_fetch_assoc($result); - -// Process renewal +// Process renewal: mark the existing order as a 'renew' so it appears in the cart if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['confirm_renewal'])) { $duration = isset($_POST['duration']) ? $_POST['duration'] : 'month'; - $price = ($duration === 'year') ? $order['price_year'] : $order['price_monthly']; - - // Create a new order for renewal - // In a real system, this would redirect to payment gateway - // For now, we'll just show a message - - $message = "Renewal initiated for " . htmlspecialchars($order['service_name']) . ". "; - $message .= "Duration: " . ($duration === 'year' ? '1 year' : '1 month') . ". "; - $message .= "Total: $" . number_format($price, 2) . ". "; - $message .= "In a production system, you would be redirected to payment processing."; - - echo '
' . $message . '
'; + $invoice_duration = ($duration === 'year') ? 'year' : 'month'; + $qty = 1; + + // Determine price based on duration (fall back to monthly if missing) + $price = ($duration === 'year' && !empty($order['price_year']) && floatval($order['price_year']) > 0) ? floatval($order['price_year']) : floatval($order['price_monthly']); + + // Prepare update to set this order into renew state + if ($upd = $db->prepare("UPDATE ogp_billing_orders SET status = ?, invoice_duration = ?, qty = ?, price = ? WHERE order_id = ? AND user_id = ? LIMIT 1")) { + $new_status = 'renew'; + $orderIdInt = intval($order_id); + $userIdInt = intval($user_id); + $price_val = number_format($price, 2, '.', ''); + $upd->bind_param('ssiids', $new_status, $invoice_duration, $qty, $price_val, $orderIdInt, $userIdInt); + $ok = $upd->execute(); + $affected = $upd->affected_rows; + $upd->close(); + if ($ok && $affected > 0) { + // Log to panel logger that the order was marked for renewal + if (isset($db) && method_exists($db, 'logger')) { + $db->logger("USER-RENEW: User " . intval($userIdInt) . " marked order " . intval($orderIdInt) . " as renew"); + } + // Successfully transitioned to renew — go to cart + header('Location: cart.php'); + exit; + } else { + $err = mysqli_error($db); + echo '
Failed to mark order for renewal: ' . htmlspecialchars($err) . '
'; + } + } else { + $err = mysqli_error($db); + echo '
Failed to prepare renewal update: ' . htmlspecialchars($err) . '
'; + } } ?> @@ -73,27 +184,27 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['confirm_renewal'])) {
Renew Server
-

+

-
-
@@ -103,27 +214,6 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['confirm_renewal'])) { mysqli_close($db); ?> - - diff --git a/modules/billing/server_status.php b/modules/billing/server_status.php index a7fc5ba9..1aad2b7b 100644 --- a/modules/billing/server_status.php +++ b/modules/billing/server_status.php @@ -66,8 +66,8 @@ $result = mysqli_query($db, $query);
Server Status
-
-

Real-time status of our game server infrastructure

+
+

Real-time status of our game server infrastructure

0): ?> @@ -143,7 +143,7 @@ $result = mysqli_query($db, $query); - + @@ -152,12 +152,12 @@ $result = mysqli_query($db, $query); -
+

No server status information available.

-
+

Server status is updated automatically every 5 minutes.

If you experience any issues, please contact support.

@@ -168,37 +168,6 @@ $result = mysqli_query($db, $query); mysqli_close($db); ?> - - diff --git a/modules/billing/serverlist.php b/modules/billing/serverlist.php index 2089d870..841a6ee8 100644 --- a/modules/billing/serverlist.php +++ b/modules/billing/serverlist.php @@ -111,7 +111,7 @@ include(__DIR__ . '/includes/menu.php'); ?> -
Please login to order
+