| 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 and settled on an audited workflow.
Why this module
EH HR Gratuity
One transparent formula
Gratuity is basic salary over 30, times days per year, times years of service. The result is a stored computed field, so it stays consistent on screen, in lists and in exports, and recomputes whenever an input changes.
Every change is on the record
State, employee, years, salary, days-per-year and the computed amount are captured into an append-only, sha256 hash-chained audit log on create, write and unlink. A verify pass walks the chain and reports the first tampered row.
Right people, right step
Compute and cancel are gated to HR Officers, approve and mark-paid to HR Admins. Transitions are refused from the wrong state, and the paid and cancelled states are final, so a settled record cannot be quietly reopened.
Day in the life
From last working day to settled payout
An HR officer opens a gratuity record for a leaving employee, fills in years of service, basic salary and the days-per-year basis, and saves. A GRAT reference is generated automatically and the computed payout appears at once. The officer runs Compute to move the record to computed, and the audit log captures the snapshot. An HR admin reviews the figure, approves it, then marks it paid once settled. Each step is group-gated and final states are locked, so the paid record stands as a tamper-evident settlement on the audit trail.
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.
Audit appends are serialised by a transaction-scoped Postgres advisory lock, so two transactions writing gratuity events at once cannot read the same chain tail and fork the hash chain.
A reference is generated from the sequence only when the name is still New, so re-saving or copying a record never burns a second GRAT number or overwrites an existing one.
company_id is required and defaults to the active company. A cross-company write is refused even under sudo unless an explicit audited override context is set, and the override itself is logged with every affected record id.
Paid and cancelled are marked final in the workflow definition. Any further transition from a final state is refused, even one a misconfigured definition might declare.
A transition is only applied when it is defined from the record's current state and the user holds one of its allowed groups; otherwise it is rejected with a clear error rather than silently advancing.
A write that does not change any audited field emits no audit row, so the trail stays meaningful instead of filling with no-op edits, while create and unlink are always recorded.
A database CHECK constraint rejects negative years of service or negative basic salary, so the computed payout cannot be driven below zero by bad input.
What is inside
Built to do the job, end to end.
- Gratuity record and formula. The eh.hr.gratuity model holds employee, computation date, years of service, basic salary and an integer days-per-year basis defaulting to 21. The gratuity amount is a stored computed field equal to basic salary over 30, times days per year, times years of service, recomputed on any input change.
- Configurable workflow. States draft, computed, approved, paid and cancelled, and the transitions between them, are workflow definition records rather than code. The status bar and header buttons are driven from that definition, so the steps can be reconfigured without touching Python.
- Append-only audit trail. Through the platform audited mixin, every create, write and unlink on a gratuity record is captured into eh.hr.audit.log with before and after snapshots, chained by sha256 over the previous row. No group is granted write or unlink rights on the log itself.
- Strict company scope. The company-aware mixin makes company_id required, defaults it to the active company and forbids cross-company writes by default, with a logged, explicit override path for the rare legitimate case.
- References, security and chatter. Records carry an auto-generated GRAT reference, an HR Officer and HR Admin access model, a menu under HR records, and a mail.thread chatter with field tracking on the key figures.
Honest about the edges
What this does not do, so nothing surprises you.
- The days-per-year basis is a single value per record, defaulting to 21. The module does not model tiered schedules such as a different rate for the first years of service versus later years; adjust the basis per record where a different rate applies.
- Years of service and basic salary are entered on the record, not derived. The module does not auto-calculate tenure from contract or join dates, nor pull the salary from a contract or payslip.
- This module computes and records the settlement only. It does not post a journal entry, generate a payslip, or create a vendor or employee payment; mark paid is a workflow state, not an accounting action.
- Transitions are gated by user group, not by a multi-step approval chain. The platform approval engine exists but is not wired into this module, so there is no escalation ladder or per-record approver routing here.
- There is no scheduled job in this module; records are created and advanced by users, not by a cron.
- Currency follows the company; the amount is a plain monetary figure with no built-in multi-currency conversion of the basic salary input.
end of service gratuity odoo, eos gratuity, severance pay odoo 17, final pay calculation, gratuity calculator odoo, leaving entitlement hr, odoo 17 community hr, hr workflow approval, hash chained audit trail, multi company hr odoo, employee end of service settlement, days per year gratuity
Please log in to comment on this module