| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
•
Employees (hr)
• Time Off (hr_holidays) • Discuss (mail) • Attendances (hr_attendance) • Calendar (calendar) |
| Community Apps Dependencies | Show |
| Lines of code | 7108 |
| Technical Name |
eh_hr_leave_pro |
| License | LGPL-3 |
| Website | https://erpheritage.com.au |
| Versions | 16.0 17.0 18.0 19.0 |
HR Leave Pro for Odoo 18
Event-sourced leave balances, accrual, carryover, and approval on Odoo 18 Community.
Why this module
HR Leave Pro for Odoo 18
Balances are a ledger, not a counter
Every grant, consume, carryover, expiry, adjustment and reversal is an immutable row. The current balance is the sum of ledger deltas as of a date, so balances are auditable and rebuildable. The ledger blocks edits except admin corrections, which are made by writing a reversal row rather than mutating history, and deletes only through the retention service.
Idempotent by construction
Accrual, grant, consume, reversal, carryover and expiry each carry a deterministic correlation_id, and a unique constraint dedupes a re-run. A cron that retries after a crash, or a mobile submit replayed with the same idempotency key, lands the same single effect rather than double-counting leave.
Native Time Off, kept in step
On approval the platform request projects an hr.leave row keyed to the request and marked managed, so the standard Time Off calendar and reporting see real data. Cancellation retracts it. Rows created by hand in core Time Off are never touched, and managed-row edits are written to the audit log.
Day in the life
A request from tap to balance
An employee opens the quick wizard, which pre-fills annual leave for today and runs eligibility server-side: balance, overlap and certificate checks block submission, and a short-notice flag warns. On submit the request enters a serial chain, line manager first then HR officer, with escalation hours per step and the real submitter captured so a delegated submitter cannot self-approve. On approval the duration is counted in working days only, skipping weekends from the resource calendar and the company public holiday calendar, a consume row hits the ledger, the request expands into per-day rows, attendance days flip to leave, and a native Time Off row is projected. Nightly crons accrue, sweep carryover at the year boundary, and expire stale allocations.
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.
The balance ledger refuses writes except for an HR admin, and even then the intended pattern is a reversal row, not an edit. Rows are undeletable outside the retention purge context, so balance history cannot be silently rewritten.
Accrual, carryover and expiry each derive a deterministic correlation_id per employee, type and period. The ledger unique constraint dedupes, so a cron that re-runs after a crash, or runs twice in a day, does not double-grant or double-expire.
The request captures the real submitter id before the approval engine elevates to sudo, and passes it through, so a user who submits on another employee behalf cannot then approve their own submission.
Duration counts only working weekdays from the employee resource calendar and excludes the company public holidays, so a leave spanning a weekend or a holiday does not over-consume balance. A mid-month hire accrues only the worked fraction of the first month.
A live request cannot overlap another active request for the same employee, enforced both by a constraint and a pre-flight service. Leave at or above the type certificate threshold is blocked at submit unless an evidence attachment is present.
Allocations, requests and the ledger are scoped by record rules into a self, team and company triplet, and leave types and balances are company-aware, so a multi-country group keeps separate calendars and entitlements.
Cancelling an approved request writes a reversal row that restores balance, drops the per-day rows, recomputes the affected attendance days, and retracts the projected Time Off row through a state every supported version permits deleting.
What is inside
Built to do the job, end to end.
- Balance ledger and balance service. Append-only event log of grant, consume, carryover, expiry, adjustment and reversal rows. The balance service reads current balance by SQL aggregation as of a date and a full per-type matrix, and emits ledger rows for every mutation.
- Accrual, carryover and expiry crons. Three daily crons read per-type policy documents through the policy engine: periodic accrual with proration and a cap, a year-boundary carryover sweep that forfeits excess over the carryover limit, and an expiry sweep that reverses unused allocation past its grant window.
- Workflow, approval chain and notifications. Request states and transitions are declared in data, not Python. Submission opens a serial manager-then-officer chain with per-step escalation hours and a per-type chain override, and submitted, approved and refused notification templates dispatch through the notification engine.
- Requests, allocations and per-day expansion. Requests own dates, type, half-day or hourly granularity, reason and evidence; allocations own entitlement grants by manual, accrual, carryover or adjustment source. Approved requests expand into idempotent per-day rows as a stable integration surface.
- Native Time Off projection and attendance bridge. Approved requests project a managed hr.leave row keyed to the request, validated without core approval and never colliding with hand-created rows. The attendance bridge recomputes the affected days so they show as leave.
- Public holiday calendar and mobile API. A company-scoped public holiday model with Australian state and territory regions is the single holiday source for the suite. A JSON mobile API exposes leave types, balance, eligibility and an idempotent submit endpoint.
Honest about the edges
What this does not do, so nothing surprises you.
- This module is part of the EH HR Platform and depends on its core, workflow, approval, policy, notification and attendance modules plus standard hr and hr_holidays. It is not a standalone leave app and will not install without that engine stack.
- Accrual, carryover and expiry ship with one standard policy each, for example 1.75 days per month capped at 30, carryover capped at 5 days, and expiry 12 months from grant. Policies are data-driven and editable, but the module is not a library of pre-built jurisdiction rule packs.
- The public holiday calendar models Australian state and territory regions out of the box. Holidays for other countries can be entered manually, but no other regional scheme is predefined.
- The approval chain is a serial manager-then-officer flow with per-type override. It is the configured ladder rather than an arbitrary parallel or quorum approval designer.
- Hourly leave is supported only for leave types whose hourly flag is set, and half-day leave applies only to a single-day request on a type that allows it.
- Projection writes into native Time Off so the standard calendar and reports stay accurate; the platform request, not the core hr.leave row, remains the source of record.
Odoo 18 leave management, Odoo 18 Community time off, leave accrual Odoo, leave balance ledger, leave approval workflow, annual leave Odoo, sick leave tracking, carryover and expiry, half-day leave, hourly leave, public holiday calendar Odoo, multi-company leave, leave allocation, HR leave Odoo 18, employee self-service leave
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