EH HR Payroll Canada
Federal and provincial income tax, CPP and EI on one auditable salary structure you control.
Why this module
EH HR Payroll Canada
The math is fixed and tested, the rates are yours
Federal and provincial income tax run as progressive marginal brackets: income is annualised, taxed band by band, then divided back to the pay period. CPP and EI annualise period earnings against the exemption and maximums the same way. The engine math is covered by tests with controlled brackets so you can trust the computation while you keep the figures current.
Brackets are data, rates are company settings
Federal and provincial bands live on eh.hr.ca.tax.bracket with an editable list and a Payroll menu entry, gated to HR admins. CPP and EI rate, basic exemption and the pensionable and insurable maximums are fields on the company. When the CRA revises a number you edit a row or a setting, no code change, no redeploy.
One structure, deductions that add up
The seeded Canada - Standard structure carries Basic, Gross, Federal tax, Provincial tax, CPP, EI and Net rules in sequence. Each tax helper is injected into the engine's closed rule sandbox, so formulas read tax_federal, tax_provincial, cpp and ei without ever touching a raw recordset. Net is gross less the deduction category, and the tests assert it ties out.
Day in the life
Run a Canada payslip
Install alongside eh_hr_payroll, open the company and confirm the CPP rate, basic exemption and maximum pensionable, plus the EI rate and maximum insurable, against the current CRA figures for the year. Open Tax Brackets (CA) and set the federal bands and the bands for the province you operate in, replacing the representative provincial schedule that ships. Assign the Canada - Standard structure to an employee, create a payslip for the period and compute: the slip annualises gross from the period length, applies the marginal federal and provincial tax, takes CPP on pensionable earnings and EI on insurable earnings, then nets it. Every line is on the slip for review before you confirm.
Edge cases
The cases most modules quietly ignore.
In the shipped code today, each one a place where a cheaper module silently does the wrong thing.
Helpers annualise using pay periods inferred from the period span (52 weekly, 26 fortnightly, 12 monthly), and accept an explicit periods override, so a weekly and a monthly slip annualise to the same marginal rate correctly.
compute_annual_tax, compute_period_tax, cpp and ei all short-circuit to 0.0 when gross is not positive or periods is missing, so an empty or nil-wage slip produces clean zero lines instead of errors.
Pensionable earnings are clamped: annual earnings are capped at the maximum pensionable, the basic exemption is removed, and the result floored at zero, so earnings below the exemption yield no CPP and earnings above the cap stop contributing.
Insurable earnings are capped at the maximum insurable before the rate applies, so high earners stop accruing EI at the ceiling rather than paying on the full wage.
The marginal loop walks bands in ascending order and stops once annual income is exhausted, with the top band using a very large upper bound, so any income level is taxed without a missing-bracket gap.
CPP and EI figures are read from the payslip's own company_id, so each company in the database carries its own rates, exemption and maximums.
Tax helpers are injected into the engine's closed rule namespace where payslip and employee are read-only proxies, so a salary rule can call the tax functions but cannot reach or mutate a raw recordset.
What is inside
Built to do the job, end to end.
- eh.hr.ca.tax.bracket. The federal and provincial schedules as data. Each row is a jurisdiction, an annual upper bound and a marginal rate. compute_annual_tax taxes income band by band for one jurisdiction; compute_period_tax annualises a period amount, taxes it and divides back. Editable list view, ordered by jurisdiction and upper bound, on the Payroll menu for HR admins.
- Rate helpers on the payslip. payslip_ca.py extends _get_rule_helpers to add tax_federal, tax_provincial, cpp and ei to the rule sandbox. CPP and EI read the company CPP rate, basic exemption and maximum pensionable, and the EI rate and maximum insurable, then annualise, clamp and divide back to the period.
- Company settings. res.company gains CPP rate, CPP basic exemption, CPP maximum pensionable, EI rate and EI maximum insurable, each with a template default that you must verify against the current CRA figures for the tax year.
- Seeded structure and brackets. ca_structure.xml seeds the Canada - Standard structure with Basic, Gross, Federal tax, Provincial tax, CPP, EI and Net rules. ca_brackets.xml seeds template federal bands and one representative provincial schedule to replace for your province. Both are noupdate so your edits survive upgrades.
- Tests. test_ca_payroll.py sets controlled brackets and rates, then asserts the federal marginal split, the provincial flat case, and a full monthly payslip where federal tax, provincial tax, CPP, EI, total deductions and net all tie out. The suite proves the engine math, not the template CRA figures.
Honest about the edges
What this does not do, so nothing surprises you.
- Tax and contribution figures are templates. You must verify the federal and provincial brackets and the CPP and EI rates, exemption and maximums against the current Canada Revenue Agency and provincial rates for the tax year before running real pay.
- One provincial schedule is active at a time. The module holds a single provincial bracket set, so it does not select a province per employee or run several provinces side by side in one database.
- Income tax only models marginal brackets. It does not apply TD1 personal amounts, non-refundable tax credits, surtaxes or other province-specific adjustments.
- CPP and EI are the base employee contributions only. CPP2 additional contributions, QPP, QPIP and employer-share remittance reporting are not modelled.
- No CRA filing, remittance or year-end forms. There is no T4, T4A, ROE, PD7A or electronic CRA submission; this is a payslip computation localization.
- Depends on eh_hr_payroll and the EH HR platform groups. It runs on the EH salary-rule engine, not on the stock Odoo or Enterprise payroll app.
- Built and tested for Odoo 17 Community. Other versions are not in scope for this package.
Canada payroll Odoo 17, Odoo Canada CRA payroll, federal income tax Odoo payroll, provincial income tax payroll, CPP contribution Odoo, EI premium Odoo payroll, pensionable earnings calculation, insurable earnings cap, progressive marginal tax brackets, Odoo HR payroll localization, salary structure Canada, payslip computation Odoo 17 Community, editable tax bracket tables, per company payroll rates, Canada salary rule engine
Need this fitted to the way you work?
ERP Heritage delivers end to end Odoo work: Odoo Implementation, Customization and Development, Integration, Migration, Consultation, Support and Training. We help teams put this module into production, shape it to their process, and keep it running.
We work with businesses across Australia (Melbourne, Sydney, Brisbane, Perth, Adelaide, Canberra) and the Middle East (Dubai, Abu Dhabi, Riyadh, Jeddah, Doha, Kuwait City, Muscat). Start a conversation at erpheritage.com.au or email info@erpheritage.com.au.
Languages
Available in 19 languages
The interface ships translated out of the box. Switch language in Odoo and the fields, menus, and messages follow.
Modules teams pair with this one.
Premium ERP Heritage modules that extend the same stack, each built to the same engineering bar.
Inbound webhook receiver for the Employment Hero people and payroll platform on Odoo 17 Community
Real-time fiscalisation of customer invoices and credit notes with the Mauritius Revenue Authority e-Invoicing (E...
The Canada country pack for the ERP Heritage Employment Hero integration
Imports finalised pay run journals from the Employment Hero payroll platform (KeyPay) into Odoo Community account...
Please log in to comment on this module