Payroll is where close enough stops working
A sales report that’s slightly off gets a shrug. A payslip that’s slightly off gets a queue outside the HR office on the first of the month. That’s why most companies are careful with payroll software, and also why so many of them run a clean system with a messy spreadsheet bolted to the side.
The spreadsheet holds the rules that didn’t fit. Overtime at double rate after 48 hours. A night shift allowance for one site. A deduction when a uniform isn’t returned. Each one is small. Together they’re a full day of someone’s month, every month.
What HR and payroll software on Frappe HR or Odoo needs from you
First, a platform fact that trips people up. On the ERPNext side, HR and payroll moved out of ERPNext into Frappe HR (the hrms app) in version 14. You install it on the same bench, and it provides Employee lifecycle, Salary Component, Salary Structure, Salary Structure Assignment, Payroll Entry, Salary Slip and Additional Salary. Custom payroll work is really Frappe HR work.
On Odoo, the Employees app is Community, but Payroll is Enterprise. Salary structures, salary rules with Python conditions and hr.payslip all need an Enterprise subscription. We’re happy to generate rules for it. We’re less happy to rebuild statutory payroll from nothing on Community, and we’ll say so.
What we need from you is less than you’d think: a copy of your salary components, one real payslip with the numbers explained, and the contract clause for anything unusual. If two people in HR explain the same rule differently, that’s not a problem for the software. Settle it before we generate anything, because code will faithfully pay whichever version you pick.
Worked example: overtime at a packaging plant
Picture a plant with around 140 hourly staff on ERPNext and Frappe HR. Supervisors already approve overtime on paper forms. Payroll types the hours into a spreadsheet, calculates the amount and adds it to each salary slip by hand.
The rule in the employment contract: overtime is paid at twice the ordinary hourly rate, and the hourly rate is monthly base divided by 26 working days and 8 hours.
Take Sunita, a machine operator with a monthly base of 31,200. Her hourly rate is 31,200 / 26 / 8 = 150. Overtime pays 300 an hour. Her supervisor approved 11 hours across September, so her Overtime line is 3,300.
What erpfly generates:
- An Overtime Claim DocType with employee, date and hours, and a Workflow so only the shift supervisor can approve.
- The function on this page, which runs before the Payroll Entry and creates one submitted Additional Salary per employee for the month.
- A link back from each claim, so the same hours can’t be paid twice if someone reruns payroll.
The Salary Slip then picks up the Overtime component the normal way. The hours aren’t retyped anywhere. If Sunita asks why she got 3,300, the slip’s print format lists the claims behind it.
Where we’ll slow you down on purpose
Going live without a parallel run. Run the old payroll and the new one side by side for a month. It’s tedious. It’s also the only way to find the rule someone applied from memory for six years.
Clever formulas only their author can read. A salary component with a nested condition four levels deep is a future incident. We’d rather split it into two components with plain names.
Payroll inside a Server Script. Payroll logic belongs in version-controlled code with tests. Our take on Server Scripts vs a custom app explains why.
Guessing at local law. We turn rules into code. Your accountant decides what the rules are.
What payroll depends on
Overtime and deductions are only as good as the hours behind them, so attendance management usually comes first. Unpaid days and encashments flow in from leave management, and reimbursements often run through expense management instead of payroll. Before you upgrade, read how to keep ERPNext customizations through an upgrade.