Four people, one schedule, four different ways to be paid
A workforce where factory, field and remote staff share a calendar but not a contract — and an attendance engine that can tell them apart.
The problem a client brought us
“Four of our people work the same hours on the same calendar. Two get paid for overtime and two don't, because that's what their contracts say. The system can't tell them apart.”
Before and after
Derived from a schedule that cannot express them
- Overtime eligibility
- Site allowances
- Break deduction
- Day counting
Each read from what the person is entitled to
One attendance engine
What we found and built
A resource calendar models when someone is expected to work. It does not model whether they are entitled to be paid for working beyond it. Those are independent facts, and Odoo carries only the first.
So every rule that depends on the second — overtime eligibility, site allowances, how a day is counted — was being derived from a schedule that cannot express it. The same gap showed up everywhere attendance met money: device punches at the factory gate, phone check-ins from client sites, travel days — all sharing one calendar, all needing different treatment.
We gave the missing fact a home of its own, and made every rule that pays for an hour read it from there.
Result
Payroll and attendance agree for every employee, however differently their contracts treat the same hour worked. 147 tests pin the rules that money depends on.
What we built
-
Overtime entitlement
Overtime entitlement is its own fact
A per-employee switch, gated by a schedule-level policy: all staff, selected departments, or named employees. Four people on one calendar, four different outcomes.
-
Attendance types
Each way of working carries its own rules
Four configurable types plus device and manual sources. Each type decides whether it needs approval, whether breaks are deducted, and whether it carries an allowance.
-
Overtime thresholds
Small overruns never become payroll noise
A 10-minute grace after scheduled end, then a 60-minute minimum stay before overtime is paid. Shift ending 18:00: leave at 18:55 and nothing is paid; leave at 19:30 and 1 h 20 is paid, counted from 18:10.
-
Day classifier
Payroll counts a day the way attendance does
Worked hours as a share of expected become a full day, half day or absent, at per-schedule thresholds. Payroll reads the same classifier, so the two can't drift.
-
Site allowances
Allowances follow where the work happened
Sites carry a centre and a radius; an allowance is claimable only when the employee was outside every assigned site. The allowance belongs to the attendance type, not the site.
-
Exception dashboard
Problems surface before payroll closes
Absent, late, missing check-out, outside the hour band, under expected hours, pending approval — one detector feeds both the dashboard and the report.
-
Overtime ledger
Earned overtime has an exit of its own
A ledger kept separate from payroll, so earned hours can be taken as leave or paid in cash without either path corrupting the other.
The pattern behind it
One definition everyone calls
When several parts of a system each decide the same fact, they eventually disagree. We don't add a fourth opinion — we collapse the disagreement into one definition and make everything else read from it.
How we think about problemsFurther reading
We read our own attendance engine twice, and the second pass corrected six things
Nine things a business believed about its overtime, allowance and payroll rules — checked line by line against the code, then checked again.
Read the noteOvertime that can be paid, not only taken as leave
Earned overtime had one exit — a leave allocation. Now an administrator pays the days they choose, at a rate, and the rest stay pending.
~8,000 LOC Read the case studyBiometric attendance data the payroll engine can trust
Three punches from one person became one event — and HR notifications stopped firing for months-old data.
Read the case studyRecognise any of this?
Most of our work starts with a message that sounds a lot like this one did.