| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
Discuss (mail)
|
| Lines of code | 2735 |
| Technical Name |
eh_access_studio |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
| Availability |
Odoo Online
Odoo.sh
On Premise
|
| Odoo Apps Dependencies |
Discuss (mail)
|
| Lines of code | 2735 |
| Technical Name |
eh_access_studio |
| License | LGPL-3 |
| Website | https://www.erpheritage.com.au/ |
Heritage Access Studio
User-driven access overlay for Odoo 19.
Hide menus, fields, buttons, tabs, filters and chatter. Per-model record rules with smart placeholders that resolve at evaluation time. One LGPL-3 module on Community. Stock Odoo domain widget, no fork. Documented engineering principles you can verify in the source.
15 capabilities on one profile
19 smart placeholder sentinels
5 ormcaches keyed on (uid, cid, today, model)
30 tests (18 standalone + 12 Odoo)
3 dependencies: base, mail, web
Operations leads, IT teams and compliance officers who need to restrict what their Odoo users can see and do without writing record rules, editing CSVs, or forking views.
The four-screens-per-user dance through groups, ir.rule, menu visibility groups and ir.model.access. One profile screen. One save. Effective on the next page load.
Overview
What this module does, in one read.
Heritage Access Studio replaces the four-screen dance with a single profile model. Bundle a list of users with overlays for menus, fields, buttons, tabs, filters, chatter, model toggles, and per-model record rules. Save once and the configuration applies system-wide.
The architecture is honest. Stock Odoo domain widget, no fork. Five ormcache-decorated lookups keyed on (uid, cid, today, model). Parameterised SQL only. All errors logged with stack trace, fall-back permissive on view render so a misconfigured rule never breaks the UI. Fail-closed on unparseable Domain Access filters.
Audit posture
Every claim on this page is verifiable against the code. Read tools/domain_resolver.py for the placeholder grammar, models/ir_rule.py for the ORM gate, models/eh_access_profile.py for the cache strategy, tests/ for the proof. A senior engineer can audit the whole module in an hour.
Capabilities
15 things this module gives you, with no padding.
Hide menus
Drop menus and submenus from navigation. The Heritage Access Studio configuration menu stays exempt so admins cannot lock themselves out.
Hide / lock / require fields
Mark fields invisible, read-only with force-save, or required, on a per-model basis. Labels follow their fields.
Restrict create / edit / delete
Per-model toggles for create, edit, delete, archive, duplicate, import, export, spreadsheet, add property.
Hide reports and server actions
Per-model lists of toolbar entries to drop. The cog menu shows only what the user is allowed to use.
Hide view types
Stop kanban, calendar, pivot, gantt or any other view type from showing on a model.
Hide buttons, tabs, links
Hide individual smart buttons, notebook tabs and kanban links by their technical name.
Hide filters and group-by
Remove specific search-panel filters or group-by entries. The search bar UX stays clean.
Hide chatter
System-wide, per model, or per individual button (Send Message, Log Note, Activity).
Per-model record rules
Strict ORM-level gates. Read, create, edit, delete with optional filter. AND-ed onto Odoo's stock record rules. Fails closed on parse errors.
Smart placeholders
Use __uid__, __today__, __month_start__ and a dozen more. Resolved at evaluation time.
Time-bound profiles
Set Active From and Active Until. Daily cron deactivates expired profiles, posts a chatter line, bulk-invalidates the cache.
Disable login per profile
Block sign-in at the credential gate. Administrators always exempt. Denials post to the profile chatter for audit.
Quick-start templates
Read-only viewer, sales rep with own records, vendor portal, time-bound auditor. One wizard, three clicks.
Health check & conflict report
Two cog-menu actions. Health check flags orphan, no-op, expired, unparseable rules. Conflict report flags users in two profiles with contradictory domains.
YAML import / export
Round-trip every profile to a portable YAML file. Idempotent re-import. Version-control your access configuration.
Architecture
Three layers of enforcement.
Each layer has a clear scope. Pick the layer that matches the rule's intent. Mixing layers on the same profile is fine and often correct.
UI hide
Hidden menus, fields, buttons, tabs, filters and chatter. Removes UI surface. Does not block the ORM.
Use for clutter reduction and least-confusion UX.
Per-model toggles
Hide create / edit / delete / import / export buttons. Drop reports and server actions from the toolbar. Hide entire view types.
Still UI-only. Server code, the API and other interaction paths are unaffected.
Domain Access
Strict ORM-level gates. AND-ed onto Odoo's standard record rules. Blocks server code, the API, the web client and any other interaction path.
Fails closed on parse errors.
Reference
Smart placeholder grammar.
Nineteen sentinels recognised by the resolver. All resolve at evaluation time against the current user, the current company and today. The resolver lives at tools/domain_resolver.py as plain Python, covered by 18 unit tests that run without Odoo loaded.
User and company sentinels
| Sentinel | Resolves to | Example |
|---|---|---|
| __uid__ | Current user id (int). | [("user_id", "=", "__uid__")] |
| __cid__ | Current company id (int). | [("company_id", "=", "__cid__")] |
| __company_ids__ | List of allowed company ids. | [("company_id", "in", "__company_ids__")] |
Date sentinels (current periods)
| Sentinel | Resolves to (ISO string) |
|---|---|
| __today__ | Today's date. |
| __yesterday__ | Today minus one day. |
| __tomorrow__ | Today plus one day. |
| __week_start__ | Monday of the current ISO week. |
| __week_end__ | Sunday of the current ISO week. |
| __month_start__ | First day of the current calendar month. |
| __month_end__ | Last day of the current calendar month. |
| __quarter_start__ | First day of the current calendar quarter. |
| __quarter_end__ | Last day of the current calendar quarter. |
| __year_start__ | January 1 of the current calendar year. |
| __year_end__ | December 31 of the current calendar year. |
Date sentinels (rolling windows)
| Sentinel | Resolves to (ISO string) |
|---|---|
| __last_7_days__ | Today minus 7 days. |
| __last_30_days__ | Today minus 30 days. |
| __last_90_days__ | Today minus 90 days. |
| __last_365_days__ | Today minus 365 days. |
Quick start
Five minutes from install to enforcement.
Install
Through the Apps menu after purchase, or via the standard -i eh_access_studio CLI flag on a new database.
Open the menu
Top-level Heritage Access Studio appears for users in the group_eh_access_user group.
Pick a template
New from Template, choose a scenario, set users, click Create. A working profile in three clicks.
Test as that user
Sign in as the target user in a private browser window. The profile applies on the next page load.
Iterate
Use Summary for a plain-English readout. Run Health Check before promoting to production.
Integration matrix
How it works alongside core Odoo apps.
Heritage Access Studio is model-agnostic. Any model that ships an ir.model entry can be the target of a profile rule.
| Odoo app | Typical pattern |
|---|---|
| CRM (crm.lead) | Domain rule with [("user_id", "=", "__uid__")] for own-leads-only. |
| Sales (sale.order) | Same own-records pattern, plus restrict_delete and restrict_create on the model toggles for non-managers. |
| Accounting (account.move) | Hide Apps menu, hide_export, restrict_create on internal-only roles. Domain by company_id in multi-company setups. |
| Inventory (stock.picking) | Per-warehouse domain via picking_type_id.warehouse_id.id. |
| HR (hr.employee) | Hide chatter on operational employee records. Restrict edit to managers via per-model toggles. |
| Project (project.task) | Hide kanban link for "View Project". Restrict view types to list-only on contractor profiles. |
| Helpdesk (helpdesk.ticket) | Domain on team membership. Hide internal_note field for vendor tier. |
| Purchase (purchase.order) | Threshold-based hide of approve / cancel buttons. Combine with Odoo's standard purchase approval rules. |
| Manufacturing (mrp.production) | Hide cost-related fields for shop-floor users. Restrict export to ops manager profile. |
| Custom modules | Same patterns. Heritage Access Studio sees any model with an ir.model entry. No list to maintain. |
Performance and safety
Concrete numbers. Specific gates.
What "we hold ourselves to a high standard" actually looks like when a senior engineer audits the source.
Performance posture
Five ormcache-decorated methods keyed on (uid, cid, today, model). Cold lookup runs one indexed search; warm lookup is a dict read.
Cache invalidation: registry.clear_cache() (default category) plus signal_changes() for cross-worker. Categories outside default stay warm.
Cron deactivation: skip per-row invalidation, fire one signal at end of batch. A thousand-row cleanup costs one signal, not a thousand.
Safety posture
Fail-closed on Domain Access parse errors. Returns [("id", "=", False)] instead of granting access.
Admin users in base.group_system or base.group_erp_manager rejected from read-only profiles at constraint level.
Heritage Access Studio configuration menu hardcoded exempt. Login denials post to the profile chatter for audit. Per-record savepoints in cron loops.
Scope
What this is. What this is not.
In scope
- Per-profile UI hide for menus, fields, buttons, tabs, filters, group-by, chatter.
- Per-profile per-model CRUD, IO, view-type, report and server-action toggles.
- Per-profile per-model record rules with smart placeholders.
- Time-bound activation with daily auto-deactivation cron.
- Disable login per profile, with audit log.
- Disable developer mode per profile.
- Quick-start templates and YAML import / export.
- Conflict and health diagnostics.
Out of scope
- Multi-factor authentication. Use Odoo's
auth_totp. - Single sign-on. Use
auth_oauth,auth_saml, or your IdP. - Password policy enforcement.
- Session management and concurrent-login limits.
- Replacement of Odoo groups. We sit on top of standard groups.
- API key per-endpoint scoping.
- Field-level encryption.
- Visual rule builder (text-based domain editor today).
FAQ
Everything we get asked.
If your question is not here, write to info@erpheritage.com.au. We respond within one business day.
How is this different from Odoo's standard groups and record rules?
Odoo groups and record rules are powerful but fragmented across many forms and CSV files. Heritage Access Studio is one configuration screen for everything an admin typically wants to do: hide menus and fields, restrict CRUD per model, enforce per-model record rules with smart placeholders, set time-bound profiles. Standard Odoo groups remain the source of truth for module access. Heritage Access Studio sits on top.
Does it require Odoo Enterprise?
No. Heritage Access Studio runs on Odoo 19 Community Edition. It depends only on base, mail and web.
Does hiding a field block the API?
UI hide is UI hide. A hidden field is not rendered in views, but its value remains readable through the API and from server code. When you need a strict gate, use Domain Access. That layer enforces at the ORM level and blocks every code path including the API.
What happens when an administrator is placed in a read-only profile?
The system refuses the save at constraint level. Members of base.group_system or base.group_erp_manager cannot be added to a read-only profile. The Heritage Access Studio configuration menu is also exempt from any profile restriction so administrators can never lock themselves out of the configuration screens.
How does caching work?
Per-user active-profile resolution is cached on (uid, cid, today_iso). The cache is cleared automatically on profile create, write or unlink. Two users sharing a profile share the cache. View arch caching uses the profile set as part of the cache key, so the standard Odoo view cache continues to work as designed.
Can I add my own smart placeholders?
Yes. Custom sentinels can be added by extending tools/domain_resolver.py. The resolver is plain Python and unit-tested. Eighteen tests cover every shipped sentinel and run without Odoo loaded.
Can a profile expire automatically?
Yes. Set Active Until on a profile. A daily scheduled action deactivates expired profiles in bulk, with a per-record savepoint so a single bad row never blocks the batch. The cron also bulk-invalidates the cache once at the end of the run, not per row.
How does it interact with Odoo's standard ir.rule?
Heritage Access Studio extends ir.rule._compute_domain directly. Our domain is AND-ed onto whatever standard ir.rule returns. Multiple rules on the same model are OR-combined per the standard Odoo semantic.
What about multi-company?
Profiles have an apply_to_all_companies flag and a company_ids many2many. The active-profile resolver keys on the user's current company. __cid__ resolves to the current company at evaluation time.
Performance impact on large databases?
The hot-path lookup is one ormcache hit. Cold lookups run one indexed search on a small number of rows. For users with no active profile the overhead is a single dict read returning empty. We run cleanly on databases with thousands of users.
What happens during the upgrade path?
Standard Odoo module upgrade. Run -u eh_access_studio. The schema is stable across patch releases. Existing profiles are preserved. The cache is invalidated at registry load.
How do I version-control my access configuration?
Configuration, Import / Export, click Export with the profiles selected, save the YAML payload to your git repo. Re-import is idempotent. Existing profiles with the same name are upserted. Diff the YAML quarter over quarter for a quarterly access review.
Does it work on Odoo.sh?
Yes. The module follows Odoo.sh conventions: Community-only dependencies, no external Python packages beyond Odoo's standard stack, no shell calls, no filesystem assumptions. Push to your branch and Odoo.sh installs and upgrades through its standard pipeline.
Backup and restore behaviour?
Standard Odoo database dump captures all profile data. Restore the dump and the profiles come back. The active-profile cache is rebuilt on first use after restore.
Can it audit who changed which rule?
Yes. The profile model inherits mail.thread with twelve tracked fields. Every change to name, active, readonly, the global toggles and time-bound dates is logged with timestamp and editor. Login denials are also posted to the chatter.
What is the support policy?
Three months of free support for any defect found in the documented features. After that, a paid extension is available. Contact info@erpheritage.com.au for terms.
Where can I report bugs or request features?
By email at info@erpheritage.com.au. We respond within one business day for support tickets and triage every feature request.
Licensing
Commercial module. LGPL-3 source.
Heritage Access Studio is a paid module distributed via the Odoo Apps Store. Purchase grants a per-database licence at the price shown on the Apps Store listing.
What you get
- Per-database licence covering your production deployment.
- Three months of free support for any defect found in the documented features.
- Free upgrades within the same major Odoo version.
- Source code under LGPL-3.0 or later. You can read, audit, fork and extend.
Add-ons
- Extended support contract beyond the included three months.
- Custom rule design and migration assistance.
- Training for the operations team.
- Bespoke extensions on top of the public extension points.
For procurement and add-on quotes, write to info@erpheritage.com.au.
Please log in to comment on this module