diff --git a/htdocs/app/Http/Controllers/ListController.php b/htdocs/app/Http/Controllers/ListController.php
index 71763c01..a71168e7 100644
--- a/htdocs/app/Http/Controllers/ListController.php
+++ b/htdocs/app/Http/Controllers/ListController.php
@@ -237,7 +237,11 @@ class ListController extends Controller
$tcmtb,
$urine
);
-
+ $batasWaktu = Carbon::now()->subHours(24);
+ Periksa::whereNull('status')->where('mulai', '<', $batasWaktu)->update([
+ 'status' => 'Dibatalkan (Arsip)',
+ 'updated_at' => now()
+ ]);
$arraylist = Periksa::select(
'id', 'mulai', 'akhir', 'orderid', 'noloket', 'nofoto', 'noregister', 'asalpasien', 'nmrs', 'pasien_id', 'nmpasien',
'jkpasien', 'tgllahirpasien', 'tlppasien', 'alamatpasien', 'reques', 'usia', 'berat', 'ktp', 'bpjs', 'ruangan_id',
diff --git a/htdocs/app/Services/AstmMessageService.php b/htdocs/app/Services/AstmMessageService.php
index d58c8341..2f47d590 100644
--- a/htdocs/app/Services/AstmMessageService.php
+++ b/htdocs/app/Services/AstmMessageService.php
@@ -285,7 +285,7 @@ class AstmMessageService
Periksa::where('nofoto', $accession_number)->update([
'status' => 'Data Vitek di Terima',
]);
- Log::info("Data berhasil disimpan:", $resultSample->toArray());
+ //Log::info("Data berhasil disimpan:", $resultSample->toArray());
$resultSample->save();
}
return response()->json(['message' => 'Data berhasil diproses dan disimpan.']);
@@ -467,7 +467,7 @@ class AstmMessageService
'status' => 'Data Vitek di Terima',
]);
}
- Log::info("Data MTRL Berhasil di Parse dan di simpan ", $resultSample->toArray());
+ //Log::info("Data MTRL Berhasil di Parse dan di simpan ", $resultSample->toArray());
return response()->json(['message' => 'Data berhasil diproses dan disimpan.']);
} else {
$headerData = explode("|", $astmData);
@@ -628,7 +628,7 @@ class AstmMessageService
$resultSample->additional_result = json_encode($resultData);
if ($noregister){
$resultSample->save();
- Log::info("Data ASTM Berhasil di Parse dan di simpan ", $resultSample->toArray());
+ //Log::info("Data ASTM Berhasil di Parse dan di simpan ", $resultSample->toArray());
return response()->json(['message' => 'Data berhasil diproses dan disimpan.']);
}
} else {
@@ -823,7 +823,7 @@ class AstmMessageService
]
);
}
- Log::info("Data BD ASTM Berhasil di Parse dan di simpan ", $resultSample->toArray());
+ //Log::info("Data BD ASTM Berhasil di Parse dan di simpan ", $resultSample->toArray());
return true;
@@ -838,7 +838,6 @@ class AstmMessageService
public function processAstmMessagesLokal($dataListener) {
foreach ($dataListener as $data) {
try {
- // Ambil pesan ASTM dari kolom 'message' atau yang relevan
$response = $data->rawdt;
if ($data->alat == 'MGIT' OR $data->alat == 'COM5' OR $data->alat == 'BACTEC'){
$assembled = $this->reassembleAstmFrames($data->rawdt);
diff --git a/htdocs/resources/views/cetak/ekspertisecci.blade.php b/htdocs/resources/views/cetak/ekspertisecci.blade.php
index fae1b4d4..97aee6f6 100644
--- a/htdocs/resources/views/cetak/ekspertisecci.blade.php
+++ b/htdocs/resources/views/cetak/ekspertisecci.blade.php
@@ -70,9 +70,9 @@
Tanggal Kirim Sample |
: |
{{ $periksa->daftar }} |
- |
- |
- |
+ Spesimen |
+ : |
+ {!! $periksa->nm_spesimen !!} |
diff --git a/htdocs/resources/views/cetak/ekspertisedefault.blade.php b/htdocs/resources/views/cetak/ekspertisedefault.blade.php
index 5bd77108..79aa72df 100644
--- a/htdocs/resources/views/cetak/ekspertisedefault.blade.php
+++ b/htdocs/resources/views/cetak/ekspertisedefault.blade.php
@@ -69,9 +69,9 @@
| Tanggal Kirim Sample |
: |
{{ $periksa->daftar }} |
- |
- |
- |
+ Spesimen |
+ : |
+ {!! $periksa->nm_spesimen !!} |
diff --git a/htdocs/resources/views/cetak/ekspertisekultur.blade.php b/htdocs/resources/views/cetak/ekspertisekultur.blade.php
index ad2fd365..63565771 100644
--- a/htdocs/resources/views/cetak/ekspertisekultur.blade.php
+++ b/htdocs/resources/views/cetak/ekspertisekultur.blade.php
@@ -87,9 +87,9 @@
| Tanggal Kirim Sample |
: |
{{ $periksa->daftar }} |
- |
- |
- |
+ Spesimen |
+ : |
+ {!! $periksa->nm_spesimen !!} |
diff --git a/htdocs/resources/views/cetak/ekspertisepl.blade.php b/htdocs/resources/views/cetak/ekspertisepl.blade.php
index d6612aae..e4eb90c3 100644
--- a/htdocs/resources/views/cetak/ekspertisepl.blade.php
+++ b/htdocs/resources/views/cetak/ekspertisepl.blade.php
@@ -69,9 +69,9 @@
| Tanggal Kirim Sample |
: |
{{ $periksa->daftar }} |
- |
- |
- |
+ Spesimen |
+ : |
+ {!! $periksa->nm_spesimen !!} |
diff --git a/htdocs/resources/views/cetak/ekspertisevl.blade.php b/htdocs/resources/views/cetak/ekspertisevl.blade.php
index a5322394..5339136e 100644
--- a/htdocs/resources/views/cetak/ekspertisevl.blade.php
+++ b/htdocs/resources/views/cetak/ekspertisevl.blade.php
@@ -85,9 +85,9 @@
| Tanggal Kirim Sample |
: |
{{ $periksa->daftar }} |
- |
- |
- |
+ Spesimen |
+ : |
+ {!! $periksa->nm_spesimen !!} |
diff --git a/htdocs/resources/views/cetak/igmiggletospira.blade.php b/htdocs/resources/views/cetak/igmiggletospira.blade.php
index 0e937934..bd0c4831 100644
--- a/htdocs/resources/views/cetak/igmiggletospira.blade.php
+++ b/htdocs/resources/views/cetak/igmiggletospira.blade.php
@@ -70,9 +70,9 @@
| Tanggal Kirim Sample |
: |
{{ $periksa->daftar }} |
- |
- |
- |
+ Spesimen |
+ : |
+ {!! $periksa->nm_spesimen !!} |
diff --git a/htdocs/resources/views/dokter/pemeriksaan.blade.php b/htdocs/resources/views/dokter/pemeriksaan.blade.php
index f412edd1..acaaa40e 100644
--- a/htdocs/resources/views/dokter/pemeriksaan.blade.php
+++ b/htdocs/resources/views/dokter/pemeriksaan.blade.php
@@ -1555,8 +1555,8 @@
@@ -1707,8 +1707,8 @@
diff --git a/htdocs/resources/views/dokter/ppds.blade.php b/htdocs/resources/views/dokter/ppds.blade.php
index d94a6f75..5787b05f 100644
--- a/htdocs/resources/views/dokter/ppds.blade.php
+++ b/htdocs/resources/views/dokter/ppds.blade.php
@@ -1610,8 +1610,8 @@
@@ -1762,8 +1762,8 @@
diff --git a/htdocs/resources/views/dokter/ppdsdeveloper.blade.php b/htdocs/resources/views/dokter/ppdsdeveloper.blade.php
index 32d090ff..a3da3ac1 100644
--- a/htdocs/resources/views/dokter/ppdsdeveloper.blade.php
+++ b/htdocs/resources/views/dokter/ppdsdeveloper.blade.php
@@ -1610,8 +1610,8 @@
@@ -1762,8 +1762,8 @@
diff --git a/listener/app.py b/listener/app.py
index 17bf1339..7034ee82 100644
--- a/listener/app.py
+++ b/listener/app.py
@@ -75,7 +75,7 @@ active_genexpert_connections = {}
connection_lock = threading.Lock()
DEVICE_CONFIGS = [
{
- 'port': 'COM6', 'baud_rate': 19200, 'device_type': 'vitek', 'alat_name': 'Vitek 1',
+ 'port': 'COM6', 'baud_rate': 9600, 'device_type': 'vitek', 'alat_name': 'Vitek 1',
'protocol': 'serial', 'flag_column': 'flg_vitek1'
},
{
@@ -133,7 +133,7 @@ class LisPhoenix(Base):
__tablename__ = 'lis_phoenix'
id = Column(Integer, primary_key=True)
no_id = Column(String(50)) # Patient ID
- seq_no = Column(String(50), unique=True) # Isolate ID / Sample ID
+ seq_no = Column(String(50)) # Isolate ID / Sample ID
rnmpas = Column(String(100)) # Patient Name
tgl_data = Column(SqDate)
rawdt = Column(Text)
@@ -145,7 +145,7 @@ class LisPhoenix(Base):
class LisPhoenixDtl(Base):
__tablename__ = 'lis_phoenix_dtl'
id = Column(Integer, primary_key=True)
- seq_no = Column(String(50), index=True) # Isolate ID / Sample ID
+ seq_no = Column(String(50)) # Isolate ID / Sample ID
kd_antibiotik = Column(String(50))
nm_antibiotik = Column(String(100))
keterangan = Column(String(50)) # MIC Value (e.g., <=0.5)
@@ -557,111 +557,121 @@ def calculate_vitek_checksum(data_str):
def parse_and_save_vitek_result(raw_data, port_name="VITEK"):
session = SessionLocal()
try:
- # --- LANGKAH 1: PEMBERSIHAN DATA ---
- # Vitek sering mengirim karakter framing \x1e (RS), \x1d (GS), \x03 (ETX)
- # Hapus framing characters dan newline
- clean_data = raw_data.replace('\x02', '').replace('\x03', '').replace('\x1e', '').replace('\r', '').replace('\n', '')
+ # --- 1. CLEANING DATA ---
+ # Hapus karakter kontrol STX(02), ETX(03), RS(1e/30), GS(1d/29), CR, LF
+ # Perhatikan: Log Anda menunjukkan RS () muncul di tengah kata, jadi harus dihapus total.
+ clean_data = raw_data.replace('\x02', '').replace('\x03', '').replace('\x1e', '').replace('\x1d', '').replace('\r', '').replace('\n', '')
- # Pisahkan jika ada checksum di akhir (biasanya setelah \x1d)
- if '\x1d' in clean_data:
- clean_data = clean_data.split('\x1d')[0]
-
- # --- LANGKAH 2: PARSING FIELD BERDASARKAN TAG ---
- # Format Vitek: tag|value|tag|value...
+ # Pisahkan field berdasarkan pipa '|'
fields = clean_data.split('|')
- msg_type = fields[0] # mtmpr (Order) atau mtrsl (Result)
+ # Cek apakah ini pesan result (mtrsl)
+ if not fields or fields[0] != 'mtrsl':
+ return # Abaikan jika bukan result
- # Inisialisasi variabel
- sample_id = None # ci (Accession Number)
- patient_id = "" # pi
+ # --- 2. VARIABLE INIT ---
+ sample_id = None # ci (No Lab / No Container)
+ patient_id = "" # pi (No RM)
patient_name = "" # pn
organism_name = "" # o2
- antibiotics = [] # List untuk menyimpan hasil AB
+ card_barcode = "" # is
+ antibiotics = [] # List penampung hasil AB
result_date = datetime.datetime.now()
- # Penanda apakah kita sedang membaca blok antibiotik
- current_ab_name = ""
- current_ab_mic = ""
- current_ab_int = ""
+ # Variabel sementara untuk looping antibiotik
+ curr_ab_name = ""
+ curr_ab_mic = ""
+ curr_ab_int = ""
- # Loop setiap field untuk mencari Tag
+ # --- 3. PARSING LOOP ---
for field in fields:
if not field: continue
# --- HEADER INFO ---
- if field.startswith("pi") and len(field) > 2: # Patient ID
- patient_id = field[2:].strip()
- elif field.startswith("pn") and len(field) > 2: # Patient Name
- patient_name = field[2:].strip()
- elif field.startswith("ci") and len(field) > 2: # Case ID / No Reg (KUNCI UTAMA)
- # Format Vitek kadang 25-035007, kita ambil angkanya saja atau sesuai format LIS
+ if field.startswith("ci") and len(field) > 2:
sample_id = field[2:].strip()
-
- # --- ORGANISME (Bakteri) ---
+ elif field.startswith("pi") and len(field) > 2:
+ patient_id = field[2:].strip()
+ elif field.startswith("pn") and len(field) > 2:
+ patient_name = field[2:].strip()
+ elif field.startswith("is") and len(field) > 2:
+ card_barcode = field[2:].strip()
+ # --- ORGANISME ---
elif field.startswith("o2") and len(field) > 2:
organism_name = field[2:].strip()
- # --- ANTIBIOTIK (Looping Block) ---
- # Penanda blok antibiotik baru dimulai dengan tag 'ra'
+ # --- ANTIBIOTIK BLOCK (Mulai Pesan Kedua) ---
+ # Tag 'ra' adalah pemisah antar obat
elif field == "ra":
- # Simpan antibiotik sebelumnya jika ada
- if current_ab_name:
- ab_str = f"{current_ab_name} {current_ab_mic} ({current_ab_int})"
+ # Jika ada data obat sebelumnya di memori, simpan dulu
+ if curr_ab_name:
+ ab_str = f"{curr_ab_name} {curr_ab_mic} ({curr_ab_int})"
antibiotics.append(ab_str)
- # Reset temp vars
- current_ab_name = ""
- current_ab_mic = ""
- current_ab_int = ""
+ # Reset untuk obat berikutnya
+ curr_ab_name = ""; curr_ab_mic = ""; curr_ab_int = ""
- # Detail Antibiotik
- elif field.startswith("a2") and len(field) > 2: # Nama Antibiotik
- current_ab_name = field[2:].strip()
- elif field.startswith("a3") and len(field) > 2: # Nilai MIC
- current_ab_mic = field[2:].strip()
- elif field.startswith("a4") and len(field) > 2: # Interpretasi (S/I/R)
- current_ab_int = field[2:].strip()
+ # Detail Obat
+ elif field.startswith("a2") and len(field) > 2: # Nama Obat (mis: Cefoxitin)
+ curr_ab_name = field[2:].strip()
+ elif field.startswith("a3") and len(field) > 2: # MIC (mis: >=4)
+ curr_ab_mic = field[2:].strip()
+ elif field.startswith("a4") and len(field) > 2: # Interpretasi (R/S/I)
+ curr_ab_int = field[2:].strip()
elif field.startswith("an") and len(field) > 2: # Interpretasi Alternatif
- if not current_ab_int: current_ab_int = field[2:].strip()
+ if not curr_ab_int: curr_ab_int = field[2:].strip()
- # Jangan lupa simpan antibiotik terakhir setelah loop selesai
- if current_ab_name:
- ab_str = f"{current_ab_name} {current_ab_mic} ({current_ab_int})"
- antibiotics.append(ab_str)
+ # Jangan lupa simpan obat terakhir yang tersisa di buffer
+ if curr_ab_name:
+ ab_str = f"{curr_ab_name} {curr_ab_mic} ({curr_ab_int})"
+ antibiotics.append(ab_str)
- # --- LANGKAH 3: FORMAT FINAL & SAVE ---
- # Kita hanya memproses jika tipe pesan adalah 'mtrsl' (Result) dan ada Sample ID
- if msg_type == 'mtrsl' and sample_id:
+ # --- 4. FORMAT FINAL STRING ---
+ # Format: "Staphylococcus hominis | Cefoxitin >=4 (R), Gentamicin 4 (S)..."
+ final_res_string = organism_name
+ #if antibiotics:
+ # final_res_string += " | " + ", ".join(antibiotics)
+
+ # Fallback jika negatif (biasanya tidak ada o2, tapi ada teks neg)
+ #if not final_res_string and "neg" in raw_data.lower():
+ # final_res_string = "NEGATIVE / NO GROWTH"
+
+ # --- 5. LOGIKA DATABASE (UPSERT: UPDATE or INSERT) ---
+ if sample_id:
+ # Cari data berdasarkan No Lab (Sample ID)
+ final_seq_no = card_barcode if card_barcode else patient_id
+ existing_data = session.query(LisPhoenix).filter(
+ LisPhoenix.seq_no == final_seq_no
+ ).first()
+
+ if existing_data:
+ # === SKENARIO PESAN KEDUA (UPDATE) ===
+ logging.info(f"[{port_name}] UPDATE Data (Tahap 2) -> ID: {sample_id}, Pasien: {patient_name}")
+ print(f"[{port_name}] UPDATE Data -> ID: {sample_id} (Hasil Lengkap)")
+ existing_data.rnmpas = patient_name
+ existing_data.organisme = final_res_string
+ existing_data.rawdt = raw_data
+ existing_data.tgl_data = result_date
+ existing_data.processed = None
+
+ else:
+ # === SKENARIO PESAN PERTAMA (INSERT) ===
+ logging.info(f"[{port_name}] INSERT Data Baru (Tahap 1) -> ID: {sample_id}, Pasien: {patient_name}")
+ print(f"[{port_name}] INSERT Data -> ID: {sample_id} (Identifikasi Awal)")
+
+ new_entry = LisPhoenix(
+ no_id=sample_id,
+ seq_no=final_seq_no,
+ rnmpas=patient_name,
+ tgl_data=result_date,
+ rawdt=raw_data,
+ organisme=final_res_string,
+ alat=port_name
+ )
+ session.add(new_entry)
- # Gabungkan hasil: Organisme | AB1, AB2, AB3...
- final_res_string = organism_name
- if antibiotics:
- final_res_string += " | " + ", ".join(antibiotics)
-
- # Jika tidak ada organisme tapi tipe result, mungkin Negative?
- if not final_res_string and "neg" in raw_data.lower():
- final_res_string = "NEGATIVE / NO GROWTH"
-
- logging.info(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Bakteri: {organism_name}")
- print(f"[{port_name}] Save DB -> ID: {sample_id}, Pasien: {patient_name}, Bakteri: {organism_name}")
- new_entry = LisPhoenix(
- no_id=sample_id, # Menggunakan tag 'ci'
- seq_no=patient_id, # Menggunakan tag 'pi'
- rnmpas=patient_name, # Menggunakan tag 'pn'
- tgl_data=result_date,
- rawdt=raw_data,
- organisme=final_res_string, # Hasil gabungan
- alat=port_name
- )
- session.add(new_entry)
session.commit()
else:
- if msg_type != 'mtrsl':
- logging.info(f"[{port_name}] Mengabaikan pesan tipe {msg_type}")
- print(f"[{port_name}] Mengabaikan pesan tipe {msg_type}")
- else:
- logging.warning(f"[{port_name}] Data tidak lengkap (No Sample ID). Raw: {raw_data[:50]}...")
- print(f"[{port_name}] Data tidak lengkap (No Sample ID). Raw: {raw_data[:50]}...")
+ logging.warning(f"[{port_name}] Pesan diabaikan (Tanpa Sample ID): {clean_data[:30]}...")
except Exception as e:
logging.error(f"Error Parsing Vitek: {e}")
@@ -669,7 +679,6 @@ def parse_and_save_vitek_result(raw_data, port_name="VITEK"):
session.rollback()
finally:
session.close()
-
def create_vitek_order_message(order):
"""
Membuat Frame Order Vitek sesuai Manual Ref 514937.