بُعدان متشابكان لكل رصيد في المخزن: اللوط (تشغيلة·صلاحية) والمالك (بضاعتنا أم بضاعة عميل على سبيل الأمانة). كل لوط باين لوحده برصيده الحيّ ومالكه، تجرده وتصرف منه أو تشتغل منه أو تردّه — بضاعة العميل تظهر بلا ما تختلط ببضاعتك ولا بحساباتك. مبني على قراءة فعلية للكود (٥ باحثين) وتصميم Fable.
هذه المرحلة تجمع طلبين مترابطين في نموذج واحد: (أ) كل تشغيلة (لوط) يكون لها رصيد حيّ مستقل وصرف بالأقرب انتهاءً، و(ب) بضاعة العملاء «الأمانة» (خاصة في التصنيع للغير) تظهر وتُجرَد وتُستهلك وتُرَدّ — دون أن تختلط ببضاعتك أو بحساباتك. الدراسة كشفت أن الطلبين ليسا منفصلين: كلاهما يحتاج نفس الشيء — بُعد على مستوى اللوط.
١) طبقات التكلفة لا تصلح سجلًّا للوطات. وضع التكلفة الافتراضي «متوسط مرجّح» لا يستهلك الطبقات أبدًا، وهي «لكل سطر» بلا صلاحية — فنبني سجل لوطات مستقلًّا يُخصم دائمًا.
٢) نظام الأمانة موجود لكنه «سيلو مزدوج يتسرّب». بضاعة العميل تُكتب كمخزون حقيقي (StockService::increaseStock) و في دفتر منفصل (consignment_material_ledgers) — لكنهما يفترقان: استهلاك التصنيع للغير يخصم المخزون ولا يخصم الدفتر أبدًا (recordIssue كود ميت). أسوأ: بضاعة العميل تُقيَّم داخل مخزونك وتضخّم قيمته (استبعاد is_consignment وُعِد به في هجرة ولم يُبنَ)، ولا يوجد بُعد مالك على أي لوط، ولا مسار «رد للعميل».
نوحّد المسارين في نموذج «لوط مملوك» واحد: نضيف بُعد المالك (owner_partner_id، و٠ = الشركة) وعلَم «داخل الدفاتر» (on_book) على سجل أرصدة اللوطات. عندها بضاعة العميل تصير ببساطة «لوطات مملوكة للعميل X»: تظهر حسب المالك، تُجرَد مفصولةً، تُستهلك والمخزون والدفتر في تطابق لأنهما نفس السجل، وتُرَدّ بحركة خارجة عادية. يبقى inventory_stock_balances «أعمى للملكية» (الحقيقة الفيزيائية) فلا تتغيّر منطقيات الـ15 موديولًا. يتراجع الدفتر المنفصل ليصبح مذكرة مالية فقط، وعلَم is_consignment يتقاعد كآلية فصل.
StockService) لكل الحركات — نخيط اللوط والمالك في مكان واحد.supply_source على BOM، الاستلاف/التسوية بقيودها، فاتورة رسوم التصنيع.inventory_lot_balances بِبُعدَي اللوط + المالك يُخصم دائمًا.🔗 يكمّل هذا الملف تحليلَ الأمانة الأسبق: inventory-consignment-stock-analysis.html (2026-07-08). القرار هنا يتجاوز توصيته «مخزن لكل عميل بلا عمود مالك» — لأن وضع المالك على جدول اللوط الجديد (لا على stock_balances) يتفادى جراحة الـ15 موديولًا تمامًا.
«كل لوط في المخزن يبان لوحده علشان أعرف أصرف منه لوحده… أصرف من اللوط أو الأقدم يخرج الأول ويتخصم من اللوطات، علشان أعرف المتبقي والناقص لكل لوط.»
«أشتري أو أستلم بضاعة من العملاء على سبيل الأمانة، موجودة في مخزني كلوطات لكنها طرف عميل معيّن — المفروض تظهر معايا وأقدر أجردها، وأتسلّم منها وأشتغل منها على سبيل السلف وأرجّعها تاني — خاصة في التصنيع للغير حيث العميل يوفّر البضاعة.»
الطلب (ب) هو الطلب (أ) مضافًا إليه بُعد المالك. «كل لوط باين لوحده» + «طرف عميل معيّن» = لوط له (تشغيلة·صلاحية·مالك). فبدل بناء نظامين، نبني نموذج لوط واحدًا ببُعدين متعامدين: اللوط والمالك. كل شاشة تجيب عن سؤالين معًا: «إيه الموجود فيزيائيًّا على الرف؟» و«إيه اللي أملكه فعلًا؟» — والرقم الافتراضي دائمًا ملكنا، والفيزيائي بجانبه لا بداخله.
مؤكَّد بقراءة /home/moonui2/moon-erp-be (بحثان مستقلان متطابقان).
كل تغيير في الرصيد يمرّ عبر دالتين في StockService.php: increaseStock() (ينشئ دائمًا طبقة تكلفة + حركة، ويمرّر التشغيلة/الصلاحية للحركة فقط) وdecreaseStock() (يستهلك أقدم الطبقات في وضع FIFO فقط؛ بلا أي بُعد تشغيلة — الصرف يفقد هوية اللوط). مكسب: نضيف اللوط والمالك في مكان واحد فيرثه كل مسار.
remaining_quantity غير موثوقة كرصيد.inventory_receipt_item_batches (ثابت، تفصيل ما استُلم بلا رصيد متبقٍ) · product_serials (حيّ لكل وحدة) · نَسَب الحركات (التشغيلة الأولى فقط) · inventory_stock_balances (كمية مجمّعة بلا أي بُعد لوط). النقطة العمياء: التحويل بين المخازن يدمّر هوية اللوط.
نظام موجود (وُصف في الكود بـ«MFG Phase-C») لكنه v1 بمشاكل بنيوية موثّقة.
استلام بضاعة العميل (CreateConsignmentReceipt) يكتب في ثلاثة أماكن: الدفتر (consignment_material_ledgers) + لوط (MfgBatch بحالة «حجر») + مخزون حقيقي عبر StockService::increaseStock بالقيمة المعلنة. فبضاعة العميل مخزون حقيقي — لكنها لا تُميَّز عن بضاعتك على الشاشات.
| طلبك | مدعوم اليوم؟ | الفجوة (بالدليل) |
|---|---|---|
| تظهر كلوطات في المخزن | جزئي/مضلِّل | مخزون حقيقي لكن لا يُميَّز عن بضاعتك؛ لا حقل مالك على اللوط؛ لوط الأمانة بحالة «حجر» يبدو غير مُفرَج عنه. |
| تُجرَد | فيزيائيًّا نعم، لكن خطأ | تُعدّ كبضاعتك بلا فصل ملكية، وتُقيَّم داخل مخزونك — استبعاد is_consignment وُعِد به في هجرة ولم يُبنَ أبدًا ⇒ تضخيم قيمة مخزونك. |
| تُستهلك في الإنتاج | فيزيائيًّا نعم، الدفتر مكسور | الاستهلاك يخصم المخزون لكن لا يخصم دفتر الأمانة أبدًا (recordIssue بلا مستدعٍ) ⇒ balance_quantity يبالغ إلى الأبد. ولوط الأمانة (حجر، بلا أمر إنتاج) لا يُختار FEFO أبدًا. |
| تُرَدّ للعميل | لا مسار | المسار الخارج الوحيد هو تسوية استلاف (رد لسداد التزام)، لا «رد فائض العميل». لا يوجد إجراء رد أمانة مقابل لإجراء الاستلام. |
الغلاف التجاري متين: supply_source على مكوّنات BOM (مصنع/عميل/مقسوم) + own_qty/customer_qty؛ وسم الملكية على سطور الإصدار؛ قيود الاستلاف (DR WIP / CR Materials Due to Customer بالقيمة المعلنة) والتسوية (شراء/إحلال)؛ عقد التصنيع للغير + دفعة مقدمة + فاتورة رسوم + استرداد مواد المصنع. كلها تجلس فوق نموذج «اللوط المملوك» دون تغيير يُذكر.
الحدّ مطبَّق في طبقة القيود (الاستلام بلا قيد؛ الإصدار يتخطّى قيمة مادة العميل من WIP) لكنه غير مطبَّق في طبقة تقييم المخزون — فبضاعة العميل تُقيَّم وتُمزَج في متوسط تكلفة المخزن. القيد سليم، لكن سجل المخزون يبالغ في قيمة ما تملكه. هذا بالضبط ما تشعر به.
جدول inventory_lot_balances بحبيبة (منتج·متغيّر·مخزن·تشغيلة·صلاحية·مالك) + علَم on_book. يُخصم عند كل صرف مستقلًّا عن طريقة التكلفة. هو الحقيقة الكمية لكل لوط ولكل مالك. الدفتر consignment_material_ledgers يتراجع إلى مذكرة مالية (قيم معلنة، استلاف، تسويات) تُطابَق ضد مجاميع اللوطات — بعمود «فرق دفتر-فعلي» كإنذار مبكر.
stock_balances يبقى أعمى للملكيةلا نضيف المالك على stock_balances (كان اعتراض تحليل ٨ يوليو: جراحة ١٥ موديولًا). المالك على جدول اللوط الجديد فقط. stock_balances = الحقيقة الفيزيائية (كل الملّاك). القيمة الدفترية = SUM(remaining WHERE owner=0) مشتقّة.
owner_partner_id NOT NULL، ٠=الشركةلا nullable (فخّ فهرس الفريد في MySQL). الثابت: SUM(كل اللوطات، كل الملّاك) == stock_balances.quantity (فيزيائي)، وon_book يفصل ما يدخل التقييم.
on_book=falseاستلام الأمانة يُنشئ لوط مالكه العميل وon_book=false ⇒ يظهر، يُجرَد، يُستهلك، يُرَدّ — ومُستبعَد من كل تقارير قيمة الشركة. يُصلح تسريب التقييم بنيويًّا.
لأن الاستهلاك واللوط والدفتر يمرّون عبر decreaseStock، نكتب recordIssue هناك ⇒ ينتهي الانحراف (يُغلق الكود الميت) وتصير الحقيقة واحدة.
-- رصيد لوط واحد لكل (تشغيلة·صلاحية·منتج·متغيّر·مخزن·مالك). يُخصم دائمًا. Schema::create('inventory_lot_balances', function (Blueprint $table) { $table->id(); $table->foreignId('company_id')->constrained()->cascadeOnDelete(); $table->foreignId('product_id')->constrained('products'); $table->foreignId('product_variant_id')->nullable()->constrained('product_variants')->nullOnDelete(); $table->foreignId('warehouse_id')->constrained('warehouses'); ── بُعد المالك (الجديد) ────────────────────────────────── $table->unsignedBigInteger('owner_partner_id')->default(0); -- 0 = الشركة (ملكنا)؛ غير ذلك = عميل $table->boolean('on_book')->default(true); -- false = أمانة (خارج تقييم الشركة) $table->decimal('declared_unit_cost', 15, 3)->default(0); -- للأمانة: قيمة معلنة/مرجعية فقط ── بُعد اللوط ──────────────────────────────────────────── $table->string('batch_number', 100)->nullable(); $table->date('production_date')->nullable(); $table->date('expiry_date')->nullable(); -- null → يرتّب بتاريخ الاستلام $table->decimal('original_quantity', 15, 3); $table->decimal('remaining_quantity', 15, 3); -- ← الرصيد الحيّ لكل لوط/مالك $table->decimal('unit_cost', 15, 3)->default(0); -- تكلفة حقيقية للوط المملوك (on_book) $table->foreignId('receipt_item_id')->nullable()->constrained('inventory_receipt_items')->nullOnDelete(); $table->date('received_date'); $table->boolean('is_estimated')->default(false); -- من الترحيل التقديري (~) $table->timestamps(); -- الفريد يشمل المالك؛ owner_partner_id غير قابل للـnull ليعمل الفهرس بأمان $table->unique(['company_id','product_id','product_variant_id','warehouse_id', 'owner_partner_id','batch_number','expiry_date'], 'lot_owner_uq'); $table->index(['product_id','warehouse_id','owner_partner_id','remaining_quantity']); $table->index(['company_id','expiry_date']); });
فيزيائي: SUM(remaining, كل الملّاك) == stock_balances.quantity (يبقى تذييل التطابق في الواجهة صادقًا). دفتري: التقييم والتكلفة يستهلكان SUM(remaining WHERE owner_partner_id=0) فقط. صف «غير مخصّص» القديم دائمًا ملكنا (رصيد ما قبل التتبّع بالتعريف بضاعة شركة).
-- ما استهلكه كل صرف — للإلغاء الدقيق ولتزامن دفتر الأمانة. Schema::create('inventory_issue_lot_allocations', function (Blueprint $table) { $table->id(); $table->foreignId('company_id')->constrained()->cascadeOnDelete(); $table->string('reference_type'); $table->unsignedBigInteger('reference_id'); $table->unsignedBigInteger('reference_line_id')->nullable(); $table->foreignId('lot_balance_id')->constrained('inventory_lot_balances'); $table->unsignedBigInteger('owner_partner_id')->default(0); -- يرث مالك اللوط المستهلَك $table->decimal('quantity', 15, 3); $table->decimal('unit_cost', 15, 3)->default(0); $table->boolean('is_borrow')->default(false); -- استلاف من أمانة العميل لأمر الشركة $table->boolean('expired_override')->default(false); $table->timestamps(); $table->index(['reference_type','reference_id']); });
FEFO لا يعبر حدود المالك أبدًا. التخصيص يجري ضمن لوطات مالك واحد. «نطاق المالك» مُدخَل للتخصيص تمامًا كالمخزن — ويُعرض كترويسة سياق مقفولة لا فلترًا يمكن توسيعه بالخطأ.
function allocateFefo(product, variant, warehouse, owner, needed): lots = lot_balances .where(product, variant, warehouse, owner_partner_id = owner) ← نطاق المالك .where(remaining_quantity > 0) .where(expiry not expired OR policy allows) -- التلقائي لا يلمس منتهيًا أبدًا .orderByRaw('expiry_date IS NULL, expiry_date ASC, received_date ASC, id ASC') ... يأخذ من الأقدم انتهاءً حتى تُغطّى الكمية؛ ناقص ⇒ SHORT (يمنع الترحيل) ...
recordIssue في نفس النقطة (يُغلق الكود الميت).يُعاد استخدام إطاري الاستلام/التسليم مع تمييز خماسي مكرّر يستحيل معه الخلط: نوع مستند مستقل + سلسلة أرقام (CRN-…/CRT-… لا GRN-…) + ترويسة بنفسجية + حقل «المالك (عميل)» لا «مورّد» + عمود «القيمة المعلنة (للحصر فقط)». الاستلام يلتقط التشغيلة/الصلاحية (هذا ما يمنح بضاعة العميل لوطات) ⇒ يُنشئ لوطات موسومة بالمالك + يطبع بطاقات لوط تحمل اسم العميل (وقاية الجرد). بلا قيود محاسبية (يُقيَّد في مذكرة العميل فقط). الرد (CRT) يخصم لوطات العميل عبر حوار التخصيص مقفولًا على مالكه، ويُطبع كإذن تسليم بخانة توقيع العميل — الورقة إثبات انتهاء الأمانة.
لو سطر BOM موسوم «مادة عميل» ⇒ نطاق الإصدار مقفول على عميل العقد. لو نقصت لوطاته: عرض صريح «استخدام من مخزوننا» (تحميل على العميل حسب العقد). والعكس (أمر شركة ناقص ومتاح أمانة عميل) ⇒ مراسم استلاف (RecordBorrow): يعرض لوطات العميل + القيمة المعلنة + جملة «سيُسجَّل التزام تجاه العميل بقيمة X — تسدّده بالشراء أو بالإرجاع»، ويَسِم صفوف التخصيص is_borrow=true.
الاستلاف دَين قائم فيأخذ سطحًا دائمًا: شارة بنفسجية «مستحق الإرجاع (N)» على لوحة القيادة وشريط الأدوات ⇐ قائمة الاستلافات (عميل·منتج·كمية·قيمة معلنة·العمر) بزرّين: [إرجاع] (يرد مادة مكافئة من مخزونك ويولّد إذن CRT ويُقفل الالتزام) و[شراء تسوية] (فوترة شراء للعميل). الصفوف المتقادمة تصير برتقالية — مضاد «محدش بيرجّع أبدًا».
الاستلاف: DR WIP / CR Materials Due to Customer بالمعلنة. التسوية «شراء»: فاتورة شراء باسم العميل (بلا مخزن على السطر فلا GRN ثانٍ) + قيد تصفية. التسوية «إحلال»: خصم من مخزونك + DR Materials Due to Customer / CR Inventory. رسوم التصنيع للغير + استرداد مواد المصنع + إغلاق الأمر (أساس WIP = التحويل فقط) — كلها سليمة وتُبقى.
صعب — اختيار لوط سهل — تمرير آلي ملكية خارج النطاق
| العملية | الموضع | +/− | التصنيف |
|---|---|---|---|
| اعتماد إذن استلام / افتتاحي | ApproveReceipt.php:141 | + | سهل — يكتب لوط ملكنا |
| اعتماد إذن صرف (القناة الرئيسية + الإنتاج) | ApproveIssue.php:195 | − | صعب — تخصيص FEFO/يدوي |
| تسليم/فاتورة البيع + POS | ConfirmDeliveryNote / PostSalesInvoice | − | صعب مقفول على ملكنا |
| التحويل — شحن/استلام | ShipTransfer / ReceiveTransfer | ± | تمرير اللوط والمالك (يصلح النقطة العمياء) |
| تسوية / جرد | ApproveAdjustment / FinalizeCount | ± | صعب فروق لكل مالك |
| استلام أمانة (CRN) | CreateConsignmentReceipt | + | لوط عميل، on_book=false |
| رد أمانة (CRT) — جديد | (إجراء جديد) | − | خصم لوط عميل + مذكرة |
| استهلاك التصنيع للغير | IssueMaterials (supply_source=customer) | − | صعب نطاق مالك = العميل + recordIssue |
| الاستلاف / التسوية | RecordBorrow / SettleBorrow | ± | تحويل ملكية لوط + قيود |
| مرتجع بيع / مرتجع شراء | PostSalesReturn / PostPurchaseReturn | ± | لوط جديد / إعادة لوط |
| ~٩ مسارات إلغاء | Cancel* | ± | عكس نفس اللوطات المسجّلة |
| إعادة التقييم · الحجز | RevalueStock · reserve/release | لا كمية | خارج النطاق |
▾ غزل قطن 40/1 Main WH On-hand: 105 +45 🤝 Nearest: 2026-08-20 🤝 ┌─────────────────────────────────────────────────────────────────────────┐ │ Lot Expiry Received Issued On-hand Value Status │ │ ── ملكنا (Own) ──────────────────────────────────────── subtotal 105 ── │ │ B-2201 2026-09-01 80 20 60 4,800 │ │ B-2288 2027-02-11 50 13 37 2,960 │ │ Unassigned (pre-lot) ⓘ — — 8 640 [LEGACY] │ │ ── 🤝 شركة النور (أمانة) ─────────────────────────── subtotal 30 ── │ │ B-7010 2026-08-20 ⚠ 40 10 30 معلنة 2,100ⓘ [NEAR]│ │ ── 🤝 مصنع الأمل (أمانة) ──────────────────────────── subtotal 15 ── │ │ B-2201 ⚠ⓘ 2027-03-15 15 0 15 معلنة 900ⓘ │ │ ───────────────────────────────────────────────────────────────────────── │ │ Physical total: 150 ✓ matches balance │ │ ملكنا (on-book): 105 — قيمة 8,400 · أمانة (ليست ملكك): 45 — معلنة 3,000 │ │ Valuation & costing use the 105 only. Show depleted (3) ▾ │ └─────────────────────────────────────────────────────────────────────────┘
⚠ = نفس رقم التشغيلة تحت مالك آخر (كاشف تصادم يمنع كارثة الجرد).105 غامق + شريحة بنفسجية +45 🤝. الفرز على «ملكنا».العدسة: p-select واحد (الكل فعلي · ملكنا فقط · أمانة فقط · عميل محدّد). أي عدسة غير «الكل» ⇒ شريط بنفسجي دائم «تعرض بضاعة شركة النور — ليست أرصدتك الدفترية» + إعادة تسمية العمود + العدسة في الـURL (بيان أمانة قابل للمشاركة).
الجرد: بضاعة العميل داخل الجرد افتراضيًّا، مجمّعة لكل مالك. توجيه الفروق مختلف ومسمّى: فرق ملكنا ⇒ تسوية مخزون (ربح/خسارة الشركة)؛ عجز العميل ⇒ تسوية أمانة على بيان العميل (لا يمسّ حساب خسائر مخزونك أبدًا)؛ فائض العميل ⇒ بانتظار تأكيده.
┌─ تخصيص لوطات — قماش قطن · PO-341 — تصنيع للغير 🤝 شركة النور ────────┐ │ ┌────────────────────────────────────────────────────────────────┐ │ │ │ 🤝 خامة العميل — الصرف من بضاعة «شركة النور» فقط [مقفول] │ │ │ └────────────────────────────────────────────────────────────────┘ │ │ Mode: (●) تلقائي — الأقرب انتهاءً أولًا ( ) يدوي Required: 70 │ │ Lot (🤝 النور) Expiry On-hand Take Remaining after │ │ B-7010 2026-08-20 ⚠ 30 [ 30 ] 0 │ │ B-7150 2026-11-05 55 [ 40 ] 15 │ │ ┌──────────────────────────────────────────────┐ │ │ │ Allocated 70 / 70 ✓ fully allocated │ │ │ └──────────────────────────────────────────────┘ │ │ ⓘ لوطاتك الخاصة (105) غير معروضة — هذا صرف من ملكية العميل │ │ [ إلغاء ] [ تأكيد التخصيص ] │ └────────────────────────────────────────────────────────────────────────────┘
سطر «لوطاتك غير معروضة» هو الفرق بين الثقة وتذكرة دعم. البيع اليدوي يُظهر لوطات الأمانة معطّلة بتلميحة «بضاعة أمانة — لا تُباع؛ لتملّكها اشترِها من العميل أولًا» (مرئية-مقفولة تُعلّم القاعدة).
| الفشل | الوقاية |
|---|---|
| اختلاط إجمالي ملكنا/الأمانة | خلية On-hand مركّبة + تذييل سطرين + لا إجمالي قيمة كبير + المالك عمود في التصدير |
| بيع بضاعة العميل كأنها ملكنا | تخصيص البيع مقفول على ملكنا بالبناء + لوطات الأمانة معطّلة + مستند رد CRT منفصل |
| مخزون عميل منتهٍ لا يردّه أحد | مؤشرات الصلاحية تنفصل لكل مالك بنداء مختلف («أبلغ العميل/أرجِعها» لا «إعدام») |
| مادة مستلَفة لا تُرَدّ | شارة «مستحق الإرجاع (N)» دائمة + تقادم برتقالي |
| فرق جرد العميل يقع في أرباح الشركة | لوحات فروق لكل مالك بوجهات مسمّاة مختلفة (بنيويًّا لا يمسّ حساب الخسارة) |
| تصادم نفس التشغيلة تحت مالكين | كاشف ⚠ + بطاقات لوط موسومة بالمالك + مساعد تقسيم صريح |
inventory_receipt_item_batches بترتيب FEFO؛ يوسم ~ + بانر أمانة.~. لوطات الأمانة تُرحَّل من مستندات استلام الأمانة الموجودة (لها بالفعل تشغيلة/صلاحية على MfgBatch).on_book=true فقط ⇒ بضاعة العميل تخرج من قيمة مخزونك ومن المتوسط المرجّح. قسم مذكرة منفصل مُؤطَّر: «بضائع أمانة لدينا (خارج الدفاتر) — بالقيمة المعلنة» لكل عميل.الملكية عمود على كل سطح لا موديول منفصل. البوابة production.enable_consignment: مطفأة ⇒ لا واجهة ملكية إطلاقًا (المرحلة ٤ تشحن لعملاء بلا تصنيع للغير بلا مساس).
جدول inventory_lot_balances بعمود owner_partner_id NOT NULL DEFAULT 0 وon_book من اليوم الأول (إضافة العمود بعد وجود بيانات مكلفة)؛ التغذية لكل تشغيلة عند الاستلام؛ ترحيل لوطات الأمانة الموجودة موسومةً بمالكها؛ Surface 1 (توسعة + مجموعات ملّاك + تذييل سطرين) — تظهر فقط عند وجود مالك ثانٍ (منتج بمالك واحد يبدو كموك المرحلة ٤ الأصلي، صفر ضريبة على ٩٥٪).
خيط اللوط والمالك في decreaseStock؛ FEFO ضمن نطاق مالك؛ جدول التخصيصات؛ Surface 2 بترويسة النطاق المقفولة (تشحن هنا وإن استُخدمت غير-ملكنا لاحقًا)؛ عكس الإلغاء الدقيق؛ حاجز الرصيد السالب لكل لوط.
البيع/POS مقفول على ملكنا؛ استهلاك مادة العميل بنطاق مالكه + كتابة recordIssue (يُغلق العيب الحرج)؛ مراسم الاستلاف + دُرج «مستحق الإرجاع»؛ مسارات الإلغاء المقابلة.
تمرير اللوط والمالك في التحويل (شحن FEFO → استلام يمرّر نفس اللوط/المالك)؛ نسخ التشغيلة في فاتورة الشراء المباشرة.
مستندات CRN/CRT؛ عدسة الملكية + عمود المالك على تقرير اللوطات + شريط المنتهي منفصلًا لكل مالك؛ الجرد لكل مالك + توجيه الفروق؛ حاجز التقييم (استبعاد الأمانة)؛ معالج الترحيل التقديري.
بوابة enable_consignment في الواجهات؛ عتبة تقادم الاستلاف؛ عمود «فرق دفتر-فعلي» على بيان العميل؛ (اختياري) حجز على مستوى اللوط.
بعد 4.0 تشوف أرقام لوطات حقيقية مفصولة بالمالك على الشاشة وتتحقّق منها ضد الرف قبل أي منطق صرف. لو الأرقام صحّت، نكمل 4.1 بثقة.
| الخطر | الوقاية |
|---|---|
| تضخيم قيمة مخزونك ببضاعة العميل (تسريب اليوم) | on_book + كل تقارير القيمة تقرأ ملكنا فقط — إصلاح بنيوي، لا اعتماد على علَم is_consignment |
| انحراف الدفتر عن المخزون (العيب الحالي) | سجل اللوط = الحقيقة الكمية؛ recordIssue يُكتب في نفس نقطة الخصم ⇒ حقيقة واحدة |
| بيع بضاعة عميل بالخطأ | تخصيص البيع مقفول على ملكنا بالبناء + لوطات أمانة معطّلة + مستند رد منفصل |
| فرق جرد العميل في أرباح الشركة | وجهات فروق لكل مالك؛ عجز العميل يذهب لبيانه لا لحساب خسائرك (بنيويًّا) |
| مادة مستلَفة لا تُرَدّ / التزام غير مُقرّ | دُرج «مستحق الإرجاع» دائم + تقادم + الاستلاف مراسم صريحة تسمّي العميل والقيمة |
| تصادم نفس التشغيلة تحت مالكين في الجرد | كاشف ⚠ + بطاقات موسومة + مساعد تقسيم صريح + (توصية) صناديق/مخزن لكل عميل |
| انحراف التطابق / الرصيد السالب لكل لوط | صف «غير مخصّص» يمتص الفرق؛ التخصيص لا يتجاوز remaining_quantity |
| المتوسط المرجّح لا يستهلك الطبقات | سجل اللوط مستقل تمامًا عن طريقة التكلفة |
| التحويل يجرّد اللوط/المالك | المالك يركب تمرير اللوط في 4.3؛ حركة الأمانة تُسجَّل على بيان العميل |
production.consignment.borrow منفصلة (يُنشئ التزامًا قانونيًّا — على الأرجح مستوى مشرف)؟hazemdev2)؟ابدأ بـ 4.0 — أصغر خطوة تُثبت البنية وتُريك أرقام لوطات حقيقية مفصولة بالمالك دون لمس أي منطق صرف. الافتراضات: منتجات بالتشغيلة أولًا · FEFO مثبّت ضمن نطاق مالك · منع المنتهي · owner_partner_id ٠=الشركة من اليوم الأول · بضاعة الأمانة on_book=false مُستبعَدة من التقييم. أخبرني بأي تعديل على هذه الافتراضات.
Moon ERP · المرحلة ٤ (أرصدة اللوطات × الملكية + FEFO + الأمانة) · مبني على قراءة فعلية للكود (٥ باحثين مستقلّين) وتصميم Fable · مُعاد هيكلته 2026-07-11 · hazemdev2
مرجع: StockService · ApproveReceipt · ApproveIssue · CreateConsignmentReceipt · ConsignmentMaterialLedger · ConsignmentBorrow · MfgTollContract · inventory_cost_layers · inventory_receipt_item_batches
يكمّل: تحليل بضاعة الأمانة (2026-07-08)