@php $dashboardDailyCostRowsSource = is_array($dashboardDailyCostRows ?? null) ? $dashboardDailyCostRows : []; $expenseDailyBudgetSource = is_array($payrollExpenseWidget['daily_budget'] ?? null) ? $payrollExpenseWidget['daily_budget'] : []; $expenseDailyByDate = collect($expenseDailyBudgetSource)->keyBy(fn ($row) => (string) ($row['date'] ?? '')); $attendanceDates = is_array($dashSeries['dates'] ?? null) ? $dashSeries['dates'] : []; $attendanceOnTime = is_array($morningSeries['checkin_ontime'] ?? null) ? $morningSeries['checkin_ontime'] : []; $attendanceLatePre = is_array($morningSeries['checkin_late_precheck'] ?? null) ? $morningSeries['checkin_late_precheck'] : []; $attendanceLateGrace = is_array($morningSeries['checkin_late_grace'] ?? null) ? $morningSeries['checkin_late_grace'] : []; $attendanceNonShift = is_array($morningSeries['checkin_nonshift'] ?? null) ? $morningSeries['checkin_nonshift'] : []; $attendanceWeekendHoliday = is_array($morningSeries['checkin_lembur'] ?? null) ? $morningSeries['checkin_lembur'] : []; $attendanceCuti = is_array($morningSeries['cuti'] ?? null) ? $morningSeries['cuti'] : []; $attendanceSick = is_array($morningSeries['sick'] ?? null) ? $morningSeries['sick'] : []; $attendanceAlpha = is_array($morningSeries['missing_checkin_due'] ?? null) ? $morningSeries['missing_checkin_due'] : []; $estimateCount = max(1, (int) ($payrollExpenseWidget['estimate_count'] ?? 0)); $fallbackDailyEmployeeCost = (float) ($payrollExpenseWidget['estimate_net'] ?? 0) > 0 ? ((float) ($payrollExpenseWidget['estimate_net'] ?? 0) / $estimateCount / max(1, count($expenseDailyBudgetSource))) : 0.0; $dailyCostRows = $dashboardDailyCostRowsSource; foreach ($attendanceDates as $i => $attendanceDate) { if ($dashboardDailyCostRowsSource !== []) { break; } $sourceBudget = (array) ($expenseDailyByDate->get((string) $attendanceDate) ?? ($expenseDailyBudgetSource[$i] ?? [])); $hadirCount = (int) (($attendanceOnTime[$i] ?? 0) + ($attendanceLatePre[$i] ?? 0) + ($attendanceLateGrace[$i] ?? 0) + ($attendanceNonShift[$i] ?? 0) + ($attendanceWeekendHoliday[$i] ?? 0)); $leavePaidCount = (int) (($attendanceCuti[$i] ?? 0) + ($attendanceSick[$i] ?? 0)); $alphaCount = (int) ($attendanceAlpha[$i] ?? 0); $paidCount = $hadirCount + $leavePaidCount; $sourceEmployeeCount = max(1, (int) ($sourceBudget['employee_count'] ?? 0)); $employeeCostPerDay = (float) ($sourceBudget['net'] ?? 0) > 0 ? ((float) ($sourceBudget['net'] ?? 0) / $sourceEmployeeCount) : $fallbackDailyEmployeeCost; $pph21PerDay = (float) ($sourceBudget['pph21'] ?? 0) > 0 ? ((float) ($sourceBudget['pph21'] ?? 0) / $sourceEmployeeCount) : 0.0; $bpjsPerDay = (float) ($sourceBudget['bpjs'] ?? 0) > 0 ? ((float) ($sourceBudget['bpjs'] ?? 0) / $sourceEmployeeCount) : 0.0; $reimbursePerDay = (float) ($sourceBudget['reimburse'] ?? 0) > 0 ? ((float) ($sourceBudget['reimburse'] ?? 0) / $sourceEmployeeCount) : 0.0; $dailyCostRows[] = array_merge($sourceBudget, [ 'date' => (string) $attendanceDate, 'day' => substr((string) $attendanceDate, -2), 'mode' => (string) ($sourceBudget['mode'] ?? 'attendance_based'), 'label' => 'Attendance cost: hadir + leave paid, alpha tidak dibayar', 'employee_count' => $paidCount, 'hadir_count' => $hadirCount, 'leave_paid_count' => $leavePaidCount, 'alpha_count' => $alphaCount, 'net' => round($employeeCostPerDay * $paidCount, 2), 'net_hadir' => round($employeeCostPerDay * $hadirCount, 2), 'net_leave_paid' => round($employeeCostPerDay * $leavePaidCount, 2), 'pph21' => round($pph21PerDay * $paidCount, 2), 'bpjs' => round($bpjsPerDay * $paidCount, 2), 'reimburse' => round($reimbursePerDay * $paidCount, 2), ]); } if (empty($dailyCostRows)) { $dailyCostRows = $expenseDailyBudgetSource; } $dailyCostMax = 1.0; $dailyCostTotals = [ 'grand' => 0.0, 'employee' => 0.0, 'pph21' => 0.0, 'bpjs' => 0.0, 'reimburse' => 0.0, ]; $dailyCostActiveDays = 0; $dailyCostActualDays = 0; $dailyCostEstimateDays = 0; foreach ($dailyCostRows as $costRow) { $employeeCost = max(0.0, (float) ($costRow['net'] ?? 0)); $pph21Cost = max(0.0, (float) ($costRow['pph21'] ?? 0)); $bpjsCost = max(0.0, (float) ($costRow['bpjs'] ?? 0)); $reimburseCost = max(0.0, (float) ($costRow['reimburse'] ?? 0)); $grandCost = $employeeCost + $pph21Cost + $bpjsCost + $reimburseCost; $dailyCostMax = max($dailyCostMax, $grandCost); $dailyCostTotals['grand'] += $grandCost; $dailyCostTotals['employee'] += $employeeCost; $dailyCostTotals['pph21'] += $pph21Cost; $dailyCostTotals['bpjs'] += $bpjsCost; $dailyCostTotals['reimburse'] += $reimburseCost; if (!empty($costRow['is_workday']) || $grandCost > 0) { $dailyCostActiveDays++; } if (($costRow['mode'] ?? '') === 'actual') { $dailyCostActualDays++; } else { $dailyCostEstimateDays++; } } $dailyCostAvg = $dailyCostActiveDays > 0 ? $dailyCostTotals['grand'] / $dailyCostActiveDays : 0.0; $dailyCostShort = function (float $value): string { if ($value >= 1000000000) return 'Rp ' . number_format($value / 1000000000, 1, ',', '.') . 'M'; if ($value >= 1000000) return 'Rp ' . number_format($value / 1000000, 1, ',', '.') . 'Jt'; if ($value >= 1000) return 'Rp ' . number_format($value / 1000, 0, ',', '.') . 'Rb'; return 'Rp ' . number_format($value, 0, ',', '.'); }; @endphp

