248 lines
16 KiB
PHP
248 lines
16 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
require_once __DIR__ . '/app.php';
|
|
|
|
if (!is_logged_in()) {
|
|
render_header('بوابة ERP', 'نظام ERP ويب على PHP + MySQL مع تسجيل دخول وصلاحيات ومخزون ومشتريات ومبيعات وتصنيع ومحاسبة.', 'dashboard');
|
|
?>
|
|
<section class="hero-panel mb-4 mb-lg-5">
|
|
<div class="row g-4 align-items-center">
|
|
<div class="col-lg-8">
|
|
<span class="eyebrow">ERP Access Portal</span>
|
|
<h1 class="hero-title">نظام ERP ويب جاهز كبداية تشغيلية متكاملة.</h1>
|
|
<p class="hero-copy">تم تجهيز نواة تشغيلية تشمل تسجيل الدخول، الصلاحيات، العملاء، الموردين، الأصناف، المشتريات، المبيعات، التصنيع، المحاسبة، وسجل حركات المخزون. ادخل بحساب مناسب لفتح لوحة التحكم.</p>
|
|
<div class="d-flex flex-wrap gap-2 mt-4">
|
|
<a href="login.php" class="btn btn-dark px-4">تسجيل الدخول</a>
|
|
<a href="healthz.php" class="btn btn-outline-secondary px-4">Health API</a>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<div class="hero-side-card h-100">
|
|
<div class="metric-label">حسابات تجريبية</div>
|
|
<?php foreach (default_account_credentials() as $cred): ?>
|
|
<div class="small mb-2"><strong><?= e($cred['username']) ?></strong> / <?= e($cred['password']) ?></div>
|
|
<?php endforeach; ?>
|
|
<p class="text-secondary small mb-0">هذه الحسابات لأغراض البداية فقط.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<?php
|
|
render_footer();
|
|
exit;
|
|
}
|
|
|
|
require_permission('dashboard');
|
|
|
|
$counts = fetch_counts();
|
|
$inventory = inventory_totals();
|
|
$financial = accounting_summary();
|
|
$salesToday = today_record_count('sales_order');
|
|
$purchasesToday = today_record_count('purchase_order');
|
|
$manufacturingToday = today_record_count('manufacturing_order');
|
|
$latestSales = recent_records('sales_order', 5);
|
|
$latestPurchases = recent_records('purchase_order', 5);
|
|
$latestManufacturing = recent_records('manufacturing_order', 5);
|
|
$movements = recent_records('stock_movement', 6);
|
|
$accountingActivity = recent_accounting_activity(6);
|
|
$lowStock = low_stock_products(5);
|
|
$current = current_user();
|
|
$rawPercent = $inventory['all_qty'] > 0 ? round(($inventory['raw_qty'] / $inventory['all_qty']) * 100, 1) : 0;
|
|
$finishedPercent = $inventory['all_qty'] > 0 ? round(($inventory['finished_qty'] / $inventory['all_qty']) * 100, 1) : 0;
|
|
$totalManufactured = 0.0;
|
|
foreach (fetch_records('manufacturing_order') as $order) {
|
|
$totalManufactured += (float)($order['payload_data']['produced_qty'] ?? 0);
|
|
}
|
|
|
|
render_header('لوحة ERP المركزية', 'لوحة تشغيل يومية للعملاء والموردين والأصناف والمبيعات والمشتريات والتصنيع والمحاسبة وحركات المخزون.', 'dashboard');
|
|
?>
|
|
<section class="hero-panel mb-4 mb-lg-5">
|
|
<div class="row g-4 align-items-center">
|
|
<div class="col-lg-8">
|
|
<span class="eyebrow">Phase 5 ERP Foundation</span>
|
|
<h1 class="hero-title">تشغيل يومي موحّد مع تقارير فورية لكل أقسام الـ ERP.</h1>
|
|
<p class="hero-copy">مرحبًا <?= e($current['full_name'] ?? '') ?> — هذه النسخة تدعم تسجيل الدخول والصلاحيات، الموردين، أوامر الشراء، مسار المبيعات الكامل، أوامر التصنيع، المحاسبة التشغيلية، وسجل حركات المخزون، مع صفحة تقارير جديدة لتجميع الأداء حسب الفترة.</p>
|
|
<div class="quick-links mt-4">
|
|
<?php foreach (nav_items() as $item): ?>
|
|
<?php if (can_access($item['area'])): ?>
|
|
<a href="<?= e($item['href']) ?>" class="quick-link-card">
|
|
<strong><?= e($item['label']) ?></strong>
|
|
<span>فتح القسم</span>
|
|
</a>
|
|
<?php endif; ?>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<div class="hero-side-card h-100">
|
|
<div class="metric-label">الدور الحالي</div>
|
|
<div class="metric-value"><?= e(role_label((string)($current['role'] ?? ''))) ?></div>
|
|
<p class="text-secondary mb-3">إجمالي السجلات التشغيلية: <?= e((string)(array_sum($counts))) ?></p>
|
|
<div class="small text-secondary">آخر تحديث: <?= e(date('Y-m-d H:i')) ?> UTC</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="row g-3 mb-4">
|
|
<div class="col-12">
|
|
<div class="panel-card reports-callout">
|
|
<div class="section-header mb-0">
|
|
<div>
|
|
<h2 class="section-title">التقارير التنفيذية</h2>
|
|
<p class="section-copy mb-0">افتح صفحة التقارير لفلترة النتائج حسب التاريخ ومراجعة المبيعات والمشتريات والتصنيع والمحاسبة من شاشة واحدة.</p>
|
|
</div>
|
|
<?php if (can_access('reports')): ?>
|
|
<a href="reports.php" class="btn btn-dark">فتح التقارير</a>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="row g-3 mb-4 mb-lg-5">
|
|
<div class="col-6 col-xl-3"><div class="stat-card"><div class="stat-label">العملاء</div><div class="stat-value"><?= e((string)$counts['customer']) ?></div><div class="stat-note">سجل العملاء</div></div></div>
|
|
<div class="col-6 col-xl-3"><div class="stat-card"><div class="stat-label">الموردون</div><div class="stat-value"><?= e((string)$counts['supplier']) ?></div><div class="stat-note">ربط المشتريات</div></div></div>
|
|
<div class="col-6 col-xl-3"><div class="stat-card"><div class="stat-label">الأصناف</div><div class="stat-value"><?= e((string)$counts['product']) ?></div><div class="stat-note">مواد خام ونهائية</div></div></div>
|
|
<div class="col-6 col-xl-3"><div class="stat-card"><div class="stat-label">أوامر التصنيع</div><div class="stat-value"><?= e((string)($counts['manufacturing_order'] ?? 0)) ?></div><div class="stat-note"><?= e((string)$manufacturingToday) ?> اليوم</div></div></div>
|
|
<div class="col-6 col-xl-3"><div class="stat-card"><div class="stat-label">مبيعات اليوم</div><div class="stat-value"><?= e((string)$salesToday) ?></div><div class="stat-note"><?= e(format_money(today_sales_value())) ?></div></div></div>
|
|
<div class="col-6 col-xl-3"><div class="stat-card"><div class="stat-label">مشتريات اليوم</div><div class="stat-value"><?= e((string)$purchasesToday) ?></div><div class="stat-note"><?= e(format_money(today_purchase_value())) ?></div></div></div>
|
|
<div class="col-6 col-xl-3"><div class="stat-card"><div class="stat-label">المقبوضات</div><div class="stat-value"><?= e(format_money((float)$financial['customer_receipts'])) ?></div><div class="stat-note">اليوم <?= e(format_money((float)$financial['today_receipts'])) ?></div></div></div>
|
|
<div class="col-6 col-xl-3"><div class="stat-card"><div class="stat-label">المصروفات</div><div class="stat-value"><?= e(format_money((float)$financial['expenses'])) ?></div><div class="stat-note">اليوم <?= e(format_money((float)$financial['today_expenses'])) ?></div></div></div>
|
|
</section>
|
|
|
|
<section class="row g-4 mb-4 mb-lg-5">
|
|
<div class="col-lg-7">
|
|
<div class="panel-card h-100">
|
|
<div class="section-header"><div><h2 class="section-title">الصورة التشغيلية والمالية</h2><p class="section-copy">مخزون، ذمم، ربح متوقع، وتدفق نقدي في ملخص واحد.</p></div></div>
|
|
<div class="row g-3">
|
|
<div class="col-md-6"><div class="stat-card stat-card-soft"><div class="stat-label">إجمالي المخزون</div><div class="stat-value"><?= e((string)$inventory['all_qty']) ?></div><div class="stat-note"><?= e((string)$inventory['sku_count']) ?> صنف نشط</div></div></div>
|
|
<div class="col-md-6"><div class="stat-card stat-card-soft"><div class="stat-label">إجمالي الإنتاج المرحّل</div><div class="stat-value"><?= e((string)$totalManufactured) ?></div><div class="stat-note">ناتج أوامر التصنيع المكتملة</div></div></div>
|
|
<div class="col-md-6"><div class="stat-card stat-card-soft"><div class="stat-label">ذمم العملاء</div><div class="stat-value"><?= e(format_money((float)$financial['receivables'])) ?></div><div class="stat-note">من فواتير المبيعات</div></div></div>
|
|
<div class="col-md-6"><div class="stat-card stat-card-soft"><div class="stat-label">ذمم الموردين</div><div class="stat-value"><?= e(format_money((float)$financial['payables'])) ?></div><div class="stat-note">من المشتريات المستلمة</div></div></div>
|
|
<div class="col-md-6"><div class="stat-card stat-card-soft"><div class="stat-label">الربح المتوقع</div><div class="stat-value"><?= e(format_money((float)$financial['expected_profit'])) ?></div><div class="stat-note">فواتير - مشتريات - مصروفات</div></div></div>
|
|
<div class="col-md-6"><div class="stat-card stat-card-soft"><div class="stat-label">صافي التدفق النقدي</div><div class="stat-value"><?= e(format_money((float)$financial['net_cashflow'])) ?></div><div class="stat-note">المقبوضات - المدفوعات - المصروفات</div></div></div>
|
|
</div>
|
|
<div class="mt-4">
|
|
<div class="summary-row mb-2"><span>الخامات (<?= e((string)$rawPercent) ?>%)</span><strong><?= e((string)$inventory['raw_qty']) ?></strong></div>
|
|
<div class="progress app-progress mb-3"><div class="progress-bar bg-secondary" style="width: <?= e((string)$rawPercent) ?>%"></div></div>
|
|
<div class="summary-row mb-2"><span>المنتجات النهائية (<?= e((string)$finishedPercent) ?>%)</span><strong><?= e((string)$inventory['finished_qty']) ?></strong></div>
|
|
<div class="progress app-progress"><div class="progress-bar bg-dark" style="width: <?= e((string)$finishedPercent) ?>%"></div></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-5">
|
|
<div class="panel-card h-100">
|
|
<div class="section-header compact"><div><h2 class="section-title">تنبيهات المخزون المنخفض</h2><p class="section-copy">الأصناف الأقرب لإعادة الطلب.</p></div></div>
|
|
<?php if ($lowStock): ?>
|
|
<div class="vstack gap-2">
|
|
<?php foreach ($lowStock as $product): $payload = $product['payload_data']; ?>
|
|
<div class="subtle-card">
|
|
<div class="d-flex justify-content-between"><strong><?= e($product['title']) ?></strong><span><?= e($payload['sku'] ?? $product['code']) ?></span></div>
|
|
<div class="small text-secondary mt-1">المتوفر: <?= e((string)($payload['stock_qty'] ?? 0)) ?> — حد الطلب: <?= e((string)($payload['reorder_level'] ?? 0)) ?></div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="empty-inline">لا توجد أصناف منخفضة حاليًا.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="row g-4 mb-4 mb-lg-5">
|
|
<div class="col-lg-6">
|
|
<div class="panel-card h-100">
|
|
<div class="section-header"><div><h2 class="section-title">آخر أوامر البيع</h2><p class="section-copy">أحدث عمليات البيع المؤكدة.</p></div></div>
|
|
<?php if ($latestSales): ?>
|
|
<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 ($latestSales as $order): $payload = $order['payload_data']; ?>
|
|
<tr><td><?= e($order['code']) ?></td><td><?= e($payload['customer_name'] ?? '') ?></td><td><?= e($payload['product_name'] ?? '') ?></td><td><?= e(format_money((float)($payload['grand_total'] ?? 0))) ?></td></tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="empty-inline">لا توجد أوامر بيع بعد.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-6">
|
|
<div class="panel-card h-100">
|
|
<div class="section-header"><div><h2 class="section-title">آخر أوامر الشراء</h2><p class="section-copy">أحدث الأوامر الواردة من الموردين.</p></div></div>
|
|
<?php if ($latestPurchases): ?>
|
|
<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 ($latestPurchases as $order): $payload = $order['payload_data']; ?>
|
|
<tr><td><?= e($order['code']) ?></td><td><?= e($payload['supplier_name'] ?? '') ?></td><td><?= e($payload['product_name'] ?? '') ?></td><td><?= e(format_money((float)($payload['grand_total'] ?? 0))) ?></td></tr>
|
|
<?php endforeach; ?>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="empty-inline">لا توجد أوامر شراء بعد.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="row g-4">
|
|
<div class="col-lg-4">
|
|
<div class="panel-card h-100">
|
|
<div class="section-header"><div><h2 class="section-title">آخر أوامر التصنيع</h2><p class="section-copy">ملخص العمليات الإنتاجية المرحّلة.</p></div></div>
|
|
<?php if ($latestManufacturing): ?>
|
|
<div class="vstack gap-2">
|
|
<?php foreach ($latestManufacturing as $order): $payload = $order['payload_data']; ?>
|
|
<div class="list-row">
|
|
<div><strong><?= e($order['code']) ?></strong><div class="small text-secondary"><?= e($payload['finished_product_name'] ?? '') ?></div></div>
|
|
<div class="text-start small"><?= e((string)($payload['produced_qty'] ?? 0)) ?> <?= e($payload['finished_unit'] ?? '') ?></div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="empty-inline">لا توجد أوامر تصنيع بعد.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<div class="panel-card h-100">
|
|
<div class="section-header"><div><h2 class="section-title">أحدث حركات المخزون</h2><p class="section-copy">تشمل المبيعات والمشتريات والتصنيع في سجل واحد.</p></div></div>
|
|
<?php if ($movements): ?>
|
|
<div class="vstack gap-2">
|
|
<?php foreach ($movements as $movement): $payload = $movement['payload_data']; $delta = (float)($payload['qty_change'] ?? 0); ?>
|
|
<div class="list-row">
|
|
<div><strong><?= e($payload['product_name'] ?? '') ?></strong><div class="small text-secondary"><?= e($payload['movement_type'] ?? '') ?> — <?= e($payload['reference_code'] ?? '') ?></div></div>
|
|
<div class="text-start"><span class="badge <?= e(movement_badge_class($delta)) ?> mb-1"><?= e(movement_direction_label($delta)) ?></span><div class="small"><?= e((string)$delta) ?> / بعد الحركة <?= e((string)($payload['qty_after'] ?? 0)) ?></div></div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="empty-inline">لا توجد حركات مخزون بعد.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
<div class="col-lg-4">
|
|
<div class="panel-card h-100">
|
|
<div class="section-header"><div><h2 class="section-title">آخر نشاط محاسبي</h2><p class="section-copy">مقبوضات ومدفوعات ومصروفات مرحّلة.</p></div></div>
|
|
<?php if ($accountingActivity): ?>
|
|
<div class="vstack gap-2">
|
|
<?php foreach ($accountingActivity as $row): $payload = $row['payload_data']; ?>
|
|
<div class="list-row">
|
|
<div><strong><?= e($row['title']) ?></strong><div class="small text-secondary"><?= e($row['code']) ?></div></div>
|
|
<div class="text-start small"><?= e(format_money((float)($payload['amount'] ?? 0))) ?></div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="empty-inline">لا توجد قيود محاسبية بعد.</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<?php render_footer(); ?>
|