39528-vm/reports.php
2026-04-09 09:46:40 +00:00

264 lines
14 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/app.php';
require_permission('reports');
$today = date('Y-m-d');
$defaultStart = date('Y-m-01');
$startDate = trim((string)($_GET['start_date'] ?? $defaultStart));
$endDate = trim((string)($_GET['end_date'] ?? $today));
if ($startDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDate)) {
$startDate = $defaultStart;
}
if ($endDate !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $endDate)) {
$endDate = $today;
}
if ($startDate !== '' && $endDate !== '' && $startDate > $endDate) {
[$startDate, $endDate] = [$endDate, $startDate];
}
$salesInvoices = filter_records_by_date(fetch_records('sales_invoice'), $startDate, $endDate);
$purchaseOrders = filter_records_by_date(fetch_records('purchase_order'), $startDate, $endDate);
$receivedPurchases = array_values(array_filter($purchaseOrders, static fn (array $row): bool => (string)($row['status'] ?? '') === 'received'));
$manufacturingOrders = filter_records_by_date(fetch_records('manufacturing_order'), $startDate, $endDate);
$completedManufacturing = array_values(array_filter($manufacturingOrders, static fn (array $row): bool => (string)($row['status'] ?? '') === 'completed'));
$customerPayments = filter_records_by_date(fetch_records('customer_payment'), $startDate, $endDate);
$supplierPayments = filter_records_by_date(fetch_records('supplier_payment'), $startDate, $endDate);
$expenses = filter_records_by_date(fetch_records('expense_entry'), $startDate, $endDate);
$stockMovements = filter_records_by_date(fetch_records('stock_movement'), $startDate, $endDate);
$salesTotal = 0.0;
$topCustomers = [];
foreach ($salesInvoices as $invoice) {
$payload = $invoice['payload_data'];
$amount = (float)($payload['grand_total'] ?? 0);
$salesTotal += $amount;
$customerName = (string)($payload['customer_name'] ?? 'عميل غير محدد');
if (!isset($topCustomers[$customerName])) {
$topCustomers[$customerName] = 0.0;
}
$topCustomers[$customerName] += $amount;
}
arsort($topCustomers);
$topCustomers = array_slice($topCustomers, 0, 5, true);
$purchaseTotal = 0.0;
foreach ($receivedPurchases as $purchase) {
$purchaseTotal += (float)($purchase['payload_data']['grand_total'] ?? 0);
}
$manufacturedQty = 0.0;
foreach ($completedManufacturing as $order) {
$manufacturedQty += (float)($order['payload_data']['produced_qty'] ?? 0);
}
$receiptsTotal = 0.0;
foreach ($customerPayments as $payment) {
$receiptsTotal += (float)($payment['payload_data']['amount'] ?? 0);
}
$supplierPaymentsTotal = 0.0;
foreach ($supplierPayments as $payment) {
$supplierPaymentsTotal += (float)($payment['payload_data']['amount'] ?? 0);
}
$expensesTotal = 0.0;
$expenseBreakdown = [];
foreach ($expenses as $expense) {
$payload = $expense['payload_data'];
$amount = (float)($payload['amount'] ?? 0);
$expensesTotal += $amount;
$category = expense_category_label((string)($payload['category'] ?? 'other'));
if (!isset($expenseBreakdown[$category])) {
$expenseBreakdown[$category] = 0.0;
}
$expenseBreakdown[$category] += $amount;
}
arsort($expenseBreakdown);
$productActivity = [];
foreach ($stockMovements as $movement) {
$payload = $movement['payload_data'];
$productName = (string)($payload['product_name'] ?? 'صنف غير محدد');
if (!isset($productActivity[$productName])) {
$productActivity[$productName] = 0.0;
}
$productActivity[$productName] += abs((float)($payload['qty_change'] ?? 0));
}
arsort($productActivity);
$productActivity = array_slice($productActivity, 0, 5, true);
$profitEstimate = $salesTotal - $purchaseTotal - $expensesTotal;
$netCashflow = $receiptsTotal - $supplierPaymentsTotal - $expensesTotal;
render_header('التقارير التنفيذية', 'تقارير ERP تشغيلية موحدة للمبيعات والمشتريات والتصنيع والمحاسبة مع فلترة حسب التاريخ.', 'reports');
?>
<div class="panel-card mb-4">
<div class="section-header">
<div>
<h1 class="section-title">التقارير التنفيذية</h1>
<p class="section-copy">شاشة موحدة لمراجعة أداء الفترة بين <?= e($startDate) ?> و<?= e($endDate) ?>.</p>
</div>
</div>
<form method="get" class="report-filter-grid">
<div>
<label class="form-label">من تاريخ</label>
<input type="date" class="form-control" name="start_date" value="<?= e($startDate) ?>">
</div>
<div>
<label class="form-label">إلى تاريخ</label>
<input type="date" class="form-control" name="end_date" value="<?= e($endDate) ?>">
</div>
<div class="d-flex align-items-end gap-2">
<button class="btn btn-dark w-100" type="submit">تحديث التقرير</button>
</div>
</form>
</div>
<section class="row g-3 mb-4">
<div class="col-6 col-xl-3"><div class="kpi-card"><div class="kpi-label">فواتير المبيعات</div><div class="kpi-value"><?= e(format_money($salesTotal)) ?></div><div class="kpi-note"><?= e((string)count($salesInvoices)) ?> فاتورة خلال الفترة</div></div></div>
<div class="col-6 col-xl-3"><div class="kpi-card"><div class="kpi-label">مشتريات مستلمة</div><div class="kpi-value"><?= e(format_money($purchaseTotal)) ?></div><div class="kpi-note"><?= e((string)count($receivedPurchases)) ?> أمر شراء مستلم</div></div></div>
<div class="col-6 col-xl-3"><div class="kpi-card"><div class="kpi-label">إنتاج مكتمل</div><div class="kpi-value"><?= e(number_format($manufacturedQty, 2)) ?></div><div class="kpi-note"><?= e((string)count($completedManufacturing)) ?> أمر تصنيع مكتمل</div></div></div>
<div class="col-6 col-xl-3"><div class="kpi-card"><div class="kpi-label">حركات المخزون</div><div class="kpi-value"><?= e((string)count($stockMovements)) ?></div><div class="kpi-note">إجمالي الإضافات والخصومات</div></div></div>
<div class="col-6 col-xl-3"><div class="kpi-card"><div class="kpi-label">مقبوضات العملاء</div><div class="kpi-value"><?= e(format_money($receiptsTotal)) ?></div><div class="kpi-note"><?= e((string)count($customerPayments)) ?> حركة قبض</div></div></div>
<div class="col-6 col-xl-3"><div class="kpi-card"><div class="kpi-label">مدفوعات الموردين</div><div class="kpi-value"><?= e(format_money($supplierPaymentsTotal)) ?></div><div class="kpi-note"><?= e((string)count($supplierPayments)) ?> حركة دفع</div></div></div>
<div class="col-6 col-xl-3"><div class="kpi-card"><div class="kpi-label">المصروفات</div><div class="kpi-value"><?= e(format_money($expensesTotal)) ?></div><div class="kpi-note"><?= e((string)count($expenses)) ?> قيد مصروف</div></div></div>
<div class="col-6 col-xl-3"><div class="kpi-card"><div class="kpi-label">صافي النقدية</div><div class="kpi-value"><?= e(format_money($netCashflow)) ?></div><div class="kpi-note">مقبوضات - مدفوعات - مصروفات</div></div></div>
</section>
<section class="row g-4">
<div class="col-xl-7">
<div class="panel-card mb-4">
<div class="section-header compact"><div><h2 class="section-title">أحدث فواتير المبيعات</h2><p class="section-copy">آخر 8 فواتير داخل الفترة المحددة.</p></div></div>
<?php if ($salesInvoices): ?>
<div class="table-responsive">
<table class="table align-middle app-table">
<thead><tr><th>الرقم</th><th>العميل</th><th>الإجمالي</th><th>التاريخ</th></tr></thead>
<tbody>
<?php foreach (array_slice($salesInvoices, 0, 8) as $invoice): $payload = $invoice['payload_data']; ?>
<tr>
<td><a class="table-link" href="sales_orders.php?id=<?= (int)$invoice['id'] ?>"><?= e($invoice['code']) ?></a></td>
<td><?= e($payload['customer_name'] ?? '') ?></td>
<td><?= e(format_money((float)($payload['grand_total'] ?? 0))) ?></td>
<td><?= e(record_created_date($invoice)) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="empty-inline">لا توجد فواتير مبيعات ضمن الفترة المحددة.</div>
<?php endif; ?>
</div>
<div class="panel-card mb-4">
<div class="section-header compact"><div><h2 class="section-title">المشتريات والتصنيع</h2><p class="section-copy">ملخص آخر الأوامر المستلمة والمكتملة.</p></div></div>
<div class="row g-3">
<div class="col-lg-6">
<div class="subtle-card h-100">
<div class="section-title mb-3">أوامر شراء مستلمة</div>
<?php if ($receivedPurchases): ?>
<?php foreach (array_slice($receivedPurchases, 0, 5) as $purchase): $payload = $purchase['payload_data']; ?>
<div class="summary-row"><span><?= e($purchase['code']) ?></span><strong><?= e(format_money((float)($payload['grand_total'] ?? 0))) ?></strong></div>
<?php endforeach; ?>
<?php else: ?>
<div class="empty-inline">لا توجد مشتريات مستلمة في هذه الفترة.</div>
<?php endif; ?>
</div>
</div>
<div class="col-lg-6">
<div class="subtle-card h-100">
<div class="section-title mb-3">أوامر تصنيع مكتملة</div>
<?php if ($completedManufacturing): ?>
<?php foreach (array_slice($completedManufacturing, 0, 5) as $order): $payload = $order['payload_data']; ?>
<div class="summary-row"><span><?= e($order['code']) ?></span><strong><?= e((string)($payload['produced_qty'] ?? 0)) ?> <?= e($payload['finished_unit'] ?? '') ?></strong></div>
<?php endforeach; ?>
<?php else: ?>
<div class="empty-inline">لا توجد أوامر تصنيع مكتملة في هذه الفترة.</div>
<?php endif; ?>
</div>
</div>
</div>
</div>
<div class="panel-card">
<div class="section-header compact"><div><h2 class="section-title">الحركة المالية</h2><p class="section-copy">آخر المقبوضات والمدفوعات والمصروفات خلال الفترة.</p></div></div>
<?php $activity = array_merge($customerPayments, $supplierPayments, $expenses); ?>
<?php usort($activity, static fn (array $a, array $b): int => strcmp((string)($b['created_at'] ?? ''), (string)($a['created_at'] ?? ''))); ?>
<?php $activity = array_slice($activity, 0, 10); ?>
<?php if ($activity): ?>
<div class="table-responsive">
<table class="table align-middle app-table">
<thead><tr><th>النوع</th><th>الوصف</th><th>القيمة</th><th>التاريخ</th></tr></thead>
<tbody>
<?php foreach ($activity as $row): $payload = $row['payload_data']; ?>
<tr>
<td><?= e(match ((string)$row['record_type']) { 'customer_payment' => 'مقبوض', 'supplier_payment' => 'مدفوع', 'expense_entry' => 'مصروف', default => (string)$row['record_type'] }) ?></td>
<td><?= e($row['title']) ?></td>
<td><?= e(format_money((float)($payload['amount'] ?? 0))) ?></td>
<td><?= e(record_created_date($row)) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php else: ?>
<div class="empty-inline">لا توجد حركة مالية ضمن الفترة المحددة.</div>
<?php endif; ?>
</div>
</div>
<div class="col-xl-5">
<div class="panel-card mb-4">
<div class="section-header compact"><div><h2 class="section-title">مؤشرات الربحية</h2></div></div>
<div class="subtle-card">
<div class="summary-row"><span>الربح المتوقع</span><strong><?= e(format_money($profitEstimate)) ?></strong></div>
<div class="summary-row"><span>صافي التدفق النقدي</span><strong><?= e(format_money($netCashflow)) ?></strong></div>
<div class="summary-row"><span>المبيعات - المشتريات</span><strong><?= e(format_money($salesTotal - $purchaseTotal)) ?></strong></div>
<div class="summary-row"><span>إجمالي المصروفات</span><strong><?= e(format_money($expensesTotal)) ?></strong></div>
</div>
</div>
<div class="panel-card mb-4">
<div class="section-header compact"><div><h2 class="section-title">أفضل العملاء</h2><p class="section-copy">حسب قيمة الفواتير داخل الفترة.</p></div></div>
<?php if ($topCustomers): ?>
<div class="subtle-card">
<?php foreach ($topCustomers as $customerName => $amount): ?>
<div class="summary-row"><span><?= e($customerName) ?></span><strong><?= e(format_money($amount)) ?></strong></div>
<?php endforeach; ?>
</div>
<?php else: ?>
<div class="empty-inline">لا توجد بيانات مبيعات كافية لحساب أفضل العملاء.</div>
<?php endif; ?>
</div>
<div class="panel-card mb-4">
<div class="section-header compact"><div><h2 class="section-title">أكثر الأصناف حركة</h2><p class="section-copy">حسب إجمالي الكميات المتحركة في المخزون.</p></div></div>
<?php if ($productActivity): ?>
<div class="subtle-card">
<?php foreach ($productActivity as $productName => $qty): ?>
<div class="summary-row"><span><?= e($productName) ?></span><strong><?= e(number_format($qty, 2)) ?></strong></div>
<?php endforeach; ?>
</div>
<?php else: ?>
<div class="empty-inline">لا توجد حركات مخزون ضمن الفترة المحددة.</div>
<?php endif; ?>
</div>
<div class="panel-card">
<div class="section-header compact"><div><h2 class="section-title">تحليل المصروفات</h2><p class="section-copy">تجميع حسب الفئة.</p></div></div>
<?php if ($expenseBreakdown): ?>
<div class="subtle-card">
<?php foreach ($expenseBreakdown as $category => $amount): ?>
<div class="summary-row"><span><?= e($category) ?></span><strong><?= e(format_money($amount)) ?></strong></div>
<?php endforeach; ?>
</div>
<?php else: ?>
<div class="empty-inline">لا توجد مصروفات ضمن الفترة المحددة.</div>
<?php endif; ?>
</div>
</div>
</section>
<?php render_footer(); ?>