Search code examples
xmlsecurityodoo-8odoorules

How to understand the rules' behaviours in Odoo?


I'm, as always, stuck with rules, since I'm not able to understand them yet.

This is what we're said:

Interaction between rules

Global rules (non group-specific) are restrictions, and cannot be bypassed. Group-local rules grant additional permissions, but are constrained within the bounds of global ones. The first group rules restrict further than global rules, but any additional group rule will add more permissions.

Detailed algorithm:

  1. Global rules are combined together with a logical AND operator, and with the result of the following steps
  2. Group-specific rules are combined together with a logical OR operator
  3. If user belongs to several groups, the results from step 2 are combined with logical OR operator

Example: GLOBAL_RULE_1 AND GLOBAL_RULE_2 AND ((GROUP_A_RULE_1 OR GROUP_A_RULE_2) OR (GROUP_B_RULE_1 OR GROUP_B_RULE_2))

But I always have problems with rules, that above text isn't true for me (unless I'm misunderstanding anything).

And now I have this simple situation: I have a model whose records can be read by any user, but only created, edited and removed by users who belong to the same company as the record belongs to.

So I need a global rule (it's going to apply over all people, not only a group).

<record model="ir.rule" id="my_custom_rule_a">
    <field name="name">My custom rule A</field>
    <field name="model_id" ref="my_module.model_my_model"/>
    <field name="domain_force">[('company_id', '=', user.company_id.id)]</field>
    <field name="perm_read" eval="True"/>
    <field name="perm_write" eval="True"/>
    <field name="perm_create" eval="True"/>
    <field name="perm_unlink" eval="True"/>
</record>

If I only create this rule, users who belong to the same company as the record can read, create, edit and remove it, which is OK, but if the user doesn't belong to the same company as the record, they can't even read the record.

So let's add another rule to allow them to read those records which belong to other company:

<record model="ir.rule" id="my_custom_rule_b">
    <field name="name">My custom rule B</field>
    <field name="model_id" ref="my_module.model_my_model"/>
    <field name="domain_force">[('company_id', '!=', user.company_id.id)]</field>
    <field name="perm_read" eval="True"/>
    <field name="perm_write" eval="False"/>
    <field name="perm_create" eval="False"/>
    <field name="perm_unlink" eval="False"/>
</record>

When I add this rule, nobody can't even read any record, it doesn't matter if users belong to the same company of the record or not... so I've modified the second rule this way:

<record model="ir.rule" id="my_custom_rule_b">
    <field name="name">My custom rule B</field>
    <field name="model_id" ref="my_module.model_my_model"/>
    <field name="domain_force">['|', ('company_id', '=', user.company_id.id), ('company_id', '!=', user.company_id.id)]</field>
    <field name="perm_read" eval="True"/>
    <field name="perm_write" eval="False"/>
    <field name="perm_create" eval="False"/>
    <field name="perm_unlink" eval="False"/>
</record>

But the behaviour now it's exactly the same as if I only added the very first rule: users who belong to the same company can do whatever to the record and the ones who doesn't belong to the same company can't even read the record.

I've had bigger problems with rules, so it would be great to start understanding this small issue to face the other ones.


Solution

  • Global rules are always AND as you can read in the doc you've copied in your question. Every record will be checked against those rules.

    So your first attempt is mutually exclusive, that's why no record is found. The outcome of your second attempt is correct too, because only records of the users company are satisfying both record rules.

    What do you have to do to get your desired outcome: You have to use non-global record rules.

    A very simple example:

    Model -> my.model

    model access (ir.model.access) for group Employees (default user group in Odoo, but you can create your own ones) -> CRUD 1111 (all rights for everyone on every record, will be affected by the record rules)

    Now you need two record rules for group Employees, too:

    A with domain [('company_id', '=', user.company_id.id)] and CRUD 1111 (all rights on users company records)

    B with domain [(1, '=', 1)] and CRUD 0100 (read rights on every record)

    That's it actually. As a sidenote: the client behaves very bad in such constellations. Users of company B will see records of company A (as desired) and at first it seems the user can change them, because the edit button is shown and "functional", but on save the access right warning will pop up.