Singapore CPF Payroll for Odoo
Age-banded CPF, Ordinary and Additional Wage ceilings, on the EH payroll engine.
Why this module
Singapore CPF Payroll for Odoo
CPF is not one flat rate
Employee and employer percentages step down with age. This pack seeds all five published bands (55 and below, above 55 to 60, above 60 to 65, above 65 to 70, above 70) and picks the band from the employee age at the period end, so a senior worker is contributed correctly without manual rate edits.
OW and AW caps, done right
Contributions apply to the Ordinary Wage capped at the monthly ceiling plus the Additional Wage capped at the annual ceiling, less the year Ordinary Wage already subject to CPF. The math that trips up spreadsheets is in the engine, not in your head.
Reads like your other slips
CPF is exposed to salary rules as cpf_employee() and cpf_employer() helpers on the same EH payroll engine, so the SG slip computes, accumulates categories, and nets the same way every other country pack on the engine does.
Day in the life
Run a January 2026 SG payroll
You assign the Singapore - Standard structure to your employees and compute the run. For each payslip the engine reads the employee age at the period end, resolves the CPF rate band, caps the Ordinary Wage at the monthly ceiling and the bonus at the remaining Additional Wage room, then posts CPF_EE as a deduction and CPF_ER as an employer cost. Take-home reflects only the employee share. A staffer turning 61 lands on the lower band automatically. A $10,000 month is capped to the $8,000 Ordinary Wage ceiling without you touching a rate.
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.
Ordinary Wage above the monthly ceiling ($8,000 from 1 Jan 2026) is capped before CPF is applied, so a high earner is contributed on the ceiling, not on full salary.
A bonus is treated as Additional Wage and capped at the annual ceiling ($102,000) less the year Ordinary Wage already subject to CPF, projected as twelve months of the capped Ordinary Wage when no actual annual figure is supplied.
Age is computed from the birthday at the pay period end (date_to), including the month and day comparison, so a contribution rate change in the band that month is applied on the correct side of the birthday.
When an employee has no birthday on file, the engine falls back to the 55-and-below band rather than failing the run, so payroll still computes and the gap is visible to correct.
Birthday is a group-restricted HR field. It is read with sudo only to pick the CPF age band and is never passed into the salary-rule sandbox, so an officer running payroll does not need to see dates of birth.
If the cited rate table is cleared, computation falls back to the company flat employee and employer percentages on the Ordinary Wage ceiling, so a misconfiguration degrades to a defined number instead of zero or an error.
The Ordinary Wage and Additional Wage ceilings and the fallback rates live on res.company, so a multi-company database can hold different settings per entity.
What is inside
Built to do the job, end to end.
- CPF rate table (eh.hr.cpf.rate). Five age bands with employee and employer percentages, ordered by age, seeded as cited noupdate data from the CPF Board contribution table effective 1 January 2026. A _rate_for_age helper resolves the band covering an age, with the youngest band as a safe default.
- compute_cpf and the ceilings. A single method caps the Ordinary Wage at the monthly ceiling, caps the Additional Wage at the annual ceiling remaining for the year, sums the contributable wage, and rounds the employee and employer amounts to two decimals at the band rate.
- Rule helpers on the payslip. The SG payslip extension adds cpf_employee() and cpf_employer() to the rule helper set, resolves the age band once per slip, and routes either to the band calculation or to the company flat-rate fallback.
- Singapore - Standard structure. A complete SG_STANDARD salary structure with BASIC, GROSS, CPF employee deduction, CPF employer cost, and NET rules, wired to the standard payroll categories so the slip computes end to end out of the box.
- Company settings (res.company). Monthly Ordinary Wage ceiling, annual Additional Wage ceiling, and fallback employee and employer rates, each defaulted to the cited figures and documented to verify against the current CPF Board table each year.
- Tests against published figures. Four tests assert real CPF Board numbers: a below-ceiling slip, an Ordinary-Wage-ceiling cap, a senior age-band slip, and an Additional Wage ceiling case with a bonus, not rates the test invents.
Honest about the edges
What this does not do, so nothing surprises you.
- No monthly income-tax (PAYE) withholding. Singapore residents file income tax annually, so it is not a payroll deduction. This pack covers CPF, which is the monthly obligation.
- CPF rates and the wage ceilings are seeded as cited data and company settings. The CPF Board revises them (senior-worker rates step up over several years), so verify both against the current table each year.
- Rates are seeded for Singapore Citizens and Singapore Permanent Residents from their third year, on wages above $750 per month. First and second year SPR graduated rates and the lower-wage tapered bands are not separately modelled.
- The Additional Wage ceiling is applied per payslip using a twelve-month projection of the capped Ordinary Wage unless a real year-to-date Ordinary Wage figure is supplied. It does not by itself reconcile across a full year of historical slips.
- This is a country pack. It requires and runs on the EH payroll engine (eh_hr_payroll), which provides the salary-rule evaluation, category accumulation, and slip computation.
- No CPF e-submission, CPF EZPay file, or IRAS reporting export is included. The pack computes contributions; it does not file them.
- Self-Help Group and SDL contributions are not included.
Singapore CPF payroll Odoo, CPF contribution Odoo 19, Central Provident Fund Odoo, Singapore salary structure Odoo, CPF employee employer rate, Ordinary Wage ceiling CPF, Additional Wage ceiling CPF, Singapore HR payroll Community, CPF age band rates, Odoo 19 Singapore payroll free
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.
Post Irish payslips to the general ledger on the Irish chart of accounts
Interactive drag and drop Gantt planner for Odoo 19 Community project tasks with a deterministic server side sche...
Employment Hero Connector is the integration core of the ERP Heritage Employment Hero suite, providing per compan...
The United Kingdom country pack for the ERP Heritage Employment Hero integration
Sync Employment Hero employees, departments and payroll bank details into standard Odoo Community HR over the pla...
Inbound webhook receiver for the Employment Hero people and payroll platform on Odoo 19 Community
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Employees (hr)
• Discuss (mail) |
| Community Apps Dependencies | Show |
| Lines of code | 2438 |
| Technical Name |
eh_hr_payroll_sg |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
Please log in to comment on this module