العميل بيجرّب الصرف الجزئي لخامات أمر الإنتاج، وبيبلّغ بمشكلتين:
completed بينما المادة «خام بودرة ميلامين» متصرّف منها 5.000 من 12.360 (متبقّي 7.360) → زر الصرف مختفي تمامًا فمفيش أي مكان للصرف — لا للمتبقّي ولا للزيادة.
| الأمر | الحالة | المادة | مطلوب | متصرّف | متبقّي |
|---|---|---|---|---|---|
| PRD-2026-00022 (id 39) | completed | خام بودرة ميلامين | 12.360 | 5.000 | 7.360 |
| بودرة جليز | 0.400 | 0.400 | 0.000 |
produced_quantity = 0.000 — الأمر «مكتمل» رغم عدم إنتاج شيء وعدم اكتمال صرف الخامات.
production_orders.status = 'completed' · مادة id 84 consumed 5.000 < planned 12.360. moonui2_dev_be (SELECT فقط)canIssue() = Released || InProcess فقط — completed غير مشمولة. Production/app/Enums/ProductionOrderStatus.php:74-77canIssueMaterials(status) = status==='released' || status==='in_process' → على أمر مكتمل الزر لا يُعرض إطلاقًا (قائمة وتفاصيل). production-orders.component.ts:1329-1330 · .html:120-123, 316-319complete() يتحقّق من canComplete() (الحالة = InProcess) فقط — لا يوجد حارس يمنع الاكتمال ومواد لسه ناقصة الصرف. ProductionOrderController.php:314-329 · Enum transitions InProcess→[Completed] :47consumed_quantity بيتراكم (يُضاف لا يُستبدل)، فالصرف على دفعات مدعوم بالكامل خادميًا. IssueMaterials.php:300-303 · resolveLines:465-528completed بينما بعض المواد لسه ناقصة الصرف (الحارس complete() يفحص الحالة فقط بلا فحص «اكتمال صرف الخامات» — ProductionOrderController.php:314-329)، وcanIssue()/الواجهة تستثني completed — فبعد الاكتمال يختفي مدخل الصرف نهائيًا. النتيجة: لا يمكن صرف المتبقّي ولا الزائد لأن أي صرف أصبح ممنوعًا بالحالة.insufficient_stock) في Inventory/app/Actions/ApproveIssue.php:200-207. يعني إحساس العميل بأن «النظام يمنع الصرف فوق المطلوب» سببه إمّا حالة الأمر المكتمل (أعلاه) أو نقص رصيد — مش قاعدة إنتاج.
released/in_process: الواجهة تبني صفًّا لكل مادة بأعمدة مطلوب/متصرّف/متبقّي وتملأ الكمية بالمتبقّي وتعيد الجلب عند كل فتح؛ الصرف الجزئي واختيار جزء من المواد (كمية 0 = تخطّي) وصرف أكتر من المتبقّي (لا يوجد max) كلها تعمل. production-orders.component.ts:882-900,1051-1074 · .html:591-618 · IssueMaterials.php:300-303 · canIssue InProcess=trueحارس ناقص عند الاكتمال (missing guard) + حالة تمنع الصرف. منطق أوامر الإنتاج يسمح بالاكتمال بمجرد أن الحالة in_process بغضّ النظر عن اكتمال صرف الخامات أو الإنتاج (produced_quantity=0). لأن الصرف الناقص (under-issue) سلوك مشروع أحيانًا، مفيش حارس. لكن ما إن يكتمل الأمر حتى تُغلق كل مداخل الصرف (canIssue() تستثني completed) — فالمستخدم اللي أكمل الأمر مبكرًا (يدويًا أو بالخطأ) يعلق بلا طريق لصرف الباقي. مش انحدار (regression) — ده فجوة تصميمية في دورة حياة الأمر ظهرت أول ما العميل جرّب الصرف على دفعات.
| البُعد | النتيجة |
|---|---|
| البيانات | PRD-00022 عالق فعلًا (completed + متبقّي 7.360). أوامر أخرى مكتملة بمواد ناقصة محتملة — يُفحص عند الإصلاح. لا يحتاج migration بيانات لو أضفنا «إعادة فتح». |
| مسار الكود (كل المنادين) | الصرف يمرّ من ProductionOrderController::issueMaterials وConfirmOperation::backflush (كلاهما IssueMaterials). الحارس المفقود في complete() فقط. ProductionOrderController.php:314 |
| الإعداد/الأنماط | فيتشر ISS-9103 (موافقة المخزن، افتراضي OFF) موجود على نفس الشجرة. لا يغيّر الجذر: الحالة completed تمنع الصرف في الوضعين. |
| الصلاحيات | غير معتمِد على الدور؛ زر الصرف محكوم بالحالة لا بالصلاحية. |
| مالي [FIN] | صرف الخامات يرحّل قيد WIP؛ صرف مواد على أمر «مكتمل» له معنى محاسبي حسّاس (WIP بعد الاكتمال) → قرار التصميم يجب أن يراعيه. |
| حالات حدّية | الصرف الزائد فوق المطلوب: مسموح فنيًّا (يقيّده الرصيد فقط). under-issue: مشروع. الأمر المُقفل (Closed) لا يُعاد فتحه. |
| مواضع مشابهة كامنة | canIssue() يُستدعى من الـFE والـBE بنفس الاستثناء — نقطة واحدة. لا يوجد حارس اكتمال مشابه في close() أيضًا (يُراجع). |
عند الضغط على «إنهاء»، لو فيه مواد متبقّية > 0 → تأكيد صريح («فيه خامات لسه ما اتصرفتش — تصرفها الأول ولا تكمّل بصرف ناقص؟») بدل الاكتمال الصامت. + رسالة insufficient_stock أوضح. لا يمنع under-issue المشروع، بس يمنع الاكتمال «بالغلط».
زر «إعادة فتح للصرف» ينقل الأمر من completed لـin_process → يظهر زر الصرف → يصرف المتبقّي/الزائد → يكمّل تاني. يصلح PRD-00022 والحالات العالقة فورًا بلا تعديل بيانات يدوي.
توسيع canIssue() لتشمل completed (حتى الإقفال). أبسط لكن يُضعف معنى «مكتمل» ويسمح بترحيل WIP بعد الاكتمال بلا وعي — غير مفضّل مقارنة بـA+C.
الصرف حتى الكمية المطلوبة (التقييم الأوّلي) = حرّ زي ما هو (يشمل المتبقّي والصرف على دفعات). أمّا الصرف اللي يتجاوز المطلوب (consumed + الكمية الجديدة > planned للمادة) → يُحجز بانتظار موافقة مسؤول الإنتاج قبل تحريك المخزون، مع سبب إلزامي (هدر/سقط/إعادة تشغيل). الجزء المعتمَد يُصرف ويظهر انحرافه في التكلفة عبر production.cost_variance_account_id (موجود). يُبنى خلف إعداد production.over_issue_requires_approval بصلاحية جديدة production.orders.approve_over_issue (مسؤول إنتاج، منفصلة عن أمين المخزن في ISS-9103).
| WP | النطاق | Repo | الاختبار | [FIN] | Migration |
|---|---|---|---|---|---|
| WP1 | حارس تأكيد عند «إنهاء» أمر فيه مواد متبقّية > 0 (تأكيد صريح بدل الاكتمال الصامت). حماية BE + رسالة FE. | BE+FE | Pest: إنهاء بمواد ناقصة يتطلّب تأكيد/يُرفض بلا العلم | — | — |
| WP2 | إجراء «إعادة فتح للصرف» Completed→InProcess (صلاحية + endpoint + زر). يصلح الأوامر العالقة. | BE+FE | Pest: reopen يعيد الحالة ويسمح بصرف المتبقّي | ✅ (WIP) | — |
| WP3 | الصرف حتى المطلوب حرّ: تحسين وضوح زر الصرف (label) وعرض المتبقّي + توضيح رسالة نقص الرصيد. الصرف على دفعات/المتبقّي يشتغل بلا موافقة إضافية. | FE (+رسائل BE) | Pest: صرف المتبقّي حتى planned ينجح مباشرةً | — | — |
| WP4 | دورة موافقة للصرف الزائد فوق المطلوب: إعداد production.over_issue_requires_approval + صلاحية production.orders.approve_over_issue (مسؤول إنتاج)؛ لمّا consumed+الكمية > planned → يُحجز الجزء الزائد بانتظار موافقة مع سبب إلزامي؛ بعد الاعتماد يُصرف ويظهر في انحراف التكلفة. يتوافق مع موافقة أمين المخزن (ISS-9103) كطبقتين مستقلتين. | BE+FE | Pest: تجاوز planned يُحجز؛ بعد approve يُصرف؛ رفض الموافقة لا يحرّك مخزون | ✅ (WIP/انحراف) | محتمل (جدول/عمود طلب موافقة زائد) |
مؤجّل/للمراجعة: هل نضيف حارسًا مشابهًا عند الإقفال (close)؟ · فحص أوامر مكتملة أخرى بمواد ناقصة (تقرير، لا migration).
production.orders.approve_over_issue) منفصلة عن أمين المخزن (ISS-9103)؟ أم نفس معتمِد المخزن؟production.over_issue_requires_approval افتراضي ON (يطابق طلبك: أي تجاوز يحتاج موافقة) وتقدر الشركة تقفله؟تقرير مرحلة أولى (تشخيص) — لا يُكتب أي كود قبل موافقتك على الحلّ والخطة أعلاه. بعد الموافقة تُنفَّذ WP1→WP3 مع اختبار يثبت الإصلاح ومراجعة مستقلة.