Files
lis/htdocs/app/Http/Controllers/ReportController.php
T
2026-04-20 09:50:38 +07:00

1350 lines
42 KiB
PHP

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Poli;
use App\Logbook;
use App\User;
use App\Periksa;
use App\Dokter;
use App\Pasien;
use App\Jadwalperiksa;
use App\Riwayat;
use App\RekapAntibiotik;
use App\Organisms;
use App\RekapPenerimaanSamplePrintHistory;
use DateTime;
use Carbon\Carbon;
use Session;
use Symfony\Component\HttpFoundation\StreamedResponse;
class ReportController extends Controller
{
public function index() {
if (Session::get('previlage') == ''){
return redirect('/login');
} else {
$dokterOptions = Periksa::select('dokter_id', 'nmdokter')
->whereNotNull('dokter_id')
->where('dokter_id', '<>', 0)
->whereNotNull('nmdokter')
->where('nmdokter', '<>', '')
->groupBy('dokter_id', 'nmdokter')
->orderBy('nmdokter', 'ASC')
->get();
return view('admin.report', [
'dokterOptions' => $dokterOptions
]);
}
}
public function rekapPeriksa(Request $request) {
set_time_limit(0);
$bulan = $request->input('bulan');
$tahun = $request->input('tahun');
if ($bulan == 'ALL' OR $bulan == 'Pick Month') {
$orderbydate = Periksa::selectRaw('SUM(id) as jumlah, DATE(daftar) as day')->whereYear('daftar', $tahun)->groupBy(DB::raw('daftar'))->orderBy('daftar', 'ASC')->get();
$bulan = '';
} else {
$tglcari = $tahun . '-' . str_pad($bulan, 2, '0', STR_PAD_LEFT);
$orderbydate = Periksa::selectRaw('SUM(id) as jumlah, DATE(daftar) as day')->where('day', 'LIKE', '%' . $tglcari . '%')->groupBy(DB::raw('daftar'))->orderBy('daftar', 'ASC')->get();
$bulanNames = [
'01' => 'BULAN JANUARI',
'02' => 'BULAN FEBRUARI',
'03' => 'BULAN MARET',
'04' => 'BULAN APRIL',
'05' => 'BULAN MEI',
'06' => 'BULAN JUNI',
'07' => 'BULAN JULI',
'08' => 'BULAN AGUSTUS',
'09' => 'BULAN SEPTEMBER',
'10' => 'BULAN OKTOBER',
'11' => 'BULAN NOVEMBER',
'12' => 'BULAN DESEMBER',
];
$bulan = $bulanNames[$bulan] ?? $bulan;
}
$data = [];
$data['bulan'] = $bulan;
$data['tahun'] = $tahun;
$data['orderbydate']= $orderbydate;
$generatetabel = view('cetak.rekap_periksa_table', $data)->render();
echo $generatetabel;
}
protected static function getPasienData($result) {
return [
'nama' => $result->nmpasien,
'tgl' => $result->tgllahirpasien,
'jk' => $result->jkpasien,
];
}
protected static function updateTotals($totals, $asuransi, $urgensi, $jk) {
if ($jk == 'L') {
$totals['m']++;
} else {
$totals['f']++;
}
if ($asuransi == 'JKN') {
$totals['jkn']++;
} elseif ($asuransi == 'Umum') {
$totals['umum']++;
} elseif ($asuransi == 'TAG') {
$totals['tag']++;
} elseif ($asuransi == 'GCU') {
$totals['gcu']++;
} elseif ($asuransi == 'Billing') {
$totals['bill']++;
} else {
$totals['swasta']++;
}
if ($urgensi == 'Elective') {
$totals['electiv']++;
} else {
$totals['cito']++;
}
return $totals;
}
protected static function mapResultToArray($result) {
$nmpasien = $result->nmpasien;
$tgl = $result->tgllahirpasien;
$jk = $result->jkpasien;
$jenis = $result->reques;
$tlppasien = $result->tlppasien;
$nofoto = $result->nofoto;
$verifikasi = $result->verifikasi;
$tanggal = $result->daftar;
$tanggalfoto = $result->foto;
$asuransi = $result->asuransi;
$urgensi = $result->urgensi;
$from = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $result->daftar);
if (is_null($verifikasi)){
$verifikasi = '';
$to = '';
$durasi = 'On Progress';
} else {
$to = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $verifikasi);
$durasi = $to->diffForHumans($from);
}
$arrayttllhr = explode("-", $tgl);
if (isset($arrayttllhr[2])){
$yy = $arrayttllhr[0];
$mm = $arrayttllhr[1];
$dd = $arrayttllhr[2];
$tgllahir = $dd.'-'.$mm.'-'.$yy;
} else { $tgllahir = $tgl; }
$arrayttl = explode(" ", $tanggal);
$tanggal = $arrayttl[0];
if ($jk == 'L') {
$l = '1';
$p = '';
} else {
$l = '';
$p = '1';
}
if ($asuransi == 'JKN') {
$jkn = '1';
$umm = '';
$swasta = '';
$gcu = '';
$tag = '';
$bill = '';
} else if ($asuransi == 'Umum') {
$jkn = '';
$umm = '1';
$swasta = '';
$gcu = '';
$tag = '';
$bill = '';
} else if ($asuransi == 'TAG') {
$jkn = '';
$umm = '';
$swasta = '';
$gcu = '';
$bill = '';
$tag = '1';
} else if ($asuransi == 'GCU') {
$jkn = '';
$umm = '';
$swasta = '';
$gcu = '1';
$tag = '';
$bill = '';
} else if ($asuransi == 'Billing') {
$jkn = '';
$umm = '';
$swasta = '';
$gcu = '';
$bill = '1';
$tag = '';
} else {
$jkn = '';
$umm = '';
$swasta = '1';
$gcu = '';
$tag = '';
$bill = '';
}
if ($urgensi == 'Elective') {
$ele = '1';
$cito = '';
} else {
$ele = '';
$cito = '1';
}
$getjennofoto = explode("-", $nofoto);
$jenis = $getjennofoto[0].' '.$jenis;
return [
'id' => $result->id,
'filefoto' => '<a href="' . url('/') . '/hasil/' . $result->nofoto . '" target="_blank">' . $result->nofoto . '</a>',
'l' => $l,
'p' => $p,
'jenis' => $jenis,
'jkn' => $jkn,
'umm' => $umm,
'gcu' => $gcu,
'tag' => $tag,
'swasta' => $swasta,
'billing' => $bill,
'ele' => $ele,
'cito' => $cito,
'asuransi' => $asuransi,
'nofoto' => $result->nofoto,
'noregister' => $result->noregister,
'nmpasien' => $nmpasien,
'usia' => $result->usia,
'kesimpulan' => $result->kesimpulan,
'ruangan' => $result->ruangan,
'daftar' => $result->daftar,
'created_at' => $result->created_at,
'nmdokter' => $result->nmdokter,
'nmppdssenior' => $result->nmppdssenior,
'nmmiddleppds' => $result->nmmiddleppds,
'nmppdsjunior' => $result->nmppdsjunior,
'nmppdsmiddle2' => $result->nmppdsmiddle2,
'nmppdsjunior2' => $result->nmppdsjunior2,
'diagnosa2' => $result->diagnosa2,
'nmanalis' => $result->nmanalis,
'nmexcutor' => $result->nmexcutor,
'alamatpasien' => $result->alamatpasien,
'tgllahirpasien'=> $tgl,
'jkpasien' => $jk,
'tlppasien' => $tlppasien,
'modality' => $result->modality,
'dlp' => $result->dlp,
'kd_spesimen' => $result->kd_spesimen,
'nm_spesimen' => $result->nm_spesimen,
'status' => $result->status,
'asalpasien' => $result->asalpasien,
'nmrs' => $result->nmrs,
'berat' => $result->berat,
'klinisi' => $result->klinisi,
'klinis' => $result->klinis,
'telpon' => $tlppasien,
'verifikasi' => $result->verifikasi,
'noloket' => $result->noloket,
'foto' => $result->foto,
'export' => $result->export,
'nmdrafter' => $result->nmdrafter,
'tgldraft' => $result->tgldraft,
'baca' => $result->baca,
'nmpembaca' => $result->nmpembaca,
'tgladendum' => $result->tgladendum,
'nmadendum' => $result->nmadendum,
'durasi' => $durasi,
];
}
protected static function getTotalRow($totals) {
return [
'id' => '',
'filefoto' => '',
'noregister'=> '',
'nama' => '<strong>Total</strong>',
'l' => $totals['m'],
'p' => $totals['f'],
'jkn' => $totals['jkn'],
'umm' => $totals['umum'],
'gcu' => $totals['gcu'],
'tag' => $totals['tag'],
'swasta' => $totals['swasta'],
'billing' => $totals['bill'],
'ele' => $totals['electiv'],
'cito' => $totals['cito'],
];
}
private $listAntibiotik = [
'Oxacillin-OX',
'Cefoxitin-FOX',
'Benzylpenicillin-P',
'Ampicillin-AM',
'Azithromycin-AZM',
'Erythromycin-ERY',
'Cefazolin-CZO',
'Cefepime-FEP',
'Cefixime-CFM',
'Cefotaxime-CTX',
'Cefuroxime-CXM',
'Ceftazidime-CAZ',
'Ceftriaxone-CRO',
'Ceftazidime/Avibactam-CZA',
'Piperacilin/Tazobactam-TZP',
'Ampicillin/Sulbactam-SAM',
'Amoxicillin/Clavulanate-AMC',
'Cefoperazon/Sulbactam-SCF',
'Aztreonam-ATM',
'Ceftaroline-CPT',
'Ciprofloxacin-CIP',
'Levofloxacin-LEV',
'Moxifloxacin-MFX',
'Clindamycin-CLI',
'Colistin-CS',
'Tetracyclin-TCY',
'Tigecycline-TGC',
'Gentamicin-GM',
'Amikacin-AN',
'Meropenem-MEM',
'Imipenem-IPM',
'Doripenem-DOR',
'Ertapenem-ETP',
'Minocycline-MNO',
'Doxycycline-DOX',
'Spectinomycin-SPT',
'Trimethoprim/Sulfamethoxazole-SXT',
'Fosfomycin-FOS',
'Vancomycin-VAN',
'Linezolid-LNZ',
'Fluconazole',
'Voriconazole',
'Caspofungin',
'Micafungin',
'Amphotericin B',
'Flucytosine'
];
public function report(Request $request) {
$bulan = $request->input('bulan');
$tahun = $request->input('tahun');
$jenisreport = $request->input('jenisreport');
$dokterId = $request->input('dokter_id');
$tanggalFilter = $request->input('tanggal_filter', 'daftar');
$statusFilter = $request->input('status_filter', 'ALL');
$dateColumn = $tanggalFilter === 'verifikasi' ? 'verifikasi' : 'daftar';
$homebase = url("/");
$arraylist = [];
$limit = $request->input('limit') ?? 500;
$page = $request->input('pagenum') ?? 1;
$order = $request->input('order') ?? 'id desc';
$filterscount = $request->input('filterscount') ?? 0;
if ($jenisreport == 'biorepository'){
if ($bulan == 'ALL'){
$queryBiorepo = DB::table('db_komponenjawaban')
->select('db_komponenjawaban.*',
'periksa.nofoto',
'periksa.noregister',
'periksa.nmpasien',
'periksa.usia',
'periksa.reques',
'periksa.dlp',
'periksa.nm_spesimen',
'periksa.kd_spesimen',
DB::raw("CONCAT('<a href=\"http://10.10.123.218/hasil/', nofoto, '\" target=\"_blank\">Lihat Hasil</a>') as urlhasil"))
->leftJoin('periksa', 'db_komponenjawaban.accnumber', 'periksa.nofoto')
->whereIn('db_komponenjawaban.komponen', ['id_bakteri01', 'id_bakteri02', 'bakteri'])
->where('db_komponenjawaban.isidata', '!=', '')
->where('periksa.daftar', 'LIKE', $tahun.'-%');
if (!empty($dokterId) && $dokterId != 'ALL' && $dokterId != '0') {
$queryBiorepo->where('periksa.dokter_id', $dokterId);
}
$lists = $queryBiorepo->orderBy('periksa.id', 'DESC')->get();
} else {
$queryBiorepo = DB::table('db_komponenjawaban')
->select('db_komponenjawaban.*',
'periksa.nofoto',
'periksa.noregister',
'periksa.nmpasien',
'periksa.usia',
'periksa.reques',
'periksa.dlp',
'periksa.nm_spesimen',
'periksa.kd_spesimen',
DB::raw("CONCAT('<a href=\"http://10.10.123.218/hasil/', nofoto, '\" target=\"_blank\">Lihat Hasil</a>') as urlhasil"))
->leftJoin('periksa', 'db_komponenjawaban.accnumber', 'periksa.nofoto')
->whereIn('db_komponenjawaban.komponen', ['id_bakteri01', 'id_bakteri02', 'bakteri'])
->where('db_komponenjawaban.isidata', '!=', '')
->where('periksa.daftar', 'LIKE', $tahun.'-'.$bulan.'-%');
if (!empty($dokterId) && $dokterId != 'ALL' && $dokterId != '0') {
$queryBiorepo->where('periksa.dokter_id', $dokterId);
}
$lists = $queryBiorepo->orderBy('periksa.id', 'DESC')->get();
}
echo json_encode($lists);
} else {
$query = Periksa::select('id', 'poli_id', 'nofoto', 'noregister', 'nmpasien', 'tlppasien', 'tgllahirpasien', 'usia', 'alamatpasien', 'ktp', 'jkpasien', 'bpjs', 'asuransi', 'urgensi', 'asalpasien', 'klinisi', 'klinis', 'nmanalis', 'nmppdssenior', 'kd_spesimen', 'nm_spesimen', 'dlp', 'diagnosa2', 'mulai', 'verifikasi', 'status', 'reques', 'nmdokter', 'daftar')
->whereYear($dateColumn, $tahun);
if ($bulan !== 'ALL') {
$query->whereMonth($dateColumn, $bulan);
}
if (!empty($dokterId) && $dokterId != 'ALL' && $dokterId != '0') {
$query->where('dokter_id', $dokterId);
}
if ($statusFilter === 'Selesai') {
$query->where('status', 'LIKE', '%Selesai%');
}
/**
* CURSOR → Streaming data, tidak boros memori
*/
$periksaCursor = $query->orderBy($dateColumn, 'ASC')->cursor();
$hasil = [];
/**
* Karena cursor tidak bisa pluck di awal,
* kita kumpulkan accnumber & poli_id sambil streaming
*/
$acc = [];
$poli_ids = [];
foreach ($periksaCursor as $r) {
$acc[] = $r->nofoto;
$poli_ids[] = $r->poli_id;
$hasil[] = $r; // simpan pointer row
}
/** Jika tidak ada data */
if (empty($hasil)) {
return response()->json([]);
}
/**
* Ambil komponen terkait (1 query saja)
*/
$komponen = DB::table('db_komponenjawaban')
->select('accnumber','komponen','isidata')
->whereIn('accnumber', array_unique($acc))
->whereIn('komponen', [
'id_bakteri01','id_bakteri02','bakteri'
])
->get()
->groupBy('accnumber');
/**
* Ambil poli terkait (1 query)
*/
$poli = DB::table('poli')
->select('id','subpoli','modaliti2')
->whereIn('id', array_unique($poli_ids))
->get()
->keyBy('id');
/**
* Proses setiap row → tidak ada map() untuk hemat memori
*/
foreach ($hasil as $row) {
$k = $komponen[$row->nofoto] ?? collect([]);
$row->id_bakteri01 = optional($k->firstWhere('komponen','id_bakteri01'))->isidata;
$row->id_bakteri02 = optional($k->firstWhere('komponen','id_bakteri02'))->isidata;
$row->bakteri = optional($k->firstWhere('komponen','bakteri'))->isidata;
$row->filefoto = "<a href='".url('/hasil/'.$row->nofoto)."'>$row->nofoto</a>";
$p = $poli[$row->poli_id] ?? null;
$row->subpoli = $p->subpoli ?? null;
$row->modaliti2 = $p->modaliti2 ?? '1';
// Hitung status target
if (!empty($row->verifikasi)) {
$selisih = Carbon::parse($row->mulai)->diffInDays($row->verifikasi);
$row->selisih_hari = $selisih;
$row->status_target = ($selisih <= intval($row->modaliti2))
? "MEMENUHI TARGET"
: "TIDAK MEMENUHI TARGET";
} else {
$row->selisih_hari = null;
$row->status_target = "TIDAK ADA HASIL";
}
}
/**
* Return untuk dua mode (rekaptat / data penuh)
*/
if ($jenisreport == 'rekaptat') {
$rekap = collect($hasil)->groupBy('kd_spesimen')->map(function($g){
return [
'jenis_pemeriksaan' => $g->first()->kd_spesimen,
'memenuhi' => $g->where('status_target','MEMENUHI TARGET')->count(),
'tidak_memenuhi' => $g->where('status_target','TIDAK MEMENUHI TARGET')->count(),
'tidak_ada_hasil' => $g->where('status_target','TIDAK ADA HASIL')->count(),
'total' => $g->count(),
];
})->values();
return response()->json($rekap);
}
return response()->json($hasil);
}
}
public function genRekapAntibiotik(Request $request) {
$bulan = $request->input('bulan');
$tahun = $request->input('tahun');
if ($tahun == '' OR is_null($tahun)){
$getarray = explode('?', $bulan);
$bulan = $getarray[0] ?? date('m');
$tahun = $getarray[1] ?? date('Y');
$bulan = str_replace('bulan=', '', $bulan);
$tahun = str_replace('tahun=', '', $tahun);
}
$listAntibiotik = $this->getDynamicAntibioticHeaders($bulan, $tahun);
$query = Periksa::query()->whereYear('daftar', $tahun);
if ($bulan != 'ALL' && $bulan != 'Pick Month') {
$query->whereMonth('daftar', $bulan);
}
// 3. Pagination (50 Data)
$orderbydate = $query->paginate(50);
$orderbydate->appends(['bulan' => $bulan, 'tahun' => $tahun]);
// 4. Mapping Data Antibiotik (Hanya untuk 50 pasien ini)
$pageIds = $orderbydate->pluck('id')->toArray();
$antibiotikLookup = $this->mapAntibiotikData($pageIds);
return view('admin.rekapantibiotik', [
'orderbydate' => $orderbydate,
'antibiotikLookup' => $antibiotikLookup,
'listAntibiotik' => $listAntibiotik, // Kirim header dinamis ke View
'bulan' => $bulan,
'tahun' => $tahun
]);
}
private function mapAntibiotikData($orderIds) {
$raw = RekapAntibiotik::whereIn('orderid', $orderIds)->get();
$lookup = [];
foreach($raw as $row) {
$lookup[$row->orderid][$row->antibiotic] = $row->interpretation;
}
return $lookup;
}
private function getDynamicAntibioticHeaders($bulan, $tahun) {
$query = DB::table('rekapantibiotik')
->join('periksa', 'rekapantibiotik.orderid', '=', 'periksa.id')
->whereYear('periksa.daftar', $tahun);
if ($bulan != 'ALL' && $bulan != 'Pick Month') {
$query->whereMonth('periksa.daftar', $bulan);
}
return $query->distinct()
->orderBy('rekapantibiotik.antibiotic', 'ASC')
->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([]);
$speciesNames = [];
foreach ($komponenRows as $komponenRow) {
$value = trim(strip_tags((string) $komponenRow->isidata));
if ($value === '') {
continue;
}
if (in_array($komponenRow->komponen, ['bakteri', 'id_bakteri01', 'id_bakteri02'], true) && stripos($value, 'Ditemukan morfologi') === false) {
$speciesNames[] = $value;
}
}
$speciesNames = array_values(array_filter($speciesNames, function ($value) {
return trim((string) $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] ?? '')) !== '';
$hasFungalAntibiotic = collect($headers['B_antibiotics'])->contains(function ($antibioticHeader) use ($antibioticValues) {
return array_key_exists($antibioticHeader, $antibioticValues);
});
if (!empty($speciesNames) && $hasJenisSpesimen && !$hasFungalAntibiotic) {
foreach ($speciesNames as $speciesName) {
$tableRow = array_merge($baseRow, [
$speciesName,
$row->id_esbl ?? '',
$row->id_mrsa ?? '',
]);
foreach ($headers['A_antibiotics'] as $antibioticHeader) {
$tableRow[] = $antibioticValues[$antibioticHeader] ?? '';
}
$tables['A'][] = $tableRow;
}
continue;
}
if (!empty($speciesNames) && $hasJenisSpesimen && $hasFungalAntibiotic) {
foreach ($speciesNames as $speciesName) {
$tableRow = array_merge($baseRow, [
$speciesName,
]);
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');
if ($tahun == '' OR is_null($tahun)){
$getarray = explode('?', $bulan);
$bulan = $getarray[0] ?? date('m');
$tahun = $getarray[1] ?? date('Y');
$bulan = str_replace('bulan=', '', $bulan);
$tahun = str_replace('tahun=', '', $tahun);
}
// Query Periksa
$query = Periksa::query()->whereYear('daftar', $tahun);
if ($bulan != 'ALL' && $bulan != 'Pick Month') {
$query->whereMonth('daftar', $bulan);
}
// Preview dibuat paginated agar aman saat filter setahun.
$orderbydate = $query->orderBy('daftar', 'ASC')->orderBy('id', 'ASC')->paginate(50);
$orderbydate->appends(['bulan' => $bulan, 'tahun' => $tahun]);
$pageIds = $orderbydate->pluck('id')->toArray();
$antibiotikLookup = $this->mapAntibiotikData($pageIds);
$glassRows = $orderbydate->getCollection();
$glassLookups = $this->getGlassReportLookups($glassRows);
$glassTables = $this->splitGlassReportRows($glassRows, $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
]);
}
public function exportGlassReport(Request $request) {
// Set memory limit sementara untuk proses export berat, tapi streaming tetap kuncinya
ini_set('memory_limit', '512M');
ini_set('max_execution_time', 300); // 5 menit
$bulan = $request->input('bulan');
$tahun = $request->input('tahun');
// Logic cleaning input...
if (strpos($bulan, 'bulan=') !== false) {
$parts = explode('?', $bulan);
$bulan = str_replace('bulan=', '', $parts[0]);
$tahun = str_replace('tahun=', '', $parts[1] ?? date('Y'));
}
$response = new StreamedResponse(function() use ($bulan, $tahun) {
$handle = fopen('php://output', 'w');
$headers = $this->getGlassReportHeaders();
$tables = [
'A' => [],
'B' => [],
'C' => [],
];
// Query Tanpa Get() tapi Chunk()
$query = Periksa::query()->whereYear('daftar', $tahun);
if ($bulan != 'ALL' && $bulan != 'Pick Month') {
$query->whereMonth('daftar', $bulan);
}
// Proses per 500 data agar RAM stabil
$query->orderBy('id')->chunk(500, function($rows) use (&$tables) {
$lookups = $this->getGlassReportLookups($rows);
$chunkTables = $this->splitGlassReportRows($rows, $lookups);
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);
});
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="GlassReport_'.$bulan.'_'.$tahun.'.csv"');
return $response;
}
public function exportRekapAntibiotik(Request $request) {
ini_set('memory_limit', '512M');
ini_set('max_execution_time', 600); // 10 menit jika data besar
$bulan = $request->input('bulan');
$tahun = $request->input('tahun');
if (strpos($bulan, 'bulan=') !== false) {
$parts = explode('?', $bulan);
$bulan = str_replace('bulan=', '', $parts[0]);
$tahun = str_replace('tahun=', '', $parts[1] ?? date('Y'));
}
// 1. Dapatkan Header Dinamis
$listAntibiotik = $this->getDynamicAntibioticHeaders($bulan, $tahun);
$response = new StreamedResponse(function() use ($bulan, $tahun, $listAntibiotik) {
$handle = fopen('php://output', 'w');
// Header Statis
$staticHeaders = [
'No', 'Status', 'No.RM', 'Name', 'Order', 'Gender', 'Date',
'Urgensi', 'Comming From', 'Code', 'Spesimen', 'Finish',
'BHP Media', 'BHP Pot Sputum', 'BHP Pot Urine', 'BHP Oshe',
'BHP Obyek Glass', 'BHP Botol BD', 'BHP Parafilm', 'BHP Tips',
'BHP Cotton Swab', 'BHP Ab Tambahan', 'ESBL', 'MRSA'
];
// Gabung Header Statis + Header Dinamis dari DB
fputcsv($handle, array_merge($staticHeaders, $listAntibiotik));
// Query Utama (Chunking)
$query = Periksa::query()->whereYear('daftar', $tahun);
if ($bulan != 'ALL' && $bulan != 'Pick Month') {
$query->whereMonth('daftar', $bulan);
}
$query->chunk(500, function($rows) use ($handle, $listAntibiotik) {
// Ambil data nilai antibiotik untuk chunk ini
$chunkIds = $rows->pluck('id')->toArray();
$antibiotikLookup = $this->mapAntibiotikData($chunkIds);
foreach ($rows as $row) {
$csvRow = [
$row->noloket,
$row->status,
$row->noregister,
$row->nmpasien,
$row->reques,
$row->jkpasien,
$row->daftar,
$row->urgensi,
$row->asalpasien,
$row->kd_spesimen,
$row->nm_spesimen,
$row->updated_at,
$row->bhp_media,
$row->bhp_potsputum,
$row->bhp_poturine,
$row->bhp_oshe,
$row->bhp_obyekglass,
$row->bhp_botolbd,
$row->bhp_parafilm,
$row->bhp_tips,
$row->bhp_cottonswab,
$row->bhp_antibiotiktambahan,
$row->id_esbl,
$row->id_mrsa
];
// Loop sesuai Header Dinamis
foreach ($listAntibiotik as $headerAb) {
// Cek apakah pasien ini punya nilai utk antibiotik tsb
$val = $antibiotikLookup[$row->id][$headerAb] ?? '';
$csvRow[] = $val;
}
fputcsv($handle, $csvRow);
}
});
fclose($handle);
});
$response->headers->set('Content-Type', 'text/csv');
$response->headers->set('Content-Disposition', 'attachment; filename="RekapAntibiotik_'.$bulan.'_'.$tahun.'.csv"');
return $response;
}
public function genZNreport(Request $request) {
$data = [];
$bulan = $request->input('bulan');
$tahun = $request->input('tahun');
if ($tahun == '' OR is_null($tahun)){
$getarray = explode('?', $bulan);
$bulan = $getarray[0] ?? date('m');
$tahun = $getarray[1] ?? date('Y');
$bulan = str_replace('bulan=', '', $bulan);
$tahun = str_replace('tahun=', '', $tahun);
}
// komponen Ziehl yang mau dianalisa
$komponenList = [
'id_pewarnaanziehlnielsen',
'id_pewarnaanziehlnielsensewaktu',
'lsg_pewarnaanziehlnielsen',
'lsg_pewarnaanziehlnielsensewaktu'
];
// Nilai Ziehl yang ingin dihitung
$nilaiList = Organisms::where('kelompok', 'Pewarnaan Ziehl Nielsen')->pluck('name')->toArray();
// 1. Ambil periksa sesuai bulan & tahun
if ($bulan == '' OR $bulan == 'ALL'){
$periksa = Periksa::with(['komponen' => function($q) use ($komponenList){
$q->whereIn('komponen', $komponenList);
}])
->whereYear('mulai', $tahun)
->get();
} else {
$periksa = Periksa::with(['komponen' => function($q) use ($komponenList){
$q->whereIn('komponen', $komponenList);
}])
->whereMonth('mulai', $bulan)
->whereYear('mulai', $tahun)
->get();
}
// 2. Ambil distinct kd_spesimen → ini akan jadi kolom
$kdSpesimenList = $periksa
->pluck('kd_spesimen')
->unique()
->values();
// 3. Bangun struktur perhitungan
$rekapLaki = [];
$rekapPerempuan = [];
foreach ($nilaiList as $nilai) {
foreach ($kdSpesimenList as $spesimen) {
// hitung laki-laki
$rekapLaki[$nilai][$spesimen] = $periksa
->where('kd_spesimen', $spesimen)
->where('jkpasien', 'L')
->filter(function($px) use ($nilai, $komponenList){
return $px->komponen
->whereIn('komponen', $komponenList)
->where('isidata', $nilai)
->count() > 0;
})->count();
// hitung perempuan
$rekapPerempuan[$nilai][$spesimen] = $periksa
->where('kd_spesimen', $spesimen)
->where('jkpasien', 'P')
->filter(function($px) use ($nilai, $komponenList){
return $px->komponen
->whereIn('komponen', $komponenList)
->where('isidata', $nilai)
->count() > 0;
})->count();
}
}
$chartL = [];
$chartP = [];
foreach ($nilaiList as $nilai) {
$chartL[] = array_sum($rekapLaki[$nilai]);
$chartP[] = array_sum($rekapPerempuan[$nilai]);
}
return view('cetak.znreport', compact(
'rekapLaki',
'rekapPerempuan',
'kdSpesimenList',
'nilaiList',
'bulan',
'tahun',
'chartL',
'chartP'
));
}
public function genTATreport(Request $request) {
$data = [];
$bulan = $request->input('bulan');
$tahun = $request->input('tahun');
if ($tahun == '' OR is_null($tahun)){
$getarray = explode('?', $bulan);
$bulan = $getarray[0] ?? date('m');
$tahun = $getarray[1] ?? date('Y');
$bulan = str_replace('bulan=', '', $bulan);
$tahun = str_replace('tahun=', '', $tahun);
}
$query = Periksa::select('*');
if ($bulan !== 'ALL') {
$query->whereMonth('mulai', $bulan);
}
$periksa = $query->whereYear('mulai', $tahun)->orderBy('mulai', 'ASC')->get();
if ($periksa->count() == 0) {
return response()->json([]);
}
$accnumbers = $periksa->pluck('nofoto')->toArray();
$komponen = DB::table('db_komponenjawaban')->whereIn('accnumber', $accnumbers)->whereIn('komponen', ['id_bakteri01','id_bakteri02','id_mikroorganisme'])->get()->groupBy('accnumber');
$poli = DB::table('poli')->whereIn('id', $periksa->pluck('poli_id'))->get()->keyBy('id');
$hasil = $periksa->map(function($row) use ($komponen, $poli){
$k = $komponen[$row->nofoto] ?? collect([]);
$row->id_bakteri01 = optional($k->firstWhere('komponen', 'id_bakteri01'))->isidata;
$row->id_bakteri02 = optional($k->firstWhere('komponen', 'id_bakteri02'))->isidata;
$row->bakteri = optional($k->firstWhere('komponen', 'bakteri'))->isidata;
$row->filefoto = "<a href='".url('/hasil/'.$row->nofoto)."'>$row->nofoto</a>";
$p = $poli[$row->poli_id] ?? null;
$row->subpoli = $p->subpoli ?? null;
$target = $p->modaliti2 ?? '1';
$row->modaliti2 = $target;
if (!empty($row->verifikasi)) {
$selisih_hari = Carbon::parse($row->mulai)->diffInDays(Carbon::parse($row->verifikasi));
$target = intval($target);
$hari = intval($selisih_hari);
$row->selisih_hari = $selisih_hari;
if ($hari <= $target) {
$row->status_target = "MEMENUHI TARGET";
} else {
$row->status_target = "TIDAK MEMENUHI TARGET";
}
} else {
$row->selisih_hari = null;
$row->status_target = "TIDAK ADA HASIL";
}
return $row;
});
$rekap = $hasil->groupBy('kd_spesimen')->map(function($group){
return [
'jenis_pemeriksaan' => $group->first()->kd_spesimen,
'memenuhi' => $group->where('status_target', 'MEMENUHI TARGET')->count(),
'tidak_memenuhi' => $group->where('status_target', 'TIDAK MEMENUHI TARGET')->count(),
'tidak_ada_hasil' => $group->where('status_target', 'TIDAK ADA HASIL')->count(),
'total' => $group->count()
];
})->values();
return view('cetak.tatreport', [
'bulan' => $bulan,
'tahun' => $tahun,
'detail' => $hasil,
'rekap' => $rekap
]);
}
public function genRekapPenerimaanSample(Request $request) {
$data = [];
$tanggal = $request->input('tanggal');
$tanggal = str_replace('tanggal=', '', $tanggal);
$query = Periksa::select('*');
$periksa = $query->whereDate('daftar', $tanggal)->orderBy('id', 'ASC')->get();
if ($periksa->count() == 0) {
return response()->json([]);
}
$histories = RekapPenerimaanSamplePrintHistory::whereDate('tanggal', $tanggal)
->orderBy('printed_at', 'DESC')
->orderBy('id', 'DESC')
->get()
->map(function ($h) {
$rowIds = json_decode($h->row_ids, true);
$rowsPayload = json_decode($h->rows_payload, true);
return [
'id' => $h->id,
'printed_by_id' => $h->printed_by_id,
'printed_by_name' => $h->printed_by_name,
'printed_at' => $h->printed_at,
'printed_at_label' => $h->printed_at ? Carbon::parse($h->printed_at)->format('Y-m-d H:i:s') : '-',
'row_ids' => is_array($rowIds) ? $rowIds : [],
'rows_payload' => is_array($rowsPayload) ? $rowsPayload : [],
'total_rows' => is_array($rowIds) ? count($rowIds) : 0,
];
})
->values();
return view('cetak.rekappenerimaansample', [
'tanggal' => $tanggal,
'detail' => $periksa,
'printHistories' => $histories
]);
}
public function markRekapPenerimaanSamplePrinted(Request $request) {
$userId = Session::get('id');
$userNama = Session::get('nama');
if (empty($userId)) {
return response()->json([
'status' => 'error',
'message' => 'Session login tidak valid.'
], 401);
}
$ids = $request->input('ids', []);
if (!is_array($ids) || count($ids) === 0) {
return response()->json([
'status' => 'error',
'message' => 'Data yang dipilih tidak valid.'
], 422);
}
$ids = collect($ids)
->filter(function ($id) {
return is_numeric($id);
})
->map(function ($id) {
return intval($id);
})
->unique()
->values()
->toArray();
if (count($ids) === 0) {
return response()->json([
'status' => 'error',
'message' => 'Data yang dipilih tidak valid.'
], 422);
}
$tanggal = $request->input('tanggal');
$tanggal = !empty($tanggal) ? $tanggal : null;
$printableIds = Periksa::whereIn('id', $ids)
->where(function ($query) {
$query->whereNull('ppdsjunior2')
->orWhere('ppdsjunior2', 0);
})
->pluck('id')
->toArray();
if (count($printableIds) === 0) {
return response()->json([
'status' => 'error',
'message' => 'Semua data yang dipilih sudah pernah dicetak.'
], 422);
}
if (count($printableIds) > 0) {
Periksa::whereIn('id', $printableIds)->update([
'ppdsjunior2' => $userId,
'nmppdsjunior2' => $userNama,
'updated_at' => date('Y-m-d H:i:s'),
]);
}
// Ambil data setelah update supaya payload cetak (petugas) sesuai yang tampil di tabel
$rowsToPrint = Periksa::whereIn('id', $printableIds)
->orderBy('id', 'ASC')
->get()
->map(function ($row) {
$petugas = trim(($row->nmppdsmiddle2 ?? '').' '.($row->nmppdsjunior2 ?? ''));
$status = trim((string)($row->status ?? ''));
if ($status === '') {
$status = '-';
}
return [
'id' => $row->id,
'noregister' => $row->noregister ?? '',
'nmpasien' => $row->nmpasien ?? '',
'nofoto' => $row->nofoto ?? '',
'asalpasien' => $row->asalpasien ?? '',
'daftar' => $row->daftar ?? '',
'reques' => $row->reques ?? '',
'kd_spesimen' => $row->kd_spesimen ?? '',
'nm_spesimen' => $row->nm_spesimen ?? '',
'status' => $status,
'tgldraft' => $row->tgldraft ?? '',
'petugas' => $petugas,
];
})
->values()
->toArray();
$history = RekapPenerimaanSamplePrintHistory::create([
'tanggal' => $tanggal,
'printed_by_id' => $userId,
'printed_by_name' => $userNama,
'printed_at' => Carbon::now()->format('Y-m-d H:i:s'),
'row_ids' => json_encode(array_values($printableIds)),
'rows_payload' => json_encode($rowsToPrint),
'created_at' => date('Y-m-d H:i:s'),
'updated_at' => date('Y-m-d H:i:s'),
]);
$historyResponse = [
'id' => $history->id,
'printed_by_id' => $history->printed_by_id,
'printed_by_name' => $history->printed_by_name,
'printed_at' => $history->printed_at,
'printed_at_label' => Carbon::parse($history->printed_at)->format('Y-m-d H:i:s'),
'row_ids' => $printableIds,
'rows_payload' => $rowsToPrint,
'total_rows' => count($printableIds),
];
return response()->json([
'status' => 'success',
'message' => 'Status cetak berhasil diperbarui.',
'affected_ids'=> $printableIds,
'printed_by' => $userNama,
'history' => $historyResponse
]);
}
}