EH HR Disciplinary
Progressive discipline with acknowledgement and a hash-chained audit trail.
Why this module
EH HR Disciplinary
The ladder picks the next step
Each warning has a validity window. The record counts how many of the employee's other warnings are still active on the issue date and recommends the next rung up the ladder: verbal, then written, then final. One click applies it to the action type.
An audit trail you can verify
State, employee, action type, severity and reason changes land in an append-only, sha256 hash-chained log with before and after snapshots. A verify_chain check walks the chain and reports the first tampered row, independent of the chatter.
Issued by one party, acknowledged by another
Managers issue and close; the employee acknowledges. Transitions are gated by HR group, the acknowledgement text is recorded on the case, and final states refuse any further movement so a closed or cancelled record stays closed.
Day in the life
A repeat lateness case, end to end
A manager opens a new disciplinary record for an employee. The form already shows two prior warnings still inside their validity window, so the recommendation reads final; the manager reviews and applies it. They issue the warning, which moves the case to issued and stamps the audit log. The employee opens the record and enters their acknowledgement, advancing it to acknowledged. Weeks later the manager closes the case. Each step is a gated transition, each writes a hash-chained audit row, and the warning will drop out of future escalation counts automatically once its validity window lapses.
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 warning counts toward escalation only while expiry_date (issue date plus validity months, default 12) is on or after the issue date being evaluated and the case is not cancelled. Old warnings drop out of the count on their own with no cron or manual reset.
The prior-active count excludes the current record by id, so a warning never counts itself when computing its own escalation recommendation. Unsaved records (no integer id yet) simply skip that exclusion clause.
Closed and cancelled are marked is_final in the workflow definition. The engine refuses any transition out of a final state, even one a misconfigured definition might declare, so a closed case cannot be quietly reopened.
The hash chain is inherently serial. Appends take a transaction-scoped Postgres advisory lock so two concurrent writes cannot read the same tail and fork the chain; the lock releases at commit.
company_id is required and defaults to the active company. A write that moves a record into another company is rejected, even under sudo, unless an explicit audited override context is set, and the elevation is itself logged.
The reference is drawn from the DISC/year sequence only when the name is still New, so duplicating or re-saving a record never burns a second number or overwrites an existing reference.
What is inside
Built to do the job, end to end.
- Four action types, three severities. Verbal warning, written warning, suspension and final warning, each tagged low, medium or high severity. Action type and severity are tracked fields, so changes show in the chatter and the audit log.
- Configurable workflow, no code. States and transitions come from a workflow definition record (draft, issued, acknowledged, closed, cancelled). The state field and its statusbar are derived from that definition, so steps and ordering can be adjusted without touching Python.
- Validity and escalation fields. validity_months, a stored expiry_date, an is_active flag, prior_active_count and recommended_action are all on the form, plus an Apply Recommended button that copies the recommendation onto the action type.
- Platform audit and acknowledgement. The case captures issuer, date, reason and the employee acknowledgement text. State, employee, action type, severity and reason are the audited fields written to the hash-chained log on every change.
- Group-gated access. Three access rows: HR admin (full), HR manager (create and edit, no delete) and employee self (read and acknowledge). Issue, close and cancel are manager transitions; acknowledge is the employee transition.
- Tested behaviour. The shipped test suite covers default numbering and initial state, the full issue to acknowledge to close path, cancel from draft, the validity and is_active computation, and the escalation recommendation across three stacked warnings.
Honest about the edges
What this does not do, so nothing surprises you.
- The escalation ladder runs verbal, then written, then final. Suspension is a selectable action type but is not a rung the recommendation suggests.
- Recommendations are advisory. The module suggests the next step and offers a one-click apply; it never auto-issues or auto-escalates a warning.
- This module declares no approval-gated transitions. Issue, acknowledge, close and cancel are group-gated but do not open an approval chain.
- There is no built-in employee portal or email step. The acknowledgement is recorded by entering text on the case and firing the acknowledge transition.
- Validity is counted in whole months from the issue date. There is no part-month or day-level proration of a warning's active window.
- Requires the EH HR Platform engine modules (eh_hr_core, eh_hr_compat, eh_hr_engine_workflow). It is a consumer of the shared workflow and audit services, not a standalone app.
Odoo 16 disciplinary action, employee disciplinary management Odoo, progressive discipline HR, written warning tracking, final warning Odoo, HR disciplinary workflow, employee acknowledgement, tamper evident audit trail HR, corrective action log, warning expiry escalation, multi company HR Odoo, 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