🏭 تدقيق موديول التصنيع — مراجعة الوضع الحالي

تدقيق متعمّق عبر 4 محاور بالتوازي: دورة الإنتاج والترحيل المحاسبي · التكاليف والانحرافات · التخطيط (MRP/CRP/MPS) · الواجهة

Moon ERP · Modules/Production + features/production · شغّال على /app/factory · قراءة فقط

📅 14 يونيو 2026 🤖 4 وكلاء تدقيق متوازيين 🔍 قراءة فقط — لم يُعدَّل أي كود 💰 تركيز على دقة الأموال
2
CRITICAL — لازم تتصلّح قبل التشغيل الجاد
8
HIGH — دقة مالية / أمان / أداء
12+
MEDIUM — تناسق وجودة
الأساس سليم: الموازنة المحاسبية + الـi18n كاملين

الخلاصة التنفيذية

الموديول مبني باحتراف وانضباط — كل القيود المحاسبية متوازنة (DR==CR) وبتمر على فاليديشن، والـstock+GL في معاملة واحدة (atomic)، والـi18n كامل 100% (850 مفتاح في العربي والإنجليزي)، وانفصال machine/labor صح ومحافظ على الإجماليات. لكن فيه مشكلتين حرجتين + مجموعة دقة مالية/أداء تحتاج إصلاح قبل التشغيل على بيانات حقيقية بحجم كبير.

🔴 أخطر حاجتين:
  • نافذة ترحيل مزدوج (double-post): فحص الحالة بيتعمل قبل قفل الصف (lock)، ومفيش idempotency key على القيود → طلبين متزامنين ممكن يرحّلوا نفس القيد مرتين (أخطرها Close = تسوية WIP مرتين، وReceive = استلام مخزون مرتين).
  • خطأ في صافي احتياجات MRP متعدد المستويات: الـnetting بيمشي FIFO مش low-level-code حقيقي → بيـ«يقلّل تخطيط» المكوّنات المشتركة/العميقة (تحت-تخطيط فعلي).
🟢 مؤكّد سليم: الموازنة المحاسبية على كل المسارات · التقريب للقرش · حواجز الـstate machine (التحوّلات غير القانونية ممنوعة) · فكّ القيود (reversal) للمخزون والـGL · ذرّية المعاملات · انفصال machine/labor (الديمو بيطابق 31.80 بالظبط) · الـi18n كامل · شاشات board/terminal real-time محترفة · product-search المعاد كتابته صح.

المشاكل الحرجة (CRITICAL)

C1 — نافذة ترحيل مزدوج (دورة الإنتاج/GL)

فحص الحالة (canRelease/canIssue/canReceive/canClose) بيتعمل قبل الـlockForUpdate (أو من غير إعادة فحص بعد الـrefresh)، ومفيش idempotency guard على القيود (الجدول فيه index بس، مش unique على المستند).

الإصلاح: انقل فحص الحالة جوّه المعاملة بعد الـlock + refresh وأعد التأكيد؛ أضف lock مفقود لـRelease وClose؛ واربط القيد بمستنده (unique على (company_id, source_doc_type, source_doc_id)).

C2 — صافي الاحتياجات متعدد المستويات في MRP خاطئ

RunMrp.php:376-549 (planLevelByLevel) — بيدّعي المشي «الآباء قبل الأبناء» لكنه FIFO عادي مش low-level-code. أي طلب dependent بيتدمج في مكوّن بعد أول مرة اتعالج فيه → بيتجاهله الـprocessedOnce guard → المكوّنات المشتركة/العميقة بتتخطّط ناقصة. الاختبارات بتغطّي سلسلة 2-مستوى متوازنة بس (مفيش diamond/3-مستوى).

الإصلاح: حساب low-level-code لكل منتج أول (تمريرة واحدة)، وبعدين معالجة بالترتيب التصاعدي للـLLC — مايتعالجش منتج قبل ما كل آبائه الأقل مستوى يفجّروا مساهماتهم. + إضافة اختبارات للمكوّنات المشتركة والعمق.

