Sick pay (loondoorbetaling)
HRMQ already modelled the administrative side of sickness
(SickLeaveCase and the Poortwachter
clock) and already has the gross-to-net engine, but the two are
connected: a sick employee's payslip does not simply feed the engine
the full grossMonthlySalary. SickPayCalculator computes loondoorbetaling
bij ziekte (BW 7:629 lid 1) first, and the resulting doorbetaald loon
is what the payroll engine actually taxes.
The calculation
For a fully-sick employee, in order:
- Continuation —
70%of the reference wage (the case'sloondoorbetalingPercentage, default 70; many CAOs set 90 or 100) - Year-1 minimum-wage floor — in the first 52 weeks of
firstSickDay, doorbetaald loon is raised to the statutory WML monthly floor if the raw 70% would fall below it (part-time scaled). Past 52 weeks (year 2) the WML floor drops out, leaving the bare 70%-of-wage floor. - Wachtdag deduction — one waiting day, valued at the doorbetaald
daily rate, deducted once per case, only in the month
firstSickDayactually falls in — never in a continuation month. - Samengesteld/aangepast loon — an optional
aangepastLoon(wage still earned from partial work) composes as the worked wage at 100% plus continuation on the non-worked remainder.
All arithmetic is integer cents with half-up rounding at the
percentage-multiply and wachtdag-divide steps — never accumulated
floats. PayrollCalculator itself is not modified: SickPayCalculator
computes the doorbetaald loon, and that figure is fed into the existing
engine as the period's taxable gross.
Worked example
A fully-sick, full-time employee earning €3.800,00, 70%, year 1, no
wachtdag: continuation is €2.660,00, the floor doesn't bind
(floorApplied: false), and payableGross is €2.660,00 — the figure
that goes into loonheffing/net, not €3.800,00.
The payslip reflects doorbetaald loon, not the full salary
When PayrollRunService finds an open (gemeld) SickLeaveCase
covering the run period for an employee, it feeds the computed
payableGross into CalculationInput instead of the full salary. The
generated Payslip is stamped with sickLeaveCaseId, doorbetaaldLoon,
wachtdagDeduction, sickPayReferenceWage, sickPayPercentage,
sickPayMinimumWageFloor and sickPayYearOne (all null/absent on a
non-sick payslip). When no open case covers the period, the full-salary
path is entirely unchanged.
Machine-checked floor
nl-loondoorbetaling-floor independently recomputes the 70%/WML floor
from a Payslip's own recorded fields and flags any doorbetaald loon
below it — a mandatory violation:
occ hrmq:rules:audit
Sick pay is generated automatically as part of the normal run:
occ hrmq:payroll:run --period 2026-06
There is no separate command — SickLeaveCase lookups happen inside
PayrollRunService::generate() for every active employee.