Cost Per Hari

Daily cost breakdown dari payroll planning periode terpilih.
@if ($builderMode)
@endif
Daily Cost Overview
{{ $payrollExpenseWidget['profil_code'] ?? '-' }} @if (!empty($payrollExpenseWidget['period_start']) && !empty($payrollExpenseWidget['period_end'])) | {{ $payrollExpenseWidget['period_start'] }} s/d {{ $payrollExpenseWidget['period_end'] }} @endif
{{ number_format($dailyCostActualDays) }} actual / {{ number_format($dailyCostEstimateDays) }} estimasi
Rata-rata Cost / Day
{{ $dailyCostShort($dailyCostAvg) }}
Per tanggal - klik bar untuk detail karyawan dan komponen cost.
@if (!empty($dailyCostRows)) @php $dailyCostChartRows = collect($dailyCostRows)->map(function ($costRow) use ($dailyCostShort, $payrollExpenseWidget) { $employeeCost = max(0.0, (float) ($costRow['net'] ?? 0)); $hadirCost = max(0.0, (float) ($costRow['net_hadir'] ?? $employeeCost)); $leavePaidCost = max(0.0, (float) ($costRow['net_leave_paid'] ?? 0)); $pph21Cost = max(0.0, (float) ($costRow['pph21'] ?? 0)); $bpjsCost = max(0.0, (float) ($costRow['bpjs'] ?? 0)); $reimburseCost = max(0.0, (float) ($costRow['reimburse'] ?? 0)); $grandCost = $employeeCost + $pph21Cost + $bpjsCost + $reimburseCost; $dateText = (string) ($costRow['date'] ?? ''); $dayName = $dateText !== '' ? \Carbon\Carbon::parse($dateText)->locale('id')->isoFormat('ddd') : ''; $payload = array_merge([ 'kind' => 'payroll_daily_budget', 'profil_bulan_id' => (int) ($payrollExpenseWidget['profil_id'] ?? 0), 'grand_total' => round($grandCost, 2), ], $costRow); return [ 'label' => trim($dayName . ' ' . (string) ($costRow['day'] ?? '')), 'date' => $dateText, 'day_name' => $dayName, 'grand' => round($grandCost, 2), 'employee' => round($employeeCost, 2), 'hadir' => round($hadirCost, 2), 'leave_paid' => round($leavePaidCost, 2), 'pph21' => round($pph21Cost, 2), 'bpjs' => round($bpjsCost, 2), 'reimburse' => round($reimburseCost, 2), 'alpha_count' => (int) ($costRow['alpha_count'] ?? 0), 'hadir_count' => (int) ($costRow['hadir_count'] ?? 0), 'leave_paid_count' => (int) ($costRow['leave_paid_count'] ?? 0), 'is_workday' => !empty($costRow['is_workday']), 'is_today' => !empty($costRow['is_today']), 'short' => $dailyCostShort($grandCost), 'payload' => $payload, ]; })->values()->all(); @endphp
@else
Belum ada data daily payroll. Pilih profil payroll atau generate penggajian dulu.
@endif
LEGENDA
Cost
Grand total per hari

