Enable Dark Mode!
how-to-restrict-records-by-company-using-iraccess-in-odoo20.jpg
By: Sayyid Jahfar

How to Restrict Records by Company Using ir.access in Odoo 20

Functional Odoo 19 Odoo Enterprises Odoo Community

When the topic comes to Odoo 20, the traditional way of using record rules (ir.rule) and access rights (ir.model.access) for security is completely changed. In Odoo 20 a single ir.access model handles both the record rules and access rights. 

Implementing multi_company data security in Odoo 20 requires a new approach, a unified ir.access.csv file. Here is how to build a multi-company record rule in Odoo 20. Let's get started.

1. Model Setup:

In order to apply the multi_company rule, the model must be configured to handle company data.

  • Set the model parameter _check_company_auto = True. This will trigger the _check_company method on write and create operations to ensure company consistency on the relational fields having check_company=True.
  • Define a company_id field with a default value of lambda self: self.env.company. This will make the record’s company ownership upon creation of the record.
company_id = fields.Many2one(
        comodel_name='res.company',
        string='Company',
        default=lambda self: self.env.company,
)
  • Add check_company=True to any relational fields (e.g., a Many2one pointing to res.partner). This ensures that only data related to the same company is linked, and if not, Odoo raises an error. This prevents attaching a Company A contact to a Company B document.
partner_id = fields.Many2one(
   comodel_name='res.partner',
   string='Partner',
   check_company=True,
)

2. Permission and Restriction in ir.access.csv

Instead of writing complex XML records for ir.rule, Odoo 20 handles restrictions (record rules) directly in the CSV along with access rights.

Creating a row in the security/ir.access.csv file with the group column (group_id/id) blank and the value in the domain column will create a global restriction for every user. Leaving the group column blank means this rule or restriction is applicable to every group. So the records will be filtered based on the domain in the domain for all users.

Creating a row with a value in the group column will create permission for the specified group. By giving value in the group column, Odoo 20 reads it as an access right and gives access to the group specified in the group column.

Creating a row with a value in the group column and the domain column will create a permission with a restriction. That is, the group specified in the group column will have access to the records, but the records will be filtered based on the domain in the domain column.

The value in the options column determines what operations the user can perform. Set the options as  crud to give full permission to all operations. To give permission for a single operation, set the value of the options column as c or r or u or d for create, read, update, or delete respectively. When setting a value to the options column, the order of letters must be followed.

idnamemodel_idgroup_id/idoperationdomain
permissiontest.modeltest.modelbase.group_usercrud
multi-companyrestrictionmulti-company test.modeltest.model
crud['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]

3. How the Context Powers company_ids

The company_ids variable in the restriction evaluates dynamically based on the current user's active session. When a user toggles their active companies using the checkboxes in the Odoo systray on the top left corner, the UI injects the allowed_company_ids key into the session context. The Odoo ORM immediately reads this context and populates env.companies with the selected company records. Your CSV domain dynamically compares the record's company_id against this active environment to filter visibility on the fly.

4. Common Leaks

Small configuration mistakes can easily expose multi_company data.

  • Quoting Variables: Writing "company_ids" inside quotes within your domain makes Odoo evaluate it as a string rather than a dynamic list of company IDs, leading to immediate access errors when users try to create records.
  • Accidental Group Assignment: Assigning a specific group to your restriction row means users outside that group bypass the rule entirely.
  • Sudo Usage: Using .sudo() in backend Python logic can bypass all restrictions.

Odoo 20 makes its security architecture very easy by combining record rules and access rights under one ir.access model without risking data separation for record rules. By applying control mechanisms like _check_company_auto=True and check_company=True combined with global limitations without using any group, you will make sure that your data is completely safe, even when there are multiple companies present. It is better to apply these mechanisms from the beginning stage of the development process to save yourself from any future security problems.

To read more about How to Migrate ir.model.access.csv and Record Rules to ir.access.csv in Odoo 20, refer to our blog, How to Migrate ir.model.access.csv and Record Rules to ir.access.csv in Odoo 20.


Frequently Asked Questions

How do multi_company restrictions in Odoo 20 differ from Odoo 19?

In Odoo 19, the multi_company rule required defining Record Rules (ir.rule) in XML files separate from Access Rights (ir.model.access). In Odoo 20, these models are merged into a single model named ir.access. Now, we define multi_company domains directly inside your security/ir.access.csv file using a group-less row (leaving the group_id/id column blank) to apply the restriction globally.

How do I allow a record to be shared across all companies?

If you want a record to be visible globally when no specific company is assigned to it, you need to include a False fallback in your CSV domain. Instead of [('company_id', 'in', company_ids)], you would write: ['|', ('company_id', '=', False), ('company_id', 'in', company_ids)]. This ensures that the records with company_id = False are shared across all companies.

What is the difference between check_company=True and _check_company_auto = True?

check_company=True is applied to relational fields like a Many2one field, to set them for multi_company validation. _check_company_auto = True is declared at the model attribute to automatically trigger multi_company validation of those fields that are set for multi_company validation every time a record is created or updated.

Why am I getting an "Access Error" when trying to create a record in my active company?

This usually happens when there is a syntax error in your ir.access.csv domain column. The most common mistake found is putting the company_ids variable inside quotes. Eg :- ("company_id", "in", "company_ids")). If company_ids variable is quoted, Odoo evaluates it as a string instead of fetching a list of the active company IDs, which instantly triggers an access block when you try to create a record.

If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



WhatsApp