Odoo Record Rules

Record Rules are an important part of security in Odoo.  They control which records users can access.  For example, sales users can only access their own quotations and sales orders (see below).

Quick Guide

  1. Users are members of user access groups (e.g. Peter Lee might be a Purchase Manager and an Inventory User).
  2. Each of those access groups may “inherit” access from a related group, for example
    • Purchase Manager inherits the Purchase User rights
    • Purchase User inherits the Internal User rights
  3. Access groups control access to:
    1. Database Models (e.g. Products, Sales Orders)
    2. Database Rows / Records (through Record Rules) – the subject of this article.
    3. Fields (not normally used) 
    4. Views
    5. Menus
    6. Windows Actions 
    7. Other elements (Buttons, Filters, Wizards)

Record Rules might make it easier to develop functionality in Odoo (because the rules have already been set up, and so you don’t have to worry about access). Or they might cause problems if there are multiple requirements related to one Model (database table).

  • So it is possible that installing another app or module (or just enabling another feature, such as Private Addresses) can have unexpected results.

Record Rules

Record Rules use domain to specify which records can be selected for read, write, create and delete, as explained below.

  1. They are optional and if there are no Record Rules for a Model, there are no record-level restrictions.
  2. The Administrator account is not subject to Record Rules. 
  3. I believe that In Odoo 12 the Administrator account was a member of all Access Groups and was subject to Record Rules (but could temporarily become a “Superuser” and bypass access rules).  I’m not sure when that stopped being the case.

As with other types of Odoo access rules, a user could have Read access from one user access group and Write access from another group (see Permissions below).

There are two types of Record Rule:

  1. Global rules (with no access group specified).
    • These restrict access, and cannot be bypassed by other Record Rules.
    • They are generally used for multi-company restrictions.
    • They are quite easy to understand!
  2. Group-specific rules (for one or more access groups – e.g. Purchase Manager)
    • These grant permission (subject to the restrictions imposed by the Global Rules).
    • If there are multiple Group-specific rules then access is granted if ANY of the conditions are satisfied.
      • This can make Group-specific rules more difficult to understand, and care needs to be taken when using them.

Example of a group-specific Record Rule

The access group “Sales / User: Own Documents Only” has a Record Rule on Sales Orders (and Quotations) with this domain:

['|',
   ('user_id','=',user.id),
   ('user_id','=',False)
] 

This will only allow access to:

  • the user’s own orders / quotations (where salesman = current user)
  • orders with no salesman (user_id) specified).

Alongside this, the group “Sales / User: All Documents” has a Record Rule with this domain:

 [(1,'=',1)] 

This will grant access to ALL Sales Orders / Quotations.

Note: there are identical Record Rules for Leads (the field names are the same).

Group Record Rules are almost always in sets of two, one to restrict access, one to grant full access (a set of three or more rules is also possible).

Permissions

Record Rules grant permission for one or all of the following actions:

  1. Read
  2. Write (update)
  3. Create
  4. Delete

Note that Read access is required in order to have any access!

There are several possible types of access, including:

  • Read-Only
  • Read and Write (but not create and delete)
  • Read, Write and Create but not delete
  • Full access

This can be done either through Model access or Record Rules, and there is an important difference between the two:

  1. If Read Access is not specified for a Model and user group, the user(s) will not have Read Access to that Model*
  2. If Read Access is not specified for a Record Rule (for a user group), the domain in that Rule will not apply, and so will not restrict user access*.
    • However, if there are other Record Rules for Read access they would apply.

* Note that in both the above examples, users may be members of other user groups that will either grant or restrict access.

Using Sales Order and Quotations (sale.order) as an example:

  • As standard, only the Sales Manager can delete Sales Orders (this is from the Model Access)
  • As explained above, some sales users can only access their own orders (through Record Rules)
  • You could add record rules so that:
    1. Only supervisors or managers can cancel confirmed Sales Orders
    2. All sales users can cancel Quotations (draft Sales Orders)
      • A cancelled Sales Order is still in the Odoo database, and a manager would be able to delete it.

Challenges

It’s easy to have problems with Record Rules because of the way they interact with each other. These can be in either direction:

  • access is allowed when it should not be,
  • users are not allowed do something they should be able to do

Here’s one example:

Private addresses

Odoo 12 introduced a Record Rule that was designed to limit access to “private addresses”. It’s on the Contacts model (res.partner). It’s been removed in Odoo 17.

Just like the above example, there are a pair of Record Rules:

1.  Allow access to “private addresses” for selected users

[('type', '=', 'private')]

2. Allow access for all users to other “non-private addresses”

['|', 
('type', '!=', 'private'),
('type', '=', False)
]

