المعمل الخارجي: قوائم أسعار متعددة + مريض + فاتورة في البورتال

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

١. المطلوب (بكلامك)

  1. جديد / أولوية: كل معمل خارجي يبقى ليه عدد لا نهائي من قوائم الأسعار — أقدر أضيف لكل مركز أكتر من قائمة، وعند اختيار المركز (من شاشتنا /lab/requests/new أو من البورتال الخارجي) أختار للعميل قائمة الأسعار حسب وضعه.
  2. لما أختار معمل خارجي، أقدر كمان أختار مريض أو أضيف مريض عادي — الاتنين مع بعض.
  3. الفاتورة تتحسب على المعمل الخارجي (هو الدافع)، والمريض يفضل مسجّل على الطلب.
  4. الفواتير تظهر في بورتال المعمل حتى لو الطلب اتعمل من شاشتنا مش من البورتال.

٢. الوضع الحالي (اتأكدت منه في الكود النهاردة)

✗ كل معمل خارجي عنده قائمة أسعار واحدة بس BACKEND

دلوقتي المعمل مربوط بقائمة سعر واحدة فقط عن طريق price_list_id (علاقة BelongsTo)، بالإضافة لجدول أسعار per-test خاص بالمركز:

مفيش حاليًا أي طريقة تربط المركز بأكتر من قائمة أسعار مسمّاة ولا تختار وحدة منهم وقت الطلب.

✓ نظام قوائم الأسعار المسمّاة موجود وجاهز

فيه فعلاً 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)

يبقى مش محتاجين صفحة بورتال جديدة — بس محتاجين الداتا توصلها صح.

٣. الثغرات (ليه مش شغّال دلوقتي)

ثغرة ٠ (الأساسية الجديدة) — مفيش دعم لقوائم أسعار متعددة للمركز 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دايمًا بيطبّق VATlis.vat_rate_percentage (افتراضي ١٥٪)
فاتورة الموظف (تعديلي الأخير في recalculateTotals)VAT بس لو المريض غير سعودي0.15 ثابت

الخطر: بمجرد ما نصلّح ثغرة ٢، الفاتورة B2B لمريض سعودي هتطلع VAT = ٠ بالغلط — لازم نوحّد المنطق قبل التنفيذ.

٤. الحلول المقترحة (أهداف بس — لسه مفيش كود)

حل ٠ — قوائم أسعار متعددة لكل معمل خارجي BACKEND FRONTEND

قاعدة البيانات:

الـ API:

الواجهة:

حل ١ — المريض + المعمل يتواجدوا مع بعض FRONTEND

حل ٢ — نوع الفاتورة ExternalLabReceivable من شاشة الموظف BACKEND

حل ٣ — توحيد الـ VAT في recalculateTotals() BACKEND

٥. القرارات (اتأكدت ✓)

س١ ✓ القائمة الافتراضية للمركز

القرار: فيه قائمة افتراضية لكل مركز تتاخد تلقائيًا في الـ wizard، وقابلة للتغيير وقت الطلب.

س٢ ✓ المرضى اللي يظهروا لما أختار معمل خارجي

القرار: كل المرضى يظهروا بدون فلترة.

س٣ ✓ جدول الأسعار القديم (lab_external_lab_pricing)

القرار: البرنامج لسه بيتصمم ومفيش داتا مهمة → نعمل الصح:

س٤ ✓ التأمين لما المعمل هو الدافع

القرار: نقفل اختيار التأمين لما المعمل الخارجي هو الدافع. الدكتور يفضل اختياري.

٦. خارج النطاق

٧. ترتيب التنفيذ (بعد ما تجاوب الأسئلة)

  1. BE حل ٠ — جدول pivot + علاقة + API + Resource لقوائم الأسعار المتعددة.
  2. FE حل ٠ — قسم قوائم الأسعار في شاشة المعامل + dropdown في الـ wizard + البورتال.
  3. BE حل ٣ (توحيد الـ VAT) — قبل حل ٢.
  4. BE حل ٢ (نوع الفاتورة) — وبعدها نتأكد الفاتورة بتظهر في /external-lab-portal/statement.
  5. FE حل ١ (المريض + المعمل مع بعض).
  6. اختبار من الأول للآخر: طلب بمريض + معمل + قائمة أسعار مختارة → فاتورة ExternalLabReceivable بالـ VAT الصح تظهر في بورتال المركز.