| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Employees (hr)
• Discuss (mail) |
| Community Apps Dependencies | Show |
| Lines of code | 1304 |
| Technical Name |
eh_hr_gratuity |
| License | LGPL-3 |
| Website | https://erpheritage.com.au |
| Versions | 16.0 17.0 18.0 19.0 |
EH HR Gratuity
End-of-service gratuity, computed, approved, and paid on one audited workflow.
Why this module
EH HR Gratuity
The accrual basis is data
Days accrued per year of service is a field on the record, defaulting to 21. Change the basis per record without touching Python, and the amount recomputes from basic salary, years of service and that basis automatically.
Four states, role-gated
A gratuity moves draft, computed, approved, paid, with cancel available from draft. The workflow engine refuses any transition that is not defined from the current state, locks the final states, and checks the user is in the allowed group before each step.
Tamper-evident audit
Every create, write and cancel is written to an append-only, sha256 hash-chained log. State, employee, years, salary, the days basis and the computed amount are captured, and the chain can be verified on demand to show nothing was edited after the fact.
Day in the life
A leaver, settled on the record
An HR officer opens a gratuity for the departing employee, enters years of service and basic salary, and the settlement amount computes from the days-per-year basis. The officer hits Compute to move it to computed; an HR administrator reviews and Approves, then marks it Paid once the money is out. Each step is permission-checked and written to the audit chain, so the final settlement is fully reconstructable from the trail rather than from a spreadsheet nobody kept.
Edge cases
The cases most modules quietly ignore.
In the shipped code today, each one a place where a cheaper module silently does the wrong thing.
Once a gratuity reaches paid or cancelled, the engine treats it as final and refuses any further transition, even one a misconfigured definition might declare from it.
A transition only fires if it is defined from the record's current state. You cannot mark a draft paid, or approve a record that was never computed; the engine raises rather than silently advancing.
Compute and Cancel require the HR officer group; Approve and Mark paid require the HR administrator group. A user outside the allowed group is refused, and admin is the only bypass.
Audit appends take a transaction-scoped Postgres advisory lock, so two concurrent saves cannot fork the hash chain; the lock releases automatically on commit or rollback.
A write that does not actually change any captured field emits no audit row, so the trail records real edits rather than no-op saves.
Each gratuity is owned by a company, required on create. Moving a record into a company the user does not belong to is rejected, and any cross-company override is itself written to the audit log.
A database check constraint refuses negative years of service or negative basic salary, so the computed amount cannot be driven below zero by bad input.
Each record is auto-numbered from a year-prefixed sequence on create, with a fallback reference if the sequence is unavailable, so saved records always carry a non-default name.
What is inside
Built to do the job, end to end.
- Model it adds. One model, eh.hr.gratuity, holding the employee, computation date, years of service, basic salary, the days-per-year basis and the computed gratuity amount, with chatter on the form.
- The computation. gratuity_amount is a stored computed field equal to (basic_salary / 30) times days_per_year times years_of_service, recomputed whenever any of the three inputs changes.
- Workflow as data. The draft, computed, approved, paid and cancelled states and their transitions ship as workflow-definition records, not hard-coded Python, so the path is inspectable and the engine enforces it.
- Audit and company mixins. The model inherits the platform's audited mixin and strict company-aware mixin, so the hash-chained log and multi-company guards apply without any code living in this module.
- Security and access. HR administrators get full access, HR officers read, write and create without delete, and HR managers get read-only, set in ir.model.access.csv.
- Tests in the box. Automated tests cover the computed amount and defaults and the full draft to paid transition path, run as part of the platform suite.
Honest about the edges
What this does not do, so nothing surprises you.
- The days-per-year basis defaults to 21 and is editable per record. The module does not ship country-specific gratuity rule tables, tiered slabs, or unpaid-leave deductions; the formula is a single straight-line accrual you supply inputs to.
- Years of service is entered as a number on the record. The module does not auto-derive tenure from contract or joining dates.
- Marking a gratuity paid is a workflow step that records the settlement. It does not post a journal entry, generate a payslip, or move money; integration with payroll or accounting is not included here.
- The shipped gratuity workflow uses direct role-gated transitions. It does not wire in the multi-step approval-chain engine, so there is no N-step escalation ladder on this document type out of the box.
- There is no scheduled job in this module; gratuity records are created and advanced by people, not by a cron.
odoo gratuity, end of service gratuity odoo, EOSB odoo, gratuity calculation, end of service benefit, severance pay odoo, terminal benefits, employee final settlement, odoo 18 hr, offboarding settlement, leaver pay, gratuity workflow, hr platform odoo community, self-hosted hr odoo
Please log in to comment on this module