363 lines
16 KiB
PHP
363 lines
16 KiB
PHP
<?php
|
|
require_once __DIR__ . '/includes/header.php';
|
|
|
|
// Check permission
|
|
if (function_exists('require_permission')) {
|
|
require_permission('reports_view');
|
|
}
|
|
|
|
$pdo = db();
|
|
|
|
// Date and Outlet Filter
|
|
$startDate = $_GET['start_date'] ?? date('Y-m-d');
|
|
$endDate = $_GET['end_date'] ?? date('Y-m-d');
|
|
$outletId = $_GET['outlet_id'] ?? '';
|
|
|
|
// Fetch Outlets for filter
|
|
$outletsStmt = $pdo->query("SELECT id, name FROM outlets ORDER BY name ASC");
|
|
$allOutlets = $outletsStmt->fetchAll();
|
|
|
|
// Base query additions
|
|
$outletCondition = "";
|
|
$expenseOutletCondition = "";
|
|
$queryParams = [$startDate, $endDate];
|
|
if (!empty($outletId)) {
|
|
$outletCondition = " AND o.outlet_id = ? ";
|
|
$expenseOutletCondition = " AND e.outlet_id = ? ";
|
|
$queryParams[] = $outletId;
|
|
}
|
|
|
|
// 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 ?
|
|
$outletCondition
|
|
GROUP BY o.user_id
|
|
ORDER BY total_sales DESC
|
|
");
|
|
$staffStmt->execute($queryParams);
|
|
$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 ?
|
|
$outletCondition
|
|
GROUP BY o.outlet_id
|
|
ORDER BY total_sales DESC
|
|
");
|
|
$outletStmt->execute($queryParams);
|
|
$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 ?
|
|
$outletCondition
|
|
GROUP BY c.id
|
|
ORDER BY total_sales DESC
|
|
");
|
|
$categoryStmt->execute($queryParams);
|
|
$categorySales = $categoryStmt->fetchAll();
|
|
|
|
// 4. Expenses by Category
|
|
$expenseCatStmt = $pdo->prepare("
|
|
SELECT
|
|
ec.name as category_name,
|
|
SUM(e.amount) as total_amount
|
|
FROM expenses e
|
|
JOIN expense_categories ec ON e.category_id = ec.id
|
|
WHERE e.expense_date BETWEEN ? AND ?
|
|
$expenseOutletCondition
|
|
GROUP BY ec.id
|
|
ORDER BY total_amount DESC
|
|
");
|
|
$expenseCatStmt->execute($queryParams);
|
|
$expenseSales = $expenseCatStmt->fetchAll();
|
|
|
|
// Total Summary
|
|
$totalStmt = $pdo->prepare("
|
|
SELECT
|
|
COUNT(id) as total_orders,
|
|
SUM(total_amount) as total_revenue
|
|
FROM orders o
|
|
WHERE DATE(o.created_at) BETWEEN ? AND ?
|
|
$outletCondition
|
|
");
|
|
$totalStmt->execute($queryParams);
|
|
$summary = $totalStmt->fetch();
|
|
|
|
$totalExpStmt = $pdo->prepare("
|
|
SELECT SUM(amount) as total_expenses
|
|
FROM expenses e
|
|
WHERE expense_date BETWEEN ? AND ?
|
|
$expenseOutletCondition
|
|
");
|
|
$totalExpStmt->execute($queryParams);
|
|
$totalExpenses = $totalExpStmt->fetchColumn() ?? 0;
|
|
|
|
$netProfit = ($summary['total_revenue'] ?? 0) - $totalExpenses;
|
|
?>
|
|
|
|
<div class="container-fluid p-0">
|
|
<div class="d-flex justify-content-between align-items-center mb-4 flex-wrap gap-3">
|
|
<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="row g-2 align-items-center" method="GET">
|
|
<div class="col-auto">
|
|
<select name="outlet_id" class="form-select" style="min-width: 180px;">
|
|
<option value="">All Outlets</option>
|
|
<?php foreach ($allOutlets as $o): ?>
|
|
<option value="<?= $o['id'] ?>" <?= $outletId == $o['id'] ? 'selected' : '' ?>>
|
|
<?= htmlspecialchars($o['name']) ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-auto">
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-white border-end-0 text-muted"><i class="bi bi-calendar"></i></span>
|
|
<input type="date" name="start_date" class="form-control border-start-0" value="<?= htmlspecialchars($startDate) ?>">
|
|
</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<div class="input-group">
|
|
<span class="input-group-text bg-white border-end-0 text-muted"><i class="bi bi-calendar"></i></span>
|
|
<input type="date" name="end_date" class="form-control border-start-0" value="<?= htmlspecialchars($endDate) ?>">
|
|
</div>
|
|
</div>
|
|
<div class="col-auto">
|
|
<div class="d-flex gap-2">
|
|
<button type="submit" class="btn btn-primary px-4 text-nowrap">Filter</button>
|
|
<a href="reports.php" class="btn btn-light text-nowrap">Reset</a>
|
|
</div>
|
|
</div>
|
|
</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 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-danger-subtle text-danger">
|
|
<i class="bi bi-cash-stack"></i>
|
|
</div>
|
|
<div>
|
|
<small class="text-muted d-block">Total Expenses</small>
|
|
<h4 class="fw-bold mb-0"><?= format_currency($totalExpenses) ?></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-info-subtle text-info">
|
|
<i class="bi bi-piggy-bank"></i>
|
|
</div>
|
|
<div>
|
|
<small class="text-muted d-block">Net Profit</small>
|
|
<h4 class="fw-bold mb-0 <?= $netProfit < 0 ? 'text-danger' : 'text-info' ?>"><?= format_currency($netProfit) ?></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-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-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>
|
|
|
|
<!-- Expenses by Category -->
|
|
<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-cash-stack me-2 text-danger"></i> Expenses 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-end pe-3">Total Amount</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php if (empty($expenseSales)): ?>
|
|
<tr><td colspan="2" class="text-center py-4 text-muted">No data found for this period</td></tr>
|
|
<?php else: ?>
|
|
<?php foreach ($expenseSales as $exp): ?>
|
|
<tr>
|
|
<td class="ps-3">
|
|
<div class="fw-bold"><?= htmlspecialchars($exp['category_name']) ?></div>
|
|
</td>
|
|
<td class="text-end pe-3 fw-bold text-danger"><?= format_currency($exp['total_amount']) ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
<?php endif; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|