| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Lines of code | 105 |
| Technical Name |
eh_hr_compat |
| License | LGPL-3 |
| Website | https://erpheritage.com.au |
| Versions | 16.0 17.0 18.0 19.0 |
EH HR Compatibility
One codebase, four Odoo versions.
Why this module
EH HR Compatibility
Version logic resolved once
Every part of the Odoo API that changed between 16 and 19 is detected once here from odoo.release.version_info and exposed as a constant or helper. Feature modules call the helper and stay version-agnostic, instead of scattering version checks through the codebase.
Nothing to maintain twice
The module defines no models, no singletons, no caches and no global state, and imports nothing from the rest of the platform. It is importable before the Odoo registry is built, so it can be used safely from pre-migrate scripts and module __init__ hooks.
Load-bearing, not decorative
The group, access-level and migration helpers are called across the platform engines, the approval and workflow engines, attendance, leave, payroll and core. This is the seam the rest of the suite runs on, not an unused convenience layer.
Day in the life
The seam you never notice
A developer assigns a security group in a create() call. On Odoo 18 the field is groups_id, on 19 it is group_ids. They call groups_field(env) once and write to whichever key the running version uses, and the same source installs cleanly on both. An administrator opens a user form and sees a single ordered access-level dropdown (employee, manager, officer, admin) instead of loose checkboxes, because setup_access_dropdown wired the group chain through category_id on 16 to 18 and through the new privilege_id on 19. During an upgrade, a pre-migrate script renames a column with safe_field_rename, which only acts when the old column exists and the new one does not, so re-running the upgrade does nothing and never drops data.
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.
res.users groups field is groups_id on 16 to 18 and group_ids on 19. user_groups() reads it and groups_field() returns the correct key name for building create and write vals, so both reads and writes stay portable.
res.groups members field flipped from users to user_ids on 19 (the inverse of the user-side rename). group_users() returns the member recordset under whichever name the running version exposes.
The access-level selector depends on a categorisation that moved: res.groups.category_id on 16 to 18, and a separate res.groups.privilege (privilege_id) on 19 after category_id was removed. setup_access_dropdown() detects which field exists and wires the group chain accordingly.
safe_field_rename() inspects information_schema before acting and renames only when the old column is present and the new one is absent, so a re-run upgrade is a no-op and a partially migrated table is never corrupted.
api_shim imports only odoo.release, with no env, records or models, so it loads before the registry is built and is safe to call from migration scripts and __init__ install hooks.
setup_access_dropdown() looks records up by name and reuses any existing category or privilege rather than duplicating it, so repeated installs and upgrades converge instead of multiplying configuration.
What is inside
Built to do the job, end to end.
- Group and access-level helpers. user_groups(), group_users() and groups_field() resolve the res.users and res.groups field renames between 16 and 19. setup_access_dropdown() renders an implication chain of groups as one ordered, mutually exclusive access-level selector on the user form, portable across the category_id to privilege_id move on 19.
- Migration helper. safe_field_rename(cr, table, old, new) performs an idempotent column rename in pre-migrate scripts, acting only when the old column exists and the new one does not, and returning whether it renamed. It avoids the class of upgrade bug where a blind rename silently drops data.
- Version constants and view shims. ODOO_VERSION and the IS_17_PLUS, IS_18_PLUS, IS_19_PLUS flags are computed once from odoo.release. CONTRACT_MODEL exposes hr.version on 19 and hr.contract earlier. legacy_view_mode() maps list and tree view-mode vocabulary, and owl_import_path() returns the canonical OWL import string, keeping the public surface symmetric.
- No models, no data, no views. The manifest ships no data files and depends only on base. There are no models, wizards, cron jobs or stored records. It is a pure Python helper module that other EH HR modules import.
Honest about the edges
What this does not do, so nothing surprises you.
- This is infrastructure, not a feature. It has no user interface of its own, no menus, no models and no records. Installing it on its own does nothing visible.
- It depends only on base, but its purpose is to support the other EH HR Platform modules. On its own it provides import-time helpers and constants and nothing more.
- The CONTRACT_MODEL constant, the tracking(), legacy_view_mode() and owl_import_path() helpers are part of the stable public surface but are not yet relied on by the shipped feature modules. They exist so future code has one place to resolve those differences.
- Version coverage is Odoo 16, 17, 18 and 19 Community. The module installs natively on 18 and 19; the 16 and 17 view layers across the platform are produced from the same source by a build step.
- It resolves a fixed, known set of API renames. It is not a general-purpose abstraction over every Odoo version difference, and new framework changes are added here as the platform meets them.
odoo hr version compatibility, odoo 19 hr.version rename, groups_id to group_ids odoo 19, odoo cross version module, res.groups privilege_id odoo 19, idempotent column rename odoo migration, odoo 16 17 18 19 community hr, version agnostic odoo addon, eh hr platform, self hosted lgpl-3 hr
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.
Please log in to comment on this module