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."

How an Odoo payslip batch becomes an accepted — or rejected — WPS file Flow diagram. A posted Odoo payslip batch is exported with the UAE WPS export format into a Salary Information File. Inside the file, one Employee Detail Record per employee carries the 14-digit Person ID, the 9-digit agent routing code, the pay start and end dates, the fixed and variable income components and the unpaid leave days; Employee Variable Pay records carry variable pay coming from payslip other inputs; and a single Salary Control Record trailer carries the 13-digit employer ID, the bank routing code, the salary month, the record count and the total salary. The bank uploads the file to the Wage Protection System, which validates identifier padding, routing codes, date formats, the record count, and whether the total equals the sum of all fixed and variable components. Validation either returns an acknowledgement, after which wages are credited to workers through their agent, or rejects the entire file and returns an error record giving the line number and error code, which loops back to be fixed, regenerated and resubmitted before the due date. Odoo payslip batch confirmed, journal entry posted and balanced Export Format: UAE WPS Salary Information File (.SIF) ASCII, comma separated, one employer, records in this order EDR — one per employee Person ID (14) · agent routing code (9) · pay dates fixed component · variable component · unpaid days EVP — variable pay from payslip inputs: overtime, allowances, encashment SCR — trailer, exactly one employer ID (13) · bank routing code · month · count · total uploaded by your bank WPS validation IDs padded with leading zeros · routing codes on file dates YYYY-MM-DD · salary month MMYYYY record count = employee records in file total salary = sum of every fixed and variable component Accepted wages credited to workers through their agent reconcile back to the batch Rejected the entire file, not one row error record returns the line number and the error code fix the field, regenerate, resubmit — before the due date
From posted payslips to an accepted file: the checks that decide whether your salary file clears, and what comes back when it does not.

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?
With the United Arab Emirates payroll localization installed, yes. In Odoo 19 you set an Employer Unique ID and a Salaries Bank Account under the Emirati Localization settings, put the Identification No on every employee record, then create a payment report with the Export Format set to UAE WPS. Odoo's documentation says the resulting file consists of an Employee Detail Record per employee, an Employee Variable Pay record and one Salary Control Record, and that the exported format is based on MoHRE guidelines and aligned with the formats used by most WPS agents. Prove it against your own agent's template before the first live run.
Why does my SIF file get rejected when the payslip totals look correct?
Because WPS validates fields, not intent. The Ministry of Labour and Central Bank Companies Responsibility Guide requires the 13-digit employer ID and the 14-digit employee Person ID to be padded with leading zeros, 9-digit routing codes assigned by the Central Bank on both record types, dates as YYYY-MM-DD, the salary month as MMYYYY, a record count equal to the number of employee records, and a total salary equal to the sum of every fixed and variable component in the file. A file that does not comply is rejected in its entirety, and the rejection comes back with a line number, an error code and a short description. Read those before you touch Odoo.
When do UAE salaries have to be paid now?
The UAE Government's official portal states that under Ministerial Resolution No. 340 of 2026 on the Wage Protection System, 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 where lawful deductions apply. The portal also sets out gradual measures for employers who delay, beginning with alerts from the second day after the due date and escalating to suspended work permits, administrative fines, automatic labour dispute registration and travel bans. Confirm your own obligations with MoHRE.
How does Odoo calculate end-of-service gratuity?
End of service is triggered when the employee's departure reason is set and the record is archived: nothing under one year, then 21 days of salary for each year of service between one and five years, with the daily rate taken as the monthly basic divided by 30 unless you set a Daily Salary on the contract. Past five years, Odoo's documentation describes the employee as eligible for 30 days of salary for each year they spent on the company, which read literally is not what Article 51 of Federal Decree-Law No. 33 of 2021 gives: the UAE Government's portal describes that as 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 five, calculated on the basic salary and capped at the wage of two years. Odoo also accrues a monthly end-of-service provision that does not affect net pay. Test your own leaver scenarios against a manual calculation before go-live.
Do I need Odoo Enterprise for UAE payroll?
For the standard app, yes. Odoo's own editions comparison marks Payroll as an Enterprise application and not part of Community, so a Community deployment needs a third-party payroll solution — which changes both the WPS work and who supports it when a file is rejected. Settle the edition question before you scope payroll. If you want a second opinion on an existing setup, the contact form on this site is the quickest way to reach me.

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