HRM — Payroll

Turning hours, leave, and salary structures into payslips

Statutory math is a starting point, not legal advice

The built-in country presets (tax/PF/ESI etc.) are scaffolding. Always verify rates against your jurisdiction before paying real people. The product surfaces this disclaimer too.

What This Module Does (Plain Language)

Payroll calculates what each person earns and produces a payslip. It pulls together their salary structure (basic + allowances + deductions), days worked and overtime (from attendance), paid/unpaid leave (from the leave module), and any salary advances being repaid — then computes gross pay, deductions, and net pay. Once a payslip is finalized and approved it becomes a locked legal document: you never edit it; corrections are issued as adjustment lines on a future payslip.

The Pieces

EntityWhat it is
Salary StructureA reusable compensation template (e.g. "Standard IT"), optionally tied to a country.
Salary ComponentA line in a structure — Basic, House Rent, PF, Tax — with a type and a calculation method.
Employee SalaryAn effective-dated assignment of a structure + basic pay to a specific employee.
Payroll RunA batch covering a pay period for some or all employees.
PayslipOne employee's result for one run. Immutable once finalized.
Salary AdvanceA loan to an employee, recovered over future paychecks.

Key enums

EnumValues
SalaryComponentTypeEARNING · DEDUCTION · STATUTORY_DEDUCTION · EMPLOYER_CONTRIBUTION · REIMBURSEMENT · ADJUSTMENT
ComponentCalcMethodFIXED · PERCENT_OF_BASIC · PERCENT_OF_GROSS · FORMULA · ATTENDANCE_DERIVED
PayCycleMONTHLY · BIWEEKLY · WEEKLY
PayrollRunStatusDRAFT · PROCESSING · REVIEW · APPROVED · PAID · CANCELLED · FAILED
PayslipStatusDRAFT · FINALIZED · VOIDED
SalaryAdvanceStatusPENDING · APPROVED · DISBURSED · RECOVERING · SETTLED · REJECTED · CANCELLED

Step 1 — Build a Salary Structure

You can build a structure component-by-component, or apply a country preset to get a sensible starting set you can then edit.

http
json

Then apply a preset (this copies components into your structure — no live link, so you stay free to edit afterward):

http

Manage component lines under /api/v2/hr/payroll/salary-structures/:id/components[/:cid].

Step 2 — Assign Salaries to Employees

Dev Only POST /api/v2/hr/payroll/employee-salaries
json
Salaries are effective-dated

A raise doesn't overwrite history. Assigning a new salary creates a new row with an effectiveFrom date and closes the previous one. A payroll run for May uses the salary that was effective during May — so a June 1 raise never retroactively changes the May payslip.

Step 3 — Run Payroll

A payroll run moves through a strict state machine. Each transition is a separate endpoint and a separate permission — this is how POSVelo enforces separation of duties (the person who approves must not be the one who processed).

text
1

Create the run

json

POST /api/v2/hr/payroll/runs · hr.payroll.run.create. A storeId of null covers all stores.

2

Process it

POST .../runs/:id/process queues a background job that computes every employee's draft payslip, then moves the run to REVIEW.

3

Review the drafts

HR checks the batch. If anything upstream was missing (no salary, no attendance), that employee is flagged for a human to verify rather than silently zeroed.

4

Approve

POST .../runs/:id/approve finalizes the payslips — DRAFT → FINALIZED. From here they are immutable. Must be a different person than the processor; step-up 2FA may be required.

5

Disburse

POST .../runs/:id/disburse records who paid and when, and can notify employees that payslips are ready. (Actual bank transfer integration is a later release.)

How a payslip is computed

For each employee the engine resolves the salary effective during the period, walks the structure's components in order, and applies each one:

Calc methodWhat it does
FIXEDA flat amount.
PERCENT_OF_BASICA percentage of basic pay.
PERCENT_OF_GROSSA percentage of gross-so-far (order matters).
FORMULAA preset, pure function (used by country presets).
ATTENDANCE_DERIVEDOvertime earnings and loss-of-pay deductions from attendance.

Then it recovers any due salary-advance installment as a deduction, totals up gross / deductions / net, and writes a draft payslip whose line labels and codes are snapshotted as text — so renaming a component later never changes an old payslip.

Determinism

Re-processing a run on the same inputs produces byte-identical drafts. No randomness, no "now" timestamps inside the math.

Payslips Are Immutable

Never edit a finalized payslip

Once a payslip is FINALIZED it cannot be edited or deleted — it's a legal record for pay disputes and tax. To fix a mistake you create a new run with an ADJUSTMENT line that points back at the original (and the original may be marked VOIDED). Both stay in history.

Employees download their own payslips as PDF/print via ESS (GET /api/v2/me/payslips/:id/pdf); HR can fetch any payslip (GET /api/v2/hr/payroll/payslips/:id and .../pdf).

Salary Advances

A short loan recovered over future paychecks.

text
json

Each subsequent payroll run automatically recovers one installment as a deduction until the advance is fully repaid (SETTLED).

Money Discipline

Decimals, not floats

All money is stored as fixed-precision decimals (e.g. 50000.00) and all arithmetic uses a decimal library — never JavaScript floating-point — so totals always add up to the cent.

In the App

PageRoute
Payroll overview/hr/payroll
Runs/hr/payroll/runs
Run detail/hr/payroll/runs/[id]
Salary structures/hr/payroll/structures
Structure detail/hr/payroll/structures/[id]
Employee salaries/hr/payroll/salaries
Advances/hr/payroll/advances

Who Can Do What

CapabilityADMINHR_MANAGERACCOUNTANTEMPLOYEE
Manage structures / componentsYesYesLimited viewNo
Create / process runsYesYesYesNo
Approve a runYesYesIf not the processorNo
Disburse a runYesYesYesNo
Manage advancesYesYesYesNo
Read own payslipsYesYesYesYes (via ESS)
Next step

Employees see their payslips, leave balance, roster, and attendance in the Employee Self-Service portal.