Split glass report into three tables
This commit is contained in:
@@ -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);
|
||||
});
|
||||
|
||||
|
||||
@@ -9,52 +9,41 @@
|
||||
<div class="ribbon ribbon-danger">Rekapitulasi Data Bulan {{$bulan}} Tahun {{$tahun}}</div>
|
||||
<p></p>
|
||||
<div class="mt-3 mb-3">
|
||||
<a href="{{ route('exportGlassReport', ['bulan' => $bulan, 'tahun' => $tahun]) }}" class="btn btn-success">
|
||||
<a href="{{ route('exportGlassReport', ['bulan' => $bulan, 'tahun' => $tahun]) }}" class="btn btn-success">
|
||||
<i class="fa fa-file-excel-o"></i> Download Full Excel (CSV)
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="table table-bordered" id="datatable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nama Pasien</th>
|
||||
<th>No RM</th>
|
||||
<th>Bakteri</th>
|
||||
@foreach($jsonantibiotik as $antibiotic)
|
||||
<th title="{{ $antibiotic }}">{{ $antibiotic }}</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse($orderbydate as $data)
|
||||
@foreach (['A', 'B', 'C'] as $tableKey)
|
||||
<div class="table-responsive" style="margin-bottom: 24px;">
|
||||
<h4>TABEL {{ $tableKey }}</h4>
|
||||
<table class="table table-bordered table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>{{ $data->nmpasien }}</td>
|
||||
<td>{{ $data->noregister }}</td>
|
||||
<td>{{ $data->nm_spesimen }}</td> @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
|
||||
<td class="text-center" style="{{ $interpretasi == 'R' ? 'background-color:#ffcccc' : '' }}">
|
||||
{{ $interpretasi }}
|
||||
</td>
|
||||
@foreach (($glassHeaders[$tableKey] ?? []) as $header)
|
||||
<th>{{ $header }}</th>
|
||||
@endforeach
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="{{ count($jsonantibiotik) + 3 }}">Data tidak ditemukan</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</thead>
|
||||
<tbody>
|
||||
@forelse (($glassTables[$tableKey] ?? []) as $row)
|
||||
<tr>
|
||||
@foreach ($row as $cell)
|
||||
<td>{{ $cell }}</td>
|
||||
@endforeach
|
||||
</tr>
|
||||
@empty
|
||||
<tr>
|
||||
<td colspan="{{ count($glassHeaders[$tableKey] ?? []) }}">Data tidak ditemukan</td>
|
||||
</tr>
|
||||
@endforelse
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@endsection
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
|
||||
+105
-7
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user