ليه الـ«Thyroid Panel» بيظهر تحاليل مفكوكة في Collect — وإزاي نحلّها جذرياً

في طلب LR-2026-00308، تحاليل الغدة الدرقية (TSH / FT4 / FT3) ظاهرة في Collect كأكواد منفصلة بدل ما تتجمّع تحت اسم «Thyroid Panel». الملف ده بيشرح إيه اللي حصل بالظبط بالأدلة، السبب الجذري، والحل المعتمد على الباك إند (مش الفرونت) عشان يتعالج نهائياً لكل البنلات والباكدچات.

🗓️ 2026-06-08🧬 LIS — Collect / Reception / WorklistBackend-first · Plan before implement

1 العرض (اللي إنت شفته)

❌ الحاصل

تيوب واحد فيه أكواد مفكوكة:

TSH, FT4, FT3 (وكمان CHOL, TG, HDL, LDL, VLDL) — كل واحد لوحده.

✅ المتوقّع

تتجمّع تحت اسم الباكدج/البنل:

Thyroid Panel (TSH · FT4 · FT3) — مجموعة واحدة.

2 التشخيص — بالأدلة من قاعدة البيانات

أ. الطلب فيه الأعضاء بس — مفيش «أب بنل» مربوط

lab_request_investigations لـ LR-2026-00308الكودis_panel
investigation 17TSH0 (عضو)
investigation 18FT40 (عضو)
investigation 19FT30 (عضو)
مفيش صف للـ«أب البنل» (THYROID id=87 أو Thyroid Profile id=137).

ب. التحاليل دي فعلاً أعضاء بنل — بس في بنلين!

البنل (is_panel=1)أعضاؤه
THYROID (87) «هرمونات الغدة الدرقية»TSH · FT4 · FT3
THYROI (137) «Thyroid Profile»TSH · FT4 · FT3

كمان فيه باكدج PKG-THYR (2) «باقة الغدة الدرقية» محتوياته = نفس التلاتة (17/18/19). يعني نفس التحاليل تنتمي لـبنلين + باكدج.

ج. إنشاء الطلب بيفكّ البنل/الباكدج لأعضائه — ويرمي الأصل

// LabRequestController@store (سطر 285) if ($investigation->is_panel) { foreach ($investigation->panelMembers as $member) { // بيضيف صف request_investigation لكل عضو فقط // ❌ «أب البنل» ما بيتربطش، وما بيتسجّلش العضو ده جه من أنهي بنل } } // الباكدج (سطر 309): بيضيف الأفراد كمان — من غير ما يسجّل إنهم من باكدج معيّن

د. منطق التجميع في العرض بيحتاج «أب البنل» يكون مربوط

// LabSampleResource — collapse logic $candidatePanel = $investigation->panels->first(); // ← أنهي بنل؟ (87 ولا 137؟ مبهم) $bound = lab_request_investigations.exists(panel_id); // ← أب البنل مربوط؟ $panel = $bound ? $candidatePanel : null; // ← مش مربوط → null → يظهر مفكوك

3 السبب الجذري

🎯 الطلب بيخزّن «تحاليل فردية» بس — من غير أي ذاكرة إنها اتطلبت كبنل/باكدج

  • جدول lab_request_investigations مفيهوش أي عمود يتتبّع أصل المجموعة (لا panel_id ولا package_id).
  • وقت الطلب، البنل/الباكدج بيتفكّ لأعضائه، والأصل (الاسم «Thyroid Panel») بيضيع.
  • منطق العرض بيحاول يجمّع بشرط إن «أب البنل» يكون مربوط — وهو مش مربوط أبداً → بيظهروا مفكوكين.
  • وحتى لو حاولنا نجمّع بالعافية: العضو في بنلين (87 و137) → مبهم نختار أنهي اسم.

الخلاصة

