@extends('layouts.adminlte') @section('title', 'Budget Payroll Harian') @section('page_title', 'Budget Payroll Harian') @push('styles') @endpush @section('content') @php $rows = collect($detail['rows'] ?? []); $costRows = collect($costDetail['rows'] ?? []); $costSummary = (array) ($costDetail['summary'] ?? []); $detailColumns = collect($detail['columns'] ?? []); $costRowsForColumns = $costRows; $dynamicOtKeys = $costRowsForColumns ->flatMap(fn ($row) => array_keys((array) ($row['ot_values'] ?? []))) ->filter(fn ($key) => is_numeric($key)) ->map(fn ($key) => rtrim(rtrim(number_format((float) $key, 1, '.', ''), '0'), '.')) ->unique() ->sortBy(fn ($key) => (float) $key) ->values(); if ($dynamicOtKeys->isEmpty()) { $dynamicOtKeys = $detailColumns ->pluck('key') ->filter(fn ($key) => is_numeric($key) && (float) $key > 0) ->map(fn ($key) => rtrim(rtrim(number_format((float) $key, 1, '.', ''), '0'), '.')) ->unique() ->sortBy(fn ($key) => (float) $key) ->values(); } $columns = $dynamicOtKeys ->map(fn ($key) => [ 'key' => (string) $key, 'label' => rtrim(rtrim(number_format(((float) $key) * 100, 1, ',', ''), '0'), ',') . '%', ]) ->values(); $summary = (array) ($detail['summary'] ?? []); $otSummary = (array) ($summary['ot_values'] ?? []); $fmt = fn ($value, $digits = 2) => number_format((float) ($value ?? 0), $digits, ',', '.'); $rupiah = fn ($value) => 'Rp ' . number_format((float) ($value ?? 0), 0, ',', '.'); $dashFmt = fn ($value, $digits = 2) => abs((float) ($value ?? 0)) > 0.00001 ? number_format((float) $value, $digits, ',', '.') : '-'; $dashRupiah = fn ($value) => abs((float) ($value ?? 0)) > 0.00001 ? ('Rp ' . number_format((float) $value, 0, ',', '.')) : '-'; $personalCostColumnCount = 22 + $columns->count(); $dateLabel = $date instanceof \Carbon\Carbon ? $date->format('Y-m-d') : (string) ($detail['date'] ?? '-'); $detailNet = (float) ($budget['net'] ?? 0); $detailGross = (float) ($budget['gross'] ?? 0); if ($detailGross < $detailNet) { $detailGross = $detailNet; } $totalNormalNominal = (float) ($summary['estimasi_gaji_normal'] ?? 0); $totalOvertimeNominal = (float) ($summary['estimasi_lembur'] ?? 0); $payrollRowsByEmployee = $rows->keyBy(fn ($row) => (int) ($row['karyawan_id'] ?? 0)); $attendanceBaseNominal = (float) ($budget['net_hadir'] ?? 0) + (float) ($budget['net_leave_paid'] ?? 0); if ((float) ($costSummary['net'] ?? 0) > 0) { $attendanceBaseNominal = (float) ($costSummary['net'] ?? 0); $detailNet = $attendanceBaseNominal; $detailGross = max($detailGross, $attendanceBaseNominal); } elseif ($attendanceBaseNominal <= 0) { $attendanceBaseNominal = $detailNet; } $hadirCount = (int) ($costSummary['hadir'] ?? $budget['hadir_count'] ?? 0); $leavePaidCount = (int) ($costSummary['leave_paid'] ?? $budget['leave_paid_count'] ?? 0); $leaveUnpaidCount = $costRows->where('category', 'leaveNoPay')->count(); $alphaCount = (int) ($costSummary['alpha'] ?? $budget['alpha_count'] ?? 0); $paidAttendanceCount = $hadirCount + $leavePaidCount; $actualEmployeeCount = (int) ($summary['employees'] ?? 0); if ($actualEmployeeCount <= 0) { $actualEmployeeCount = (int) ($costSummary['paid'] ?? $budget['employee_count'] ?? 0); } $groupedCostRows = $costRows ->map(function ($row) use ($payrollRowsByEmployee) { $row = (array) $row; $otRow = (array) ($payrollRowsByEmployee[(int) ($row['karyawan_id'] ?? 0)] ?? []); $hasCalculationRow = !empty($otRow); $row['display_rate_harian'] = round((float) ($row['rate_harian'] ?? 0), 2); $row['display_normal_cost'] = round((float) ($row['normal_cost'] ?? 0), 2); $row['display_norest_cost'] = round((float) ($row['norest_cost'] ?? 0), 2); $row['display_target_cost'] = round((float) ($row['target_cost'] ?? 0), 2); $row['display_continues_cost'] = round((float) ($row['continues_cost'] ?? 0), 2); $row['display_overtime_cost'] = max(0, round((float) ($row['overtime_cost'] ?? 0), 2)); $row['display_subtotal_cost'] = max(0, round((float) $row['display_normal_cost'] + (float) $row['display_norest_cost'] + (float) $row['display_overtime_cost'] + (float) $row['display_target_cost'] + (float) $row['display_continues_cost'], 2)); $hasActual = trim((string) ($row['checkin_time'] ?? '')) !== '' && trim((string) ($row['checkin_time'] ?? '')) !== '-'; $hasCost = (float) ($row['display_subtotal_cost'] ?? 0) > 0; $row['display_sort_bucket'] = ($hasActual || $hasCost) ? 0 : 1; $row['display_group'] = !empty($row['is_leave_paid']) ? 'Leave Paid' : ((string) ($row['category'] ?? '') === 'leaveNoPay' ? 'Leave Unpaid' : (!empty($row['is_alpha']) ? 'Alpha / No Paid' : 'Hadir')); return $row; }) ->sortBy(function ($row) { $order = ['Hadir' => 1, 'Leave Paid' => 2, 'Leave Unpaid' => 3, 'Alpha / No Paid' => 4]; return ($order[(string) ($row['display_group'] ?? '')] ?? 5) . '|' . (int) ($row['display_sort_bucket'] ?? 1) . '|' . sprintf('%012.2f', 999999999 - (float) ($row['display_subtotal_cost'] ?? 0)) . '|' . ($row['nama_karyawan'] ?? ''); }, SORT_NATURAL | SORT_FLAG_CASE) ->groupBy('display_group'); $flatGroupedCostRows = $groupedCostRows->flatten(1); $personalNormalTotal = (float) $flatGroupedCostRows->sum('display_normal_cost'); $personalNoRestTotal = (float) $flatGroupedCostRows->sum('display_norest_cost'); $personalOvertimeTotal = (float) $flatGroupedCostRows->sum('display_overtime_cost'); $personalTargetTotal = (float) $flatGroupedCostRows->sum('display_target_cost'); $personalContinuesTotal = (float) $flatGroupedCostRows->sum('display_continues_cost'); $personalSubtotalTotal = (float) $flatGroupedCostRows->sum('display_subtotal_cost'); @endphp
Profil {{ request('profil_bulan_id') }} | {{ $dateLabel }}
Budget Payroll {{ $dateLabel }}
Rincian actual hadir harian. Halaman ini tidak dipotong pagination, jadi seluruh karyawan approved pada tanggal tersebut ikut tampil.
Kembali Dashboard
Mode
{{ $budget['label'] ?: '-' }}
{{ $budget['mode'] ?: 'actual/estimate' }}
Net Harian
{{ $rupiah($detailNet) }}
Budget dari widget payroll
Bruto Harian
{{ $rupiah($detailGross) }}
Sebelum PPh21/BPJS
Karyawan Actual
{{ number_format($actualEmployeeCount, 0, ',', '.') }}
Widget: {{ number_format((int) ($budget['employee_count'] ?? 0), 0, ',', '.') }} karyawan dihitung
Hadir Dibayar
{{ number_format($hadirCount, 0, ',', '.') }}
Gaji harian tanpa lembur.
Leave Paid
{{ number_format($leavePaidCount, 0, ',', '.') }}
Tetap masuk cost harian.
Alpha
{{ number_format($alphaCount, 0, ',', '.') }}
Tidak dihitung nominal.
Basis Dibayar
{{ number_format($paidAttendanceCount, 0, ',', '.') }}
Hadir + Leave Paid.
Grand Total Actual Hadir
Hari Hadir
{{ $fmt($summary['hari_hadir'] ?? 0) }}
Rate / Jam
{{ $rupiah($summary['rate_gaji_per_jam'] ?? 0) }}
Jam Normal
{{ $fmt($summary['jam_normal'] ?? 0) }}
Jam Lembur xKali
{{ $fmt($summary['jam_lembur_xkali'] ?? 0) }}
Gaji Harian Tanpa Lembur
{{ $rupiah($attendanceBaseNominal) }}
Gaji Harian + Lembur Approved
{{ $rupiah($personalSubtotalTotal ?: ($attendanceBaseNominal + $totalOvertimeNominal)) }}
PPh21
{{ $rupiah($budget['pph21'] ?? 0) }}
BPJS
{{ $rupiah($budget['bpjs'] ?? 0) }}
Pembanding Planning Normal
Planning normal {{ $rupiah($budget['planning_net'] ?? 0) }}
Bruto normal {{ $rupiah($budget['planning_gross'] ?? 0) }}
Potensi OT dikeluarkan {{ $rupiah($budget['overtime_removed'] ?? 0) }}
Planning dipakai sebagai pembanding jika semua karyawan masuk normal tanpa lembur.
Drilldown Personal Cost Harian
Hadir {{ number_format($hadirCount, 0, ',', '.') }} | Leave paid {{ number_format($leavePaidCount, 0, ',', '.') }} | Leave unpaid {{ number_format($leaveUnpaidCount, 0, ',', '.') }} | Alpha {{ number_format($alphaCount, 0, ',', '.') }} | Basis dibayar {{ number_format($paidAttendanceCount, 0, ',', '.') }}
{{ number_format($costRows->count(), 0, ',', '.') }} row
@foreach ($columns as $col) @endforeach @forelse ($groupedCostRows as $groupName => $groupRows) @foreach ($groupRows as $row) @php $rowClass = !empty($row['is_alpha']) || (string) ($row['category'] ?? '') === 'leaveNoPay' ? 'table-danger' : (!empty($row['is_leave_paid']) ? 'table-warning' : ''); if ((float) ($row['rate_harian'] ?? 0) <= 0 && empty($row['is_alpha']) && (string) ($row['category'] ?? '') !== 'leaveNoPay') { $rowClass = 'table-secondary'; } $otRow = (array) ($payrollRowsByEmployee[(int) ($row['karyawan_id'] ?? 0)] ?? []); $hasCalculationRow = !empty($otRow); $otValues = (array) ($hasCalculationRow ? ($otRow['ot_values'] ?? []) : ($row['ot_values'] ?? [])); $normalCost = (float) ($row['display_normal_cost'] ?? 0); $noRestCost = (float) ($row['display_norest_cost'] ?? 0); $overtimeCost = (float) ($row['display_overtime_cost'] ?? 0); $targetCost = (float) ($row['display_target_cost'] ?? 0); $continuesCost = (float) ($row['display_continues_cost'] ?? 0); $totalOneDay = (float) ($row['display_subtotal_cost'] ?? ($normalCost + $noRestCost + $overtimeCost + $targetCost + $continuesCost)); $jamLemburBersih = (float) ($hasCalculationRow ? ($otRow['jam_lembur_bersih'] ?? 0) : ($row['spl_hours_normal'] ?? 0)); $jamLemburXKali = $overtimeCost > 0 && (float) ($row['rate_per_jam'] ?? 0) > 0 ? ($overtimeCost / (float) ($row['rate_per_jam'] ?? 1)) : 0.0; $dayTypeLabel = match ((string) ($row['day_type'] ?? 'workday')) { 'weekend' => 'Weekend', 'holiday' => 'Holiday', 'holiday_special' => 'Holiday Special', default => 'Workday', }; @endphp @foreach ($columns as $col) @php $key = (string) ($col['key'] ?? ''); @endphp @endforeach @endforeach @empty @endforelse
No. Karyawan Kode Finger Jabatan Jenis Hari Basis HK Plan Jam Actual In Actual Out Status Rate Harian Rate / Jam Upah 1 Day Cost Upah 1HK Jam Lembur Bersih{{ $col['label'] ?? '-' }}Jam Lembur xKali Cost NoRest Cost OVT Cost Target Cost Continues Workdays Sub Total 1 Day
{{ $groupName }} - {{ number_format($groupRows->count(), 0, ',', '.') }} orang
{{ number_format($loop->parent->iteration, 0, ',', '.') }}.{{ number_format($loop->iteration, 0, ',', '.') }} {{ $row['nama_karyawan'] ?? '-' }} {{ $row['id_finger'] ?? '-' }} {{ $row['jabatan'] ?? '-' }} {{ $row['jenis_pekerja'] ?? '-' }} {{ $dayTypeLabel }} {{ $row['work_basis'] ?? '-' }} {{ $row['shift'] ?? '-' }} {{ $row['checkin_time'] ?? '-' }} {{ $row['checkout_time'] ?? '-' }} {{ $row['status'] ?? '-' }} @if (!empty($row['spl_badge_label'])) {{ $row['spl_badge_label'] }} @endif {{ $rupiah($row['display_rate_harian'] ?? 0) }} @if ((float) ($row['rate_harian'] ?? 0) <= 0 && empty($row['is_alpha']) && (string) ($row['category'] ?? '') !== 'leaveNoPay') rate kosong @endif {{ $dashRupiah($row['rate_per_jam'] ?? 0) }} {{ $rupiah($normalCost) }} {{ $dashRupiah($normalCost) }} {{ $dashFmt($jamLemburBersih) }}{{ $dashFmt($otValues[$key] ?? $otValues[number_format((float) $key, 1, '.', '')] ?? 0) }}{{ $dashFmt($jamLemburXKali) }} {{ $dashRupiah($noRestCost) }} {{ $dashRupiah($overtimeCost) }} {{ $dashRupiah($targetCost) }} {{ $dashRupiah($continuesCost) }} {{ $rupiah($totalOneDay) }}
Belum ada data personal cost untuk tanggal ini.
Grand Total Cost Harian {{ $dashRupiah($personalNormalTotal) }} {{ $dashRupiah($personalNoRestTotal) }} {{ $dashRupiah($personalOvertimeTotal) }} {{ $dashRupiah($personalTargetTotal) }} {{ $dashRupiah($personalContinuesTotal) }} {{ $rupiah($personalSubtotalTotal) }}
Rincian Actual Hadir
{{ $dateLabel }} | {{ number_format((int) ($summary['employees'] ?? 0), 0, ',', '.') }} karyawan | Hari hadir {{ $fmt($summary['hari_hadir'] ?? 0) }} | Jam normal {{ $fmt($summary['jam_normal'] ?? 0) }} | Lembur bersih {{ $fmt($summary['jam_lembur_bersih'] ?? 0) }}
@if (!request()->boolean('with_actual_detail')) Muat rincian actual @else {{ number_format($rows->count(), 0, ',', '.') }} row @endif
@foreach ($columns as $col) @endforeach @forelse ($rows as $row) @foreach ($columns as $col) @php $key = (string) ($col['key'] ?? ''); @endphp @endforeach @empty @endforelse @foreach ($columns as $col) @php $key = (string) ($col['key'] ?? ''); @endphp @endforeach
No. Karyawan Hari Hadir Rate Gaji / Jam Jam Normal Jam Lembur Bersih{{ $col['label'] ?? $col['key'] ?? '-' }}Jam Lembur xKali Est. Gaji Normal Est. Lembur
{{ number_format((int) ($row['no'] ?? $loop->iteration), 0, ',', '.') }} {{ $row['karyawan'] ?? '-' }} {{ $fmt($row['hari_hadir'] ?? 0) }} {{ $rupiah($row['rate_gaji_per_jam'] ?? 0) }} {{ $fmt($row['jam_normal'] ?? 0) }} {{ $fmt($row['jam_lembur_bersih'] ?? 0) }}{{ $fmt(($row['ot_values'] ?? [])[$key] ?? 0) }}{{ $fmt($row['jam_lembur_xkali'] ?? 0) }} {{ $rupiah($row['estimasi_gaji_normal'] ?? 0) }} {{ $rupiah($row['estimasi_lembur'] ?? 0) }}
@if (!request()->boolean('with_actual_detail')) Rincian actual belum dimuat agar halaman cost cepat dibuka. @else Belum ada actual hadir approved pada tanggal ini. @endif
Grand Total {{ $fmt($summary['hari_hadir'] ?? 0) }} {{ $rupiah($summary['rate_gaji_per_jam'] ?? 0) }} {{ $fmt($summary['jam_normal'] ?? 0) }} {{ $fmt($summary['jam_lembur_bersih'] ?? 0) }}{{ $fmt($otSummary[$key] ?? 0) }}{{ $fmt($summary['jam_lembur_xkali'] ?? 0) }} {{ $rupiah($summary['estimasi_gaji_normal'] ?? 0) }} {{ $rupiah($summary['estimasi_lembur'] ?? 0) }}
@endsection @push('scripts') @endpush