هذا الملحق يربط دورة العميل الفعلية (مصنع أدوية يصنّع للغير بالأوردر — «تصنيع للغير») بما هو مبنيٌّ فعلاً في Moon ERP. لكل لبنة تحتاجها الدورتان — دورة التكلفة الاستكشافية ودورة الإنتاج بالأوردر — حُسم أحد ثلاثة أحكام: موجود يُعاد استخدامه كما هو، أو جزئي بنية أساسية حاضرة تحتاج توصيلاً أو توسعة، أو مفقود بناء جديد. كل حكم مسنود بملف وسطر في الشيفرة.
Draft BOM) ← المحاسبة تحسب التكلفة المبدئية ← يعود السعر المبدئي للعميل كعرض سعر.| اللبنة المطلوبة | الحكم | أين تقع / ما الناقص |
|---|---|---|
| عرض سعر وتحويله إلى أوردر (سعر الدورة 1 + الأوردر الرسمي للدورة 2) | موجود | Modules/Sales دورة كاملة Draft→Sent→Accepted→Converted مع إجراء convertFromQuotation |
| دفعة العميل تحت الحساب بمعالجة محاسبية صحيحة (التزام مقدم لا تحصيل ذمم) | جزئي | سند القبض ReceiptVoucher وحساب 2104 إيرادات مقدمة موجودان، لكن بلا ربط بأوردر، وSalesPayment مقيّد بالفاتورة |
| خامات العميل المملوكة له (أمانة/عهدة لدى المصنع) | مفقود | لا نوع Consignment في المخازن ولا حقل ملكية على الرصيد |
| سير عمل البحث والتطوير ودفعة التجربة | جزئي | BomStatus::Draft جاهز للقائمة المبدئية؛ وحدة CMMS صيانة أصول لا بحث وتطوير؛ لا كيان لدفعة التجربة |
| سير موافقات لبوابات المراحل (اعتماد القائمة، بوابة الدفعة، إطلاق الأوردر) | جزئي | محرك موافقات عام في Modules/Core لكن المسجَّل فيه Sales وPurchases فقط — لا Production |
| خط CRM لاستقبال طلبات التسعير (RFQ) | مفقود | Modules/CRM دعم وتذاكر (Tickets/SLA) لا خط فرص بيعية |
| بدائية حجز المواد | جزئي | عمود StockBalance.reserved_quantity ودالة available موجودان لكن لا كود يكتب فيهما |
| انتقالات مراحل الإنتاج (أساس واجهات المراحل) | جزئي | ProductionOrderController فيه confirm/start/complete/consume؛ لا مراحل عميل/تجربة/دفعة/حجز |
العمود الفقري للدورة 1 (عرض السعر) وللأوردر الرسمي في الدورة 2 مبنيٌّ بالكامل في Modules/Sales.
SalesQuotation.php برأس وبنود وإجماليات وتاريخ صلاحية، وحقل ربط عكسي sales_order_id (سطر 56).Draft → Sent → Accepted/Rejected/Expired → Converted/Cancelled مع duplicate لإعادة التسعير (المتحكم SalesQuotationController).SalesOrderController::convertFromQuotation() (سطر 368) مشروط بحالة Accepted، ينسخ الرأس والبنود ويعلّم العرض Converted؛ المسار POST quotations/{quotation}/convert-to-order.قيد التطبيق على الدورة: سعر الدورة 1 هو SalesQuotation مسعّر من قائمة المواد المبدئية؛ والأوردر الرسمي للدورة 2 هو ناتج convertFromQuotation. كل مستندات الدورة 2 يجب أن تتعلّق بمعرّف هذا الأوردر، أي أن أوامر الإنتاج الجديدة (mfg_*) تحتاج مفتاحاً أجنبياً sales_order_id.
هذه أدقّ نقطة مالياً: الدفعة تحت الحساب التزام مقدم على المصنع وليست تحصيلاً لذمة مدينة. تسجيلها كدفعة بيع عادية يشوّه الذمم والإيراد معاً.
DefaultChartOfAccountsSeeder سطر 44 ← 2104 إيرادات مقدمة (التزامات/دائن)، ومقابله 1106 مصروفات مدفوعة مقدماً.ReceiptVoucher.php به partner_id وحساب استلام وربط متعدد الأشكال reference_type/reference_id وبنود لكل منها account_id خاص.ApproveReceiptVoucher::buildJournalLines() (سطر 76) يجعل النقدية/البنك مديناً والحساب الموجود على البند دائناً — فيمكن قيد الدفعة من ح/ النقدية إلى ح/ 2104 إيرادات مقدمة بلا تعديل كود، بمجرد تحديد حساب البند.الناقص: لا ربط بأوردر ولا دلالة «دفعة مطلوبة قبل الإطلاق» ولا بوابة «هل اكتملت الدفعة؟». وSalesPayment أداة خاطئة هنا لأنه مقيّد بـinvoice_id وPostSalesPayment مثبّت على «من ح/ النقدية إلى ح/ الذمم المدينة» مقابل فاتورة (أسطر 30–56) — لا مسار للالتزام المقدم. كما لا توجد سابقة مالية في LIS (كلمة advance هناك تعني تقدّم حالة لا دفعة).
التعديل المقترح: خطوة دفعة على مسار الأوردر تُصدر ReceiptVoucher بـreference_type=sales_order وبند دائن لحساب دفعات عملاء تحت الحساب (يصلح 2104 أو حساب فرعي جديد 2105). والبوابة المالية = مجموع سندات الدفعة المعتمدة ≥ الدفعة المطلوبة. عند الفوترة النهائية تُخصم الدفعة (من ح/ الإيرادات المقدمة إلى ح/ الذمم أو الإيراد).
قال صاحب المصنع صراحةً إن العميل قد يورّد خاماته وتبقى ملكه. لا يعرف Moon ERP اليوم مفهوم ملكية المخزون إطلاقاً.
Warehouse.php لا يحمل أي حقل مالك؛ حقوله: type, account_id, allow_negative_stock.WarehouseType = Main, Sub, Transit, Damaged, Returns — لا نوع Consignment/مملوك للعميل.consign/owned_by/ownership في وحدة المخزون = صفر نتيجة؛ الرصيد والحركات بلا مالك.الأثر: خامات العميل ستُقيَّم وتُرحَّل لمخزون الشركة (تضخيم الأصول) وقد تُصرف لأوامر أخرى — والمصنع حائزٌ لها بالأمانة لا بالملكية.
خياران للتعديل: (1) علم المخزن — وفق القرار المعتمد سلفاً D-15 هو العلم warehouses.is_consignment لا نوع تعداد WarehouseType::Consignment جديد — مع owner_partner_id على المخازن، يكون تقييمها خارج الدفاتر (لا قيد أصل)، والصرف منها لا يولّد سطر تكلفة مواد. (تصحيح: الصياغة الأصلية اقترحت قيمة تعداد جديدة متجاهلةً اعتماد D-15 لصيغة العلم — الملحقان 33 و36 يتبعان D-15.) (2) إضافة owner_partner_id على stock_balances والحركات (فارغ = ملك الشركة) مع تصفية الرصيد والتقييم حسب المالك. كلاهما بناء جديد.
BomStatus = Active, Inactive, Draft — قائمة R&D الاستكشافية هي BillOfMaterials في حالة Draft.ProductionOrder ذاته (يحمل تكاليف مواد/عمالة/أعباء مخططة وفعلية).الناقص: لا مفهوم «دفعة تجربة» (ProductionOrder بلا حقل kind/is_trial ولا ربط customer_id/sales_order_id). ووحدة CMMS صيانة أصول (CmmsAsset, CmmsWorkOrder, CmmsPmSchedule) لا تصلح للبحث والتطوير رغم اسم «أمر عمل». لا كيان مشاريع/مهام لاستقبال طلب R&D قبل وجود قائمة مواد.
التعديل: نمذجة التجربة كـProductionOrder بـkind=trial وsales_order_id لترث كل بنية التكلفة والمخزون وتبقى معلّقة على أوردر العميل.
يوجد محرك موافقات عام في Core يصلح تماماً للبوابات التي يريدها العميل (اعتماد القائمة، تأكيد الدفعة، إطلاق الأوردر، قبول التجربة).
ApprovalWorkflow.php وApprovalLog.php ومتحكماتهما وحالات ApprovalLogStatus.ApprovalModule = Sales, Purchases فقط؛ وApprovalDocumentType يغطي عروض/أوامر/فواتير البيع والشراء — لا أنواع إنتاج (قائمة مواد، أمر إنتاج، دفعة تجربة).التعديل: إضافة ApprovalModule::Production وأنواع مستندات (bom, production_order, trial_batch) لإعادة استخدام المحرك بدل بناء منطق موافقات خاص.
Modules/CRM وحدة دعم وتذاكر لا خط مبيعات: نماذجها CrmTicket, CrmTicketComment, CrmSlaPolicy, CrmCustomerInteraction, CrmCustomerTag — لا Lead/Opportunity/Pipeline/Stage.
الأثر: لا خط فرص يستضيف استقبال «العميل يأتي بمنتج → طلب تسعير». والحل العملي: (1) إعادة استخدام SalesQuotation كسجل RFQ (حالة Draft = طلب مفتوح) — الأرخص، فيصير الطلب الاستكشافي والعرض سجلاً واحداً تحمل حالاته القمع. (2) أو تسجيل الاستفسار في CrmCustomerInteraction ثم توليد عرض. خط CRM كامل غير مطلوب لتلبية العميل.
ProductionOrderController يتيح confirm/start/complete/consume(الصرف)/recordOutput/cancel كلٌّ محمي بصلاحية — هذا هيكل واجهات المراحل.ProductionOrderStatus = Draft, Confirmed, InProgress, Completed, Cancelled مع حُرّاس انتقال — آلة حالات صغيرة.StockBalance به reserved_quantity ودالة available = quantity - reserved_quantity لكن لا كود يكتب الحجز — خطوة «احجز المواد للأوردر» لها عمود تستقر فيه دون إجراء حجز بعد.الناقص لمسار العميل: لا customer_id/sales_order_id على أمر الإنتاج، ولا مرحلة تجربة ولا بوابة دفعة مكتملة ولا مرحلة حجز ولا فحص جاهزية/تخطيط — الآلة الحالية تقفز Draft→Confirmed→InProgress.
التعديل: آلة مراحل تجارية موازية (لا توسعة ProductionOrderStatus — حُسمت كمظلّة mfg_order_cases في الملحق 35) لسلسلة العميل مثل: Requested → TrialInProgress → TrialAccepted → AwaitingDeposit → Released(+Reserved) → InProgress → Completed → ReceivedToFG، وتوصيل إجراء حجز يزيد reserved_quantity. تصحيح ترتيبي: وفق الصف 13 المعتمد في الخريطة، الحجز أثر جانبي لإجراء الإصدار — فمرحلة «محجوز» يدخلها الإصدار ولا تسبقه أبداً (السلسلة الأصلية هنا وضعت الحجز قبل الإصدار وكان ذلك ترتيباً دائرياً مخالفاً للتصميم المعتمد). كل مرحلة تقابل واجهة بنسبة 1:1.
SalesQuotation وconvertFromQuotation؛ محرك ترحيل ReceiptVoucher؛ حساب 2104؛ BomStatus::Draft؛ محرك ApprovalWorkflow؛ بنية تكلفة ProductionOrder؛ عمود reserved_quantity.sales_order_id + customer_id + kind لأمر الإنتاج؛ ApprovalModule::Production؛ افتراض دفعة ReceiptVoucher دائنة لالتزام مقدم ومربوطة بالأوردر؛ توصيل إجراء الحجز؛ توسعة آلة حالات الإنتاج.is_consignment المعتمد D-15 + owner_partner_id بتقييم خارج الدفاتر)؛ كيان/علم دفعة التجربة؛ استقبال RFQ (المُوصى به: إعادة استخدام عرض السعر بحالة Draft لا خط CRM جديد).