المشكلة مش في الفرونت ولا في منطق العرض — المشكلة إن الباك مش بيحفظ المعلومة من الأساس: إن التلات تحاليل دول اتطلبوا كمجموعة «Thyroid Panel». من غير المعلومة دي، أي عرض (Collect/Reception/Worklist) مستحيل يجمّعهم صح.

4 الحل الجذري (معتمد على الباك إند)

نخلّي الطلب يفتكر المجموعة: نسجّل على كل تحليل إنه اتطلب كجزء من أنهي بنل/باكدج، والباك يجمّع العرض بناءً عليها. الفرونت يرسم الجاهز بس.

قبل: lab_request_investigations(investigation_id) → تحاليل فردية، الأصل ضايع → عرض مفكوك بعد: lab_request_investigations(investigation_id, source_panel_id?, source_package_id?, group_label?) └─ وقت الطلب: نختم على كل عضو المجموعة اللي جه منها └─ وقت العرض: الباك يجمّع تحت اسم البنل/الباكدج → تيوب فيه "Thyroid Panel (TSH, FT4, FT3)"

ليه ده الأصحّ؟

  • بيشتغل لـالبنلات والباكدچات الاتنين (إنت طلبت باكدج).
  • بيحلّ غموض «العضو في بنلين» — لأننا بنسجّل المجموعة الفعلية اللي اتطلبت.
  • مفيش صفوف وهمية ولا تأثير على التسعير/العدّ.
  • مصدر واحد للحقيقة (الباك) — كل الشاشات تتجمّع نفس الطريقة.

بديل أبسط (وأضعف)

إننا نربط «أب البنل» في الطلب → التجميع الحالي يشتغل. بس ده مايغطّيش الباكدچات (واللي إنت طلبته باكدج)، وبيضيف صف غير قابل للفوترة. فمش كافي.

5 خطة التنفيذ (آمنة، بالترتيب)

مرحلة 1

تتبّع المصدر في قاعدة البيانات DB Backend

الهدف: الطلب يفتكر المجموعة.
  • migration: إضافة source_panel_id + source_package_id (nullable) على lab_request_investigations.
  • تعديل إنشاء الطلب: وقت فكّ البنل/الباكدج، نختم المصدر على كل عضو.
مرحلة 2

تجميع العرض في الباك Backend

الهدف: الباك يرجّع المجموعات جاهزة.
  • تحديث LabSampleResource + endpoints (reception-worklist / collection / worklist): يجمّعوا التحاليل تحت اسم البنل/الباكدج المسجّل (بدل شرط «أب البنل مربوط»).
  • fallback: لو مفيش مصدر مسجّل (طلبات قديمة)، نرجع للسلوك الحالي.
مرحلة 3

الفرونت يرسم الجاهز Frontend

الهدف: صفر منطق تجميع في الفرونت.
  • Collect/Reception يعرضوا المجموعة بالاسم اللي الباك بيرجّعه — من غير حسابات.
مرحلة 4

تحقّق Backend

  • طلب باكدج Thyroid → Collect يعرض «Thyroid Panel (TSH, FT4, FT3)» مجموعة واحدة.
  • طلب تحليل مفرد (TSH لوحده) → يفضل مفرد (مش يتجمّع غلط).
  • طلبات قديمة → السلوك زي ما هو.

6 قرار / ملاحظة

  1. التحاليل دي تنتمي لـبنلين (THYROID 87, Thyroid Profile 137) + باكدج (PKG-THYR). تأكيد: اللي بتطلبه هو الباكدج «باقة الغدة الدرقية»؟ (عشان نختار اسم العرض الصح).
  2. موافق على الحل المعتمد على تتبّع المصدر (source_panel_id/source_package_id)؟ ده الأصحّ والأشمل.

أنا جاهز أبدأ بمرحلة 1 (الـmigration + ختم المصدر وقت الطلب) أول ما توافق. كل الشغل في الباك، والفرونت يرسم الجاهز — زي ما عملنا في الورك ليست و Reception.