diff --git a/listener/app.py b/listener/app.py index 85ff4ff7..57191272 100644 --- a/listener/app.py +++ b/listener/app.py @@ -100,13 +100,48 @@ GENEXPERT_TEST_MAPPING = { "TCM TB": "MTB-RIF", # Xpert MTB-RIF Assay G4 Version 6 "TCM TB ULTRA": "MTB-RIF_ULTRA2", # Xpert MTB-RIF Ultra Version 4 "TCM TB XDR": "MTB-XDR", # Xpert MTB-XDR Version 1 - "COVID-19": "COV-2 2", # Xpert Xpress SARS-CoV-2 Version 2 "HCV VL": "HCV", # Xpert HCV Viral Load Version 1 + "COVID-19": "COV-2 2", # Xpert Xpress SARS-CoV-2 Version 2 + "17.3.1 TCM COVID-19": "COV-2 2", # Xpert Xpress SARS-CoV-2 Version 2 + "17.3.2 PCR COVID-19": "COV-2 2", # Xpert Xpress SARS-CoV-2 Version 2 + "E.2.5 HCV TCM": "HCV", + "18.1.1 TCM HCV": "HCV", + "18.1.2 TCM HIV VIRAL LOAD": "HIV-1_VL", + "18.1.4 TCM HPV": "HCV", + "7.3.7 KULTUR TBC MGIT (AUTOMATIC)": "MTB-RIF", + "5.3.8 KULTUR TBC MGIT (AUTOMATIC)": "MTB-RIF", + "5.3.7 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "3.3.6 KULTUR TBC MEDIA LJ (KONVENSIONAL) ": "MTB-XDR", + "2.3.7 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "1.3.6 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "1.3.7 KULTUR TBC MGIT (AUTOMATIC)": "MTB-XDR", + "15.2.1 KULTUR TB MEDIA LJ": "MTB-XDR", + "8.3.7 KULTUR TBC MGIT (AUTOMATIC)": "MTB-XDR", + "9.3.5 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "9.3.6 KULTUR TBC MGIT (AUTOMATIC)": "MTB-XDR", + "12.3.7 KULTUR TBC MGIT (AUTOMATIC)": "MTB-XDR", + "H.2.5 PEMERIKSAAN KULTUR MYCROBACTERIUM TBC": "MTB-XDR", + "12.3.6 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "11.3.6 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "10.3.7 KULTUR TBC MGIT (AUTOMATIC)": "MTB-XDR", + "10.3.6 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "3.3.7 KULTUR TBC MGIT (AUTOMATIC)": "MTB-XDR", + "15.2.2 KULTUR TB MEDIA MGIT (AUTOMATIC)": "MTB-XDR", + "11.3.7 KULTUR TBC MGIT (AUTOMATIC)": "MTB-XDR", + "8.3.6 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "7.3.6 KULTUR TBC MEDIA LJ (KONVENSIONAL)": "MTB-XDR", + "2.3.10 TCM CLAMIDIA TRACHOMATIS / NEISSERIA GONORRHOE": "MTB-RIF", + "12.3.8 TCM TB (GENE EXPERT)": "MTB-RIF", + "15.2.3 TCM TB (GENE EXPERT)": "MTB-RIF", + "2.3.9 TCM GENE EXPERT": "MTB-RIF", + "3.3.8 TCM GENE EXPERT": "MTB-RIF", + "3.3.9 TCM MYCOBACTERIUM TUBERCULOSIS": "MTB-RIF", + "5.3.9 TCM TBC (GENE EXPERT)": "MTB-RIF", + "7.3.8 TCM TBC (GENE EXPERT)": "MTB-RIF", + "8.3.8 TCM TBC (GENE EXPERT)": "MTB-RIF", + "10.3.8 TCM TBC (GENE EXPERT)": "MTB-RIF", + "11.3.9 TCM TB (GENE EXPERT)": "MTB-RIF", - # Mapping untuk IP 10.10.120.74 (Khusus) - # Catatan: Di dokumen Anda tertulis Assay 'HBV' tapi kodenya 'HCV'. - # Pastikan ini benar, atau sesuaikan jika itu typo di dokumen. - "HBV VL": "HCV", } GENEXPERT_IP_CAPABILITIES = { "10.10.120.75": ["MTB-RIF", "MTB-RIF_ULTRA2", "MTB-XDR", "HIV-1_VL", "COV-2 2"], @@ -278,35 +313,32 @@ def parse_genexpert_qpd(qpd_segment): "param_2": param_2, } -def resolve_genexpert_test_code(order, ip_addr=None): +def resolve_genexpert_assay(order, ip_addr=None): assay_name = str(getattr(order, "tes", "") or "").strip() - test_code = GENEXPERT_TEST_MAPPING.get(assay_name) - supported_codes = None - if ip_addr is not None: - supported_codes = GENEXPERT_IP_CAPABILITIES.get(str(ip_addr or "").strip(), []) + specimen_code = str(getattr(order, "kd_spesimen", "") or "").strip() + assay_code = GENEXPERT_TEST_MAPPING.get(assay_name) + assay_source = "mapping:tes" - if not test_code: + if not assay_code and specimen_code: + assay_code = specimen_code + assay_source = "fallback:kd_spesimen" + + supported_codes = GENEXPERT_IP_CAPABILITIES.get(str(ip_addr or "").strip(), []) if ip_addr else [] + capability_match = True if not supported_codes else assay_code in supported_codes + + if not assay_code: print( - f"[GENEXPERT] Skip rnoreg={getattr(order, 'rnoreg', '')} di {ip_addr}: " - f"mapping test code tidak ditemukan untuk tes='{assay_name}'" + f"[GENEXPERT-DEBUG] rnoreg={getattr(order, 'rnoreg', '')}, ip={ip_addr}, " + f"tes='{assay_name}', kd_spesimen='{specimen_code}', assay_code=EMPTY" ) - return None + return None, "none", capability_match - if supported_codes is not None and supported_codes and test_code not in supported_codes: - print( - f"[GENEXPERT] Skip rnoreg={getattr(order, 'rnoreg', '')} di {ip_addr}: " - f"test_code={test_code} tidak didukung alat" - ) - return None - - if supported_codes is not None and not supported_codes: - print( - f"[GENEXPERT] Skip rnoreg={getattr(order, 'rnoreg', '')} di {ip_addr}: " - "capability IP belum dikonfigurasi" - ) - return None - - return test_code + print( + f"[GENEXPERT-DEBUG] rnoreg={getattr(order, 'rnoreg', '')}, ip={ip_addr}, " + f"tes='{assay_name}', kd_spesimen='{specimen_code}', assay_code='{assay_code}', " + f"assay_source={assay_source}, capability_match={capability_match}" + ) + return assay_code, assay_source, capability_match def get_genexpert_query_orders(ip_addr, hl7_msg): flag = get_flag_by_device(ip_addr) @@ -328,21 +360,24 @@ def get_genexpert_query_orders(ip_addr, hl7_msg): (flag_attr == False) | (flag_attr == None) ).order_by(PaslabOrder.urut.asc()).all() - supported_codes = GENEXPERT_IP_CAPABILITIES.get(str(ip_addr or "").strip(), []) - if not supported_codes: - print(f"[GENEXPERT] Tidak ada capability test_code untuk IP {ip_addr}.") - return [] - requested_sample_id = (param_2 or param_1).strip() if (param_2 or param_1) else "" if requested_sample_id and requested_sample_id.upper() != "ALL": for order in base_orders: if str(order.rnoreg or "").strip() != requested_sample_id: continue + assay_code, _, _ = resolve_genexpert_assay(order, ip_addr) + if not assay_code: + return [] return [order] print(f"[GENEXPERT] Tidak ada order untuk sample_id={requested_sample_id} di {ip_addr}") return [] - return base_orders[:1] + for order in base_orders: + assay_code, _, _ = resolve_genexpert_assay(order, ip_addr) + if assay_code: + return [order] + print(f"[GENEXPERT] Tidak ada order dengan assay valid untuk IP {ip_addr}") + return [] finally: session.close() @@ -373,7 +408,6 @@ def create_genexpert_rsp_z02_response(orders, incoming_hl7, ip_addr=None): query_tag = qpd.get("query_tag") or (extract_msg_control_id(incoming_hl7) or "UNKNOWN") query_name = qpd.get("query_name") or "Z03^HOST QUERY" resp_control_id = f"RSP{datetime.datetime.now().strftime('%Y%m%d%H%M%S')}" - supported_codes = GENEXPERT_IP_CAPABILITIES.get(str(ip_addr or "").strip(), []) msh = build_genexpert_response_msh("RSP^Z02", incoming_hl7, resp_control_id) msa = f"MSA|AA|{query_tag}" @@ -386,17 +420,22 @@ def create_genexpert_rsp_z02_response(orders, incoming_hl7, ip_addr=None): patient_id = str(order.norm or order.rnoreg or "").strip() sample_id = str(order.rnoreg or "").strip() order_ts = datetime.datetime.now().strftime('%Y%m%d%H%M%S') + assay_code, assay_source, capability_match = resolve_genexpert_assay(order, ip_addr) + if not assay_code: + print(f"[GENEXPERT] Payload order dilewati rnoreg={sample_id} karena assay kosong.") + continue + + print( + f"[GENEXPERT-DEBUG] Build RSP rnoreg={sample_id}, ip={ip_addr}, " + f"patient_id={patient_id}, assay_code={assay_code}, assay_source={assay_source}, " + f"capability_match={capability_match}, query_name='{query_name}', query_tag='{query_tag}'" + ) + segments.append(f"PID|{patient_idx}||{patient_id}") - - test_codes = supported_codes if supported_codes else [] - if not test_codes: - print(f"[GENEXPERT] Tidak ada test_code capability untuk payload ke {ip_addr}") - - for order_idx, test_code in enumerate(test_codes, start=1): - segments.append(f"ORC|NW|{order_idx}|||||||{order_ts}") - segments.append(f"OBR|{order_idx}|||{test_code}|||||||A") - segments.append("TQ1|||||||||R") - segments.append(f"SPM|{order_idx}|{sample_id}^||ORH|||||||P") + segments.append(f"ORC|NW|1|||||||{order_ts}") + segments.append(f"OBR|1|||{assay_code}|||||||A") + segments.append("TQ1|||||||||R") + segments.append(f"SPM|1|{sample_id}^||ORH|||||||P") return "\r".join(segments) + "\r" @@ -411,6 +450,11 @@ def send_all_orders(conn, ip_addr, hl7_msg, msg_id): conn.sendall(f"\x0b{rsp}\x1c\r".encode('utf-8')) return + qpd_segment = extract_segment(hl7_msg, "QPD") + print( + f"[GENEXPERT-DEBUG] QBP diproses untuk ip={ip_addr}, msg_id={msg_id}, " + f"qpd='{qpd_segment}', selected_rnoreg={[str(order.rnoreg or '').strip() for order in orders]}" + ) print(f"[GENEXPERT] Mengirim {len(orders)} order ke {ip_addr}") rsp = create_genexpert_rsp_z02_response(orders, hl7_msg, ip_addr=ip_addr) mllp = f"\x0b{rsp}\x1c\r"