Theory (rules and csv)
About rules
Get from this thanks to these guys for their work
Record rules are conditions that records must satisfy for an operation (create, read, write or delete) to be allowed. Example of a condition: User can update Task that assigned to him.
Group field defines for which group rule is applied. If Group is not specified, then rule is global and applied for all users.
Domain field defines conditions for records.
Boolean fields (read, write, create, delete) of ir.rule mean Apply this rule for this kind of operation. They do not mean restrict access for this kind of operation.
Checking access algorithm
To check either user has access for example to read a record, system do as following:
- Check access according to ir.model.access records. If it doesn’t pass, then user doesn’t get access
- Find and check global rules for the model and for read operation
- if the record doesn’t satisfy (doesn’t fit to domain) for at least one of the global rules, then user doesn’t get access
- Find and check non-global rules for the model, which perm_read equal True and
groups
that intersect with current user groups.- if there are no such rules, then user get access
- if the record satisfy (fit to domain) for at least one of the non-global rules, then user get access
- if the record doesn’t satisfy for all non-global rules, then user doesn’t get access
To check either user has access for example to read a record, system do as following:
- Check access according to ir.model.access records. If it doesn’t pass, then user doesn’t get access
- Find and check global rules for the model and for read operation
- if the record doesn’t satisfy (doesn’t fit to domain) for at least one of the global rules, then user doesn’t get access
- Find and check non-global rules for the model, which perm_read equal True and
groups
that intersect with current user groups.- if there are no such rules, then user get access
- if the record satisfy (fit to domain) for at least one of the non-global rules, then user get access
- if the record doesn’t satisfy for all non-global rules, then user doesn’t get access
Real task, case
I recently encountered a problem that I could not solve for a long time, although I already thought that such problems did not exist for me in odoo :)
So we have sale.order and sale.order.line in it.
And we need to prevent some users who belong to a certain group from changing and deleting sale.order.line after the compute field in sale.order takes a certain value. But if this prohibition should only apply to those sale.order.line that were created before the moment when the compute field crossed a certain threshold. And new sale.order.line users can create, delete, modify. And there is a group of users, like admins, to whom these restrictions do not apply. so my 3 steps before i made a working solution
Implementation in code
1. variant XML attributes
{'readonly':[('state','not in',['draft','sent'])]}
</attribute>
</record>
Let's analyze it in detail. This code determines for all users with the base.group_user group to change the attribute of the client_order_ref field to readonly by condition. Thus, we can, as it were, prohibit a certain group from recalling a field or, on the contrary, allow it, we can also change the attribute in the tree element and thereby prohibit deleting one2many rows for the group.
But what if we need to prohibit the deletion of certain lines for a certain group of users, but allow some lines to be deleted, then such a solution will not help.
2. variant fields_view_get
@api.model def fields_view_get(self, view_id=None, view_type='form', toolbar=False, submenu=False): """ Переопределяем вью, если пользователь не в группе которой разрешенно редактировать и удалять и при этом есть какая то сумма оплаченная клиенту, то выключаем возможность удаления и редактирования детализации """ res = super(mta_saleorder, self).fields_view_get(view_id=view_id, view_type=view_type, toolbar=toolbar, submenu=submenu) if view_type == 'form': _logger.warning("!!!!"*10) _logger.warning(self._context) if not self.user_has_groups('mta_base.mta_sale_order_line_editor'): active_id = self._context.get('params') and self._context.get('params').get('id') or self._context.get('active_id', False) if active_id: if self.env['sale.order'].browse(active_id).mt_detail_balance_supp > 0: doc = etree.fromstring(res['fields']['order_line']['views']['tree']['arch']) # выключаем режим редактировани и удаления for tree in doc.xpath("//tree"): tree.set('delete', '0') tree.set('edit', '0') tree.set('create', '1') # tree.set('editable', 'top') # tree.set('editable', 'bottom') # все поля реадонли, потому что режим выключенного редактирования не работает (баг в текущем инстансе) for field in doc.xpath("//field"): if field.get('modifiers'): modifiers = json.loads(field.get('modifiers')) modifiers['readonly'] = True field.set('modifiers', json.dumps(modifiers)) res['fields']['order_line']['views']['tree']['arch'] = etree.tostring(doc, encoding='unicode')
doc = etree.fromstring(res['fields']['details_ids']['views']['tree']['arch']) # выключаем режим редактировани и удаления for tree in doc.xpath("//tree"): tree.set('delete', '0') tree.set('edit', '0') tree.set('create', '1') # tree.set('editable', 'top') # все поля реадонли, потому что режим выключенного редактирования не работает (баг в текущем инстансе) for field in doc.xpath("//field"): if field.get('modifiers'): modifiers = json.loads(field.get('modifiers')) modifiers['readonly'] = True field.set('modifiers', json.dumps(modifiers)) res['fields']['details_ids']['views']['tree']['arch'] = etree.tostring(doc, encoding='unicode') return res
We can override the fields view_get function which returns the xml view for the form, but it will also only allow dynamically changing attributes and will not allow deleting one2many fields in some new lines