What Are Your Staff's Default Permissions in Odoo?
Product cost and contacts are visible to all internal users by default. That range follows from how master data is referenced, and narrowing it means choosing the right layer — this guide covers what the defaults are, where they come from, how to check your own system, and what each of the three approaches costs.
Once a system is live and the user accounts exist, the range of data each employee can see is determined by Odoo’s defaults.
This guide sets out several of those defaults, where they come from, and the layer constraints encountered when narrowing them.
The behaviour described here was verified on Odoo 19. Permission defaults can change between versions; where your own results differ from this guide, check the version first.
1. The Default Range
The following is the state with no additional configuration applied:
- Cost data — product cost and the corresponding inventory valuation are visible to all internal users. The cost field does carry a field-level permission group, but its default value is “all internal employees”, which in practice imposes no restriction.
- Contacts — readable by all internal users. Once CRM is enabled, sales users have edit rights on all contacts.
Cost has more than one exit. The field display on the product form, grouped aggregation in list views, and search filters are all different ways of reading the same value.
Portal users are not internal users and fall outside this range.
2. Where That Range Comes From
Odoo’s read permissions operate at three layers:
- Model level — whether the model can be read at all.
- Record level — which records within that model can be read.
- Field level — which fields within a record can be read.
Document calculations and validations run on the server, under the identity of the current user. That produces a chain:
A document references master data → referencing means reading → to complete the operation, the user must hold read access to that master data.
The visible range is therefore not drawn around who needs to know. It is pushed open by what operations require. A warehouse user must be able to read the customer record to complete a delivery; an accountant must be able to read it to issue an invoice. Neither role needs the customer’s contact details, but at the permission layer that cannot be separated from being able to read the record.
Which gives the constraint this guide turns on: the difficulty is not whether something can be closed, but whether documents can still be issued once it is.
3. The Same Cause at Another Layer: Group Bundling
Beyond record reading, the visible range also widens through the granularity of permission groups. Landed cost is a complete example:
- Landed cost sits under the Inventory module, and its access rights belong to the Inventory Manager group.
- When entering a vendor bill, an accountant needs to mark whether a product line counts as a landed cost.
- The rights required to perform that marking are attached to the Inventory Manager group.
- To let the accountant complete that step, the accountant must be granted Inventory Manager.
- Once granted, everything else that group covers opens up with it.
A single operational action is bundled with an entire feature group, and obtaining the action means accepting the group’s whole visible range. This is the same cause as section 2, expressed at a different layer.
4. First Approach: Record Rules
The first way to narrow the range is a record rule — for example, restricting sales users to the contacts they are responsible for.
What that produces in practice:
- It works functionally. The list ends up showing only that user’s contacts.
- The list throws a permission error while loading. Use is unaffected once loading completes, but the error during it cannot be eliminated.
The conflict is more direct in other roles:
Accounting and warehouse users must hold read access to all contact records in order to invoice and ship. Tighten a record rule to “only what I am responsible for” and those two roles can no longer issue documents; leave it open and what they can read is every contact in the company.
Record-level narrowing and document operability are in direct conflict, with no state in between.
5. Second Approach: Field-Level Restriction
Since records have to remain readable, the boundary can only fall back to the field layer.
Field-level restriction operates at the data-reading layer rather than the display layer. One setting therefore closes four exits at once:
- Reading the field value directly
- Grouping, averaging or summing by that field in a list view
- Probing the value through search filters, narrowing the range step by step
- Field selection in data export
A user outside the permission group who triggers any of these receives a permission error, not an empty value.
The constraint on this approach is computational dependency.
Any module that needs to pull in or calculate cost while a document is being created runs that calculation under the current user’s identity as well. Once the cost field’s permission group is narrowed, a user without that permission performing those operations is interrupted. Sales orders, manufacturing orders and other document modules that reference master data cost all fall into this category.
What is not affected is worth confirming too: inventory valuation and accounting entries are calculated under the system identity, so narrowing the field’s permission group does not change valuation on deliveries or invoices.
6. The Rule That Follows
Taking sections 4 and 5 together produces a reusable test:
Whether a field can be closed at the data layer depends on whether any document needs to read it automatically at creation time.
- It does — closing it at the data layer interrupts normal operations, so the only remaining option is hiding it at the display layer. Cost is in this category.
- It does not — it can be closed at the data layer. Contact phone and email are in this category.
Contacts therefore end up handled in layers:
- The record layer is left alone — preserving the ability of accounting and warehouse users to issue documents.
- List views are narrowed — reducing bulk browsing unrelated to the role.
- Phone and email carry field-level restrictions — neither participates in document calculations, so both can be closed at the data layer.
Email warrants the same treatment as phone because it is also the external party’s portal registration identifier, not only a means of contact.
The conclusion is not that one layer is better. It is that each field’s narrowing layer is determined by how it is referenced, which has to be established field by field and cannot be handled uniformly.
7. The Limits of Display-Layer Hiding
Display-layer hiding operates on the definition of one particular view, removing the field from that view’s structure.
Custom filters and custom grouping in the search panel do not read view definitions. They read the model’s field list, which comes from the model itself and is unrelated to which views a field appears on.
So once a field is removed from the form and the list, it still appears among the options for custom filters and custom grouping. Applying a greater-than or less-than condition to cost and observing which records drop out narrows in on the value without it ever being displayed.
That is the fundamental difference between the two approaches: field-level restriction removes the field from the model’s field list and closes all four exits at once; display-layer hiding changes what one view shows.
Of the four exits listed in section 5:
- Data export — export rights form part of master data permission configuration and are not usually granted alongside an ordinary role, so this exit is generally already closed by a separate control.
- Grouped aggregation and search filters — require no additional rights. Any user who can open the list can use them.
Two requirements therefore need to be assessed separately:
- Reducing what unrelated roles see day to day — display-layer hiding is effective.
- Making data unreadable within the system — requires field-level restriction, which is bound by the rule in section 6.
For data like cost, which is constrained by computational dependency yet still needs its range controlled, the workable approach combines display-layer narrowing with operational audit rather than relying on a single switch.
8. Checking Your Own System
The following can be carried out directly, without developer access:
- Log in as an ordinary internal user holding only sales rights.
- Open any product and check whether the cost field appears on the purchase or inventory tab.
- Return to the product list view and try grouping by cost, or adding a custom filter on cost in the search panel.
- Open the Contacts app and check whether the visible record count equals the company’s total.
- Switch to a user holding only accounting rights and repeat step 4.
- Check whether the accounting user holds Inventory Manager, and whether it was granted in order to handle landed costs.
The results of steps 4 and 5 correspond directly to the mechanism described in section 2: the readable range is determined by what document operations require, independently of whether the role needs to know.
9. How SuiteState Approaches It
The material in this guide comes from SuiteState’s own wholesale operation on Odoo. The sequence was: narrow contacts with a record rule, meet the loading error and the inability of accounting and warehouse roles to issue documents; switch to a field-level restriction on cost, meet the interruption in document calculation. Those two results determined the final implementation, which is the rule in section 6.
Four modules came out of that work, each corresponding to a section above:
- Cost Guard — display-layer narrowing of the cost field. Cost is bound by computational dependency and cannot be closed at the data layer (section 5), so this module reduces what unrelated roles see day to day and is not offered as a guarantee that the data is unreadable.
- Contact Guard — layered narrowing of contacts: the record layer left intact to preserve document operability, list views narrowed, phone and email restricted at the field level (section 6).
- Landed Cost Access — separates the landed cost marking right out of the Inventory Manager group, so accounting can complete the marking on a bill without accepting that group’s entire visible range (section 3).
- Inventory Access — scoping of access to inventory data.
These modules divide up the visible range. They do not change Odoo’s permission mechanism. The constraint in section 5 holds for any implementation: cost cannot be closed at the data layer, and that follows from the reference structure rather than from configuration.
The defaults are the starting point the system provides. Whether they match the information boundaries your organisation actually operates with is something to confirm field by field.