🔬 تشخيص شامل: مشكلة Defer/Recollect في صفحة التجميع

تاريخ التشخيص: ٢٦ مايو ٢٠٢٦
الـ Request المتأثر: LR-2026-00145 (id=87) — Lipid Panel
الـ Environment: Dev backend (moonui.elbaset.com/moon-erp-be/api)

١. الأعراض اللي ظهرت

بعد ما أجلت TG من Lipid Panel وعملت Recollect:

٢. البيانات الفعلية في الـ Database

تركيب الـ Request 87

Pivot IDInvestigation IDCodeis_panelprice
145284LIPIDtrue (parent)السعر الكامل
145315CHOLfalse0.000
145416TGfalse0.000
145539HDLfalse0.000
145640LDLfalse0.000
145741VLDLfalse0.000

السامبلز الـ ٣ الموجودة للـ Request

IDSample #BarcodeStatusis_deferredparent_iddeferred_investigation_idsNotes
269SMP-2026-05-001012605266XHLQHpendingfalsenullnullالـ parent — مخفي لأن عنده child
270SMP-2026-05-00101-BIO2605266XHLQH-BIOdeliveredfalse269nullالـ BIO aliquot
272SMP-2026-05-00103SMP-2026-05-00103collectedfalsenull[16] ← TG فقط!Recollected from deferred samples
✓ ملاحظة مهمة: الـ database فعلياً مخزّن deferred_investigation_ids = [16] على sample 272 (TG فقط). يعني الـ Backend اشتغل صح، والـ FE PUT workaround بتاعنا فعّال.

٣. ليه الـ UI بيعرض "LIPID" بدل "TG"؟

الـ Logic الحالي في الـ FE

// collection-worklist.component.ts — tubes builder
if (isDeferred) {
  // sample مؤجل — display codes من deferred_investigation_ids
} else if (isExt) {
  // sample خارجي
} else if (isRecollected) {
  // sample مش مؤجل لكن عنده defer_ids → scoped
  for (const inv of allInvs) {
    const invId = inv.investigation?.id || inv.investigation_id;
    if (!scopedIds.has(invId)) continue;
    const invIsPanel = !!inv.investigation?.is_panel;
    if (invIsPanel) continue;
    const code = inv.investigation?.code || '';
    if (code) tubeCodes.push(code);
  }
} else {
  // sample عادي — display billable tests only (panel parent = single test)
  const billable = filterBillableTests(allInvs);
  ...
}

التطبيق على sample 272

scopedIds = new Set([16])      // TG
isRecollected = true

loop over pivot_investigations:
  pivot 1452 → inv_id=84 (LIPID)  → scopedIds.has(84)? NO → skip ✓
  pivot 1453 → inv_id=15 (CHOL)   → scopedIds.has(15)? NO → skip ✓
  pivot 1454 → inv_id=16 (TG)     → scopedIds.has(16)? YES, is_panel=false → ADD "TG" ✓
  pivot 1455 → inv_id=39 (HDL)    → scopedIds.has(39)? NO → skip ✓
  ...

النتيجة المتوقعة: tubeCodes = ["TG"]
النتيجة الظاهرة: tubeCodes = ["LIPID"] ← المشكلة!
الـ logic صحيح ١٠٠٪. فلازم يكون فيه واحد من ٣ احتمالات:
  1. Browser cache: الـ JS chunk الجديد مش بيتحمل فعلياً (lazy chunk بيستجيب من cache)
  2. الـ chunk اللي يحتوي على الـ logic مش بيتحمل أصلاً (route lazy loading + service worker)
  3. الـ `isRecollected` branch مش بيتنفذ لسبب خفي (ممكن `scopedIds.size === 0` نتيجة مشكلة JSON parsing)

اختبار سريع لتحديد السبب

الخطوات للمستخدم
  1. افتح https://moonui.elbaset.com/app/lab/samples
  2. اعمل Hard Refresh: Ctrl+Shift+R (Windows) أو Cmd+Shift+R (Mac)
  3. افتح Developer Tools (F12) → tab "Network"
  4. اعمل refresh تاني، شوف لو الـ chunks بترجع بـ status 200 ولا 304
  5. افتح tab "Console" واطبع: localStorage.clear(); sessionStorage.clear(); وriload

٤. المشكلة الجوهرية في الـ Architecture

الـ system بُني على افتراض: "تحليل واحد = عينة واحدة محددة" — مفيش جدول sample_investigations صريح. بدلاً منه: نحن دلوقتي بنوسع deferred_investigation_ids لتعمل overload: تخدم defer وكمان تخدم "scoped recollect". ده يشتغل لكنه هشّ.

٥. الحل المقترح (Structural)

الخيار أ: حل سطحي (Quick fix)

لو الـ isRecollected branch صحيح، السبب الحقيقي هو browser cache. الحل:

الخيار ب: حل ميكانيكي (Workaround)

نضيف عمود scoped_investigation_ids منفصل عن deferred_investigation_ids:
عمودالاستخدام
is_deferred + deferred_investigation_idsالمؤجلات فقط (is_deferred=true)
(جديد) scoped_investigation_idsأي sample (مؤجل أو لأ) عندها قيود على الـ tests اللي تنفع تطلع منها
المميزات: سيمنتك أوضح، لا مزيد من overload.
التكلفة: migration جديد + تعديل LabSampleService::recollect.

الخيار ج: حل جذري (Proper structural fix)

نـ introduce جدول lab_sample_investigations:
lab_sample_investigations
├── id
├── lab_sample_id   → fk
├── lab_investigation_id → fk
└── status enum (pending/collected/deferred/rejected/recollected)
كل sample بيبقى متضمن قائمة صريحة بالـ tests اللي عليها. لا مزيد من الـ "استنتاج" من section/specimen_type.

المميزات: التكلفة: migration كبيرة + إعادة كتابة الـ FE display logic + إعادة كتابة الـ aliquot logic + الـ kanban/results يحتاجوا تحديث.

٦. توصيتي

المرحلة الأولى — اليوم:
  1. تأكد إن الـ browser cache فاضي عند الـ user
  2. لو الـ isRecollected branch مش شغّال، نتأكد إنه deployed بـ console.log debug
  3. اختبر بـ Lipid Panel جديد، أجل TG واحد، شوف الـ display
المرحلة الثانية — بعد الـ kickoff: نتجه للـ الخيار ج (جدول lab_sample_investigations). ده الـ fix الجذري اللي يخلي: بس ده شغل ٢-٣ أيام، ومش هينفع نضربه في feature branch. لازم سبرنت منفصل.

٧. سؤال للمستخدم

  1. عملت Hard Refresh للصفحة؟ لو لأ، اعمل وقولي لو لسه التحليل بيظهر "LIPID"
  2. هل تفضل المضي في الخيار ب (سهل، يوم واحد) أو الخيار ج (جذري، أسبوع)؟
  3. هل في عينات تانية في النظام نفس المشكلة عليها، ولا فقط SMP-2026-05-00103؟