١. المطلوب (بكلامك)
- جديد / أولوية: كل معمل خارجي يبقى ليه عدد لا نهائي من قوائم الأسعار — أقدر أضيف لكل مركز أكتر من قائمة، وعند اختيار المركز (من شاشتنا
/lab/requests/newأو من البورتال الخارجي) أختار للعميل قائمة الأسعار حسب وضعه. - لما أختار معمل خارجي، أقدر كمان أختار مريض أو أضيف مريض عادي — الاتنين مع بعض.
- الفاتورة تتحسب على المعمل الخارجي (هو الدافع)، والمريض يفضل مسجّل على الطلب.
- الفواتير تظهر في بورتال المعمل حتى لو الطلب اتعمل من شاشتنا مش من البورتال.
٢. الوضع الحالي (اتأكدت منه في الكود النهاردة)
✗ كل معمل خارجي عنده قائمة أسعار واحدة بس BACKEND
دلوقتي المعمل مربوط بقائمة سعر واحدة فقط عن طريق price_list_id (علاقة BelongsTo)، بالإضافة لجدول أسعار per-test خاص بالمركز:
lab_external_labs.price_list_id→ قائمة سعر واحدة مرتبطة.
Modules/LIS/app/Models/LabExternalLab.php:40,80lab_external_lab_pricing→ أسعار لكل تحليل (inbound/outbound) خاصة بالمركز — مش قوائم مسمّاة.
migrations/2026_03_05_200002_create_lab_external_lab_pricing_table.php
مفيش حاليًا أي طريقة تربط المركز بأكتر من قائمة أسعار مسمّاة ولا تختار وحدة منهم وقت الطلب.
✓ نظام قوائم الأسعار المسمّاة موجود وجاهز
فيه فعلاً lab_price_lists + lab_price_list_items (وضفنا عليهم عمود TAT قريّب). دي الأساس اللي هنبني عليه الربط المتعدد.
features/lis/price-lists/ · Modules/LIS/.../LabPriceList*
✓ الـ Backend بيقبل مريض + معمل خارجي على نفس الطلب
// request-wizard-v2.component.ts — submitOrder() if (patient) data.patient_id = patient.id; if (extLab) data.external_lab_id = extLab.id;
FE: request-wizard-v2.component.ts:923-924
✓ الفاتورة بتتحسب على المعمل لما يكون متحدد
$partnerId = $patient?->partner_id;
if ($request->external_lab_id) {
$partnerId = $externalLab?->partner_id ?? $partnerId;
}
BE: InsuranceInvoiceService.php:66-99
✓ بورتال المعمل + صفحة كشف الحساب (statement) موجودين (BE + FE)
- BE:
/external-lab-portal/statement→ الرصيد + الفواتير + المطالبات الشهرية. - FE: صفحة
client-statementبتعرضهم.
يبقى مش محتاجين صفحة بورتال جديدة — بس محتاجين الداتا توصلها صح.
٣. الثغرات (ليه مش شغّال دلوقتي)
ثغرة ٠ (الأساسية الجديدة) — مفيش دعم لقوائم أسعار متعددة للمركز BACKEND FRONTEND
محتاجين علاقة many-to-many بين المعمل الخارجي وقوائم الأسعار المسمّاة + اختيار وقت الطلب. مش موجودة خالص حاليًا.
ثغرة ١ — المريض والمعمل الخارجي بيلغوا بعض FRONTEND
selectPatient(p) { ...; this.selectedExtLab.set(null); }
selectExtLab(lab) { ...; this.selectedPatient.set(null); }
request-wizard-v2.component.ts:486-528 — اختيار واحد بيمسح التاني.
ثغرة ٢ — نوع الفاتورة غلط من شاشة الموظف BACKEND
دي السبب المباشر إن الفاتورة ما بتظهرش في البورتال. كشف حساب البورتال بيـ filter على نوع ExternalLabReceivable بس:
->where('partner_id', $lab->partner_id)
->where('invoice_type', LabInvoiceType::ExternalLabReceivable)
لكن مسار الموظف بيحط Standard حتى لو فيه معمل خارجي:
'invoice_type' => LabInvoiceType::Standard, // المفروض ExternalLabReceivable
// لما يكون فيه external_lab_id
BE: InsuranceInvoiceService.php:87 — البورتال نفسه بيعملها صح (سطر 221).
ثغرة ٣ — تعارض منطق ضريبة القيمة المضافة (خطر regression) BACKEND
| المسار | قاعدة الـ VAT دلوقتي | مصدر النسبة |
|---|---|---|
| طلب البورتال B2B | دايمًا بيطبّق VAT | lis.vat_rate_percentage (افتراضي ١٥٪) |
فاتورة الموظف (تعديلي الأخير في recalculateTotals) | VAT بس لو المريض غير سعودي | 0.15 ثابت |
الخطر: بمجرد ما نصلّح ثغرة ٢، الفاتورة B2B لمريض سعودي هتطلع VAT = ٠ بالغلط — لازم نوحّد المنطق قبل التنفيذ.
٤. الحلول المقترحة (أهداف بس — لسه مفيش كود)
حل ٠ — قوائم أسعار متعددة لكل معمل خارجي BACKEND FRONTEND
قاعدة البيانات:
- جدول pivot جديد
lab_external_lab_price_listsفيه:external_lab_id,price_list_id,is_default(قائمة افتراضية اختيارية),is_active. - علاقة
belongsToManyعلى موديلLabExternalLab→priceLists(). price_list_idالقديمة تفضل موجودة للتوافق، أو تتحوّل لـ "الافتراضية" في الـ pivot.
الـ API:
- endpoints لربط/فك قوائم الأسعار بالمركز (attach/detach/list).
LabExternalLabResourceيرجّعprice_lists[]المرتبطة + الافتراضية.- بورتال المعمل:
/external-lab-portal/catalogأو endpoint جديد يرجّع قوائم أسعار المركز عشان يختار منها.
الواجهة:
- شاشة المعامل الخارجية (
lis-external-labs): تبويب/قسم "قوائم الأسعار" يضيف عدد لا نهائي من القوائم المسمّاة للمركز + تحديد الافتراضية. - الـ wizard (شاشتنا): لما أختار معمل خارجي → dropdown قوائم الأسعار المرتبطة بالمركز ده فقط → القائمة المختارة تبني الـ
priceMap. لو فيه افتراضية تتحدد تلقائيًا. - البورتال الخارجي: نفس الفكرة — العميل/الموظف يختار قائمة أسعار من قوائم مركزه حسب وضع العميل.
حل ١ — المريض + المعمل يتواجدوا مع بعض FRONTEND
- نوقف
selectPatient()/selectExtLab()من إنهم يمسحوا بعض. نضيفclearExtLab()منفصلة. - الواجهة: خانة "المريض" وخانة "الفاتورة على (معمل خارجي)" مستقلتين، كل وحدة chip + زر مسح خاص بيها.
- في خطوة الفوترة يظهر "الفاتورة على: <المعمل>" عشان يبان إن المريض مش هيتحاسب.
حل ٢ — نوع الفاتورة ExternalLabReceivable من شاشة الموظف BACKEND
- في
createStandardInvoice(): لوexternal_lab_idموجود → النوعExternalLabReceivableبدلStandard. - ده لوحده بيخلي الفاتورة تظهر في كشف حساب البورتال (الـ partner_id مظبوط أصلًا).
حل ٣ — توحيد الـ VAT في recalculateTotals() BACKEND
- نستخدم setting
lis.vat_rate_percentage(افتراضي ١٥٪) بدل0.15الثابت. - الـ VAT يتطبّق لو أيٍّ من: الفاتورة B2B (
invoice_type == ExternalLabReceivable) أو المريض غير سعودي. - ده بيحافظ على قاعدة المريض غير السعودي + يخلي B2B دايمًا فيها VAT + يمنع الـ regression بعد حل ٢.
٥. القرارات (اتأكدت ✓)
س١ ✓ القائمة الافتراضية للمركز
القرار: فيه قائمة افتراضية لكل مركز تتاخد تلقائيًا في الـ wizard، وقابلة للتغيير وقت الطلب.
س٢ ✓ المرضى اللي يظهروا لما أختار معمل خارجي
القرار: كل المرضى يظهروا بدون فلترة.
س٣ ✓ جدول الأسعار القديم (lab_external_lab_pricing)
القرار: البرنامج لسه بيتصمم ومفيش داتا مهمة → نعمل الصح:
- تسعير العميل B2B (inbound) مصدره الوحيد من دلوقتي = قائمة الأسعار المسمّاة المختارة (الـ pivot الجديد). مش هنستخدم الجدول القديم للـ inbound.
- تسعير الإحالات (outbound — اللي المعمل بيحاسبنا بيه لما نبعتله) يفضل في
lab_external_lab_pricingزي ما هو — ده feature منفصل (مسار الـ send-out).
س٤ ✓ التأمين لما المعمل هو الدافع
القرار: نقفل اختيار التأمين لما المعمل الخارجي هو الدافع. الدكتور يفضل اختياري.
٦. خارج النطاق
- إنشاء الطلب من جهة البورتال (موجود وبيحط النوع الصح).
- صفحات بورتال جديدة — كشف الحساب موجود.
- منطق المطالبات الشهرية — مش هيتغير؛ بيقرأ نفس الفواتير فيستفيد تلقائيًا من تصحيح النوع.
٧. ترتيب التنفيذ (بعد ما تجاوب الأسئلة)
- BE حل ٠ — جدول pivot + علاقة + API + Resource لقوائم الأسعار المتعددة.
- FE حل ٠ — قسم قوائم الأسعار في شاشة المعامل + dropdown في الـ wizard + البورتال.
- BE حل ٣ (توحيد الـ VAT) — قبل حل ٢.
- BE حل ٢ (نوع الفاتورة) — وبعدها نتأكد الفاتورة بتظهر في
/external-lab-portal/statement. - FE حل ١ (المريض + المعمل مع بعض).
- اختبار من الأول للآخر: طلب بمريض + معمل + قائمة أسعار مختارة → فاتورة
ExternalLabReceivableبالـ VAT الصح تظهر في بورتال المركز.