Expand GenXpert assay mapping and use assay-based responses

This commit is contained in:
Dwi Swandhana
2026-04-15 18:39:01 +07:00
parent 2b91b18275
commit b7195cc629
+90 -46
View File
@@ -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"