👔 Staff & Payroll Guide
This guide covers Ledgr's HR & payroll module — employees with country-specific compliance fields, leave management, validity-dated salary structures, salary runs with proper journal entries, and advances with EMI auto-deduction.
What you get
- Employee master — separate from your software users (login) and salesmen (sales role). Most staff have no software login but are real headcount.
- Country-aware compliance — IN / US / UK / AE compliance fields adapt automatically based on your company country.
- Leave management — types (CL, SL, EL, etc.), requests with approval workflow, year-wise balances.
- Salary structures — validity-dated, section-grouped (Earnings / Reimbursements / Deductions / Employer Contributions), per-employee customizations.
- Salary runs — draft → finalised → paid lifecycle with immutable line snapshots and balanced double-entry journal entries.
- Three-pass salary resolution — handles percent_of_basic + percent_of_gross dependencies in correct order.
- Employee advances — one-time or EMI; auto-deducted from finalised salary runs until cleared.
- Daily Attendance Grid — quick today's mark.
- Monthly Attendance Grid — spreadsheet view, click cells to cycle status, keyboard shortcuts (P/A/H/L/W), CSV import/export.
- Country-aware seeding — leave types + salary components pre-populated based on company.country on first enable.
- Salesman ↔ Employee linking — run payroll for sales reps from the same record.
- Biometric integration — automatic attendance from ZKTeco / eSSL devices. See Biometric guide.
The boundary between Users / Salesmen / Employees
Three database tables, three different concerns:
| Table | Purpose | Has login? |
|---|---|---|
| users | Software access — login + RBAC permissions. Owner, Admin, Accountant, Manager, Sales, Viewer roles. | ✅ Yes — has password |
| salesmen | Sales-rep entity with territory + commission %. Drives Salesman Performance reports. | ❌ No (unless also a user) |
| employees | HR identity. Real headcount with salary, leaves, attendance, compliance fields. | ❌ No (unless also a user) |
The same person can be all three — e.g. the owner is a user (admin role), an employee (with salary), and a salesman (commission). Linking is via foreign keys: salesmen.employee_id and employees.user_id.
Country-aware seeding
When you enable the Staff module for the first time, Ledgr looks at companies.country and seeds appropriate defaults. You can edit/add/remove afterwards.
🇮🇳 India
| Type | Seeded entries |
|---|---|
| Leave types | Casual Leave (CL, 12 days), Sick Leave (SL, 12 days), Earned Leave (EL, 15 days + 30 carry-forward), Maternity Leave (ML, 182 days) |
| Earnings | Basic, HRA (40% of basic), DA, Conveyance, Special |
| Deductions | EPF (12% EE + 12% ER), ESIC (0.75% EE + 3.25% ER), Professional Tax (₹200), TDS |
🇺🇸 United States
| Type | Seeded entries |
|---|---|
| Leave types | PTO (15 days), Sick (5 days), FMLA (84 days) |
| Earnings | Salary, Overtime, Bonus |
| Deductions | Federal Tax, Social Security (6.2% EE + 6.2% ER), Medicare (1.45% EE + 1.45% ER), State Tax |
🇬🇧 United Kingdom
| Type | Seeded entries |
|---|---|
| Leave types | Annual Leave (28 days), Sick Leave (5 days) |
| Earnings | Salary |
| Deductions | PAYE, National Insurance Cat A (8% EE + 13.8% ER), Pension (5% EE + 3% ER) |
🇦🇪 UAE
| Type | Seeded entries |
|---|---|
| Leave types | Annual Leave (30 days), Sick Leave (90 days), Maternity Leave (60 days) |
| Earnings | Basic, Housing, Transport, Other |
| Deductions / Provisions | EOSG (End-of-Service Gratuity) accrual placeholder — accrue per UAE labour law (21 days basic for first 5 years, 30 days thereafter) |
Other countries: minimal default — Annual Leave (20 days), Sick (10 days), Salary + generic Tax. Customize as needed.
Adding employees
The employee form
Staff → Employees → + New Employee. Standard fields:
- Name (first, last, display name override)
- Employee code, contact (email, phone, mobile)
- DOB, gender, marital status
- Hire date (required), probation end date, exit date + exit reason
- Employment type — full_time / part_time / contractor / intern
- Department, designation, reports-to (another employee)
- Pay basics — payment_type (monthly_salary / hourly / piece_rate), base salary, hourly rate, pay frequency
- Bank details — bank name, account, IFSC (IN) / SWIFT / Routing (US) / IBAN (EU)
- Photo upload (optional)
- Linked user — if this employee should have software login (e.g. they're also a Manager role user)
Country-specific compliance fields
The form's Compliance section adapts based on company.country:
🇮🇳 India compliance fields
- PAN (10 chars)
- Aadhaar last 4 digits only — for privacy. Don't store the full 12.
- UAN (Universal Account Number for EPF)
- ESIC IP Number (Insured Person)
- PT State (Professional Tax — varies by state, not all states have PT)
🇺🇸 US compliance fields
- SSN last 4 digits only — for privacy
- W-4 Filing Status — Single / Married Joint / Married Separate / Head of Household
- State — drives state tax calculation
🇬🇧 UK compliance fields
- NI Number (National Insurance, format: AB 12 34 56 C)
- NI Category (A, B, C, X, etc.)
- Tax Code (e.g. 1257L)
🇦🇪 UAE compliance fields
- Emirates ID
- Passport Number
- Visa Number + Visa Expiry
- Nationality
All compliance data is stored as JSON in employees.compliance_data — adapts on the fly without schema migrations.
Leave management
Leave types
Staff → Leaves → Types tab. Edit / add / disable any. Each type has a default annual entitlement and a max carry-forward.
Leave requests
Staff → Leaves → Requests tab. Workflow:
- Employee (or HR on their behalf) raises a leave request — pick type, date range, reason.
- Status defaults to
pending. - Manager / HR approves or rejects.
- On approval: leave_balance is decremented for that year × leave_type.
- The dates appear on Monthly Attendance Grid as
leaveafter running "Apply Approved Leaves".
Leave balances
Staff → Leaves → Balances tab. Per-employee × leave-type × year breakdown:
- Opening — start of year balance (carry-forward from previous year)
- Accrued — granted this year
- Used — taken so far
- Encashed — converted to cash
- Available = opening + accrued − used − encashed
Salary structure
Components
Staff → Payroll → Salary Components. Each component has:
- Name — Basic, HRA, PF, etc.
- Type — Earnings / Reimbursements / Deductions / Employer Contributions
- Calc method:
fixed_amount— exact rupees / dollarspercent_of_basic— e.g. HRA 40% of Basicpercent_of_gross— e.g. some bonusesformula— limited expressions (future)
- Default value — % or fixed amount
- Country — restricts visibility (e.g. PF only for India)
Per-employee structure
Each employee gets their salary structure assigned via Staff → Employees → click employee → Wallet icon → Salary Structure Dialog. The dialog shows:
- All applicable components grouped by section (Earnings / Reimbursements / Deductions / Employer Contributions)
- Per-component value (fixed amount or percent)
- Live preview totals (Gross / Total Deductions / Net / CTC) computed via three-pass resolution
Validity-dating
Salary structures are validity-dated. When you save a new structure for an employee:
- Old structure rows get
valid_to= new structure'svalid_from. - New structure rows are inserted with
valid_from= today (or your chosen date).
Salary runs always pull the structure that was valid on the run's period start date — so a backdated payroll re-run uses the structure from then, not the current one.
Three-pass salary resolution
Components depend on each other:
- Basic = ₹30,000 (fixed)
- HRA = 40% of Basic = ₹12,000
- Bonus = 5% of Gross = 5% of (Basic + HRA + ...) — needs gross to be known
Ledgr resolves in three passes:
- Pass 1: All
fixed_amountcomponents. - Pass 2: All
percent_of_basiccomponents (basic is now known). - Pass 3: All
percent_of_grosscomponents (gross = sum of pass 1 + 2).
Without this ordering, you'd get circular dependencies. Ledgr handles it automatically.
Salary runs (the payroll cycle)
A salary run is a payroll period (typically one month). Lifecycle:
draft → finalised → paid
↓
(cancellable in draft only)
1. Draft
Staff → Payroll → + New Salary Run. Pick period start + end (typically month boundaries).
Ledgr generates one salary_run_lines row per active employee using:
- Their structure that was valid at period start
- Three-pass resolution to compute Gross / Net / CTC
- Active EMI advances (added as preview deductions)
- Days worked / hours from
attendancetable for hourly employees
Status = draft. You can review each line, edit any value, regenerate if you change attendance.
2. Finalised
Click Finalise Run. Status flips to finalised. Side-effects:
- Lines become immutable — frozen snapshot for audit trail.
- Balanced journal entries are posted: Dr. Salary expense (gross) / Cr. Salary Payable (net) + various deduction-payable accounts (PF, ESIC, TDS).
- Active EMI advances get repayment rows created in
advance_repayments;amount_repaidupdates on the advance. Whenamount_repaidreachesamount, advance status flips tosettled.
Finalised runs cannot be deleted (they're audit-trail). To correct an error: cancel the run before finalising, or issue an off-cycle adjustment.
3. Paid
Click Mark All Paid after disbursing salaries. Status = paid. Each line's paid_on = today, run's paid_at = timestamp.
Bank reconciliation in the Banking module shows the salary disbursement entries — match them off when the bank statement comes in.
Employee advances
Staff → Advances. Two types:
- One-time — single repayment (next salary or lump-sum cash).
- EMI — split across N months. Auto-deducted from each finalised salary run until cleared.
Disbursement
- Staff → Advances → + New Advance.
- Pick employee, amount, repayment method (one_time / emi), EMI count if applicable, EMI amount.
- Mark "Disburse Now" — Ledgr posts journal: Dr. Employee Advances / Cr. Cash. Cash leaves your bank.
EMI auto-deduction
While the advance has amount_repaid < amount and repayment_method = 'emi', every salary run draft includes an EMI_ADV deduction line at the configured EMI amount. On finalise, repayment is recorded.
Settlement
An advance auto-settles when fully repaid. You can also manually settle (one-time advance) or cancel (if not yet disbursed) — the journal entries are reversed in both cases.
Attendance
Two grid views, both feed payroll. See Biometric guide for automated attendance from ZKTeco / eSSL devices.
Daily Attendance Grid
Staff → Attendance → Daily Mark sub-tab. Pick a date, mark every active employee with status (present/absent/half_day/weekoff/holiday/leave). "All Present" / "All Week Off" quick buttons. Save commits via upsert.
Monthly Attendance Grid
Staff → Attendance → Monthly Grid sub-tab. Spreadsheet view — rows = employees, columns = days. Click cells to cycle status, or type single-letter shortcuts:
- P — Present
- A — Absent
- / or 0 — Half day
- W — Week off
- H — Holiday
- L — Leave
- Esc — Clear
Toolbar bulk operations:
- Apply Default Pattern — fills weekdays as Present, weekly-off days as W (per Settings → Attendance Policy)
- Apply Approved Leaves — overlays approved leave_requests as L
- Mark All Present — fills empty cells with P
- Clear Edits — resets dirty cells
CSV import (long format: employee_code, date, status, in_time, out_time, hours, notes) and CSV export (wide format) both work.
Common workflows
Monthly payroll cycle (India)
- 1st of month: ensure last month's attendance is complete (Monthly Grid).
- If using biometric: click status pill → "Sync Now" → "Aggregate to Attendance".
- Override any anomalies (approved leaves not yet applied, exceptional cases).
- Save attendance grid.
- Staff → Payroll → New Salary Run for last month's period.
- Review the draft lines — verify Gross/Net per employee.
- Click Finalise. Journal entries post.
- Disburse salaries via bank transfer.
- Click Mark All Paid.
- Reconcile in Banking when statements arrive.
New employee mid-month
- Add employee with hire_date = mid-month.
- Assign salary structure.
- Mark attendance from hire_date forward.
- When you create the salary run, Ledgr pro-rates based on days worked.
Employee resignation / exit
- Staff → Employees → click employee → set
exit_date+ exit reason. - Generate final salary run for the exit month — pro-rated to exit_date.
- For UAE: EOSG accrual gets settled (manual entry for now; auto-accrual on roadmap).
- For India: F&F settlement — encash unused leaves (set leave_balance.encashed += unused EL), include in final salary.
- Mark employee inactive (Power button on EmployeeList).
Salary increment mid-year
- Staff → Employees → click → Wallet icon → Salary Structure Dialog.
- Edit basic + linked components to new values.
- Set "Effective from" date = increment date.
- Save. Old structure closes (valid_to = increment date), new one starts.
- Salary run for the increment month uses the new structure (since validity_from ≤ run period start).
Bonus / one-time payment
- Staff → Advances → +New Advance with type=one_time.
- Disburse via cash/bank.
- To recover from next salary: use repayment_method=one_time. Auto-deducts from next run.
- Or skip recovery if it's actually a bonus — settle manually as paid.
Reports
Payroll Register
Staff → Reports tab. Flat list of all salary_run_lines for a date range. Columns: run period, employee, designation, days worked, gross, deductions, net, payment status, paid_on. CSV export.
Use it for:
- Quarterly / annual payroll consolidation
- Tax filings (TDS-Q4, Form 24Q)
- Audit submissions
- Comparative analysis ("salary growth this year")
FAQ — Staff & Payroll specific
Can an employee log into Ledgr to see their own payslip?
Yes — link the employee to a user record (with role = Sales / Viewer). When they log in, RBAC restricts what they see. A self-service payslip portal is on the roadmap; currently the admin / HR has to download and email the payslip.
Does Ledgr auto-file PF / ESIC / TDS returns?
Not yet. Ledgr generates the data (Payroll Register, deduction breakdowns), and you upload to the respective portals. Direct API filing is on the long-term roadmap; for now, copy/upload via portal.
Can I customize the payslip template?
Standard payslip covers most needs (header with company logo, employee details, components grouped by section, totals, signature line). For deeper customization (different layouts per category), the PDF is generated via @react-pdf/renderer — code-level changes possible. WhatsApp us for tailored templates.
What about overtime calculation?
Overtime hours can be entered manually as an "Overtime Hours" component on the salary run line. Auto-calculation from biometric punches (time-after-shift-end) is on the roadmap; for now manual.
How do I handle multiple legal entities (e.g. different state offices)?
One Ledgr install per legal entity (separate company database). Employees are per-company. For consolidated HR reporting across entities — export each, merge in Excel for now.
What if my country isn't in the IN/US/UK/AE list?
Ledgr falls back to a minimal default (Annual + Sick leave types, generic Salary + Tax components). Edit the seeded values to match your local labour law. The compliance section on the employee form shows generic name/ID/passport fields if no specific country profile exists.
Can I run weekly / bi-weekly payroll instead of monthly?
Yes. Each employee has a pay_frequency field (monthly / weekly / biweekly / semi_monthly). Set per-employee. When you create a salary run, pick the matching period (e.g. "Week 12 2026"). Ledgr computes pro-rated values.
Salesman has both salary + commission. How is it set up?
Link the salesman to an employee record (CRM → Salesman → Linked Employee dropdown, or briefcase icon on EmployeeList). On the employee's salary structure, add a "Salesman Commission" earnings component — Ledgr computes it from invoice attribution × commission_pct. More in the Wholesale doc.
Can I import existing employees from Tally / Greythr / Zoho People?
CSV import is supported (Settings → Import Data → Employees). Map the CSV columns to Ledgr fields. Compliance data (PAN, UAN, etc.) maps to a JSON sub-fields. WhatsApp us for migration help with specific source systems.
Does Ledgr handle reimbursements (expense claims)?
Reimbursement components on the salary structure are settled with the salary run. For ad-hoc expense claims (with receipts attached), use Quick Entry or Purchase Bills under the employee as a vendor. A formal "Expense Claims" workflow with receipt attachments is on the roadmap.
Setting up payroll for the first time?
WhatsApp us — we'll help you map your salary structure, set up country-specific compliance, and run your first salary cycle. Free 1-hour onboarding call.