T1 Electrical SolutionsT1 Platform Docs
Allowance Matrix

Allowance Calculation Engine

Allowance Calculation Engine

The calculation engine is App\Service\Payroll\AllowanceMatrixCalculator.

High-level algorithm

calculateLines(Timesheet $timesheet) performs this flow:

1. Resolve project from timesheet.
2. Stop if project or client is missing.
3. Load client allowances for the project client, sorted by name.
4. Keep only active and enabled allowances.
5. For each allowance:
   a. Check project applicability.
   b. Resolve effective amount unit.
   c. Dispatch to hourly, daily, weekly, daily_or_weekly, or project_variable calculation.
6. Return calculated TimesheetAllowanceLine objects.

refreshCalculatedLines(Timesheet $timesheet) removes all existing allowance lines from the timesheet and EntityManager, then persists the newly calculated lines. This makes recalculation idempotent for the current state.

Amount-unit dispatch

UnitMethodQuantity behavior
hourlycalculateHourlyLinesSum matched entry hours, or use overtime/normal time aggregate quantities for those trigger types.
dailycalculateDailyLinesCount unique worked dates that match the trigger.
daily_or_weeklycalculateDailyOrWeeklyLineCount unique worked dates until threshold, then use one weekly unit. Can use triggerConfig.weeklyAmount.
weeklycalculateWeeklyLineOne unit if any entry matches.
project_variablecalculateManualSelectionLines or project-resolved unitIf project type resolves to hourly/daily/weekly/daily_or_weekly, the calculator dispatches to that effective type. Otherwise manual quantity is read from entry selections.

Effective amount unit

resolveEffectiveAmountUnit() keeps the client allowance unit unless it is project_variable. For project-variable allowances, it reads the matching project allowance row type and maps it to:

  • hourly
  • daily
  • weekly
  • daily_or_weekly

If no valid project type exists, it remains project_variable and uses manual-selection style quantity.

Effective unit rate

resolveUnitRate() first checks project allowance rows for a matching name and numeric rate. It strips non-numeric/currency characters before parsing. If a project rate exists, it overrides ClientAllowance.amount. If not, the client allowance amount is used, defaulting to 0.

Line snapshot

Every output line stores a sourceSnapshot containing:

  • clientAllowanceId
  • triggerType
  • applicationMode
  • amountUnit
  • configuredAmountUnit
  • isEab
  • triggerConfig
  • extra context such as matched dates, matched entries, overtime hours, normal time hours, selected mode, or threshold values

This snapshot is critical because project/client rules may change later. The line should still explain what was calculated at the time it was generated.

On this page