Expand GenXpert assay mapping and use assay-based responses
This commit is contained in:
+90
-46
@@ -100,13 +100,48 @@ GENEXPERT_TEST_MAPPING = {
|
|||||||
"TCM TB": "MTB-RIF", # Xpert MTB-RIF Assay G4 Version 6
|
"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 ULTRA": "MTB-RIF_ULTRA2", # Xpert MTB-RIF Ultra Version 4
|
||||||
"TCM TB XDR": "MTB-XDR", # Xpert MTB-XDR Version 1
|
"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
|
"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 = {
|
GENEXPERT_IP_CAPABILITIES = {
|
||||||
"10.10.120.75": ["MTB-RIF", "MTB-RIF_ULTRA2", "MTB-XDR", "HIV-1_VL", "COV-2 2"],
|
"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,
|
"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()
|
assay_name = str(getattr(order, "tes", "") or "").strip()
|
||||||
test_code = GENEXPERT_TEST_MAPPING.get(assay_name)
|
specimen_code = str(getattr(order, "kd_spesimen", "") or "").strip()
|
||||||
supported_codes = None
|
assay_code = GENEXPERT_TEST_MAPPING.get(assay_name)
|
||||||
if ip_addr is not None:
|
assay_source = "mapping:tes"
|
||||||
supported_codes = GENEXPERT_IP_CAPABILITIES.get(str(ip_addr or "").strip(), [])
|
|
||||||
|
|
||||||
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(
|
print(
|
||||||
f"[GENEXPERT] Skip rnoreg={getattr(order, 'rnoreg', '')} di {ip_addr}: "
|
f"[GENEXPERT-DEBUG] rnoreg={getattr(order, 'rnoreg', '')}, ip={ip_addr}, "
|
||||||
f"mapping test code tidak ditemukan untuk tes='{assay_name}'"
|
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(
|
||||||
print(
|
f"[GENEXPERT-DEBUG] rnoreg={getattr(order, 'rnoreg', '')}, ip={ip_addr}, "
|
||||||
f"[GENEXPERT] Skip rnoreg={getattr(order, 'rnoreg', '')} di {ip_addr}: "
|
f"tes='{assay_name}', kd_spesimen='{specimen_code}', assay_code='{assay_code}', "
|
||||||
f"test_code={test_code} tidak didukung alat"
|
f"assay_source={assay_source}, capability_match={capability_match}"
|
||||||
)
|
)
|
||||||
return None
|
return assay_code, assay_source, capability_match
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def get_genexpert_query_orders(ip_addr, hl7_msg):
|
def get_genexpert_query_orders(ip_addr, hl7_msg):
|
||||||
flag = get_flag_by_device(ip_addr)
|
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)
|
(flag_attr == False) | (flag_attr == None)
|
||||||
).order_by(PaslabOrder.urut.asc()).all()
|
).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 ""
|
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":
|
if requested_sample_id and requested_sample_id.upper() != "ALL":
|
||||||
for order in base_orders:
|
for order in base_orders:
|
||||||
if str(order.rnoreg or "").strip() != requested_sample_id:
|
if str(order.rnoreg or "").strip() != requested_sample_id:
|
||||||
continue
|
continue
|
||||||
|
assay_code, _, _ = resolve_genexpert_assay(order, ip_addr)
|
||||||
|
if not assay_code:
|
||||||
|
return []
|
||||||
return [order]
|
return [order]
|
||||||
print(f"[GENEXPERT] Tidak ada order untuk sample_id={requested_sample_id} di {ip_addr}")
|
print(f"[GENEXPERT] Tidak ada order untuk sample_id={requested_sample_id} di {ip_addr}")
|
||||||
return []
|
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:
|
finally:
|
||||||
session.close()
|
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_tag = qpd.get("query_tag") or (extract_msg_control_id(incoming_hl7) or "UNKNOWN")
|
||||||
query_name = qpd.get("query_name") or "Z03^HOST QUERY"
|
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')}"
|
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)
|
msh = build_genexpert_response_msh("RSP^Z02", incoming_hl7, resp_control_id)
|
||||||
msa = f"MSA|AA|{query_tag}"
|
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()
|
patient_id = str(order.norm or order.rnoreg or "").strip()
|
||||||
sample_id = str(order.rnoreg or "").strip()
|
sample_id = str(order.rnoreg or "").strip()
|
||||||
order_ts = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
|
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}")
|
segments.append(f"PID|{patient_idx}||{patient_id}")
|
||||||
|
segments.append(f"ORC|NW|1|||||||{order_ts}")
|
||||||
test_codes = supported_codes if supported_codes else []
|
segments.append(f"OBR|1|||{assay_code}|||||||A")
|
||||||
if not test_codes:
|
segments.append("TQ1|||||||||R")
|
||||||
print(f"[GENEXPERT] Tidak ada test_code capability untuk payload ke {ip_addr}")
|
segments.append(f"SPM|1|{sample_id}^||ORH|||||||P")
|
||||||
|
|
||||||
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")
|
|
||||||
|
|
||||||
return "\r".join(segments) + "\r"
|
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'))
|
conn.sendall(f"\x0b{rsp}\x1c\r".encode('utf-8'))
|
||||||
return
|
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}")
|
print(f"[GENEXPERT] Mengirim {len(orders)} order ke {ip_addr}")
|
||||||
rsp = create_genexpert_rsp_z02_response(orders, hl7_msg, ip_addr=ip_addr)
|
rsp = create_genexpert_rsp_z02_response(orders, hl7_msg, ip_addr=ip_addr)
|
||||||
mllp = f"\x0b{rsp}\x1c\r"
|
mllp = f"\x0b{rsp}\x1c\r"
|
||||||
|
|||||||
Reference in New Issue
Block a user