The Canadian Payroll Regulatory Landscape — Why Odoo Canada Is Not Odoo US
Canadian payroll is deceptively complex. On paper it's one country with one payroll engine; in practice it's two parallel tax administrations, thirteen provincial and territorial tax schedules, two public pension schemes, two unemployment insurance programs, four distinct workers' compensation regimes, and an employer health tax that changes name and rate at every provincial border. If you are migrating to Odoo from ADP, Ceridian Dayforce, Nethris, or QuickBooks Payroll, the first rule is that the Canadian Odoo localization is not a minor skin on the US module — it is a separate module, l10n_ca_hr_payroll, with its own structures, rules, and year-end reporting engine.
At the federal level, the Canada Revenue Agency (CRA) administers income tax withholding, Canada Pension Plan (CPP and CPP2) contributions, Employment Insurance (EI) premiums, and the T4/T4A information return for every province except Quebec. For Quebec-resident employees, almost everything splits: Revenu Québec administers Quebec provincial income tax (via the TP-1 return), the Quebec Pension Plan (QPP) replaces CPP, the Quebec Parental Insurance Plan (QPIP) runs alongside a reduced federal EI rate, and year-end slips are filed as RL-1 instead of T4. An employee based in Gatineau who crosses the river to work in Ottawa has federal CPP and EI on their payslip; their coworker one desk over who lives and works in Montreal has QPP, QPIP, and reduced EI. Both work for the same company. Both run through the same Odoo database. Different rules fire for each.
On top of this sit the provincial payroll taxes. Ontario employers pay the Employer Health Tax (EHT) on the portion of annual payroll above the exemption threshold. Quebec employers pay the Fonds des services de santé (FSS), a health services fund with a sliding rate depending on total payroll. British Columbia has its own EHT. Manitoba has the Health and Post-Secondary Education Tax Levy. None of these are employee deductions — they are employer-only costs computed on the payroll base, and they need journal entries on every payslip run even though they never appear on the employee's T4.
Workers' compensation is another four-way split. In Ontario it's WSIB billed quarterly on assessable earnings. In Quebec it's CNESST with monthly remittance and an annual reconciliation. In Alberta it's the WCB-Alberta. In British Columbia it's WorkSafeBC. Each province publishes its own classification units, rate groups, and maximum assessable earnings ceilings. Odoo models these as separate "contribution" rules tied to the employee's work-location province, not the company's head-office province — a distinction that trips up implementations where the head office is in Toronto but half the crew is on a job site in Calgary.
The upshot is that "Canadian payroll in Odoo" is not one configuration — it's a matrix of federal rules, provincial rules, and Quebec-specific overrides that must be bound to the right employee contract through the right work-location record. Get the matrix right on day one and month-end close takes twenty minutes; get it wrong and your first RL-1 run in February will surface errors that have compounded for twelve months. The rest of this guide walks through that matrix, with the exact module configuration, Python salary rule logic, and year-end filing workflow we use for Octura Solutions clients running Odoo in Canada.
Installing and Configuring the Canadian Payroll Module in Odoo 19
The Canadian payroll localization lives in the l10n_ca_hr_payroll module (Enterprise only). Installing l10n_ca — the Canadian accounting chart — does not install the payroll pieces. These are separate modules, and on a fresh database you typically need to install both plus the Quebec-specific overlay if you employ anyone in Quebec.
# From odoo-bin, install the full Canadian stack
./odoo-bin -c /etc/odoo/odoo.conf -d octura_prod \
-i l10n_ca,l10n_ca_hr_payroll,l10n_ca_hr_payroll_account,hr_payroll \
--stop-after-init
# If you employ anyone in Quebec, also install:
./odoo-bin -c /etc/odoo/odoo.conf -d octura_prod \
-i l10n_ca_qc_hr_payroll \
--stop-after-initOnce installed, the module ships with pre-built salary structure types for Canadian federal and provincial regimes, pre-loaded CRA tax tables (T4127 federal and provincial brackets) and Revenu Québec tables (TP-1015.F), contribution rules for CPP, CPP2, QPP, EI, QPIP, and wrappers for employer-only items like EHT, FSS, CNESST, and WSIB. The default data is a starting point — every rate and ceiling still needs to be verified against the current year's CRA and RQ publications before you confirm your first payslip batch.
Company Configuration — The Employer Identity
Payroll journal entries, T4 and RL-1 slips all pull their identifying numbers from the res.company record. Before you run anything, the company must carry: the CRA Business Number (BN) with the RP payroll account suffix (for example 123456789RP0001), the Quebec enterprise number (NEQ), the Revenu Québec identification number for source deductions, the CNESST numéro d'employeur, the WSIB/WorkSafe account number, and the EI reduced-rate classification if you employ anyone in Quebec.
from odoo.exceptions import ValidationError
company = env.company
missing = []
if not company.l10n_ca_cra_business_number:
missing.append('CRA Business Number (BN15 with RP suffix)')
if company.country_id.code == 'CA':
if not company.vat:
missing.append('GST/HST number')
# Quebec-specific
quebec_employees = env['hr.employee'].search_count([
('address_id.state_id.code', '=', 'QC'),
('company_id', '=', company.id),
])
if quebec_employees and not company.l10n_ca_qc_enterprise_number:
missing.append('Quebec NEQ')
if quebec_employees and not company.l10n_ca_rq_identification_number:
missing.append('Revenu Québec identification number')
if missing:
raise ValidationError(
"Cannot run Canadian payroll. Missing: " + ", ".join(missing)
)Employee Contract Configuration
Canadian payroll is driven almost entirely by the contract. The fields that matter on every hr.contract record: structure_type_id must point to "CA Employee" (or "QC Employee" for Quebec residents), wage_type is monthly, hourly, or fixed, schedule_pay sets the pay period (weekly, bi-weekly, semi-monthly, monthly), and l10n_ca_claim_code_federal and l10n_ca_claim_code_provincial store the TD1 claim amounts from the employee's signed TD1/TD1-provincial form. Quebec employees also need l10n_ca_claim_code_qc from their TP-1015.3-V form.
| Pay Schedule | Code | Annualization Factor | Typical Use |
|---|---|---|---|
| Weekly | weekly | 52 | Unionized trades, hourly site workers |
| Bi-weekly | bi-weekly | 26 | Most Canadian private-sector employers |
| Semi-monthly | semi-monthly | 24 | Salaried office staff, professional services |
| Monthly | monthly | 12 | Executives, small-company owner-operators |
Salary Structure Inheritance
Odoo's Canadian module uses the same inheritance model covered in our Odoo 19 Payroll Setup guide. One "CA Employee" structure type contains multiple concrete structures: Regular Pay, Bonus, Commission, Severance, and Stock Option Benefit. Each structure inherits the federal and provincial contribution rules but varies the basic rule — so a bonus payslip still triggers CPP, EI, and income tax withholding, but uses the bonus tax method (TD1X) rather than the periodic method.
Work Entry Types for Canadian Payroll
The default WORK100 entry type covers regular hours, but Canadian payroll usually needs additional types to keep the T4/RL-1 boxes clean at year-end: STAT for statutory holiday pay (required separately by most provincial Employment Standards Acts), VAC for vacation pay (accrual tracking is a legal obligation), OVT for overtime premium hours (Ontario's 44-hour threshold differs from BC's 40-hour threshold — configure per province), SICK for paid sick leave (mandatory in BC, QC, PEI, federally-regulated sectors), and BRVMT for bereavement. Each type maps to a salary rule that decides whether hours are pensionable, insurable, vacationable, and which T4/RL-1 box they land in.
Every Canadian jurisdiction requires employers to either pay vacation pay on each cheque or accrue it to a liability account. In Odoo, this is a VAC salary rule that computes as categories['GROSS'] * vacation_rate, where vacation_rate is 4% for most employees (minimum), 6% after 5 years in Saskatchewan, 8% in Nunavut. Misconfigure this and you will owe employees retroactive vacation pay plus interest — a common finding in provincial Employment Standards audits.
CPP and CPP2: Configuring Canada Pension Plan Contributions for 2026
The Canada Pension Plan has been running through its enhancement schedule since 2019, and 2026 is the first full year with the second-tier CPP2 bracket fully phased in. There are now two separate ceilings, two rates, and two corresponding boxes on the T4 slip. For 2026, the Year's Maximum Pensionable Earnings (YMPE) sits at approximately CAD $72,400, with a basic exemption of $3,500. The employee contribution rate on earnings between the exemption and the YMPE is 5.95%, matched by the employer. Earnings between the YMPE and the Year's Additional Maximum Pensionable Earnings (YAMPE) — roughly $82,400 for 2026 — are subject to CPP2 at 4.00% employee and 4.00% employer.
# Rule code: CPP — sequence 61, category DED
# 2026 parameters (verify annually against CRA T4127)
YMPE = 72400.00
YAMPE = 82400.00
BASIC_EXEMPTION = 3500.00
CPP_RATE = 0.0595
CPP2_RATE = 0.0400
# Pay period gross (pensionable earnings for this cheque)
pensionable = categories['GROSS']
# Annualize for ceiling comparison using the contract's pay schedule
periods = {
'weekly': 52, 'bi-weekly': 26,
'semi-monthly': 24, 'monthly': 12,
}[contract.schedule_pay]
# Per-period exemption (basic exemption pro-rated)
period_exemption = BASIC_EXEMPTION / periods
period_ympe = YMPE / periods
period_yampe = YAMPE / periods
# Tier 1: CPP on earnings above exemption up to YMPE
tier1_base = max(0, min(pensionable, period_ympe) - period_exemption)
cpp = tier1_base * CPP_RATE
# Tier 2: CPP2 on earnings between YMPE and YAMPE
tier2_base = max(0, min(pensionable, period_yampe) - period_ympe)
cpp2 = tier2_base * CPP2_RATE
# Deductions are negative
result = -round(cpp + cpp2, 2)The employer-side matching contribution runs as a separate rule (category Employer Cost, sequence 200 range) that mirrors the calculation but does not reduce net pay — it posts to an employer CPP expense account and an employer CPP payable account in the payroll journal. Odoo's Canadian module ships with this pair already wired; the only thing you typically override is the rate constants at the turn of each calendar year.
CPP ceilings apply per employer, not per person. If an employee changes jobs mid-year they may over-contribute across the two employers; CRA reconciles this on their personal T1 return. Do not try to credit previous-employer contributions in Odoo — your only obligation is to stop deducting once your cumulative YTD pensionable earnings hit the YMPE for the tier.
Employment Insurance (EI): Federal Rate, Quebec Reduced Rate, Employer 1.4x Match
Employment Insurance premiums are simpler than CPP: a flat percentage up to an annual Maximum Insurable Earnings (MIE) ceiling, with no exemption. For 2026, the MIE is approximately CAD $65,700. The federal employee rate is 1.64%, and employers pay 1.4 times the employee premium. For employees resident in Quebec, the federal EI rate is reduced (to roughly 1.31% for 2026) because QPIP covers maternity and parental benefits separately.
# Rule code: EI — sequence 62, category DED
MIE = 65700.00 # 2026 Maximum Insurable Earnings
EI_RATE_FEDERAL = 0.0164 # rest of Canada
EI_RATE_QUEBEC = 0.0131 # Quebec reduced rate (QPIP offset)
insurable = categories['GROSS']
periods = {
'weekly': 52, 'bi-weekly': 26,
'semi-monthly': 24, 'monthly': 12,
}[contract.schedule_pay]
period_cap = MIE / periods
capped = min(insurable, period_cap)
# Branch on employee's province of residence
is_qc = employee.address_id.state_id.code == 'QC'
rate = EI_RATE_QUEBEC if is_qc else EI_RATE_FEDERAL
result = -round(capped * rate, 2) The 1.4x employer match is a separate rule on the employer-cost side; if your business qualifies for an EI Premium Reduction (short-term disability plans, certain registered programs), the employer multiplier drops below 1.4 — Odoo stores this as l10n_ca_ei_employer_rate on the company record and the rule reads it as a parameter instead of hardcoding 1.4.
Provincial Income Tax: Ten Provinces, Three Territories, One Rule Engine
Every Canadian employee pays two income taxes on every cheque: federal income tax and one provincial (or territorial) income tax. The federal tax is uniform across the country; the provincial tax varies in both rates and brackets. Alberta has a nearly-flat structure. Ontario layers a "surtax" on the basic calculation once tax payable exceeds a threshold. BC has seven brackets. Quebec is not handled by CRA at all and has its own section below.
Odoo's l10n_ca_hr_payroll module stores the bracket tables in hr.rule.parameter records keyed by year and province. Each jurisdiction has a distinct parameter — l10n_ca_tax_federal_brackets_2026, l10n_ca_tax_on_brackets_2026, l10n_ca_tax_bc_brackets_2026, and so on. The salary rule reads the parameter at compute time, so when CRA publishes the new T4127 tables each January, you update the parameter record and every payslip from that date forward uses the new rates without touching the rule code.
# Rule code: TAX_PROV — sequence 63, category DED
from datetime import date
province = employee.work_location_id.state_id.code or employee.address_id.state_id.code
year = payslip.date_to.year
# Fetch bracket table for this province + year
param_key = f'l10n_ca_tax_{province.lower()}_brackets_{year}'
brackets = env['hr.rule.parameter'].get_param(param_key) or []
# Annualize per-period gross for bracket lookup
periods = {
'weekly': 52, 'bi-weekly': 26,
'semi-monthly': 24, 'monthly': 12,
}[contract.schedule_pay]
annual_gross = categories['GROSS'] * periods
# Apply the TD1 provincial claim code exemption
claim_amount = contract.l10n_ca_claim_code_provincial or 0
taxable = max(0, annual_gross - claim_amount)
# Progressive bracket walk: brackets = [(upper, rate, constant), ...]
annual_tax = 0
for upper, rate, constant in brackets:
if taxable <= upper:
annual_tax = taxable * rate - constant
break
else:
upper, rate, constant = brackets[-1]
annual_tax = taxable * rate - constant
# Convert to per-period and negate
result = -round(annual_tax / periods, 2) The critical configuration detail: Odoo binds the province to the employee's work location, not their residence. This matters for remote workers. An employee living in Gatineau (Quebec) but reporting to an Ottawa office has their payroll taxes computed on the Ontario bracket table and pays Ontario provincial tax, with a reconciliation on their personal T1 at year-end. CRA's rule is that the "province of employment" for withholding is determined by the employer's permanent establishment where the employee reports. Odoo exposes this via the work_location_id field on the employee; if that's left blank the rule falls back to the home address province, which is almost always wrong for cross-province workers.
| Province | Top Marginal (2026) | Notes |
|---|---|---|
| Ontario | ~13.16% + surtax | Surtax kicks in once provincial tax exceeds the threshold |
| Quebec | ~25.75% | Administered by Revenu Québec, not CRA |
| British Columbia | ~20.5% | 7 brackets, highest top rate outside QC |
| Alberta | ~15.0% | Near-flat structure, minimal bracket complexity |
| Nova Scotia | ~21.0% | Brackets not fully indexed to inflation |
| Manitoba | ~17.4% | Also collects Health & Post-Secondary Education Tax Levy |
CRA publishes T4127 in late December for the coming year. Update your hr.rule.parameter bracket records before your first pay period of the new year, not after the fact. A bi-weekly employer running the January 10 payroll on old brackets will under- or over-withhold for every employee on that cheque and have to issue amendments.
Quebec: QPP, QPIP, CNESST, FSS, TP-1 Withholding, and RL-1
Employing one person in Quebec doubles your Canadian payroll configuration. Quebec operates its own pension plan (QPP), its own parental insurance plan (QPIP), its own income tax administration (Revenu Québec, via the TP-1015 source deduction tables), its own workers' compensation regime (CNESST), and its own employer health tax (FSS). T4 slips don't cover Quebec-only items — you also issue RL-1 slips. Every Quebec-resident contract needs the QC Employee structure type instead of the federal CA Employee.
QPP — Quebec Pension Plan
QPP mirrors CPP structurally but uses higher rates. For 2026 the QPP employee rate is approximately 6.40% on the same $3,500 basic exemption up to the YMPE, versus 5.95% for CPP. The enhanced QPP2 on the YMPE-to-YAMPE bracket runs at roughly 4.00%, matching CPP2. Employer match is 1:1. Revenu Québec publishes the annual parameters in TP-1015.F.
QPIP — Quebec Parental Insurance Plan
QPIP is Quebec's answer to federal EI maternity/parental benefits and runs as a separate deduction on every Quebec payslip. 2026 rates sit near 0.494% employee, 0.692% employer, with maximum insurable earnings around CAD $98,000 — notably higher than federal EI's MIE. The employee still pays federal EI (at the reduced Quebec rate) plus QPIP; these are two separate lines on the payslip, two separate remittances, and two separate year-end boxes.
# Rule code: QPIP_EE — sequence 64, category DED (Quebec only)
QPIP_MIE = 98000.00
QPIP_RATE_EE = 0.00494
QPIP_RATE_ER = 0.00692
periods = {
'weekly': 52, 'bi-weekly': 26,
'semi-monthly': 24, 'monthly': 12,
}[contract.schedule_pay]
period_cap = QPIP_MIE / periods
capped = min(categories['GROSS'], period_cap)
result = -round(capped * QPIP_RATE_EE, 2)
# Separate rule for employer side, same base, different rate
# Rule code: QPIP_ER — sequence 205, category COMPTP-1 Quebec Provincial Income Tax
Quebec provincial income tax withholding uses the TP-1015.TI tables, not the CRA T4127. The brackets (roughly 14%, 19%, 24%, 25.75% for 2026) are applied against the Quebec-specific claim amount from the employee's TP-1015.3-V form, which is a distinct form from the federal TD1. Odoo stores this in l10n_ca_claim_code_qc on the contract. The salary rule is structurally identical to the provincial tax rule above, but reads the l10n_ca_qc_tax_brackets_2026 parameter and posts to a Revenu Québec payable account instead of CRA.
CNESST — Quebec Workers' Compensation
CNESST (Commission des normes, de l'équité, de la santé et de la sécurité du travail) is employer-only and computed as a percentage of assessable earnings, with the percentage determined by your classification unit and claims history. Rates range from under 0.5% for low-risk office work to well over 10% for construction and forestry. CNESST is not deducted from the employee — it's an employer expense. Configure it as a rule in the Employer Cost category that debits a CNESST expense account and credits a CNESST payable, with monthly remittance.
FSS — Employer Health Services Fund
The FSS is a sliding-scale employer payroll tax on total Quebec payroll. For 2026 the rate ranges from approximately 1.25% on the first tranche for small employers up to 4.26% for employers with large Quebec payrolls. Configure this as a monthly or per-payslip employer-cost rule reading a company-level parameter for the rate band.
Year-End Reporting: T4, T4 Summary, RL-1, and XML Filing
At year-end, every Canadian employer issues T4 slips to every employee (and a T4 Summary to CRA). Employers with Quebec-resident staff additionally issue RL-1 slips to Revenu Québec. Both are due by the last day of February following the calendar year. Odoo's l10n_ca_hr_payroll module ships a T4/RL-1 generation wizard that walks the year's confirmed payslips, aggregates by employee and by T4/RL-1 box, and produces both the employee-facing PDF slip and the XML file for electronic transmission.
T4 Box Mapping — Salary Rules to Tax Boxes
Every salary rule must be tagged with the T4 box it contributes to. Odoo models this via the l10n_ca_t4_box field on hr.salary.rule. The canonical mapping:
| T4 Box | Description | Typical Salary Rules |
|---|---|---|
| 14 | Employment income | BASIC, GROSS, BONUS, COMMISSION, VAC, STAT, OVT |
| 16 | Employee CPP contributions | CPP tier 1 deduction |
| 16A | Employee CPP2 contributions | CPP2 deduction |
| 17 | Employee QPP contributions | QPP (Quebec) — T4 still shows this |
| 18 | Employee EI premiums | EI deduction |
| 22 | Income tax deducted | Federal + provincial tax withheld |
| 24 | EI insurable earnings | Cumulative capped insurable base |
| 26 | CPP/QPP pensionable earnings | Cumulative capped pensionable base |
| 44 | Union dues | DUES rule if configured |
| 46 | Charitable donations | If payroll-deducted |
| 52 | Pension adjustment (PA) | RPP/DPSP contributions |
Taxable benefits — employer-paid group insurance above the exempt threshold, employer-paid parking, company vehicle personal-use benefit — land in Box 14 (employment income) and usually require Other Information codes such as 40 (other taxable allowances and benefits), 30 (board and lodging), or 34 (personal use of employer's automobile). Configure each taxable benefit as a salary rule with both the l10n_ca_t4_box and l10n_ca_t4_other_info_code set so the wizard routes the amount correctly.
RL-1 Box Mapping
RL-1 boxes map similarly: A = employment income, B = QPP contribution, C = EI premium, D = RRSP deduction at source, E = Quebec income tax withheld, F = union dues, G = pensionable salary for QPP, H = QPIP premium, I = insurable salary for QPIP. Quebec employees effectively have two sets of year-end slips — a T4 for federal items and an RL-1 for Quebec items — and the Odoo wizard generates both from the same consolidated payslip data.
XML Upload to CRA and Revenu Québec
Once slips are validated, the wizard produces two XML files: one in the CRA's T619 schema for the T4 batch (uploaded via CRA's Web Forms or Internet File Transfer), and one in Revenu Québec's XML schema for the RL-1 batch (uploaded via clicSÉQUR-entreprises). Both require a valid certifier identifier; for CRA it's your BN with RP suffix, for RQ it's your NEQ plus the identification number. Odoo stores the generated XML on the payroll period record so you have an audit trail of what was actually filed.
January Close Checklist — Getting Year-End Right the First Time
The biggest reason Canadian employers miss the February filing deadline is not year-end itself — it's that bonus adjustments, taxable benefit true-ups, and CPP/EI over-contribution reconciliations all land on the final December payslip. Plan for a structured January close with discrete steps.
| Step | Action | Deadline |
|---|---|---|
| 1 | Run final bonus / retro payroll for the calendar year | Before December 31 |
| 2 | Post year-end taxable benefit adjustments (group insurance, parking, auto benefit) | First week of January |
| 3 | Verify CPP/QPP maximum hit for fully-loaded employees; refund over-contributions on a final adjustment payslip | Mid-January |
| 4 | Reconcile EI insurable earnings YTD against Box 24 for every employee | Mid-January |
| 5 | Generate draft T4 / RL-1 slips, review box-by-box with finance | End of January |
| 6 | Distribute slips to employees (electronic with consent, otherwise paper) | Last day of February |
| 7 | File T4 XML with CRA and RL-1 XML with Revenu Québec | Last day of February |
For hands-on help with this close cycle, our Odoo Partner Quebec and Odoo Partner Canada teams run a January compliance review for client databases — verifying box mappings, XML generation, and deadline adherence end to end.
Canadian Payroll in Odoo — Frequently Asked Questions
Can Odoo Community run Canadian payroll?
No. The l10n_ca_hr_payroll module and its Quebec overlay are Enterprise-only. Odoo Community ships the generic hr_payroll framework but none of the Canadian tax tables, CPP/QPP/EI/QPIP rules, or T4/RL-1 generation. You need Odoo Enterprise or Odoo.sh to run legal Canadian payroll.
Does Odoo file T4 and RL-1 slips electronically for me?
Odoo generates the XML files in CRA T619 and Revenu Québec formats, but you upload them yourself through CRA's Internet File Transfer portal and the RQ clicSÉQUR-entreprises portal. There is no direct API integration — the slips are your employer obligation, Odoo gives you the file.
How does Odoo handle an employee who moves from Ontario to Quebec mid-year?
Create a new contract (or update work_location_id) with the Quebec work location starting on the effective date. Payslips before that date use the Ontario / CA Employee structure; payslips after use the Quebec / QC Employee structure. At year-end the employee receives a T4 covering federal items for the full year plus an RL-1 covering only the Quebec portion.
What about bilingual payslips?
Quebec's Charter of the French Language requires French-language payslips for Quebec-resident employees. Odoo's salary rule names and T4/RL-1 slip templates support French translations out of the box; set the employee's language preference on res.partner to fr_CA and the payslip PDF, email notifications, and RL-1 will render in French. Employees outside Quebec can opt into English (en_CA) or keep French.
How do I configure ROE (Record of Employment) generation?
Service Canada's ROE Web accepts XML uploads. Odoo's Canadian module includes an ROE generation wizard that pulls the last 53 weeks of insurable earnings and hours from work entries, computes the reason for issuance, and exports the ROE XML. File it through ROE Web within five calendar days of the interruption of earnings.
Can I run CRA remittances directly from Odoo?
Odoo generates the PD7A remittance voucher data and the payroll journal entries that feed accounts payable. The actual remittance is paid through your bank's CRA Payroll (RP) payment channel or directly via CRA My Business Account. Use Odoo's batch payment feature to create the ACH file if you remit via business banking.
How are bonus payments taxed in Odoo?
Use the separate Bonus salary structure with the TD1X bonus tax method, which annualizes the bonus differently from a regular cheque. Running a bonus through the regular structure over-withholds on high bonuses and under-withholds on small ones. The Canadian module ships with the bonus structure preconfigured; make sure HR uses it when generating bonus payslips rather than manually adjusting a regular payslip.
What support does Octura provide for Canadian payroll implementations?
As an Odoo Ready Partner based in Canada, we configure the full stack end to end: company registration setup, structure and rule configuration per province, Quebec-specific overlays, T4/RL-1 mapping audits, CRA/RQ XML validation, and first-cycle payroll review. See our services page for the full scope.