🧩 باكدجات الـB2B بسعر مباشر — تحليل شامل والتصميم المقترح

الميزة المطلوبة: باقة = مجموعة تحاليل بسعر مباشر واحد، أقدر أعيّنها لأكتر من شريك B2B (المعامل الخارجية — علاقة inbound: بيبعتوا لنا مرضى/طلبات). الباقة تتفوتر سطر واحد بسعرها المباشر — من غير أي تقسيم/توزيع على المكوّنات. التحاليل بتتعمل في المعمل عادي، لكن الفوترة والإيراد على مستوى الباقة.

🔄 نسخة v2 (3 يوليو) — بعد توضيحك: غيّرنا من "سعر باقة موزّع على المكوّنات" (v1) إلى سعر مباشر بلا تقسيم + سطر فاتورة واحد + تعيين لأكتر من شريك. ده بيبسّط المحاسبة ويلغي خطر "ثبات المبلغ" بالكامل.
📅 3 يوليو 2026 · v2 🧬 موديول LIS — معامل خارجية / تسعير / محاسبة 🔎 فحص كود (3 استكشافات) + KB moon1 + استشارة Fable 5 الحالة: تحليل — لسه مفيش تنفيذ

✅ أبسط من v1 — سطر واحد

الباقة تتفوتر سطر واحد بسعر مباشر. مفيش توزيع، مفيش خطر ثبات-المبلغ، والتحاليل بتتنفّذ في المعمل زي ما هي.

💰 قيد واحد للباقة

الإيراد يتسجّل قيد واحد وقت اكتمال الباقة (رفع كل نتايجها): مدين ذمم الشريك / دائن إيراد / دائن VAT. صافي، مفيش contra-revenue.

🎯 التصميم

نعيد استخدام LabPackage + وضع فوترة مباشر + جدول تعيين lab_external_lab_packages (باقة ↔ عدة شركاء، سعر اختياري لكل شريك).

1 الوضع الحالي (متتبّع في الكود)

3 حاجات موجودة: (أ) الباقة الحالية، (ب) تسعير الـB2B، (ج) المحاسبة B2B.

أ) الباقة الحالية (Retail) — بتوزّع السعر على المكوّنات

👈 الفرق الجوهري في v2: الباقة الحالية (Retail) بتوزّع السعر على المكوّنات. باقة الـB2B الجديدة اللي إحنا عايزينها مالهاش توزيعسعر مباشر واحد + سطر فاتورة واحد. فده وضع فوترة جديد على الباقة، مش نفس سلوك الـRetail.

ب) تسعير الـB2B — نظامين (كلاهما investigation-only، مفيش باقات)

النظامالجدوللإيه
A — Referrallab_external_lab_pricingتسعير الإحالات per-lab/per-investigation/per-direction
B — Price Listslab_price_lists/items (متعيّنة عبر lab_external_lab_price_lists)فوترة العميل B2B (inbound) — تحليل تحليل

في v2 مش هنعدّل على قوايم الأسعار — هنستخدم تعيين مباشر للباقة على الشريك (أبسط ويطابق "أحطها لكذا B2B"). القوايم تفضل زي ما هي للتحاليل الفردية.

ج) المحاسبة B2B — قيد لكل تحليل عند رفع النتيجة

ملاحظة توافق v2: كل الآلة الحالية (فاتورة + قيد) شغّالة لكل تحليل (per-item). باقة B2B بسطر واحد محتاجة مسار سطر-باقة جديد (سطر فاتورة واحد + قيد واحد وقت الاكتمال) — ده أهم نقطة تكامل في v2 (§4).

2 الفجوة

3 التصميم المقترح — سعر مباشر، سطر واحد، تعيين متعدد

3.1 نموذج البيانات

