588 lines
30 KiB
PHP
588 lines
30 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 = [];
|
|
}
|
|
} elseif ($tab === 'daily') {
|
|
$reportDate = $_GET['date'] ?? date('Y-m-d');
|
|
$branchFilter = $_GET['branch'] ?? '';
|
|
|
|
$params = [];
|
|
$where = base_sales_query_filters($params, null, $branchFilter ?: null);
|
|
$where .= " AND DATE(sale_date) = :rdate AND status != 'order'";
|
|
$params[':rdate'] = $reportDate;
|
|
|
|
$dailyTotals = [
|
|
'seller' => [],
|
|
'outlet' => [],
|
|
'payment' => [],
|
|
'total' => 0
|
|
];
|
|
|
|
try {
|
|
// By Seller
|
|
$sql = "SELECT cashier_name, SUM(total_amount) as total FROM sales_orders" . $where . " GROUP BY cashier_name";
|
|
$stmt = db()->prepare($sql);
|
|
$stmt->execute($params);
|
|
$dailyTotals['seller'] = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
|
|
// By Outlet
|
|
$sql = "SELECT branch_code, SUM(total_amount) as total FROM sales_orders" . $where . " GROUP BY branch_code";
|
|
$stmt = db()->prepare($sql);
|
|
$stmt->execute($params);
|
|
$dailyTotals['outlet'] = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
|
|
// By Payment
|
|
$sql = "SELECT payment_method, SUM(total_amount) as total FROM sales_orders" . $where . " GROUP BY payment_method";
|
|
$stmt = db()->prepare($sql);
|
|
$stmt->execute($params);
|
|
$dailyTotals['payment'] = $stmt->fetchAll(PDO::FETCH_KEY_PAIR);
|
|
|
|
// Grand total
|
|
$sql = "SELECT SUM(total_amount) as total FROM sales_orders" . $where;
|
|
$stmt = db()->prepare($sql);
|
|
$stmt->execute($params);
|
|
$dailyTotals['total'] = (float) $stmt->fetchColumn();
|
|
|
|
} catch(Throwable $e) {
|
|
$dbError = $e->getMessage();
|
|
}
|
|
} 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 === 'daily' ? 'active' : '' ?>" href="reports.php?tab=daily"><?= h(tr('التقرير اليومي', 'Daily Report')) ?></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):
|
|
$vat = (float) ($sale['vat_amount'] ?? 0);
|
|
$total = (float) $sale['total_amount'];
|
|
$calcSubtotal = $total - $vat;
|
|
|
|
$subtotalSum += $calcSubtotal;
|
|
$vatSum += $vat;
|
|
$totalSum += $total;
|
|
?>
|
|
<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($calcSubtotal)) ?></td>
|
|
<td class="text-end"><?= h(currency($vat)) ?></td>
|
|
<td class="text-end fw-bold"><?= h(currency($total)) ?></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 elseif ($tab === 'daily'): ?>
|
|
|
|
<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="daily">
|
|
<div class="col-md-4">
|
|
<label class="form-label"><?= h(tr('التاريخ', 'Date')) ?></label>
|
|
<input type="date" name="date" class="form-control" value="<?= h($reportDate) ?>" onchange="this.form.submit()">
|
|
</div>
|
|
<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>
|
|
<div class="col-md-2">
|
|
<button type="submit" class="btn btn-primary w-100"><?= h(tr('بحث', 'Search')) ?></button>
|
|
</div>
|
|
<div class="col-md-2">
|
|
<button type="button" class="btn btn-outline-secondary w-100" onclick="window.print()"><i class="bi bi-printer"></i> <?= h(tr('طباعة', 'Print')) ?></button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="d-none d-print-block mb-4 text-center">
|
|
<h2><?= h(tr('التقرير اليومي', 'Daily Report')) ?></h2>
|
|
<p><?= h(tr('التاريخ:', 'Date:')) ?> <?= h($reportDate) ?></p>
|
|
<?php if ($branchFilter): ?>
|
|
<p><?= h(tr('الفرع:', 'Branch:')) ?> <?= h(branch_label($branchFilter)) ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<?php if ($dailyTotals['total'] == 0): ?>
|
|
<div class="alert alert-info"><?= h(tr('لا توجد مبيعات في هذا اليوم.', 'No sales on this day.')) ?></div>
|
|
<?php else: ?>
|
|
<div class="row g-4 mb-4">
|
|
<!-- Total Card -->
|
|
<div class="col-12">
|
|
<div class="surface-card text-center py-4 bg-primary text-white rounded shadow-sm">
|
|
<h3 class="h5 mb-2"><?= h(tr('إجمالي المبيعات', 'Total Sales')) ?></h3>
|
|
<div class="fs-1 fw-bold"><?= h(currency($dailyTotals['total'])) ?></div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- By Seller -->
|
|
<div class="col-md-4">
|
|
<div class="surface-card h-100 shadow-sm">
|
|
<h3 class="h5 mb-3 border-bottom pb-2"><i class="bi bi-person me-2 text-primary"></i><?= h(tr('حسب الموظف', 'By Seller')) ?></h3>
|
|
<ul class="list-group list-group-flush">
|
|
<?php foreach($dailyTotals['seller'] as $seller => $amount): ?>
|
|
<li class="list-group-item d-flex justify-content-between align-items-center px-0 bg-transparent">
|
|
<span><?= h($seller ?: tr('غير محدد', 'Unknown')) ?></span>
|
|
<span class="fw-bold"><?= h(currency((float)$amount)) ?></span>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- By Outlet -->
|
|
<div class="col-md-4">
|
|
<div class="surface-card h-100 shadow-sm">
|
|
<h3 class="h5 mb-3 border-bottom pb-2"><i class="bi bi-shop me-2 text-primary"></i><?= h(tr('حسب الفرع', 'By Outlet')) ?></h3>
|
|
<ul class="list-group list-group-flush">
|
|
<?php foreach($dailyTotals['outlet'] as $outlet => $amount): ?>
|
|
<li class="list-group-item d-flex justify-content-between align-items-center px-0 bg-transparent">
|
|
<span><?= h(branch_label((string)$outlet)) ?></span>
|
|
<span class="fw-bold"><?= h(currency((float)$amount)) ?></span>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- By Payment -->
|
|
<div class="col-md-4">
|
|
<div class="surface-card h-100 shadow-sm">
|
|
<h3 class="h5 mb-3 border-bottom pb-2"><i class="bi bi-credit-card me-2 text-primary"></i><?= h(tr('حسب طريقة الدفع', 'By Payment')) ?></h3>
|
|
<ul class="list-group list-group-flush">
|
|
<?php
|
|
$payLabels = ['cash' => tr('كاش', 'Cash'), 'card' => tr('بطاقة', 'Card'), 'bank' => tr('تحويل بنكي', 'Bank'), 'mixed' => tr('متعدد', 'Mixed')];
|
|
foreach($dailyTotals['payment'] as $payment => $amount):
|
|
?>
|
|
<li class="list-group-item d-flex justify-content-between align-items-center px-0 bg-transparent">
|
|
<span><?= h($payLabels[$payment] ?? ucfirst($payment)) ?></span>
|
|
<span class="fw-bold"><?= h(currency((float)$amount)) ?></span>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php else: ?>
|
|
|
|
<!-- Top KPIs -->
|
|
<section class="row g-3 mb-4 d-print-none">
|
|
<div class="col-md-3">
|
|
<article class="metric-card d-flex align-items-center h-100">
|
|
<div class="me-3 fs-1 text-primary"><i class="bi bi-wallet2"></i></div>
|
|
<div>
|
|
<div class="eyebrow text-muted mb-1"><?= h(tr('إجمالي المبيعات', 'Gross sales')) ?></div>
|
|
<div class="metric-value fs-4 fw-bold"><?= h(currency((float) $report['gross'])) ?></div>
|
|
<div class="small text-muted" style="font-size:0.8rem;"><?= h(tr('شامل جميع العمليات', 'Includes all transactions')) ?></div>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<article class="metric-card d-flex align-items-center h-100">
|
|
<div class="me-3 fs-1 text-info"><i class="bi bi-receipt"></i></div>
|
|
<div>
|
|
<div class="eyebrow text-muted mb-1"><?= h(tr('إجمالي الضريبة', 'Total VAT')) ?></div>
|
|
<div class="metric-value fs-4 fw-bold"><?= h(currency((float) ($report['total_vat'] ?? 0))) ?></div>
|
|
<div class="small text-muted" style="font-size:0.8rem;"><?= h(tr('مجموع ضريبة القيمة المضافة', 'Total Value Added Tax')) ?></div>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<article class="metric-card d-flex align-items-center h-100">
|
|
<div class="me-3 fs-1 text-success"><i class="bi bi-basket3"></i></div>
|
|
<div>
|
|
<div class="eyebrow text-muted mb-1"><?= h(tr('عدد الفواتير', 'Invoices')) ?></div>
|
|
<div class="metric-value fs-4 fw-bold"><?= h((string) $report['sales_count']) ?></div>
|
|
<div class="small text-muted" style="font-size:0.8rem;"><?= h(tr('إجمالي الفواتير المسجلة', 'Total logged invoices')) ?></div>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
<div class="col-md-3">
|
|
<article class="metric-card d-flex align-items-center h-100">
|
|
<div class="me-3 fs-1 text-warning"><i class="bi bi-star"></i></div>
|
|
<div class="overflow-hidden">
|
|
<div class="eyebrow text-muted mb-1"><?= h(tr('أفضل صنف', 'Top product')) ?></div>
|
|
<div class="metric-value fs-5 fw-bold text-truncate" style="max-width: 150px;"><?= h($report['product_totals'] ? product_label((string) array_key_first($report['product_totals'])) : tr('لا يوجد', 'None yet')) ?></div>
|
|
<div class="small text-muted" style="font-size:0.8rem;"><?= h(tr('الأكثر مبيعاً حتى الآن', 'Most sold item so far')) ?></div>
|
|
</div>
|
|
</article>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- Charts and Breakdowns -->
|
|
<section class="row g-4 d-print-none">
|
|
|
|
<!-- Trend Chart -->
|
|
<div class="col-lg-12">
|
|
<div class="surface-card h-100">
|
|
<h3 class="h5 mb-3"><i class="bi bi-graph-up-arrow me-2 text-primary"></i><?= h(tr('أداء المبيعات الشهري', 'Monthly Sales Performance')) ?></h3>
|
|
<?php if (!$report['monthly_totals']): ?>
|
|
<div class="empty-state compact"><h4><?= h(tr('لا توجد بيانات', 'No data')) ?></h4></div>
|
|
<?php else: ?>
|
|
<canvas id="monthlySalesChart" height="80"></canvas>
|
|
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const ctx = document.getElementById('monthlySalesChart').getContext('2d');
|
|
const rawData = <?= json_encode($report['monthly_totals']) ?>;
|
|
const labels = Object.keys(rawData);
|
|
const data = Object.values(rawData);
|
|
|
|
new Chart(ctx, {
|
|
type: 'line',
|
|
data: {
|
|
labels: labels,
|
|
datasets: [{
|
|
label: '<?= h(tr('المبيعات', 'Sales')) ?>',
|
|
data: data,
|
|
borderColor: '#0d6efd',
|
|
backgroundColor: 'rgba(13, 110, 253, 0.1)',
|
|
borderWidth: 3,
|
|
fill: true,
|
|
tension: 0.4,
|
|
pointBackgroundColor: '#0d6efd',
|
|
pointRadius: 4,
|
|
pointHoverRadius: 6
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
plugins: { legend: { display: false } },
|
|
scales: { y: { beginAtZero: true } },
|
|
interaction: {
|
|
intersect: false,
|
|
mode: 'index',
|
|
},
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-6">
|
|
<div class="surface-card h-100">
|
|
<h3 class="h5 mb-4"><i class="bi bi-shop me-2 text-primary"></i><?= 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-3">
|
|
<?php
|
|
foreach ($report['branch_totals'] as $branchCode => $amount):
|
|
$percent = $report['gross'] > 0 ? ($amount / $report['gross']) * 100 : 0;
|
|
?>
|
|
<div>
|
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
|
<span class="fw-bold fs-6"><?= h(branch_label((string) $branchCode)) ?></span>
|
|
<div class="text-end">
|
|
<strong class="d-block"><?= h(currency((float) $amount)) ?></strong>
|
|
<small class="text-muted"><?= round($percent, 1) ?>%</small>
|
|
</div>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-primary rounded-pill" role="progressbar" style="width: <?= $percent ?>%"></div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-lg-6">
|
|
<div class="surface-card h-100">
|
|
<h3 class="h5 mb-4"><i class="bi bi-credit-card me-2 text-primary"></i><?= 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-3">
|
|
<?php
|
|
$colors = ['cash' => 'success', 'card' => 'info', 'bank' => 'warning', 'mixed' => 'secondary'];
|
|
foreach ($report['payment_totals'] as $payment => $amount):
|
|
$percent = $report['gross'] > 0 ? ($amount / $report['gross']) * 100 : 0;
|
|
$bg = $colors[$payment] ?? 'primary';
|
|
?>
|
|
<div>
|
|
<div class="d-flex justify-content-between align-items-center mb-1">
|
|
<span class="fw-bold fs-6"><?= h(ucfirst((string) $payment)) ?></span>
|
|
<div class="text-end">
|
|
<strong class="d-block"><?= h(currency((float) $amount)) ?></strong>
|
|
<small class="text-muted"><?= round($percent, 1) ?>%</small>
|
|
</div>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-<?= $bg ?> rounded-pill" role="progressbar" style="width: <?= $percent ?>%"></div>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
</section>
|
|
|
|
<?php endif; ?>
|
|
|
|
<?php require __DIR__ . '/includes/footer.php'; ?>
|