١ دورة الإنتاج + الترحيل المحاسبي

الخطورةالمشكلةالمكان / الإصلاح
CRITICALنافذة ترحيل مزدوج (C1)guard قبل الـlock + مفيش idempotency — راجع فوق
HIGHClose مبيقفلش صف الأوردر إطلاقاًCloseProductionOrder.php:45-90 — أضف lockForUpdate + refresh + إعادة فحص canClose
HIGHإلغاء صرف المواد بيعكس على حسابات «آخر صرف» مش الصرف الملغيCancelMaterialIssue.php:160-219 — احفظ JE id على المستند واعكسه تحديداً (انحراف per-account)
HIGHأرضيات تكلفة عكس التأكيد بتكسر تطابق WIP↔AppliedConfirmOperation.php:355-364 — اعكس نفس المبلغ المسموح أو متعملش floor (drift بين الدفتر والفرعي)
MEDIUMاكتشاف «الريل» بـ=== 0.0 هشّProductionOrderController.php:323 — اكتشف بوجود مستندات issue/GR (زي Close)
MEDIUMبواقي تحت 0.01 بتتسايب في WIP وبتتراكمCloseProductionOrder.php:53-72 — اكنس أي بقية غير صفرية أو وثّق sweep دوري
MEDIUMفشل الترحيل التلقائي بيسيب المخزون اتحرّك والـGL Draft بصمتCreateJournalEntry.php:134-146 — راقب قيود الإنتاج Draft أو افشل بصوت عالٍ
LOWتكلفة الصرف بـfirstWhere(product_id) بتخلط السطور المكرّرةIssueMaterials.php:117 — طابق بالـindex/id (الإجمالي صح، التوزيع لأ)

٢ التكاليف والانحرافات

انفصال machine/labor مؤكّد سليم: decomposition فقط، الإجماليات ثابتة عبر كل المسارات (roll-up · accumulators · GL · variances)، والديمو بيطابق 31.80 بالظبط. مفيش CRITICAL.
الخطورةالمشكلةالمكان / الإصلاح
HIGHأساس المعيار في الانحرافات (3 أرجل) ممكن يختلف قرش-قرشين عن قيد GR (رجل واحدة)ComputeOrderVariances.php:178/236/289 ضد PostGoodsReceiptJournal.php:56 — وحّد أساس التقريب بين الاتنين
MEDIUMمجمّع تكلفة المواد مش بيتعمله re-round بعد الجمع (تسريب أقل من قرش)IssueMaterials.php:165round(sum + inc, 3) زي confirmation/cancel
MEDIUMFOVV في وضع applied tautology (بيتسجّل كانحراف لكنه لا يطابق)ComputeOrderVariances.php:368 — اقمعه أو علّمه structured flag
MEDIUMحساب Applied OH مبيتصفّاش في الوضع الافتراضي → الحساب بيكبر بلا حدSettleAppliedOverhead.php:166 — وثّق/صفّي حساب الامتصاص دورياً (نظافة GL)
LOWfallback صفر-ساعات بيحط كل الانحراف في رجل المعدّل · اختيار routing مكرّر في ملفين · Labor Applied تحت الخصومتفاصيل في تقرير الوكيل — تطابق reconciliation محفوظ

٣ التخطيط (MRP / CRP / MPS)