العنصرالتفاصيل
الباقة (نعيد استخدام lab_packages)نضيف وضع فوترة: billing_mode = allocated (الحالي/Retail) أو direct (الجديد/B2B). في وضع direct السعر = سعر مباشر واحد للباقة (نستخدم package_price كسعر مباشر) — مفيش توزيع على المكوّنات.
التعيين جدول جديد lab_external_lab_packagesexternal_lab_id, package_id, price (اختياري — override لسعر الشريك، الافتراضي = سعر الباقة المباشر), is_active, valid_from/to (اختياري), unique(external_lab_id, package_id). ده اللي بيخلّي الباقة الواحدة تتحط لكذا شريك.
ليه تعيين مباشر مش قايمة أسعار؟ "أحطها لكذا B2B" = علاقة باقة ↔ شركاء مباشرة (many-to-many)، أبسط من إني أحط الباقة في قايمة وأعيّن القايمة. والسعر مباشر على الباقة (مع override اختياري لكل شريك). لو حبيت لاحقًا تدخّلها في قوايم الأسعار، الجدول ده يقدر يمتد.

3.2 الفلو — سطر واحد، بلا تقسيم

طلب B2B فيه باقة مُعيّنة للشريك
حلّ السعر المباشر pivot override → سعر الباقة المباشر
سطر فاتورة واحد للباقة بالسعر المباشر (مفيش توزيع)
المكوّنات تتفكّك للتنفيذ بس (collect/receive/result) بسعر صفر

3.3 الواجهة (FE)

4 المعالجة المحاسبية — قيد واحد للباقة (بلا تقسيم)

بما إن الباقة سطر واحد بسعر مباشر، الإيراد يتسجّل قيد واحد للباقة كلها — مش قيد لكل تحليل.

توقيت الاعتراف — عند اكتمال الباقة (رفع كل نتايجها)

الباقة = التزام أداء واحد (سعر واحد، مفيش تقسيم) → الإيراد يتحقق لما الباقة تتسلّم بالكامل = رفع كل نتايج مكوّناتها. قيد واحد ساعتها:

قيد الباقة عند اكتمالها — مثال: سعر مباشر 200، VAT 15% = 30
الحسابمديندائن
ذمم المعمل الخارجي (Partner AR)230.00
إيراد المختبر (Lab Revenue)200.00
ض.ق.م المستحقة (VAT Payable)30.00
قيد واحد · بلا توزيع · balanced · VAT بعد/على السعر المباشر
✅ إيراد صافي (Net) — مش contra-revenue (Fable 5 / IFRS 15): السعر المباشر هو سعر الصفقة؛ الفرق عن مجموع أسعار التحاليل مش خصم محاسبي، ده تسعير. متّسق مع خصومات B2B الحالية (بترحّل net). لو الإدارة عايزة تشوف "قيمة التوفير" — تقرير من (مجموع أسعار التحاليل − السعر المباشر) بلا مساس بالـGL.
⚠️ توقيت الاعتراف — قرار لازم: "عند اكتمال الباقة" هو الأنظف (إيراد وقت التسليم الكامل). بديل أبسط: الاعتراف عند الفوترة/الطلب (لو العمل بيحاسب مقدّم). التوصية: عند الاكتمال. حالة جزئية: لو مكوّن اتلغى/QNS ومكمّلش — سياسة صريحة: (أ) الباقة تتفوتر كاملة (المتفق عليه الباقة) لو التسليم مقبول، أو (ب) تتظبط. لازم تتحدّد.
نقطة التكامل الأساسية: الآلة الحالية per-item؛ محتاجين مسار سطر-باقة: (1) بند فاتورة واحد للباقة، (2) trigger اكتمال (آخر نتيجة تترفع) يرحّل قيد الباقة الواحد، (3) المطالبة الشهرية تجمّع سطر الباقة زي أي بند، (4) التحصيل/التخصيص زي ما هو (على مستوى الفاتورة).

5 قرارات مطلوبة منك

