From 5c5bf0ce19034310b0d3fdc0cd825bdbc5f84edd Mon Sep 17 00:00:00 2001 From: Dwi Swandhana Date: Mon, 20 Apr 2026 05:15:17 +0700 Subject: [PATCH] Split glass report into three tables --- .../app/Http/Controllers/ReportController.php | 356 ++++++++++++++++-- .../views/admin/glassreport.blade.php | 63 ++-- htdocs/resources/views/admin/report.blade.php | 2 +- listener/app.py | 112 +++++- 4 files changed, 454 insertions(+), 79 deletions(-) diff --git a/htdocs/app/Http/Controllers/ReportController.php b/htdocs/app/Http/Controllers/ReportController.php index 6b5537eb..f08fcdbe 100644 --- a/htdocs/app/Http/Controllers/ReportController.php +++ b/htdocs/app/Http/Controllers/ReportController.php @@ -549,6 +549,298 @@ class ReportController extends Controller ->pluck('rekapantibiotik.antibiotic') ->toArray(); } + private function getGlassReportHeaders() { + $tableC = [ + 'ID Rumah Sakit', + 'Nama Pasien', + 'No Rekam Medis', + 'Jenis Kelamin', + 'Tanggal Lahir', + 'Usia', + 'Ruang Rawat', + 'Tanggal Pasien Masuk', + 'Tanggal Pengambilan Spesimen', + 'Specimen Origin', + 'Jenis Spesimen', + ]; + + $tableAAntibiotics = [ + 'Cefoxitin', + 'Oxacillin', + 'Penicillin', + 'Ampicillin', + 'Amoxicillin', + 'Cefazolin', + 'Cefuroxime', + 'Cefixime', + 'Cefotaxime', + 'Ceftriaxone', + 'Ceftazidime', + 'Cefepime', + 'Ceftaroline', + 'Ertapenem', + 'Imipenem', + 'Meropenem', + 'Aztreonam', + 'Amoxicillin-clavulanate', + 'Ampicillin-sulbactam', + 'Piperacillin-tazobactam', + 'Ceftazidime-avibactam', + 'Gentamicin', + 'Amikacin', + 'Ciprofloxacin', + 'Levofloxacin', + 'Moxifloxacin', + 'Trimethoprim-sulfamethoxazole', + 'Azithromycin', + 'Clarithromycin', + 'Erythromycin', + 'Clindamycin', + 'Tetracycline', + 'Minocycline', + 'Doxycycline', + 'Colistin', + 'Vancomycin', + 'Linezolid', + 'Tigecycline', + 'Daptomycin', + 'Nitrofurantoin', + 'Fosfomycin', + ]; + + $tableBAntibiotics = [ + 'Fluconazole', + 'Voriconazole', + 'Amphotericin B', + 'Micafungin', + 'Caspofungin', + 'Flucytosine', + ]; + + return [ + 'A' => array_merge($tableC, ['Nama Spesies Bakteri', 'ESBL', 'MRSA'], $tableAAntibiotics), + 'B' => array_merge($tableC, ['Nama Spesies Jamur'], $tableBAntibiotics), + 'C' => $tableC, + 'A_antibiotics' => $tableAAntibiotics, + 'B_antibiotics' => $tableBAntibiotics, + ]; + } + private function getGlassReportAntibioticAliases() { + return [ + 'Cefoxitin' => ['cefoxitin', 'cefoxitinscreen'], + 'Oxacillin' => ['oxacillin'], + 'Penicillin' => ['penicillin', 'benzylpenicillin'], + 'Ampicillin' => ['ampicillin'], + 'Amoxicillin' => ['amoxicillin'], + 'Cefazolin' => ['cefazolin', 'cefazolinurine', 'cefazolinother'], + 'Cefuroxime' => ['cefuroxime', 'cefuroximeiv', 'cefuroximeoral'], + 'Cefixime' => ['cefixime'], + 'Cefotaxime' => ['cefotaxime'], + 'Ceftriaxone' => ['ceftriaxone'], + 'Ceftazidime' => ['ceftazidime'], + 'Cefepime' => ['cefepime'], + 'Ceftaroline' => ['ceftaroline'], + 'Ertapenem' => ['ertapenem'], + 'Imipenem' => ['imipenem'], + 'Meropenem' => ['meropenem'], + 'Aztreonam' => ['aztreonam'], + 'Amoxicillin-clavulanate' => ['amoxicillinclavulanate', 'amoxicillinclavulanicacid'], + 'Ampicillin-sulbactam' => ['ampicillinsulbactam'], + 'Piperacillin-tazobactam' => ['piperacillintazobactam'], + 'Ceftazidime-avibactam' => ['ceftazidimeavibactam'], + 'Gentamicin' => ['gentamicin'], + 'Amikacin' => ['amikacin'], + 'Ciprofloxacin' => ['ciprofloxacin'], + 'Levofloxacin' => ['levofloxacin'], + 'Moxifloxacin' => ['moxifloxacin'], + 'Trimethoprim-sulfamethoxazole' => ['trimethoprimsulfamethoxazole', 'trimetrophimesulfamethoxazole'], + 'Azithromycin' => ['azithromycin'], + 'Clarithromycin' => ['clarithromycin'], + 'Erythromycin' => ['erythromycin'], + 'Clindamycin' => ['clindamycin'], + 'Tetracycline' => ['tetracycline', 'tetracyclinescreenonly', 'tetracyclineu'], + 'Minocycline' => ['minocycline'], + 'Doxycycline' => ['doxycycline'], + 'Colistin' => ['colistin'], + 'Vancomycin' => ['vancomycin'], + 'Linezolid' => ['linezolid'], + 'Tigecycline' => ['tigecycline'], + 'Daptomycin' => ['daptomycin'], + 'Nitrofurantoin' => ['nitrofurantoin'], + 'Fosfomycin' => ['fosfomycin'], + 'Fluconazole' => ['fluconazole'], + 'Voriconazole' => ['voriconazole'], + 'Amphotericin B' => ['amphotericinb'], + 'Micafungin' => ['micafungin'], + 'Caspofungin' => ['caspofungin'], + 'Flucytosine' => ['flucytosine'], + ]; + } + private function normalizeGlassReportValue($value) { + return preg_replace('/[^a-z0-9]+/', '', strtolower(strip_tags((string) $value))); + } + private function pickGlassReportResistanceValue($row, $header) { + $rawResistance = $row->resistence ?? $row->resistance ?? null; + $rawInterpretation = $row->interpretation ?? null; + $resistance = trim((string) $rawResistance); + $interpretation = trim((string) $rawInterpretation); + + if ($resistance === '') { + return $interpretation; + } + + $normalizedResistance = $this->normalizeGlassReportValue($resistance); + $normalizedAntibiotic = $this->normalizeGlassReportValue($row->antibiotic ?? ''); + $normalizedHeader = $this->normalizeGlassReportValue($header); + + if ($normalizedResistance === $normalizedAntibiotic || $normalizedResistance === $normalizedHeader) { + return $interpretation; + } + + return $resistance; + } + private function getGlassReportOrigin($row) { + if (empty($row->daftar) || empty($row->mulai)) { + return ''; + } + + try { + $selisihHari = Carbon::parse($row->daftar)->diffInDays(Carbon::parse($row->mulai)); + return $selisihHari >= 3 ? 'Hospital Origin' : 'Community Origin'; + } catch (\Throwable $e) { + return ''; + } + } + private function buildGlassReportBaseRow($row) { + $jenisSpesimen = trim(implode(' ', array_filter([ + $row->kd_spesimen ?? '', + $row->nm_spesimen ?? '', + ]))); + + return [ + $row->nmrs ?? '', + $row->nmpasien ?? '', + $row->noregister ?? '', + $row->jkpasien ?? '', + $row->tgllahirpasien ?? '', + $row->usia ?? '', + $row->asalpasien ?? '', + $row->daftar ?? '', + $row->mulai ?? '', + $this->getGlassReportOrigin($row), + $jenisSpesimen, + ]; + } + private function getGlassReportLookups($rows) { + $orderIds = $rows->pluck('id')->filter()->values()->all(); + $accnumbers = $rows->pluck('nofoto')->filter()->values()->all(); + + $komponen = DB::table('db_komponenjawaban') + ->select('accnumber', 'komponen', 'isidata') + ->whereIn('accnumber', $accnumbers) + ->whereIn('komponen', ['bakteri', 'id_bakteri01', 'id_bakteri02', 'id_mikroorganisme']) + ->whereNotNull('isidata') + ->where('isidata', '!=', '') + ->get() + ->groupBy('accnumber'); + + $antibiotik = RekapAntibiotik::query() + ->whereIn('orderid', $orderIds) + ->get(['orderid', 'antibiotic', 'resistance', 'interpretation']) + ->groupBy('orderid'); + + return [ + 'komponen' => $komponen, + 'antibiotik' => $antibiotik, + ]; + } + private function splitGlassReportRows($rows, $lookups) { + $headers = $this->getGlassReportHeaders(); + $aliases = $this->getGlassReportAntibioticAliases(); + $tables = ['A' => [], 'B' => [], 'C' => []]; + + foreach ($rows as $row) { + $baseRow = $this->buildGlassReportBaseRow($row); + $komponenRows = $lookups['komponen'][$row->nofoto] ?? collect([]); + $antibioticRows = $lookups['antibiotik'][$row->id] ?? collect([]); + + $bacterialName = ''; + $fungalName = ''; + $foundMorphology = false; + + foreach ($komponenRows as $komponenRow) { + $value = trim(strip_tags((string) $komponenRow->isidata)); + if ($value === '') { + continue; + } + + if (stripos($value, 'Ditemukan morfologi') !== false) { + $foundMorphology = true; + } + + if (in_array($komponenRow->komponen, ['bakteri', 'id_bakteri01', 'id_bakteri02'], true) && $bacterialName === '' && stripos($value, 'Ditemukan morfologi') === false) { + $bacterialName = $value; + } + + if ($komponenRow->komponen === 'id_mikroorganisme' && $fungalName === '') { + $fungalName = $value; + } + } + + $antibioticValues = []; + foreach ($antibioticRows as $antibioticRow) { + $matchedHeader = null; + $normalizedAntibiotic = $this->normalizeGlassReportValue($antibioticRow->antibiotic ?? ''); + $normalizedResistance = $this->normalizeGlassReportValue($antibioticRow->resistance ?? ''); + + foreach ($aliases as $header => $variants) { + if (in_array($normalizedAntibiotic, $variants, true) || in_array($normalizedResistance, $variants, true)) { + $matchedHeader = $header; + break; + } + } + + if ($matchedHeader === null || isset($antibioticValues[$matchedHeader])) { + continue; + } + + $antibioticValues[$matchedHeader] = $this->pickGlassReportResistanceValue($antibioticRow, $matchedHeader); + } + + $hasJenisSpesimen = trim((string) ($baseRow[10] ?? '')) !== ''; + if ($bacterialName !== '' && $hasJenisSpesimen) { + $tableRow = array_merge($baseRow, [ + $bacterialName, + $row->id_esbl ?? '', + $row->id_mrsa ?? '', + ]); + + foreach ($headers['A_antibiotics'] as $antibioticHeader) { + $tableRow[] = $antibioticValues[$antibioticHeader] ?? ''; + } + + $tables['A'][] = $tableRow; + continue; + } + + if ($foundMorphology || $fungalName !== '') { + $tableRow = array_merge($baseRow, [ + $fungalName !== '' ? $fungalName : 'Ditemukan morfologi', + ]); + + foreach ($headers['B_antibiotics'] as $antibioticHeader) { + $tableRow[] = $antibioticValues[$antibioticHeader] ?? ''; + } + + $tables['B'][] = $tableRow; + continue; + } + + $tables['C'][] = $baseRow; + } + + return $tables; + } public function genGlassReport(Request $request) { $bulan = $request->input('bulan'); $tahun = $request->input('tahun'); @@ -574,11 +866,16 @@ class ReportController extends Controller // 2. Ambil Data Antibiotik HANYA untuk 50 pasien tersebut $pageIds = $orderbydate->pluck('id')->toArray(); $antibiotikLookup = $this->mapAntibiotikData($pageIds); + $glassLookups = $this->getGlassReportLookups($orderbydate->getCollection()); + $glassTables = $this->splitGlassReportRows($orderbydate->getCollection(), $glassLookups); + $glassHeaders = $this->getGlassReportHeaders(); return view('admin.glassreport', [ 'orderbydate' => $orderbydate, 'antibiotikLookup' => $antibiotikLookup, // Kirim array hasil mapping 'jsonantibiotik' => $this->listAntibiotik, + 'glassTables' => $glassTables, + 'glassHeaders' => $glassHeaders, 'bulan' => $bulan, 'tahun' => $tahun ]); @@ -600,10 +897,12 @@ class ReportController extends Controller $response = new StreamedResponse(function() use ($bulan, $tahun) { $handle = fopen('php://output', 'w'); - - // Header CSV - $staticHeader = ['ID RS', 'Nama Pasien', 'No RM', 'JK', 'Tgl Lahir', 'Usia', 'Ruang', 'Tgl Masuk', 'Tgl Sample', 'Origin', 'Jenis Spesimen', 'Spesies Bakteri', 'ESBL', 'MRSA']; - fputcsv($handle, array_merge($staticHeader, $this->listAntibiotik)); + $headers = $this->getGlassReportHeaders(); + $tables = [ + 'A' => [], + 'B' => [], + 'C' => [], + ]; // Query Tanpa Get() tapi Chunk() $query = Periksa::query()->whereYear('daftar', $tahun); @@ -612,39 +911,28 @@ class ReportController extends Controller } // Proses per 500 data agar RAM stabil - $query->chunk(500, function($rows) use ($handle) { - - // Mapping Antibiotik untuk batch 500 ini saja - $chunkIds = $rows->pluck('id')->toArray(); - $antibiotikLookup = $this->mapAntibiotikData($chunkIds); + $query->orderBy('id')->chunk(500, function($rows) use (&$tables) { + $lookups = $this->getGlassReportLookups($rows); + $chunkTables = $this->splitGlassReportRows($rows, $lookups); - foreach ($rows as $row) { - $csvRow = [ - $row->id_rs ?? '', // Sesuaikan nama kolom - $row->nmpasien, - $row->noregister, - $row->jkpasien, - $row->tgllahirpasien, - $row->usia, - $row->asalpasien, - $row->mulai, - $row->daftar, - '', // Origin - $row->kd_spesimen, - $row->nm_spesimen, // Asumsi nama bakteri disini atau kolom lain - $row->id_esbl, - $row->id_mrsa - ]; - - foreach ($this->listAntibiotik as $headerAntibiotik) { - $nilai = $antibiotikLookup[$row->id][$headerAntibiotik] ?? ''; - $csvRow[] = $nilai; - } - - fputcsv($handle, $csvRow); - } + foreach (['A', 'B', 'C'] as $tableKey) { + foreach ($chunkTables[$tableKey] as $tableRow) { + $tables[$tableKey][] = $tableRow; + } + } }); + foreach (['A', 'B', 'C'] as $tableKey) { + fputcsv($handle, ['TABEL '.$tableKey]); + fputcsv($handle, $headers[$tableKey]); + + foreach ($tables[$tableKey] as $tableRow) { + fputcsv($handle, $tableRow); + } + + fputcsv($handle, []); + } + fclose($handle); }); diff --git a/htdocs/resources/views/admin/glassreport.blade.php b/htdocs/resources/views/admin/glassreport.blade.php index 5a4980db..d732a0eb 100644 --- a/htdocs/resources/views/admin/glassreport.blade.php +++ b/htdocs/resources/views/admin/glassreport.blade.php @@ -9,52 +9,41 @@
Rekapitulasi Data Bulan {{$bulan}} Tahun {{$tahun}}

- + Download Full Excel (CSV)
-
- - - - - - - @foreach($jsonantibiotik as $antibiotic) - - @endforeach - - - - @forelse($orderbydate as $data) + @foreach (['A', 'B', 'C'] as $tableKey) +
+

TABEL {{ $tableKey }}

+
Nama PasienNo RMBakteri{{ $antibiotic }}
+ - - - @foreach($jsonantibiotik as $headerAntibiotik) - @php - // LOGIC UTAMA: - // Cek di array lookup: [id_pasien][nama_antibiotik] - // Jika ada, ambil nilainya. Jika tidak, kosong. - $interpretasi = $antibiotikLookup[$data->id][$headerAntibiotik] ?? ''; - @endphp - + @foreach (($glassHeaders[$tableKey] ?? []) as $header) + @endforeach - @empty - - - - @endforelse - -
{{ $data->nmpasien }}{{ $data->noregister }}{{ $data->nm_spesimen }} - {{ $interpretasi }} - {{ $header }}
Data tidak ditemukan
-
- + + + @forelse (($glassTables[$tableKey] ?? []) as $row) + + @foreach ($row as $cell) + {{ $cell }} + @endforeach + + @empty + + Data tidak ditemukan + + @endforelse + + + + @endforeach -@endsection \ No newline at end of file +@endsection diff --git a/htdocs/resources/views/admin/report.blade.php b/htdocs/resources/views/admin/report.blade.php index bed62696..caefc718 100644 --- a/htdocs/resources/views/admin/report.blade.php +++ b/htdocs/resources/views/admin/report.blade.php @@ -629,7 +629,7 @@ $(document).ready(function () { type : 'error', }); } else { - var url = '{{url('/')}}/glassreport?bulan='+bulan+'?tahun='+tahun; + var url = '{{url('/')}}/glassreport?bulan='+bulan+'&tahun='+tahun; window.location.href = url; } }); diff --git a/listener/app.py b/listener/app.py index 90bdb398..2d8c3ba2 100644 --- a/listener/app.py +++ b/listener/app.py @@ -402,6 +402,27 @@ def create_genexpert_ack_r01_response(incoming_hl7): msa = f"MSA|CA|{incoming_control_id}" return f"{msh}\r{msa}\r" +def format_hl7_date(value): + if not value: + return "" + if isinstance(value, datetime.datetime): + return value.strftime("%Y%m%d") + if isinstance(value, datetime.date): + return value.strftime("%Y%m%d") + text = str(value).strip() + digits = re.sub(r"[^0-9]", "", text) + return digits[:8] if len(digits) >= 8 else "" + +def map_hl7_sex(value): + text = str(value or "").strip().upper() + if not text: + return "" + if text.startswith("L") or "LAKI" in text or text == "M": + return "M" + if text.startswith("P") or "PEREM" in text or text == "F": + return "F" + return "" + def create_genexpert_rsp_z02_response(orders, incoming_hl7, ip_addr=None): qpd_segment = extract_segment(incoming_hl7, "QPD") qpd = parse_genexpert_qpd(qpd_segment) @@ -417,25 +438,45 @@ def create_genexpert_rsp_z02_response(orders, incoming_hl7, ip_addr=None): segments.append(qpd_segment) for patient_idx, order in enumerate(orders, start=1): - 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') + patient_id = sanitize_astm_field(order.norm or order.rnoreg, max_len=50) + sample_id = sanitize_astm_field(order.rnoreg, max_len=50) + order_ts = ( + getattr(order, "rtglast", None).strftime('%Y%m%d%H%M%S') + if getattr(order, "rtglast", None) + else 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 + first_name, last_name = split_patient_name(order.nama) + patient_name = sanitize_astm_field(f"{last_name}^{first_name}", uppercase=True, max_len=80, allow_component_sep=True) + dob = format_hl7_date(getattr(order, "tgllahir", None)) + sex = map_hl7_sex(getattr(order, "rjenis", "")) + address = sanitize_astm_field(getattr(order, "alamat", ""), max_len=120) + room = sanitize_astm_field(getattr(order, "ruangan", ""), uppercase=True, max_len=80) + doctor = sanitize_astm_field(getattr(order, "namadok", ""), max_len=80) + requested_test_name = sanitize_astm_field(getattr(order, "tes", ""), max_len=120) + specimen_type = sanitize_astm_field( + getattr(order, "nm_spesimen", "") or getattr(order, "kd_spesimen", "") or "ORH", + uppercase=True, + max_len=40 + ) + 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}'" + f"capability_match={capability_match}, patient_name='{patient_name}', dob='{dob}', " + f"sex='{sex}', room='{room}', doctor='{doctor}', specimen_type='{specimen_type}', " + f"requested_test_name='{requested_test_name}', query_name='{query_name}', query_tag='{query_tag}'" ) - segments.append(f"PID|{patient_idx}||{patient_id}") + segments.append(f"PID|{patient_idx}||{patient_id}||{patient_name}||{dob}|{sex}|||{address}") segments.append(f"ORC|NW|1|||||||{order_ts}") - segments.append(f"OBR|1|||{assay_code}|||||||A") + segments.append(f"OBR|1|||{assay_code}^{requested_test_name}^L|||||||A") segments.append("TQ1|||||||||R") - segments.append(f"SPM|1|{sample_id}^||ORH|||||||P") + segments.append(f"SPM|1|{sample_id}^{sample_id}||{specimen_type}|||||||P") return "\r".join(segments) + "\r" @@ -456,6 +497,7 @@ def send_all_orders(conn, ip_addr, hl7_msg, msg_id, response_framing="mllp"): print(f"[GENEXPERT] Mengirim {len(orders)} order ke {ip_addr}") rsp = create_genexpert_rsp_z02_response(orders, hl7_msg, ip_addr=ip_addr) first_accnumber = str(orders[0].rnoreg or "").strip() if orders else "" + debug_genexpert_order_message(rsp, ip_addr=ip_addr) send_genexpert_response(conn, ip_addr, rsp, response_framing, label=f"qbp-order:{first_accnumber}") for order in orders: @@ -553,6 +595,62 @@ def send_genexpert_response(conn, ip_addr, hl7_message, framing, label=""): ) conn.sendall(payload) +def debug_genexpert_order_message(hl7_message, ip_addr=None): + segments = parse_hl7_segments(hl7_message) + current_pid = "" + current_patient_name = "" + order_index = 0 + + for segment in segments: + fields = segment.split("|") + seg_type = fields[0] if fields else "" + + if seg_type == "PID": + current_pid = fields[3] if len(fields) > 3 else "" + current_patient_name = fields[5] if len(fields) > 5 else "" + dob = fields[7] if len(fields) > 7 else "" + sex = fields[8] if len(fields) > 8 else "" + address = fields[11] if len(fields) > 11 else "" + print( + f"[GENEXPERT-ORDER-DEBUG] ip={ip_addr}, seg=PID, patient_id='{current_pid}', " + f"patient_name='{current_patient_name}', dob='{dob}', sex='{sex}', " + f"address='{address}', raw='{segment}'" + ) + elif seg_type == "ORC": + order_index = fields[2] if len(fields) > 2 else "" + order_time = fields[9] if len(fields) > 9 else "" + print( + f"[GENEXPERT-ORDER-DEBUG] ip={ip_addr}, seg=ORC, placer_order='{order_index}', " + f"order_time='{order_time}', patient_id='{current_pid}', " + f"patient_name='{current_patient_name}', raw='{segment}'" + ) + elif seg_type == "OBR": + assay_code = fields[4] if len(fields) > 4 else "" + result_status = fields[11] if len(fields) > 11 else "" + assay_parts = assay_code.split("^") + assay_id = assay_parts[0] if len(assay_parts) > 0 else "" + assay_name = assay_parts[1] if len(assay_parts) > 1 else "" + print( + f"[GENEXPERT-ORDER-DEBUG] ip={ip_addr}, seg=OBR, placer_order='{order_index}', " + f"assay_code='{assay_id}', assay_name='{assay_name}', result_status='{result_status}', " + f"patient_id='{current_pid}', patient_name='{current_patient_name}', raw='{segment}'" + ) + elif seg_type == "TQ1": + priority = fields[9] if len(fields) > 9 else "" + print( + f"[GENEXPERT-ORDER-DEBUG] ip={ip_addr}, seg=TQ1, placer_order='{order_index}', " + f"priority='{priority}', patient_id='{current_pid}', " + f"patient_name='{current_patient_name}', raw='{segment}'" + ) + elif seg_type == "SPM": + specimen_id = fields[2] if len(fields) > 2 else "" + specimen_type = fields[4] if len(fields) > 4 else "" + print( + f"[GENEXPERT-ORDER-DEBUG] ip={ip_addr}, seg=SPM, placer_order='{order_index}', " + f"specimen_id='{specimen_id}', specimen_type='{specimen_type}', patient_id='{current_pid}', " + f"patient_name='{current_patient_name}', raw='{segment}'" + ) + def build_genexpert_result_query(accnumber, msg_control_id): ts = datetime.datetime.now().strftime('%Y%m%d%H%M%S') # Query hasil berbasis accession number di QRD-8.