Payroll Module — User Manual

Table of Contents


1. Introduction

The Payroll module (Mod-Payroll-*) runs South African payroll for the firm's own staff: employee records and salary structures, monthly payrun processing (PAYE, UIF, SDL, ETI), payslips, and the SARS-facing outputs (EMP201, IRP5/IT3(a), EMP501 reconciliation). It is a separate concern from Trust Accounting — payroll never touches a client's trust ledger; it posts to the firm's own General Ledger via the same GL posting pipeline every other financial transaction uses.

This manual documents the module as it exists today, including recently added capability (employer retirement fringe benefit, bonuses, reimbursive travel, termination lump-sum tax directives) and — per the module's own compliance audit — what is not yet implemented. Section 9 below lists known limitations plainly so nobody mistakes a documented gap for a bug report.

For the underlying compliance research this module is built against, see docs/plans/2026-08-25-sa-payroll-compliance-audit.md and the standing SARS source-code matrix.


2. Getting Started

Screen Menu Path Purpose
Employees Accounting → Payroll → Employee Records → Employees Employee list, create/edit employee, salary structure
Payroll Cockpit Accounting → Payroll → Payroll Processing → Payroll Cockpit Tax-year dashboard: payrun status at a glance, outstanding validation issues
Payrun Workspace Accounting → Payroll → Payroll Processing → Payrun Workspace Create, calculate, approve, post, cancel, and reverse a payrun
Submissions Hub Accounting → Payroll → Payroll Processing → Submissions Hub Generate EMP201, IRP5/IT3(a), and EMP501 reconciliation outputs
Payroll Options Accounting → Payroll → Payroll Processing → Payroll Options GL account mapping, SARS reference numbers, SDL/ETI toggles, periods-per-year

Prerequisites Before Running Payroll

  1. Tax table imported and activated for the tax year you intend to pay (Payroll Options → Tax Tables). A payrun cannot be created without an active table for its tax year.
  2. Employees created with a tax number (an employee with no tax number is silently excluded from calculation — see §4).
  3. A current salary structure effective on or before the intended pay date for every employee expected to be paid.
  4. Payroll settings configured — at minimum the GL account mapping (GL_SALARY_EXPENSE, GL_PAYE_PAYABLE, GL_UIF_PAYABLE, etc.) in Payroll Options, otherwise posting a payrun will fail.

3. Employee Records

Creating / Editing an Employee

The Employees screen (Employee Explorer) lists all employees; selecting one opens the employee editor across four tabs — Personal, Tax, Pay & Allowances, Compliance, Banking.

Key fields:

Salary Structure Versioning

Saving a salary change does not overwrite the existing structure — it creates a new effective-dated version and flags it current. A payrun always calculates using the salary structure version that was actually in effect on the payrun's pay date, not whichever version is flagged current at calculation time. This means a mid-month raise or a back-dated/delayed payrun correctly reproduces the salary that applied at the time, and re-running an old payrun's numbers later (e.g. for a reversal) stays reproducible even after later raises.


4. Running a Payrun

