From 9e078bdfa70b683b7227f63082b9e70deeed3898 Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Fri, 15 May 2026 14:23:28 +0300 Subject: [PATCH] Update: 2026-05-15 14:23:28 --- app/modules_app/invoices/export_excel.php | 328 +++++++++++++--------- app/modules_app/invoices/upload.php | 18 +- public/shell.php | 61 +++- 3 files changed, 257 insertions(+), 150 deletions(-) diff --git a/app/modules_app/invoices/export_excel.php b/app/modules_app/invoices/export_excel.php index fd913f1..f251352 100644 --- a/app/modules_app/invoices/export_excel.php +++ b/app/modules_app/invoices/export_excel.php @@ -132,8 +132,72 @@ $totalFont = '065F46'; // Dark green $borderColor = 'E2E1F0'; // Light border $altRowBg = 'F8F7FD'; // Alternating row -// Process each invoice -$sheetIndex = 0; +// ══════════════════════════════════════════ +// 1. SUMMARY SHEET (First Sheet) +// ══════════════════════════════════════════ + +$summarySheet = $spreadsheet->getActiveSheet(); +$summarySheet->setTitle('الملخص الإجمالي'); +$summarySheet->setRightToLeft(true); + +// --- SUMMARY HEADER --- +$summarySheet->mergeCells("A1:J1"); +$summarySheet->setCellValue("A1", 'مُـصَـادَق — ملخص الفواتير الإجمالي'); +$summarySheet->getStyle("A1")->applyFromArray([ + 'font' => ['bold' => true, 'size' => 16, 'color' => ['argb' => 'FF' . $headerFont]], + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $headerBg]], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER], +]); +$summarySheet->getRowDimension(1)->setRowHeight(40); + +// Summary Meta Info +$companyNameFilter = 'جميع الشركات'; +if ($companyId) { + $cStmt = $db->prepare("SELECT name FROM companies WHERE id = ?"); + $cStmt->execute([$companyId]); + $cName = $cStmt->fetchColumn(); + if ($cName) $companyNameFilter = $dec($cName); +} + +$summarySheet->setCellValue("A3", 'الشركة:'); +$summarySheet->setCellValue("B3", $companyNameFilter); +$summarySheet->setCellValue("D3", 'الفترة:'); +$summarySheet->setCellValue("E3", ($dateFrom ?? '—') . ' إلى ' . ($dateTo ?? '—')); +$summarySheet->setCellValue("G3", 'عدد الفواتير:'); +$summarySheet->setCellValue("H3", count($invoices)); + +$summarySheet->getStyle("A3:H3")->getFont()->setBold(true); + +// --- SUMMARY TABLE HEADERS --- +$row = 5; +$summaryHeaders = ['#', 'رقم الفاتورة', 'المورّد', 'وصف البند', 'الكمية', 'سعر الوحدة', 'المجموع الجزئي', 'نسبة الضريبة', 'قيمة الضريبة', 'الصافي']; +$sumCols = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J']; + +foreach ($summaryHeaders as $i => $h) { + $summarySheet->setCellValue($sumCols[$i] . $row, $h); +} + +$summarySheet->getStyle("A{$row}:J{$row}")->applyFromArray([ + 'font' => ['bold' => true, 'color' => ['argb' => 'FF' . $headerFont]], + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $headerBg]], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER], +]); + +// Summary column widths +$summarySheet->getColumnDimension('B')->setWidth(18); +$summarySheet->getColumnDimension('C')->setWidth(25); +$summarySheet->getColumnDimension('D')->setWidth(35); +$summarySheet->getColumnDimension('G')->setWidth(14); +$summarySheet->getColumnDimension('I')->setWidth(14); +$summarySheet->getColumnDimension('J')->setWidth(16); + +$row++; +$summaryStartRow = $row; +$globalLineCount = 0; + +// ══════════════════════════════════════════ +// 2. INDIVIDUAL INVOICE SHEETS + POPULATE SUMMARY +// ══════════════════════════════════════════ foreach ($invoices as $invIdx => $inv) { // Fetch line items for this invoice @@ -141,15 +205,46 @@ foreach ($invoices as $invIdx => $inv) { $stmtLines->execute([$inv['id']]); $lines = $stmtLines->fetchAll(); - // Create sheet (reuse first sheet for first invoice) - if ($sheetIndex === 0) { - $sheet = $spreadsheet->getActiveSheet(); + // --- Add to Summary Sheet --- + if (!empty($lines)) { + foreach ($lines as $line) { + $globalLineCount++; + $summarySheet->setCellValue("A{$row}", $globalLineCount); + $summarySheet->setCellValue("B{$row}", $inv['invoice_number'] ?? '-'); + $summarySheet->setCellValue("C{$row}", $dec($inv['supplier_name'])); + $summarySheet->setCellValue("D{$row}", $line['description'] ?? 'بدون وصف'); + $summarySheet->setCellValue("E{$row}", (float)$line['quantity']); + $summarySheet->setCellValue("F{$row}", (float)$line['unit_price']); + $summarySheet->setCellValue("G{$row}", "=E{$row}*F{$row}"); + $summarySheet->setCellValue("H{$row}", (float)$line['tax_rate']); + $summarySheet->setCellValue("I{$row}", "=G{$row}*H{$row}"); + $summarySheet->setCellValue("J{$row}", "=G{$row}+I{$row}"); + + if ($globalLineCount % 2 === 0) { + $summarySheet->getStyle("A{$row}:J{$row}")->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('FFF8F7FD'); + } + $row++; + } } else { - $sheet = $spreadsheet->createSheet(); + // Fallback if no line items + $globalLineCount++; + $summarySheet->setCellValue("A{$row}", $globalLineCount); + $summarySheet->setCellValue("B{$row}", $inv['invoice_number'] ?? '-'); + $summarySheet->setCellValue("C{$row}", $dec($inv['supplier_name'])); + $summarySheet->setCellValue("D{$row}", 'إجمالي الفاتورة'); + $summarySheet->setCellValue("E{$row}", 1); + $summarySheet->setCellValue("F{$row}", (float)$inv['subtotal']); + $summarySheet->setCellValue("G{$row}", "=E{$row}*F{$row}"); + $summarySheet->setCellValue("H{$row}", 0.16); + $summarySheet->setCellValue("I{$row}", "=G{$row}*H{$row}"); + $summarySheet->setCellValue("J{$row}", "=G{$row}+I{$row}"); + $row++; } - $invoiceNum = $inv['invoice_number'] ?? ('INV-' . ($sheetIndex + 1)); - $sheetTitle = mb_substr(preg_replace('/[^a-zA-Z0-9\x{0600}-\x{06FF}\s\-]/u', '', $invoiceNum), 0, 31) ?: ('فاتورة ' . ($sheetIndex + 1)); + // --- Create Individual Sheet --- + $sheet = $spreadsheet->createSheet(); + $invoiceNum = $inv['invoice_number'] ?? ('INV-' . ($invIdx + 1)); + $sheetTitle = mb_substr(preg_replace('/[^a-zA-Z0-9\x{0600}-\x{06FF}\s\-]/u', '', $invoiceNum), 0, 31) ?: ('فاتورة ' . ($invIdx + 1)); $sheet->setTitle($sheetTitle); $sheet->setRightToLeft(true); @@ -164,20 +259,20 @@ foreach ($invoices as $invIdx => $inv) { $sheet->getColumnDimension('H')->setWidth(14); // Discount $sheet->getColumnDimension('I')->setWidth(18); // Net Total (formula) - $row = 1; + $invRow = 1; // ── INVOICE HEADER ────────────────────────── - $sheet->mergeCells("A{$row}:I{$row}"); - $sheet->setCellValue("A{$row}", 'مُـصَـادَق — تقرير فاتورة مشتريات'); - $sheet->getStyle("A{$row}")->applyFromArray([ + $sheet->mergeCells("A{$invRow}:I{$invRow}"); + $sheet->setCellValue("A{$invRow}", 'مُـصَـادَق — تقرير فاتورة مشتريات'); + $sheet->getStyle("A{$invRow}")->applyFromArray([ 'font' => ['bold' => true, 'size' => 16, 'color' => ['argb' => 'FF' . $headerFont]], 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $headerBg]], 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER], ]); - $sheet->getRowDimension($row)->setRowHeight(40); - $row++; + $sheet->getRowDimension($invRow)->setRowHeight(40); + $invRow++; - // Invoice meta data (2 columns layout) + // Invoice meta data $metaData = [ ['رقم الفاتورة', $inv['invoice_number'] ?? '-', 'اسم المورّد', $dec($inv['supplier_name'])], ['تاريخ الفاتورة', $inv['invoice_date'] ?? '-', 'الرقم الضريبي للمورّد', $dec($inv['supplier_tin'])], @@ -192,155 +287,108 @@ foreach ($invoices as $invIdx => $inv) { ]; foreach ($metaData as $meta) { - $sheet->setCellValue("A{$row}", $meta[0]); - $sheet->mergeCells("B{$row}:C{$row}"); - $sheet->setCellValue("B{$row}", $meta[1]); - $sheet->setCellValue("E{$row}", $meta[2]); - $sheet->mergeCells("F{$row}:I{$row}"); - $sheet->setCellValue("F{$row}", $meta[3]); + $sheet->setCellValue("A{$invRow}", $meta[0]); + $sheet->mergeCells("B{$invRow}:C{$invRow}"); + $sheet->setCellValue("B{$invRow}", $meta[1]); + $sheet->setCellValue("E{$invRow}", $meta[2]); + $sheet->mergeCells("F{$invRow}:I{$invRow}"); + $sheet->setCellValue("F{$invRow}", $meta[3]); - // Style labels - $sheet->getStyle("A{$row}:C{$row}")->applyFromArray([ + $sheet->getStyle("A{$invRow}:C{$invRow}")->applyFromArray([ 'font' => ['bold' => true, 'size' => 11, 'color' => ['argb' => 'FF' . $subHeaderFont]], 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $subHeaderBg]], ]); - $sheet->getStyle("E{$row}")->applyFromArray([ + $sheet->getStyle("E{$invRow}")->applyFromArray([ 'font' => ['bold' => true, 'size' => 11, 'color' => ['argb' => 'FF' . $subHeaderFont]], 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $subHeaderBg]], ]); - $sheet->getRowDimension($row)->setRowHeight(24); - $row++; + $sheet->getRowDimension($invRow)->setRowHeight(24); + $invRow++; } - $row++; // Empty spacer row + $invRow++; - // ── LINE ITEMS TABLE HEADER ───────────────── + // Items Header $headers = ['#', 'وصف البند', 'الكمية', 'سعر الوحدة', 'المجموع الجزئي', 'نسبة الضريبة', 'قيمة الضريبة', 'الخصم', 'الصافي']; $cols = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I']; - $headerRow = $row; - $itemsStartRow = $row + 1; + foreach ($headers as $i => $h) $sheet->setCellValue($cols[$i] . $invRow, $h); - foreach ($headers as $i => $header) { - $sheet->setCellValue($cols[$i] . $row, $header); - } - - $sheet->getStyle("A{$row}:I{$row}")->applyFromArray([ - 'font' => ['bold' => true, 'size' => 12, 'color' => ['argb' => 'FF' . $headerFont]], + $sheet->getStyle("A{$invRow}:I{$invRow}")->applyFromArray([ + 'font' => ['bold' => true, 'color' => ['argb' => 'FF' . $headerFont]], 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $headerBg]], - 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER, 'vertical' => Alignment::VERTICAL_CENTER], - 'borders' => [ - 'allBorders' => ['borderStyle' => Border::BORDER_THIN, 'color' => ['argb' => 'FF' . $headerBg]], - ], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER], ]); - $sheet->getRowDimension($row)->setRowHeight(32); - $row++; - - // ── LINE ITEMS WITH FORMULAS ──────────────── - $firstDataRow = $row; + $sheet->getRowDimension($invRow)->setRowHeight(32); + $invRow++; + $itemsStart = $invRow; if (!empty($lines)) { - foreach ($lines as $lineIdx => $line) { - $lineNum = $lineIdx + 1; - $quantity = is_numeric($line['quantity'] ?? null) ? (float)$line['quantity'] : 1; - $unitPrice = is_numeric($line['unit_price'] ?? null) ? (float)$line['unit_price'] : 0; - $taxRate = is_numeric($line['tax_rate'] ?? null) ? (float)$line['tax_rate'] : 0.16; - $discount = is_numeric($line['discount_amount'] ?? null) ? (float)$line['discount_amount'] : 0; - - $sheet->setCellValue("A{$row}", $lineNum); - $sheet->setCellValue("B{$row}", $line['description'] ?? 'بدون وصف'); - $sheet->setCellValue("C{$row}", $quantity); - $sheet->setCellValue("D{$row}", $unitPrice); - $sheet->setCellValue("E{$row}", "=C{$row}*D{$row}"); - $sheet->setCellValue("F{$row}", $taxRate); - $sheet->getStyle("F{$row}")->getNumberFormat()->setFormatCode('0%'); - $sheet->setCellValue("G{$row}", "=E{$row}*F{$row}"); - $sheet->setCellValue("H{$row}", $discount); - $sheet->setCellValue("I{$row}", "=E{$row}+G{$row}-H{$row}"); - - if ($lineIdx % 2 === 1) { - $sheet->getStyle("A{$row}:I{$row}")->applyFromArray([ - 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $altRowBg]], - ]); - } - - foreach (['D', 'E', 'G', 'H', 'I'] as $col) { - $sheet->getStyle("{$col}{$row}")->getNumberFormat()->setFormatCode('#,##0.000'); - } - $sheet->getStyle("C{$row}")->getNumberFormat()->setFormatCode('#,##0'); - $sheet->getStyle("A{$row}:I{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - $sheet->getStyle("B{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT); - $sheet->getRowDimension($row)->setRowHeight(26); - $row++; + foreach ($lines as $lIdx => $line) { + $sheet->setCellValue("A{$invRow}", $lIdx + 1); + $sheet->setCellValue("B{$invRow}", $line['description'] ?? 'بدون وصف'); + $sheet->setCellValue("C{$invRow}", (float)$line['quantity']); + $sheet->setCellValue("D{$invRow}", (float)$line['unit_price']); + $sheet->setCellValue("E{$invRow}", "=C{$invRow}*D{$invRow}"); + $sheet->setCellValue("F{$invRow}", (float)$line['tax_rate']); + $sheet->getStyle("F{$invRow}")->getNumberFormat()->setFormatCode('0%'); + $sheet->setCellValue("G{$invRow}", "=E{$invRow}*F{$invRow}"); + $sheet->setCellValue("H{$invRow}", (float)$line['discount_amount']); + $sheet->setCellValue("I{$invRow}", "=E{$invRow}+G{$invRow}-H{$invRow}"); + if ($lIdx % 2 === 1) $sheet->getStyle("A{$invRow}:I{$invRow}")->getFill()->setFillType(Fill::FILL_SOLID)->getStartColor()->setARGB('FFF8F7FD'); + foreach (['D','E','G','H','I'] as $c) $sheet->getStyle("{$c}{$invRow}")->getNumberFormat()->setFormatCode('#,##0.000'); + $invRow++; } } else { - $sheet->setCellValue("A{$row}", 1); - $sheet->setCellValue("B{$row}", 'إجمالي الفاتورة (بدون تفاصيل بنود)'); - $sheet->setCellValue("C{$row}", 1); - $sheet->setCellValue("D{$row}", (float)($inv['subtotal'] ?? 0)); - $sheet->setCellValue("E{$row}", "=C{$row}*D{$row}"); - $sheet->setCellValue("F{$row}", 0.16); - $sheet->getStyle("F{$row}")->getNumberFormat()->setFormatCode('0%'); - $sheet->setCellValue("G{$row}", "=E{$row}*F{$row}"); - $sheet->setCellValue("H{$row}", (float)($inv['discount_total'] ?? 0)); - $sheet->setCellValue("I{$row}", "=E{$row}+G{$row}-H{$row}"); - foreach (['D', 'E', 'G', 'H', 'I'] as $col) { - $sheet->getStyle("{$col}{$row}")->getNumberFormat()->setFormatCode('#,##0.000'); - } - $sheet->getStyle("A{$row}:I{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - $sheet->getRowDimension($row)->setRowHeight(26); - $row++; + $sheet->setCellValue("A{$invRow}", 1); + $sheet->setCellValue("B{$invRow}", 'إجمالي الفاتورة'); + $sheet->setCellValue("C{$invRow}", 1); + $sheet->setCellValue("D{$invRow}", (float)$inv['subtotal']); + $sheet->setCellValue("E{$invRow}", "=C{$invRow}*D{$invRow}"); + $sheet->setCellValue("F{$invRow}", 0.16); + $sheet->getStyle("F{$invRow}")->getNumberFormat()->setFormatCode('0%'); + $sheet->setCellValue("G{$invRow}", "=E{$invRow}*F{$invRow}"); + $sheet->setCellValue("H{$invRow}", (float)$inv['discount_total']); + $sheet->setCellValue("I{$invRow}", "=E{$invRow}+G{$invRow}-H{$invRow}"); + foreach (['D','E','G','H','I'] as $c) $sheet->getStyle("{$c}{$invRow}")->getNumberFormat()->setFormatCode('#,##0.000'); + $invRow++; } - $lastDataRow = $row - 1; - - // ── DATA AREA BORDERS ── - $sheet->getStyle("A{$itemsStartRow}:I" . ($row - 1))->applyFromArray([ - 'borders' => [ - 'allBorders' => ['borderStyle' => Border::BORDER_THIN, 'color' => ['argb' => 'FF' . $borderColor]], - ] - ]); - - // ── TOTALS ROW WITH SUM FORMULAS ──────────── - $sheet->mergeCells("A{$row}:B{$row}"); - $sheet->setCellValue("A{$row}", 'المجموع الكلي'); - $sheet->setCellValue("C{$row}", "=SUM(C{$firstDataRow}:C{$lastDataRow})"); - $sheet->setCellValue("D{$row}", ''); - $sheet->setCellValue("E{$row}", "=SUM(E{$firstDataRow}:E{$lastDataRow})"); - $sheet->setCellValue("F{$row}", ''); - $sheet->setCellValue("G{$row}", "=SUM(G{$firstDataRow}:G{$lastDataRow})"); - $sheet->setCellValue("H{$row}", "=SUM(H{$firstDataRow}:H{$lastDataRow})"); - $sheet->setCellValue("I{$row}", "=SUM(I{$firstDataRow}:I{$lastDataRow})"); - - $sheet->getStyle("G{$row}:I{$row}")->applyFromArray([ - 'font' => ['bold' => true, 'size' => 13, 'color' => ['argb' => 'FF' . $totalFont]], + // Totals row for individual sheet + $lastItemRow = $invRow - 1; + $sheet->mergeCells("A{$invRow}:B{$invRow}"); + $sheet->setCellValue("A{$invRow}", 'المجموع الكلي'); + $sheet->setCellValue("C{$invRow}", "=SUM(C{$itemsStart}:C{$lastItemRow})"); + $sheet->setCellValue("E{$invRow}", "=SUM(E{$itemsStart}:E{$lastItemRow})"); + $sheet->setCellValue("G{$invRow}", "=SUM(G{$itemsStart}:G{$lastItemRow})"); + $sheet->setCellValue("H{$invRow}", "=SUM(H{$itemsStart}:H{$lastItemRow})"); + $sheet->setCellValue("I{$invRow}", "=SUM(I{$itemsStart}:I{$lastItemRow})"); + $sheet->getStyle("G{$invRow}:I{$invRow}")->applyFromArray([ + 'font' => ['bold' => true, 'color' => ['argb' => 'FF' . $totalFont]], 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $totalBg]], - 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER], - 'borders' => [ - 'allBorders' => ['borderStyle' => Border::BORDER_MEDIUM, 'color' => ['argb' => 'FF059669']], - ] ]); - $sheet->getStyle("A{$row}")->getAlignment()->setHorizontal(Alignment::HORIZONTAL_CENTER); - foreach (['C', 'E', 'G', 'H', 'I'] as $col) { - $sheet->getStyle("{$col}{$row}")->getNumberFormat()->setFormatCode('#,##0.000'); - } - $sheet->getRowDimension($row)->setRowHeight(36); - - $row += 2; - - // ── FOOTER ── - $sheet->mergeCells("A{$row}:I{$row}"); - $sheet->setCellValue("A{$row}", 'تم إنشاء هذا التقرير تلقائياً من منصة مُصادَق — ' . date('Y-m-d H:i')); - $sheet->getStyle("A{$row}:I{$row}")->applyFromArray([ - 'font' => ['italic' => true, 'size' => 9, 'color' => ['argb' => 'FF8B82B0']], - 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER] - ]); - - // ── Print settings ── - $sheet->getPageSetup()->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE); - $sheet->getPageSetup()->setFitToWidth(1); - - $sheetIndex++; + foreach (['C','E','G','H','I'] as $c) $sheet->getStyle("{$c}{$invRow}")->getNumberFormat()->setFormatCode('#,##0.000'); + $invRow += 2; + $sheet->setCellValue("A{$invRow}", 'تم إنشاء هذا التقرير تلقائياً من منصة مُصادَق — ' . date('Y-m-d H:i')); } +// Final Summary Row with totals +$lastSummaryRow = $row - 1; +$summarySheet->mergeCells("A{$row}:D{$row}"); +$summarySheet->setCellValue("A{$row}", 'المجموع الكلي النهائي'); +$summarySheet->setCellValue("G{$row}", "=SUM(G{$summaryStartRow}:G{$lastSummaryRow})"); +$summarySheet->setCellValue("I{$row}", "=SUM(I{$summaryStartRow}:I{$lastSummaryRow})"); +$summarySheet->setCellValue("J{$row}", "=SUM(J{$summaryStartRow}:J{$lastSummaryRow})"); + +$summarySheet->getStyle("A{$row}:J{$row}")->applyFromArray([ + 'font' => ['bold' => true, 'size' => 13, 'color' => ['argb' => 'FF' . $totalFont]], + 'fill' => ['fillType' => Fill::FILL_SOLID, 'startColor' => ['argb' => 'FF' . $totalBg]], + 'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER], +]); + +foreach (['F', 'G', 'I', 'J'] as $c) { + $summarySheet->getStyle("{$c}{$summaryStartRow}:{$c}{$row}")->getNumberFormat()->setFormatCode('#,##0.000'); +} +$summarySheet->getStyle("H{$summaryStartRow}:H{$row}")->getNumberFormat()->setFormatCode('0%'); + // Set first sheet as active $spreadsheet->setActiveSheetIndex(0); diff --git a/app/modules_app/invoices/upload.php b/app/modules_app/invoices/upload.php index b62aae6..3b0d126 100644 --- a/app/modules_app/invoices/upload.php +++ b/app/modules_app/invoices/upload.php @@ -19,18 +19,18 @@ try { $tenantId = $decoded['tenant_id']; $userId = $decoded['user_id']; - // --- QUOTA CHECK --- - QuotaMiddleware::checkInvoiceQuota($tenantId); - // ------------------- - - $db = Database::getInstance(); - - $allowedRoles = ['admin', 'accountant', 'employee']; + $allowedRoles = ['super_admin', 'admin', 'accountant', 'employee']; if (!in_array($decoded['role'], $allowedRoles)) { json_error('غير مصرح لك برفع الفواتير', 403); exit; } + // --- QUOTA CHECK (skip for super_admin ONLY) --- + if ($decoded['role'] !== 'super_admin') { + QuotaMiddleware::checkInvoiceQuota($tenantId); + } + // ------------------- + // 2. Validate Request // استخدام $_POST للتعامل الآمن مع multipart/form-data $companyId = $_POST['company_id'] ?? null; @@ -197,7 +197,9 @@ try { } $savedIds[] = $invoiceId; - QuotaMiddleware::incrementInvoiceUsage($tenantId); + if ($decoded['role'] !== 'super_admin') { + QuotaMiddleware::incrementInvoiceUsage($tenantId); + } } $db->commit(); diff --git a/public/shell.php b/public/shell.php index d9e23f4..b90eef0 100644 --- a/public/shell.php +++ b/public/shell.php @@ -1391,7 +1391,7 @@ - @@ -2789,6 +2789,48 @@ + + +