EH HR Document
Employee document register with live expiry status and a daily reminder, audited and company scoped.
Why this module
EH HR Document
Always current, never stored stale
Status and days to expiry are computed against today's date each time you open the record, so a document that lapses overnight reads as expired the next morning without any recompute job to wait on.
Every change on a verifiable chain
Create, write and delete are written to an append only, hash chained audit log with advisory lock serialized appends. Run verify_chain to prove on demand that no document record was edited after the fact.
Records locked to their company
Each document carries a required company_id defaulting to the active company, and cross company writes are refused even under sudo unless an explicit, audited override is set. No null company leakage between firms.
Day in the life
A reminder that fires before the visa lapses
An HR officer logs a worker's new visa with its expiry date. Months later, thirty days out, the daily cron posts a note in the document's chatter so the team renews it in time. The list view paints the row amber as it enters the window and red once it passes, and every edit along the way is on the audit chain.
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.
A document with no expiry date is treated as never expiring: status reads 'No expiry', days to expiry is zero, and the reminder cron skips it rather than firing on a null date.
Status and days to expiry are non stored computes evaluated from context_today, so a record valid today becomes expiring or expired purely as the clock advances, with no nightly recompute and no risk of a stale stored value.
Audit rows are appended under a transaction scoped Postgres advisory lock, so concurrent edits cannot fork the chain. Each row hashes the previous row's hash, and verify_chain walks the chain to flag the first broken link.
Reassigning a document to a company the user is not a member of is rejected with an AccessError, even through sudo, unless the allow_cross_company context key is set, in which case the elevation is itself written to the audit log with every affected record id.
A write that does not actually change any audited field produces no audit row: before and after snapshots are compared per record, so no-op saves do not pad the trail.
Documents are linked to the employee with ondelete cascade, so removing an employee removes their documents cleanly, and each removal is captured as an unlink event in the audit log first.
What is inside
Built to do the job, end to end.
- One model, eh.hr.document. Title, employee, document type (passport, visa or permit, licence, contract, certificate, other), official number, issue date and expiry date, plus computed days to expiry and status. Ordered by expiry date so the most urgent rows sit at the top.
- Daily expiry reminder cron. An ir.cron runs once a day, finds every document expiring within the next 30 days, and posts a dated note to each document's chatter. It returns the count it touched so the run is observable.
- List and form with status colouring. A list view that decorates expiring rows amber and expired rows red, and a form with the document details, live status and a chatter thread for the reminders and history.
- Three access tiers. HR admins get full read, write, create and delete; HR officers can read, write and create; self service employees get read only. The Documents menu is officer gated.
- Platform audit and company mixins. Inherits the shared audited and strict company aware mixins from eh_hr_core, so audit logging and multi company safety are identical to the rest of the HR Platform with no per module reimplementation.
Honest about the edges
What this does not do, so nothing surprises you.
- This module stores document metadata: titles, types, numbers and dates. It does not attach or store the actual file or scan; pair it with Odoo's standard attachments on the chatter if you need the file itself.
- The expiring window is fixed at 30 days in code and is not a per record or per company setting in this version.
- The reminder is a chatter note posted by the daily cron. There is no email, SMS or escalation ladder and no approval workflow on documents.
- Status and the document type list are not jurisdiction specific; there is no built in compliance rule set for any particular country.
- It depends on eh_hr_core and eh_hr_compat, so it runs as part of the EH HR Platform rather than fully standalone.
Odoo employee document expiry tracking, HR document register Odoo, passport visa licence expiry reminder, certificate validity tracking, document expiry cron Odoo, employee document management Community, multi company HR documents, audited employee records Odoo, Odoo 16 17 18 19 Community HR, ERP Heritage HR Platform
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