Fix billing cart schema/pricing and storefront OS grouping

Agent-Logs-Url: https://github.com/GameServerPanel/GSP/sessions/0b6f5123-e13c-4bf7-94c0-339760fe3034

Co-authored-by: iaretechnician <2749183+iaretechnician@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2026-05-07 00:35:58 +00:00 committed by GitHub
parent 10aff1e1c6
commit c9cf3ac298
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 214 additions and 89 deletions

View file

@ -17,6 +17,11 @@ if (session_status() === PHP_SESSION_NONE) {
require_once __DIR__ . '/bootstrap.php';
require_once __DIR__ . '/includes/login_required.php';
function billing_free_money_to_cents(float $amount): int
{
return (int) round($amount * 100);
}
$userId = intval($_SESSION['website_user_id'] ?? $_SESSION['user_id'] ?? 0);
if ($userId <= 0) {
header('Location: /login.php');
@ -30,15 +35,15 @@ if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
}
// DB connection
$db = mysqli_connect($db_host, $db_user, $db_pass, $db_name, isset($db_port) ? (int)$db_port : null);
if (!$db) {
die('<p>Database connection failed. Please <a href="/order.php">return to the shop</a> or contact support.</p>');
$mysqli = mysqli_connect($db_host, $db_user, $db_pass, $db_name, isset($db_port) ? (int)$db_port : null);
if (!$mysqli) {
die('<p>Database connection failed. Please <a href="/serverlist.php">return to the shop</a> or contact support.</p>');
}
mysqli_set_charset($db, 'utf8mb4');
mysqli_set_charset($mysqli, 'utf8mb4');
// Fetch unpaid invoices for this user (prepared statement)
$invoices = [];
$stmt = mysqli_prepare($db, "SELECT * FROM {$table_prefix}billing_invoices
$stmt = mysqli_prepare($mysqli, "SELECT * FROM {$table_prefix}billing_invoices
WHERE user_id = ?
AND (status = 'due' OR status = '')
AND (payment_status IS NULL OR payment_status NOT IN ('paid','cancelled','refunded'))
@ -54,7 +59,9 @@ if ($stmt) {
}
if (empty($invoices)) {
mysqli_close($db);
if ($mysqli instanceof mysqli) {
mysqli_close($mysqli);
}
header('Location: /cart.php?msg=empty');
exit;
}
@ -65,8 +72,8 @@ $couponCode = trim($_POST['coupon_code'] ?? $_SESSION['cart_coupon_code'] ?? '')
$discountPct = 0.0;
if ($couponCode !== '') {
$safe = mysqli_real_escape_string($db, $couponCode);
$cr = mysqli_query($db, "SELECT * FROM {$table_prefix}billing_coupons
$safe = mysqli_real_escape_string($mysqli, $couponCode);
$cr = mysqli_query($mysqli, "SELECT * FROM {$table_prefix}billing_coupons
WHERE code = '$safe' AND is_active = 1 LIMIT 1");
if ($cr && mysqli_num_rows($cr) === 1) {
$coupon = mysqli_fetch_assoc($cr);
@ -76,16 +83,20 @@ if ($couponCode !== '') {
}
// Calculate total and verify it is $0 after discount
$totalAmount = 0.0;
$totalAmountCents = 0;
foreach ($invoices as $inv) {
$totalAmount += (float)($inv['amount'] ?? 0);
$lineAmount = (float)($inv['amount'] ?? 0);
$totalAmountCents += billing_free_money_to_cents($lineAmount);
}
$discountAmount = $totalAmount * ($discountPct / 100.0);
$finalAmount = round($totalAmount - $discountAmount, 2);
$discountAmountCents = (int) round($totalAmountCents * ($discountPct / 100.0));
$discountAmountCents = min($discountAmountCents, $totalAmountCents);
$finalAmountCents = max(0, $totalAmountCents - $discountAmountCents);
if ($finalAmount > 0.00) {
if ($finalAmountCents !== 0) {
// Coupon no longer covers the full amount — redirect to cart
mysqli_close($db);
if ($mysqli instanceof mysqli) {
mysqli_close($mysqli);
}
header('Location: /cart.php?msg=coupon_insufficient');
exit;
}
@ -97,7 +108,7 @@ $txid = 'free-' . time() . '-' . $userId;
require_once __DIR__ . '/classes/BillingRepository.php';
require_once __DIR__ . '/classes/BillingService.php';
$repo = new BillingRepository($db, $table_prefix);
$repo = new BillingRepository($mysqli, $table_prefix);
$newOrderIds = [];
$duration_meta = static function (array $invoice): array {
$duration = strtolower((string)($invoice['invoice_duration'] ?? $invoice['rate_type'] ?? 'month'));
@ -213,7 +224,7 @@ foreach ($invoices as $inv) {
}
if ($couponId > 0 && !empty($invoices)) {
mysqli_query($db, "UPDATE {$table_prefix}billing_coupons
mysqli_query($mysqli, "UPDATE {$table_prefix}billing_coupons
SET current_uses = current_uses + 1
WHERE coupon_id = " . intval($couponId));
}
@ -234,7 +245,9 @@ if (!empty($newOrderIds)) {
// If panel bootstrap fails the order is Active and admins can provision via the orders panel.
}
mysqli_close($db);
if ($mysqli instanceof mysqli) {
mysqli_close($mysqli);
}
header('Location: /payment_success.php?order_id=' . urlencode($txid));
exit;