Skip to main content

Overview

SushiGo maintains a complete history of employee wages using effective-dated records. This allows the system to track wage changes over time, apply the correct wage for payroll calculations in any period, and maintain an audit trail of compensation changes.

Why Effective-Dated History?

Traditional systems might simply update an employee’s current wage, losing historical data. Effective-dated history solves several business problems:

Historical Accuracy

Calculate past payroll periods with the wages that were actually in effect at that time

Future Planning

Schedule wage increases in advance with a future effective date

Audit Trail

Complete record of all wage changes for compliance and review

Retroactive Corrections

Close previous wage records and create new ones if errors are discovered

Data Model

WageHistory Fields

'employee_id'              // Foreign key to Employee
'hourly_rate'              // Decimal(10,2), must be > 0
'weekly_scheduled_hours'   // Decimal(5,2), must be > 0
'effective_from'           // Required date - when wage starts
'effective_to'             // Nullable date - when wage ends (null = current)

Key Concepts

The amount paid per hour worked. Must be strictly greater than zero.Examples:
  • 125.00 - $125.00 per hour
  • 85.50 - $85.50 per hour
Zero or negative rates are invalid and will be rejected
The standard number of hours the employee is scheduled to work per week. Used to calculate full-time equivalency and proportional benefits.Examples:
  • 48.00 - Standard full-time (6 days × 8 hours)
  • 40.00 - 5-day work week
  • 24.00 - Part-time employee
Must be strictly greater than zero
The date when this wage becomes effective. Can be:
  • Past date: Retroactive wage (e.g., correcting historical records)
  • Current date: Immediate wage change
  • Future date: Scheduled wage increase
System uses this date to determine which wage applies for payroll calculations
The last date this wage is valid. After this date, the next wage record takes effect.
  • NULL: Currently active wage (open-ended)
  • Date value: Wage was replaced or closed on this date
Only one wage record should have effective_to = NULL per employee (the current wage)

Validation Rules

The validation rules are defined as constants in WageHistory.php:22:
const RULES = [
    'hourly_rate' => ['required', 'numeric', 'gt:0'],
    'weekly_scheduled_hours' => ['required', 'numeric', 'gt:0'],
    'effective_from' => ['required', 'date'],
    'effective_to' => ['nullable', 'date', 'after_or_equal:effective_from'],
];

Field Requirements

FieldRequiredTypeConstraints
hourly_rateYesNumericMust be > 0
weekly_scheduled_hoursYesNumericMust be > 0
effective_fromYesDateISO 8601 format
effective_toNoDateMust be ≥ effective_from if provided

Creating Wage Records

Initial Wage

When an employee is created, you’ll typically create their initial wage record:
curl -X POST "/api/v1/employees/{employee_id}/wages" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "hourly_rate": 125.00,
    "weekly_scheduled_hours": 48.00,
    "effective_from": "2026-03-06"
  }'
effective_to is null, indicating this is the current active wage

Wage Increase

To give an employee a raise, create a new wage record:
1

Create new wage record

Create a new WageHistory record with the increased rate and new effective_from date
2

System closes previous wage

The system automatically sets effective_to on the previous wage record to the day before the new wage’s effective_from
This automation may be implementation-specific. Check your actual API behavior.
3

New wage becomes active

On the effective_from date, the new wage is used for all payroll calculations
curl -X POST "/api/v1/employees/{employee_id}/wages" \
  -H "Authorization: Bearer {token}" \
  -H "Content-Type: application/json" \
  -d '{
    "hourly_rate": 135.00,
    "weekly_scheduled_hours": 48.00,
    "effective_from": "2026-04-01"
  }'
Result: Employee will earn 125/hruntilMarch31,2026,then125/hr until March 31, 2026, then 135/hr starting April 1, 2026.

Querying Wage History

Get Current Wage

To find the wage effective on a specific date, use the effective() scope:
$currentWage = WageHistory::where('employee_id', $employee->id)
    ->effective(now())
    ->first();
The effective() scope is defined in WageHistory.php:64:
public function scopeEffective(Builder $query, DateTimeInterface|string $date): Builder
{
    return $query
        ->where('effective_from', '<=', $date)
        ->where(function (Builder $q) use ($date) {
            $q->whereNull('effective_to')
              ->orWhere('effective_to', '>=', $date);
        });
}

Logic Explanation

A wage is effective on a date when:
  1. effective_from ≤ date: The wage has started
  2. AND either:
    • effective_to IS NULL: The wage is currently active, OR
    • effective_to ≥ date: The wage hasn’t ended yet
Wage Records:
[
  {
    "hourly_rate": 100.00,
    "effective_from": "2026-01-01",
    "effective_to": "2026-02-29"
  },
  {
    "hourly_rate": 110.00,
    "effective_from": "2026-03-01",
    "effective_to": "2026-03-31"
  },
  {
    "hourly_rate": 120.00,
    "effective_from": "2026-04-01",
    "effective_to": null
  }
]
Query Results:
  • effective('2026-02-15') → $100.00/hr (first record)
  • effective('2026-03-15') → $110.00/hr (second record)
  • effective('2026-04-15') → $120.00/hr (third record, current)
  • effective('2026-05-15') → $120.00/hr (third record, still current)

