تدقيق مالي شامل · 6 محاور متوازية

تدقيق الحسابات + المبيعات/المشتريات/المخازن + جاهزية التصنيع

تحليل عميق لموديول الحسابات (هل شغّال، الناقص، مقارنة بالأنظمة الكبرى، نضيف إيه)، وفحص المبيعات والمشتريات والمخازن وجاهزيتهم للتكامل مع التصنيع — بأدلة من الكود وخطة عمل.

2026-06-16 · Accounting ~42.6K LOC (44 model · 40 service · 40 action · 139 route · 63 test) · Sales 17K · Purchases 18.5K · Inventory 16.3K
ناضجالحسابات: نظام محاسبي حقيقي
7+باجز محاسبية حرجة
~85٪جاهزية Sales→MRP (الطلب)
~60٪جاهزية المخازن للتصنيع
18اقتراح إضافة (KSA + كبرى)
⚖️

٠ — الحكم العام

حسابات ناضجة وشاملة فعلاً — بس فيها عيوب سلامة بيانات حرجة في GL. والمخازن محتاجة شغل قبل التصنيع.

الحسابات نظام محاسبي حقيقي وكامل (مش skeleton): دليل حسابات شجري، قيود مزدوجة بـ bcmath، فترات مالية بقفل، عملات متعددة + إعادة تقييم، بنوك وتسويات، أصول ثابتة وإهلاك، موازنات ومراكز تكلفة، زكاة، وZATCA (في موديول EInvoicing). القوائم المالية موجودة (ميزان مراجعة، دخل، مركز مالي، تدفقات). والـ posting موحّد عبر action واحد — تصميم ممتاز.

لكن — العيب الأخطر: القيد المزدوج (مدين=دائن) مش مفروض وقت الحفظ! دالة التحقق validateBalance() موجودة بس **كود ميت مش متنادى**. قيد غير متوازن من أي موديول بيتحفظ ويُرحّل، والخلل بيتكشف لاحقاً بـ scanner مش بيتمنع. ده + باجز الإقفال السنوي المزدوج والترحيل المزدوج = مخاطر مالية حقيقية.
التكامل مع التصنيع: المبيعات→MRP (الطلب) جاهز فعلاً ✅. المشتريات→MRP (التوريد) فيه فجوات (حلقة الشراء بتقف عند موافقة يدوية). المخازن عقد StockService اللي التصنيع بيستخدمه ممتاز، بس التكلفة (WAC layers) والـ UoM والـ lot/expiry محتاجين شغل قبل تشغيل التصنيع جدّياً.
🏛️

١ — الحسابات: المعمارية والموجود (هل شغّال؟)

نعم شغّال وكامل — الدورة المحاسبية مقفولة والقوائم موجودة.

الموجود فعلاً

الحكم: نطاق production-grade حقيقي. ZATCA Phase-2 موجود في موديول EInvoicing منفصل (UBL 2.1 + CSID + clearance) لكنه مدفوع من Sales/POS مش من الحسابات.

ضعف معماري

🐞

٢ — الحسابات: باجز GL حرجة

العيوب اللي بتأثر على توازن الدفاتر والأرقام المالية مباشرة.
CRITICAL القيد المزدوج مش مفروض وقت الإنشاء/الترحيل (validateBalance كود ميت)
JournalEntryService.php:44 (مش متنادى) · CreateJournalEntry.php:61 · StoreJournalEntryRequest.php (مفيش قاعدة توازن)

القيد بيحسب total_debit/credit ويخزّنهم من غير ما يتأكد إنهم متساويين. قيد غير متوازن بيتحفظ Draft من غير خطأ، والوحيد اللي بيمنع = خطوة الاعتماد (لو مش متجاوَزة). مفيش DB CHECK constraint ولا حارس وقت الكتابة → التوازن معتمد على فحص واحد بيقرأ أعمدة self-reported.

CRITICAL الإقفال السنوي يقدر يشتغل مرتين → أرباح محتجزة مزدوجة
YearEndClosingService.php:25 · ExecuteYearEndClosing.php:44 (مفيش unique على fiscal_year_id)

الحارس بيتأكد بس من isClosed()؛ بعد ReopenFiscalYear الحالة تبقى Reopened فالـ readiness يعدّي تاني. إقفال تاني = نقل صافي الدخل للأرباح المحتجزة مرة كمان → حقوق الملكية مبالغ فيها بسنة كاملة. وكمان: السنة بتتعلّم "مقفولة" حتى لو قيود الإقفال فشلت تترحّل بصمت.

CRITICAL الاعتماد المزدوج/إعادة المحاولة بيرحّل لـ GL مرتين (idempotency_key مش متبعت)
ApprovePaymentVoucher.php:22 · ApproveReceiptVoucher · ApproveExpense · ApproveRevenue

الحارس if(!isDraft()) بدون قفل، والمستند بيتحمّل بدون lockForUpdate. اعتمادان متزامنان (دبل كليك/retry) الاتنين يعدّوا ويرحّلوا → قيدان لمستند واحد. آلية الـ idempotency موجودة في CreateJournalEntry بس مفيش action بيبعت المفتاح.