Mode
H = hadir, L = leave paid, A = alpha. Klik bar untuk detail personal.

Estimasi Biaya Overtime

Permintaan SPL dan biaya yang timbul sebelum approve.
@if ($builderMode)
@endif
Total Request0
0 tanpa actual
Overtime Plan0
Planning Jam0,00
Cost PlanningRp 0
Planning xKali0,00
Overtime Actual0
Actual Jam0,00
Cost ActualRp 0
Memuat... Total estimasi: Rp 0
Grafik Harian
Memuat...
Grafik Type Overtime
Memuat...
Type Overtime per Project
Memuat...
No Tanggal Hari Orang Jabatan Type Hari Jenis Lembur Project Jam Aktual / Dibayar Rincian Multiplier Status Biaya
Memuat...
Total halaman 0,00 0,00 Rp 0
Grand total filter 0,00 0,00 Rp 0
Lembur Tanpa SPL 0
0,00 jam
Klik untuk tampilkan daftar pembuatan SPL
Halaman 1
@php $expenseEstimateNet = max(0.0, (float) ($payrollExpenseWidget['estimate_net'] ?? 0)); $expensePaidNet = max(0.0, (float) ($payrollExpenseWidget['period_net'] ?? 0)); $expenseUnpaidNet = max(0.0, (float) ($payrollExpenseWidget['unpaid_net'] ?? max(0, $expenseEstimateNet - $expensePaidNet))); $expenseTotalForChart = max(1.0, $expensePaidNet + $expenseUnpaidNet, $expenseEstimateNet); $expensePaidPct = min(100, round(($expensePaidNet / $expenseTotalForChart) * 100, 2)); $expenseUnpaidPct = min(100, round(($expenseUnpaidNet / $expenseTotalForChart) * 100, 2)); $expenseSource = (string) ($payrollExpenseWidget['estimate_source'] ?? 'paid_only'); $expenseDailyBudget = is_array($payrollExpenseWidget['daily_budget'] ?? null) ? $payrollExpenseWidget['daily_budget'] : []; $expenseDailyMax = 1.0; foreach ($expenseDailyBudget as $dayBudget) { $expenseDailyMax = max($expenseDailyMax, (float) ($dayBudget['net'] ?? 0)); } $expenseActualRunRate = (float) ($payrollExpenseWidget['daily_actual_total'] ?? 0); $expenseEstimateRunRate = (float) ($payrollExpenseWidget['daily_estimate_total'] ?? 0); $expenseOvertimeSaving = (float) ($payrollExpenseWidget['daily_overtime_removed_total'] ?? 0); $expensePlanningNet = !empty($expenseDailyBudget) ? ($expenseActualRunRate + $expenseEstimateRunRate) : $expenseEstimateNet; $expenseTodayBudget = []; foreach ($expenseDailyBudget as $dayBudget) { if (!empty($dayBudget['is_today'])) { $expenseTodayBudget = $dayBudget; break; } } @endphp

Pengeluaran Payroll

