🧩 باكدجات B2B بسعر مباشر — مراجعتي التنفيذية

تعليقي على الخطة (v2) بعد التحقق من الكود الفعلي · + مواصفة التكامل الدقيقة · + خطة WPs نبني منها

المصدر: تحقّق مباشر من كود moonui2 + خطة v2 التاريخ: 2026-07-03 الحالة: جاهز للتنفيذ بعد قرارات §5

١ حكمي على الخطة — ✅ صلبة ودقيقة، ننفّذها

الخطة ممتازة — التصميم (سعر مباشر · سطر واحد · تعيين متعدد · قيد واحد عند الاكتمال · إيراد صافي IFRS-15) هو الاختيار الصح: أبسط، محاسبيًا سليم، وبيلغي خطر «ثبات المبلغ» بالكامل. وتحققت من ادعاءاتها الأساسية ضد الكود الفعلي وطلعت كلها مظبوطة (تفاصيل §2). ماعنديش اعتراض على الاتجاه — عندي تحديد أدق لنقطة التكامل الأخطر (§3) وتأييد لقراراتك (§4).

٢ اللي تحققت منه في الكود (يثبّت الخطة)

ادعاء الخطةالتحقق من الكود
المحاسبة B2B per-item عند رفع النتيجةPostInvoiceItemOnResultRelease بيسمع LabResultReleased، يلاقي بند الفاتورة بـinvestigation_id وposted_at=null ويرحّله عبر PostLabInvoiceItem (DR AR / CR Revenue / CR Tax، idempotent).
الباقة الحالية بتتفكّك per-componentCreateLabRequest (~220-255) بيعمل foreach package->investigations صف لكل تحليل بـsource_package_id → الفوترة per-component.
الباقة مفيهاش وضع فوترةLabPackage فيها package_price/total_price/price_deductible بس — مفيش billing_mode (نضيفه).
الترحيل «only wired for B2B receivables»✅ مكتوبة حرفيًا في PostLabInvoiceItem.

٣ 🎯 أخطر نقطة تكامل — تحديدها بدقة (إضافتي الأساسية)

الخطة رصدت إن «الآلة per-item ومحتاجين مسار سطر-باقة». من الكود، دي المواصفة الدقيقة اللي هننفّذها:

CreateLabRequest
يتفرّع على billing_mode
direct: بند فاتورة واحد للباقة
+ مكوّنات تنفيذ بلا بنود فاتورة
trigger اكتمال جديد
يرحّل قيد الباقة الواحد
أكبر خطر (متفق مع الخطة): موثوقية trigger الاكتمال. الفخّان: (1) مكوّن ملغى/QNS مايحبسش الاكتمال للأبد → «اكتمال» = كل المكوّنات غير الملغاة اترفعت. (2) لا ترحيل مزدوج (re-test / رفع آخر نتيجة مرتين) → حارس posted_at. ده لبّ اختبارات م2.

٤ قراراتك (§5) — رأيي

القرارتوصية الخطةرأيي
السعر لكل شريكمباشر + override اختياريأوافق يغطّي «سعر موحّد» و«سعر خاص» بجدول واحد.
توقيت الإيرادعند الاكتمالأوافق إيراد وقت التسليم = IFRS-15 صح، ومتّسق مع per-item الحالي (اللي بيرحّل عند الرفع).
الحالة الجزئيةتُفوتر كاملةأوافق السعر المباشر = الصفقة. + شرط: الملغى مايحبسش الاكتمال.
الضريبةغير شاملة (تُضاف)أوافق نكتبها في الشاشة صراحة.
عرض المطالبةسطر باقة واحدأوافق + المكوّنات معلوماتية تحته (اختياري). المطالبة الشهرية بتجمّع البنود فسطر الباقة بيندمج طبيعي.
الـRetail الحاليةتفضل allocatedأوافق billing_mode يفصل المسارين نظيف — صفر انحدار على Retail.

٥ خطة العمل (WPs) — اللي هننفّذها

WPالشغلحجم
WP1 — نواة BE + بياناتmigration: lab_packages.billing_mode + جدول lab_external_lab_packages + lab_invoice_items.investigation_id nullable + package_id. models/علاقات. خدمة حلّ السعر المباشر (opt-in: الباقة تُطلب لو مُعيّنة+فعّالة للشريك).متوسط
WP2 — مسار سطر-الباقة في الطلبCreateLabRequest يتفرّع: direct → بند فاتورة واحد للباقة + مكوّنات تنفيذ بلا بنود فاتورة (بصفر). allocated → زي ما هو.متوسط
WP3 — المحاسبة (الأخطر)posting action لسطر الباقة + handler اكتمال على LabResultReleased (كل المكوّنات غير الملغاة مرفوعة → قيد واحد) + idempotency + سياسة الجزئي. + اختبارات: قيد واحد=السعر+VAT · لا ازدواج · ملغى مايحبسش.حسّاس — تركيز التست هنا
WP4 — FE (موظّف)شاشة الباقات: وضع الفوترة + تبويب «الشركاء (B2B)» (تعيين + سعر لكل شريك). أو تبويب «الباقات» في شاشة المعمل الخارجي.متوسط
WP5 — البورتال + المطالبة + تقريركتالوج البورتال يعرض باقات الشريك بسعرها؛ الطلب بنفس خدمة BE؛ المطالبة تعرض سطر الباقة؛ تقرير «قيمة التوفير» (مجموع أسعار − السعر المباشر، بلا مساس GL).متوسط
التتابع: WP1 → WP2 → WP3 (بوابة تست مشدّدة على المحاسبة) → WP4 → WP5. كل WP بمراجعة (native + Codex للمحاسبة/المال). البناء على moonui2 (كوده هو اللي فيه بنية Actions/Listeners دي).
جاهز أبدأ. محتاج بس قرارات §4 (كلها عندي توصية = «موافق») — أكّدها أو عدّل، وأبدأ WP1 فورًا بالمنهجية المعتادة (Opus + Fable + SDD).