@extends('layouts.adminlte') @section('title', 'DETAIL PENGGAJIAN') @section('page_title', 'DETAIL PENGGAJIAN') @push('styles') @endpush @section('content') @php $dayTypeLabelResolver = static fn (string $dayType): string => match ($dayType) { 'holiday_special' => 'Holiday Special', 'holiday' => 'Holiday', 'weekend' => 'Weekend', default => 'Workday', }; $specialPaymentModeLabelResolver = static fn (?string $mode): string => match (strtolower(trim((string) $mode))) { 'payroll' => 'Gabung Payroll', 'separate' => 'Bayar Terpisah', default => '-', }; $emergencyBaselineLabelResolver = static fn (?string $mode): string => match (strtolower(trim((string) $mode))) { 'after_normal_shift' => 'Setelah jam normal selesai', 'after_normal_or_existing_ot' => 'Setelah jam normal / OT existing selesai', default => trim((string) $mode) !== '' ? trim((string) $mode) : '-', }; $emergencyMultiplierLabelResolver = static fn (?string $profile): string => match (strtolower(trim((string) $profile))) { 'default' => 'Default Emergency x2', default => trim((string) $profile) !== '' ? trim((string) $profile) : '-', }; $workTargetBonusSourceLabelResolver = static fn (?string $source): string => match (strtolower(trim((string) $source))) { 'manual_override' => 'Override manual', 'remaining_target' => 'Sisa target aktual', default => trim((string) $source) !== '' ? trim((string) $source) : '-', }; $dayTypeRowClassResolver = static fn (string $dayType): string => match ($dayType) { 'holiday_special' => 'row-holiday-special', 'holiday' => 'row-holiday', 'weekend' => 'row-weekend', default => '', }; $isHolidayLikeDayType = static fn (string $dayType): bool => in_array($dayType, ['holiday', 'holiday_special'], true); $resolvePayrollDayCredit = static fn (array $detailRow, float $hkHoursPerDay, $profil): array => \App\Modules\AttendanceReview\Services\AttendanceDayCreditResolver::resolve($detailRow, $profil, $hkHoursPerDay); @endphp

Detail Karyawan

Preview PDF
{{ $assignment->karyawan?->employee_code }} - {{ $assignment->karyawan?->full_name }}
Profil Bulan: {{ $profil->code }} - {{ $profil->name }} ({{ $profil->start_date }} s/d {{ $profil->end_date }})
Siklus: {{ $cycleLabel }} | Anchor: {{ $anchorDate }} | Pay Date: {{ $payDate }} | Due: {{ $dueDate }} ({{ $isDue ? 'Jatuh Tempo' : 'Belum Tempo' }})
Periode Tertagih: {{ $effectiveStart }} s/d {{ $effectiveEnd }}
@if ($paymentStatus === 'paid') Sudah Terbayar {{ $paymentMarkedAt ? 'ditandai pada ' . $paymentMarkedAt : '' }} @if (!empty($paymentId)) Bukti Potong @endif @else Belum Terbayar @endif

Ringkasan Nominal & Jam

@php $bd = is_array($breakdown ?? null) ? $breakdown : []; $allowFixed = (float) ($bd['allowance_fixed'] ?? 0); $allowPosition = (float) ($bd['allowance_position'] ?? 0); $allowSkill = (float) ($bd['allowance_skill'] ?? 0); $allowMedicalHousing = (float) ($bd['allowance_medical_housing'] ?? 0); $allowOther = (float) ($bd['allowance_other'] ?? 0); $allowTotal = (float) ($bd['allowance_total'] ?? 0); $overtimeRate = (float) ($bd['overtime_rate'] ?? 0); $incentive = (float) (($bd['incentive_amount'] ?? 0)); $overtimeNominal = (float) (($bd['overtime_nominal'] ?? 0)); $reimburse = (float) (($bd['reimburse_nominal'] ?? 0)); $specialPayrollBonusNominal = (float) (($bd['special_overtime_payroll_bonus_nominal'] ?? 0)); $specialSeparateBonusNominal = (float) (($bd['special_overtime_separate_bonus_nominal'] ?? 0)); $specialSummary = is_array($bd['special_overtime_summary'] ?? null) ? $bd['special_overtime_summary'] : []; $bpjsDetailRows = is_array($bd['bpjs_details'] ?? null) ? $bd['bpjs_details'] : []; $bpjsSummary = is_array($bd['bpjs_summary'] ?? null) ? $bd['bpjs_summary'] : []; $bpjsSourceMode = (string) ($bd['bpjs_source_mode'] ?? 'live_period'); $bpjsEffectiveDate = (string) ($bd['bpjs_effective_date'] ?? $effectiveEnd ?? ''); $bpjsGeneralRow = collect($bpjsDetailRows)->firstWhere('basis_type', 'general'); $bpjsJpRow = collect($bpjsDetailRows)->firstWhere('basis_type', 'jp'); $bpjsHealthRow = collect($bpjsDetailRows)->firstWhere('basis_type', 'health'); $bpjsBasisGeneralDisplay = (float) ($bpjsGeneralRow['basis_source_nominal'] ?? ($bd['bpjs_basis_general_nominal'] ?? 0)); $bpjsBasisJpDisplay = (float) ($bpjsJpRow['basis_source_nominal'] ?? ($bd['bpjs_basis_jp_nominal'] ?? 0)); $bpjsBasisHealthDisplay = (float) ($bpjsHealthRow['basis_source_nominal'] ?? ($bd['bpjs_basis_health_nominal'] ?? 0)); $pph21Method = (string) ($bd['pph21_method'] ?? 'legacy_flat_rate'); $pph21PtkpStatus = (string) ($bd['pph21_ptkp_status'] ?? ''); $pph21TerCategory = (string) ($bd['pph21_ter_category'] ?? ''); $pph21TaxableGross = (float) ($bd['pph21_taxable_gross'] ?? 0); $pph21CalculationDetails = is_array($bd['pph21_calculation_details'] ?? null) ? $bd['pph21_calculation_details'] : []; $pph21RuleCode = (string) ($pph21CalculationDetails['rule_set_code'] ?? ''); $pph21CalculationDate = (string) ($pph21CalculationDetails['calculation_date'] ?? $effectiveEnd ?? ''); $pph21HasNpwp = array_key_exists('has_npwp', $pph21CalculationDetails) ? (bool) $pph21CalculationDetails['has_npwp'] : null; $pph21BracketMin = isset($pph21CalculationDetails['bracket_min']) ? (float) $pph21CalculationDetails['bracket_min'] : null; $pph21BracketMax = isset($pph21CalculationDetails['bracket_max']) ? (float) $pph21CalculationDetails['bracket_max'] : null; $pph21GrossComponents = is_array($pph21CalculationDetails['gross_components'] ?? null) ? $pph21CalculationDetails['gross_components'] : []; $pph21GrossReductions = is_array($pph21CalculationDetails['gross_reductions'] ?? null) ? $pph21CalculationDetails['gross_reductions'] : []; $pph21GrossBeforeDeductions = (float) ($pph21CalculationDetails['gross_before_internal_deductions'] ?? $pph21TaxableGross); $pph21LegacyBasis = (float) ($pph21CalculationDetails['legacy_basis'] ?? $pph21TaxableGross); $pph21FormulaBasis = $pph21Method === 'legacy_flat_rate' ? $pph21LegacyBasis : $pph21TaxableGross; $pph21RawResult = round($pph21FormulaBasis * (float) $pph21Rate, 2); $pph21FormulaLabel = $pph21Method === 'ter_monthly' ? 'Bruto Kena Pajak x Tarif TER' : ($pph21Method === 'legacy_flat_rate' ? 'Basis Fallback x Tarif Fallback' : 'PPh21 dinonaktifkan'); $pph21IsSnapshot = !empty($payment); $pph21MethodLabel = match ($pph21Method) { 'ter_monthly' => 'TER Bulanan', 'legacy_flat_rate' => 'Fallback Tarif Lama', 'disabled' => 'Dinonaktifkan', default => strtoupper(str_replace('_', ' ', $pph21Method)), }; // "Penambah": tunjangan + insentif + upah lembur + reimburse approved. $additionsTotal = max(0.0, $allowTotal + $incentive + $overtimeNominal + $reimburse); $dedAbsence = (float) (($bd['absence_deduction_nominal'] ?? 0)); $dedLate = (float) (($bd['late_deduction_nominal'] ?? 0)); $dynamicDeductionRows = collect(is_array($bd['dynamic_deduction_components'] ?? null) ? $bd['dynamic_deduction_components'] : []) ->filter(fn ($row) => (float) ($row['amount'] ?? 0) > 0) ->values(); $dedDynamic = (float) ($bd['dynamic_deduction_nominal'] ?? $dynamicDeductionRows->sum(fn ($row) => (float) ($row['amount'] ?? 0))); $dedBpjs = (float) ($bpjsNominal ?? 0); $dedPph21 = (float) ($pph21Nominal ?? 0); $deductionsTotal = max(0.0, $dedAbsence + $dedLate + $dedDynamic + $dedBpjs + $dedPph21); $grossNominalDisplay = (float) ($bd['gross_nominal'] ?? 0); $grossBeforeInternalDeductionsDisplay = max(0.0, $grossNominalDisplay + $dedAbsence + $dedLate); $salaryScheme = (string) ($bd['salary_scheme'] ?? ''); $absenceMode = (string) ($bd['absence_deduction_mode'] ?? ''); // Samakan indikator HK web dengan detail attendance/PDF: basis jam, bukan hitung hari integer. $payrollBasisDisplay = is_array($payrollBasis ?? null) ? $payrollBasis : []; $hkHoursPerDayDisplay = (float) ($payrollBasisDisplay['hours_per_day'] ?? ($profil->jam_per_hari ?? 8)); $hkBaseHoursDisplay = (float) ($payrollBasisDisplay['monthly_hour_base'] ?? (((float) ($profil->hk_basis ?? 21)) * $hkHoursPerDayDisplay)); $hkBasisDisplay = $hkHoursPerDayDisplay > 0 ? ($hkBaseHoursDisplay / $hkHoursPerDayDisplay) : (float) ($profil->hk_basis ?? 21); $sumNormalHoursDisplay = 0.0; $deficitHoursDisplay = 0.0; foreach (($dailyRows ?? []) as $detailRow) { $sumNormalHoursDisplay += max(0.0, (float) ($detailRow['normal_hours'] ?? 0)); $dayCredit = $resolvePayrollDayCredit((array) $detailRow, $hkHoursPerDayDisplay, $profil); if (($dayCredit['hk_flag'] ?? 0) === 1) { $deficitHoursDisplay += (float) ($dayCredit['deficit_hours'] ?? 0.0); } } $jamTidakMasukDisplay = max(0.0, $deficitHoursDisplay); $jamMasukNormalDisplay = max(0.0, $hkBaseHoursDisplay - $jamTidakMasukDisplay); $hkMasukDisplay = $hkHoursPerDayDisplay > 0 ? ($jamMasukNormalDisplay / $hkHoursPerDayDisplay) : 0.0; $rawOvertimeHoursDisplay = (float) ($overtimeHours ?? ($bd['overtime_hours'] ?? 0)); $weightedOvertimeHoursDisplay = (float) ($bd['weighted_overtime_hours'] ?? $rawOvertimeHoursDisplay); $calculatedBaseSalaryDisplay = max(0.0, $grossBeforeInternalDeductionsDisplay - $allowTotal - $incentive - $overtimeNominal); $subtotalIncomeDisplay = max(0.0, $calculatedBaseSalaryDisplay + $allowTotal + $incentive + $overtimeNominal + $reimburse); $grandTakePayDisplay = (float) ($netNominal ?? ($bd['net_nominal'] ?? 0)); $unapprovedHourRows = collect($dailyRows ?? []) ->filter(function ($row) { $isApproved = (bool) ($row['is_approved'] ?? false); if ($isApproved || !empty($row['leave_tag_label'])) { return false; } $in = trim((string) ($row['in_time'] ?? '')); $out = trim((string) ($row['out_time'] ?? '')); $hasInOut = $in !== '' && $in !== '-' && $out !== '' && $out !== '-'; $hasHours = (float) ($row['actual_hours'] ?? 0) > 0 || (float) ($row['overtime_hours'] ?? 0) > 0 || (float) ($row['overtime_hours_gross'] ?? 0) > 0; return $hasInOut || $hasHours; }) ->values(); $unapprovedDateCount = $unapprovedHourRows ->pluck('work_date') ->filter() ->unique() ->count(); $unapprovedDatePreview = $unapprovedHourRows ->pluck('work_date') ->filter() ->unique() ->take(10) ->implode(', '); $unapprovedActualHours = $unapprovedHourRows ->sum(fn ($row) => (float) ($row['actual_hours'] ?? 0)); @endphp @if ($unapprovedDateCount > 0)
Catatan approval: ada {{ $unapprovedDateCount }} tanggal dengan jam/log belum approve. Jam pada tanggal tersebut belum dianggap final di payroll. @if ($unapprovedActualHours > 0) Estimasi jam log belum approve: {{ number_format($unapprovedActualHours, 2, ',', '.') }} jam. @endif @if ($unapprovedDatePreview !== '') Tanggal: {{ $unapprovedDatePreview }}{{ $unapprovedDateCount > 10 ? ', ...' : '' }} @endif
@endif
Basis Jam Profil
{{ number_format($hkBaseHoursDisplay, 2, ',', '.') }} jam
HK basis: {{ number_format($hkBasisDisplay, 2, ',', '.') }} x {{ number_format($hkHoursPerDayDisplay, 2, ',', '.') }} jam
Total Jam Kurang
{{ number_format($jamTidakMasukDisplay, 2, ',', '.') }} jam
Pengurang dari basis jam profil
HK Masuk Riil
{{ number_format($hkMasukDisplay, 2, ',', '.') }}/{{ number_format($hkBasisDisplay, 2, ',', '.') }}
Jam normal: {{ number_format($jamMasukNormalDisplay, 2, ',', '.') }} / {{ number_format($hkBaseHoursDisplay, 2, ',', '.') }}
Jam Tertagih
{{ number_format(($billedHours ?? $approvedHours), 2, ',', '.') }} jam
Aktual: {{ number_format($approvedHours, 2, ',', '.') }} jam
Alpha / Cuti / Lembur
A {{ number_format($alphaDays ?? 0, 0, ',', '.') }} | C {{ number_format($cutiDays ?? 0, 0, ',', '.') }} | OT {{ number_format($overtimeHours ?? 0, 2, ',', '.') }}j
Rate/Jam (Base/{{ (int) ($monthlyHourBase ?? 173) }})
Rp {{ number_format($hourlyRate, 2, ',', '.') }}
PPh21
Rp {{ number_format($pph21Nominal, 2, ',', '.') }} ({{ number_format($pph21Rate * 100, 2, ',', '.') }}%)
{{ $pph21MethodLabel }}{{ $pph21TerCategory !== '' ? ' | TER '.$pph21TerCategory : '' }}{{ $pph21PtkpStatus !== '' ? ' | '.$pph21PtkpStatus : '' }}
BPJS Potongan
Rp {{ number_format($bpjsNominal, 2, ',', '.') }} ({{ number_format($bpjsRateTotal * 100, 2, ',', '.') }}%)
{{ $bpjsSourceMode === 'snapshot_paid' ? 'Snapshot dari payroll yang sudah dibayar.' : 'Live hitung dari rule aktif periode ini.' }}
Reimbursement Approved
Rp {{ number_format($reimburseNominal, 2, ',', '.') }}
Netto Dibayarkan
Rp {{ number_format($netNominal, 2, ',', '.') }}
Bonus SPL Khusus Masuk Payroll
Rp {{ number_format($specialPayrollBonusNominal, 2, ',', '.') }}
{{ number_format((float) ($bd['special_overtime_payroll_bonus_hours'] ?? 0), 2, ',', '.') }} jam | {{ number_format((int) ($bd['special_overtime_payroll_bonus_hk'] ?? 0), 0, ',', '.') }} HK
Bonus SPL Khusus Bayar Terpisah
Rp {{ number_format($specialSeparateBonusNominal, 2, ',', '.') }}
{{ number_format((float) ($bd['special_overtime_separate_bonus_hours'] ?? 0), 2, ',', '.') }} jam | {{ number_format((int) ($bd['special_overtime_separate_bonus_hk'] ?? 0), 0, ',', '.') }} HK
Rincian Perhitungan PPh21 {{ $pph21IsSnapshot ? 'Snapshot Bayar' : 'Live Periode' }} {{ $pph21MethodLabel }}
Tanggal acuan: {{ $pph21CalculationDate !== '' ? $pph21CalculationDate : '-' }}
Rule Digunakan
{{ $pph21RuleCode !== '' ? $pph21RuleCode : ($pph21Method === 'legacy_flat_rate' ? 'Fallback Internal' : '-') }}
Status Pajak Karyawan
PTKP {{ $pph21PtkpStatus !== '' ? $pph21PtkpStatus : 'Belum Diisi' }}
NPWP: {{ $pph21HasNpwp === null ? '-' : ($pph21HasNpwp ? 'Ada' : 'Tidak Ada') }}
Kategori dan Tarif
{{ $pph21TerCategory !== '' ? 'TER '.$pph21TerCategory : $pph21MethodLabel }}
{{ number_format($pph21Rate * 100, 4, ',', '.') }}%
PPh21 Dipotong
Rp {{ number_format($pph21Nominal, 2, ',', '.') }}
A. Pembentuk Penghasilan Bruto Kena Pajak
@if (!empty($pph21GrossComponents)) @else @endif
Penghasilan gaji terhitungRp {{ number_format((float) ($pph21GrossComponents['salary_income'] ?? 0), 2, ',', '.') }}
Tunjangan kena pajakRp {{ number_format((float) ($pph21GrossComponents['allowances'] ?? 0), 2, ',', '.') }}
Insentif kena pajakRp {{ number_format((float) ($pph21GrossComponents['incentive'] ?? 0), 2, ',', '.') }}
Lembur yang masuk bruto kena pajakRp {{ number_format((float) ($pph21GrossComponents['overtime'] ?? 0), 2, ',', '.') }}
Rincian pembentuk bruto belum tersedia pada snapshot pembayaran lama.
Bruto sebelum potongan internalRp {{ number_format($pph21GrossBeforeDeductions, 2, ',', '.') }}
Potongan ketidakhadiran- Rp {{ number_format((float) ($pph21GrossReductions['absence'] ?? 0), 2, ',', '.') }}
Potongan keterlambatan- Rp {{ number_format((float) ($pph21GrossReductions['late'] ?? 0), 2, ',', '.') }}
Penghasilan bruto kena pajakRp {{ number_format($pph21TaxableGross, 2, ',', '.') }}
B. Pemilihan Tarif dan Rumus
@if ($pph21Method === 'ter_monthly')
Kategori berdasarkan PTKP:
{{ $pph21PtkpStatus }} → TER {{ $pph21TerCategory }}
Bracket bruto yang terpilih:
Rp {{ number_format((float) ($pph21BracketMin ?? 0), 0, ',', '.') }} s/d {{ $pph21BracketMax === null ? 'tanpa batas' : 'Rp '.number_format($pph21BracketMax, 0, ',', '.') }}
@elseif ($pph21Method === 'legacy_flat_rate')
PTKP atau rule TER belum lengkap. Sistem memakai basis fallback sebesar Rp {{ number_format($pph21LegacyBasis, 2, ',', '.') }}.
@endif
Tarif diterapkan:
{{ number_format($pph21Rate * 100, 4, ',', '.') }}%
{{ $pph21FormulaLabel }}
Rp {{ number_format($pph21FormulaBasis, 2, ',', '.') }} × {{ number_format($pph21Rate * 100, 4, ',', '.') }}%

Hasil PPh21 Rp {{ number_format($pph21RawResult, 2, ',', '.') }}
@if (!empty($pph21CalculationDetails['fallback_used']))
Perlu diperbaiki: lengkapi Status PTKP karyawan atau rule TER periode ini agar payroll tidak memakai fallback internal.
@endif
@if ($bpjsSourceMode === 'snapshot_paid') Snapshot Bayar @else Live Periode @endif Rate BPJS dibaca per tanggal acuan {{ $bpjsEffectiveDate !== '' ? $bpjsEffectiveDate : '-' }}.
{{ $bpjsSourceMode === 'snapshot_paid' ? 'Karena payroll periode ini sudah ditandai bayar, rincian BPJS di bawah memakai snapshot yang tersimpan saat pembayaran dibuat. Perubahan rate BPJS tahun depan tidak mengubah angka periode ini.' : 'Payroll periode ini belum dibayar, jadi rincian BPJS di bawah memakai rule aktif pada akhir periode payroll. Jika histori BPJS berubah sebelum dibayar, nominal simulasi bisa ikut berubah.' }}
@if (!empty($bpjsSummary['full']))
{{ $bpjsSummary['full'] }}
@endif
@if (!empty($payrollReportOnly))
Report Jam Only. Jam, HK, dan detail attendance tetap dihitung untuk laporan, tetapi nominal gaji, lembur, BPJS, PPh21, dan take pay dibuat Rp 0 serta tidak masuk proses bayar.
@endif @if (!empty($payrollReimburseOnly))
Rembes/Reimburse Only. Jam, HK, dan detail attendance tetap dihitung untuk laporan, tetapi gaji, lembur, BPJS, dan PPh21 dibuat Rp 0. Yang masuk proses bayar hanya nominal rembes/reimburse approved.
@endif
Gaji Pokok Terhitung
@if ($salaryScheme !== '') {{ strtoupper($salaryScheme) }} @endif
Rp {{ number_format($calculatedBaseSalaryDisplay, 2, ',', '.') }}
Base bulanan: Rp {{ number_format($monthlyBaseSalary, 2, ',', '.') }}
Jam tertagih: {{ number_format(($billedHours ?? $approvedHours), 2, ',', '.') }} jam x Rp {{ number_format($hourlyRate, 2, ',', '.') }}
Total lembur: {{ number_format($overtimeRate, 2, ',', '.') }} @if (abs($weightedOvertimeHoursDisplay - $rawOvertimeHoursDisplay) > 0.0001) x {{ number_format($weightedOvertimeHoursDisplay, 2, ',', '.') }} jam @endif | Gaji lembur: Rp {{ number_format($overtimeNominal, 2, ',', '.') }}
@if ($absenceMode !== '') Mode potongan alpha: {{ strtoupper($absenceMode) }} @endif
Komponen Penambah
Tunjangan Total
Rp {{ number_format($allowTotal, 2, ',', '.') }}
@if ($allowFixed > 0)
Tunjangan Tetap
Rp {{ number_format($allowFixed, 2, ',', '.') }}
@endif @if ($allowPosition > 0)
Tunjangan Jabatan
Rp {{ number_format($allowPosition, 2, ',', '.') }}
@endif @if ($allowSkill > 0)
Tunjangan Keahlian
Rp {{ number_format($allowSkill, 2, ',', '.') }}
@endif @if ($allowMedicalHousing > 0)
Medical/Housing
Rp {{ number_format($allowMedicalHousing, 2, ',', '.') }}
@endif @if ($allowOther > 0)
Tunjangan Lainnya
Rp {{ number_format($allowOther, 2, ',', '.') }}
@endif @if ($incentive > 0)
Insentif
Rp {{ number_format($incentive, 2, ',', '.') }}
@endif @if ($specialPayrollBonusNominal > 0)
Bonus SPL Khusus (Payroll)
Rp {{ number_format($specialPayrollBonusNominal, 2, ',', '.') }}
@endif @if ($overtimeNominal > 0)
Upah Lembur
Rp {{ number_format($overtimeNominal, 2, ',', '.') }}
@endif @if ($reimburse > 0)
Reimbursement
Rp {{ number_format($reimburse, 2, ',', '.') }}
@endif
Total Penambah
Rp {{ number_format($additionsTotal, 2, ',', '.') }}
Komponen Pengurang
@if ($dedAbsence > 0)
Potongan Tidak Masuk (Alpha)
Rp {{ number_format($dedAbsence, 2, ',', '.') }}
@endif @if ($dedLate > 0)
Potongan Keterlambatan
Rp {{ number_format($dedLate, 2, ',', '.') }}
@endif @foreach ($dynamicDeductionRows as $dedRow)
{{ $dedRow['component_name'] ?? $dedRow['component_code'] ?? 'Potongan Lain' }}
Rp {{ number_format((float) ($dedRow['amount'] ?? 0), 2, ',', '.') }}
@endforeach
BPJS
Rp {{ number_format($dedBpjs, 2, ',', '.') }}
PPh21
Rp {{ number_format($dedPph21, 2, ',', '.') }}

Total Pengurang
Rp {{ number_format($deductionsTotal, 2, ',', '.') }}
Base gaji bulanan terdeteksi: Rp {{ number_format($monthlyBaseSalary, 2, ',', '.') }} | Progress bulan: {{ number_format(($monthlyAttendance['approved_hours'] ?? 0), 2, ',', '.') }} jam. @if (!empty($bankAccountLabel)) | Rekening Default: {{ $bankAccountLabel }} @endif @if (!empty($taxProofNo)) | No Bukti Potong: {{ $taxProofNo }} @endif
Rincian Program BPJS Periode Ini
Basis umum: Rp {{ number_format($bpjsBasisGeneralDisplay, 2, ',', '.') }} | Basis JP: Rp {{ number_format($bpjsBasisJpDisplay, 2, ',', '.') }} | Basis Kesehatan: Rp {{ number_format($bpjsBasisHealthDisplay, 2, ',', '.') }}.
@php $bpjsCompanyTotalDisplay = collect($bpjsDetailRows)->sum(fn ($row) => (float) ($row['company_nominal'] ?? 0)); $bpjsEmployeeTotalDisplay = collect($bpjsDetailRows)->sum(fn ($row) => (float) ($row['employee_nominal'] ?? 0)); @endphp
Total BPJS Perusahaan Rp {{ number_format($bpjsCompanyTotalDisplay, 2, ',', '.') }}
Total BPJS Karyawan Rp {{ number_format($bpjsEmployeeTotalDisplay, 2, ',', '.') }}
@forelse ($bpjsDetailRows as $bpjsRow) @empty @endforelse
Program Basis Basis Hitung Plafon Co (Perusahaan) Emp (Karyawan) Catatan
{{ $bpjsRow['component_code'] ?? '-' }}
{{ $bpjsRow['component_name'] ?? '-' }}
{{ strtoupper((string) ($bpjsRow['basis_type'] ?? 'general')) }} Src: Rp {{ number_format((float) ($bpjsRow['basis_source_nominal'] ?? 0), 2, ',', '.') }}
Dipakai: Rp {{ number_format((float) ($bpjsRow['basis_nominal'] ?? 0), 2, ',', '.') }}
@php $bpjsBasisSource = (float) ($bpjsRow['basis_source_nominal'] ?? 0); $bpjsBasisUsed = (float) ($bpjsRow['basis_nominal'] ?? 0); $bpjsCeilingMin = (float) ($bpjsRow['ceiling_min_nominal'] ?? 0); $bpjsCeilingMax = (float) ($bpjsRow['ceiling_max_nominal'] ?? $bpjsRow['ceiling_nominal'] ?? 0); $bpjsCeilingApplied = ($bpjsCeilingMin > 0 && $bpjsBasisSource < $bpjsCeilingMin && $bpjsBasisUsed > $bpjsBasisSource) || ($bpjsCeilingMax > 0 && $bpjsBasisSource > $bpjsCeilingMax && $bpjsBasisUsed < $bpjsBasisSource); @endphp @if ($bpjsCeilingApplied) @if ($bpjsCeilingMin > 0 && $bpjsBasisSource < $bpjsCeilingMin)
Min Rp {{ number_format($bpjsCeilingMin, 2, ',', '.') }}
@endif @if ($bpjsCeilingMax > 0 && $bpjsBasisSource > $bpjsCeilingMax)
Max Rp {{ number_format($bpjsCeilingMax, 2, ',', '.') }}
@endif @else - @endif
{{ number_format((float) ($bpjsRow['rate_company_percent'] ?? 0), 2, ',', '.') }}%
Rp {{ number_format((float) ($bpjsRow['company_nominal'] ?? 0), 2, ',', '.') }} @if (!empty($bpjsRow['is_enrolled']) && (float) ($bpjsRow['rate_company_percent'] ?? 0) > 0) Report Only @endif
{{ number_format((float) ($bpjsRow['rate_employee_percent'] ?? 0), 2, ',', '.') }}%
Rp {{ number_format((float) ($bpjsRow['employee_nominal'] ?? 0), 2, ',', '.') }} @if (!empty($bpjsRow['is_enrolled'])) @if (!empty($bpjsRow['deduct_to_payroll'])) Potong Payroll @else Report Only @endif @else Tidak Ikut @endif
{{ $bpjsRow['notes'] ?? '-' }}
Belum ada rincian program BPJS yang bisa ditampilkan untuk periode ini.
Rincian Sub Total & Grand Total
@if ($dedAbsence > 0) @endif @if ($dedLate > 0) @endif @foreach ($dynamicDeductionRows as $dedRow) @endforeach
Komponen Keterangan Nominal
Gaji Pokok Sesuai Hitungan Kehadiran Rp {{ number_format($calculatedBaseSalaryDisplay, 2, ',', '.') }}
Total Lembur {{ number_format($overtimeRate, 2, ',', '.') }} @if (abs($weightedOvertimeHoursDisplay - $rawOvertimeHoursDisplay) > 0.0001) x {{ number_format($weightedOvertimeHoursDisplay, 2, ',', '.') }} jam @endif Rp {{ number_format($overtimeNominal, 2, ',', '.') }}
Komponen Penambah Tunjangan, insentif/bonus payroll, dan reimbursement approved. Rp {{ number_format($allowTotal + $incentive + $reimburse, 2, ',', '.') }}
Sub Total Pendapatan Gaji pokok terhitung + lembur + penambah. Rp {{ number_format($subtotalIncomeDisplay, 2, ',', '.') }}
Potongan Tidak Masuk / Alpha Sesuai mode potongan {{ strtoupper($absenceMode ?: '-') }}. Rp {{ number_format($dedAbsence, 2, ',', '.') }}
Potongan Keterlambatan {{ number_format((float) ($bd['late_hours'] ?? 0), 2, ',', '.') }} jam x Rp {{ number_format((float) ($bd['late_rate_per_hour'] ?? 0), 2, ',', '.') }} Rp {{ number_format($dedLate, 2, ',', '.') }}
{{ $dedRow['component_name'] ?? $dedRow['component_code'] ?? 'Potongan Lain' }} {{ ($dedRow['source'] ?? '') === 'override' ? 'Import/override profil bulan.' : 'Komponen potongan profil gaji.' }} Rp {{ number_format((float) ($dedRow['amount'] ?? 0), 2, ',', '.') }}
BPJS Karyawan Potongan payroll dari program BPJS aktif. Rp {{ number_format($dedBpjs, 2, ',', '.') }}
PPh21 {{ $pph21MethodLabel }}{{ $pph21TerCategory !== '' ? ' kategori '.$pph21TerCategory : '' }}{{ $pph21PtkpStatus !== '' ? ' (PTKP '.$pph21PtkpStatus.')' : '' }}: {{ number_format($pph21Rate * 100, 2, ',', '.') }}% dari bruto kena pajak Rp {{ number_format($pph21TaxableGross, 2, ',', '.') }}. Rp {{ number_format($dedPph21, 2, ',', '.') }}
Sub Total Pengurang Total seluruh komponen pengurang payroll. Rp {{ number_format($deductionsTotal, 2, ',', '.') }}
Grand Total (Take Pay) Sub Total Pendapatan - Sub Total Pengurang. Rp {{ number_format($grandTakePayDisplay, 2, ',', '.') }}
@if (!empty($specialSummary['rows']))
Rincian Bonus SPL Khusus
@foreach (($specialSummary['rows'] ?? []) as $specialRow) @endforeach
No SPL Tanggal Jenis Mode Bayar Bonus Jam Bonus HK Nominal Catatan
{{ $specialRow['document_no'] ?? '-' }} {{ $specialRow['work_date'] ?? '-' }} {{ $specialRow['overtime_type_label'] ?? '-' }} {{ $specialRow['payment_mode_label'] ?? '-' }} {{ number_format((float) ($specialRow['bonus_hours'] ?? 0), 2, ',', '.') }} {{ number_format((int) ($specialRow['bonus_hk'] ?? 0), 0, ',', '.') }} Rp {{ number_format((float) ($specialRow['nominal'] ?? 0), 2, ',', '.') }} {{ $specialRow['notes'] ?? '-' }}
Bonus mode Gabung Payroll sudah ikut ke komponen penambah payroll. Bonus mode Bayar Terpisah hanya tampil sebagai referensi dan tidak ikut netto payroll.
@endif

Rincian Jam Harian (Periode Tertagih)

@include('attendancereview::partials.calculation_detail_shared', [ 'detailRows' => $dailyRows, 'detailOtColumns' => $dailyRowsOtColumns, 'detailProfil' => $profil, ])
@endsection