@php $tanggal_presensi = $periode_dari; @endphp @while (strtotime($tanggal_presensi) <= strtotime($periode_sampai)) @php $tanggal_presensi = date('Y-m-d', strtotime('+1 day', strtotime($tanggal_presensi))); @endphp @endwhile @php $tanggal_presensi = $periode_dari; @endphp @while (strtotime($tanggal_presensi) <= strtotime($periode_sampai)) @php $tanggal_presensi = date('Y-m-d', strtotime('+1 day', strtotime($tanggal_presensi))); @endphp @endwhile @foreach ($laporan_presensi as $d) @php $tanggal_presensi = $periode_dari; // Mapping jadwal untuk NIK ini dari berbagai sumber $mapJadwalByDate = $jadwal_bydate[$d['nik']] ?? []; $mapJadwalGrupByDate = $jadwal_grup_bydate[$d['nik']] ?? []; $mapJadwalByDay = $jadwal_byday[$d['nik']] ?? []; @endphp @php $total_denda = 0; $total_potongan_jam = 0; $total_jam_lembur = 0; $jml_hadir = 0; $jml_sakit = 0; $jml_izin = 0; $jml_cuti = 0; $jml_libur = 0; $jml_alfa = 0; $jml_terlambat = 0; $jml_pulangcepat = 0; $jml_tidakscanmasuk = 0; $jml_tidakscanpulang = 0; $total_potongan_istirahat = 0; $rekap_istirahat = []; @endphp @while (strtotime($tanggal_presensi) <= strtotime($periode_sampai)) @php $denda = 0; $potongan_jam = 0; // Optimized: Check libur using pre-loaded data (no DB query) $is_libur_nasional = isset($libur_nasional_dates[$tanggal_presensi]); if ($is_libur_nasional) { $is_libur = true; } else { $has_schedule = false; $nama_hari = getHari($tanggal_presensi); if (isset($mapJadwalByDate[$tanggal_presensi])) $has_schedule = true; elseif (isset($mapJadwalGrupByDate[$tanggal_presensi])) $has_schedule = true; elseif (isset($mapJadwalByDay[$nama_hari])) $has_schedule = true; else { $keyDC = $d['kode_dept'] . '|' . $d['kode_cabang']; $mapD = $jadwal_bydept[$keyDC] ?? []; if (isset($mapD[$nama_hari])) $has_schedule = true; elseif (isset($jadwal_global[$nama_hari])) $has_schedule = true; } $is_libur = !$has_schedule; } $tipe_hari = $is_libur ? 2 : 1; // Cek snapshot lembur (data terkunci) $lembur_key = $d['nik'] . '|' . $tanggal_presensi; $ceklembur_data = $datalembur_indexed[$lembur_key] ?? []; $snapshot_lembur = isset($d[$tanggal_presensi]) && ($d[$tanggal_presensi]['jam_lembur_aktual'] ?? null) !== null; if ($snapshot_lembur) { $jml_jam_lembur = $d[$tanggal_presensi]['jam_lembur_aktual']; } else { $lembur = hitungLembur($ceklembur_data); $jml_jam_lembur = !empty($ceklembur_data) ? $lembur : 0; } $nama_hari = getHari($tanggal_presensi); // O(1) libur lookup $libur_key = $d['nik'] . '|' . $tanggal_presensi; $ceklibur = $datalibur_indexed[$libur_key] ?? ($datalibur_by_tanggal[$tanggal_presensi] ?? []); @endphp @if (isset($d[$tanggal_presensi])) @if ($d[$tanggal_presensi]['status'] == 'h') @php $bgcolor = ''; $textcolor = ''; $jml_hadir++; $ket_nama_jam_kerja = '' . e($d[$tanggal_presensi]['nama_jam_kerja']) . '
'; $ket_jadwal_kerja = '' . date('H:i', strtotime($d[$tanggal_presensi]['jam_masuk'])) . ' - ' . date('H:i', strtotime($d[$tanggal_presensi]['jam_pulang'])) . '
'; $jam_masuk = $tanggal_presensi . ' ' . $d[$tanggal_presensi]['jam_masuk']; $jam_in = !empty($d[$tanggal_presensi]['jam_in']) ? date('H:i', strtotime($d[$tanggal_presensi]['jam_in'])) : '✘'; $jam_out = !empty($d[$tanggal_presensi]['jam_out']) ? date('H:i', strtotime($d[$tanggal_presensi]['jam_out'])) : '✘'; $color_jam_in = !empty($d[$tanggal_presensi]['jam_in']) ? 'green' : 'red'; $color_jam_out = !empty($d[$tanggal_presensi]['jam_out']) ? 'green' : 'red'; $ket_presensi = '' . $jam_in . ' - ' . $jam_out . '
'; $terlambat = hitungjamterlambat($d[$tanggal_presensi]['jam_in'], $jam_masuk); $color_terlambat = $terlambat != null ? $terlambat['color'] : ''; $ket_terlambat = $terlambat != null ? '' . $terlambat['show_laporan'] . '
' : ''; // Cek apakah denda sudah dikunci (ada di database) $denda_dari_db = isset($d[$tanggal_presensi]['denda']) && $d[$tanggal_presensi]['denda'] !== null ? $d[$tanggal_presensi]['denda'] : null; if ($denda_dari_db !== null) { // Gunakan denda dari database (sudah dikunci) $denda = $denda_dari_db; // Hitung potongan jam tetap menggunakan rumus if ($terlambat != null) { if ($terlambat['desimal_terlambat'] < 1) { $potongan_jam_terlambat = 0; } else { $potongan_jam_terlambat = $terlambat['desimal_terlambat'] > $d[$tanggal_presensi]['total_jam'] ? $d[$tanggal_presensi]['total_jam'] : $terlambat['desimal_terlambat']; } if ($terlambat['menitterlambat'] > 0) { $jml_terlambat++; } } else { $potongan_jam_terlambat = 0; } } else { // Hitung denda menggunakan rumus (belum dikunci) if ($terlambat != null) { if ($terlambat['desimal_terlambat'] < 1) { $potongan_jam_terlambat = 0; $denda = hitungdenda($denda_list, $terlambat['menitterlambat']); } else { $potongan_jam_terlambat = $terlambat['desimal_terlambat'] > $d[$tanggal_presensi]['total_jam'] ? $d[$tanggal_presensi]['total_jam'] : $terlambat['desimal_terlambat']; $denda = 0; } if ($terlambat['menitterlambat'] > 0) { $jml_terlambat++; } } else { $potongan_jam_terlambat = 0; $denda = 0; } } $ket_denda = $denda != 0 ? 'Denda : ' . formatAngka($denda) . '
' : ''; $pulangcepat = hitungpulangcepat( $tanggal_presensi, $d[$tanggal_presensi]['jam_out'], $d[$tanggal_presensi]['jam_pulang'], $d[$tanggal_presensi]['istirahat'], $d[$tanggal_presensi]['jam_awal_istirahat'], $d[$tanggal_presensi]['jam_akhir_istirahat'], $d[$tanggal_presensi]['lintashari'], ); $pulangcepat = $pulangcepat > $d[$tanggal_presensi]['total_jam'] ? $d[$tanggal_presensi]['total_jam'] : $pulangcepat; if ($pulangcepat != null) { $jml_pulangcepat++; } $ket_pulang_cepat = $pulangcepat != null ? 'PC : ' . $pulangcepat . ' Jam
' : ''; $color_pulang_cepat = $pulangcepat != null ? 'red' : ''; $potongan_tidak_absen_masuk_atau_pulang = empty($d[$tanggal_presensi]['jam_out']) || empty($d[$tanggal_presensi]['jam_in']) ? $d[$tanggal_presensi]['total_jam'] : 0; $potongan_istirahat = hitungPotonganIstirahat( $d[$tanggal_presensi]['istirahat_out'], $d[$tanggal_presensi]['istirahat_in'], $d[$tanggal_presensi]['jam_awal_istirahat'], $d[$tanggal_presensi]['jam_akhir_istirahat'] ); $status_potongan_istirahat = $d[$tanggal_presensi]['status_potongan_istirahat'] ?? $generalsetting->potongan_istirahat; $potongan_jam = $potongan_tidak_absen_masuk_atau_pulang == 0 ? $pulangcepat + $potongan_jam_terlambat + ($status_potongan_istirahat == 1 ? $potongan_istirahat : 0) : $potongan_tidak_absen_masuk_atau_pulang; if (!empty($d[$tanggal_presensi]['istirahat_out']) && !empty($d[$tanggal_presensi]['istirahat_in'])) { $rekap_istirahat[] = '' . date('H:i', strtotime($d[$tanggal_presensi]['istirahat_out'])) . ' - ' . date('H:i', strtotime($d[$tanggal_presensi]['istirahat_in'])) . ''; } else { $rekap_istirahat[] = 'Belum Absen'; } $ket_potongan_jam = !empty($potongan_jam) ? 'PJ: ' . formatAngkaDesimal($potongan_jam) . ' Jam
' : ''; $ket_jam_lembur = $jml_jam_lembur > 0 ? ' Lembur :' . $jml_jam_lembur . ' Jam
' : ''; $ket = $ket_nama_jam_kerja . $ket_jadwal_kerja . $ket_presensi . $ket_terlambat . $ket_denda . $ket_pulang_cepat . $ket_potongan_jam . $ket_jam_lembur; if (empty($d[$tanggal_presensi]['jam_in'])) { $jml_tidakscanmasuk++; } if (empty($d[$tanggal_presensi]['jam_out'])) { $jml_tidakscanpulang++; } @endphp @elseif($d[$tanggal_presensi]['status'] == 'i') @php $bgcolor = '#dea51f'; $textcolor = 'white'; $jml_izin++; $potongan_jam = $d[$tanggal_presensi]['total_jam']; // Cek apakah denda sudah dikunci (untuk izin biasanya 0, tapi ambil dari DB jika ada) $denda_dari_db = isset($d[$tanggal_presensi]['denda']) && $d[$tanggal_presensi]['denda'] !== null ? $d[$tanggal_presensi]['denda'] : null; $denda = $denda_dari_db !== null ? $denda_dari_db : 0; $ket = 'IZIN
' . e($d[$tanggal_presensi]['keterangan_izin_absen']) . '
PJ : ' . formatAngkaDesimal($potongan_jam) . ' Jam'; @endphp @elseif($d[$tanggal_presensi]['status'] == 's') @php $bgcolor = '#c8075b'; $textcolor = 'white'; $jml_sakit++; // Cek apakah denda sudah dikunci (untuk sakit biasanya 0, tapi ambil dari DB jika ada) $denda_dari_db = isset($d[$tanggal_presensi]['denda']) && $d[$tanggal_presensi]['denda'] !== null ? $d[$tanggal_presensi]['denda'] : null; $denda = $denda_dari_db !== null ? $denda_dari_db : 0; $ket = 'SAKIT
' . e($d[$tanggal_presensi]['keterangan_izin_sakit']) . ' '; @endphp @elseif($d[$tanggal_presensi]['status'] == 'c') @php $bgcolor = '#0164b5'; $textcolor = 'white'; $jml_cuti++; // Cek apakah denda sudah dikunci (untuk cuti biasanya 0, tapi ambil dari DB jika ada) $denda_dari_db = isset($d[$tanggal_presensi]['denda']) && $d[$tanggal_presensi]['denda'] !== null ? $d[$tanggal_presensi]['denda'] : null; $denda = $denda_dari_db !== null ? $denda_dari_db : 0; $ket = 'CUTI
' . e($d[$tanggal_presensi]['keterangan_izin_cuti']) . ''; @endphp @elseif($d[$tanggal_presensi]['status'] == 'a') @php $bgcolor = 'red'; $textcolor = 'white'; $jml_alfa++; $potongan_jam = $d[$tanggal_presensi]['total_jam']; // Cek apakah denda sudah dikunci (ada di database) $denda_dari_db = isset($d[$tanggal_presensi]['denda']) && $d[$tanggal_presensi]['denda'] !== null ? $d[$tanggal_presensi]['denda'] : null; // Untuk alpa, denda biasanya 0 atau null, tapi tetap ambil dari DB jika sudah dikunci $denda = $denda_dari_db !== null ? $denda_dari_db : 0; $ket_denda_alpa = $denda != 0 ? '
Denda : ' . formatAngka($denda) . '' : ''; $ket = 'Alpa
PJ : ' . formatAngkaDesimal($potongan_jam) . ' Jam' . $ket_denda_alpa; @endphp @endif @else @php $bgcolor = 'red'; $textcolor = 'white'; $ket = ''; $potongan_jam = 0; // Jika hari ini libur khusus karyawan, tandai libur if (!empty($ceklibur)) { $bgcolor = 'green'; $textcolor = 'white'; $jml_libur++; $ket = e($ceklibur[0]['keterangan']); } else { // Bukan libur → cek jadwal berurutan: // 1) Jadwal by-date per karyawan $totalJamJadwal = $mapJadwalByDate[$tanggal_presensi] ?? null; // 2) Kalau kosong, cek jadwal grup by-date if ($totalJamJadwal === null) { $totalJamJadwal = $mapJadwalGrupByDate[$tanggal_presensi] ?? null; } // 3) Kalau masih kosong, cek jadwal by-day per karyawan if ($totalJamJadwal === null) { $totalJamJadwal = $mapJadwalByDay[$nama_hari] ?? null; } // 4) Kalau masih kosong, cek jadwal by-day per departemen & cabang if ($totalJamJadwal === null) { $keyDeptCabang = $d['kode_dept'] . '|' . $d['kode_cabang']; $mapDept = $jadwal_bydept[$keyDeptCabang] ?? []; $totalJamJadwal = $mapDept[$nama_hari] ?? null; } // 5) Kalau masih kosong, cek jadwal global if ($totalJamJadwal === null) { $totalJamJadwal = $jadwal_global[$nama_hari] ?? null; } if ($totalJamJadwal !== null) { // Ada jadwal tapi tidak ada presensi sama sekali → Alpa & potong full jam kerja $jml_alfa++; $potongan_jam = is_array($totalJamJadwal) ? $totalJamJadwal['total_jam'] : $totalJamJadwal; // Untuk alpa yang belum ada di database, denda = 0 $denda = 0; $ket = 'Alpa
PJ : ' . formatAngkaDesimal($potongan_jam) . ' Jam'; } } // Jika ada lembur terpisah, tetap tampilkan info lembur if (!empty($ceklembur_data)) { $bgcolor = 'white'; $textcolor = 'black'; $ket_jam_lembur = ' Lembur :' . $jml_jam_lembur . ' Jam
'; $ket = $ket_jam_lembur; } @endphp @endif @php $total_denda += $denda; $total_potongan_jam += $potongan_jam; $total_jam_lembur += $jml_jam_lembur; $bgcolor = $is_libur ? 'orange' : $bgcolor; @endphp @php $tanggal_presensi = date('Y-m-d', strtotime('+1 day', strtotime($tanggal_presensi))); @endphp @endwhile @endforeach {{-- LEGEND --}}
LAPORAN PRESENSI
{{ $generalsetting->nama_perusahaan }}
PERIODE {{ date('d-m-Y', strtotime($periode_dari)) }} - {{ date('d-m-Y', strtotime($periode_sampai)) }}
{{ $generalsetting->alamat }}
{{ $generalsetting->telepon }}
No Nik Nama Karyawan Jabatan Dept Cabang Tanggal Jam Istirahat Denda Pot. Jam Lembur Rekap
{{ getHari(date('Y-m-d', strtotime($tanggal_presensi))) }}Hadir Izin Sakit Alfa Libur Terlambat Tidak Scan Masuk Tidak Scan Pulang Pulang Cepat
{{ date('d', strtotime($tanggal_presensi)) }}
{{ $loop->iteration }} '{{ $d['nik_show'] ?? $d['nik'] }} {{ $d['nama_karyawan'] }} {{ $d['nama_jabatan'] }} {{ $d['kode_dept'] }} {{ $d['kode_cabang'] }} {!! $ket !!} @if ($generalsetting->absen_istirahat == 1) {!! implode('
', $rekap_istirahat) !!} @else - @endif
{{ formatAngka($total_denda) }} {{ formatAngkaDesimal($total_potongan_jam) }} {{ formatAngkaDesimal($total_jam_lembur) }} {{ $jml_hadir }} {{ $jml_izin }} {{ $jml_sakit }} {{ $jml_alfa }} {{ $jml_libur }} {{ $jml_terlambat }} {{ $jml_tidakscanmasuk }} {{ $jml_tidakscanpulang }} {{ $jml_pulangcepat }}
Kode Keterangan
PC Pulang Cepat
PJ Potongan Jam