Payroll is the part of an HRMS where a wrong assumption is expensive, so this page describes the actual model rather than the screens. The calculation itself is a pure function: the same inputs always produce the same breakup, with no clock and no database in the middle.
The derivation runs in a fixed order
Everything starts from monthly CTC, which is simply the annual CTC divided by twelve. From there:
Basic
A percentage of monthly CTC — 50% by default, and configurable per tenant.
HRA
A percentage of Basic — 50% by default.
Conveyance
A fixed monthly rupee amount, 1,600 by default.
Employer contributions
Employer PF and the gratuity provision are computed next, because they sit inside CTC rather than on top of it.
Special Allowance — the balance
Monthly CTC minus the fixed earnings, minus every employer contribution. Special Allowance is whatever is left.
That last step is the one worth internalising. Special Allowance is not a rate you set; it is a residual. It is also why the engine can guarantee that gross pay plus employer cost reconciles back to the CTC you entered, to within a rupee. If a CTC is too low to cover the fixed allowances and the employer contributions, the balance would go negative — the engine clamps it at zero and refuses to save the structure rather than quietly producing a wrong number.
There is a second guard on the same screen: a minimum Basic percentage of CTC, defaulted to 50%, which blocks a structure that pushes Basic below your configured floor. Both checks run through the same save gate whether you are in the structure builder or saving through a server-side action, so the two can never disagree.
Money is rounded to whole rupees at every step. There are no paise anywhere in the model.
Interns and other stipend-paid people take a deliberately different path: a stipend structure is a single line with no statutory computation at all.
The statutory rates, and what is configurable
These are tenant settings with Indian defaults, not hardcoded law:
| Component | Default | Notes | |---|---|---| | PF | 12% of Basic | Wage ceiling of 15,000 applied by default; both the rate and the ceiling are editable, and the ceiling can be switched off entirely | | ESI | 0.75% employee, 3.25% employer | Applies while monthly gross is at or below the 21,000 threshold | | Professional tax | 200 flat per month | Or state slabs matched on monthly gross | | Gratuity | 4.81% of Basic | An employer-cost provision inside CTC, not a payout |
A few honest details behind that table.
Employer PF equals employee PF. There is one PF rate, applied to the same base on both sides. The engine does not model the EPS and EPF split of the employer share, EDLI, or PF administrative charges.
ESI eligibility is checked, never guessed. When someone's applicability changes from the previous month, or their gross lands within 5% of the threshold, the run raises a borderline flag for a human to resolve. The contribution-period continuation rule is not automated.
Professional tax does not prorate. It is a flat monthly figure regardless of how many days were paid. State slab presets ship for seven states; they are starting points an admin edits, and you should verify them against the current state notification. Where a state has an annual cap that requires a top-up in a particular month, that top-up is a manual adjustment.
Income tax has two modes. In manual mode a payroll admin sets the TDS figure per employee per run. In automatic mode the engine computes it: annual taxable income under the employee's chosen regime, slab tax, the section 87A rebate, then cess — and then it spreads the balance. The monthly figure is the annual tax still outstanding divided by the months remaining in the financial year, so a mid-year declaration change reshapes the rest of the year rather than producing a single shock deduction. Both regimes are data, editable per tenant and per financial year, and a manual override always beats the automatic figure.
Tax declarations — the rent, 80C, 80D and home-loan figures that feed the old regime — are recorded by a payroll admin. Absent a declaration, the engine assumes the new regime with no exemptions.
How a month is actually paid
Structure lines are a snapshot. Changing a setting today does not retroactively edit a structure saved last month, and it does not touch a run that has already been processed.
For a given month the engine works out how many days exist, on either a calendar basis or a working-day basis that excludes weekends and public holidays. Then:
- Unpaid days outside the employment window — before someone joined or after their last working day — become a proration deduction.
- Approved loss-of-pay leave becomes a separate loss-of-pay deduction.
- Both are priced at gross divided by the number of days in the period.
Earnings always display at their full monthly value; unpaid time appears as explicit, itemised deductions rather than as quietly shrunken earnings. That is a readability decision — an employee can see exactly what was removed and why, down to a half day.
PF is then recomputed on the paid Basic, so a month with unpaid leave contributes proportionally less. Professional tax, as noted, does not move.
One thing that surprises people: attendance does not drive payroll. Only leave approved against the loss-of-pay leave type reduces pay. The attendance module can produce a loss-of-pay feed, but nothing consumes it automatically — payroll will never reclassify someone's paid leave as unpaid on its own.
Bonuses, reimbursements and arrears
One-off money is a single concept with six flavours: bonus, reimbursement, arrears and other earnings on one side; loan deductions and other deductions on the other. They are recorded against an employee, claimed by a run when it is processed, and finalised when that run locks — which is what stops the same bonus being paid twice.
Critically, adjustments are applied after all the structure maths. A bonus does not change PF, ESI or the loss-of-pay arithmetic; statutory contributions stay on regular wages. Taxable adjustments do feed the automatic tax projection.
Arrears are something you record, not something the engine discovers. There is no automatic retro-computation from a back-dated salary revision.
The run state machine
A run moves strictly forward through five states:
draft → review → approved → paid → locked
Processing a run computes every employee's line items and moves it to review; you can reprocess as many times as you like. Approval refuses to proceed while any employee has a negative net pay. Marking a run paid records that you have made the transfer. Locking is the final step.
Every transition asserts its exact source state twice — once in code and once as a condition on the write itself — so two people clicking at the same time cannot skip a state or double-apply one.
Locking is what releases payslips to employees. Before a run is locked, payslips are visible only to payroll admins. Locking also finalises the adjustments the run claimed and notifies everyone their payslip is ready.
There is no unlock, reopen or rollback. This is deliberate: a locked run is the record of what was actually paid, and corrections belong in the next run as arrears or a deduction. Note that this immutability is enforced by the application — there is no code path that edits a locked run — rather than by a database constraint.
A payslip is not a stored file. It is the computed breakdown attached to a run item, rendered to PDF on demand against your letterhead, and every download is audited.
What the engine does not do
Being clear about the edges matters more than the feature list:
- No money movement. There is no bank or payment-gateway integration. Payroll produces a bank transfer CSV; you make the transfer.
- No e-filing. PF, ESI, professional tax, TDS and Form 16 outputs are CSV filing aids you submit yourself. They are not in any regulator's proprietary upload format.
- No full-and-final settlement engine. Gratuity is modelled as a monthly employer provision, not as an exit payout with service-length rules.
- Monthly salaried pay only. Hourly and attendance-priced pay are not modelled here; people paid per hour or per deliverable go through contractor payouts instead.
- No surcharge, perquisites, previous-employer income, or proof-verification workflow in the tax computation.
Where tenant boundaries sit
Every payroll table is tenant-scoped and covered by a restrictive isolation policy, so a query can only ever see one tenant's rows. On top of that, payroll has its own access grant: an organisation can mark specific people as finance users and then restrict payroll to finance only, which removes the HR-admin route into payroll pages and actions. Only an org admin can grant or restrict that — a finance user cannot widen their own access — and the restriction refuses to switch on if it would lock everybody out. Every mutating payroll action is written to the audit log.
Related reading
Frequently asked questions
- Why is Special Allowance a different amount for every employee?
- Because it is the balancing line. Basic, HRA and Conveyance are computed first, then employer contributions are subtracted from the monthly CTC, and whatever remains becomes Special Allowance. It absorbs every rounding difference so that gross plus employer cost reconciles to the CTC you entered.
- Can I reopen a locked payroll run?
- No. Locking is final and there is no unlock action. Corrections are made as an arrears or deduction adjustment in a later run, so the history of what was actually paid is never rewritten.
- Does the engine file my PF, ESI or TDS returns?
- No. Every statutory output is a CSV export you download and submit yourself. ASHR.work is a filing aid, not an e-filing service, and it does not move money.
- Does attendance automatically reduce pay?
- No. Only leave approved against the loss-of-pay leave type reduces pay, plus unpaid days outside someone's employment window. Payroll never reclassifies paid leave as unpaid on its own.