Files
HRM-System/docs/PLAN-overtime-summary-fix.md

4.6 KiB

PLAN - Overtime Summary Mapping Fix

This document outlines the plan to resolve the issue where Overtime Hours and Overtime Earnings are missing (showing as 0) in the Payroll Run Summary table, despite being correctly computed and displayed on individual employee payslips.


1. Problem Analysis & Scope

Current Behavior

  • When a payroll run is processed, PayrollRun::processEmployeePayroll creates a PayrollEntry row.
  • The mapping of overtime data is currently hardcoded or incorrect in PayrollRun.php:
    'overtime_hours'  => 0,
    'overtime_amount' => $summary['reg_ot'] ?? 0,
    
  • Because $summary from PayrollService returns reg_ot_hours and reg_ot_amount instead of reg_ot, both fields are stored as 0 in the database.
  • The frontend show.tsx reads directly from these columns, resulting in 0 display in the summary grid.
  • The payslip template template.blade.php is unaffected because it reads directly from the nested earnings_breakdown JSON structure.

Goals

  1. Update PayrollRun mapping to populate overtime_hours and overtime_amount columns.
  2. Update the SimulatePayslips artisan command to also populate these columns when running simulations.
  3. Write a database migration to backfill historical payroll_entries records by parsing their earnings_breakdown JSON columns, ensuring previously generated payrolls display overtime correctly.

2. Proposed Changes

A. Code Changes

1. app/Models/PayrollRun.php

Map the correct overtime summary keys from PayrollService:

- 'overtime_hours'       => 0,
- 'overtime_amount'      => $summary['reg_ot'] ?? 0,
+ 'overtime_hours'       => (float) ($summary['reg_ot_hours'] ?? 0),
+ 'overtime_amount'      => (float) ($summary['reg_ot_amount'] ?? 0),

2. app/Console/Commands/SimulatePayslips.php

Ensure simulated payroll entries populate overtime columns:

             $payrollEntry = PayrollEntry::create([
                 'payroll_run_id' => $payrollRun->id,
                 'employee_id' => $user->id,
                 'basic_salary' => $computation['basic_salary'],
                 'gross_pay' => $computation['total_earnings'],
                 'total_earnings' => $computation['total_earnings'],
                 'total_deductions' => $computation['total_deductions'],
                 'net_pay' => $computation['net_pay'],
                 'earnings_breakdown' => $computation['earnings'],
                 'deductions_breakdown' => $computation['deductions'],
+                'overtime_hours' => (float) ($computation['summary']['reg_ot_hours'] ?? 0),
+                'overtime_amount' => (float) ($computation['summary']['reg_ot_amount'] ?? 0),
                 'created_by' => 1,
             ]);

B. Database Migration (Backfill Historical Data)

Create a new migration database/migrations/2026_06_26_150000_backfill_payroll_entry_overtime.php that fetches all existing payroll_entries, parses the earnings_breakdown JSON, and updates the overtime_hours and overtime_amount fields:

public function up()
{
    $entries = \DB::table('payroll_entries')->get();

    foreach ($entries as $entry) {
        $breakdown = json_decode($entry->earnings_breakdown, true);
        $summary = $breakdown['summary'] ?? [];

        $otHours = (float) ($summary['reg_ot_hours'] ?? 0);
        $otAmount = (float) ($summary['reg_ot_amount'] ?? 0);

        if ($otHours > 0 || $otAmount > 0) {
            \DB::table('payroll_entries')
                ->where('id', $entry->id)
                ->update([
                    'overtime_hours' => $otHours,
                    'overtime_amount' => $otAmount,
                ]);
        }
    }
}

3. Verification & Testing Checklist

  • Database Migration Execution: Run php artisan migrate locally and verify the migration runs without error.
  • Historical Data Backfill: Query the payroll_entries table before and after migration to verify overtime_hours and overtime_amount are populated for older entries.
  • New Payroll Run Processing: Create a new payroll run, verify that the database fields are correctly calculated and stored.
  • Frontend View: Verify the Payroll Run Summary page displays the correct non-zero overtime columns.
  • Payslip Preservation: Confirm that payslip download and preview layouts remain correct and unaffected.