Skip to main content
itzseo
HRMS · Phase 40

Payroll that runs on the data you already have.

Attendance, leave, OT, holidays — already in ItzSEO. So payroll reads from those instead of asking HR to retype them into Tally, QuickBooks, or a spreadsheet. Monthly drafts, audited lifecycle, PDF payslips employees actually see.

What HR does

Define once. Finalize monthly. Audit always.

No per-month re-entry. The structure persists; only attendance + leaves drive the monthly delta.

Salary structures

One per employee. Define basic, gross, and components — EARNINGS (HRA, special allowance, conveyance, custom) + DEDUCTIONS (PF, ESI, PT, TDS, custom). Version-history kept on every edit so you can answer 'why did Anindita's net pay change in July'.

14-calculator registry

FIXED, PER_DAY, PERCENT_OF_BASIC, PERCENT_OF_GROSS, BASIC_PRORATED, OT_HOURLY, plus India: IN_PF_EMPLOYEE/EMPLOYER, IN_ESI_EMPLOYEE/EMPLOYER, IN_PT_MAHARASHTRA/KARNATAKA/WEST_BENGAL, IN_TDS (Budget 2025). Component order enforced — gross-dependent calcs can't precede core earnings.

Monthly lifecycle

DRAFT → FINALIZED → AMENDED. DRAFTs auto-recalculate when source attendance or leave changes. FINALIZED locks the row + sends the employee an email + makes the PDF available. AMENDED writes an immutable audit row with HR's reason.

Manual entry + override

Mid-month joiners with no attendance yet? Create a manual-entry payslip with hand-typed values. Bonus or court-ordered garnishment? Direct-override after finalize, with required HR reason captured in the audit log. Both paths gated to HR + workspace owner.

Bulk finalize

Finalize the whole roster at once with a single click + confirm. Per-row failures surface inline, succeeded rows commit. No alert() interruptions — HR sees a color-coded result strip and re-runs as needed.

Modification history

Every recalc, override, amend, status change writes a PayslipModification row with before/after snapshot + actor + reason + trigger. Surfaces in the per-payslip detail panel. Concurrent recalc protection via lastRecalcAt CAS — no silent overwrites.

What employees see

/me/payroll — clean, simple, downloadable.

DRAFTs are hidden until HR finalizes. No half-baked numbers leak.

Payslip list

Reverse chronological. Status pill (Final / Amended). Net pay + gross + period. Click a row → full breakdown of working days, present days, leave, OT, every earning + deduction line.

One-click PDF

@react-pdf/renderer single-page A4 with employer letterhead + employee name + period + line-item table + net pay box + finalized/amended dates. Logo failure-safe — broken logo URL falls back to text header without breaking the download.

Auto-emailed on finalize

Resend-delivered email lands when HR clicks Finalize. Amendment fires a second email with the reason. Both gated by /settings/notifications toggles employees control themselves.

Background

Two crons keep drafts honest.

You shouldn't have to remember to draft payroll on the 1st. Or recalculate when an attendance event changes mid-month.

Monthly draft

/api/cron/payroll-monthly-draft fires on the 1st at 00:30 IST. Creates DRAFT payslips for every employee with an active salary structure, sourcing attendance + leave + OT from the prior month. Idempotent — safe to re-run.

Recalc safety net

/api/cron/payroll-recalc-pending fires every 4 hours. Catches DRAFTs where the source data changed but the inline recalc hook didn't fire (silent error, migration script, engineVersion bump). Optimistic concurrency guard on lastRecalcAt prevents stale overwrites.

For Indian agencies

PF, ESI, PT, TDS — all live.

Statutory math implemented to current spec. We audit ourselves when the law changes (we just rewrote TDS for Budget 2025).

PF (Provident Fund)

12% of basic, employee + employer halves as separate components. Wage-ceiling option available. Voluntary PF supported via custom components.

