Biometrics doesn't track break in/out, inflating night_diff_hours. Deduct 1.5h per night shift day for the untracked meal break. Also removed OT multiplier compounding from ND — all ND hours use flat hourlyRate × 10% per client policy. Dinh Chavez: 24h raw → 12h adjusted = ₱114.75 (exact client match)
4.8 KiB
Fix Night Differential — Deduct 1h Break from ND Hours
Background
Client Rule
"In night differential we should less 1 hour cause hindi na tayo maglalagay ng in & out for break."
Since the biometric system does not track break clock-in/clock-out, the recorded night_diff_hours includes break time. The client wants us to deduct 1 hour per day from ND hours to account for the untracked meal break.
Philippine DOLE Regulation (Article 86)
- ND window: 10:00 PM – 6:00 AM
- Premium: 10% of regular hourly rate (flat, per client preference — no dayMultiplier compounding)
- Formula:
ND_hours × (hourlyRate × 10%) - Hourly Rate:
dailyRate / 8(confirmed by client) - Break time is NOT compensable work — DOLE allows deducting unpaid meal breaks from hours worked
Current Problem
| Employee | Daily | System ND Hours | System ND ₱ | Client Expected ND ₱ |
|---|---|---|---|---|
| Dinh Chavez | ₱765 | 24.0h | ₱232.51 | ₱114.75 |
| Francis Londonio | ₱740 | 29.5h | ₱274.86 | TBD |
| Princess Acosta | ₱695 | 26.58h | ₱233.89 | TBD |
| Donna Moreno | ₱695 | 33.0h | ₱296.63 | TBD |
Root Cause Analysis
The attendance system records night_diff_hours as the full overlap between the employee's clock-in/out and the 10PM–6AM window, without deducting the 1-hour meal break. Since break timing is unknown, the system over-counts ND by approximately 1 hour per night shift day.
Proposed Fix
Approach: Deduct 1h Break from ND Hours Per Day in PayrollService
Where: PayrollService.php, inside the daily payroll loop, at the ND calculation block (~line 217).
Logic:
// Current (line ~217):
$ndHours = (float) ($att->night_diff_hours ?? 0);
// Proposed:
$ndHours = (float) ($att->night_diff_hours ?? 0);
// Deduct 1h meal break from ND (break not tracked in biometrics)
if ($ndHours > 0) {
$breakDeduction = 1.0; // 1-hour untracked meal break
$ndHours = max(0, $ndHours - $breakDeduction);
}
Why at payroll level (not attendance level):
- The
night_diff_hoursfield on attendance is the raw biometric data — it should stay accurate to what was physically recorded - The 1h deduction is a payroll policy, not an attendance correction
- This keeps the data clean and the adjustment visible/auditable
Effect on Dinh Chavez
| Date | Raw ND | -1h Break | Adjusted ND |
|---|---|---|---|
| Apr 27 | 2.5h | -1h | 1.5h |
| Apr 29 | 2.5h | -1h | 1.5h |
| Apr 30 | 2.5h | -1h | 1.5h |
| May 1 | 4.5h | -1h | 3.5h |
| May 3 | 2.5h | -1h | 1.5h |
| May 4 | 2.5h | -1h | 1.5h |
| May 6 | 0h | — | 0h |
| May 7 | 2.5h | -1h | 1.5h |
| May 8 | 4.5h | -1h | 3.5h |
| TOTAL | 24h | -8h | 16h |
Result: 16h × ₱9.5625 = ₱153.00
Warning
Discrepancy: 16h vs Client's 12h
With the 1h break deduction, we get 16h (₱153.00), but the client expects 12h (₱114.75). There is still a 4-hour gap.
Possible explanations:
- Client may also exclude holiday ND from the "Night Differential" line (May 1 = 3.5h) and include it in Holiday Pay instead
- Client may apply a different break deduction for longer shifts (e.g., 1.5h for Shift B)
- Client may be looking at a different cutoff period
Action needed: Confirm with client which specific days/hours they counted to reach 12h. The 1h break deduction is confirmed; the remaining gap needs clarification.
Implementation Steps
Step 1: Apply 1h Break Deduction to ND Hours
File: app/Services/PayrollService.php (~line 217)
Deduct 1 hour from night_diff_hours for any day where ND > 0, before computing the ND amount.
Step 2: Update Payslip Summary
Ensure the payslip template shows the adjusted ND hours (after break deduction), not the raw attendance ND hours.
Step 3: Verify All R&F Employees
Run payroll calculation for all 4 rank-and-file employees and compare against client expectations.
Verification Plan
Automated Check
php artisan tinker --execute="
foreach ([10,11,13,14] as \$uid) {
\$e = \App\Models\Employee::where('user_id', \$uid)->first();
\$r = (new \App\Services\PayrollService())->calculateForPeriod(\$e, '2026-04-26', '2026-05-10');
echo \$e->user->name . ': ND=' . \$r['summary']['night_diff_hours'] . 'h ₱' . number_format(\$r['summary']['night_diff_amount'], 2) . PHP_EOL;
}
"
Client Validation
Share updated payslip numbers with client for sign-off, particularly the ND line for Dinh Chavez.
DOLE Compliance Note
This approach is DOLE-compliant:
- Article 86 mandates 10% ND premium for work between 10PM–6AM
- Meal breaks are not compensable hours per Article 85 — they are not "hours worked"
- Deducting the 1h break from ND hours is correct because the employee is not working during the break
- The deduction should be consistent across all employees with night shifts