Files
HRM-System/resources/views/payslips/template.blade.php

309 lines
10 KiB
PHP
Executable File

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Payslip - {{ $payrollEntry->employee->name }}</title>
<style>
@page {
margin: 40px;
}
body {
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 11px;
color: #111;
margin: 0;
padding: 0;
line-height: 1.4;
}
.header {
text-align: center;
margin-bottom: 25px;
}
.company-name {
font-size: 22px;
font-weight: 700;
margin-bottom: 3px;
}
.company-address {
color: #555;
font-size: 11px;
margin-bottom: 15px;
}
.payslip-title {
font-size: 14px;
font-weight: 700;
margin-bottom: 5px;
text-transform: uppercase;
}
.payslip-period {
color: #777;
font-size: 11px;
}
.info-grid {
width: 100%;
margin-bottom: 15px;
border-collapse: collapse;
}
.info-grid td {
padding: 4px 0;
vertical-align: top;
}
.info-label {
font-weight: bold;
color: #555;
width: 15%;
}
.info-value {
width: 35%;
}
.summary-box {
background-color: #f8f9fa;
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 12px;
margin-bottom: 20px;
}
.summary-box table {
width: 100%;
border-collapse: collapse;
}
.summary-box td {
padding: 4px 6px;
}
.summary-box .amt {
font-weight: bold;
text-align: right;
}
.main-table {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
.main-table th, .main-table td {
border: 1px solid #ddd;
padding: 8px 12px;
text-align: left;
}
.main-table th {
font-size: 10px;
font-weight: bold;
background-color: #f1f1f1;
text-transform: uppercase;
}
.main-table .amt {
text-align: right;
}
.main-table .total-row td {
font-weight: bold;
background-color: #fafafa;
}
.att-summary-title {
font-size: 13px;
font-weight: bold;
margin-bottom: 5px;
border-bottom: 2px solid #222;
padding-bottom: 4px;
}
.att-grid {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
border: 1px solid #e0e0e0;
}
.att-grid td {
padding: 8px;
border: 1px solid #e0e0e0;
width: 33.33%;
}
.net-pay-box {
background-color: #f4f6f8;
border: 1px solid #e0e0e0;
padding: 15px;
margin-top: 20px;
}
.net-pay-box table {
width: 100%;
}
.net-label {
font-size: 16px;
font-weight: bold;
}
.net-amount {
text-align: right;
font-size: 20px;
font-weight: bold;
color: #2c5282;
}
.net-words {
font-style: italic;
color: #777;
font-size: 10px;
margin-top: 10px;
}
</style>
</head>
<body>
@php
$rawEarnings = $payrollEntry->earnings_breakdown ?? [];
$meta = $rawEarnings['meta'] ?? [];
$summary = $rawEarnings['summary'] ?? [];
unset($rawEarnings['meta'], $rawEarnings['summary']);
// 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;
});
// Include adjustments
$adjustmentEarnings = $adjustments ? collect($adjustments)->where('type', 'earning')->toArray() : [];
$adjustmentDeductions = $adjustments ? collect($adjustments)->where('type', 'deduction')->toArray() : [];
// Add them to the earnings and deductions arrays
foreach ($adjustmentEarnings as $adj) {
$earnings[] = ['name' => $adj['name'], 'amount' => $adj['amount']];
}
foreach ($adjustmentDeductions as $adj) {
$deductions[] = ['name' => $adj['name'], 'amount' => $adj['amount']];
}
// Re-index after filtering
$earnings = array_values($earnings);
$deductions = array_values($deductions);
$payType = $meta['pay_type'] ?? 'Monthly';
$formatter = class_exists('NumberFormatter') ? new \NumberFormatter("en", \NumberFormatter::SPELLOUT) : null;
$words = $formatter ? ucwords($formatter->format($payrollEntry->net_pay)) . " Pesos Only" : "PHP " . $payrollEntry->net_pay;
if ($formatter && strpos((string)$payrollEntry->net_pay, '.') !== false) {
$parts = explode('.', number_format($payrollEntry->net_pay, 2, '.', ''));
$cents = (int)$parts[1];
if ($cents > 0) {
$words = ucwords($formatter->format((int)$parts[0])) . " Point " . ucwords($formatter->format($cents)) . " Pesos Only";
}
}
@endphp
<div class="header">
<div class="company-name">{{ $companySettings['titleText'] ?? 'Your Company Name' }}</div>
<div class="company-address">{{ $companySettings['companyAddress'] ?? 'Your Company Address' }}</div>
<div class="payslip-title">PAYSLIP</div>
<div class="payslip-period">{{ \Carbon\Carbon::parse($payrollEntry->payrollRun->pay_period_start)->format('M d, Y') }} - {{ \Carbon\Carbon::parse($payrollEntry->payrollRun->pay_period_end)->format('M d, Y') }} ({{ $payType }})</div>
</div>
<table class="info-grid">
<tr>
<td class="info-label">Employee Name:</td>
<td class="info-value">{{ $employee->name }}</td>
<td class="info-label">Employee ID:</td>
<td class="info-value">{{ $employeeData->employee_id ?? '' }}</td>
</tr>
<tr>
<td class="info-label">Department:</td>
<td class="info-value">{{ $employeeData->department->name ?? 'N/A' }}</td>
<td class="info-label">Designation:</td>
<td class="info-value">{{ $employeeData->designation->name ?? 'N/A' }}</td>
</tr>
<tr>
<td class="info-label">Payment Date:</td>
<td class="info-value">{{ \Carbon\Carbon::parse($payrollEntry->payrollRun->pay_date)->format('d M, Y') }}</td>
<td class="info-label">Status:</td>
<td class="info-value">{{ ucfirst($payrollEntry->payslip->status ?? 'Generated') }}</td>
</tr>
</table>
<table class="main-table">
<tr>
<th width="35%">EARNINGS</th>
<th width="15%" class="amt">AMOUNT</th>
<th width="35%">DEDUCTIONS</th>
<th width="15%" class="amt">AMOUNT</th>
</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>
<td>Total Deductions</td>
<td class="amt">{{ formatCurrency($payrollEntry->total_deductions) }}</td>
</tr>
</table>
<div class="att-summary-title">Attendance Summary</div>
<table class="att-grid">
<tr>
<td><strong>Daily Rate:</strong> {{ formatCurrency($meta['daily_rate'] ?? 0) }}</td>
<td><strong>Days Worked:</strong> {{ $summary['days_worked'] ?? 0 }} / {{ $summary['expected_working_days'] ?? '-' }}</td>
<td><strong>Absences:</strong> {{ $summary['absences'] ?? 0 }}</td>
</tr>
<tr>
<td><strong>Expected Hours:</strong> {{ isset($summary['expected_hours']) ? $summary['expected_hours'].'h' : '0.00h' }}</td>
<td><strong>Rendered Hours:</strong> {{ isset($summary['rendered_hours']) ? $summary['rendered_hours'].'h' : '0.00h' }}</td>
<td><strong>Reg. OT:</strong> {{ isset($summary['reg_ot_hours']) ? $summary['reg_ot_hours'].'h' : (isset($summary['reg_ot']) ? $summary['reg_ot'].'h' : '0h') }}</td>
</tr>
<tr>
<td><strong>Night Diff:</strong> {{ isset($summary['night_diff_hours']) ? $summary['night_diff_hours'].'h' : (isset($summary['night_diff']) ? $summary['night_diff'].'h' : '0h') }}</td>
<td><strong>Holiday:</strong> {{ $summary['holiday'] ?? 0 }}</td>
<td><strong>Leaves:</strong> {{ $summary['leaves'] ?? 0 }}</td>
</tr>
</table>
<div class="net-pay-box">
<table>
<tr>
<td class="net-label">Net Pay: {{ $companySettings['currency_symbol'] ?? '$' }} {{ number_format($payrollEntry->net_pay, 2) }}</td>
<td class="net-amount"></td>
</tr>
</table>
<div class="net-words">Amount in words: {{ $words }}</div>
</div>
</body>
</html>