User Acceptance Testing
MY-Payroll — End-to-End UAT Script
A complete, hand-to-tester script that exercises the Malaysian payroll from empty configuration to paid runs and annual forms — with pre-computed expected figures to the sen so every calculation can be verified, not just observed. Follow the test cases in order: later cases depend on earlier ones (the July PCB true-up needs June approved).
12
Test cases
2
Test employees
2
Pay runs
6
Negative tests
Before you start
- Environment: a fresh test company (tenant) with the HR module enabled, a chart of accounts, and no payroll runs in 2026. One HR Admin login (used for both preparing and approving — the system has no maker/checker).
- Timing convention: the script uses June/July 2026. Every run's pay period is deliberately set to a single Saturday — a test tenant has no attendance records, and a normal month period would deduct every working day as absence. This isolates the salary/statutory/tax math; attendance inputs are covered in the optional extension.
- Recording: for each numbered step record Pass/Fail; where an expected-figures table is given, record the actual value next to each expected value. Any mismatch beyond ±RM0.01 is a defect.
Test data at a glance
| Object | Values |
|---|---|
| Employee 1 — "Ahmad UAT" | Malaysian · DOB 15-05-1990 · single, 0 children · resident · full-time · join 01-01-2024 · Basic RM6,000 + Fixed Allowance RM1,000 |
| Employee 2 — "Siti UAT" | Malaysian · DOB 01-01-1995 · single, 0 children · resident · full-time · join 16-06-2026 (mid-month joiner) · Basic RM3,000 |
| Items | Basic Salary (allowance, basic-salary flag, taxable, EPF+SOCSO+EIS, monthly) · Fixed Allowance (allowance, taxable, EPF+SOCSO+EIS, monthly) · Annual Bonus (allowance, taxable, additional remuneration, no statutory types, one-off) |
| Contribution group | "UAT EPF+SOCSO+EIS" — EPF both 11%/13%, SOCSO both (table), EIS both (table), each with a payable GL account |
| Config | HRDF enabled at 1% · payroll expense / PCB payable / salary payable GL accounts set · 2026 tax bracket: default bands, reliefs RM9,000 / RM4,000 / RM2,000, caps EPF RM4,000 + SOCSO/EIS RM350 |
| Runs | June: pay date 30-06-2026, period 06-06-2026 → 06-06-2026 (Saturday) · July: pay date 31-07-2026, period 04-07-2026 → 04-07-2026 (Saturday), + RM6,000 bonus for Ahmad |
1SetupTC-01 … TC-05 · HR Admin + Finance Admin
Phase 1 · Setup
Verify the seeded 2026 tax bracket TC-01
- 1HR AdminOpen Payroll → Tax Brackets.A bracket named "Malaysia PCB 2026" exists (auto-seeded at boot), plus one for 2027.
- 2HR AdminOpen the 2026 bracket and inspect bands and reliefs.10 bands from 0–5,000 @0% up to 2,000,000+ @30%; individual relief 9,000 · spouse 4,000 · per child 2,000. If reliefs are 0, set them now — every PCB expectation below depends on them.
- 3HR AdminConfirm statutory relief caps (or leave unset).EPF RM4,000 and SOCSO+EIS RM350 — these are also the legal defaults when unset, so either state passes.
Phase 1 · Setup
Configure GL accounts & HRDF TC-02
- 1Finance AdminIn company configuration set: payroll expense account (e.g. "Salaries & Wages"), payroll tax account ("PCB Payable"), payroll liability account ("Salaries Payable").All three save and re-display correctly.
- 2Finance AdminEnable HRDF with rate 1%.Saved; used at calculate time in TC-08.
Phase 1 · Setup
Create the item catalogue TC-03
- 1HR AdminCreate item "Basic Salary": type Allowance, basic-salary flag ON, taxable ON, statutory types EPF + SOCSO + EIS, frequency Monthly.Saves; listed in the catalogue.
- 2HR AdminCreate item "Fixed Allowance": type Allowance, taxable ON, statutory types EPF + SOCSO + EIS, Monthly.Saves. Basic Salary keeps its basic flag (only one item may hold it — try flagging Fixed Allowance as basic and confirm the flag moves, then move it back).
- 3HR AdminCreate item "Annual Bonus": type Allowance, taxable ON, additional remuneration ON, no statutory types, frequency One-off.Saves; used only in TC-11.
Phase 1 · Setup
Create the contribution group TC-04
- 1HR AdminCreate group "UAT EPF+SOCSO+EIS" with three entries — EPF (paid by both, employee 11% / employer 13%), SOCSO (both), EIS (both) — each mapped to a payable GL account (EPF Payable, SOCSO Payable, EIS Payable).Saves with all three schemes visible.
- 2TesterNote the deliberate trap: whatever percentages you type for EPF/SOCSO/EIS, the legal schedule computes the amounts.TC-08 verifies this: Ahmad's employer EPF must come out at 12% (wage > RM5,000) even though 13% is configured.
Phase 1 · Setup
Company statutory numbers TC-05
- 1HR AdminOpen the company statutory form and enter numbers for all four schemes (EPF, SOCSO, EIS, PCB — e.g. "E 1234567890" for PCB).All four save; the PCB entry is the LHDN E-number that appears on Borang E in TC-12.
- 2HR AdminBlank out the EIS number and save, then re-enter it.Blanking deletes the record (row shows empty); re-entering restores it.
2EnrolmentTC-06 … TC-07 · HR Admin
Phase 2 · Enrolment
Enrol employee 1 — Ahmad TC-06
- 1HR AdminCreate employee "Ahmad UAT" per the test-data table (Malaysian, DOB 15-05-1990, single, 0 children, resident, join 01-01-2024) and link contribution group "UAT EPF+SOCSO+EIS".Employee saves with the group visible on the profile.
- 2HR AdminAssign standing items from 01-01-2026, no end date: Basic Salary = 6,000, Fixed Allowance = 1,000.Both assignments save as ACTIVE.
- 3HR AdminTry to assign a second overlapping "Basic Salary" (any amount, from 01-03-2026).Rejected — overlapping active assignment of the same item is not allowed.
- 4HR AdminEnter Ahmad's statutory numbers (EPF, SOCSO, income tax) on the employee statutory form.Saved; they surface on the EA form in TC-12.
Phase 2 · Enrolment
Enrol employee 2 — Siti, mid-month joiner TC-07
- 1HR AdminCreate employee "Siti UAT" (Malaysian, DOB 01-01-1995, single, resident, join date 16-06-2026), same contribution group.Saves.
- 2HR AdminAssign Basic Salary = 3,000 from 16-06-2026, no end date.Saves as ACTIVE. Her June figures must come out at exactly half (15 of 30 days) in TC-08.
3June RunTC-08 … TC-10 · the core cycle
Phase 3 · June Run
June run — create, add, calculate TC-08
- 1HR AdminCreate run "UAT June 2026": pay date 30-06-2026, period 06-06-2026 → 06-06-2026.Run appears in DRAFT. (The one-Saturday period neutralises attendance-derived amounts — see "Before you start".)
- 2HR AdminAdd Ahmad and Siti to the run.Two lines appear. Overtime, unpaid leave and absence are all 0.00 on both lines. Contribution rows exist per scheme per employee.
- 3HR AdminRun the calculation.Status → PENDING_APPROVAL; both lines show calculated figures. Verify against the tables below to the sen.
Expected — Ahmad (full month)
| Figure | Expected | Why |
|---|---|---|
| Gross salary | 7,000.00 | 6,000 basic + 1,000 allowance |
| EPF employee / employer | 770.00 / 840.00 | 11% / 12% of 7,000 (wage > 5,000 → 12%, proving the schedule overrides the configured 13%) |
| SOCSO employee / employer | 30.00 / 105.00 | 0.5% / 1.75% of capped 6,000 |
| EIS employee / employer | 12.00 / 12.00 | 0.2% of capped 6,000 |
| PCB (MTD) | 91.30 | P = 49,000 − 4,000 (EPF cap) − 9,000 − 350 = 35,650 → tax 639.00, ÷7 months → 91.2857 → round up to 5 sen |
| Net salary | 6,096.70 | 7,000 − 812 statutory − 91.30 PCB |
| HRDF levy | 70.00 | 1% × 7,000 (employer only) |
| Employer cost | 8,027.00 | 7,000 + 957 employer statutory + 70 HRDF |
Expected — Siti (joined 16 June → ×0.5)
| Figure | Expected | Why |
|---|---|---|
| Gross salary | 1,500.00 | 3,000 × 15/30 days |
| EPF employee / employer | 165.00 / 195.00 | 11% / 13% of 1,500 (wage ≤ 5,000 → 13%) |
| SOCSO employee / employer | 7.50 / 26.25 | 0.5% / 1.75% of 1,500 |
| EIS employee / employer | 3.00 / 3.00 | 0.2% of 1,500 |
| PCB (MTD) | 0.00 | Annualised chargeable income is below the reliefs → P = 0 |
| Net salary | 1,324.50 | 1,500 − 175.50 |
| HRDF levy | 15.00 | 1% × 1,500 |
| Employer cost | 1,739.25 | 1,500 + 224.25 + 15 |
Expected — run totals & payslips
| Figure | Expected |
|---|---|
| Total gross / total net | 8,500.00 / 7,421.20 |
| Total employee contributions (statutory + PCB) | 1,078.80 |
| Total employer contributions / total HRDF | 1,181.25 / 85.00 |
| Total employer cost / total tax | 9,766.25 / 91.30 |
| Ahmad's payslip | Earnings: Basic Salary 6,000 + Fixed Allowance 1,000. Deductions: EPF 770, SOCSO 30, EIS 12, PCB 91.30 — nothing else. |
Phase 3 · June Run
Reject & recalculate TC-09
- 1HR AdminReject the pending June run.Status → DRAFT; both lines reset (calculated figures zeroed, estimates shown again); an in-app notification fires to creator/managers.
- 2HR AdminRecalculate without changing anything.Status → PENDING_APPROVAL; every figure matches TC-08 exactly (determinism check).
Phase 3 · June Run
Approve, post journal, mark paid TC-10
- 1HR AdminTry "Mark as Paid" while only PENDING_APPROVAL / before any journal.Blocked — approval and a posted journal are both required.
- 2HR AdminApprove the run.Status → APPROVED; figures locked; notification fires.
- 3Finance AdminOpen the journal preview.Balanced preview, no unmapped items, totals matching the table below.
- 4Finance AdminPost the journal (accept the configured salary-liability account).Journal entry created, dated 30-06-2026, description "Payroll: UAT June 2026"; linked to the run.
- 5Finance AdminMark as paid.Status → PAID (terminal); notification fires. June is now finalised — required for July's PCB true-up.
Expected journal (must balance exactly)
| Leg | Side | Account | Amount |
|---|---|---|---|
| Salary Expense | DR | Salaries & Wages | 8,500.00 |
| EPF (employee shares) | CR | EPF Payable | 935.00 (770 + 165) |
| SOCSO (employee shares) | CR | SOCSO Payable | 37.50 (30 + 7.50) |
| EIS (employee shares) | CR | EIS Payable | 15.00 (12 + 3) |
| PCB | CR | PCB Payable | 91.30 (Ahmad only) |
| Net salaries | CR | Salaries Payable | 7,421.20 (6,096.70 + 1,324.50) |
Verify: employer EPF/SOCSO/EIS (1,181.25) and HRDF (85.00) do not appear anywhere in this journal — by design.
4Bonus & Annual FormsTC-11 … TC-12 · needs June PAID
Phase 4 · Bonus & Annual
July bonus run — differential PCB TC-11
- 1HR AdminAssign Ahmad the Annual Bonus item: amount 6,000, start 01-07-2026, end 31-07-2026.Saves — the single-month window makes it pay once.
- 2HR AdminCreate run "UAT July 2026": pay date 31-07-2026, period 04-07-2026 → 04-07-2026; add Ahmad only; calculate.PENDING_APPROVAL with the figures below — the bonus is taxed by the LHDN differential method on top of normal MTD, using June's finalised figures as year-to-date.
- 3HR AdminApprove → preview → post journal → mark paid (as TC-10).All guards behave identically; journal balances at DR 13,000.00.
Expected — Ahmad, July
| Figure | Expected | Why |
|---|---|---|
| Gross (paid) | 13,000.00 | 7,000 normal + 6,000 bonus (never prorated, never ÷12) |
| EPF / SOCSO / EIS employee | 770.00 / 30.00 / 12.00 | Unchanged — the bonus item carries no statutory types |
| Normal MTD | 91.30 | Same P = 35,650 with June's 91.30 trued-up: (639 − 91.30) ÷ 6 → 91.30 |
| MTD on bonus | 359.90 | P with bonus = 41,650 → tax 999.00, minus projected year normal MTD 639.10 |
| Total PCB | 451.20 | 91.30 + 359.90 |
| Net salary | 11,736.80 | 13,000 − 812 − 451.20 |
| HRDF levy | 70.00 | Base excludes the bonus |
| Employer cost | 14,027.00 | 13,000 + 957 + 70 |
Phase 4 · Bonus & Annual
EA Form & Borang E TC-12
- 1HR AdminGenerate Ahmad's EA Form for 2026 (preview, then PDF download).Section A shows his name, IC and statutory numbers from TC-06. B1 gross = 20,000.00 (12,000 salary + 2,000 allowance + 6,000 bonus) · D-PCB = 542.50 · E-EPF = 1,540.00 · E-SOCSO = 60.00. PDF downloads as
EA-Form-2026-…pdf. - 2HR AdminGenerate Borang E 2026 (with CP8D).Header: employer name, SSM number, and the LHDN E-number from TC-05. Counts: total employees 2 · new employees 1 (Siti, joined 2026) · subject to PCB 1 (Ahmad; Siti's PCB is 0). Totals: PCB 542.50. CP8D lists both employees.
- 3TesterObserve-and-record: Siti's CP8D gross for June.Record the value. Her calculated June gross was 1,500 (prorated) while her salary snapshot is 3,000 — if the form shows 3,000 rather than ~1,500, log it as a defect candidate (joiner overstatement).
- 4HR AdminCreate (but do not calculate) an empty "UAT August 2026" draft run, then regenerate the EA form.Figures are unchanged — draft runs never enter annual forms (finalised runs only).
5Guards & Sign-offNegative tests + checklist
Phase 5 · Guards
Negative tests TC-N
| # | Action | Expected |
|---|---|---|
| N1 | Calculate a run with no employees | Blocked with a clear error. |
| N2 | Approve a DRAFT run (skip calculate) | Blocked — only PENDING_APPROVAL can be approved. |
| N3 | Mark an APPROVED run as paid before posting its journal | Blocked: "post the payroll journal before marking as paid". |
| N4 | Add a Deduction item with no GL account, assign it to Ahmad (any amount), recalc a test run, preview + post journal | Preview flags the item by name as unmapped; post refuses. Remove the assignment afterwards. |
| N5 | Cancel a PAID run | Blocked — PAID is terminal. |
| N6 | Calculate a run for a year with no tax bracket (e.g. pay date in 2030, employee added) | Observe-and-record: PCB computes as 0 with no warning — expected per current design; confirm the team accepts this behaviour. |
Phase 5 · Guards
Optional extensions (exploratory)
- Zakat offset: add a Deduction item with EA category zakat, assign RM100 to Ahmad, recalc a month — PCB drops ringgit-for-ringgit (June's 91.30 would floor to 0.00) and zakat appears as a payslip deduction.
- Attendance inputs: use a full-month period with an attendance group, approved timesheets and an approved unpaid leave — verify OT = hours × (salary ÷ 30 ÷ 8), unpaid leave = days × (salary ÷ working days), and that absence only hits days with no attendance and no leave.
- Foreign-worker EPF: a non-Malaysian employee (not domestic servant) with pay date ≥ Oct 2025 → EPF 2%/2%, no ceiling. Note SOCSO/EIS still apply citizen rules — a known gap; record actuals.
- Re-run after posting: recalc an approved+journalled run — the journal link clears but the GL entry survives (known gap); confirm the team's operating procedure covers manual cleanup.
Phase 5 · Guards
Sign-off checklist
| Area | Pass criteria | Result |
|---|---|---|
| Setup (TC-01…05) | Bracket seeded with correct bands/reliefs; catalogue, group, numbers, config all persist | ☐ |
| Enrolment (TC-06…07) | Profiles + assignments saved; overlap guard fires | ☐ |
| Statutory engine (TC-08) | EPF/SOCSO/EIS match the schedule to the sen, incl. the 12%-band and proration cases | ☐ |
| PCB engine (TC-08, TC-11) | 91.30 / 0.00 / 451.20 reproduced exactly | ☐ |
| Lifecycle (TC-09, TC-10, TC-N) | All transitions and guards behave as specified; recalc is deterministic | ☐ |
| GL (TC-10, N4) | Journal balances to the sen; unmapped items block; employer costs absent by design | ☐ |
| Annual forms (TC-12) | EA and Borang E figures match; drafts excluded | ☐ |