The payrun lifecycle is a strict state machine: DRAFT → CALCULATED → APPROVED → POSTED, with CANCELLED available from DRAFT/CALCULATED/APPROVED and REVERSED available only from POSTED. Each transition is guarded — you cannot, for example, post a payrun that hasn't been approved.

  1. Create — pick a period start/end and pay date. The system rejects a period that overlaps an existing non-cancelled/non-reversed payrun.
  2. Calculate — runs every active employee through the calculation engine (PAYE, UIF, SDL, ETI, and — where applicable — this period's bonus/reimbursive travel/lump-sum directive, see §5) and produces one payslip per included employee. Employees are excluded, not silently dropped: any employee with no tax number, or no salary structure effective on the pay date, is listed with a reason in the calculation result so you can fix the underlying data and recalculate before proceeding.
  3. Recalculate — from DRAFT, re-runs calculation (e.g. after fixing a skipped employee's data or changing a bonus/travel-km entry). Not available once APPROVED.
  4. Approve — transitions CALCULATED → APPROVED. Requires the "Approve Payroll" permission, distinct from "Run Payroll".
  5. Post — writes the payslips as immutable, posts the balanced GL journal entry, and updates every included employee's year-to-date accumulators. Requires the "Post Payroll" permission. A posted payrun cannot be edited or recalculated.
  6. Cancel — available before posting; deletes the (unposted) payslips and marks the payrun CANCELLED. Use this to discard a payrun created or calculated in error.
  7. Reverse — available only after posting; posts a mirror-image GL batch (debits and credits swapped) and rolls back every affected employee's YTD accumulators. Warning: if later payruns in the same tax year have already been posted, their cumulative PAYE figures depended on this payrun's YTD contribution — those payruns must be recalculated and reposted after a reversal, or their PAYE will be wrong going forward.

5. This Period's Extras — Bonus, Reimbursive Travel, Termination Lump Sums

Three variable, per-employee, per-payrun inputs are supported by the calculation engine so that once-off events don't get mistaxed as if they recurred every month:

5.1 Bonuses

A bonus entered for an employee in a given payrun is taxed under SARS's annual-payment method — the increment in tax that results from adding the bonus, un-annualised, on top of the employee's already-computed annual-equivalent income — rather than being folded into ordinary recurring pay and taxed as if it happened every month. It is reported separately on the payslip and IRP5 (SARS code 3605).

5.2 Reimbursive Travel (Per-Kilometre)

Distinct from the fixed monthly travel allowance already on the salary structure (which is a recurring amount, 80% taxable by default per SARS's rules for a fixed allowance), reimbursive travel is business kilometres reimbursed at the employee's configured Reimbursive Rate (R/km):

Set the employee's own rate on the Pay & Allowances tab; the kilometres driven are entered per payrun (see §5.4).

5.3 Termination Lump Sums (Tax Directives)

The software does not calculate lump-sum/retirement/retrenchment/severance tax. SARS's Second Schedule directive process determines that figure, and Principle 10 of this module's design (see the compliance audit) is explicit that a legally uncertain determination like this must never be silently computed by application code. Instead:

  1. Once SARS has issued a tax directive for an employee's termination lump sum, record it (directive number, type — RETIREMENT/RETRENCHMENT/WITHDRAWAL/DEATH/SEVERANCE — gross lump sum, and the directive's own tax amount).
  2. Apply the recorded directive to the specific payrun that will pay it out. The engine applies the gross and tax figures exactly as directed — it never recalculates them — and reports them under IRP5 codes 3901 (lump sum) and 4102 (directive tax).
  3. A directive can only be applied to one payrun. Applying an already-applied directive to a second payrun is rejected.

5.4 Entering These Per Payrun

While a payrun is DRAFT, click Extras… in the Payrun Workspace action bar (next to Calculate/Recalculate). This opens "This Period's Extras," listing every active employee with editable Bonus (R) and Reimb. KM columns, plus a Choose Directive…/Clear Directive pair of buttons that apply to the selected row — the picker offers that employee's own unapplied directives (those already recorded and not yet applied to another payrun). Saving writes each row to payrun_employee_adjustments; a row with everything blank is simply not saved (or removed, if one existed before). Extras… is disabled once the payrun leaves DRAFT — the same guard PayrunServiceContract.setEmployeeAdjustment enforces server-side.

To record a new directive, select the employee's row and click New Directive… — a small form collects the directive number, type, gross lump sum, directive tax, tax year (pre-filled from the payrun), issued date, and notes. The directive is recorded but not automatically applied; use Choose Directive… afterwards to apply it to this payrun (or a later one — a directive is not tied to the payrun it was recorded from until it's actually applied).

If the payrun has already been calculated once, saving extras does not retroactively change the existing payslips — click Recalculate afterwards so the engine picks up the new bonus/km/directive values (the dialog reminds you of this when it applies).


6. Employer Retirement Fund Contribution

The employer's percentage contribution to an employee's retirement fund (retirement_employer_pct on the salary structure) is now:

No action is required beyond setting the employer percentage on the salary structure — the effect is automatic from the next calculated payrun onward.


7. SARS Submission Outputs — Submissions Hub

Output What it is Notes
EMP201 Monthly employer declaration (PAYE/UIF/SDL/ETI totals) Reconciled from actual posted payslips, never manually re-entered
IRP5 / IT3(a) Per-employee annual employees' tax certificate Generated per employee or as a combined booklet for the whole tax year. Reports employer retirement contribution (3817), bonus (3605), reimbursive travel (3703/3722), and termination lump sum/directive tax (3901/4102) alongside the original 3601/3701/4001/4474/4005/4101/4115/4116 codes — each only appears on a certificate when the corresponding amount is non-zero for that employee/year
EMP501 reconciliation Compares cumulative EMP201 PAYE against summed IRP5 figures and flags discrepancies Produces a CSV suitable for manual review/capture — not a SARS e@syFile-importable file (see §9)

8. Payroll Options

Configure once per firm, changed rarely:


9. Known Limitations / Outstanding Issues

This section is maintained deliberately honestly. Every item below is a confirmed gap traced against the actual code, not a hedge — see the linked compliance audit for the file-and-method-level evidence behind each row.

Confirmed gaps, not yet started (see the compliance audit for full detail):

By design, not a gap:


10. Troubleshooting

"No active tax table for [tax year]"

Import and activate a tax table for that tax year in Payroll Options before creating a payrun.

An employee doesn't appear on a calculated payrun

Check the calculation result's skipped-employee list first — the two most common reasons are a missing tax number and no salary structure effective on the pay date. Fix the underlying employee/salary record and recalculate.

"A payrun already exists that overlaps with [dates]"

Cancel or reverse the conflicting payrun before creating a new one for an overlapping period — the system will not allow two active payruns to cover the same dates.

Posting fails with a missing GL account error

A required account code in Payroll Options → GL account mapping is blank. Set it and retry — the posting service refuses to submit an unbalanced or incompletely-mapped entry rather than posting silently wrong figures.

A reversed payrun's later payruns look wrong

This is expected, not a bug — see the Reverse warning in §4. Recalculate and repost every payrun for the same tax year that was posted after the one you reversed.