رفض عينات B2B: العميل لا يعلم أبداً أن تحليله رُفض
معمل العميل يرسل طلباً عبر البورتال، عينته تُرفض داخلياً (عينة منحلّة، كمية غير كافية…) — واليوم لا يصل للعميل أي أثر لذلك: التحليل يظل «قيد الانتظار» للأبد، والعينة البديلة تُوجَّه لقائمة سحب معملنا الداخلي رغم أن المريض موجود عند العميل. هذه الدراسة توثّق الوضع بالدليل السطري وتقترح الحل.
📅 التاريخ: 10 يونيو 2026🔍 المنهجية: 3 مسارات تحليل متوازية، قراءة فقط🧪 النطاق: 3 مسارات رفض × 4 أسطح بورتال
0
مرة تظهر كلمة "rejected" في كود بورتال العميل كله
3
مسارات رفض داخلية (عينة / كانبان / فقدان المندوب)
0
إشعار أو حقل سبب يعبر حدود البورتال
+2
خلل إضافي اكتُشف أثناء الدراسة (أخطرها is_complete)
2
مرحلتا حل مقترحتان (~4 أيام عمل)
1
الخلاصة التنفيذية
Executive Summary
الرفض الداخلي موثّق بالكامل عندنا (حالة العينة، السبب، التوقيت، المنفّذ، تسلسل كل تحليل) — لكن ولا معلومة واحدة منه تُسلسَل لأي endpoint من endpoints البورتال. خريطة حالة التحليل في البورتال تعرف ثلاث قيم فقط: released / partial / pending — فالتحليل المرفوض يُبلَّغ كـ«pending» إلى الأبد، والتقرير المطبوع يُسقطه بصمت بلا هامش.
الأخطر من الإظهار — التوجيه: كل مسارات إعادة السحب تُنشئ العينة البديلة بحالة Pending الداخلية، فتهبط على قائمة سحب معملنا — بينما المريض جالس عند معمل العميل. والبورتال لا يستطيع جمعها حتى لو عَلِم (نداءات الجمع تقبل PendingCollection فقط)، ومنظومة المناديب لا تراها (تغذيتها at_external_lab فقط). أي: بعد أي رفض لعينة B2B، الطلب يدخل طريقاً مسدوداً لا يخرج منه إلا بتدخل يدوي خارج النظام.
خللان إضافيان اكتُشفا أثناء التتبع: (1) is_complete يُحسب من صفوف النتائج فقط — تحليل رُفض قبل أن تُنشأ له نتيجة يسقط من المقام، فقد يظهر الطلب للعميل «مكتمل ✓» وفيه تحليل مرفوض ينتظر إعادة سحب. (2) ربط «الأصلية ↔ البديلة» مختلف في كل مسار: الكانبان يربط بعمود خاص، فقدان المندوب بـ parent_id، وإعادة السحب اليدوية بلا أي ربط.
2
الوضع الحالي — ماذا يُسجَّل داخلياً مقابل ما يعبر للبورتال
Internal Signals vs Portal Boundary
الإشارة
تُسجَّل داخلياً؟
تعبر للبورتال؟
الدليل
حالة العينة rejected + السبب + التوقيت + المنفّذ
نعم — كاملة
الحالة الخام فقط بلا سبب — وتُعرض بلا ترجمة ولا تنسيق (chip شفاف)
وللمعامل المفعّل عندها المناديب: بعد الجمع تدخل سلسلة المندوب تلقائياً
بعد الحل — التقرير
CBC — رُفضت العينة (عينة منحلّة) وأُعيد طلب السحب بتاريخ …
هامش صريح بدل الاختفاء الصامت
4
خطة الحل — مرحلتان
Two-Phase Solution
المرحلة 1 — الخادم
الحقيقة تعبر الحدود + توجيه البديلة صح
⏱ ~يومان · Pest جديدة + تغطية الرجعية بالسويتات القائمة
show(): حالة تحليل rejected + سبب الرفض (ثنائي اللغة عبر كود الكتالوج عند توفره، وإلا النص الحر) + التوقيت؛ وحالة recollect_pending للتحاليل المعاد سحبها؛ والعينات تحمل rejection_reason / rejected_at / parent_sample_id
توحيد الربط على parent_id في المسارات الثلاثة (الكانبان واليدوي يلحقان بمسار المندوب)
index(): rejected_count + recollect_pending_count + إصلاح خلل is_complete (العدّ من تحاليل الطلب لا من صفوف النتائج فقط)
توجيه البديلة لطلبات B2B (helper واحد لكل المسارات): تبدأ PendingCollection ليجمعها العميل بنداءات الجمع الموجودة فعلاً؛ وبعد جمع البورتال، لو المعمل مفعّل عنده المناديب تتحول at_external_lab وتظهر للمندوب فوراً (بلا ready ثانية — هي مجموعة بالفعل). الطلبات الداخلية تبقى كما هي (Pending)
يبقى recollect قرار staff صريحاً كما هو اليوم (التاريخ أثبت أن الإنشاء التلقائي يولّد أنابيب مكررة) — باستثناء مساري الكانبان والمندوب المؤتمتين أصلاً
المرحلة 2 — واجهة البورتال
العميل يرى ويتصرف
⏱ ~يومان · يشمل بوابة المريض حيث ينطبق
القائمة: شارة حمراء «N مرفوض — يلزم إعادة سحب» في عمود الحالة + إصلاح شارة البيك أب المضللة («وصلت للمعمل» رغم الرفض)
التفاصيل: chip «مرفوض» مترجم بستايل + السبب والتوقيت + صف البديلة متداخلاً تحت الأصلية بحالة «بانتظار سحبكم» وزر «جُمعت — اطبع الباركود» (ولمعامل المناديب: تتبُّع دخولها السلسلة)
التقرير المطبوع: هامش «رُفضت العينة (السبب) وأُعيد طلب السحب» بدل الإسقاط الصامت — في القوالب الستة عبر العقد القائم
رئيسية البورتال: عدّاد «بانتظار إعادة سحب» ضمن المؤشرات
لماذا هذا التقسيم آمن؟ المرحلة 1 كلها إضافات حقول وعدّادات + توجيه حالة البديلة (سلوك جديد لطلبات B2B فقط — الداخلي لا يتغير). المستهلك الوحيد الحساس هو is_complete وإصلاحه يصحّح كذبة قائمة أصلاً. اختبارات Pest بورتال جديدة + السويتات القائمة (B2B/Courier/PdfParity) تغطي الرجعية، وهامش التقرير يدخل تحت حماية عقد القوالب التشغيلي.
5
قرارات مطلوب اعتمادها قبل التنفيذ
Decisions Needed
القرار 1 — مسار البديلة لمعامل المناديب
بعد أن يجمع العميل العينة البديلة من البورتال: تدخل سلسلة المندوب تلقائياً (at_external_lab) أم تحتاج «جاهزة للاستلام» جديدة؟
التوصية: تلقائياً — العميل أكد الجمع للتو، وطلب «ready» ثانية خطوة بيروقراطية ستُنسى وتعلّق البديلة. (مع تسجيل custody كالمعتاد.)
القرار 2 — فوترة التحليل المرفوض نهائياً
فاتورة B2B تُنشأ مقدماً بكامل التحاليل. تحليل رُفض ولم يُعَد سحبه أبداً (أو ألغاه العميل بعد الرفض): يبقى على الفاتورة أم يُخصم؟ خارج نطاق هذه الخطة تقنياً لكنه سيُسأل عنه فور ظهور شارة «مرفوض».
التوصية: v1 يبقى على الفاتورة مع ظهور الحالة بشفافية، ويُعالج الخصم ضمن دورة المطالبات الشهرية كقرار مالي منفصل.
القرار 3 — إشعارات v2
هل نكتفي بالشارات (v1) أم نضيف endpoint إشعارات بورتال (polling) يعرض «رُفضت عينة في LR-321 — السبب…» كقائمة؟
التوصية: v1 الآن؛ وv2 يُقيَّم بعد أسبوعين من الاستخدام الفعلي — البيانات ستقول إن كانت الشارات كافية.
6
منهجية الدراسة
Methodology
3 مسارات تحليل متوازية (قراءة فقط): مسارات الرفض في الخادم وتتبّع كل ما يُكتب، أسطح البورتال الأربعة (قائمة/تفاصيل/تقرير/رئيسية)، وتركيب الفجوة وتصميم الحل بتحقق مستقل.
كل ادعاء في هذا المستند موثّق بملف وسطر — شاملاً الخللين الإضافيين (is_complete والربط المتضارب) اللذين لم يكونا في سؤال الدراسة الأصلي.
بوابة المريض فُحصت أيضاً: تعاني العمى نفسه — الحل يُصمَّم بحيث تتشاركه حيث ينطبق.