This Record Rule grants access to all internal users through the “Internal User” access group (“Employee” in earlier versions). This group is inherited by all application access groups.

The problem is that the second Record Rule would effectively override other Record Rules for Contacts.

  • For example, you might have used Record Rules to limit access to vendors (suppliers), but:
    • a user who had not had access to vendors would now be granted access (because type will be blank).
      • They would also be able to access private addresses for customers and other types of contact!

That’s because access is granted if the conditions for ANY of the Group-specific rules are satisfied – and these can come from multiple access groups.

The solution is either to remove the two “private address” rules or to replace them with several rules that cover all the combinations.

Alternatives

It is also possible to restrict access without using Record Rules.

  • Domains can be added to restrict access to fields in views
  • Changes can be made to menus:
    • Limit access to menus
    • Create different menus with specific domains (example)
  • Other options are available by doing development or installing add-ons.

The disadvantage of these methods is that the restrictions may need to be applied in multiple places (which, of course, is what makes it more flexible). But it is easy to miss one or more views or menus and then the user has access they should not have!

List of Record Rules for a user (Odoo 13)

Navigate to Settings / Users & Companies / Users

These “smart buttons” can be useful for troubleshooting, and you can use Filters to show information for one or more Models:

This shows us that the user has full access to their own sales order lines (from the “Sales / User: Own Documents Only” group) plus Read-Only access to Sales Order lines for projects (as the “Project Administrator”).

This is the domain for the second Record Rule:

['&', '&',
     ('state', 'in', ['sale', 'done']),
     ('is_service', '=', True),
    '|', ('project_id','!=', False), ('task_id','!=', False)]

This selects Sales Order Lines that are:

  • confirmed or locked, and
  • service items and
  • with either a project or task id

This will be used when billing from timesheets, so it logical that this access is available for a Project Administrator.

Note: there should be no conflict between these two Record Rules (a combination can sometimes produce undesirable results, as explained above).

