@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);
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'];
@endphp
@elseif($d[$tanggal_presensi]['status'] == 'a')
@php
$potongan_jam = $d[$tanggal_presensi]['total_jam'];
@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
NIK:
{{ $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, 1) }} 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)
@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, ',', '.') }}