Overtime Rules — How It Works
Overview
Overtime kicks in when an employee works more than a set number of hours in a period. How those extra hours are paid depends on the overtime mode — typically at 1.5x the regular rate (time-and-a-half), but the x0.5 bank mode handles it differently (see below).
Overtime only applies to hourly employee positions, everything else is excluded. Currently the exclusion applies to:
- Salaried (yearly) employee positions
- Fixed amount per shift paid employee positions who get $0/h + fixed amount/shift. In order to export that on Nethris or Employeur D, they would use an earning code with Amount column type, not Hours + Rate.
The Two Settings That Matter
1. Max Hours Per Week (Company Setting)
Found in Account Settings > Preferences. The user selects the weekly hour threshold from a dropdown of hour values. This threshold determines when overtime begins. Defaults to 40 hours.
This setting is based on legal requirements that vary by province (and eventually by state and country). The company should choose the value that matches the labor laws where they operate.
2. Overtime Calculation Mode (Per Pay Period)
Found in Payroll > Settings > Hours Settings > Overtime Paid. Four options:
| Option | What It Does |
|---|---|
| Not Calculated | Overtime is ignored entirely. All hours are treated as regular hours. |
| Weekly (40 hours) | Overtime is calculated per week. Once an employee exceeds the max hours threshold in a single week, extra hours are overtime. |
| Biweekly (80 hours) | Overtime is calculated across the full two-week pay period. The threshold is double the max hours (e.g., 80 hours). Hours only become overtime after crossing that combined total. |
| Weekly (40 hours) x0.5 | Same calculation as Weekly, but the export includes an extra "bank" line with the overtime hours multiplied by 0.5. This is a specific use case. |
Weekly vs Biweekly — What's the Difference?
This matters most when the payroll frequency is biweekly (two weeks per pay period).
Weekly Overtime on a Biweekly Payroll
Each week is evaluated independently. If an employee works 45 hours in week 1 and 30 hours in week 2, they have 5 hours of overtime (from week 1 only). The weeks don't mix.
Biweekly Overtime on a Biweekly Payroll
Both weeks are combined into one pool. If an employee works 45 hours in week 1 and 30 hours in week 2, their total is 75 hours — still under the 80-hour threshold, so they have zero overtime. If there was overtime, it would be declared only when the cumulative hours surpass 80h and applies to the week where the threshold is reached (almost always week 2) for labor cost and payroll export.
Quick Comparison
| Scenario | Weekly Mode | Biweekly Mode |
|---|---|---|
| Week 1: 45h, Week 2: 30h | 5h overtime | 0h overtime |
| Week 1: 35h, Week 2: 50h | 10h overtime | 5h overtime |
| Week 1: 45h, Week 2: 45h | 10h overtime | 10h overtime |
| Week 1: 50h, Week 2: 20h | 10h overtime | 0h overtime |
Note: If the payroll frequency is weekly (not biweekly), the "Biweekly" overtime option is automatically disabled.
How Overtime Is Split Across Shifts
Overtime is calculated per shift, not as a lump sum at the end of the period.
The system looks at how many hours an employee has already worked before each shift. If a shift pushes the total past the threshold, only the portion that exceeds the threshold counts as overtime.
Example (40-hour weekly threshold):
| Day | Shift | Hours | Running Total | Regular | Overtime |
|---|---|---|---|---|---|
| Mon | Morning | 8h | 8h | 8h | 0h |
| Tue | Morning | 8h | 16h | 8h | 0h |
| Wed | Morning | 8h | 24h | 8h | 0h |
| Thu | Morning | 8h | 32h | 8h | 0h |
| Fri | Morning | 8h | 40h | 8h | 0h |
| Sat | Extra | 6h | 46h | 0h | 6h |
If Saturday's shift were 10 hours instead, the first 0 hours would be regular and all 10 would be overtime (since the employee already hit 40 before the shift started).
Multiple Shifts in the Same Day
When an employee has more than one shift on the same day, the system evaluates each shift in order of start time. Each shift's "past hours" includes all hours worked earlier in the week (or pay period, for biweekly mode) plus any earlier shifts on the same day — so if the threshold gets crossed mid-day, the shift that crosses it gets split between regular and overtime, and every shift after that is fully overtime.
Example — an employee is at 38h going into Friday and works two shifts:
| Shift | Start | Past Hours | Shift Hours | Regular | Overtime |
|---|---|---|---|---|---|
| Morning (8am) | 8:00 AM | 38h | 4h | 2h | 2h |
| Evening (6pm) | 6:00 PM | 42h | 4h | 0h | 4h |
The morning shift starts with 38h already accumulated from earlier in the week. Since the threshold is 40h, only 2 of the morning's 4 hours are regular — the remaining 2 cross the threshold and become overtime. By the time the evening shift starts, the employee is already at 42h, so all 4 evening hours are overtime.
The x0.5 Bank Mode
When set to Weekly (40 hours) x0.5, the overtime calculation is identical to regular weekly mode. The difference is only in the export file.
For every overtime hour, the export produces two lines:
- Overtime line — the full overtime hours with the configured earning code
- Bank line — the overtime hours multiplied by 0.5 with a separate earning code
Example: An employee has 5 overtime hours.
- Overtime earning code: 5 hours
- Bank earning code: 2.5 hours (5 × 0.5)
This bank line is only available for Nethris and EmployeurD integrations.
Overtime in Exports
How overtime appears depends on the export format:
| Export Format | Overtime Included? | Notes |
|---|---|---|
| Nethris / EmployeurD | Yes | Separate overtime rows with configurable earning codes. Supports hours+rate or flat amount mode. |
| Powerpay | Yes | Separate overtime entry per shift at 1.5x rate. |
| Acomba | Yes | Uses line code 103 for time-and-a-half hours. |
| By Week | Yes | Grouped by position and rate, overtime tracked per week. |
| By Shift | Yes | Overtime visible on each individual shift row. |
| QuickBooks Time | No | Regular hours only. |
| QuickBooks Online | No | Regular hours only. |
| Payevolution | Yes | Overtime included per position grouping. |
Export Earning Codes
In Payroll > Settings > Export Settings, you can configure:
- Overtime earning code — the code your payroll provider uses for overtime (e.g., "100")
- Earning mode — whether to export as hours + rate, or as a flat dollar amount
- Overtime variations — up to 2 additional overtime earning codes for special cases
What Overtime Does NOT Include
The current system does not support:
- Daily overtime thresholds (e.g., overtime after 8 hours in a single day)
- California-style overtime rules
- 7th consecutive day rules
- Double-time (2x rate) — it is always 1.5x
- Overtime for salaried/yearly employees
Visual Indicators
In the Hours table:
- Weekly total cells turn red when hours exceed the weekly threshold
- Period total cells turn red when total hours exceed the period threshold
- Individual shift hours turn red when that shift contains any overtime
Where Overtime Is Used
Payroll — Settings
| Screen | What It Does |
|---|---|
| Payroll > Settings > Hours Settings | Dropdown to select the overtime calculation mode (Not Calculated, Weekly, Biweekly, Weekly x0.5) |
| Payroll > Settings > Export Settings | Configure overtime earning codes, earning mode (hours+rate or amount), bank earning code (for x0.5), and up to 2 overtime variations |
| Account Settings > Preferences | Dropdown to select the max hours per week threshold |
Payroll — Hours Table
| Screen | What It Does |
|---|---|
| Hours table (daily rows) | Shift cells turn red when a shift contains overtime |
| Hours table (summary rows) | Weekly and period totals turn red when they exceed the overtime threshold |
| Shift popover (inline editor) | Shows overtime breakdown when editing a shift; recalculates overtime live as you adjust hours |
Payroll — Export
| Screen | What It Does |
|---|---|
| Nethris / EmployeurD | Overtime rows with earning codes; supports bank rows for x0.5 mode |
| Powerpay | Separate overtime entry per shift |
| Acomba | Overtime mapped to line code 103 (time-and-a-half) |
| By Week | Overtime tracked per week, grouped by position and rate |
| By Shift | Overtime visible on each shift row |
| Payevolution | Overtime included per position grouping |
| QuickBooks Time / Online | No overtime — regular hours only |
| Export modal | Uses overtime export settings to build the export file |
Schedule
| Screen | What It Does |
|---|---|
| Position view | Shifts are flagged as overtime when the employee's weekly hours exceed the threshold |
| Employee view | Same overtime indicators per shift |
| Shift popovers | Show overtime status for individual shifts |
| Available employee selector | Shows overtime status when picking who to assign a shift to |
| Labor cost modal | Projects overtime costs using the backend labor calculator |
Head Office
| Screen | What It Does |
|---|---|
| Head Office > Export Payroll | Multi-location export with its own overtime calculation (same logic as Payroll, simplified for bulk export) |
Requests
| Screen | What It Does |
|---|---|
| Conflict shift details popover | Shows if a conflicting shift would result in overtime |
Backend — Labor Cost
| Component | What It Does |
|---|---|
| Labor calculator | Projects labor costs for the schedule page, including overtime premium (1.5x). Uses hardcoded 40/80 thresholds (not the company setting). |
Duplicate Implementations — Testing Warning
The overtime calculation algorithm is duplicated across 5 independent implementations. Any change to overtime rules must be tested across all of them:
| # | Location | Threshold | Same-Day Logic | Notes |
|---|---|---|---|---|
| 1 | Payroll — attendanceEnhancement.ts | maxHoursPerWeek (configurable) | Earlier shifts count as past hours → later shifts get OT | Source of truth for payroll |
| 2 | Payroll — ShiftPopover.tsx | maxHoursPerWeek (configurable) | Same as #1 | Live preview when editing a shift |
| 3 | Head Office — enhanceAttendanceData.ts | maxHoursPerWeek (configurable) | Sorts ascending by start time (same result as #1) | Simplified for multi-location bulk export |
| 4 | Schedule — LaborCostModalUI.js (×2 copies) | Hardcoded 40/80 | Includes all same-day shifts except current (no ordering) | One copy for attendance, one for scheduled shifts |
| 5 | Backend — OvertimeCalculator | Hardcoded 40/80 | No same-day logic | Labor cost projections only, used for mobile at the moment |
Known inconsistencies:
- Implementations #4 and #5 use hardcoded 40/80 thresholds instead of the configurable
maxHoursPerWeekcompany setting - Implementation #4 (LaborCostModalUI) does not distinguish shift ordering on the same day — it counts all other same-day shifts as past hours regardless of start time