@foreach ($laporan_presensi as $d) @php $tanggal_presensi = $periode_dari; $total_denda = 0; $total_potongan_jam = 0; $total_tunjangan = 0; // Mapping jadwal untuk NIK ini dari berbagai sumber (sama seperti presensi_cetak & gaji_cetak) $mapJadwalByDate = $jadwal_bydate[$d['nik']] ?? []; $mapJadwalGrupByDate = $jadwal_grup_bydate[$d['nik']] ?? []; $mapJadwalByDay = $jadwal_byday[$d['nik']] ?? []; // Kalkulasi upah per jam $upah_perjam = $d['gaji_pokok'] / $generalsetting->total_jam_bulan; @endphp {{-- Proses kalkulasi denda dan potongan jam --}} @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_check = getHari($tanggal_presensi); if (isset($mapJadwalByDate[$tanggal_presensi])) $has_schedule = true; elseif (isset($mapJadwalGrupByDate[$tanggal_presensi])) $has_schedule = true; elseif (isset($mapJadwalByDay[$nama_hari_check])) $has_schedule = true; else { $keyDC = $d['kode_dept'] . '|' . $d['kode_cabang']; $mapD = $jadwal_bydept[$keyDC] ?? []; if (isset($mapD[$nama_hari_check])) $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']; $jam_netto_harian = $d[$tanggal_presensi]['jam_lembur_netto']; } else { $lembur_aktual = hitungLembur($ceklembur_data); if ($lembur_aktual > 0) { $jml_jam_lembur = $lembur_aktual; $jam_netto_harian = hitungJamNetto($lembur_aktual, $tipe_hari); } else { $jml_jam_lembur = 0; $jam_netto_harian = 0; } } // 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 $jam_masuk = $tanggal_presensi . ' ' . $d[$tanggal_presensi]['jam_masuk']; $terlambat = hitungjamterlambat($d[$tanggal_presensi]['jam_in'], $jam_masuk); // Jika denda sudah dikunci di database, gunakan nilai tersebut $denda_dari_db = isset($d[$tanggal_presensi]['denda']) && $d[$tanggal_presensi]['denda'] !== null ? $d[$tanggal_presensi]['denda'] : null; if ($denda_dari_db !== null) { // Denda sudah dikunci, gunakan dari DB $denda = $denda_dari_db; // Potongan jam tetap dihitung dengan 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']; } } else { $potongan_jam_terlambat = 0; } } else { // Belum dikunci → gunakan rumus hitungdenda seperti biasa 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; } } else { $potongan_jam_terlambat = 0; $denda = 0; } } $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; $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; @endphp @elseif($d[$tanggal_presensi]['status'] == 'i') @php $potongan_jam = $d[$tanggal_presensi]['total_jam']; // Izin: jika denda sudah dikunci, ambil dari DB, jika tidak 0 $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; @endphp @elseif($d[$tanggal_presensi]['status'] == 'a') @php $potongan_jam = $d[$tanggal_presensi]['total_jam']; // Alpa: jika denda sudah dikunci, ambil dari DB, jika tidak 0 $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; @endphp @endif @else @php // Tidak ada data presensi di tanggal ini // Jika hari libur, tidak ada potongan jam if (empty($ceklibur)) { // Bukan libur → cek jadwal berurutan (sama seperti presensi_cetak & gaji_cetak) // 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) { $nama_hari = getHari($tanggal_presensi); $totalJamJadwal = $mapJadwalByDay[$nama_hari] ?? null; } // 4) Kalau masih kosong, cek jadwal by-day per departemen & cabang if ($totalJamJadwal === null) { $nama_hari = isset($nama_hari) ? $nama_hari : getHari($tanggal_presensi); $keyDeptCabang = $d['kode_dept'] . '|' . $d['kode_cabang']; $mapDept = $jadwal_bydept[$keyDeptCabang] ?? []; $totalJamJadwal = $mapDept[$nama_hari] ?? null; } // Jika ada jadwal tapi tidak ada presensi sama sekali → potongan jam = total_jam jadwal $is_future = strtotime($tanggal_presensi) > strtotime(date('Y-m-d')); if ($totalJamJadwal !== null && !$is_future) { $potongan_jam = is_array($totalJamJadwal) ? $totalJamJadwal['total_jam'] : $totalJamJadwal; } } @endphp @endif @php $total_denda += $denda; $total_potongan_jam += $potongan_jam; $tanggal_presensi = date('Y-m-d', strtotime('+1 day', strtotime($tanggal_presensi))); @endphp @endwhile @php // Final calculations if ($generalsetting->status_potongan_jam == 0) { $total_potongan_jam = 0; } elseif ($total_potongan_jam > $generalsetting->total_jam_bulan) { $total_potongan_jam = $generalsetting->total_jam_bulan; } $jumlah_potongan_jam = ROUND($upah_perjam) * $total_potongan_jam; $total_potongan = ROUND($jumlah_potongan_jam) + $total_denda + $d['bpjs_kesehatan'] + $d['bpjs_tenagakerja'] + ($d['cicilan_pinjaman'] ?? 0); @endphp @endforeach
@foreach ($laporan_presensi as $d) @php $tanggal_presensi = $periode_dari; $total_denda = 0; $total_potongan_jam = 0; $total_tunjangan = 0; $total_jam_lembur_aktual = 0; $total_jam_netto_lembur = 0; $total_nominal_lembur_snapshot = 0; $has_lembur_snapshot = false; $lemburKhusus = $lembur_khusus_map[$d['nik']] ?? null; // Mapping jadwal untuk NIK ini dari berbagai sumber (sama seperti presensi_cetak & gaji_cetak) $mapJadwalByDate = $jadwal_bydate[$d['nik']] ?? []; $mapJadwalGrupByDate = $jadwal_grup_bydate[$d['nik']] ?? []; $mapJadwalByDay = $jadwal_byday[$d['nik']] ?? []; // Kalkulasi tunjangan foreach ($jenis_tunjangan as $j) { $total_tunjangan += $d[$j->kode_jenis_tunjangan]; } // Kalkulasi bruto $bruto = $d['gaji_pokok'] + $total_tunjangan; // Kalkulasi upah per jam $upah_perjam = $d['gaji_pokok'] / $generalsetting->total_jam_bulan; @endphp {{-- Proses kalkulasi denda dan potongan jam --}} @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_check = getHari($tanggal_presensi); if (isset($mapJadwalByDate[$tanggal_presensi])) $has_schedule = true; elseif (isset($mapJadwalGrupByDate[$tanggal_presensi])) $has_schedule = true; elseif (isset($mapJadwalByDay[$nama_hari_check])) $has_schedule = true; else { $keyDC = $d['kode_dept'] . '|' . $d['kode_cabang']; $mapD = $jadwal_bydept[$keyDC] ?? []; if (isset($mapD[$nama_hari_check])) $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) { $has_lembur_snapshot = true; $jml_jam_lembur = $d[$tanggal_presensi]['jam_lembur_aktual']; $jam_netto_harian = $d[$tanggal_presensi]['jam_lembur_netto']; $total_nominal_lembur_snapshot += $d[$tanggal_presensi]['nominal_lembur'] ?? 0; } else { $lembur_aktual = hitungLembur($ceklembur_data); if ($lembur_aktual > 0) { $jml_jam_lembur = $lembur_aktual; $jam_netto_harian = hitungJamNetto($lembur_aktual, $tipe_hari); } else { $jml_jam_lembur = 0; $jam_netto_harian = 0; } } // 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 $jam_masuk = $tanggal_presensi . ' ' . $d[$tanggal_presensi]['jam_masuk']; $terlambat = hitungjamterlambat($d[$tanggal_presensi]['jam_in'], $jam_masuk); // Jika denda sudah dikunci di database, gunakan nilai tersebut $denda_dari_db = isset($d[$tanggal_presensi]['denda']) && $d[$tanggal_presensi]['denda'] !== null ? $d[$tanggal_presensi]['denda'] : null; if ($denda_dari_db !== null) { // Denda sudah dikunci, gunakan dari DB $denda = $denda_dari_db; // Potongan jam tetap dihitung dengan 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']; } } else { $potongan_jam_terlambat = 0; } } else { // Belum dikunci → gunakan rumus hitungdenda seperti biasa 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; } } else { $potongan_jam_terlambat = 0; $denda = 0; } } $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; $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; @endphp @elseif($d[$tanggal_presensi]['status'] == 'i') @php $potongan_jam = $d[$tanggal_presensi]['total_jam']; // Izin: jika denda sudah dikunci, ambil dari DB, jika tidak 0 $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; @endphp @elseif($d[$tanggal_presensi]['status'] == 'a') @php $potongan_jam = $d[$tanggal_presensi]['total_jam']; // Alpa: jika denda sudah dikunci, ambil dari DB, jika tidak 0 $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; @endphp @endif @else @php // Tidak ada data presensi di tanggal ini // Jika hari libur, tidak ada potongan jam if (empty($ceklibur)) { // Bukan libur → cek jadwal berurutan (sama seperti presensi_cetak & gaji_cetak) // 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) { $nama_hari = getHari($tanggal_presensi); $totalJamJadwal = $mapJadwalByDay[$nama_hari] ?? null; } // 4) Kalau masih kosong, cek jadwal by-day per departemen & cabang if ($totalJamJadwal === null) { $nama_hari = isset($nama_hari) ? $nama_hari : getHari($tanggal_presensi); $keyDeptCabang = $d['kode_dept'] . '|' . $d['kode_cabang']; $mapDept = $jadwal_bydept[$keyDeptCabang] ?? []; $totalJamJadwal = $mapDept[$nama_hari] ?? null; } // Jika ada jadwal tapi tidak ada presensi sama sekali → potongan jam = total_jam jadwal $is_future = strtotime($tanggal_presensi) > strtotime(date('Y-m-d')); if ($totalJamJadwal !== null && !$is_future) { $potongan_jam = is_array($totalJamJadwal) ? $totalJamJadwal['total_jam'] : $totalJamJadwal; } } @endphp @endif @php $status_potongan_harian = isset($d[$tanggal_presensi]['status_potongan']) ? $d[$tanggal_presensi]['status_potongan'] : $generalsetting->status_potongan_jam; if ($status_potongan_harian == 0) { $potongan_jam = 0; } $total_denda += $denda; $total_potongan_jam += $potongan_jam; $total_jam_lembur_aktual += $jml_jam_lembur; $total_jam_netto_lembur += $jam_netto_harian; $tanggal_presensi = date('Y-m-d', strtotime('+1 day', strtotime($tanggal_presensi))); @endphp @endwhile @php // Final calculations if ($total_potongan_jam > $generalsetting->total_jam_bulan) { $total_potongan_jam = $generalsetting->total_jam_bulan; } $jumlah_potongan_jam = ROUND($upah_perjam) * $total_potongan_jam; $total_potongan = ROUND($jumlah_potongan_jam) + $total_denda + $d['bpjs_kesehatan'] + $d['bpjs_tenagakerja'] + ($d['cicilan_pinjaman'] ?? 0); $gaji_bersih = $d['gaji_pokok'] + $total_tunjangan - $total_potongan + $d['penambah'] - $d['pengurang']; @endphp
{{ $generalsetting->nama_perusahaan }}
SLIP GAJI
{{ date('d/m/Y', strtotime($periode_dari)) }} - {{ date('d/m/Y', strtotime($periode_sampai)) }}
NIK: {{ $d['nik_show'] ?? $d['nik'] }}
Nama: {{ $d['nama_karyawan'] }}
Jabatan: {{ $d['nama_jabatan'] }}
Dept: {{ $d['kode_dept'] }}
{{ $generalsetting->total_jam_bulan }} jam | Rp {{ number_format($upah_perjam, 0, ',', '.') }}/jam | {{ number_format($total_potongan_jam, 2) }} jam potong
PENGHASILAN
Gaji Pokok {{ number_format($d['gaji_pokok'], 0, ',', '.') }}
@foreach ($jenis_tunjangan as $j) @if ($d[$j->kode_jenis_tunjangan] > 0)
{{ $j->jenis_tunjangan }} {{ number_format($d[$j->kode_jenis_tunjangan], 0, ',', '.') }}
@endif @endforeach @if ($total_jam_netto_lembur > 0 || $total_jam_lembur_aktual > 0)
@if ($lemburKhusus) Lembur ({{ formatAngkaDesimal($total_jam_lembur_aktual) }}) jam ★ @else Lembur ({{ formatAngkaDesimal($total_jam_netto_lembur) }}) jam @endif @php if ($has_lembur_snapshot) { $upah_lembur = $total_nominal_lembur_snapshot; } elseif ($lemburKhusus) { $upah_lembur = $lemburKhusus->upah_perjam * $total_jam_lembur_aktual; } else { $upah_perjam_lembur = ($d['gaji_pokok'] + $total_tunjangan) / ($generalsetting->total_jam_bulan ?: 173); $upah_lembur = ROUND($upah_perjam_lembur) * $total_jam_netto_lembur; } @endphp {{ formatAngka($upah_lembur) }}
@else @php $upah_lembur = 0; @endphp @endif
Sub Total @php $bruto_total = $bruto + ROUND($upah_lembur); @endphp {{ number_format($bruto_total, 0, ',', '.') }}
POTONGAN
@if ($total_denda > 0)
Denda {{ number_format($total_denda, 0, ',', '.') }}
@endif @if ($jumlah_potongan_jam > 0)
Pot. Jam ({{ number_format($total_potongan_jam, 2) }}) {{ number_format($jumlah_potongan_jam, 0, ',', '.') }}
@endif @if ($d['bpjs_kesehatan'] > 0)
BPJS Kes {{ number_format($d['bpjs_kesehatan'], 0, ',', '.') }}
@endif @if ($d['bpjs_tenagakerja'] > 0)
BPJS TK {{ number_format($d['bpjs_tenagakerja'], 0, ',', '.') }}
@endif @if (($d['cicilan_pinjaman'] ?? 0) > 0)
Pinjaman {{ number_format($d['cicilan_pinjaman'], 0, ',', '.') }}
@endif
Sub Total {{ number_format($total_potongan, 0, ',', '.') }}
@if ($d['penambah'] > 0 || $d['pengurang'] > 0)
PENYESUAIAN
@if ($d['penambah'] > 0)
Penambah {{ number_format($d['penambah'], 0, ',', '.') }}
@endif @if ($d['pengurang'] > 0)
Pengurang {{ number_format($d['pengurang'], 0, ',', '.') }}
@endif @endif
GAJI BERSIH @php $gaji_bersih = $d['gaji_pokok'] + $total_tunjangan - $total_potongan + $d['penambah'] - $d['pengurang'] + ROUND($upah_lembur); @endphp {{ number_format($gaji_bersih, 0, ',', '.') }}
@endforeach