1 اللي إنت طلبته (تأكيد الفهم)
- شاشة
/lab/invoices دي المفروض فواتير العملاء الداخليين بس (المرضى/الأفراد + التأمين).
- الـ B2B (المعامل الخارجية كعملاء) لازم ميظهروش هنا — لأنهم بيتعالجوا بنظام مختلف (مطالبات شهرية / كشف حساب من البوابة).
- عايز تشوف العملاء اللي عليهم فلوس (المديونية / المتبقي) بوضوح.
- عايز تسدّد اللي عليهم بسهولة — علشان النتايج تتطبع (الدفع يفك الطباعة).
- عايز دراسة مستفيضة الأول تتعرض عليك، وبعد الموافقة ننفّذ.
خبر كويس: جزء كبير من اللي محتاجه موجود فعلاً في الباك إند — كل فاتورة عندها balance_due (المتبقي) وamount_paid (المدفوع)، وفيه بوابة جاهزة بتمنع إصدار النتيجة طول ما فيه مبلغ متبقي. الناقص أساسًا هو طريقة عرض وتجميع وتحصيل احترافية + تنظيف الـ B2B من الشاشة.
2 الوضع الحالي بالظبط (بالأدلة من الكود)
أ) شاشة الفواتير بتعرض كل الأنواع (ومنها الـ B2B)
الـ LabInvoiceController::index() بيرجّع كل الفواتير بدون أي فلترة على النوع. يعني الفواتير دي كلها بتتخلط في شاشة واحدة:
| النوع (invoice_type) | المعنى | المفروض يظهر في /lab/invoices؟ |
standard / patient_invoice | فاتورة مريض/فرد داخلي | نعم |
insurance_invoice | فاتورة تأمين | نعم |
external_lab_receivable | معمل خارجي كعميل (علينا نحصّل منه) | لأ — B2B |
external_lab_payable | معمل خارجي كمورّد (إحنا اللي بندفع له) | لأ — B2B |
المشكلة الأولى: دلوقتي الـ external_lab_* بيتخلطوا مع فواتير المرضى في نفس القايمة. ده اللي مخلّي الشاشة "مش بس العملاء الداخليين".
ب) بيانات المديونية موجودة بالفعل على كل فاتورة
موديل LabInvoice فيه الحقول دي (كلها decimal(12,3)):
total = الإجمالي−
amount_paid = المدفوع=
balance_due = المتبقي (المديونية)
والحالة (status) بتتحدّث أوتوماتيك مع كل دفعة عن طريق recalculatePaymentStatus():
draft (مسودة)→
posted (مرحّلة)→
partially_paid (مدفوعة جزئيًا)→
paid (مدفوعة)
ج) صفحة المدفوعات موجودة لكن منفصلة وغير عملية للتحصيل السريع
- صفحة
/lab/payments فيها فورم دفع: بتختار الفاتورة يدويًا، المبلغ، طريقة الدفع، الحساب المستلِم.
- الباك إند
LabPaymentController::store() بيتأكد إن الفاتورة مُرحّلة (posted)، ويمنع الدفع الزائد (amount > balance_due)، وبيرحّل قيد محاسبي تلقائي.
- الناقص: مفيش "اعرض اللي عليه فلوس واتحصّل منه في مكان واحد" — لازم تعرف رقم الفاتورة الأول وتروح صفحة تانية.
د) بوابة الدفع على إصدار النتيجة — موجودة فعلاً
دي أهم نقطة. في LabResultController فيه دالة releaseBlockedByBalance() بتشتغل عند release() وbulkRelease():
if (user can 'lis.results.release_unpaid') → allow // صلاحية تجاوز
invoice = latest invoice for request WHERE type != external_lab_receivable
if (!invoice) → allow // مفيش فاتورة = مفيش بوابة
return invoice.balance_due > 0.001 // فيه متبقي ⇒ امنع الإصدار
- يعني: طول ما فيه مبلغ متبقي على فاتورة المريض، النتيجة مش هتتصدر (إلا لو اليوزر عنده صلاحية
lis.results.release_unpaid).
- الـ B2B (
external_lab_receivable) مستثنى من البوابة — صح، لأن المعمل الخارجي بيتحاسب على مستوى الحساب مش الفاتورة.
فجوة مهمة: البوابة على الإصدار (release) مش على الطباعة (print). بمعنى إن بوابة المعمل العامة (/patient-portal) بتطبع النتيجة المُصدَرة بدون أي فحص دفع. فلو حد صدّر بصلاحية تجاوز، المريض يقدر يطبع من البوابة. محتاجين قرار: نكتفي ببوابة الإصدار ولا نضيف فحص دفع على الطباعة كمان؟ (سؤال رقم 3 تحت).
هـ) مفيش شاشة "مديونيات العملاء" خاصة بالمعمل
- فيه شاشة
AR/AP عامة في موديول المحاسبة بتجمع بالـ BusinessPartner — لكنها محاسبية وعامة ومش مربوطة بالمريض/الطلب بشكل عملي للكاشير.
- مفيش مكان بيقولك: "المريض ده عليه X، أقدم فاتورة من امتى، كام طلب مفتوح، اتحصّل دلوقتي".
3 خلاصة المشاكل اللي هنحلها
| # | المشكلة | الأثر |
| 1 | فواتير الـ B2B بتظهر مع فواتير المرضى في /lab/invoices | تشويش + أرقام غلط + اختلاط نظامين مختلفين |
| 2 | مفيش عرض واضح لـ"مين عليه فلوس وكام" | صعب تتابع المديونيات أو تطالب العملاء |
| 3 | التحصيل بيحتاج تنقّل بين شاشتين ومعرفة رقم الفاتورة | بطء على الكاشير + أخطاء |
| 4 | ربط الدفع بطباعة النتيجة مش واضح للمستخدم | الكاشير مش عارف "ليه النتيجة مش بتتطبع" |
4 التصميم المقترح — 3 ركائز
الركيزة أ — شاشة فواتير "داخلية فقط" + تبويب منفصل للـ B2B
- الباك إند: نضيف فلتر
scope=internal (يستثني external_lab_payable + external_lab_receivable) وscope=b2b (يعرض الـ external_lab فقط).
- الفرونت:
/lab/invoices تبقى افتراضيًا "داخلية". نضيف تبويبين: «فواتير داخلية» و «B2B (معامل خارجية)» — زي ما عملنا في شاشة الطلبات بالظبط.
- الـ B2B في تبويبه بيوديك على المطالبات الشهرية / كشف الحساب (المنظومة الموجودة).
توصية: نخلي الـ B2B تبويب جوّه نفس الشاشة (مش لينك تاني) عشان توحيد التجربة، بس بيفتح على آلية المطالبات الشهرية.
الركيزة ب — تبويب/شاشة «المديونيات» (Receivables — اللي عليهم فلوس)
عرض مُجمّع بالعميل/المريض (مش بالفاتورة) — كل صف عميل عليه فلوس:
المريض | رقم MRN | عدد طلبات مفتوحة | إجمالي مستحق | مدفوع | المتبقي | أقدم مديونية | إجراء
─────────────────────────────────────────────────────────────────────────────────
ayman ayman | 20561 | 2 | 120.00 | 40.00 | 80.00 | منذ 5 أيام | [تحصيل]
nehal ibrahim | 20562 | 1 | 34.50 | 0.00 | 34.50 | اليوم | [تحصيل]
─────────────────────────────────────────────────────────────────────────────────
الإجمالي المتبقي على العملاء: 114.50
- مصدر البيانات: تجميع
LabInvoice (داخلية فقط) WHERE balance_due > 0 AND status IN (posted, partially_paid) — مجمّعة بالـ patient_id.
- فلاتر: بحث بالاسم/الـ MRN، الفرع، نطاق تاريخ، "الأقدم أولاً".
- زر «تحصيل» على كل صف → يفتح ديالوج تحصيل سريع (الركيزة ج).
- كروت أعلى الشاشة: إجمالي المديونيات · عدد العملاء المدينين · تحصيل النهاردة.
الركيزة ج — تحصيل بضغطة واحدة يفك طباعة النتيجة
ديالوج تحصيل سريع من شاشة المديونيات أو من صف الفاتورة مباشرة:
اضغط [تحصيل]→
ديالوج: المبلغ (افتراضي = المتبقي) + طريقة الدفع + الخزنة→
حفظ→
balance_due = 0 ⇒ الفاتورة paid→
النتيجة بقت قابلة للإصدار/الطباعة
- يستخدم نفس الـ
LabPaymentController::store() الموجود (مفيش منطق مالي جديد).
- لو الفاتورة لسه
draft — الديالوج يرحّلها (post) أوتوماتيك قبل الدفع (عشان الكاشير ميقفش).
- بعد الدفع: رسالة واضحة «تم التحصيل — النتايج بقت جاهزة للطباعة» + زر مباشر «اطبع النتيجة».
تجربة الكاشير الكاملة (السيناريو المطلوب)
المريض بيطلب نتيجته→
الكاشير يفتح «المديونيات»→
يلاقي اسمه وعليه 80→
[تحصيل] → كاش→
اتدفع→
اطبع النتيجة
5 التغييرات التقنية (مختصرة — معظمها FE)
الباك إند (تعديلات صغيرة)
LabInvoiceController::index(): إضافة فلتر scope=internal|b2b (افتراضي internal لشاشة الفواتير).
- endpoint جديد
GET /lis/invoices/receivables: يرجّع تجميع بالمريض (المتبقي، عدد الطلبات، أقدم تاريخ) — داخلية فقط.
- (اختياري — قرار 3) فحص دفع على طباعة بوابة المريض لو اتقرر.
الفرونت إند
lis-invoices.component: تبويبات «داخلية / B2B» + إخفاء B2B افتراضيًا + عمود المتبقي بارز + زر «تحصيل» في الصف.
- كومبوننت جديد
lis-receivables (شاشة/تبويب المديونيات) + خدمة تجميع.
- ديالوج تحصيل سريع مُعاد استخدامه (Quick Collect) — يلفّ فورم الدفع الموجود.
- رسائل واضحة تربط الدفع بالطباعة + زر «اطبع» بعد التحصيل.
مبدأ: Backend-first ومفيش منطق مالي جديد — بنعيد استخدام balance_due + LabPayment + بوابة الإصدار الموجودة. التركيز على العرض والتجميع والتحصيل السريع.
6 قرارات محتاج رأيك فيها قبل التنفيذ
سؤال 1 — الـ B2B في شاشة الفواتير
نخفيه تمامًا من /lab/invoices ونخليه تبويب منفصل بيودّي على المطالبات الشهرية؟ (توصيتي: نعم، تبويب منفصل) — ولا تفضّل نشيله خالص من هنا ويبقى في صفحة المعامل الخارجية بس؟
سؤال 2 — شكل «المديونيات»
تبويب جوّه شاشة الفواتير، ولا شاشة مستقلة في القايمة الجانبية باسم «المديونيات / التحصيل»؟ (توصيتي: شاشة مستقلة عشان الكاشير يفتحها على طول)
سؤال 3 — بوابة الدفع: إصدار بس ولا طباعة كمان؟
دلوقتي الدفع بيتحكم في الإصدار. هل نضيف فحص دفع كمان على الطباعة في بوابة المريض (يمنع طباعة نتيجة لسه عليها فلوس حتى لو اتصدرت)؟ (توصيتي: نكتفي ببوابة الإصدار الحالية — أبسط وكافية، لأن النتيجة أصلاً مش بتتصدر قبل الدفع)
سؤال 4 — التأمين (insurance_invoice)
فواتير التأمين فيها «حصة المريض» (patient_share). نعتبرها «داخلية» وتظهر في المديونيات بحصة المريض فقط؟ (توصيتي: نعم — حصة المريض دين داخلي، وحصة التأمين مسارها المطالبات)
سؤال 5 — صلاحية التجاوز
مين يقدر يطبع/يصدر بدون دفع (صلاحية lis.results.release_unpaid)؟ نسيبها للأدمن بس ولا نعملها إعداد لكل دور؟ (توصيتي: الأدمن + مدير المعمل فقط)
7 خطة التنفيذ بالمراحل (بعد موافقتك)
المرحلة 1 — تنظيف شاشة الفواتير (نص يوم)
فلتر
scope في الباك + تبويبات «داخلية/B2B» في الفرونت + إبراز عمود المتبقي.
المرحلة 2 — شاشة المديونيات (يوم)
endpoint التجميع
/lis/invoices/receivables + كومبوننت العرض + الفلاتر + الكروت.
المرحلة 3 — التحصيل السريع + ربط الطباعة (نص يوم)
ديالوج Quick Collect + رسالة «جاهزة للطباعة» + زر اطبع + auto-post للمسودة.
المرحلة 4 — تلميع + اختبار (نص يوم)
اختبار السيناريو كامل: عميل عليه فلوس → تحصيل → إصدار → طباعة. + بناء ونشر على moonui.
8 الخلاصة في سطرين
المنطق المالي وبوابة الدفع موجودين. اللي هنبنيه هو طبقة عرض وتحصيل احترافية: شاشة فواتير داخلية نضيفة، شاشة «اللي عليهم فلوس»، وتحصيل بضغطة واحدة بيخلّي النتيجة جاهزة للطباعة فورًا. مفيش مخاطرة على الفلوس أو المحاسبة لأننا بنعيد استخدام اللي موجود.