Dentolize · HR Module Walkthrough
On this pageBusiness viewTechnical view

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:

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

  1. 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 SIF row,
  • one EDR (Employee Detail Record) per PAID line,
  • a trailing SCR control 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 single deductions column. The file deliberately reports the true basic (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 wpsFile is gated by PROCESS_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.