36 thoughts on “Odoo Record Rules

  1. Hi there,

    I want to setup record rule for sales men to only see his customers in contact model which identified in sales person field.

    but the sales manager can see all customers in contact model.

    I tried to change the record rule for res.partner but end up with huge bug as no one can sign in any more but this is not my problem because I tried it in the test database.

    please need your help.

    Liked by 2 people

    1. Remember that contact (res.partner) includes customers, suppliers and users. Limiting access could certainly cause problems.

      Like

    2. Hi Ahmer here you go… this works for Odoo 14 Enterprise and Odoo 15 Enterprise. I suspect it works for community but I’ve never tested it.

      Salesperson own contacts

      [‘|’, ‘|’, (‘create_uid’, ‘=’, user.partner_id.id), (‘user_id’, ‘=’, user.partner_id.id), (‘user_id’, ‘=’, user.id)]

      Liked by 2 people

      1. Hi Steven,

        I was looking for a similar rule. I tried the rule by assigning it to the group_sale_saleman group (See Own Documents) and created a test user in v15 Enterprise. However I can still see all contacts where the test user doesn’t meet the conditions. Any ideas?

        Like

      2. Yes, it’s most likely the private address rule. I went another route entirely since I ran into random issues with this rule I posted her a while ago.

        I’ll look for it and post the new one today.

        Like

      3. I don’t use that code I posted before because it started to become burdensome to manage when multiple contractors needed access to the same records.

        I threw together a module so you can see what I use now. Basically a tag on contacts that corresponds to res.users and provides access to each record. I only have it setup in contacts right now but it could be expanded on. It’s a lot easier for me to manage contacts this way.

        Let me know if you have any questions and I will try to help you out.
        https://github.com/netfxtech/misc_odoo_addons/tree/master/access_res_partner_contractor

        Like

  2. yeah that what I figured out.
    I tried to make filter in window actions but it doesn’t work.
    [(‘user_id’, ‘=’, user.id) ]
    please I need help.

    Liked by 1 person

    1. The same way that we use Record Rules for any other Model? If you have a specific question about it, maybe someone will offer some advice (not me, as I am quite busy!).

      Like

  3. How I can limit users to see only sales order made by sale team members? I have team which ID = 6 and I have tried like below but not succeed
    [(‘team_id’, ‘=’, 6)]

    Like

  4. i created those record rule to edit Purchase order at RFQ state only

    but it didn’t work
    Purchase Order [(‘state’, ‘in’,[False, ‘RFQ’])]
    Purchase Order Line [(‘order_id.state’, ‘in’,[False, ‘RFQ’])]

    Like

  5. Hi, I want to display PO and Stock Picking based on allowed branch in odoo. So if you log in as user Ana with allowed branch = Singapore, then the PO/Stock Picking that appear are only PO/Stock picking with the Singapore branch. if it’s like that, can it use ir.rule?

    Like

  6. I have Managers that have access to edit attendance. I want to restrict them to only editing attendance for their team and not themselves. There is a user: modify own attendance only record rule but how would I configure that to achieve my goal?

    Like

    1. I would probably look at the security groups in the sale module and replicate it. That would probably be the best way forward if you use sales teams or something equivalent.

      Like

  7. I have two companies, A and B. I would like my employees to have access to view the employee module of both companies, but I only want them to be able to edit or modify the employee module of company A. Is it possible to configure this process?

    Like

  8. Looking to restrict a base level manufacturing group to only internal contacts. I’ve tried several ways but haven’t been able to find the right field. Any suggestions?

    Like

      1. I define that as they work of the company and have a login. When going to setttings > Users & Companies > Users | The Odoo filter is on the model User (res.users) with a doman [(“share”, “=”, False)]

        I would like a similar domain for contacts. Struggling to create a proper domain and/or find an applicable field in contacts.

        Like

    1. I’m not certain this is the best solution but seems to have worked.

      I did have a premission conflict, which in retrospect seems obvious. The internal user group was providing greater access to contacts then I want all users to have. I updated the record rule from:

      [‘|’, (‘type’, ‘!=’, ‘private’), (‘type’, ‘=’, False)]

      to:

      [‘&’, ‘|’, (‘type’, ‘!=’, ‘private’), (‘type’, ‘=’, False), (‘partner_share’, ‘=’, False)]

      I then created a new record rule of:

      [(‘partner_share’, ‘!=’, False)]

      and applied to group ‘Sales / User: Own Documents Only’ I may find I need to apply to additional groups but still testing.

      Like

  9. hello, Happy New Year to all. I need to add record rule for Contact and CRM, user can access his/her record only and a Manager can access all of his/her records + his/her subordinates’ records. please help to create the both record rules as i am a very beginner, exploring Odoo 16 and Odoo 17.

    Like

      1. hi, it works in CRM but failed to get in Contacts… what i am missing here? kindly help.

        Like

      2. I’m trying hard to follow your post but some of it doesn’t make sense.

        You’ll be so much better off learning how domain filters work and tailoring it based off the modules you have installed. Everyone’s filter will be different depending on if they have the employee module installed or/and especially if they have custom development already done.

        You will definitely want to remove the 1, =, 1 rule if you’re creating a global rule. That will give everyone in that group the ability to see everyone’s records, not just their team/subordinates.

        Like

  10. i checked the domain filter thoroughly and found the problems.
    i tried as below for CRM only its but not working as it should be, it is showing all data to Manager / User when removing My Pipeline filter, otherwise it is showing Only Logged-In user data, Manager can’t see his/her subordinats’ data.
    for Administrator added filter (1, ‘=’, 1) so he can see All Data when remove My Pipeline filter and its working.

    [‘|’, ‘|’, ‘|’, (1, ‘=’, 1), (‘user_id’, ‘=’, user.id), (‘user_id’, ‘=’, False), (‘user_id.employee_ids.parent_id.user_id’, ‘=’, user.id)]

    above Record Rule is Global. please help.

    Like

    1. I’m trying hard to follow your post but some of it doesn’t make sense.

      You’ll be so much better off learning how domain filters work and tailoring it based off the modules you have installed. Everyone’s filter will be different depending on if they have the employee module installed or/and especially if they have custom development already done.

      You will definitely want to remove the 1, =, 1 rule if you’re creating a global rule. That will give everyone in that group the ability to see everyone’s records, not just their team/subordinates.

      Like

    2. That filter will show everything!

      As a reminder, I’m not going to spend a lot of time trying to understand problems, What I can do is provide some tips on how to use odoo.

      Like

    3. We’ve all been where you’re at right now at some point in our odoo learning path. I almost swore to never use odoo again but I finally buckled down and watched some YouTube videos.

      What you basically need to do is worry about the salesperson/most restricted person first.

      Get their record rules performing correctly (you can probably copy something extremely close to the sales: own documents group since you’re replicating this functionality in contacts – it won’t be exactly the same, but it’ll be close)

      After that you’ll make a manager group and use record rules that have already been suggested. Do not use the 1, =, 1 in your domain unless you’re ready to drive yourself mad. That is reserved for the highest level people in the organization.

      You need to learn the basics, GPT, Chris (site owner) can help in some ways but there’s no shortcut to learning the basics.

      Liked by 1 person

Leave a reply to Salem Ahmed Cancel reply