الخطورةالمشكلةالمكان / الإصلاح
CRITICALصافي الاحتياجات متعدد المستويات (C2) — FIFO مش LLCRunMrp.php:376-549 — راجع فوق
HIGHتواريخ سريان الـBOM (effective_from/to) متجاهلة تماماً في كل الـ3 resolversRunMrp.php:924 · BomExplosionService.php:136 · BuildComponentOrders.php:170
HIGHمفيش index على inventory_stock_balances(company_id, product_id) → full scan لكل منتجأضف index + ادمج الـSUMين + اسحب الكل دفعة واحدة (ده «MRP at scale» المؤجّل)
HIGHعاصفة N+1 (5 استعلام/منتج + 2/bucket، مفيش BOM cache)RunMrp.php:608/942 — preload مجمّع + cache (زي CRP)
MEDIUMالمعاملة كلها synchronous · POQ/EOQ شبه no-op · on-hand company-wide مش warehouseحوّل لـqueued job بعد إصلاح الاستعلامات · وثّق حدود lot-sizing · وحّد نطاق التوفّر
LOWCRP idle fan-out · nextRunNumber count()+1 race · مفيش وردية ليليةتفاصيل في تقرير الوكيل (محدودة)
سليم في MRP: إعادة التشغيل نظيفة (purge بيحافظ على firmed/converted) · حواجز الـBOM الدائرية · scrap/yield · الـtime-phasing وsafety stock · lot sizing (exact/fixed/min_max) · الحالات الحدّية.

٤ الواجهة (Frontend)

i18n كامل (PASS): 850 مفتاح اتأكّدوا في ar.json و en.json (صفر ناقص)، بما فيهم مفاتيح الـenum الديناميكية. مفيش نصوص مكتوبة inline.
الخطورةالمشكلةالمكان / الإصلاح
HIGHmaterial_ownership بيتشال عند الحفظ → أوامر التصنيع للغير (toll) مينفعش تتعمل أصلاًproduction-orders.component.ts:511 — ضيف الحقل للـpayload
HIGHمفيش *appCan على أزرار الكتابة إطلاقاً (0 مرة) → مفيش صلاحية «عرض فقط»؛ أي حد يفتح الشاشة يقدر يصرف/يستلم/يعمل فاتورة tollطبّق *appCan على Release/Issue/Complete/Cancel/Run/Approve (زي LIS)
HIGHنوع رجوع getCosting() غلط (nested مش flat) → تاب التكاليف فضي قبل كدهproduction-order.service.ts:185 — صحّح النوع وادمج الـflatten
HIGHتحويل استثناء MRP بيطابق بالـproduct_id بس → ممكن يحوّل الأوردر الغلطmrp-cockpit.component.ts:642 — disambiguate بمعرّف الطلب
MEDIUMعدم تناسق دقة الأرقام (2/3/4 منازل) + أرقام خام بدون number pipe + تواريخ batches off-by-oneوحّد على 3 منازل + locale حسب اللغة
MEDIUMproduction-orders.component.ts = 1502 سطر (~2× الحد)استخرج 3 dialogs (Issue/Receive/Toll) لمكوّنات فرعية
LOWابتلاع أخطاء صامت في تحميل القوائم · production-tools مفيهوش OnDestroy · كود ميت بسيطضيف toasts + takeUntilDestroyed

حاجات مؤكّد إنها سليمة (للاطمئنان)

🗺 خطة الأولويات المقترحة

الأولويةالبندالأثر
1قفل دورة الإنتاج + idempotency للقيود (C1, H1-lifecycle) — نقل فحص الحالة جوّه الـlock + ربط القيد بالمستنديمنع ترحيل/مخزون مزدوج (خطر مالي مباشر)
2إعادة كتابة netting الـMRP كـlow-level-code (C2) + اختبارات shared/deepيمنع تحت-تخطيط المكوّنات
3أداء MRP: index على stock_balances + preload مجمّع + BOM cache (الدين المؤجّل)يخلّيه يشتغل at scale
4سريان الـBOM (effective dates) في الـ3 resolversصحة الاحتياجات
5FE: material_ownership في الحفظ + *appCan على أزرار الكتابة + نوع getCostingtoll يشتغل + صلاحيات عرض-فقط
6توحيد أساس التقريب (variances↔GR) + re-round مجمّع المواد + نظافة Applied OHدقة مالية للقرش
7تنظيف: تقسيم production-orders (1502 سطر)، توحيد دقة الأرقام، toasts للأخطاءجودة وصيانة
توصية: البنود 1 و2 (CRITICAL) قبل أي تشغيل على بيانات حقيقية بحجم كبير أو متعدد المستخدمين. الباقي تحسينات دقة/أداء/جودة تتعمل على دفعات.
↑ أعلى