Align target deadlines in early warning and reports

This commit is contained in:
Dwi Swandhana
2026-04-29 09:55:00 +07:00
parent bb680d41d3
commit d8c6ab7b55
10 changed files with 237 additions and 6909 deletions
@@ -35,7 +35,7 @@ use App\RekapAntibiotik;
use App\PendaftaranOnListiner;
use App\CriticalValueSample;
use App\Paslab;
use App\SIMBHPReport;
use Carbon\Carbon;
use Aranyasen\HL7\Message;
use Aranyasen\HL7\Connection;
@@ -1941,6 +1941,40 @@ class DokterController extends Controller
'created_by' => Session('nama'),
]);
}
$media = $request->input('komponen') ?? '';
$status = $request->input('status') ?? '';
if ($media == 'Media BAP'){
$mediatanam = 'BAPPLATE';
} else if ($media == 'Media CAP'){
$mediatanam = 'CAPPLATE';
} else if ($media == 'Media Mc Conkey'){
$mediatanam = 'MCPLATE';
} else if ($media == 'Media SDA R1' OR $media == 'Media SDA R2' OR $media == 'Media SDA I1' OR $media == 'Media SDA I2'){
$mediatanam = 'SDAPLATE';
} else {
$mediatanam = '';
}
if ($mediatanam != '' AND $status == 'Sub Kultur'){
$tanggal= date("d-m-Y");
$ahrf = explode("-", $tanggal);
$tahun = $ahrf[0];
if(isset($ahrf[1])){ $wulan = (int)$ahrf[1]; } else { $wulan = (int)date("m"); }
if(isset($ahrf[2])){ $dino = (int)$ahrf[2]; } else { $dino = (int)date("d"); }
$datapemeriksaan = Periksa::where('id', $nofoto)->first();
SIMBHPReport::create([
'tanggal' => $dino,
'bulan' => $wulan,
'tahun' => $tahun,
'deskripsi' => $status.' Nomor Lab.'.$datapemeriksaan->nofoto ?? ''.' petugas '.Session('nama'),
'pemasukan' => null,
'pengeluaran' => 1,
'qty_base' => 1,
'satuan_transaksi' => 'besar',
'jenis' => $mediatanam,
'keterangan' => '',
'marking' => '',
]);
}
Periksa::where('id', $idperiksa)->update([
'status' => $request->input('komponen') ?? ''.' '.$request->input('status') ?? '',
]);
@@ -2664,6 +2698,7 @@ class DokterController extends Controller
public function periksa(Request $request) {
$nofoto = $request->input('nofoto');
$id = $request->input('id');
$mediatanams = $request->input('mediatanam');
$nama = Session('nama');
$idpemeriksa = Session('id');
if ($id == 'ubahnomorlab'){
@@ -2714,38 +2749,64 @@ class DokterController extends Controller
$statuse = $jpoli->status ?? '';
$noregister = $jpoli->noregister;
$daftar = $jpoli->daftar;
$arrnofoto = explode('-', $nofoto);
$nofoto = $arrnofoto[0];
if ($statuse == 'Pemeriksaan awal' OR $statuse == 'Penerimaan Sampel'){
Periksa::where('id', $id)->update([
'status' => 'Pemeriksaan Sampel',
'tgldraft' => date('Y-m-d H:i:s'),
'excutor' => $idpemeriksa,
'nmppdsmiddle2' => Session('nama')
]);
return response()->json(['icon' => 'success', 'warna' => '#5ba035', 'status' => 'Success', 'message' => 'Status Updated']);
return back();
} else if ($statuse == 'Pemeriksaan Sampel'){
Periksa::where('id', $id)->update([
'status' => 'Pemeriksaan awal',
'tgldraft' => date('Y-m-d H:i:s'),
'excutor' => $idpemeriksa,
'nmppdsmiddle2' => Session('nama')
]);
return response()->json(['icon' => 'success', 'warna' => '#5ba035', 'status' => 'Success', 'message' => 'Status Updated']);
return back();
} else {
Periksa::where('id', $id)->whereNull('status')->update([
'status' => 'Pemeriksaan awal',
'tgldraft' => date('Y-m-d H:i:s'),
'status' => 'Penerimaan Sampel',
'daftar' => date('Y-m-d H:i:s'),
'mulai' => date('Y-m-d H:i:s'),
'excutor' => $idpemeriksa,
'nmppdsmiddle2' => Session('nama')
]);
return response()->json(['icon' => 'success', 'warna' => '#5ba035', 'status' => 'Success', 'message' => 'Status Updated']);
return back();
}
if ($mediatanams == null OR $mediatanams == ''){
} else {
foreach($mediatanams as $media){
if ($media == 'Media BAP'){
$mediatanam = 'BAPPLATE';
} else if ($media == 'Media CAP'){
$mediatanam = 'CAPPLATE';
} else if ($media == 'Media Mc Conkey'){
$mediatanam = 'MCPLATE';
} else if ($media == 'Media SDA R1' OR $media == 'Media SDA R2' OR $media == 'Media SDA I1' OR $media == 'Media SDA I2'){
$mediatanam = 'SDAPLATE';
} else {
$mediatanam = '';
}
if ($mediatanam != ''){
$tanggal= date("Y-m-d");
$ahrf = explode("-", $tanggal);
$tahun = $ahrf[0];
if(isset($ahrf[1])){ $wulan = (int)$ahrf[1]; } else { $wulan = (int)date("m"); }
if(isset($ahrf[2])){ $dino = (int)$ahrf[2]; } else { $dino = (int)date("d"); }
$datapemeriksaan = Periksa::where('id', $id)->first();
SIMBHPReport::create([
'tanggal' => $dino,
'bulan' => $wulan,
'tahun' => $tahun,
'deskripsi' => 'Pemeriksaan Awal '.' Nomor Lab.'.$datapemeriksaan->nofoto.' petugas '.Session('nama'),
'pemasukan' => null,
'pengeluaran' => 1,
'qty_base' => 1,
'satuan_transaksi' => 'besar',
'jenis' => $mediatanam,
'keterangan' => '',
'marking' => '',
]);
}
}
}
return response()->json(['icon' => 'success', 'warna' => '#5ba035', 'status' => 'Success', 'message' => 'Status Updated']);
return back();
}
}
public function getFoto(Request $request) {
@@ -3690,6 +3751,7 @@ class DokterController extends Controller
'status' => 'Penerimaan Sampel',
'nmppdsjunior2' => Session('nama'),
'mulai' => date('Y-m-d H:i:s'),
'daftar' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d').' 00:00:00',
]);
if ($kanan == ''){
@@ -36,6 +36,16 @@ use Carbon\Carbon;
class FrontpageController extends Controller
{
protected function resolveTargetDays($modaliti2)
{
return (!empty($modaliti2) && is_numeric($modaliti2) && intval($modaliti2) > 0)
? intval($modaliti2)
: 1;
}
protected function getTargetDeadline(Carbon $startAt, $targetDays)
{
return $startAt->copy()->addDays(intval($targetDays))->endOfDay();
}
protected function buildMikroViewData($master, array $extra = [])
{
$data = [
@@ -236,16 +246,15 @@ class FrontpageController extends Controller
$earlyWarnings = [];
foreach ($rawEarlyWarnings as $row) {
$targetDays = 1;
if (!empty($row->modaliti2) && is_numeric($row->modaliti2) && intval($row->modaliti2) > 0) {
$targetDays = intval($row->modaliti2);
}
$targetDays = $this->resolveTargetDays($row->modaliti2);
$waktuDaftar = Carbon::parse($row->daftar);
$targetSelesai = $waktuDaftar->copy()->addDays($targetDays);
$targetSelesai = $this->getTargetDeadline($waktuDaftar, $targetDays);
$sisaMenit = $now->diffInMinutes($targetSelesai, false);
$batasWarningMenit = $targetDays > 1 ? 1440 : 60;
$isMelewatiTarget = $now->gt($targetSelesai);
if ($sisaMenit <= 60) {
if ($isMelewatiTarget || $sisaMenit <= $batasWarningMenit) {
$earlyWarnings[] = [
'id' => $row->id,
'mikro_master' => $this->resolveMikroMasterFromPoliId($row->poli_id),
@@ -260,7 +269,7 @@ class FrontpageController extends Controller
'target_hari' => $targetDays,
'target_selesai' => $targetSelesai->format('Y-m-d H:i:s'),
'sisa_menit' => $sisaMenit,
'warning_label' => $sisaMenit <= 0 ? 'Melewati Target' : 'Kurang dari 1 Jam'
'warning_label' => $isMelewatiTarget ? 'Melewati Target' : ($targetDays > 1 ? 'Kurang dari 1 Hari' : 'Kurang dari 1 Jam')
];
}
}
@@ -733,9 +733,6 @@ class ListController extends Controller
<div class="btn-group-vertical mb-2">
<button type="button" class="btn btn-sm btn-outline-primary waves-effect" onClick="btnMarking('.$row->id.')">
<i class="me-50 fa fa-flag"></i>
</button>
<button type="button" class="btn btn-sm btn-outline-danger waves-effect" onClick="btnOpenEditor('.$row->id.')">
<i class="me-50 fa fa-pencil"></i> Khusus Penomoran TB
</button>
</div>';
})
@@ -323,6 +323,23 @@ class ReportController extends Controller
'Amphotericin B',
'Flucytosine'
];
private function resolveTatTargetDays($modaliti2) {
return (!empty($modaliti2) && is_numeric($modaliti2) && intval($modaliti2) > 0)
? intval($modaliti2)
: 1;
}
private function getTatDeadlineDate($mulai, $targetDays) {
return Carbon::parse($mulai)->addDays(intval($targetDays))->toDateString();
}
private function getTatElapsedDays($mulai, $verifikasi) {
return Carbon::parse($mulai)->startOfDay()->diffInDays(Carbon::parse($verifikasi)->startOfDay());
}
private function resolveTatStatus($mulai, $verifikasi, $targetDays) {
$deadlineDate = $this->getTatDeadlineDate($mulai, $targetDays);
return Carbon::parse($verifikasi)->toDateString() <= $deadlineDate
? 'MEMENUHI TARGET'
: 'TIDAK MEMENUHI TARGET';
}
public function report(Request $request) {
$bulan = $request->input('bulan');
$tahun = $request->input('tahun');
@@ -455,15 +472,13 @@ class ReportController extends Controller
$p = $poli[$row->poli_id] ?? null;
$row->subpoli = $p->subpoli ?? null;
$row->modaliti2 = $p->modaliti2 ?? '1';
$row->modaliti2 = $this->resolveTatTargetDays($p->modaliti2 ?? '1');
// Hitung status target
if (!empty($row->verifikasi)) {
$selisih = Carbon::parse($row->mulai)->diffInDays($row->verifikasi);
$selisih = $this->getTatElapsedDays($row->mulai, $row->verifikasi);
$row->selisih_hari = $selisih;
$row->status_target = ($selisih <= intval($row->modaliti2))
? "MEMENUHI TARGET"
: "TIDAK MEMENUHI TARGET";
$row->status_target = $this->resolveTatStatus($row->mulai, $row->verifikasi, $row->modaliti2);
} else {
$row->selisih_hari = null;
$row->status_target = "TIDAK ADA HASIL";
+16 -13
View File
@@ -19,21 +19,24 @@ class UserController extends Controller
if (Session::get('previlage') == ''){
return redirect('/login');
} else {
if ($cekkelompok == 'supervisor' OR $cekkelompok == 'admin' OR $cekkelompok == 'developer'){
$users = User::all();
if ($cekkelompok == 'supervisor' OR $cekkelompok == 'developer'){
$getsetting = Setting::where('id', '1')->first();
$data = [];
$data['users'] = User::orderBy('nama', 'ASC')->get();
$data['pacsaddr'] = $getsetting->pacs ?? '';
$data['zfpaddr'] = $getsetting->zfp ?? '';
$data['port'] = $getsetting->port ?? '';
$data['portzfp'] = $getsetting->portzfp ?? '';
$data['username'] = $getsetting->username ?? '';
$data['password'] = $getsetting->password ?? '';
return view('admin.user', $data);
} else {
$users = User::where('previlage', $cekkelompok)->get();
$data = [];
$data['kalimatheader'] = 'Access Denied';
$data['kalimatbody'] = 'Laman khusus SPV';
return view('errors.error', $data);
}
$getsetting = Setting::where('id', '1')->first();
$data = [];
$data['users'] = $users;
$data['pacsaddr'] = $getsetting->pacs ?? '';
$data['zfpaddr'] = $getsetting->zfp ?? '';
$data['port'] = $getsetting->port ?? '';
$data['portzfp'] = $getsetting->portzfp ?? '';
$data['username'] = $getsetting->username ?? '';
$data['password'] = $getsetting->password ?? '';
return view('admin.user', $data);
}
}
public function exSetting(Request $request) {
+31 -20
View File
@@ -672,15 +672,15 @@
@push('script')
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<script type="text/javascript">
$(function () {
$("#in_tanggal").datepicker({format: 'yyyy-mm-dd'});
$("#out_tanggal").datepicker({format: 'yyyy-mm-dd'});
$("#edit_tanggal").datepicker({format: 'yyyy-mm-dd'});
$("#op_in_tanggal").datepicker({format: 'yyyy-mm-dd'});
$("#in_masa_expired").datepicker({format: 'dd-mm-yyyy'});
$("#op_in_masa_expired").datepicker({format: 'dd-mm-yyyy'});
$("#edit_masa_expired").datepicker({format: 'dd-mm-yyyy'});
});
$(function () {
$("#in_tanggal").datepicker({format: 'yyyy-mm-dd'});
$("#out_tanggal").datepicker({format: 'yyyy-mm-dd'});
$("#edit_tanggal").datepicker({format: 'yyyy-mm-dd'});
$("#op_in_tanggal").datepicker({format: 'yyyy-mm-dd'});
$("#in_masa_expired").datepicker({format: 'dd-mm-yyyy'});
$("#op_in_masa_expired").datepicker({format: 'dd-mm-yyyy'});
$("#edit_masa_expired").datepicker({format: 'dd-mm-yyyy'});
});
function openedpage( jQuery ){
var set01=document.getElementById('cekbln').value;
var set02=document.getElementById('cekthn').value;
@@ -732,17 +732,28 @@
editrow = row;
var offset = $("#gridreportblnini").offset();
var dataRecord = $("#gridreportblnini").jqxGrid('getrowdata', editrow);
var tanggal = dataRecord.tanggal;
var bulan = dataRecord.bulan;
var tahun = dataRecord.tahun;
var tulis = tahun+'-'+bulan+'-'+tanggal;
$("#edit_deskripsi").val(dataRecord.deskripsi);
$("#edit_id").val(dataRecord.id);
$("#edit_pos").val(dataRecord.jenis);
$("#edit_total").val(dataRecord.total);
$("#edit_tanggal").val(tulis);
$("#edit_masa_expired").val(dataRecord.masa_expired || '');
$("#modaleditor").modal('show');
var previlage = "{{ Session::get('previlage') }}";
if (previlage == 'developer' && previlage == 'supervisor') {
var tanggal = dataRecord.tanggal;
var bulan = dataRecord.bulan;
var tahun = dataRecord.tahun;
var tulis = tahun+'-'+bulan+'-'+tanggal;
$("#edit_deskripsi").val(dataRecord.deskripsi);
$("#edit_id").val(dataRecord.id);
$("#edit_pos").val(dataRecord.jenis);
$("#edit_total").val(dataRecord.total);
$("#edit_tanggal").val(tulis);
$("#edit_masa_expired").val(dataRecord.masa_expired || '');
$("#modaleditor").modal('show');
} else {
swal({
title: 'Akses Ditolak',
text: 'Anda tidak memiliki izin untuk mengedit data.',
icon: 'error',
confirmButtonText: 'OK'
});
}
}
},
],
@@ -203,6 +203,7 @@
<li><a href="/user">User Management</a></li>
</ul>
</li>
<li><a href="/gudang"><i class="fa fa-home"></i>Gudang</a></li>
@elseif(Session::get('previlage') == 'analis')
<li><a href="/modemobile"><i class="fa fa-h-square"></i></a></li>
<li><a href="/penerimaansample"><i class="fa fa-flask"></i></a></li>
@@ -237,6 +238,7 @@
<li><a href="/template"><i class="fa fa-medkit"></i>Database</a></li>
</ul>
</li>
<li><a href="/gudang"><i class="fa fa-home"></i>Gudang</a></li>
@elseif(Session::get('previlage') == 'admin')
<li><a href="/pendaftaran"><i class="fa fa-h-square"></i>Pendaftaran</a></li>
<li><a href="/pengambilan"><i class="fa fa-stethoscope"></i>Pengambilan</a></li>
File diff suppressed because it is too large Load Diff
@@ -104,6 +104,20 @@
</div>
<div class="modal-body">
<form class="form-horizontal">
<div class="form-group col-lg-12">
<label for="id_mediatanam" class="col-form-label">Media Tanam Yang di gunakan <font color="red">*</font></label>
<select class="form-control select2" id="id_mediatanam" name="id_mediatanam[]" style="width: 100%;" multiple="multiple">
<option value="">Bisa memilih lebih dari satu</option>
<option value="Media BAP">Media BAP</option>
<option value="Media CAP">Media CAP</option>
<option value="Media Mc Conkey">Media Mc Conkey</option>
<option value="Media SDA R1">Media SDA R1</option>
<option value="Media SDA R2">Media SDA R2</option>
<option value="Media SDA I1">Media SDA I1</option>
<option value="Media SDA I2">Media SDA I2</option>
</select>
</div>
<p class="text-muted">Khusus Yang Akan di kirim ke BD MGIT</p>
<div class="form-group col-lg-12">
<label for="id_jenis" class="col-form-label">Jenis Pengobatan Terduga/Pasien TBC</label>
<select class="form-control ekspertiseseletc" id="id_jenis" name="id_jenis">
@@ -164,11 +178,17 @@
timer = setInterval(showRemaining, 1000);
}
function btnMarking(id){
$.post('{{ route("markPeriksa") }}', { id: id, _token: '{{ csrf_token() }}'},function(data){
$('#gridkiriman').DataTable().ajax.reload();
});
//$.post('{{ route("markPeriksa") }}', { id: id, _token: '{{ csrf_token() }}'},function(data){
// $('#gridkiriman').DataTable().ajax.reload();
//});
$('.select2').val([]).select2().trigger('change');
$('#id_sample_edit').val(id);
$('#id_jenis').val('');
$('#id_bulan').val('');
$('#modaleditor').modal('show');
}
function btnOpenEditor(id){
$('.select2').val([]).select2().trigger('change');
$('#id_sample_edit').val(id);
$('#id_jenis').val('');
$('#id_bulan').val('');
@@ -212,6 +232,7 @@
}
$(document).ready(function () {
$('.select2').select2();
$("#tglreport").datepicker({format: 'yyyy-mm-dd'});
$("#mulai").datepicker({format: 'yyyy-mm-dd'});
$("#akhir").datepicker({format: 'yyyy-mm-dd'});
@@ -234,24 +255,33 @@
}
});
$("#btnSaveEditor").click(function() {
var jenis=document.getElementById('id_jenis').value;
var bulan=document.getElementById('id_bulan').value;
var sampleId=document.getElementById('id_sample_edit').value;
if (jenis != 'F' && bulan == ''){
$("#err_text").val('Jika Jenis Pengobatan Terduga/Pasien TBC bukan Follow Up, maka Bulan Ke harus diisi');
$("#modalerror").modal('show');
} else {
$.post('{{ route("markPeriksa") }}', { id: 'ubahnomorlab', jenis: jenis, bulan: bulan, sampleId: sampleId, _token: '{{ csrf_token() }}'},function(data){
var jenis = document.getElementById('id_jenis').value;
var bulan = document.getElementById('id_bulan').value;
var sampleId = document.getElementById('id_sample_edit').value;
var mediatanam = $('#id_mediatanam').val();
if (jenis == ''){
$('#modaleditor').modal('hide');
$.post('{{ route("markPeriksa") }}', { id: sampleId, mediatanam: mediatanam, _token: '{{ csrf_token() }}'},function(data){
$('#gridkiriman').DataTable().ajax.reload();
swal({
title: data.status || 'Sukses',
text: data.message || 'Data berhasil diperbarui.',
type: 'success',
}).then(function () {
$('#modaleditor').modal('hide');
});
});
} else {
if (jenis != 'F' && bulan == ''){
$("#err_text").val('Jika Jenis Pengobatan Terduga/Pasien TBC bukan Follow Up, maka Bulan Ke harus diisi');
$("#modalerror").modal('show');
} else {
$.post('{{ route("markPeriksa") }}', { id: 'ubahnomorlab', jenis: jenis, bulan: bulan, sampleId: sampleId, mediatanam: mediatanam, _token: '{{ csrf_token() }}'},function(data){
$('#gridkiriman').DataTable().ajax.reload();
swal({
title: data.status || 'Sukses',
text: data.message || 'Data berhasil diperbarui.',
type: 'success',
}).then(function () {
$('#modaleditor').modal('hide');
});
});
}
}
});
$("#btnpencarian").click(function() {
var set01=document.getElementById('valcari').value;
+25
View File
@@ -604,6 +604,10 @@ def send_genexpert_transport_ack(conn, ip_addr, framing, reason="frame-received"
except Exception as exc:
print(f"[GENEXPERT-DEBUG] Transport ACK gagal ip={ip_addr}, framing={framing}, reason={reason}, error={exc}")
def log_genexpert_handshake(ip_addr, event, detail=""):
suffix = f", detail={detail}" if detail else ""
print(f"[GENEXPERT-HANDSHAKE] ip={ip_addr}, event={event}{suffix}")
def debug_genexpert_order_message(hl7_message, ip_addr=None):
segments = parse_hl7_segments(hl7_message)
current_pid = ""
@@ -2095,12 +2099,20 @@ def handle_genexpert_client(conn, addr):
break
buffer += data
if b"\x02" in data:
log_genexpert_handshake(addr[0], "STX-RX", detail=f"bytes={len(data)}")
if b"\x03" in data:
log_genexpert_handshake(addr[0], "ETX-RX", detail=f"bytes={len(data)}")
if b"\x04" in data:
log_genexpert_handshake(addr[0], "EOT-RX", detail=f"bytes={len(data)}")
# --- 1. HANDLE HANDSHAKE (ENQ) ---
# Jika alat kirim ENQ (\x05/♣), langsung balas ACK (\x06)
if b'\x05' in buffer:
# logging.info(f"[TCP] Terima ENQ dari {addr}, kirim ACK.")
log_genexpert_handshake(addr[0], "ENQ-RX", detail=f"buffer_len={len(buffer)}")
conn.sendall(b'\x06')
log_genexpert_handshake(addr[0], "ACK-TX", detail="reason=enq")
# Hapus ENQ dari buffer agar tidak mengganggu
buffer = buffer.replace(b'\x05', b'')
@@ -2135,6 +2147,11 @@ def handle_genexpert_client(conn, addr):
full_message_bytes = buffer[:end_marker_pos]
response_framing = detect_genexpert_message_framing(full_message_bytes)
log_genexpert_handshake(
addr[0],
"FRAME-COMPLETE",
detail=f"framing={response_framing}, frame_len={len(full_message_bytes)}"
)
send_genexpert_transport_ack(
conn,
@@ -2228,6 +2245,14 @@ def handle_genexpert_client(conn, addr):
else:
# Jika pesan lengkap tapi tidak ada MSH (misal cuma EOT doang)
pass
else:
if buffer:
head_hex = buffer[:12].hex()
log_genexpert_handshake(
addr[0],
"BUFFER-WAIT",
detail=f"buffer_len={len(buffer)}, head_hex={head_hex}"
)
except ConnectionResetError:
logging.warning(f"[GenExpert_TCP] Connection reset by peer: {addr}")