ESI (Employees' State Insurance)

0.75% employee + 3.25% employer (post-2019 rates). Per-workspace eligibility per ESI Act §10 — HR controls who's in the scheme, not a static gross-threshold gate.

Professional Tax

Maharashtra (₹0 up to ₹10k, ₹200 above, ₹300 in Feb), Karnataka, West Bengal slabs all shipped. Slab table reflects 2023 Maharashtra revision (no ₹175 mid-band).

TDS (Budget 2025)

₹75k standard deduction, ₹60k 87A rebate up to ₹12L taxable, 7-band ladder (4L/8L/12L/16L/20L/24L). New regime default. Old regime not bundled — HR uses a custom calc if needed.

Why HR doesn't lose sleep

Safety rails baked in.

CSV formula-injection defense — every cell starting with = + - @ or tab/CR is prefixed with ' to disarm Excel/Sheets formula triggers. Stops the "HR opens CSV → laptop pwned" class.

Money bounds + invariants — every minor-unit field bounded to ±₹1 crore. Net pay must equal gross minus deductions. Line items capped at 30. Payslip numbers charset-whitelisted.

payslipNumber uniqueness@@unique([workspaceId, payslipNumber]) plus a P2002-retry helper means concurrent finalizes can't produce duplicate numbers.

Override blocked on DRAFT — calc engine owns DRAFTs. HR can only direct-override after finalize, so amendments can't be silently overwritten by the next recalc.

Holiday isPaid:false respected — unpaid holidays don't over-pay employees. Half-day leaves emit a 0.5 ABSENT row for the unworked half so workingDays totals correctly.

FAQ

Payroll questions.

Does this replace my accountant?
No. ItzSEO calculates the numbers + issues payslips. Your accountant still files PF challans, TDS returns, etc. with the government. We hand off via CSV export (17-column period dump) so they don't have to retype anything.
What if our country isn't India?
The calc engine is country-agnostic — the India calculators are just one set in a 14-entry registry. Non-India workspaces use FIXED + PERCENT_OF_BASIC + PERCENT_OF_GROSS + PER_DAY + BASIC_PRORATED + OT_HOURLY as building blocks. Custom country calculators land on request.
What if HR makes a mistake?
Finalized payslip wrong? Amend it. AMENDED status writes an immutable audit row with HR's reason, employee gets an 'amended' email, the PDF stamps 'Amended on YYYY-MM-DD'. The original draft + every recalc + every override is preserved in PayslipModification rows.
Can employees see drafts?
No. /me/payroll only shows FINALIZED + AMENDED. DRAFTs are HR-internal — they exist so HR can adjust before locking. Employees only see what HR has explicitly signed off.
What happens when attendance changes mid-month?
The inline recalc hook fires when HR edits a punch, decides a leave, approves OT, or changes a salary structure. The affected employee's DRAFT payslip refreshes immediately. The 4-hour cron is a safety net for missed hooks.
How does the modification history work?
Every change writes a PayslipModification row with before-snapshot + after-snapshot (JSON) + actor user + trigger type (INITIAL_GENERATION, ATTENDANCE_EDIT, LEAVE_EDIT, OT_APPROVAL, STRUCTURE_CHANGE, HOLIDAY_EDIT, DIRECT_OVERRIDE, STATUS_FINALIZED, STATUS_AMENDED) + reason. Surfaces as a timeline in /hr/payroll/[userId]/[period].
Are payslips legal documents?
In India the requirement is 'a wage slip in writing' under the Payment of Wages Act + state rules. Our PDF satisfies that — employer name + employee name + period + earnings + deductions + net + finalized date — but verify with your accountant for your jurisdiction. Customize the footer via /settings/hr/payroll.
Is payroll included in the Agency tier?
Yes. $249/mo covers your whole team — payroll engine, payslip PDFs, email delivery, CSV exports, all the calculators. No per-employee charge.

Stop running payroll in spreadsheets.

14-day trial. Drafts on the 1st, payslips by the 5th, employees emailed automatically.