orderBy('nama', 'ASC')->get(); $cdatane = SIMBHPJenis::all(); $cjenis = count($cdatane); if ($cjenis == 0){ $tasks['jjenis'][0]['jenis'] = 'Belum Ada Jenis Barang'; $tasks['jjenis'][0]['satuan'] = ''; $tasks['jjenis'][0]['satuan_kecil'] = ''; $tasks['jjenis'][0]['konversi_kecil'] = 1; $tasks['jjenis'][0]['stok_minimum'] = 0; } else { $i = 0; foreach($cdatane as $rdata){ $tasks['jjenis'][$i]['jenis'] = $rdata->jenis; $tasks['jjenis'][$i]['satuan'] = $rdata->satuan; $tasks['jjenis'][$i]['satuan_kecil'] = $rdata->satuan_kecil ?? ''; $tasks['jjenis'][$i]['konversi_kecil'] = $rdata->konversi_kecil ?? 1; $tasks['jjenis'][$i]['stok_minimum'] = $rdata->stok_minimum ?? 0; $i++; } } $getdebet = SIMBHPReport::select(DB::raw('SUM(pemasukan) as pemasukan'))->groupBy('marking')->first(); if (isset($getdebet->pemasukan)){ $totpemasukan = $getdebet->pemasukan; } else { $totpemasukan = 0 ;} $getkredit = SIMBHPReport::select(DB::raw('SUM(pengeluaran) as pengeluaran'))->groupBy('marking')->first(); if (isset($getkredit->pengeluaran)){ $totpepengeluaran = $getkredit->pengeluaran; } else { $totpepengeluaran = 0 ;} $tasks['masuk'] = $totpemasukan; $tasks['keluar'] = $totpepengeluaran; $tasks['pegawai'] = $pegawais; $tasks['tahunne'] = date("Y"); $tasks['tanggal'] = $sekarang; $tasks['sidebar'] = 'simbhp'; $tasks['stat_harian_masuk'] = $this->getAggregateBaseQty('pemasukan', 'harian'); $tasks['stat_harian_keluar'] = $this->getAggregateBaseQty('pengeluaran', 'harian'); $tasks['stat_bulanan_masuk'] = $this->getAggregateBaseQty('pemasukan', 'bulanan'); $tasks['stat_bulanan_keluar'] = $this->getAggregateBaseQty('pengeluaran', 'bulanan'); $tasks['stat_tahunan_masuk'] = $this->getAggregateBaseQty('pemasukan', 'tahunan'); $tasks['stat_tahunan_keluar'] = $this->getAggregateBaseQty('pengeluaran', 'tahunan'); $tasks['stat_perjenis_harian'] = $this->getUsagePerJenis('harian'); $tasks['stat_perjenis_bulanan'] = $this->getUsagePerJenis('bulanan'); $tasks['stat_perjenis_tahunan'] = $this->getUsagePerJenis('tahunan'); $tasks['warningstok'] = $this->getLowStockWarnings(); $tasks['expiringSoon'] = $this->getExpiringSoonItems(); $tasks['jenisRows'] = $this->getJenisRows(); return view('admin.gudang', $tasks); } } public function jsonRekapbhp() { $arraysurat = []; $getdata = SIMBHPJenis::all(); if (!empty($getdata)){ foreach($getdata as $hasil){ $jenis = $hasil->kodejenis; $satuan = $hasil->satuan; $satuanKecil = $hasil->satuan_kecil ?? ''; $konversi = (int) ($hasil->konversi_kecil ?? 1); if ($konversi <= 0) { $konversi = 1; } $tlsjenis = $hasil->jenis; $saldoBase = $this->getStockBaseByJenis($tlsjenis); $saldoakhir = $this->formatStockDisplay($saldoBase, $satuan, $satuanKecil, $konversi); $isWarning = $saldoBase <= (int) ($hasil->stok_minimum ?? 0); $arraysurat[] = array( 'id' => $hasil->id, 'satuan' => $satuan, 'jenis' => $jenis, 'tlsjenis' => $tlsjenis, 'saldo' => $saldoakhir, 'warning' => $isWarning ? 'YA' : 'TIDAK', ); } } echo json_encode($arraysurat); } public function jsonReportbhp(Request $request) { $bulan = $request->input('val01'); $tahun = $request->input('val02'); $hasil = []; if ($tahun == 'ALL'){ $bulan = date("m"); $tahun = date("Y"); $getdata = SIMBHPReport::where('bulan', $bulan)->where('tahun', $tahun)->orderBy('id', 'DESC')->get(); } else { if ($bulan == 'ALL'){ $getdata = SIMBHPReport::where('tahun', $tahun)->orderBy('id', 'DESC')->get(); } else { $getdata = SIMBHPReport::where('bulan', $bulan)->where('tahun', $tahun)->orderBy('id', 'DESC')->get(); } } foreach($getdata as $rdata){ $dd = $rdata->tanggal; $mm = $rdata->bulan; $yy = $rdata->tahun; $pengeluaran = $rdata->pengeluaran; $pemasukan = $rdata->pemasukan; if ($mm < 10){ $tgllengkap = $dd.'-0'.$mm.'-'.$yy; } else { $tgllengkap = $dd.'-'.$mm.'-'.$yy; } if ($pengeluaran == '' OR $pengeluaran == 0) {$total = $pemasukan;} else { $total = $pengeluaran; } $hasil[] = array( 'id' => $rdata->id, 'tanggal' => $rdata->tanggal, 'bulan' => $rdata->bulan, 'tahun' => $rdata->tahun, 'deskripsi' => $rdata->deskripsi, 'pemasukan' => number_format( $pemasukan , 0 , '.' , ',' ), 'pengeluaran' => number_format( $pengeluaran , 0 , '.' , ',' ), 'jenis' => $rdata->jenis, 'masa_expired' => $rdata->masa_expired, 'keterangan' => $rdata->keterangan, 'tgllengkap' => $tgllengkap, 'total' => $total, ); } echo json_encode($hasil); } public function exportReportbhp(Request $request) { $bulan = strtoupper((string) $request->query('bulan', date('m'))); $tahun = strtoupper((string) $request->query('tahun', date('Y'))); if ($tahun === 'ALL'){ $bulan = date("m"); $tahun = date("Y"); $query = SIMBHPReport::where('bulan', (int) $bulan)->where('tahun', (int) $tahun); } else { $query = SIMBHPReport::where('tahun', (int) $tahun); if ($bulan !== 'ALL') { $query->where('bulan', (int) $bulan); } } $rows = $query->orderBy('id', 'DESC')->get(); $filename = 'laporan-gudang-bln-'.$bulan.'_thn-'.$tahun.'.xlsx'; return response()->streamDownload(function () use ($rows) { $spreadsheet = new Spreadsheet(); $sheet = $spreadsheet->getActiveSheet(); $sheet->setTitle('Laporan Gudang'); $headers = ['Tanggal', 'Bulan', 'Tahun', 'Jenis', 'Deskripsi', 'Pemasukan', 'Pengeluaran', 'Satuan Transaksi', 'Masa Expired', 'Keterangan']; $sheet->fromArray($headers, null, 'A1'); $rowNumber = 2; foreach ($rows as $row) { $sheet->fromArray([ (int) ($row->tanggal ?? 0), (int) ($row->bulan ?? 0), (int) ($row->tahun ?? 0), $row->jenis ?: '-', $row->deskripsi ?: '-', (int) ($row->pemasukan ?? 0), (int) ($row->pengeluaran ?? 0), $row->satuan_transaksi ?: '-', $row->masa_expired ?: '-', $row->keterangan ?: '-', ], null, 'A'.$rowNumber); $rowNumber++; } foreach (range('A', 'J') as $col) { $sheet->getColumnDimension($col)->setAutoSize(true); } $writer = new Xlsx($spreadsheet); $writer->save('php://output'); $spreadsheet->disconnectWorksheets(); unset($spreadsheet); }, $filename, [ 'Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', ]); } public function jsonReportbhpPaginated(Request $request) { $tanggal = $request->input('tanggal'); $deskripsi = $request->input('deskripsi'); $kategori = $request->input('kategori'); $lm = 10; $limit = ($request->input('limit') == null ? $lm : $request->input('limit')); $order = ($request->input('order') == null ? 'id desc' : $request->input('order')); $data = new SIMBHPReport; if ($kategori != null AND $kategori != '') $data = $data->where('jenis', $kategori); if ($tanggal != null AND $tanggal != '') $data = $data->where('created_at', 'LIKE', '%'.$tanggal.'%'); if ($deskripsi != null AND $deskripsi != '') $data = $data->where('deskripsi', 'LIKE', '%'.$deskripsi.'%'); $data = $data->orderByRaw($order)->paginate($limit); $hasil = []; $totaldata = $data->total(); $debet = 0; $kredit = 0; if (!empty($data)){ foreach($data as $rdata){ $dd = $rdata->tanggal; $mm = $rdata->bulan; $yy = $rdata->tahun; $pengeluaran = $rdata->pengeluaran; $pemasukan = $rdata->pemasukan; $deskripsi = $rdata->deskripsi; $jenis = $rdata->jenis; $debet = $debet + $pemasukan; $kredit = $kredit + $pengeluaran; $cekjenis = SIMBHPJenis::where('kodejenis', $jenis)->first(); if (isset($cekjenis->id)){ $kodejenis = $cekjenis->kodejenis; $jenis = $cekjenis->jenis; $satuan = $cekjenis->satuan; } else { $kodejenis = $jenis; $jenis = ''; $satuan = ''; } if ($jenis != ''){ $deskripsi = ''.$jenis.'
'.$deskripsi; } if ($mm < 10){ $tgllengkap = $yy.'-0'.$mm.'-'.$dd; } else { $tgllengkap = $yy.'-'.$mm.'-'.$dd; } if ($pengeluaran == '' OR $pengeluaran == 0) { $total = $pemasukan; $jentrans = 'PEMASUKAN'; } else { $total = $pengeluaran; $jentrans = 'PENGELUARAN'; } $hasil[] = array( 'id' => $rdata->id, 'tanggal' => $rdata->tanggal, 'bulan' => $rdata->bulan, 'tahun' => $rdata->tahun, 'tlsdeskripsi' => $deskripsi, 'deskripsi' => $rdata->deskripsi, 'pemasukan' => number_format( $pemasukan , 0 , '.' , ',' ), 'pengeluaran' => number_format( $pengeluaran , 0 , '.' , ',' ), 'jenis' => $kodejenis, 'masa_expired' => $rdata->masa_expired, 'keterangan' => $rdata->keterangan, 'tgllengkap' => $tgllengkap, 'created_at' => $rdata->created_at, 'nominal' => $total.' '.$satuan, 'jentrans' => $jentrans, ); } } $response = [ 'message' => 'List Data', 'data' => $hasil, 'totaldata' => $totaldata ]; return response()->json($response, 200); } public function exAddbarang(Request $request) { $deskripsi = $request->input('set01'); $pos = $request->input('set02'); $tanggal = $request->input('set03'); $jumlah = $request->input('set04'); $jenis = $request->input('set05'); $postujuan = $request->input('set06'); $alasan = $request->input('set07'); $set08 = $request->input('set08'); $set09 = $request->input('set09'); $set10 = $request->input('set10'); $satuanTransaksi = $request->input('set11'); $masaExpired = $this->normalizeDateInput($request->input('set12')); if ($tanggal == '' OR is_null($tanggal)){ $tanggal = date("d-m-Y"); } $total = (int)str_replace(',','',$jumlah); if ($jenis == 'jenis'){ $jumlah = '-';} if ($deskripsi != '' and $pos != '' and $tanggal != '' and $jumlah != '' and $jenis != ''){ if ($jenis == 'jenis'){ $jenis = $request->input('set02'); $satuan = $request->input('set03'); $idne = $request->input('set01'); $satuanKecil = trim((string) $set08); $konversiKecil = (int) $set09; if ($konversiKecil <= 0){ $konversiKecil = 1; } $stokMinimum = (int) $set10; if ($stokMinimum < 0){ $stokMinimum = 0; } if ($satuanKecil === '') { $konversiKecil = 1; } elseif ($konversiKecil <= 1) { return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Jika memakai satuan kecil, konversi harus lebih dari 1']); } $kodejenis = preg_replace('/\s+/', '', $jenis); if ($idne == 'new' OR $idne == ''){ $ceksudah = SIMBHPJenis::where('kodejenis', $kodejenis)->where('satuan', $satuan)->count(); if ($ceksudah != 0){ return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => $jenis.' Sudah Ada, Silahkan Masukkan Jenis Barang Lain']); } else { $input = SIMBHPJenis::create([ 'kodejenis' => $kodejenis, 'jenis' => $jenis, 'satuan' => $satuan, 'satuan_kecil' => $satuanKecil, 'konversi_kecil' => $konversiKecil, 'stok_minimum' => $stokMinimum, ]); if ($input){ return response()->json(['status' => 'Success', 'message' => 'Data '.$jenis.' Sukses Ditambahkan']); } else { return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => $jenis.' Gagal di masukkan, silahkan ulangi beberapa saat lagi']); } } } else { $ceksudah = SIMBHPJenis::where('id', '!=', $idne)->where('kodejenis', $kodejenis)->where('satuan', $satuan)->count(); if ($ceksudah != 0){ return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => $jenis.' Sudah Ada, Silahkan Masukkan Jenis Barang Lain']); } else { $input = SIMBHPJenis::where('id', $idne)->update([ 'kodejenis' => $kodejenis, 'jenis' => $jenis, 'satuan' => $satuan, 'satuan_kecil' => $satuanKecil, 'konversi_kecil' => $konversiKecil, 'stok_minimum' => $stokMinimum, ]); if ($input){ return response()->json(['status' => 'Success', 'message' => 'Data '.$jenis.' Sukses Diupdate']); } else { return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => $jenis.' Gagal di masukkan, silahkan ulangi beberapa saat lagi']); } } } } else { $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"); } $unitSetting = $this->getJenisUnitSetting($pos); if ($jenis == 'pemasukan'){ if (($satuanTransaksi ?: 'besar') === 'kecil' && !$unitSetting['has_breakdown']) { return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Barang ini belum memiliki setting pecah satuan']); } $qtyBase = $this->calculateBaseQty($pos, $total, $satuanTransaksi ?: 'besar'); $bayar = SIMBHPReport::create([ 'tanggal' => $dino, 'bulan' => $wulan, 'tahun' => $tahun, 'deskripsi' => $deskripsi, 'pemasukan' => $total, 'pengeluaran' => null, 'qty_base' => $qtyBase, 'satuan_transaksi' => $satuanTransaksi ?: 'besar', 'masa_expired' => $masaExpired, 'jenis' => $pos, 'keterangan' => '', 'marking' => '', ]); } else if ($jenis == 'pengeluaran'){ if (($satuanTransaksi ?: 'besar') === 'kecil' && !$unitSetting['has_breakdown']) { return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Pengeluaran satuan kecil tidak tersedia untuk barang ini']); } $getnama = User::where('id', $deskripsi)->first(); $nama = $getnama->nama ?? 'Unkown'; $deskripsi = 'Diterima oleh '.$nama; $qtyBase = $this->calculateBaseQty($pos, $total, $satuanTransaksi ?: 'besar'); $stokSaatIni = $this->getStockBaseByJenis($pos); if ($qtyBase > $stokSaatIni){ return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Nominal Melebihi Stok']); } else { $bayar = SIMBHPReport::create([ 'tanggal' => $dino, 'bulan' => $wulan, 'tahun' => $tahun, 'deskripsi' => $deskripsi, 'pemasukan' => null, 'pengeluaran' => $total, 'qty_base' => $qtyBase, 'satuan_transaksi' => $satuanTransaksi ?: 'besar', 'jenis' => $pos, 'keterangan' => '', 'marking' => '', ]); } } else if ($jenis == 'editor'){ if ($alasan == ''){ return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Alasan Perubahan Data Wajib Di Isi!!!']); } else { $getdebet = SIMBHPReport::select(DB::raw('SUM(pemasukan) as pemasukan'))->where('jenis', $pos)->groupBy('jenis')->first(); if (isset($getdebet->pemasukan)){ $totpemasukan = $getdebet->pemasukan; } else { $totpemasukan = 0 ;} $getkredit = SIMBHPReport::select(DB::raw('SUM(pengeluaran) as pengeluaran'))->where('jenis', $pos)->groupBy('jenis')->first(); if (isset($getkredit->pengeluaran)){ $totpepengeluaran = $getkredit->pengeluaran; } else { $totpepengeluaran = 0 ;} $totpepengeluaran = $totpepengeluaran + $total; $rdatalama = SIMBHPReport::where('id', $postujuan)->first(); $ldeskripsi = $rdatalama->deskripsi; $lpemasukan = $rdatalama->pemasukan; $lpengeluaran = $rdatalama->pengeluaran; $ljenis = $rdatalama->jenis; $marking = $rdatalama->marking; if ($lpengeluaran == '' OR $lpengeluaran == 0) { $satuanEdit = $rdatalama->satuan_transaksi ?: 'besar'; $qtyBaseEdit = $this->calculateBaseQty($pos, $total, $satuanEdit); $ltotal = number_format( $lpemasukan , 0 , '.' , ',' ); if ($marking != ''){ SIMBHPReport::where('marking', $marking)->whereNotIn('id', [$postujuan])->update([ 'tanggal' => $dino, 'bulan' => $wulan, 'tahun' => $tahun, 'pengeluaran' => $total, 'qty_base' => $qtyBaseEdit, 'satuan_transaksi' => $satuanEdit ]); } $bayar = SIMBHPReport::where('id', $postujuan)->update([ 'tanggal' => $dino, 'bulan' => $wulan, 'tahun' => $tahun, 'deskripsi' => $deskripsi, 'jenis' => $pos, 'pemasukan' => $total, 'qty_base' => $qtyBaseEdit, 'satuan_transaksi' => $satuanEdit, 'masa_expired' => $masaExpired, 'keterangan' => $alasan, 'updated_at' => date("Y-m-d H:i:s") ]); } else { $satuanEdit = $rdatalama->satuan_transaksi ?: 'kecil'; $qtyBaseEdit = $this->calculateBaseQty($pos, $total, $satuanEdit); $totpepengeluaran = $totpepengeluaran + $total; if ($totpepengeluaran > $totpemasukan){ return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Nominal Melebihi Stok']); } else { $ltotal = number_format( $lpengeluaran , 0 , '.' , ',' ); if ($marking != ''){ SIMBHPReport::where('marking', $marking)->whereNotIn('id', [$postujuan])->update([ 'tanggal' => $dino, 'bulan' => $wulan, 'tahun' => $tahun, 'pemasukan' => $total, 'qty_base' => $qtyBaseEdit, 'satuan_transaksi' => $satuanEdit ]); } $bayar = SIMBHPReport::where('id', $postujuan)->update([ 'tanggal' => $dino, 'bulan' => $wulan, 'tahun' => $tahun, 'deskripsi' => $deskripsi, 'jenis' => $pos, 'pengeluaran' => $total, 'qty_base' => $qtyBaseEdit, 'satuan_transaksi' => $satuanEdit, 'keterangan' => $alasan, 'updated_at' => date("Y-m-d H:i:s") ]); } } $baris1 = ''; $baris2 = ''; $baris3 = ''; $baris4 = ''; $baris5 = '

Data Lama

Data Perubahan

Deskripsi'.$ldeskripsi.'Diubah Menjadi'.$deskripsi.'
Jenis'.$ljenis.'Diubah Menjadi'.$pos.'
Total'.$ltotal.'Diubah Menjadi'.$jumlah.'
Dengan Alasan'.$alasan.''; $baris6 = '
Eksekutor'.Session('nama').'
'; $perubahan = $baris1.$baris2.$baris3.$baris4.$baris5.$baris6; Xfiles::create([ 'xmarking' => 'SIMBHP-'.$postujuan.'-'.time(), 'xtabel' => 'History SIMBHP', 'xjenis' => '', 'xfile' => $perubahan ]); } } else { if ($alasan == ''){ return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Alasan Perubahan Data Wajib Di Isi!!!']); } else { $rdatalama = SIMBHPReport::where('id', $postujuan)->first(); $ldeskripsi = $rdatalama->deskripsi; $lpemasukan = $rdatalama->pemasukan; $lpengeluaran = $rdatalama->pengeluaran; $ljenis = $rdatalama->jenis; $marking = $rdatalama->marking; if ($lpengeluaran == '' or $lpengeluaran == 0) { $ltotal = number_format( $lpemasukan , 0 , '.' , ',' ); } else { $ltotal = number_format( $lpengeluaran , 0 , '.' , ',' ); } $baris1 = ''; $baris2 = ''; $baris3 = ''; $baris4 = ''; $baris5 = '

Data Lama

Data Perubahan

Deskripsi'.$ldeskripsi.'DIHAPUS
Jenis'.$ljenis.'DIHAPUS
Total'.$ltotal.'DIHAPUS
Dengan Alasan'.$alasan.''; $baris6 = '
Eksekutor'.Session('nama').'
'; $perubahan = $baris1.$baris2.$baris3.$baris4.$baris5.$baris6; Xfiles::create([ 'xmarking' => 'SIMBHP-'.$postujuan.'-'.time(), 'xtabel' => 'History SIMBHP', 'xjenis' => '', 'xfile' => $perubahan ]); if ($marking != ''){ $bayar = SIMBHPReport::where('marking', $marking)->delete(); } else { $bayar = SIMBHPReport::where('id', $postujuan)->delete(); } } } if ($bayar){ return response()->json(['status' => 'Success', 'message' => 'Transaksi '.$jenis.' Sukses Dilaksanakan']); } else { return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Update Gagal, Pastikan Data Yang anda Isi Sudah Sesuai']); } } } else { return response()->json(['icon' => 'error', 'warna' => '#bf441d', 'status' => 'Gagal', 'message' => 'Pastikan Formnya Anda Isi dengan Lengkap']); } } public function exKwitansi(Request $request) { return response()->json([ 'status' => 'Info', 'message' => 'Fitur kwitansi gudang belum diaktifkan pada versi ini.' ]); } private function calculateBaseQty($jenisNama, $qtyInput, $satuanTransaksi = 'besar') { $qtyInput = (int) $qtyInput; if ($qtyInput < 0) { $qtyInput = 0; } $setting = $this->getJenisUnitSetting($jenisNama); $konversi = (int) $setting['konversi']; if ($konversi <= 0) { $konversi = 1; } if ($satuanTransaksi === 'kecil') { return $qtyInput; } return $qtyInput * $konversi; } private function getJenisUnitSetting($jenisNama) { $jenis = SIMBHPJenis::where('jenis', $jenisNama)->first(); $satuanKecil = trim((string) ($jenis->satuan_kecil ?? '')); $konversi = (int) ($jenis->konversi_kecil ?? 1); if ($konversi <= 0) { $konversi = 1; } $hasBreakdown = ($satuanKecil !== '' && $konversi > 1); return [ 'has_breakdown' => $hasBreakdown, 'konversi' => $konversi, 'satuan_kecil' => $satuanKecil, ]; } private function getStockBaseByJenis($jenisNama) { $rows = SIMBHPReport::where('jenis', $jenisNama)->get(); $masuk = 0; $keluar = 0; foreach ($rows as $row) { if (!is_null($row->pemasukan) && (int)$row->pemasukan > 0) { $masuk += $this->extractBaseQty($row, 'pemasukan'); } if (!is_null($row->pengeluaran) && (int)$row->pengeluaran > 0) { $keluar += $this->extractBaseQty($row, 'pengeluaran'); } } return $masuk - $keluar; } private function extractBaseQty($row, $direction = 'pemasukan') { if (!is_null($row->qty_base) && (int)$row->qty_base > 0) { return (int) $row->qty_base; } if ($direction === 'pengeluaran') { return (int) ($row->pengeluaran ?? 0); } return (int) ($row->pemasukan ?? 0); } private function formatStockDisplay($saldoBase, $satuanBesar, $satuanKecil, $konversi) { $saldoBase = (int) $saldoBase; $konversi = (int) $konversi; if ($konversi <= 1 || $satuanKecil == '') { return number_format($saldoBase, 0, '.', ',').' '.$satuanBesar; } $besar = intdiv($saldoBase, $konversi); $kecil = $saldoBase % $konversi; return number_format($besar, 0, '.', ',').' '.$satuanBesar.' + '.number_format($kecil, 0, '.', ',').' '.$satuanKecil; } private function getLowStockWarnings() { $warnings = []; $allJenis = SIMBHPJenis::orderBy('jenis', 'ASC')->get(); foreach ($allJenis as $item) { $saldoBase = $this->getStockBaseByJenis($item->jenis); $minimum = (int) ($item->stok_minimum ?? 0); if ($saldoBase <= $minimum) { $warnings[] = [ 'jenis' => $item->jenis, 'saldo' => $this->formatStockDisplay( $saldoBase, $item->satuan, $item->satuan_kecil ?? '', $item->konversi_kecil ?? 1 ), 'minimum' => $minimum, 'satuan_kecil' => $item->satuan_kecil ?: $item->satuan, ]; } } return $warnings; } private function getExpiringSoonItems() { $today = date('Y-m-d'); $limitDate = date('Y-m-d', strtotime('+30 days')); $rows = SIMBHPReport::whereNotNull('masa_expired') ->whereNotNull('pemasukan') ->where('pemasukan', '>', 0) ->where('masa_expired', '>=', $today) ->where('masa_expired', '<=', $limitDate) ->orderBy('masa_expired', 'ASC') ->orderBy('id', 'DESC') ->get(); $items = []; foreach ($rows as $row) { $expiredAt = (string) $row->masa_expired; $daysLeft = (int) floor((strtotime($expiredAt) - strtotime($today)) / 86400); if ($daysLeft < 0) { continue; } $badge = 'warning'; if ($daysLeft <= 7) { $badge = 'danger'; } elseif ($daysLeft <= 14) { $badge = 'warning'; } $items[] = [ 'jenis' => $row->jenis ?: '-', 'deskripsi' => $row->deskripsi ?: '-', 'qty' => (int) ($row->pemasukan ?? 0), 'satuan' => $row->satuan_transaksi ?: 'besar', 'tanggal_masuk' => sprintf('%02d-%02d-%04d', (int) $row->tanggal, (int) $row->bulan, (int) $row->tahun), 'masa_expired' => date('d-m-Y', strtotime($expiredAt)), 'sisa_hari' => $daysLeft, 'badge' => $badge, ]; } return $items; } private function getAggregateBaseQty($direction, $scope = 'harian') { $now = date('Y-m-d'); $d = (int) date('d', strtotime($now)); $m = (int) date('m', strtotime($now)); $y = (int) date('Y', strtotime($now)); $query = SIMBHPReport::query(); if ($scope === 'harian') { $query->where('tanggal', $d)->where('bulan', $m)->where('tahun', $y); } elseif ($scope === 'bulanan') { $query->where('bulan', $m)->where('tahun', $y); } else { $query->where('tahun', $y); } $rows = $query->get(); $total = 0; foreach ($rows as $row) { if ($direction === 'pemasukan' && !is_null($row->pemasukan) && (int)$row->pemasukan > 0) { $total += $this->extractBaseQty($row, 'pemasukan'); } if ($direction === 'pengeluaran' && !is_null($row->pengeluaran) && (int)$row->pengeluaran > 0) { $total += $this->extractBaseQty($row, 'pengeluaran'); } } return $total; } private function getUsagePerJenis($scope = 'harian') { $now = date('Y-m-d'); $d = (int) date('d', strtotime($now)); $m = (int) date('m', strtotime($now)); $y = (int) date('Y', strtotime($now)); $query = SIMBHPReport::query(); if ($scope === 'harian') { $query->where('tanggal', $d)->where('bulan', $m)->where('tahun', $y); } elseif ($scope === 'bulanan') { $query->where('bulan', $m)->where('tahun', $y); } else { $query->where('tahun', $y); } $rows = $query->get(); $grouped = []; foreach ($rows as $row) { $jenis = $row->jenis ?: 'Tidak Diketahui'; if (!isset($grouped[$jenis])) { $grouped[$jenis] = ['jenis' => $jenis, 'masuk' => 0, 'keluar' => 0]; } if (!is_null($row->pemasukan) && (int)$row->pemasukan > 0) { $grouped[$jenis]['masuk'] += $this->extractBaseQty($row, 'pemasukan'); } if (!is_null($row->pengeluaran) && (int)$row->pengeluaran > 0) { $grouped[$jenis]['keluar'] += $this->extractBaseQty($row, 'pengeluaran'); } } return array_values($grouped); } private function normalizeDateInput($value) { $value = trim((string) $value); if ($value === '') { return null; } if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) { return $value; } if (preg_match('/^\d{2}-\d{2}-\d{4}$/', $value)) { $parts = explode('-', $value); return $parts[2].'-'.$parts[1].'-'.$parts[0]; } return null; } private function getJenisRows() { $rows = []; $items = SIMBHPJenis::orderBy('jenis', 'ASC')->get(); foreach ($items as $item) { $saldoBase = $this->getStockBaseByJenis($item->jenis); $konversi = (int) ($item->konversi_kecil ?? 1); if ($konversi <= 0) { $konversi = 1; } $rows[] = [ 'id' => $item->id, 'jenis' => $item->jenis, 'satuan' => $item->satuan, 'satuan_kecil' => $item->satuan_kecil ?? '', 'konversi_kecil' => $konversi, 'stok_minimum' => (int) ($item->stok_minimum ?? 0), 'saldo' => $this->formatStockDisplay($saldoBase, $item->satuan, $item->satuan_kecil ?? '', $konversi), 'warning' => ($saldoBase <= (int) ($item->stok_minimum ?? 0)) ? 'YA' : 'TIDAK', ]; } return $rows; } }