{{ $payrollExpenseWidget['profil_code'] ?? '-' }} @if (!empty($payrollExpenseWidget['period_start']) && !empty($payrollExpenseWidget['period_end'])) | {{ $payrollExpenseWidget['period_start'] }} s/d {{ $payrollExpenseWidget['period_end'] }} @endif
@if (!empty($payrollProfilOptions))
@foreach (request()->except('payroll_profil_id') as $key => $value) @if (is_scalar($value)) @endif @endforeach
@endif
@if ($builderMode)
@else @if ($expenseSource === 'payroll_snapshot') Snapshot payroll @elseif ($expenseSource === 'profil_gaji_fast_estimate') Estimasi profil gaji @else Paid only @endif @endif
Budget planning periode berjalan
Rp {{ number_format($expensePlanningNet, 0, ',', '.') }}
Actual H-1 + estimasi H-0 sampai akhir periode tanpa lembur.
Actual H-1
Rp {{ number_format($expenseActualRunRate, 0, ',', '.') }}
H-0 dst tanpa lembur
Rp {{ number_format($expenseEstimateRunRate, 0, ',', '.') }}
Paid Rp {{ number_format($expensePaidNet, 0, ',', '.') }} Belum Rp {{ number_format($expenseUnpaidNet, 0, ',', '.') }}
Estimate bruto
Rp {{ number_format((float) ($payrollExpenseWidget['estimate_gross'] ?? 0), 0, ',', '.') }}
Estimate reimburse
Rp {{ number_format((float) ($payrollExpenseWidget['estimate_reimburse'] ?? 0), 0, ',', '.') }}
Estimate PPh21
Rp {{ number_format((float) ($payrollExpenseWidget['estimate_pph21'] ?? 0), 0, ',', '.') }}
Estimate BPJS
Rp {{ number_format((float) ($payrollExpenseWidget['estimate_bpjs'] ?? 0), 0, ',', '.') }}
Budget Hari Ini
{{ $payrollExpenseWidget['today_date'] ?? now()->format('Y-m-d') }}
Rp {{ number_format((float) ($expenseTodayBudget['net'] ?? $payrollExpenseWidget['today_net'] ?? 0), 0, ',', '.') }}
H-0 estimasi tanpa lembur untuk {{ number_format((int) ($expenseTodayBudget['employee_count'] ?? 0), 0, ',', '.') }} karyawan
Bruto Rp {{ number_format((float) ($expenseTodayBudget['gross'] ?? $payrollExpenseWidget['today_gross'] ?? 0), 0, ',', '.') }}
PPh21 Rp {{ number_format((float) ($expenseTodayBudget['pph21'] ?? $payrollExpenseWidget['today_pph21'] ?? 0), 0, ',', '.') }}
BPJS Rp {{ number_format((float) ($expenseTodayBudget['bpjs'] ?? $payrollExpenseWidget['today_bpjs'] ?? 0), 0, ',', '.') }}
Lembur dikeluarkan Rp {{ number_format((float) ($expenseTodayBudget['overtime_removed'] ?? 0), 0, ',', '.') }}
Estimasi Bayar Harian Satu Periode
Biru = actual s/d H-1, kuning = H-0 dan ke depan tanpa lembur.
Potensi tekan OT Rp {{ number_format($expenseOvertimeSaving, 0, ',', '.') }}
@if (!empty($expenseDailyBudget))
@foreach ($expenseDailyBudget as $dayBudget) @php $dayNet = max(0.0, (float) ($dayBudget['net'] ?? 0)); $dayHeight = min(100, max(0, round(($dayNet / $expenseDailyMax) * 100, 2))); $dayMode = (string) ($dayBudget['mode'] ?? 'estimate_no_overtime'); $dayColor = $dayMode === 'actual' ? '#67e8f9' : '#fbbf24'; $payload = array_merge([ 'kind' => 'payroll_daily_budget', 'profil_bulan_id' => (int) ($payrollExpenseWidget['profil_id'] ?? 0), ], $dayBudget); @endphp
{{ $dayBudget['day'] ?? '' }}
@endforeach
@else
Belum ada data payroll/estimasi untuk membuat grafik harian. Pastikan Profil Bulan punya Profil Gaji aktif, atau buka menu Penggajian lalu klik Tampilkan agar snapshot final periode terbentuk.
@endif
Sumber estimate: @if ($expenseSource === 'payroll_snapshot') snapshot payroll terakhir. @elseif ($expenseSource === 'profil_gaji_fast_estimate') estimasi cepat dari Profil Gaji aktif, belum memasukkan hasil attendance final/lembur real-time. @else data paid saja, snapshot belum tersedia. @endif @if (!empty($payrollExpenseWidget['estimate_generated_at'])) Generate: {{ $payrollExpenseWidget['estimate_generated_at'] }}. @endif Grafik planning memakai rata-rata hari kerja efektif: H-1 sudah mengikuti snapshot aktual, H-0/H+1 dikurangi komponen lembur.