From c6040b3b85e7a0b4e36b49264e879dafd5b34acc Mon Sep 17 00:00:00 2001 From: Hamza-Ayed Date: Mon, 4 May 2026 02:18:52 +0300 Subject: [PATCH] Update: 2026-05-04 02:18:52 --- app/modules_app/invoices/file.php | 33 +++ app/modules_app/invoices/view.php | 67 ++++++ public/index.php | 2 + public/shell.php | 379 +++++++++++------------------- 4 files changed, 240 insertions(+), 241 deletions(-) create mode 100644 app/modules_app/invoices/file.php create mode 100644 app/modules_app/invoices/view.php diff --git a/app/modules_app/invoices/file.php b/app/modules_app/invoices/file.php new file mode 100644 index 0000000..af9f44e --- /dev/null +++ b/app/modules_app/invoices/file.php @@ -0,0 +1,33 @@ +prepare("SELECT tenant_id, original_file_path FROM invoices WHERE id = ?"); +$stmt->execute([$id]); +$invoice = $stmt->fetch(); + +if (!$invoice) die('Not found'); + +// Authorization +if ($decoded['role'] !== 'super_admin' && $invoice['tenant_id'] !== $decoded['tenant_id']) { + die('Unauthorized'); +} + +$filePath = $invoice['original_file_path']; +if (!file_exists($filePath)) die('File missing'); + +$mime = mime_content_type($filePath); +header("Content-Type: $mime"); +header("Content-Length: " . filesize($filePath)); +readfile($filePath); +exit; diff --git a/app/modules_app/invoices/view.php b/app/modules_app/invoices/view.php new file mode 100644 index 0000000..2ae9341 --- /dev/null +++ b/app/modules_app/invoices/view.php @@ -0,0 +1,67 @@ +prepare(" + SELECT i.*, c.name as company_name + FROM invoices i + LEFT JOIN companies c ON i.company_id = c.id + WHERE i.id = ? + "); + $stmt->execute([$id]); + $invoice = $stmt->fetch(); + + if (!$invoice) { + json_error('Invoice not found', 404); + } + + // 3. Authorization Check + if ($decoded['role'] !== 'super_admin') { + if ($invoice['tenant_id'] !== $decoded['tenant_id']) { + json_error('Unauthorized access to this invoice', 403); + } + } + + // 4. Fetch Line Items + $stmtLines = $db->prepare("SELECT * FROM invoice_lines WHERE invoice_id = ? ORDER BY line_number ASC"); + $stmtLines->execute([$id]); + $invoice['items'] = $stmtLines->fetchAll(); + + // 5. Decrypt Fields + $invoice['supplier_tin'] = Encryption::decrypt($invoice['supplier_tin'] ?? '') ?: $invoice['supplier_tin']; + $invoice['supplier_name'] = Encryption::decrypt($invoice['supplier_name'] ?? '') ?: $invoice['supplier_name']; + $invoice['supplier_address'] = Encryption::decrypt($invoice['supplier_address'] ?? '') ?: $invoice['supplier_address']; + $invoice['buyer_tin'] = Encryption::decrypt($invoice['buyer_tin'] ?? '') ?: $invoice['buyer_tin']; + $invoice['buyer_name'] = Encryption::decrypt($invoice['buyer_name'] ?? '') ?: $invoice['buyer_name']; + $invoice['buyer_national_id'] = Encryption::decrypt($invoice['buyer_national_id'] ?? '') ?: $invoice['buyer_national_id']; + + if (!empty($invoice['company_name'])) { + $invoice['company_name'] = Encryption::decrypt($invoice['company_name']) ?: $invoice['company_name']; + } + + // 6. Generate Public URL for File (Assuming storage is symlinked or served) + // For now, let's just return the relative path or a proxy route + // We'll add a proxy route later if needed. + $invoice['file_url'] = '/index.php?route=v1/invoices/file&id=' . $invoice['id']; + + json_success($invoice); + +} catch (\Exception $e) { + json_error('Error fetching invoice: ' . $e->getMessage(), 500); +} diff --git a/public/index.php b/public/index.php index 3417085..c0e518c 100644 --- a/public/index.php +++ b/public/index.php @@ -26,6 +26,8 @@ $routes = [ 'v1/companies/create' => ['POST', 'companies/create.php'], 'v1/companies/delete' => ['POST', 'companies/delete.php'], 'v1/invoices' => ['GET', 'invoices/index.php'], + 'v1/invoices/view' => ['GET', 'invoices/view.php'], + 'v1/invoices/file' => ['GET', 'invoices/file.php'], 'v1/invoices/upload' => ['POST', 'invoices/upload.php'], 'v1/dashboard/stats' => ['GET', 'dashboard/stats.php'], 'v1/tenants' => ['GET', 'tenants/index.php'], diff --git a/public/shell.php b/public/shell.php index b4c0b2e..7ad69ac 100644 --- a/public/shell.php +++ b/public/shell.php @@ -18,6 +18,7 @@ body { font-family: 'IBM Plex Sans Arabic', sans-serif; background-color: var(--bg-base); color: var(--text-primary); } [x-cloak] { display: none !important; } .glass { background: rgba(13, 20, 36, 0.7); backdrop-filter: blur(12px); border: 1px solid rgba(255,255,255,0.05); } + .scrollbar-hide::-webkit-scrollbar { display: none; } @@ -87,27 +88,6 @@
- -
-
-
-
📄
-

إجمالي الفواتير

-

-
-
-
-

قيد المعالجة

-

-
-
-
-

تم الاعتماد

-

-
-
-
-
@@ -144,7 +124,7 @@ x-text="inv.status"> - + @@ -153,160 +133,121 @@
- -
-
- - - - - - - - - - - - - - -
الشركةالأرقام الرسميةالعنوانالمكتبإجراءات
لا توجد شركات بعد
-
-
- - -
-
- - - - - - - - - - - - - - -
المستخدمالمكتبالدورالحالةإجراءات
لا يوجد مستخدمون بعد
-
-
+
- -
-
-

رفع فواتير جديدة 📤

-

سيقوم النظام باستخراج البيانات آلياً باستخدام الذكاء الاصطناعي

+ +
+
-
-
- - + +
+
+ معاينة المستند الأصلي + تحميل الملف 📥 +
+
+ + +
+
+ + +
+
+
+

تفاصيل الفاتورة المستخرجة

+

AI-Powered Extraction (Gemini 1.5 Flash)

+
+
-
- -
- 📄 -

-

PDF, PNG, JPG (Max 5MB)

+
+ +
+
+ +

+

TIN:

+

+
+
+ +

+

+

+
+
+ + +
+ +
+ + + + + + + + + + + + + + +
#الوصفالكميةالسعرالضريبةالإجمالي
+
+
+ + +
+
+
+ المجموع الفرعي + +
+
+ الخصم الإجمالي + +
+
+ ضريبة المبيعات + +
+
+ الإجمالي النهائي + +
+
-
- - +
+ +
- -
-
- - -
-
-

إضافة مستخدم جديد 👥

-
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
- - -
-
+
+
+