I've created a new group named accountant. If an user of this group opens the res.partner
form for example, he must be able to read all, but only modify some specific fields (the ones inside the tab Accountancy, for example).
So I set the permissions create
, write
, unlink
, read
to 0
, 1
, 0
, 1
in the res.partner
model for the accountant group.
The problem: if I'm an user of the accountant group and I go to the form of res.partner
, I will see the Edit button, if I click on it, I will be able to modify any field I want (and I should not, only the ones inside the tab).
So I thought to duplicate the menuitem (put the attribute groups="accountant"
to the copy) and the form (put all fields readonly except for the content of the tab).
The problem: if I'm an user of a group over accountant group (with accountant in its implied_ids
list), I will see both menuitems (the one which takes to the normal form and the one which takes to the duplicated form with the readonly fields).
Is it possible to create a menuitem which opens a specific set of views depending on the group of the user who is clicking on the mentioned menuitem? Any ideas of how can I succesfully implement this?
I was googling a lot and there are many people who ask this same question in Odoo forums, but nobody gives them an answer.
Finally, I found this workaround, which in my case worked perfectly: the method field_view_get
, which is in every single model, gets the XML view just before returning it to be shown. This means that you can manipulate the view from Python code in whatever way you want.
You only must know how to use a library like lxml
to modify the string variable with the XML code. I put my example:
RES.PARTNER model (Here we must use etree
from lxml
library)
@api.model
def fields_view_get(self, view_id=None, view_type='form', toolbar=False,
submenu=False):
res = super(res_partner, self).fields_view_get(
view_id=view_id, view_type=view_type, toolbar=toolbar,
submenu=submenu)
checking_obj = self.env['my.own.checkings']
doc = etree.XML(res['arch'])
if checking_obj.belongs_to_accountant_group():
doc.set('create', 'false')
doc.set('delete', 'false')
doc.set('edit', 'true')
if view_type == 'form':
accounting_pages = doc.xpath("//page[@name='accounting']")
accounting_page = accounting_pages[0] if accounting_pages \
else False
if accounting_page is not False:
if checking_obj.belongs_to_accountant_group():
all_fields = doc.xpath("//field")
for field in all_fields:
if accounting_page not in field.iterancestors():
checking_obj.set_modifiers(field,
{'readonly': True, })
res['arch'] = etree.tostring(doc)
return res
AUXILIAR CUSTOMIZED model (named MY.OWN.CHECKINGS) (Here we must use json
library)
def update_json_data(self, json_data=False, update_data={}):
''' It updates JSON data. It gets JSON data, converts it to a Python
dictionary, updates this, and converts the dictionary to JSON data
again. '''
dict_data = json.loads(json_data) if json_data else {}
dict_data.update(update_data)
return json.dumps(dict_data, ensure_ascii=False)
def set_modifiers(self, element=False, modifiers_upd={}):
''' It updates the JSON modifiers with the specified data to indicate
if a XML tag is readonly or invisible or not. '''
if element is not False: # Do not write only if element:
modifiers = element.get('modifiers') or {}
modifiers_json = self.update_json_data(
modifiers, modifiers_upd)
element.set('modifiers', modifiers_json)
def is_accountant(self):
return self.env.ref(
'my_module.group_accountant').id in \
self.env.user.groups_id.mapped('id')
This way you can make readonly some fields depending on the group of the current user.