#المشكلةالمكانالخطورة
سطر كشف بنكي يقدر يتطابق مرتين/أكثر من قيمته (مفيش unique ولا قفل) → رصيد مسوّى مبالغ فيهBankReconciliationService.php:187CRIT
إشارة ربح/خسارة إعادة التقييم غلط للالتزامات (AP/قروض) — مكسب يتسجّل بدل خسارةRevalueForeignBalances.php:59HIGH
الإهلاك المتناقص ~12× أبطأ (خلط شهور/سنين في المعادلة)FixedAssetService.php:48HIGH
dispose() بيحط الخسارة في حساب مصروف الإهلاك ويسيب القيد غير مرحّل → الأصل يفضل في الميزانيةFixedAssetService.php:230HIGH
شيك مرتجع/ملغي بعد التحصيل مفيش قيد عكسي → بنك/كاش مبالغ فيهReturnCheck.php · CancelCheck.phpHIGH
رصيد العهدة (petty cash) lost-update بدون قفل → سحب زائدPettyCashBalanceService.php:60HIGH
الإقفال/المقاصة غير transactional وبدون قفل (race)CloseFiscalYear.php · ArApService.php:240HIGH
فجوة تستات: صفر تغطية لـ idempotency والـ concurrency؛ ومفيش تست بيرسل قيد غير متوازن عبر الـ API ويتوقع رفضه (لأنه مفيش حارس أصلاً). الإقفال المزدوج بعد reopen مش متغطّى. (إيجابي: SequenceService توليد الأرقام atomic وآمن).
🧩

٣ — الحسابات: الناقص مقارنة بالأنظمة الكبرى + نضيف إيه

مقارنة بـ QuickBooks/Xero/Zoho/Odoo/SAP — مع سياق السعودية (ZATCA/زكاة/IFRS).
القدرةالحالةملاحظة
GL أساسي (دليل/قيود/فترات/عملات/متكررة)موجودناضج
القوائم: ميزان/دخل/مركز ماليموجود
قائمة التدفقات النقديةجزئيproxy مبسّط — مش indirect method حقيقي (مفيش working-capital/إهلاك add-back). أكبر فجوة صحة
أعمدة المقارنة (سنة سابقة)ناقصكل القوائم فترة واحدة بس
تسوية AR/AP على مستوى الفاتورة (allocation)جزئيعلى مستوى الحساب + netting بس
فرق عملة محقّق (realized FX) عند السدادناقصبس unrealized revaluation
إقرار ضريبة القيمة المضافة بصيغة ZATCAناقصفي ملخص بالنسبة بس — مفيش نموذج الـ 14 خانة
توقيع ZATCA XAdES/XMLDSIG كاملجزئيالتوقيع مخزّن كـ XML comment — ممكن يترفض في Phase-2
الزكاة (طريقة صافي الثروة)موجودمحتاج طبقة تعديلات SOCPA
أبعاد/تحليلية (project/segment) على سطر القيدجزئيمركز تكلفة بس
دمج كيانات/Intercompany · إيراد مؤجل · مسار تدقيق hash-chain · workflow اعتمادناقصقدرات enterprise

أولويات الإضافة

🛒

٤ — المبيعات والمشتريات

مبنيين كويس standalone — بس فيهم فجوات قفل وثغرة استلام خطيرة.

قوي

كل الـ actions المعدِّلة داخل transaction مع فحص enum؛ GL موحّد ومتوازن؛ المرتجعات بتعكس الإيراد/الضريبة/COGS وترجّع المخزون؛ تسوية مدفوعات FIFO بدايلوج كويس. PostLandedCostVoucher هو النمط المرجعي (قفل + idempotency).

محتاج شغل

المشكلةالمكانالخطورة
استلام بضاعة (GRN) ضد أمر شراء Draft/غير معتمد — يكتب مخزون و received_quantity لأمر لسه ماتعمدشPurchaseGrnController.php:335CRIT
مسارات إنشاء/تحويل المبيعات مش transactional → headers يتيمة تلوّث طلب الـ MRPSalesOrderController.php:120HIGH
مسارات الترحيل بدون lockForUpdate + بدون whereNull(journal_entry_id) → ترحيل/خصم مخزون مزدوجPostSalesInvoice.php:32HIGH
فاتورة يدوية بتتجاوز فحص حالة الأمر وسقف الكمية؛ مفيش فرض حد ائتمانيSalesInvoiceController.php:113HIGH
received_quantity read-modify-write غير atomic؛ مفيش مسار عكس لـ GRN معتمدPurchaseGrnController.php:524HIGH
📦

٥ — المخازن والتكلفة

عقد StockService ممتاز — بس صحة التكلفة (WAC/FIFO) والقفل والـ lot محتاجين شغل.

قوي وجاهز للتصنيع

محتاج شغل

CRITICAL طريقة WAC مبتستهلكش cost layers → تقارير التقييم مبتتطابقش
StockService.php:126 (FIFO بس) · InventoryCostReportController.php:105 vs InventoryReportController.php:221

