Autosave: 20260223-093758

This commit is contained in:
Flatlogic Bot 2026-02-23 09:37:58 +00:00
parent 9a50d0a34e
commit 3595e1b23e
4 changed files with 243 additions and 4 deletions

View File

@ -342,6 +342,7 @@ function getGroupToggleClass($pages) {
</div> </div>
</div> </div>
<?php $reportsGroup = ['reports.php']; ?> <div class="nav-group"> <a class="sidebar-heading d-flex justify-content-between align-items-center text-decoration-none <?= getGroupToggleClass($reportsGroup) ?>" data-bs-toggle="collapse" href="#collapseReports" role="button" aria-expanded="<?= isGroupExpanded($reportsGroup) ?>" aria-controls="collapseReports"> <span><i class="bi bi-bar-chart-line"></i> Reports & Analytics</span> <i class="bi bi-chevron-down chevron-icon"></i> </a> <div class="collapse <?= isGroupActive($reportsGroup) ?>" id="collapseReports" data-bs-parent="#sidebarAccordion"> <ul class="nav flex-column"> <li class="nav-item"> <a class="nav-link <?= isActive('reports.php') ?>" href="reports.php"> <i class="bi bi-graph-up me-2"></i> Daily Reports </a> </li> </ul> </div> </div>
<?php $userGroupPages = ['users.php', 'user_edit.php', 'user_groups.php', 'user_group_edit.php']; ?> <?php $userGroupPages = ['users.php', 'user_edit.php', 'user_groups.php', 'user_group_edit.php']; ?>
<div class="nav-group"> <div class="nav-group">
<a class="sidebar-heading d-flex justify-content-between align-items-center text-decoration-none <?= getGroupToggleClass($userGroupPages) ?>" <a class="sidebar-heading d-flex justify-content-between align-items-center text-decoration-none <?= getGroupToggleClass($userGroupPages) ?>"

233
admin/reports.php Normal file
View File

@ -0,0 +1,233 @@
<?php
require_once __DIR__ . '/includes/header.php';
// Check permission
if (function_exists('require_permission')) {
require_permission('manage_reports');
}
$pdo = db();
// Date Filter
$startDate = $_GET['start_date'] ?? date('Y-m-d');
$endDate = $_GET['end_date'] ?? date('Y-m-d');
// 1. Sales by Staff
$staffStmt = $pdo->prepare("
SELECT
u.full_name as staff_name,
u.username,
COUNT(o.id) as order_count,
SUM(o.total_amount) as total_sales
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE DATE(o.created_at) BETWEEN ? AND ?
GROUP BY o.user_id
ORDER BY total_sales DESC
");
$staffStmt->execute([$startDate, $endDate]);
$staffSales = $staffStmt->fetchAll();
// 2. Sales by Outlet
$outletStmt = $pdo->prepare("
SELECT
ot.name as outlet_name,
COUNT(o.id) as order_count,
SUM(o.total_amount) as total_sales
FROM orders o
JOIN outlets ot ON o.outlet_id = ot.id
WHERE DATE(o.created_at) BETWEEN ? AND ?
GROUP BY o.outlet_id
ORDER BY total_sales DESC
");
$outletStmt->execute([$startDate, $endDate]);
$outletSales = $outletStmt->fetchAll();
// 3. Sales by Category
$categoryStmt = $pdo->prepare("
SELECT
c.name as category_name,
SUM(oi.quantity) as items_sold,
SUM(oi.quantity * oi.unit_price) as total_sales
FROM order_items oi
JOIN orders o ON oi.order_id = o.id
JOIN products p ON oi.product_id = p.id
JOIN categories c ON p.category_id = c.id
WHERE DATE(o.created_at) BETWEEN ? AND ?
GROUP BY c.id
ORDER BY total_sales DESC
");
$categoryStmt->execute([$startDate, $endDate]);
$categorySales = $categoryStmt->fetchAll();
// Total Summary
$totalStmt = $pdo->prepare("
SELECT
COUNT(id) as total_orders,
SUM(total_amount) as total_revenue
FROM orders
WHERE DATE(created_at) BETWEEN ? AND ?
");
$totalStmt->execute([$startDate, $endDate]);
$summary = $totalStmt->fetch();
?>
<div class="container-fluid p-0">
<div class="d-flex justify-content-between align-items-center mb-4">
<div>
<h2 class="fw-bold mb-1">Daily Reports</h2>
<p class="text-muted mb-0">Overview of your business performance</p>
</div>
<form class="d-flex gap-2" method="GET">
<input type="date" name="start_date" class="form-control" value="<?= htmlspecialchars($startDate) ?>">
<input type="date" name="end_date" class="form-control" value="<?= htmlspecialchars($endDate) ?>">
<button type="submit" class="btn btn-primary">Filter</button>
</form>
</div>
<!-- Summary Cards -->
<div class="row g-3 mb-4">
<div class="col-md-6 col-lg-3">
<div class="card border-0 shadow-sm stat-card p-3">
<div class="d-flex align-items-center gap-3">
<div class="icon-box bg-primary-subtle text-primary">
<i class="bi bi-receipt"></i>
</div>
<div>
<small class="text-muted d-block">Total Orders</small>
<h4 class="fw-bold mb-0"><?= number_format((float)($summary['total_orders'] ?? 0)) ?></h4>
</div>
</div>
</div>
</div>
<div class="col-md-6 col-lg-3">
<div class="card border-0 shadow-sm stat-card p-3">
<div class="d-flex align-items-center gap-3">
<div class="icon-box bg-success-subtle text-success">
<i class="bi bi-currency-dollar"></i>
</div>
<div>
<small class="text-muted d-block">Total Revenue</small>
<h4 class="fw-bold mb-0"><?= format_currency($summary['total_revenue'] ?? 0) ?></h4>
</div>
</div>
</div>
</div>
</div>
<div class="row g-4">
<!-- Sales by Staff -->
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0"><i class="bi bi-people me-2 text-primary"></i> Sales by Staff</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Staff Name</th>
<th class="text-center">Orders</th>
<th class="text-end pe-3">Total Sales</th>
</tr>
</thead>
<tbody>
<?php if (empty($staffSales)): ?>
<tr><td colspan="3" class="text-center py-4 text-muted">No data found for this period</td></tr>
<?php else: ?>
<?php foreach ($staffSales as $staff): ?>
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($staff['staff_name'] ?: $staff['username']) ?></div>
</td>
<td class="text-center"><?= $staff['order_count'] ?></td>
<td class="text-end pe-3 fw-bold text-primary"><?= format_currency($staff['total_sales']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Sales by Outlet -->
<div class="col-md-6">
<div class="card border-0 shadow-sm h-100">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0"><i class="bi bi-shop me-2 text-success"></i> Sales by Outlet</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Outlet</th>
<th class="text-center">Orders</th>
<th class="text-end pe-3">Total Sales</th>
</tr>
</thead>
<tbody>
<?php if (empty($outletSales)): ?>
<tr><td colspan="3" class="text-center py-4 text-muted">No data found for this period</td></tr>
<?php else: ?>
<?php foreach ($outletSales as $outlet): ?>
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($outlet['outlet_name']) ?></div>
</td>
<td class="text-center"><?= $outlet['order_count'] ?></td>
<td class="text-end pe-3 fw-bold text-success"><?= format_currency($outlet['total_sales']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Sales by Category -->
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-header bg-white py-3 border-0">
<h5 class="fw-bold mb-0"><i class="bi bi-tags me-2 text-warning"></i> Sales by Category</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3">Category</th>
<th class="text-center">Items Sold</th>
<th class="text-end pe-3">Total Revenue</th>
</tr>
</thead>
<tbody>
<?php if (empty($categorySales)): ?>
<tr><td colspan="3" class="text-center py-4 text-muted">No data found for this period</td></tr>
<?php else: ?>
<?php foreach ($categorySales as $cat): ?>
<tr>
<td class="ps-3">
<div class="fw-bold"><?= htmlspecialchars($cat['category_name']) ?></div>
</td>
<td class="text-center"><?= $cat['items_sold'] ?></td>
<td class="text-end pe-3 fw-bold text-dark"><?= format_currency($cat['total_sales']) ?></td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<?php require_once __DIR__ . '/includes/footer.php'; ?>

View File

@ -120,6 +120,9 @@ try {
} }
// Payment Type // Payment Type
$user = get_logged_user();
$user_id = $user ? $user['id'] : null;
$payment_type_id = isset($data['payment_type_id']) ? intval($data['payment_type_id']) : null; $payment_type_id = isset($data['payment_type_id']) ? intval($data['payment_type_id']) : null;
$discount = isset($data['discount']) ? floatval($data['discount']) : 0.00; $discount = isset($data['discount']) ? floatval($data['discount']) : 0.00;
@ -149,12 +152,12 @@ try {
$stmt = $pdo->prepare("UPDATE orders SET $stmt = $pdo->prepare("UPDATE orders SET
outlet_id = ?, table_id = ?, table_number = ?, order_type = ?, outlet_id = ?, table_id = ?, table_number = ?, order_type = ?,
customer_id = ?, customer_name = ?, customer_phone = ?, customer_id = ?, customer_name = ?, customer_phone = ?,
payment_type_id = ?, total_amount = ?, discount = ?, status = 'pending' payment_type_id = ?, total_amount = ?, discount = ?, user_id = ?, status = 'pending'
WHERE id = ?"); WHERE id = ?");
$stmt->execute([ $stmt->execute([
$outlet_id, $table_id, $table_number, $order_type, $outlet_id, $table_id, $table_number, $order_type,
$customer_id, $customer_name, $customer_phone, $customer_id, $customer_name, $customer_phone,
$payment_type_id, $total_amount, $discount, $payment_type_id, $total_amount, $discount, $user_id,
$order_id $order_id
]); ]);
@ -164,8 +167,8 @@ try {
} else { } else {
// INSERT New Order // INSERT New Order
$stmt = $pdo->prepare("INSERT INTO orders (outlet_id, table_id, table_number, order_type, customer_id, customer_name, customer_phone, payment_type_id, total_amount, discount, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')"); $stmt = $pdo->prepare("INSERT INTO orders (outlet_id, table_id, table_number, order_type, customer_id, customer_name, customer_phone, payment_type_id, total_amount, discount, user_id, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'pending')");
$stmt->execute([$outlet_id, $table_id, $table_number, $order_type, $customer_id, $customer_name, $customer_phone, $payment_type_id, $total_amount, $discount]); $stmt->execute([$outlet_id, $table_id, $table_number, $order_type, $customer_id, $customer_name, $customer_phone, $payment_type_id, $total_amount, $discount, $user_id]);
$order_id = $pdo->lastInsertId(); $order_id = $pdo->lastInsertId();
} }

View File

@ -0,0 +1,2 @@
ALTER TABLE orders ADD COLUMN user_id INT(11) NULL AFTER outlet_id;
ALTER TABLE orders ADD CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL;