Odoo Payroll for the UAE: WPS, Gratuity and Why Your SIF File Gets Rejected
A UAE payroll run rarely fails in the payslip. It fails on the day the file reaches the bank, when the portal rejects a batch that looked perfect in Odoo. Almost every Wage Protection System rejection I have been called into was field-level, not logic — a padded identifier, a routing code, a date format, a total out by a few fils. Here is how I set UAE payroll up in Odoo so it clears first time.
The 2026 deadline you have to design around
The UAE Government's official portal states that wages are paid in accordance with Ministerial Resolution No. 340 of 2026 on the Wage Protection System, under which "salaries for the previous month are due on the first day of each Gregorian month", and that employers "must transfer at least 85 per cent of the total wages due to their employees on time".
The same portal sets out gradual measures for delay: alerts from the second day after the due date, suspended work permits at day five, administrative fines and reclassification at day eleven, automatic labour dispute registration at day sixteen, and executive payment instruments, precautionary attachment and travel bans at day twenty-one. Some of those steps are conditioned on establishment size or on repeat violations, so read the portal against your own headcount. Either way, payroll now has to close, post and export with days in hand: the reject-and-resubmit loop must fit inside the month.
What is actually inside the salary file
The Wage Protection System was developed by the UAE Central Bank so MoHRE can monitor whether wages are paid on time, and establishments registered with MoHRE must pay wages on the due date through it. You upload a Salary Information File — the SIF.
The Ministry of Labour and Central Bank Wages Protection System Companies Responsibility Guide specifies it as ASCII, comma-separated — and, the detail most teams have backwards, "One or more 'EDR' records are required followed by a 'SCR' record in the 'SIF' file." The employee rows come first; the control record is the trailer, not the header — one employer per file, no employee twice.
Odoo 19 produces it from the payment report: set the Export Format to UAE WPS. Per Odoo's documentation the file consists of an Employee Detail Record per employee, an Employee Variable Pay record, and one Salary Control Record carrying "the employer details and the totals for the payslips."
The field-level reasons the file gets rejected
The guide is blunt: files that do not comply "will be rejected in its entirety." One bad row is not skipped — the batch dies, and the rejection returns a line number and an error code. Start there.
- Identifiers that are not padded. The employer's unique ID is 13 digits and "will have to be padded with leading zeros"; the employee's Person ID is 14 digits under the same rule. The account with the agent is the opposite — up to 16 characters, "MUST NOT be left padded with zero's."
- Routing codes. Both record types carry 9-digit routing codes assigned by the Central Bank, validated against the WPS master database. In Odoo that is the Routing Code Agent on the bank, which must "consist of a 9-digit numeric value only".
- Date formats. Pay and file creation dates are YYYY-MM-DD, creation time HHMM, salary month MMYYYY — a field where "MOL makes key decisions based on the value provided". Stamp the wrong month and you misstate the period you are judged on.
- Counts and totals. The control record's count "must be the number of EDR records in the file", and its total is "validated to be equal to the sum of all the fixed and variable components" in it. Round two rules differently and the file is out by fils — and dead.
- Unpaid days. Each employee record reports days of leave without pay in the period. If that disagrees with the unpaid-leave deduction on the payslip, you have told MoHRE one story and paid another.
Structuring salary rules so basic and allowances map correctly
The employee record splits pay into a fixed income component and a variable one; Odoo mirrors that split. On the UAE contract, Wage sits alongside Housing Allowance, Transportation Allowance and Other Allowance, while payslip inputs for overtime, medical, annual passage and leave encashment are "reflected on the WPS as monthly variable salary for that specific employee."
So the decisive choice is what goes in Wage: it has to be the contractual basic. Load the full gross there and the file still balances, but gratuity, the provision and every leave calculation inherit the error. On the engineering and contracting builds I run, where labour cost lands against a job number, it distorts job costing too.
Gratuity: what the law says and what Odoo does
Under Article 51 of Federal Decree-Law No. 33 of 2021, per the UAE Government's portal, a worker who completes one year of continuous service earns "21 days' salary for each year of work" for the first five years and "30 days' salary for each year of work following the first 5 years", calculated on the basic salary. Fractions of a year are paid proportionately, days of unpaid absence are excluded from service, and "the total gratuity shall not exceed the wage of 2 years." The same portal adds that all outstanding wages, entitlements and gratuity are payable "within 14 days of the termination of the contract."
Odoo is close to that shape, but check the tail. End of service "is triggered when the employee's departure reason is set by archiving the employee's record", and pays nothing below a year, then 21 days of salary for each year between one and five. Past five years, Odoo's documentation describes the employee as eligible for "30 days of salary for each year they spent on the company" — read literally, 30 days across the whole service, not 30 days for the years after the first five, which is what the law gives. Recompute a long-service leaver by hand before you trust the figure.
The provision is what saves you at year-end: Odoo accrues it monthly from day one — monthly wage over 30, times 21 over 12, moving to 30 over 12 after five years — and it "does not affect their net payable." Test real leavers first: long service, mid-month exits, the two-year cap.
Leave and air-ticket accruals
Annual leave is 30 days once an employee completes a year of service, and 2 days per month for service between six and twelve months. In Odoo the Number of Leave Days field drives the leave provision and, per the documentation, "the final calculation of the end of service and unpaid leaves". That provision is total salary — wage plus allowances — over 30, times leave days, over 12. Note the asymmetry: gratuity accrues on basic, leave on total salary.
Air tickets are the accrual Odoo does not do for you. The localization ships an Annual Passage Allowance input, which reaches the file as variable pay when you pay it, but spreading the entitlement across the year is a rule I add: it is contractual, and every company words it differently — annually, every two years, or cash in lieu.
Reconciling payroll to the ledger
Odoo posts payroll by linking each salary rule to a debit and a credit account on the rule itself, then creating a draft journal entry from the payslips that you review and post. That is the easy half.
The half teams skip is the three-way tie between the batch, the file and the bank. Do not assume the control record's total equals the cash leaving your account: it is validated against the sum of income components, while your transfer reflects deductions. Reconcile gross to the file and net to the payment separately, then check the month's provisions moved the right liability accounts. For a Dubai facilities contractor with hundreds of technicians on overtime, a clean operational system upstream is what makes that possible.
Two things to settle early: whether your edition includes Payroll — Odoo's comparison marks it Enterprise, not Community — and your VAT configuration, which needs the same discipline.
The rule I give every UAE payroll client: before your first live run, push a real salary file from real payslips through your actual WPS agent — and repeat after any change of bank, agent or Odoo version. Odoo states the export is "aligned with the formats used by most WPS agents". Aligned with most is not validated against yours.
This is implementation guidance on configuring Odoo — not legal, tax or payroll-compliance advice. Wage rules and end-of-service entitlements change, and how they apply depends on your establishment and contracts. Confirm your obligations with the Ministry of Human Resources and Emiratisation, your WPS agent or a qualified adviser.
Frequently asked questions
Does Odoo generate the UAE WPS SIF file out of the box?
Why does my SIF file get rejected when the payslip totals look correct?
When do UAE salaries have to be paid now?
How does Odoo calculate end-of-service gratuity?
Do I need Odoo Enterprise for UAE payroll?
Related reading
Want your UAE payroll setup checked before the next run?
I'm Muhammad Salman Ali Khan, an Odoo Techno-Functional Consultant in Dubai and Head of Projects at Techbot Information Technology LLC, a UAE Odoo partner — 10+ years, 100+ implementations, certified across Odoo v13, v14, v15, v16, v18 and v19, and I presented Odoo 19's new features at Odoo Experience 2025 in Brussels. Show me your salary structure and a rejected file, and I'll tell you honestly what it takes to get your WPS, gratuity and provisions right — at no cost.
Get a free business evaluation