Record Rule help

I am struggling to get record rules to work. I have a ModelSQL called timeclock_event, which has an “employee” attribute. The goal is to generally allow employees access to timeclock_events only where they are the employee, but to have a “Timeclock Admin” group with access to all records. I have the first part working (restricting users to their own records), but can’t get the admin group to work.

Here is the relevant code:

    <record model="res.group" id="timeclock_admin">
        <field name="name">Timeclock Admin</field>
    </record>

   <!-- The general rule, which is working -->
   <record model="ir.rule.group" id="rule_your_timeclock_events">
        <field name="model" search="[('model', '=', 'timeclock_event')]"/>
        <field name="global_p" eval="False"/>
        <field name="default_p" eval="True"/>
        <field name="perm_read" eval="True"/>
        <field name="perm_write" eval="True"/>
        <field name="perm_delete" eval="True"/>
        <field name="perm_create" eval="True"/>
   </record>
   <record model="ir.rule" id="rule_your_timeclock_line1">
 <field name="domain">[('employee', '=', user.employee and user.employee.id or None)]</field>
     <field name="rule_group" ref="rule_your_timeclock_events"/>
   </record>

    <!-- Not working: Granting broader access to timeclock admin group member -->
    <record model="ir.model.access" id="access_admin_all_timeclock_events">
        <field name="model" search="[('model', '=', 'timeclock_event')]"/>
        <field name="group" ref="timeclock_admin"/>
        <field name="perm_read" eval="True"/>
        <field name="perm_write" eval="True"/>
        <field name="perm_create" eval="True"/>
        <field name="perm_delete" eval="True"/>
    </record>
   <record model="ir.rule.group" id="rule_all_timeclock_events">
        <field name="model" search="[('model', '=', 'timeclock_event')]"/>
        <field name="global_p" eval="False"/>
        <field name="default_p" eval="False"/>
        <field name="perm_read" eval="True"/>
        <field name="perm_write" eval="True"/>
        <field name="perm_delete" eval="True"/>
        <field name="perm_create" eval="True"/>
   </record>
   <!--  I've also tried including this, but it doesn't help
   <record model="ir.rule" id="rule_all_timeclock_line1">
 <field name="domain">[]</field>
     <field name="rule_group" ref="rule_all_timeclock_events"/>
   </record>
 -->
   <record model="ir.rule.group-res.group"
       id="rule_all_timeclock_events_timeclock_admin">
       <field name="rule_group" ref="rule_all_timeclock_events"/>
       <field name="group" ref="timeclock_admin"/>
    </record>

I think access_admin_all_timeclock_events should be explicitly put as non-global.

Thank you for the advice, but I don’t understand it. access_admin_timeclock_events is an instance of ir.model.access, and I don’t see how to mark it as non-global. It doesn’t have a global attribute.

Pool().get('ir.model.access')._fields.keys()
> ['rec_name', 'create_uid', 'create_date', 'description', 'write_date',
   'write_uid', 'perm_read', 'perm_create', 'perm_write', 'group',
   'model', 'perm_delete', 'id']

The analogous ir.rule.group (i.e., rule_all_timeclock_events) already has global_p set to False.

My bad, I was meaning this but I wrongly read it.

But is the admin user in the group “Timeclock Admin”?
And are you sure that the global_p is correctly set to False for rule_all_timeclock_events in the database. Sometimes during development, the update does not work because if incompatible changes made in the XML.

Right now, when any user accesses the timeclock events menu, they will see the timeclock events of that user’s employee. The goal is that, in addition to that behavior, members of the timeclock_admin group should be able to see all timeclock events (but this aspect is not working).

I confirmed in the gtk that rule_all_timeclock_events has both “global” and “default” unchecked.

Thanks, again, for your help and attention.

And rule_your_timeclock_events also?

The rule_your_timeclock_events was marked as non-global, but default. I experimented with changing it to non-default and, to my surprise, this did not affect the behavior. I was expecting that, without default checked, it would not apply unless the user was designated for it to apply in some way, but that it not the case. (?)

This made me think that your domain should probably be wrong.
And indeed they are. They must be PYSON statement and they should look like:

<field name="domain" eval="[('employee', '=', Eval('user', {}).get('employee'))]" pyson="1"/>

This gives me an error, NameError: name 'Eval' is not defined.

(I had tried this format previously, based on the examples at [1], but received this error. I then searched standard modules, which led me to the <field.>domain</field) syntax.)

Btw, I am using 3.4. I did a search of standard 3.4 modules and did not locate pyson=, so I am thinking this may have changed since my version?

[1] https://groups.google.com/forum/#!topic/tryton/JeXK9tJ5ctE

The pyson=“1” syntax was introduced on version 3.6

You can have a look at the timesheet module for a similar rule on 3.4 version

Thanks very much for the suggestion. I was using that syntax originally (see the above code), and it halfway worked: I was able to add a rule to restrict users to records where the record’s employee field matched their user’s employee. However, I also wanted to create a timeclock_admin group that was able to see all the record, but I was unable to make this more permissive rule work to override the default rule.

Thanks, again, though for the suggestion.

I think the only left solution is to look at the SQL query generated to understand what WHERE clause is used.

I have a similar case but a bit more complex (and for me very difficult to deal with rules): I have 4 delegations and several employees that works to one or more delegations each one. Let’s suppose:

  • employee_1 works to delegation_1
  • employee_2 works to delegation_2
  • employee_3 works to delegation_3
  • employee_4 works to delegation_1 and delegation_2
  • employee_5 is the supervisor, so he has to have permission to all delegations

Each employee should see only the records (let’s suppose moves) belonging the delegation(s) he works for. I would do a group for each delegation, and each group would have a rule to restrict the records belonging the delegation. This is okay for employee_1, employee_2 and employee_3. But what about employee_4 and employee_5? Do I have to create a group for each combination?

You can use Many2Many fields on record rules, so instead of assigning a delefation per users you can assign multiple delegation on each users. Then record rule domain can be somethinkg like:

<field name="domain" eval="[('delegation', 'in', Eval('user', {}).get('delegations', []))]" pyson="1"/>

Probably it makes sense to include a special group which allows acess to each delegation, so you do not need to manually set all delegations to supervisor users.

Thank you very much for the answer.
That’s okay. But this behaviour forces to create a group for each combination, and moreover, deal with care with this groups when combining with others because the permissions over the models, the buttons and the menus will be computed with an “or” but the rules will be computed with an “and”… An example:

  • delegation_1 group: Permissions to CRUD over moves from/to delegation_1 + menu option specific to delegations.
  • logistics group: Permissions to CRUD over moves, no matter its from/to + menu option specific to logistics.

What if I want to give access to logistics and to delegation_1 to a certain user? I should have to create a specific group joining the model access, menus and buttons, with no rules (in this case)… If I have 20 groups, 50 users (perhaps 10 different roles combining several groups each one) it can be a nightmare…

Don’t understand why you need to create too much groups. For me you should only create one group on which the restriction rules should apply.

Access rules are aditive, so if one group of the user grants access to some CRUD moves, other groups will not remove this access.

Hope it helps.

That’s true except if I combine a group that has a rule with another that doen’t. For example:

If I have a group that give me access only to some records of a model (i.e. model: shipment_*, rule: state=‘done’) and another group that give me access to all records of the same model (I don’t define a rule to no restrict nothing) when I assign both rules to a user, he will only have access to the records matching the rule of the first group even though he belongs to the second group too.

When I add a group to a user I never expect (perhaps it’s my fault) that it can “restrict” access and that’s what happened in the above example.

IIRC You should define a rule with an empty domain for the group that has access to all records. So this group will have the access to all records.