Skip to Content

China payroll natively in Odoo: per-city rates, five bases, and the tax bureau round trip

October 1, 2026 by
China payroll natively in Odoo: per-city rates, five bases, and the tax bureau round trip

Most foreign-run companies in China run payroll one of two ways: an agency, or Excel. Both work. Both have a cost. The agency charges per head per month, keeps your payroll data in its system, and takes days to answer questions. The Excel file has one owner, and when a city changes its rates, you find out late.

Why China payroll breaks standard software

五险一金 — five insurances, one housing fund. Every city sets its own contribution rates, base floors and base caps. They change, usually in July. Shanghai is not Guangzhou is not Suzhou.

And one detail most systems get wrong: China declares a separate contribution base per insurance — pension, medical, unemployment, injury — plus another one for the housing fund. Same employee, genuinely different numbers. Software with one "social insurance base" field cannot file correctly.

Then the declaration itself. Individual income tax is withheld cumulatively, and the tax bureau wants the withholding declaration in its official 51-column layout. You file, and the bureau answers with the tax it computed. Your payroll has to match that answer.

How we built it

We built China payroll natively in Odoo 19. Three design decisions carry it.

Rates are data, not code. A policy table holds one row per city per period: the statutory rates, the floors and caps, and the local oddities — a flat large-medical amount in some cities, housing fund lines that round to whole yuan in others. When a city publishes new numbers, you add a row. No code change, no update, no developer on the phone.

Bases live on the contract. Each employment contract carries its own base per insurance, plus the housing fund base. Payslips compute from the same records that already run contracts, attendance and leave in Odoo. One system, one copy of the truth.

The tax round trip is built in. Odoo exports the withholding declaration in the bureau's own 51-column layout. You upload it to the tax system, import the returned file, and Odoo records what the bureau said the tax should be. Payslip and filing match, every month, with an audit trail.

Where it runs

We built this for an EOR firm in Guangzhou. Employer-of-record means payroll is the product: staff across cities, each city with its own rates, and clients who check the numbers. The per-city policy table exists because of that — one rate table per city per period, maintained as data by the people who run payroll, not by us.

One more thing, since we usually write about AI: there is no AI in this module, on purpose. Payroll is money. Money gets computed by deterministic rules and verified against the tax bureau's own answer. Where we do use AI — drafting, scanning, triage — the rule is fixed: AI drafts, a named human approves, Odoo executes.

Bring it in-house

If you pay an agency per head per month and still keep a shadow Excel, it is worth a look. We start with a free assessment: your cities, your headcount, your current process, and a clear answer on what native payroll in Odoo would take. A clear no is also an answer.

Ask via the contact form at danmai-it.com/contactus, or see what else we build at /modules — 50+ production modules for companies running Odoo in China.

19,000 BOMs, checked every night: how an AI scanner keeps manufacturing data honest
Seven deterministic checks, one AI-written summary, zero writes to your data