في الوضع الافتراضي (weighted_avg) الصرف بيقلّل total_value بس بيسيب remaining_quantity في الطبقات زي ما هي. فتقرير الأعمار (يجمع الطبقات) وتقرير قيمة المخزون (يقرأ StockBalance) مبيتصالحوش بعد أي صرف، والطبقات تكبر بلا حدود.

المشكلةالمكانالخطورة
تكلفة FIFO بتضيع عند التحويل بين المخازن (يستلم بمتوسط مش بطبقات)ShipTransfer.php:61HIGH
FIFO بيقلّل التكلفة عند المخزون السالب (الزيادة تتصرف بتكلفة صفر) → COGS أقلStockService.php:257HIGH
قفل غير متسق: core increaseStock/decreaseStock read-modify-write بدون قفل → lost updateStockService.php:38,141HIGH
مفيش lot/expiry على StockBalance وcost layers — genealogy التصنيع مالهاش مقابل في المخزون؛ مفيش FEFOStockBalance · InventoryCostLayerHIGH
مفيش تحويل وحدات (UoM) عند حدود المخزون — صرف BOM بوحدة مختلفة عن الشراء = جمع غلطStockService.php:47HIGH
🏭

٦ — جاهزية التكامل مع التصنيع (الحكم المجمّع)

التزاوج صحي وأحادي الاتجاه — لكن فيه ٣ فجوات بتكسر الحلقة المغلقة.
التدفّقالحالةالتفاصيل
المبيعات → MRP (الطلب)جاهز ✅MRP بيقرأ SalesOrder بحقول صحيحة وdelivered_quantity متتبّع فعلاً. أهم تدفّق وهو سليم.
المشتريات → MRP (التوريد)فجوةالـ PO المُولّد من MRP بيتعمل Draft بس canConvert() بيطلب Approvedالحلقة بتقف عند موافقة يدوية. والمرتجع مبيقللش received_quantity → إشارتا التوريد بتختلفا.
المخازن → التصنيعالعقد ممتازreserve/release/ATP صحيح — بس التكلفة (WAC/FIFO) والـ UoM والـ lot محتاجين إصلاح قبل التشغيل الجدّي.
التصنيع → الحسابات (GL)شغّالعبر events→listeners بـ idempotency — أنظف نمط في الـ ERP.
الخلاصة: العمود الفقري للطلب (المبيعات) جاهز، والـ GL جاهز. اللي محتاج إصلاح قبل التصنيع الجدّي: (١) قفل حلقة الشراء MRP→PR→PO، (٢) إصلاح تكلفة المخازن (WAC layers + FIFO transfer + negative)، (٣) إضافة UoM وlot/expiry على حدود المخزون عشان batch genealogy.
🖥️

٧ — الـ UI والفورمات (هل شغّالة كويس؟)

أحسن من الـ LIS (فيه design system حقيقي، مفيش شاشات ميتة) — بس فيه فجوات مهمة.

الفورمات

الشاشات والجودة

أهم تحسينات UI: (١) إظهار الضريبة حيّة في الفواتير، (٢) منع الصرف الزائد، (٣) شاشات قوائم مالية في الحسابات (انقلها من lis)، (٤) عرض تطابق ثلاثي، (٥) استخراج <line-items-grid> مشترك + OnPush.
🗺️

٨ — خطة العمل (بالأولوية)

الموجةالشغلليه
١ — سلامة GLافرض القيد المزدوج وقت الكتابة (+ DB CHECK)، idempotency_key من كل المعتمِدين + قفل، حماية الإقفال السنوي من التكراربتفسد توازن الدفاتر والأرقام دلوقتي
٢ — باجز ماليةإشارة FX للالتزامات، إهلاك متناقص، dispose()، قيد عكس الشيكات، تطابق بنكي مزدوج، قفل العهدةأرقام مالية غلط
٣ — جاهزية التصنيعقفل حلقة MRP→PR→PO، GRN ضد PO معتمد، إصلاح WAC layers + FIFO transfer/negative، UoM + lot/expiry على المخزون، قفل post pathsقبل تشغيل التصنيع جدّياً
٤ — امتثال KSAإقرار VAT بصيغة ZATCA، توقيع XAdES كامل، ضريبة عكسية، شهادات WHT، تعديلات زكاةتنظيمي
٥ — اكتمال + UIتدفقات indirect، أعمدة مقارنة، تسوية فاتورة AR/AP، شاشات قوائم مالية في الحسابات، الضريبة الحيّة، منع الصرف الزائد، OnPush + line-items-gridاكتمال وظيفي وتجربة
٦ — enterpriseأبعاد عامة، إيراد مؤجل، دمج كيانات، مسار تدقيق hash-chain، workflow اعتمادتوسّع مستقبلي
الخلاصة: الحسابات أساس قوي جداً ومتبنيش من جديد — ركّز على إصلاحات سلامة GL (الموجة ١-٢) لأنها بتأثر على الأرقام دلوقتي، وبعدين جاهزية المخازن/الشراء للتصنيع لو هتشغّل التصنيع، وبعدين امتثال KSA.
تدقيق الحسابات + المبيعات/المشتريات/المخازن + جاهزية التصنيع — Moon ERP · 6 محاور · أدلة من الكود · 2026-06-16