314 lines
17 KiB
PHP
314 lines
17 KiB
PHP
<?php
|
|
require_once __DIR__ . '/includes/app.php';
|
|
$user = require_permission('reports', 'show');
|
|
$pageTitle = tr('التقارير', 'Reports');
|
|
$activeNav = 'reports';
|
|
|
|
$tab = $_GET['tab'] ?? 'summary';
|
|
$dbError = null;
|
|
|
|
if ($tab === 'sales') {
|
|
$dateFrom = $_GET['date_from'] ?? date('Y-m-01');
|
|
$dateTo = $_GET['date_to'] ?? date('Y-m-t');
|
|
$branchFilter = $_GET['branch'] ?? '';
|
|
|
|
$params = [];
|
|
$where = base_sales_query_filters($params, null, $branchFilter ?: null);
|
|
$where .= ' AND DATE(sale_date) >= :date_from AND DATE(sale_date) <= :date_to';
|
|
$params[':date_from'] = $dateFrom;
|
|
$params[':date_to'] = $dateTo;
|
|
|
|
$sql = 'SELECT * FROM sales_orders' . $where . ' ORDER BY sale_date DESC';
|
|
try {
|
|
$stmt = db()->prepare($sql);
|
|
foreach ($params as $k => $v) {
|
|
$stmt->bindValue($k, $v);
|
|
}
|
|
$stmt->execute();
|
|
$salesReport = $stmt->fetchAll();
|
|
} catch(Throwable $e) {
|
|
$dbError = $e->getMessage();
|
|
$salesReport = [];
|
|
}
|
|
} elseif ($tab === 'orders') {
|
|
$branchFilter = $_GET['branch'] ?? '';
|
|
$params = [];
|
|
$where = base_sales_query_filters($params, null, $branchFilter ?: null);
|
|
$where .= " AND status = 'order'";
|
|
|
|
$sql = 'SELECT * FROM sales_orders' . $where . ' ORDER BY sale_date ASC';
|
|
try {
|
|
$stmt = db()->prepare($sql);
|
|
foreach ($params as $k => $v) {
|
|
$stmt->bindValue($k, $v);
|
|
}
|
|
$stmt->execute();
|
|
$followUpOrders = $stmt->fetchAll();
|
|
} catch(Throwable $e) {
|
|
$dbError = $e->getMessage();
|
|
$followUpOrders = [];
|
|
}
|
|
} else {
|
|
$report = ['gross' => 0.0, 'branch_totals' => [], 'payment_totals' => [], 'product_totals' => [], 'sales_count' => 0];
|
|
try {
|
|
$report = report_metrics();
|
|
} catch (Throwable $e) {
|
|
$dbError = $e->getMessage();
|
|
}
|
|
}
|
|
|
|
require __DIR__ . '/includes/header.php';
|
|
?>
|
|
|
|
<div class="d-flex justify-content-between align-items-center mb-4 d-print-none">
|
|
<div>
|
|
<h1 class="h3 mb-0"><?= h($pageTitle) ?></h1>
|
|
</div>
|
|
</div>
|
|
|
|
<ul class="nav nav-tabs mb-4 d-print-none">
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= $tab === 'summary' ? 'active' : '' ?>" href="reports.php?tab=summary"><?= h(tr('ملخص عام', 'General Summary')) ?></a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= $tab === 'sales' ? 'active' : '' ?>" href="reports.php?tab=sales"><?= h(tr('تقرير المبيعات', 'Sales Report')) ?></a>
|
|
</li>
|
|
<li class="nav-item">
|
|
<a class="nav-link <?= $tab === 'orders' ? 'active' : '' ?>" href="reports.php?tab=orders"><?= h(tr('طلبات للمتابعة', 'Follow-up Orders')) ?></a>
|
|
</li>
|
|
</ul>
|
|
|
|
<?php if ($dbError): ?>
|
|
<div class="alert alert-danger d-print-none"><?= h($dbError) ?></div>
|
|
<?php endif; ?>
|
|
|
|
<?php if ($tab === 'sales'): ?>
|
|
|
|
<div class="card mb-4 d-print-none">
|
|
<div class="card-body">
|
|
<form method="GET" action="reports.php" class="row g-3 align-items-end">
|
|
<input type="hidden" name="tab" value="sales">
|
|
<div class="col-md-3">
|
|
<label class="form-label"><?= h(tr('من تاريخ', 'From Date')) ?></label>
|
|
<input type="date" name="date_from" class="form-control" value="<?= h($dateFrom) ?>">
|
|
</div>
|
|
<div class="col-md-3">
|
|
<label class="form-label"><?= h(tr('إلى تاريخ', 'To Date')) ?></label>
|
|
<input type="date" name="date_to" class="form-control" value="<?= h($dateTo) ?>">
|
|
</div>
|
|
<div class="col-md-4">
|
|
<label class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
|
|
<select name="branch" class="form-select">
|
|
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
|
|
<?php
|
|
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
|
|
foreach ($availableBranches as $code => $b):
|
|
?>
|
|
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="submit" class="btn btn-primary w-100"><?= h(tr('بحث', 'Search')) ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-none d-print-block mb-4 text-center">
|
|
<h2><?= h(tr('تقرير المبيعات', 'Sales Report')) ?></h2>
|
|
<p><?= h(tr('الفترة من', 'Period from')) ?> <?= h($dateFrom) ?> <?= h(tr('إلى', 'to')) ?> <?= h($dateTo) ?></p>
|
|
<?php if ($branchFilter): ?>
|
|
<p><?= h(tr('الفرع:', 'Branch:')) ?> <?= h(branch_label($branchFilter)) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="surface-card">
|
|
<div class="d-flex justify-content-between align-items-center mb-3 d-print-none">
|
|
<h3 class="h5 mb-0"><?= h(tr('نتائج التقرير', 'Report Results')) ?></h3>
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="window.print()"><i class="bi bi-printer"></i> <?= h(tr('طباعة', 'Print')) ?></button>
|
|
</div>
|
|
|
|
<?php if(empty($salesReport)): ?>
|
|
<p class="text-muted"><?= h(tr('لا توجد مبيعات في هذه الفترة.', 'No sales found in this period.')) ?></p>
|
|
<?php else: ?>
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-striped align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th><?= h(tr('التاريخ', 'Date')) ?></th>
|
|
<th><?= h(tr('رقم الإيصال', 'Receipt No')) ?></th>
|
|
<th><?= h(tr('الكاشير', 'Cashier')) ?></th>
|
|
<th><?= h(tr('الفرع', 'Branch')) ?></th>
|
|
<th><?= h(tr('طريقة الدفع', 'Payment Method')) ?></th>
|
|
<th><?= h(tr('الحالة', 'Status')) ?></th>
|
|
<th class="text-end"><?= h(tr('المجموع', 'Subtotal')) ?></th>
|
|
<th class="text-end"><?= h(tr('الضريبة', 'VAT')) ?></th>
|
|
<th class="text-end"><?= h(tr('الإجمالي', 'Total')) ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php
|
|
$subtotalSum = 0;
|
|
$vatSum = 0;
|
|
$totalSum = 0;
|
|
foreach($salesReport as $sale):
|
|
$subtotalSum += (float) ($sale['subtotal'] ?? 0);
|
|
$vatSum += (float) ($sale['vat_amount'] ?? 0);
|
|
$totalSum += (float) $sale['total_amount'];
|
|
?>
|
|
<tr>
|
|
<td><?= h(date('Y-m-d H:i', strtotime((string)$sale['sale_date']))) ?></td>
|
|
<td><?= h((string)$sale['receipt_no']) ?></td>
|
|
<td><?= h((string)$sale['cashier_name']) ?></td>
|
|
<td><?= h(branch_label((string)$sale['branch_code'])) ?></td>
|
|
<td><?= h(ucfirst((string)$sale['payment_method'])) ?></td>
|
|
<td>
|
|
<?php if (($sale['status'] ?? 'completed') === 'order'): ?>
|
|
<span class="badge bg-warning text-dark"><i class="bi bi-clock"></i> <?= h(tr('طلب حجز', 'Order')) ?></span>
|
|
<?php else: ?>
|
|
<span class="badge bg-success"><i class="bi bi-check-circle"></i> <?= h(tr('مدفوع', 'Paid')) ?></span>
|
|
<?php endif; ?>
|
|
</td>
|
|
<td class="text-end"><?= h(currency((float)($sale['subtotal'] ?? 0))) ?></td>
|
|
<td class="text-end"><?= h(currency((float)($sale['vat_amount'] ?? 0))) ?></td>
|
|
<td class="text-end fw-bold"><?= h(currency((float)$sale['total_amount'])) ?></td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
<tfoot class="table-dark">
|
|
<tr>
|
|
<td colspan="6" class="text-end"><?= h(tr('الإجمالي الكلي', 'Grand Total')) ?></td>
|
|
<td class="text-end fw-bold fs-6"><?= h(currency($subtotalSum)) ?></td>
|
|
<td class="text-end fw-bold fs-6"><?= h(currency($vatSum)) ?></td>
|
|
<td class="text-end fw-bold fs-5"><?= h(currency($totalSum)) ?></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<?php elseif ($tab === 'orders'): ?>
|
|
|
|
<div class="card mb-4 d-print-none">
|
|
<div class="card-body">
|
|
<form method="GET" action="reports.php" class="row g-3 align-items-end">
|
|
<input type="hidden" name="tab" value="orders">
|
|
<div class="col-md-4">
|
|
<label class="form-label"><?= h(tr('الفرع', 'Branch')) ?></label>
|
|
<select name="branch" class="form-select" onchange="this.form.submit()">
|
|
<option value=""><?= h(tr('جميع الفروع', 'All Branches')) ?></option>
|
|
<?php
|
|
$availableBranches = $user['role'] === 'owner' ? branches() : [$user['branch_code'] => branches()[$user['branch_code']]];
|
|
foreach ($availableBranches as $code => $b):
|
|
?>
|
|
<option value="<?= h($code) ?>" <?= $branchFilter === $code ? 'selected' : '' ?>><?= h(branch_label($code)) ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-none d-print-block mb-4 text-center">
|
|
<h2><?= h(tr('طلبات للمتابعة', 'Follow-up Orders')) ?></h2>
|
|
<p><?= h(date('Y-m-d H:i')) ?></p>
|
|
<?php if ($branchFilter): ?>
|
|
<p><?= h(tr('الفرع:', 'Branch:')) ?> <?= h(branch_label($branchFilter)) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="surface-card">
|
|
<div class="d-flex justify-content-between align-items-center mb-3 d-print-none">
|
|
<h3 class="h5 mb-0"><?= h(tr('طلبات حجز بانتظار الدفع', 'Reservation orders pending payment')) ?></h3>
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="window.print()"><i class="bi bi-printer"></i> <?= h(tr('طباعة', 'Print')) ?></button>
|
|
</div>
|
|
|
|
<?php if(empty($followUpOrders)): ?>
|
|
<p class="text-muted"><?= h(tr('لا توجد طلبات للمتابعة.', 'No follow-up orders.')) ?></p>
|
|
<?php else: ?>
|
|
<div class="table-responsive">
|
|
<table class="table table-bordered table-hover align-middle">
|
|
<thead>
|
|
<tr>
|
|
<th><?= h(tr('التاريخ', 'Date')) ?></th>
|
|
<th><?= h(tr('رقم الإيصال', 'Receipt No')) ?></th>
|
|
<th><?= h(tr('العميل', 'Customer')) ?></th>
|
|
<th><?= h(tr('هاتف العميل', 'Customer Phone')) ?></th>
|
|
<th><?= h(tr('الفرع', 'Branch')) ?></th>
|
|
<th class="text-end"><?= h(tr('المبلغ المستحق', 'Due Amount')) ?></th>
|
|
<th class="d-print-none text-end"><?= h(tr('إجراءات', 'Actions')) ?></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<?php foreach($followUpOrders as $sale): ?>
|
|
<tr>
|
|
<td><?= h(date('Y-m-d H:i', strtotime((string)$sale['sale_date']))) ?></td>
|
|
<td><?= h((string)$sale['receipt_no']) ?></td>
|
|
<td><?= h((string)($sale['customer_name'] ?: '-')) ?></td>
|
|
<td><?= h((string)($sale['customer_phone'] ?: '-')) ?></td>
|
|
<td><?= h(branch_label((string)$sale['branch_code'])) ?></td>
|
|
<td class="text-end fw-bold text-danger"><?= h(currency((float)$sale['total_amount'])) ?></td>
|
|
<td class="d-print-none text-end">
|
|
<a class="btn btn-sm btn-light border" href="<?= h(url_for('sale.php', ['id' => $sale['id']])) ?>"><?= h(tr('عرض', 'View')) ?></a>
|
|
<button class="btn btn-sm btn-success" onclick="markPaidFromReports(<?= $sale['id'] ?>)"><i class="bi bi-check-lg"></i> <?= h(tr('دفع', 'Pay')) ?></button>
|
|
</td>
|
|
</tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<script>
|
|
function markPaidFromReports(id) {
|
|
if(confirm("<?= h(tr('هل أنت متأكد من تأكيد دفع هذا الطلب؟', 'Are you sure you want to confirm payment for this order?')) ?>")) {
|
|
window.location.href = 'sales.php?mark_paid=' + id + '&redirect=reports.php?tab=orders';
|
|
}
|
|
}
|
|
</script>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<?php else: ?>
|
|
|
|
<section class="row g-3 mb-4 d-print-none">
|
|
<div class="col-md-3"><article class="metric-card"><div class="eyebrow"><?= h(tr('إجمالي المبيعات', 'Gross sales')) ?></div><div class="metric-value"><?= h(currency((float) $report['gross'])) ?></div><div class="small text-muted"><?= h(tr('حسب نطاق صلاحية المستخدم الحالي', 'Scoped to the current viewer permissions')) ?></div></article></div>
|
|
<div class="col-md-3"><article class="metric-card"><div class="eyebrow"><?= h(tr('إجمالي الضريبة', 'Total VAT')) ?></div><div class="metric-value"><?= h(currency((float) ($report['total_vat'] ?? 0))) ?></div><div class="small text-muted"><?= h(tr('مجموع ضريبة القيمة المضافة', 'Total Value Added Tax')) ?></div></article></div>
|
|
<div class="col-md-3"><article class="metric-card"><div class="eyebrow"><?= h(tr('عدد الفواتير', 'Invoices')) ?></div><div class="metric-value"><?= h((string) $report['sales_count']) ?></div><div class="small text-muted"><?= h(tr('إجمالي الفواتير المسجلة', 'Total logged invoices')) ?></div></article></div>
|
|
<div class="col-md-3"><article class="metric-card"><div class="eyebrow"><?= h(tr('أفضل صنف', 'Top product')) ?></div><div class="metric-value small-metric"><?= h($report['product_totals'] ? product_label((string) array_key_first($report['product_totals'])) : tr('لا يوجد', 'None yet')) ?></div><div class="small text-muted"><?= h(tr('الأكثر مبيعاً حتى الآن', 'Most sold item so far')) ?></div></article></div>
|
|
</section>
|
|
<section class="row g-4 d-print-none">
|
|
<div class="col-lg-6">
|
|
<div class="surface-card h-100">
|
|
<h3 class="h5 mb-3"><?= h(tr('المبيعات حسب الفرع', 'Sales by branch')) ?></h3>
|
|
<?php if (!$report['branch_totals']): ?>
|
|
<div class="empty-state compact"><h4><?= h(tr('لا توجد بيانات', 'No data')) ?></h4><p><?= h(tr('أضف عملية بيع أولاً لبدء التقارير.', 'Add a first sale to activate reports.')) ?></p></div>
|
|
<?php else: ?>
|
|
<div class="d-grid gap-2">
|
|
<?php foreach ($report['branch_totals'] as $branchCode => $amount): ?>
|
|
<div class="report-row"><span><?= h(branch_label((string) $branchCode)) ?></span><strong><?= h(currency((float) $amount)) ?></strong></div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="surface-card h-100">
|
|
<h3 class="h5 mb-3"><?= h(tr('المبيعات حسب الدفع', 'Sales by payment')) ?></h3>
|
|
<?php if (!$report['payment_totals']): ?>
|
|
<div class="empty-state compact"><h4><?= h(tr('بانتظار البيانات', 'Waiting for data')) ?></h4><p><?= h(tr('عند تسجيل عمليات بيع ستظهر هنا طرق الدفع.', 'Payment mix will appear here once sales are logged.')) ?></p></div>
|
|
<?php else: ?>
|
|
<div class="d-grid gap-2">
|
|
<?php foreach ($report['payment_totals'] as $payment => $amount): ?>
|
|
<div class="report-row"><span><?= h(ucfirst((string) $payment)) ?></span><strong><?= h(currency((float) $amount)) ?></strong></div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<?php endif; ?>
|
|
|
|
<?php require __DIR__ . '/includes/footer.php'; ?>
|