WPS / SIF Export
Business view
Saudi payroll must be paid through the Wage Protection System (WPS) — banks expect a specific SIF (Salary Information File) that lists each employee, their bank details, and a breakdown of basic / housing / other / deductions / net. This module produces that file straight from a processed payroll run: click Download WPS file on the run.
Two properties matter to a clinic:
- It always reconciles. The file's control total equals the run's **Total
Net** by construction — the export can't silently disagree with what you paid.
- Nobody is dropped silently. An employee missing an IBAN or **national
ID can't go in a bank file — so they're excluded from the rows but reported back** in the result, so you know exactly who to fix.
You configure the establishment identifiers (MOL / Mudad establishment ID and the employer bank code) once in HR → Settings → Payroll.
Technical view
The builder — accounting/payroll/wpsFile.js
buildWpsFile (:20) requires a PROCESSED run. It emits three record types:
- a header
SIFrow, - one
EDR(Employee Detail Record) per PAID line, - a trailing
SCRcontrol row:count, totalNet, 'SAR'.
Per employee row (:69):
basic = baseSalary (the stored, already-prorated base)
housing = allowancesAmount
gross = grossAmount ?? net
other = max(0, round2(gross − basic − housing))
deductions = max(0, round2(basic + housing + other − net))
So basic + housing + other − deductions = net holds by construction — the row always reconciles, and the SCR trailer's total equals the sum of net, i.e. the run's Total Net.
Design note: every withholding — GOSI employee share, loan installment, and the attendance/other deductions — collapses into the singledeductionscolumn. The file deliberately reports the truebasic(not a reduced figure); understating basic below the GOSI-registered wage would trip MOL/bank validation (:68).
Excluded-but-reported employees
Lines whose employee is missing iban or nationalId are pushed to a missing[] list and omitted from the CSV rows but returned in the result (:63, :92) — reported, never silently dropped. (They are, precisely, absent from the file's detail rows; the UI surfaces the list.)
Settings that feed it — PayrollSettings
molEstablishmentId— the MOL / Mudad establishment number (SIF header).employerBankCode— the SIF header bank code.- Both are set via
updatePayrollSettings(salaryConfigMutations.js:96) and edited
in HrSettings.js. There is no dedicated WPS batch model — the export is driven entirely by these settings plus the employee banking fields (EmployeeRecord.iban etc.) and the existing PayrollRun.
Permission & UI
- Query
wpsFileis gated byPROCESS_PAYROLL(permissions.js:2432). - The Download WPS file button lives on the run-detail drawer
(PayrollRunDetail.js), which downloads a BOM-prefixed CSV and lists the excluded employees.
What it is not
The module builds and reconciles the file; it does not submit it to a bank or to Mudad. Filing remains the clinic's step. Frame it that way in sales and marketing.