Get All Wage History

To retrieve complete wage history for an employee:
$wageHistory = $employee->wageHistories()
    ->orderBy('effective_from', 'desc')
    ->get();
The relationship is defined in Employee.php:94:
public function wageHistories(): HasMany
{
    return $this->hasMany(WageHistory::class)
        ->orderBy('effective_from', 'desc');
}

Calculations

Per-Minute Rate

The WageHistory model provides a helper to calculate the per-minute rate:
public function minuteRate(): float
{
    return (float) $this->hourly_rate / 60;
}
Usage:
$wage = $employee->wageHistories()->effective(now())->first();
$perMinute = $wage->minuteRate();

// Example: $125/hr ÷ 60 = $2.0833.../minute
This is used for calculating pay deductions when employees are late or take unpaid partial leave (RF-15b, RF-25b).

Weekly Base Pay

To calculate weekly base pay:
$weeklyPay = $wage->hourly_rate * $wage->weekly_scheduled_hours;

// Example: $125/hr × 48 hours = $6,000/week

Daily Rate (Proportional)

For daily wage calculations:
$workingDaysPerWeek = 6; // From employee schedule
$dailyRate = ($wage->hourly_rate * $wage->weekly_scheduled_hours) / $workingDaysPerWeek;

// Example: ($125 × 48) ÷ 6 = $1,000/day

Common Scenarios

Scenario 1: New Employee Initial Wage

1

Employee created

Employee EMP-025 hired on March 6, 2026
2

Create wage record

{
  "hourly_rate": 100.00,
  "weekly_scheduled_hours": 48.00,
  "effective_from": "2026-03-06"
}
3

Result

Employee has one wage record with effective_to = null (current wage)

Scenario 2: Scheduled Future Raise

1

Current state

Employee earning $100/hr, effective since March 6
2

Schedule raise

Create new wage record:
{
  "hourly_rate": 110.00,
  "weekly_scheduled_hours": 48.00,
  "effective_from": "2026-06-01"
}
3

Before June 1

System uses $100/hr wage for all calculations
4

On June 1 and after

System automatically uses $110/hr wage for all calculations

Scenario 3: Retroactive Wage Correction

1

Discover error

Employee should have been earning 120/hrsinceApril1,butsystemshows120/hr since April 1, but system shows 110/hr
2

Close incorrect wage

Update old wage record:
{
  "effective_to": "2026-03-31"
}
3

Create corrected wage

Create new wage record with correct rate:
{
  "hourly_rate": 120.00,
  "weekly_scheduled_hours": 48.00,
  "effective_from": "2026-04-01"
}
4

Recalculate payroll

Reopen affected pay periods and recalculate with correct wage
Retroactive corrections require admin permissions and should trigger payroll recalculation for affected periods.

Scenario 4: Change from Full-Time to Part-Time

1

Current state

Employee working 48 hours/week at $100/hr
2

Employee requests part-time

Starting April 1, employee will work 24 hours/week
3

Create new wage record

{
  "hourly_rate": 100.00,
  "weekly_scheduled_hours": 24.00,
  "effective_from": "2026-04-01"
}
Hourly rate stays the same, but weekly hours reduced
4

Result

  • Before April 1: 100/hr×48hours=100/hr × 48 hours = 4,800/week
  • After April 1: 100/hr×24hours=100/hr × 24 hours = 2,400/week

Payroll Integration

Pay Period Calculation

When calculating pay for a period:
1

Identify pay period

Example: March 4-10, 2026
2

Query effective wage

For each day in the period, get the wage effective on that day:
$wage = WageHistory::where('employee_id', $employeeId)
    ->effective($date)
    ->first();
3

Calculate daily pay

Use the effective wage’s hourly_rate and weekly_scheduled_hours for that day’s calculations
4

Sum period total

Aggregate daily calculations for period total
If wage changes mid-period, the system automatically uses the correct wage for each portion of the period.

Example: Wage Change Mid-Period

Pay Period: March 27 - April 2, 2026 (Thu-Wed) Wages:
  • $100/hr until March 31
  • $110/hr starting April 1
Calculation:
DateWageHoursPay
Mar 27$100/hr8$800
Mar 28$100/hr8$800
Mar 29$100/hr8$800
Mar 30$100/hr8$800
Mar 31$100/hr8$800
Apr 1$110/hr8$880
Apr 2$110/hr8$880
Total56 hrs$5,760
System automatically applies correct wage for each day without manual intervention

Validation Errors

{
  "message": "The hourly rate field must be greater than 0.",
  "errors": {
    "hourly_rate": [
      "The hourly rate field must be greater than 0."
    ]
  }
}

Best Practices

Never Delete Wages

Always close wage records with effective_to instead of deleting. Maintains complete audit trail.

Schedule in Advance

Create future wage records to automate raises. System applies automatically on effective date.

Document Changes

Use meta field or notes to record reason for wage changes (promotion, cost of living, etc.)

Validate Before Close

Verify wage calculations are correct before closing a pay period

Creating Employees

Learn how to create employees and set initial wages

Attendance Tracking

How wages integrate with attendance and payroll

Payroll Calculation

Detailed payroll calculation logic using wage history

API Reference

Complete API documentation for wage management

Build docs developers (and LLMs) love