working 99%, major changes next
This commit is contained in:
parent
ed94cf17db
commit
89b5344e79
6 changed files with 328 additions and 62 deletions
152
modules/billing/admin_invoices.php
Normal file
152
modules/billing/admin_invoices.php
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
<?php
|
||||
// Admin invoices viewer and editor
|
||||
$session_name = session_name(); session_start();
|
||||
require_once(__DIR__ . '/includes/config.inc.php');
|
||||
require_once(__DIR__ . '/includes/admin_auth.php');
|
||||
|
||||
$db = mysqli_connect($db_host, $db_user, $db_pass, $db_name);
|
||||
if (!$db) die('DB connection failed');
|
||||
|
||||
// Handle POST requests for invoice updates
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
||||
if (isset($_POST['update_invoice'])) {
|
||||
$orderId = intval($_POST['order_id']);
|
||||
$newStatus = mysqli_real_escape_string($db, $_POST['status']);
|
||||
$newPrice = floatval($_POST['price']);
|
||||
|
||||
$sql = "UPDATE ogp_billing_orders SET status = '$newStatus', price = $newPrice WHERE order_id = $orderId LIMIT 1";
|
||||
mysqli_query($db, $sql);
|
||||
header('Location: admin_invoices.php?updated=' . $orderId);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch all orders
|
||||
$orders = mysqli_query($db, "SELECT o.*, u.user_name
|
||||
FROM ogp_billing_orders o
|
||||
LEFT JOIN ogp_users u ON o.user_id = u.user_id
|
||||
ORDER BY o.order_id DESC");
|
||||
|
||||
function h($s){ return htmlspecialchars((string)$s, ENT_QUOTES, 'UTF-8'); }
|
||||
?>
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Admin — Invoices</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="css/header.css">
|
||||
<style>
|
||||
.edit-row { background: #f9f9f9; }
|
||||
.edit-input { width: 80px; padding: 4px; border: 1px solid #ccc; border-radius: 3px; }
|
||||
.edit-select { padding: 4px; border: 1px solid #ccc; border-radius: 3px; }
|
||||
.btn-save { background: #28a745; color: white; border: none; padding: 5px 12px; border-radius: 3px; cursor: pointer; }
|
||||
.btn-save:hover { background: #218838; }
|
||||
.status-badge { display: inline-block; padding: 3px 8px; border-radius: 3px; font-size: 12px; font-weight: 600; }
|
||||
.status-paid { background: #d4edda; color: #155724; }
|
||||
.status-pending { background: #fff3cd; color: #856404; }
|
||||
.status-in-cart { background: #d1ecf1; color: #0c5460; }
|
||||
.status-expired { background: #f8d7da; color: #721c24; }
|
||||
.status-renew { background: #cce5ff; color: #004085; }
|
||||
.status-installed { background: #d4edda; color: #155724; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<?php include(__DIR__ . '/includes/top.php'); include(__DIR__ . '/includes/menu.php'); ?>
|
||||
<div class="container-wide panel">
|
||||
<h1>Admin — All Invoices</h1>
|
||||
<?php if (isset($_GET['updated'])): ?>
|
||||
<div style="background: #d4edda; padding: 10px; margin-bottom: 15px; border-radius: 3px; color: #155724;">
|
||||
✓ Invoice #<?php echo h($_GET['updated']); ?> updated successfully.
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!$orders || mysqli_num_rows($orders) === 0): ?>
|
||||
<p>No invoices found.</p>
|
||||
<?php else: ?>
|
||||
<table class="cart-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Order ID</th>
|
||||
<th>User</th>
|
||||
<th>Home ID</th>
|
||||
<th>Home Name</th>
|
||||
<th>IP</th>
|
||||
<th>Price</th>
|
||||
<th>Duration</th>
|
||||
<th>Status</th>
|
||||
<th>Created</th>
|
||||
<th>Finish Date</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php while ($row = mysqli_fetch_assoc($orders)): ?>
|
||||
<tr id="row-<?php echo $row['order_id']; ?>">
|
||||
<td><?php echo h($row['order_id']); ?></td>
|
||||
<td><?php echo h($row['user_name'] ?? 'N/A'); ?></td>
|
||||
<td><?php echo h($row['home_id'] ?? 'N/A'); ?></td>
|
||||
<td><?php echo h($row['home_name']); ?></td>
|
||||
<td><?php echo h($row['ip']); ?></td>
|
||||
<td>$<?php echo number_format($row['price'], 2); ?></td>
|
||||
<td><?php echo h($row['invoice_duration']); ?></td>
|
||||
<td>
|
||||
<span class="status-badge status-<?php echo h($row['status']); ?>">
|
||||
<?php echo strtoupper(h($row['status'])); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php echo h($row['order_date']); ?></td>
|
||||
<td><?php echo h($row['finish_date'] ?? 'N/A'); ?></td>
|
||||
<td>
|
||||
<button onclick="editRow(<?php echo $row['order_id']; ?>)" class="gsw-btn" style="padding: 4px 10px; font-size: 12px;">Edit</button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr id="edit-<?php echo $row['order_id']; ?>" class="edit-row" style="display: none;">
|
||||
<td colspan="11">
|
||||
<form method="post" action="" style="padding: 10px;">
|
||||
<input type="hidden" name="order_id" value="<?php echo $row['order_id']; ?>">
|
||||
<strong>Edit Invoice #<?php echo $row['order_id']; ?></strong>
|
||||
<div style="margin-top: 10px;">
|
||||
<label style="margin-right: 15px;">
|
||||
<strong>Price:</strong>
|
||||
<input type="number" name="price" value="<?php echo $row['price']; ?>" step="0.01" class="edit-input" required>
|
||||
</label>
|
||||
<label style="margin-right: 15px;">
|
||||
<strong>Status:</strong>
|
||||
<select name="status" class="edit-select" required>
|
||||
<option value="in-cart" <?php echo $row['status'] === 'in-cart' ? 'selected' : ''; ?>>IN-CART</option>
|
||||
<option value="paid" <?php echo $row['status'] === 'paid' ? 'selected' : ''; ?>>PAID</option>
|
||||
<option value="installed" <?php echo $row['status'] === 'installed' ? 'selected' : ''; ?>>INSTALLED</option>
|
||||
<option value="renew" <?php echo $row['status'] === 'renew' ? 'selected' : ''; ?>>RENEW</option>
|
||||
<option value="pending" <?php echo $row['status'] === 'pending' ? 'selected' : ''; ?>>PENDING</option>
|
||||
<option value="expired" <?php echo $row['status'] === 'expired' ? 'selected' : ''; ?>>EXPIRED</option>
|
||||
</select>
|
||||
</label>
|
||||
<button type="submit" name="update_invoice" class="btn-save">Save Changes</button>
|
||||
<button type="button" onclick="cancelEdit(<?php echo $row['order_id']; ?>)" class="gsw-btn" style="padding: 5px 12px; margin-left: 5px;">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endwhile; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function editRow(orderId) {
|
||||
document.getElementById('row-' + orderId).style.display = 'none';
|
||||
document.getElementById('edit-' + orderId).style.display = 'table-row';
|
||||
}
|
||||
|
||||
function cancelEdit(orderId) {
|
||||
document.getElementById('row-' + orderId).style.display = 'table-row';
|
||||
document.getElementById('edit-' + orderId).style.display = 'none';
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php include(__DIR__ . '/includes/footer.php'); ?>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
@ -37,10 +37,49 @@ curl_close($ch);
|
|||
|
||||
if ($http !== 201 && $http !== 200) { http_response_code($http); echo $res; exit; }
|
||||
|
||||
$payload = json_decode($res, true);
|
||||
$status = $payload['status'] ?? 'UNKNOWN';
|
||||
$txnId = $payload['purchase_units'][0]['payments']['captures'][0]['id'] ?? null;
|
||||
// Parse the capture response
|
||||
$captureData = json_decode($res, true);
|
||||
$captureStatus = $captureData['status'] ?? '';
|
||||
|
||||
echo json_encode(['status'=>$status, 'txn_id'=>$txnId]);
|
||||
// If capture was successful, immediately update the order status to 'paid'
|
||||
if ($captureStatus === 'COMPLETED') {
|
||||
// Extract custom_id which contains the order_id
|
||||
$customId = $captureData['purchase_units'][0]['payments']['captures'][0]['custom_id'] ?? null;
|
||||
$txnId = $captureData['purchase_units'][0]['payments']['captures'][0]['id'] ?? null;
|
||||
|
||||
if ($customId && is_numeric($customId)) {
|
||||
// Connect to DB and update order status
|
||||
$db = @mysqli_connect($db_host, $db_user, $db_pass, $db_name);
|
||||
if ($db) {
|
||||
$orderId = intval($customId);
|
||||
|
||||
// Calculate finish_date based on qty and invoice_duration
|
||||
$qtyRes = mysqli_query($db, "SELECT qty, invoice_duration FROM ogp_billing_orders WHERE order_id = $orderId LIMIT 1");
|
||||
$finish_date = null;
|
||||
if ($qtyRes && $row = mysqli_fetch_assoc($qtyRes)) {
|
||||
$qty = intval($row['qty'] ?? 1);
|
||||
$duration = strtolower(trim($row['invoice_duration'] ?? 'month'));
|
||||
$months = (strpos($duration, 'year') !== false) ? ($qty * 12) : $qty;
|
||||
if ($months > 0) {
|
||||
$dt = new DateTime('now');
|
||||
$dt->modify('+' . $months . ' months');
|
||||
$finish_date = $dt->format('Y-m-d H:i:s');
|
||||
}
|
||||
}
|
||||
|
||||
// Update order status to 'paid'
|
||||
$sql = "UPDATE ogp_billing_orders SET status = 'paid', payment_txid = '" . mysqli_real_escape_string($db, $txnId) . "', paid_ts = NOW()";
|
||||
if ($finish_date) {
|
||||
$sql .= ", finish_date = '" . mysqli_real_escape_string($db, $finish_date) . "'";
|
||||
}
|
||||
$sql .= " WHERE order_id = $orderId AND status = 'in-cart' LIMIT 1";
|
||||
mysqli_query($db, $sql);
|
||||
mysqli_close($db);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return the full PayPal response for proper processing
|
||||
echo $res;
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,17 @@ if ($http !== 200) { http_response_code(500); echo json_encode(['error'=>'oauth_
|
|||
$access = json_decode($tok, true)['access_token'] ?? null;
|
||||
if (!$access) { http_response_code(500); echo json_encode(['error'=>'oauth_no_token']); exit; }
|
||||
|
||||
// Update site base URL to exclude 'modules/billing'
|
||||
$siteBaseUrl = 'http://gameservers.world';
|
||||
|
||||
// Ensure return_url and cancel_url are absolute URLs (relative to site root)
|
||||
if (strpos($return_url, 'http') !== 0) {
|
||||
$return_url = $siteBaseUrl . '/' . ltrim($return_url, '/');
|
||||
}
|
||||
if (strpos($cancel_url, 'http') !== 0) {
|
||||
$cancel_url = $siteBaseUrl . '/' . ltrim($cancel_url, '/');
|
||||
}
|
||||
|
||||
$purchaseUnit = [
|
||||
'amount' => [ 'currency_code' => $currency, 'value' => $amount_value ],
|
||||
'description' => $description,
|
||||
|
|
@ -64,6 +75,18 @@ $body = [
|
|||
'application_context' => [ 'return_url'=>$return_url, 'cancel_url'=>$cancel_url, 'user_action'=>'PAY_NOW' ]
|
||||
];
|
||||
|
||||
// Log the payload for debugging
|
||||
$logDir = __DIR__ . '/../data';
|
||||
@mkdir($logDir, 0775, true);
|
||||
$logFile = $logDir . '/create_order_payload.log';
|
||||
$logEntry = date('Y-m-d H:i:s') . "\n" . json_encode($body, JSON_PRETTY_PRINT) . "\n\n";
|
||||
@file_put_contents($logFile, $logEntry, FILE_APPEND);
|
||||
|
||||
// Log corrected URLs for debugging
|
||||
$logFile = $logDir . '/corrected_urls.log';
|
||||
$logEntry = date('Y-m-d H:i:s') . "\nReturn URL: $return_url\nCancel URL: $cancel_url\n\n";
|
||||
@file_put_contents($logFile, $logEntry, FILE_APPEND);
|
||||
|
||||
$ch = curl_init("$api/v2/checkout/orders");
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
|
|
@ -75,7 +98,18 @@ $res = curl_exec($ch);
|
|||
$http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($http !== 201) { http_response_code($http); echo $res; exit; }
|
||||
if ($http !== 201) {
|
||||
// Log error for debugging
|
||||
$logDir = __DIR__ . '/../data';
|
||||
@mkdir($logDir, 0775, true);
|
||||
$logFile = $logDir . '/create_order_errors.log';
|
||||
$logEntry = date('Y-m-d H:i:s') . " HTTP $http: " . substr($res, 0, 500) . "\n";
|
||||
@file_put_contents($logFile, $logEntry, FILE_APPEND);
|
||||
|
||||
http_response_code($http);
|
||||
echo $res;
|
||||
exit;
|
||||
}
|
||||
echo $res;
|
||||
|
||||
?>
|
||||
|
|
|
|||
|
|
@ -428,10 +428,12 @@ if (is_array($invoice) && count($invoice) === 1 && !empty($invoice[0]['order_id'
|
|||
$description = 'Game server order (' . count($lineItems) . ' item' . (count($lineItems)===1?'': 's') . ')';
|
||||
|
||||
// URLs
|
||||
// URLs - since the billing "website" root is the files in modules/billing,
|
||||
// return.php lives alongside cart.php so use relative paths.
|
||||
$returnUrl = 'return.php?invoice=' . urlencode($invoiceId);
|
||||
$cancelUrl = 'return.php?invoice=' . urlencode($invoiceId) . '&cancel=1';
|
||||
// Define the site base URL
|
||||
$siteBaseUrl = 'http://gameservers.world/modules/billing';
|
||||
|
||||
// Generate absolute URLs for return and cancel
|
||||
$returnUrl = $siteBaseUrl . '/return.php?invoice=' . urlencode($invoiceId);
|
||||
$cancelUrl = $siteBaseUrl . '/return.php?invoice=' . urlencode($invoiceId) . '&cancel=1';
|
||||
|
||||
// API base (relative) - point to billing module API endpoints
|
||||
$apiBase = 'api';
|
||||
|
|
@ -439,6 +441,19 @@ $apiBase = 'api';
|
|||
<!-- PayPal JS SDK (Sandbox). Use LIVE client-id when going live. -->
|
||||
<script src="https://www.paypal.com/sdk/js?client-id=AfvY_C2zA_hTHxHq7TIhtOeub4xBdySYrt_Hjj3d_WYQwjWI9NfOAVOTeResx2rgZ_nP5tOoxQSAHw8c¤cy=USD&intent=capture"></script>
|
||||
|
||||
<!-- Debug: Cart values -->
|
||||
<?php if (isset($_GET['debug'])): ?>
|
||||
<div style="background:#f0f0f0; padding:10px; margin:10px 0; font:12px monospace;">
|
||||
<strong>Debug Info:</strong><br>
|
||||
Grand Total: $<?php echo htmlspecialchars($grandTotal); ?><br>
|
||||
Invoice Items: <?php echo count($invoice); ?><br>
|
||||
Line Items: <?php echo count($lineItems); ?><br>
|
||||
Amount: <?php echo htmlspecialchars($amount); ?><br>
|
||||
Invoice ID: <?php echo htmlspecialchars($invoiceId); ?><br>
|
||||
Custom ID: <?php echo htmlspecialchars($customId); ?><br>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="paypal-button-container"></div>
|
||||
<div id="pp-status" class="mt-12" style="font:14px system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;"></div>
|
||||
|
||||
|
|
@ -446,14 +461,14 @@ $apiBase = 'api';
|
|||
(function(){
|
||||
const statusEl = document.getElementById('pp-status');
|
||||
|
||||
// Values from PHP
|
||||
const amount = "<?= $amount ?>";
|
||||
const currency = "<?= $currency ?>";
|
||||
const invoice_id = "<?= $invoiceId ?>";
|
||||
const custom_id = "<?= $customId ?>";
|
||||
const description = "<?= htmlspecialchars($description, ENT_QUOTES) ?>";
|
||||
const return_url = "<?= $returnUrl ?>";
|
||||
const cancel_url = "<?= $cancelUrl ?>";
|
||||
// Values from PHP - use json_encode for proper JavaScript escaping
|
||||
const amount = <?php echo json_encode($amount); ?>;
|
||||
const currency = <?php echo json_encode($currency); ?>;
|
||||
const invoice_id = <?php echo json_encode($invoiceId); ?>;
|
||||
const custom_id = <?php echo json_encode($customId); ?>;
|
||||
const description = <?php echo json_encode($description); ?>;
|
||||
const return_url = <?php echo json_encode($returnUrl); ?>;
|
||||
const cancel_url = <?php echo json_encode($cancelUrl); ?>;
|
||||
|
||||
// Line items (serverID + per-item amount) for your records and webhook correlation
|
||||
const line_invoices = <?php echo json_encode($invoice, JSON_UNESCAPED_SLASHES); ?>;
|
||||
|
|
@ -461,8 +476,17 @@ $apiBase = 'api';
|
|||
// PayPal "items" for purchase_units (shows on PayPal + returns in webhook under purchase_units)
|
||||
const items = <?php echo json_encode($lineItems, JSON_UNESCAPED_SLASHES); ?>;
|
||||
|
||||
// Debug logging
|
||||
console.log('PayPal cart debug:', {
|
||||
amount, currency, invoice_id, custom_id, description,
|
||||
line_invoices_count: line_invoices.length,
|
||||
items_count: items.length,
|
||||
return_url, cancel_url
|
||||
});
|
||||
|
||||
function setStatus(msg){ if(statusEl) statusEl.textContent = msg; }
|
||||
|
||||
|
||||
paypal.Buttons({
|
||||
createOrder: function() {
|
||||
setStatus('Creating order…');
|
||||
|
|
@ -477,11 +501,24 @@ $apiBase = 'api';
|
|||
line_invoices // your raw cart detail, persisted in your DB if you choose
|
||||
})
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if (!res.ok) {
|
||||
return res.text().then(errText => {
|
||||
throw new Error('API error ' + res.status + ': ' + errText.substring(0, 200));
|
||||
});
|
||||
}
|
||||
return res.json();
|
||||
})
|
||||
.then(data => {
|
||||
if (!data.id) { throw new Error(data.error || 'No order id'); }
|
||||
if (!data.id) {
|
||||
throw new Error(JSON.stringify(data).substring(0, 200) || 'No order id');
|
||||
}
|
||||
setStatus('Order created.');
|
||||
return data.id;
|
||||
})
|
||||
.catch(err => {
|
||||
setStatus('PayPal error: ' + err.message);
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@ input, textarea, select, button { color: #fff; background: #11141f; border: 1px
|
|||
.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-status-expired{background:rgba(239,68,68,0.2);color:#ef4444}
|
||||
.invoice-date{color:rgba(255,255,255,0.6);font-size:0.9rem}
|
||||
|
||||
/* Login placeholder for non-logged-in users */
|
||||
|
|
|
|||
|
|
@ -187,13 +187,26 @@ usort($invoices, function($a, $b) {
|
|||
return strtotime($b['ts'] ?? 0) - strtotime($a['ts'] ?? 0);
|
||||
});
|
||||
|
||||
// Separate current (pending) and previous (paid) invoices
|
||||
$current_invoices = array_filter($invoices, function($inv) {
|
||||
return strtolower($inv['status'] ?? '') === 'pending' || empty($inv['status']);
|
||||
});
|
||||
$previous_invoices = array_filter($invoices, function($inv) {
|
||||
return strtolower($inv['status'] ?? '') === 'paid' || strtolower($inv['status'] ?? '') === 'completed';
|
||||
});
|
||||
// Organize invoices by status
|
||||
$invoices_by_status = [];
|
||||
foreach ($invoices as $inv) {
|
||||
$status = strtolower($inv['status'] ?? 'pending');
|
||||
if (!isset($invoices_by_status[$status])) {
|
||||
$invoices_by_status[$status] = [];
|
||||
}
|
||||
$invoices_by_status[$status][] = $inv;
|
||||
}
|
||||
|
||||
// Define status display order and labels
|
||||
$status_config = [
|
||||
'pending' => ['label' => 'Pending Invoices', 'class' => 'pending'],
|
||||
'paid' => ['label' => 'Paid Invoices', 'class' => 'paid'],
|
||||
'completed' => ['label' => 'Completed Invoices', 'class' => 'paid'],
|
||||
'in-cart' => ['label' => 'In Cart', 'class' => 'pending'],
|
||||
'installed' => ['label' => 'Installed/Active', 'class' => 'paid'],
|
||||
'expired' => ['label' => 'Expired Invoices', 'class' => 'expired'],
|
||||
'cancelled' => ['label' => 'Cancelled Invoices', 'class' => 'expired'],
|
||||
];
|
||||
|
||||
?>
|
||||
|
||||
|
|
@ -333,45 +346,35 @@ $previous_invoices = array_filter($invoices, function($inv) {
|
|||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<!-- Current Invoices Due Section -->
|
||||
<?php if (!empty($current_invoices)): ?>
|
||||
<div class="account-section">
|
||||
<h2>Current Invoices Due</h2>
|
||||
<?php foreach ($current_invoices as $invoice): ?>
|
||||
<div class="invoice-item">
|
||||
<div>
|
||||
<div class="invoice-id">Invoice #<?php echo htmlspecialchars($invoice['invoice'] ?? $invoice['custom'] ?? 'N/A'); ?></div>
|
||||
<div class="invoice-date"><?php echo htmlspecialchars($invoice['ts'] ?? 'N/A'); ?></div>
|
||||
<!-- Invoices Section - Organized by Status -->
|
||||
<?php if (!empty($invoices_by_status)): ?>
|
||||
<?php foreach ($status_config as $status_key => $status_info): ?>
|
||||
<?php if (isset($invoices_by_status[$status_key]) && !empty($invoices_by_status[$status_key])): ?>
|
||||
<div class="account-section">
|
||||
<h2><?php echo htmlspecialchars($status_info['label']); ?></h2>
|
||||
<?php foreach ($invoices_by_status[$status_key] as $invoice): ?>
|
||||
<div class="invoice-item">
|
||||
<div>
|
||||
<div class="invoice-id">Invoice #<?php echo htmlspecialchars($invoice['invoice'] ?? $invoice['custom'] ?? 'N/A'); ?></div>
|
||||
<div class="invoice-date"><?php echo htmlspecialchars($invoice['ts'] ?? 'N/A'); ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="invoice-amount"><?php echo htmlspecialchars(($invoice['currency'] ?? 'USD') . ' ' . number_format((float)($invoice['amount'] ?? 0), 2)); ?></span>
|
||||
<span class="invoice-status invoice-status-<?php echo htmlspecialchars($status_info['class']); ?>">
|
||||
<?php echo htmlspecialchars(ucfirst($status_key)); ?>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<div>
|
||||
<span class="invoice-amount"><?php echo htmlspecialchars(($invoice['currency'] ?? 'USD') . ' ' . number_format((float)($invoice['amount'] ?? 0), 2)); ?></span>
|
||||
<span class="invoice-status invoice-status-pending">Pending</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<div class="account-section">
|
||||
<h2>Invoices</h2>
|
||||
<div class="no-data">No invoices found.</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<!-- Previous Invoices Section -->
|
||||
<div class="account-section">
|
||||
<h2>Previous Invoices</h2>
|
||||
<?php if (!empty($previous_invoices)): ?>
|
||||
<?php foreach ($previous_invoices as $invoice): ?>
|
||||
<div class="invoice-item">
|
||||
<div>
|
||||
<div class="invoice-id">Invoice #<?php echo htmlspecialchars($invoice['invoice'] ?? $invoice['custom'] ?? 'N/A'); ?></div>
|
||||
<div class="invoice-date"><?php echo htmlspecialchars($invoice['ts'] ?? 'N/A'); ?></div>
|
||||
</div>
|
||||
<div>
|
||||
<span class="invoice-amount"><?php echo htmlspecialchars(($invoice['currency'] ?? 'USD') . ' ' . number_format((float)($invoice['amount'] ?? 0), 2)); ?></span>
|
||||
<span class="invoice-status invoice-status-paid">Paid</span>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="no-data">No previous invoices found.</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue