Fix: Make payslip PDF template dynamically render all earnings and deductions
This commit is contained in:
@@ -165,7 +165,13 @@ class PayrollRun extends BaseModel
|
||||
'per_day_salary' => $salaryBreakdown['daily_rate'],
|
||||
'unpaid_leave_deduction' => $summary['absence_amount'] ?? 0,
|
||||
|
||||
'earnings_breakdown' => $salaryBreakdown['earnings'],
|
||||
'earnings_breakdown' => array_merge($salaryBreakdown['earnings'], [
|
||||
'meta' => [
|
||||
'daily_rate' => $salaryBreakdown['daily_rate'],
|
||||
'pay_type' => $salaryBreakdown['pay_type'],
|
||||
],
|
||||
'summary' => $summary
|
||||
]),
|
||||
'deductions_breakdown' => $salaryBreakdown['deductions'],
|
||||
'created_by' => $this->created_by,
|
||||
]);
|
||||
|
||||
@@ -179,41 +179,18 @@
|
||||
$summary = $rawEarnings['summary'] ?? [];
|
||||
unset($rawEarnings['meta'], $rawEarnings['summary']);
|
||||
|
||||
$earnings = array_values($rawEarnings);
|
||||
$deductions = array_values($payrollEntry->deductions_breakdown ?? []);
|
||||
// Filter out zero values (except Basic Salary) so they don't clutter the payslip
|
||||
$earnings = array_filter(array_values($rawEarnings), function($item) {
|
||||
return strtolower($item['name']) === 'basic salary' || (float)$item['amount'] > 0;
|
||||
});
|
||||
|
||||
$deductions = array_filter(array_values($payrollEntry->deductions_breakdown ?? []), function($item) {
|
||||
return (float)$item['amount'] > 0;
|
||||
});
|
||||
|
||||
if (!function_exists('extractAmount')) {
|
||||
function extractAmount($array, $keywords) {
|
||||
$keywords = (array) $keywords;
|
||||
foreach ($array as $item) {
|
||||
if (!isset($item['name'])) continue;
|
||||
foreach ($keywords as $keyword) {
|
||||
if (stripos($item['name'], $keyword) !== false) {
|
||||
return $item['amount'];
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Map dynamic earnings natively
|
||||
$basicSalary = extractAmount($earnings, 'Basic Salary') ?: $payrollEntry->basic_salary;
|
||||
$nightDiff = extractAmount($earnings, 'Night Diff');
|
||||
$overtime = extractAmount($earnings, ['Overtime', 'Reg. OT']);
|
||||
$holidayPay = extractAmount($earnings, 'Holiday');
|
||||
$adjustment = extractAmount($earnings, 'Adjustment');
|
||||
|
||||
// Map explicit deductions natively
|
||||
$undertimeDed = extractAmount($deductions, 'Undertime');
|
||||
$sss = extractAmount($deductions, 'SSS');
|
||||
$phic = extractAmount($deductions, 'PhilHealth');
|
||||
$hdmf = extractAmount($deductions, 'Pag-IBIG');
|
||||
$tax = extractAmount($deductions, ['Tax', 'Withholding']);
|
||||
|
||||
// Explicit penalties
|
||||
$tardiness = extractAmount($deductions, ['Late', 'Tardiness']);
|
||||
$absences = extractAmount($deductions, 'Absence');
|
||||
// Re-index after filtering
|
||||
$earnings = array_values($earnings);
|
||||
$deductions = array_values($deductions);
|
||||
|
||||
$payType = $meta['pay_type'] ?? 'Monthly';
|
||||
|
||||
@@ -264,36 +241,21 @@
|
||||
<th width="35%">DEDUCTIONS</th>
|
||||
<th width="15%" class="amt">AMOUNT</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Basic Salary</td>
|
||||
<td class="amt">{{ formatCurrency($basicSalary) }}</td>
|
||||
<td>Undertime Deduction</td>
|
||||
<td class="amt">{{ formatCurrency($undertimeDed) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-transform: uppercase;">Night Differential</td>
|
||||
<td class="amt">{{ formatCurrency($nightDiff) }}</td>
|
||||
<td>SSS Contribution (EE)</td>
|
||||
<td class="amt">{{ formatCurrency($sss) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-transform: uppercase;">Overtime</td>
|
||||
<td class="amt">{{ formatCurrency($overtime) }}</td>
|
||||
<td>PhilHealth Contribution (EE)</td>
|
||||
<td class="amt">{{ formatCurrency($phic) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-transform: uppercase;">Holiday Pay</td>
|
||||
<td class="amt">{{ formatCurrency($holidayPay) }}</td>
|
||||
<td>Pag-IBIG Contribution (EE)</td>
|
||||
<td class="amt">{{ formatCurrency($hdmf) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-transform: uppercase;">Adjustment +</td>
|
||||
<td class="amt">{{ formatCurrency($adjustment) }}</td>
|
||||
<td>Withholding Tax</td>
|
||||
<td class="amt">{{ formatCurrency($tax) }}</td>
|
||||
</tr>
|
||||
@php
|
||||
$maxRows = max(count($earnings), count($deductions));
|
||||
@endphp
|
||||
@for ($i = 0; $i < $maxRows; $i++)
|
||||
@php
|
||||
$earn = $earnings[$i] ?? null;
|
||||
$ded = $deductions[$i] ?? null;
|
||||
@endphp
|
||||
<tr>
|
||||
<td style="text-transform: uppercase;">{{ $earn ? $earn['name'] : '' }}</td>
|
||||
<td class="amt">{{ $earn ? formatCurrency($earn['amount']) : '' }}</td>
|
||||
<td style="text-transform: uppercase;">{{ $ded ? $ded['name'] : '' }}</td>
|
||||
<td class="amt">{{ $ded ? formatCurrency($ded['amount']) : '' }}</td>
|
||||
</tr>
|
||||
@endfor
|
||||
<tr class="total-row">
|
||||
<td>Total Earnings</td>
|
||||
<td class="amt">{{ formatCurrency($payrollEntry->gross_pay) }}</td>
|
||||
@@ -302,20 +264,6 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- Explicit Penalty Block as per Mockup -->
|
||||
<table width="100%" style="margin-bottom: 20px;">
|
||||
<tr>
|
||||
<td width="50%"></td>
|
||||
<td width="35%" style="text-transform: uppercase; font-weight: bold; border: 1px solid #ddd; padding: 4px 12px; background: #fff;">Tardiness</td>
|
||||
<td width="15%" style="border: 1px solid #ddd; padding: 4px 12px; text-align: right; background: #fff; font-weight: bold;">{{ formatCurrency($tardiness) }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="50%"></td>
|
||||
<td width="35%" style="text-transform: uppercase; font-weight: bold; border: 1px solid #ddd; padding: 4px 12px; border-top: none; background: #fff;">Undertime</td>
|
||||
<td width="15%" style="border: 1px solid #ddd; padding: 4px 12px; border-top: none; text-align: right; background: #fff; font-weight: bold;">{{ formatCurrency($undertimeDed) }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="att-summary-title">Attendance Summary</div>
|
||||
<table class="att-grid">
|
||||
<tr>
|
||||
|
||||
Reference in New Issue
Block a user