EH HR Loan
Employee loans and salary advances with an auto-built repayment schedule, group-gated approvals, and a tamper-evident audit trail.
Why this module
EH HR Loan
Does loans well, claims nothing more
Records loans and advances, builds the repayment schedule, and tracks paid balance. It deliberately does not post to journals or run payroll deductions; the manifest is explicit that accounting integration is a future seam, not a shipped feature.
Approvals enforced in the engine, not the UI
Transitions are gated by HR groups in the workflow definition: employees submit, managers approve or refuse, officers disburse and close. The check runs server-side in action_transition, so it holds whether the move comes from a button, code, or the engine.
Every change leaves a verifiable trace
State, employee, amount, interest rate, instalment count, and start date are written to a shared append-only audit log whose rows are SHA-256 hash-chained and serialized with a Postgres advisory lock, so silent edits are detectable by a chain walk.
Day in the life
From request to a tracked repayment plan
An employee opens a loan, enters the amount, interest rate, instalment count, and first due date, adds a reason for approvers, and submits. A manager reviews and approves or refuses; an HR officer disburses. On disbursement the module clears any prior lines and generates an even instalment schedule, one row per period from the start date forward. As repayments come in, officers mark instalments paid, and total paid and outstanding balance recompute automatically. Every transition and field change is recorded in the hash-chained audit log.
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.
generate_schedule unlinks existing repayment lines before rebuilding, so re-running disbursement never leaves duplicate or stale instalments behind.
Closed and refused are marked is_final in the workflow definition; the engine refuses any further transition from a final state even if a misconfigured definition declares one.
Audit appends take a transaction-scoped Postgres advisory lock so concurrent writers cannot read the same tail and fork the hash chain; verify_chain walks the rows and returns the first broken one.
company_id is required and defaults to the active company; a write that moves a loan to a company the user does not belong to is refused, and any permitted cross-company elevation is itself written to the audit log.
Submit, approve, disburse, close, and refuse each carry an allowed-group set checked server-side, so an employee cannot self-approve a loan through the API by skipping the button.
A database CHECK constraint rejects negative loan amounts and non-positive instalment counts, so a zero-period or negative loan cannot be saved.
Loan references come from a company-shared sequence prefixed LOAN/<year>/ with five-digit padding, falling back to LOAN/AUTO only if the sequence is missing.
What is inside
Built to do the job, end to end.
- Loan and repayment models. eh.hr.loan holds the principal, flat interest rate, instalment count, start date, and reason, with computed total repayable, total paid, and outstanding balance. eh.hr.loan.line holds each instalment with sequence, due date, amount, and a paid flag, cascade-deleted with its loan.
- Engine-driven workflow. The loan inherits the platform workflow mixin and declares the eh.hr.loan workflow code. States and transitions live in a data-defined workflow definition, so the draft to submitted to approved to disbursed to closed path, plus the refuse branch, can be reconfigured without touching Python.
- Audit and company mixins. Inheriting the audited and company-aware mixins gives the loan automatic before and after snapshots on write, create and unlink rows in the hash-chained audit log, and required company scoping with cross-company writes refused by default.
- Schedule generation. On the disburse transition the bound post-action method generate_schedule spreads total repayable evenly across the instalment count, placing each due date one month apart from the start date using relativedelta.
- Security and views. Access rights are defined for HR admin, officer, and self-service employee groups across both models. A list and form view with a statusbar, repayment schedule grid, and chatter ship ready to use under a dedicated Loans menu.
- Tests. A post-install test suite covers default numbering and totals, interest folded into the repayable amount, schedule generation on disbursement, and balance recomputation when an instalment is marked paid.
Honest about the edges
What this does not do, so nothing surprises you.
- No accounting or journal posting. The module is self-contained with no hard accounting dependency; repayments are tracked but not posted to the general ledger, and the manifest states this integration is a future seam.
- No automatic payroll deduction. Instalments are marked paid manually by an HR officer; there is no link that withholds repayments from a payslip.
- Flat interest only. Interest is a single flat percentage applied to the principal; there is no reducing-balance or compounding interest model.
- Even instalments only. The generated schedule divides total repayable evenly across all periods on a monthly cadence; bespoke amounts, irregular intervals, balloon payments, or grace periods are not generated automatically.
- No approval-chain escalation in this module. Transitions are gated by HR group membership, not by a multi-step approval chain with delegation or timeout escalation.
- Depends on the EH HR Platform. Requires eh_hr_core, eh_hr_compat, eh_hr_engine_workflow, and hr; it is not a standalone loan app and uses the platform workflow and audit infrastructure.
- Built for Odoo 18 Community.
odoo employee loan, odoo hr loan management, salary advance odoo, loan repayment schedule odoo, odoo 18 hr loan, employee advance management, instalment loan tracking odoo, hr loan approval workflow, staff loan odoo community, odoo payroll loan, loan audit trail odoo, multi company hr loan
Need this fitted to the way you work?
ERP Heritage delivers end to end Odoo work: Odoo Implementation, Customization and Development, Integration, Migration, Consultation, Support and Training. We help teams put this module into production, shape it to their process, and keep it running.
We work with businesses across Australia (Melbourne, Sydney, Brisbane, Perth, Adelaide, Canberra) and the Middle East (Dubai, Abu Dhabi, Riyadh, Jeddah, Doha, Kuwait City, Muscat). Start a conversation at erpheritage.com.au or email info@erpheritage.com.au.
Languages
Available in 19 languages
The interface ships translated out of the box. Switch language in Odoo and the fields, menus, and messages follow.
Please log in to comment on this module