القرارالخياراتالتوصية
السعر لكل شريكسعر مباشر واحد للباقة لكل الشركاء · أو سعر مختلف لكل شريكسعر مباشر + override اختياري لكل شريك (يغطّي الاتنين)
توقيت الاعتراف بالإيرادعند اكتمال الباقة (كل النتايج) · أو عند الفوترة/الطلبعند الاكتمال (إيراد وقت التسليم)
الحالة الجزئية (مكوّن ملغى/QNS)تُفوتر كاملة · أو تتظبطقرار صريح لازم — الافتراضي: كاملة (المتفق = الباقة)
دلالة الضريبةالسعر شامل VAT · أو غير شاملغير شامل (تُضاف فوقه) — نكتبها في الشاشة
عرض المطالبة/الفاتورةسطر باقة واحد · أو سطر باقة + مكوّنات معلوماتيةسطر باقة واحد (المكوّنات معلوماتية تحته اختياري)
وضع الباقة الحالية (Retail)تفضل موزّعة · أو الكل يبقى مباشرRetail تفضل موزّعة؛ billing_mode يفصل الاتنين

6 مراحل التنفيذ

  1. المرحلة 1 — نواة الـBE: billing_mode على الباقة + جدول lab_external_lab_packages (تعيين + سعر) + خدمة حلّ السعر المباشر (opt-in) + مسار سطر-باقة في الفاتورة (بند واحد، مكوّنات بصفر للتنفيذ). مسار الموظّف بس. أساس
  2. المرحلة 2 — المحاسبة: قيد الباقة الواحد عند اكتمالها (trigger آخر نتيجة) — مدين ذمم الشريك / دائن إيراد / دائن VAT. + سياسة الحالة الجزئية. + اختبار: قيد واحد = السعر المباشر + VAT.
  3. المرحلة 3 — الواجهة: وضع الفوترة + تبويب تعيين الشركاء (سعر لكل شريك) في شاشة الباقات/المعمل الخارجي.
  4. المرحلة 4 — البورتال + المطالبة: الكتالوج يعرض باقات الشريك بسعرها؛ الطلب بنفس خدمة الـBE؛ المطالبة تعرض سطر الباقة؛ تقرير "قيمة توفير الباقات".
🔴 أكبر خطر (اتغيّر عن v1): مش ثبات-المبلغ (اتلغى مع إلغاء التوزيع)، لكن تكييف آلة الفوترة/القيد per-item لتتعامل مع سطر باقة واحد + قيد واحد عند الاكتمال — لأن كل حاجة دلوقتي per-test. لازم trigger الاكتمال يكون موثوق (مايترحّلش مرتين، ومايتنسيش لو مكوّن اتلغى).

7 الحالات الحدّية والمخاطر

الحالةالمعالجة
ازدواجية الترحيلقيد الباقة يترحّل مرة واحدة عند الاكتمال — idempotent (علم package_posted_at/journal_entry_id على سطر الباقة).
مكوّن ملغى/QNSسياسة الاكتمال: هل "اكتمال" = كل المكوّنات غير الملغاة اترفعت؟ (التوصية: أيوه) → القيد يترحّل بالسعر الكامل. لو التسعير هيتظبط، ده يكسر "السعر المباشر" — يُفضّل يفضل كامل.
تغيّر تركيب الباقةإضافة/حذف تحليل من باقة مُعيّنة بيغيّر اللي الشريك بياخده بنفس السعر → log/تنبيه (versioning خارج v1).
نفس التحليل داخل الباقة ومنفردلو التحليل مطلوب داخل الباقة (بصفر) ومنفرد (بسعر) في نفس الطلب — المنفرد يتحاسب عادي، والباقة سطرها المباشر. مفيش تجميع تلقائي.
الضريبةالسعر المباشر غير شامل VAT (نضيف 15%) — نكتبها صريحة.
discount=0 في البورتالسطر الباقة مالوش "خصم" أصلاً (سعر مباشر) — مايتعارضش مع الحقل.
التحصيلعلى مستوى الفاتورة زي ما هو — سطر الباقة جزء من رصيد الفاتورة عادي.

8 الملفات المرجعية (نقاط التوسّع)

مراجع KB moon1: lis-b2b-journal-entries.html · lab-panel-vs-package-display-plan.html · lab-price-lists-ux-plan.html · topics/lis-discount.md