mirror of
https://github.com/myronblair/tomsjavajive-app
synced 2026-06-30 17:50:56 -05:00
280 lines
11 KiB
PHP
280 lines
11 KiB
PHP
<?php
|
|
ob_start();
|
|
/**
|
|
* Tom's Java Jive - Admin Orders Page
|
|
*/
|
|
|
|
$pageTitle = 'Orders';
|
|
require_once __DIR__ . '/includes/header.php';
|
|
|
|
// Handle status update
|
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
|
|
$action = $_POST['action'];
|
|
$orderId = $_POST['order_id'] ?? '';
|
|
|
|
if ($action === 'update_status' && $orderId) {
|
|
$status = $_POST['status'] ?? '';
|
|
$trackingNumber = $_POST['tracking_number'] ?? null;
|
|
|
|
$updateData = ['order_status' => $status];
|
|
if ($trackingNumber) {
|
|
$updateData['tracking_number'] = $trackingNumber;
|
|
}
|
|
|
|
db()->update('orders', $updateData, 'order_id = :id', ['id' => $orderId]);
|
|
setFlash('success', 'Order status updated');
|
|
header('Location: /admin/orders.php');
|
|
exit;
|
|
}
|
|
}
|
|
|
|
// Filters
|
|
$status = $_GET['status'] ?? '';
|
|
$search = $_GET['search'] ?? '';
|
|
$dateFrom = $_GET['date_from'] ?? '';
|
|
$dateTo = $_GET['date_to'] ?? '';
|
|
$page = max(1, intval($_GET['page'] ?? 1));
|
|
|
|
// Build query
|
|
$where = ['1=1'];
|
|
$params = [];
|
|
|
|
if ($status) {
|
|
$where[] = 'order_status = :status';
|
|
$params['status'] = $status;
|
|
}
|
|
|
|
if ($search) {
|
|
$where[] = '(order_number LIKE :search OR customer_name LIKE :search OR customer_email LIKE :search)';
|
|
$params['search'] = '%' . $search . '%';
|
|
}
|
|
|
|
if ($dateFrom) {
|
|
$where[] = 'DATE(created_at) >= :date_from';
|
|
$params['date_from'] = $dateFrom;
|
|
}
|
|
|
|
if ($dateTo) {
|
|
$where[] = 'DATE(created_at) <= :date_to';
|
|
$params['date_to'] = $dateTo;
|
|
}
|
|
|
|
$whereClause = implode(' AND ', $where);
|
|
|
|
// Get total and paginate
|
|
$totalOrders = db()->count('orders', $whereClause, $params);
|
|
$pagination = paginate($totalOrders, $page, ADMIN_ITEMS_PER_PAGE);
|
|
|
|
// Get orders
|
|
$orders = db()->fetchAll(
|
|
"SELECT * FROM orders WHERE {$whereClause} ORDER BY created_at DESC LIMIT :limit OFFSET :offset",
|
|
array_merge($params, ['limit' => $pagination['per_page'], 'offset' => $pagination['offset']])
|
|
);
|
|
|
|
$statuses = ['pending', 'confirmed', 'processing', 'shipped', 'delivered', 'cancelled', 'refunded'];
|
|
?>
|
|
|
|
<div class="page-header">
|
|
<h1 class="page-title">Orders</h1>
|
|
<a href="/admin/pos.php" class="btn btn-primary">
|
|
<i class="fas fa-plus"></i> New Order (POS)
|
|
</a>
|
|
</div>
|
|
|
|
<?php if (hasFlash('success')): ?>
|
|
<div class="alert alert-success">
|
|
<i class="fas fa-check-circle"></i>
|
|
<?= getFlash('success') ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Filters -->
|
|
<div class="admin-card">
|
|
<div class="admin-card-body">
|
|
<form method="GET" style="display: flex; gap: 1rem; flex-wrap: wrap; align-items: end;">
|
|
<div class="form-group mb-0" style="flex: 1; min-width: 200px;">
|
|
<label class="form-label">Search</label>
|
|
<input type="text" name="search" class="form-input" placeholder="Order #, name, email..."
|
|
value="<?= htmlspecialchars($search) ?>">
|
|
</div>
|
|
|
|
<div class="form-group mb-0">
|
|
<label class="form-label">Status</label>
|
|
<select name="status" class="form-select">
|
|
<option value="">All Statuses</option>
|
|
<?php foreach ($statuses as $s): ?>
|
|
<option value="<?= $s ?>" <?= $status === $s ? 'selected' : '' ?>>
|
|
<?= ucfirst($s) ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group mb-0">
|
|
<label class="form-label">From Date</label>
|
|
<input type="date" name="date_from" class="form-input" value="<?= $dateFrom ?>">
|
|
</div>
|
|
|
|
<div class="form-group mb-0">
|
|
<label class="form-label">To Date</label>
|
|
<input type="date" name="date_to" class="form-input" value="<?= $dateTo ?>">
|
|
</div>
|
|
|
|
<button type="submit" class="btn btn-secondary">
|
|
<i class="fas fa-filter"></i> Filter
|
|
</button>
|
|
|
|
<?php if ($status || $search || $dateFrom || $dateTo): ?>
|
|
<a href="/admin/orders.php" class="btn btn-secondary">Clear</a>
|
|
<?php endif; ?>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Orders Table -->
|
|
<div class="admin-card">
|
|
<div class="admin-card-header">
|
|
<span><?= $totalOrders ?> orders found</span>
|
|
</div>
|
|
<div class="admin-card-body" style="padding: 0;">
|
|
<table class="admin-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Order</th>
|
|
<th>Customer</th>
|
|
<th>Items</th>
|
|
<th>Total</th>
|
|
<th>Payment</th>
|
|
<th>Status</th>
|
|
<th>Date</th>
|
|
<th style="width: 150px;">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($orders)): ?>
|
|
<tr>
|
|
<td colspan="8" class="text-muted" style="text-align: center; padding: 2rem;">
|
|
No orders found
|
|
</td>
|
|
</tr>
|
|
<?php else: ?>
|
|
<?php foreach ($orders as $order):
|
|
$items = json_decode($order['items'], true) ?? [];
|
|
$itemCount = array_sum(array_column($items, 'quantity'));
|
|
?>
|
|
<tr>
|
|
<td>
|
|
<strong><?= htmlspecialchars($order['order_number']) ?></strong>
|
|
<?php if ($order['is_pos_order']): ?>
|
|
<span class="badge badge-primary">POS</span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td>
|
|
<div><?= htmlspecialchars($order['customer_name'] ?? 'Guest') ?></div>
|
|
<small class="text-muted"><?= htmlspecialchars($order['customer_email']) ?></small>
|
|
</td>
|
|
<td><?= $itemCount ?> item<?= $itemCount !== 1 ? 's' : '' ?></td>
|
|
<td><strong><?= formatCurrency($order['total']) ?></strong></td>
|
|
<td>
|
|
<?php
|
|
$paymentClass = match($order['payment_status']) {
|
|
'paid' => 'success',
|
|
'failed' => 'error',
|
|
'refunded' => 'warning',
|
|
default => 'primary'
|
|
};
|
|
?>
|
|
<span class="badge badge-<?= $paymentClass ?>">
|
|
<?= ucfirst($order['payment_status']) ?>
|
|
</span>
|
|
</td>
|
|
<td>
|
|
<?php
|
|
$statusClass = match($order['order_status']) {
|
|
'pending' => 'warning',
|
|
'confirmed', 'processing' => 'primary',
|
|
'shipped', 'delivered' => 'success',
|
|
'cancelled', 'refunded' => 'error',
|
|
default => 'primary'
|
|
};
|
|
?>
|
|
<span class="badge badge-<?= $statusClass ?>">
|
|
<?= ucfirst($order['order_status']) ?>
|
|
</span>
|
|
</td>
|
|
<td class="text-muted"><?= formatDate($order['created_at']) ?></td>
|
|
<td>
|
|
<a href="/admin/order.php?id=<?= $order['order_id'] ?>"
|
|
class="btn btn-sm btn-secondary" title="View">
|
|
<i class="fas fa-eye"></i>
|
|
</a>
|
|
<button type="button" class="btn btn-sm btn-secondary"
|
|
onclick="openStatusModal('<?= $order['order_id'] ?>', '<?= $order['order_status'] ?>')"
|
|
title="Update Status">
|
|
<i class="fas fa-edit"></i>
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
<?php if ($pagination['total_pages'] > 1): ?>
|
|
<div style="display: flex; justify-content: center; margin-top: 1rem;">
|
|
<?= renderPagination($pagination, '/admin/orders.php?status=' . urlencode($status) . '&search=' . urlencode($search)) ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<!-- Status Update Modal -->
|
|
<div class="modal-overlay" id="statusModal">
|
|
<div class="modal">
|
|
<div class="modal-header">
|
|
<h3 class="modal-title">Update Order Status</h3>
|
|
<button type="button" class="modal-close" onclick="Modal.close('statusModal')">×</button>
|
|
</div>
|
|
<form method="POST" action="">
|
|
<div class="modal-body">
|
|
<input type="hidden" name="action" value="update_status">
|
|
<input type="hidden" name="order_id" id="modalOrderId">
|
|
|
|
<div class="form-group">
|
|
<label class="form-label">Status</label>
|
|
<select name="status" id="modalStatus" class="form-select" required>
|
|
<?php foreach ($statuses as $s): ?>
|
|
<option value="<?= $s ?>"><?= ucfirst($s) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="form-group mb-0" id="trackingGroup" style="display: none;">
|
|
<label class="form-label">Tracking Number</label>
|
|
<input type="text" name="tracking_number" class="form-input" placeholder="Enter tracking number">
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-secondary" onclick="Modal.close('statusModal')">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Update Status</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function openStatusModal(orderId, currentStatus) {
|
|
document.getElementById('modalOrderId').value = orderId;
|
|
document.getElementById('modalStatus').value = currentStatus;
|
|
Modal.open('statusModal');
|
|
}
|
|
|
|
document.getElementById('modalStatus').addEventListener('change', function() {
|
|
document.getElementById('trackingGroup').style.display =
|
|
this.value === 'shipped' ? 'block' : 'none';
|
|
});
|
|
</script>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|