From 1cd610a9b6581b84c8a9796c1a45dcc0005c4f09 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 29 Sep 2022 12:56:27 +0000 Subject: [PATCH] [FIX] base: invisible="context.get(...)" takes priority only if True This is an oversight in odoo/odoo#100130 A modifier set with `context.get('...')`, for instance `invisible="context.get('sign_directly_without_mail',False)"` takes priority on attrs only if the result of `context.get('...')` isn't falsy e.g. https://github.com/odoo/enterprise/blob/1a4e4fafe4fc78dab0aad7ab6241a6f4a7be317a/sign/wizard/sign_send_request_views.xml#L64 should return - `modifiers="{'invisible': [['is_user_signer', '=', false]]}"` with `context.get('sign_directly_without_mail') == False` - `modifiers="{'invisible': true}"` with `context.get('sign_directly_without_mail') == True` closes odoo/odoo#101813 X-original-commit: a3dc5f5fd34671c67253c6ff36bb7c960f9170ff Signed-off-by: Denis Ledoux (dle) --- odoo/addons/base/models/ir_ui_view.py | 16 +++++++++------- odoo/addons/base/tests/test_views.py | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/odoo/addons/base/models/ir_ui_view.py b/odoo/addons/base/models/ir_ui_view.py index 4f62326680c..d9ea78d7945 100644 --- a/odoo/addons/base/models/ir_ui_view.py +++ b/odoo/addons/base/models/ir_ui_view.py @@ -92,7 +92,7 @@ def transfer_node_to_modifiers(node, modifiers): else: modifiers['invisible'] = [('state', 'not in', states)] - context_dependent_modifiers = [] + context_dependent_modifiers = {} for attr in ('invisible', 'readonly', 'required'): value_str = node.attrib.pop(attr, None) if value_str: @@ -112,8 +112,8 @@ def transfer_node_to_modifiers(node, modifiers): # if str2bool fails, it means it's something else than 1/True/0/False, # meaning most-likely `context.get('...')`, # which should be evaluated after retrieving the view arch from the cache - value = value_str - context_dependent_modifiers.append(attr) + context_dependent_modifiers[attr] = value_str + continue if value or (attr not in modifiers or not isinstance(modifiers[attr], list)): # Don't set the attribute to False if a dynamic value was @@ -121,7 +121,7 @@ def transfer_node_to_modifiers(node, modifiers): modifiers[attr] = value if context_dependent_modifiers: - node.set('context-dependent-modifiers', ','.join(context_dependent_modifiers)) + node.set('context-dependent-modifiers', json.dumps(context_dependent_modifiers)) def simplify_modifiers(modifiers): @@ -1093,9 +1093,11 @@ actual arch. context-dependent-modifiers="invisible"/> """ for node in tree.xpath('//*[@context-dependent-modifiers]'): - modifiers = json.loads(node.attrib.pop('modifiers')) - for attr in node.attrib.pop('context-dependent-modifiers').split(','): - modifiers[attr] = bool(safe_eval.safe_eval(modifiers[attr], {'context': self._context})) + modifiers = json.loads(node.attrib.pop('modifiers', '{}')) + for attr, value in json.loads(node.attrib.pop('context-dependent-modifiers')).items(): + value = bool(safe_eval.safe_eval(value, {'context': self._context})) + if value or (attr not in modifiers or not isinstance(modifiers[attr], list)): + modifiers[attr] = value transfer_modifiers_to_node(modifiers, node) return tree diff --git a/odoo/addons/base/tests/test_views.py b/odoo/addons/base/tests/test_views.py index 8574b3e4b18..e3f6a62a23a 100644 --- a/odoo/addons/base/tests/test_views.py +++ b/odoo/addons/base/tests/test_views.py @@ -2213,6 +2213,22 @@ class TestViews(ViewCase): self.assertEqual(modifiers.get('readonly'), expected.get('readonly')) self.assertEqual(modifiers.get('required'), expected.get('required')) + def test_modifier_attribute_priority(self): + view = self.assertValid(""" +
+ + + + """) + for context, expected in [ + ({}, [['type', '=', 'tree']]), + ({'foo': True}, True) + ]: + arch = self.View.with_context(**context).get_view(view.id)['arch'] + field_node = etree.fromstring(arch).xpath('//field[@name="name"]')[0] + modifiers = json.loads(field_node.get('modifiers') or '{}') + self.assertEqual(modifiers.get('invisible'), expected) + @mute_logger('odoo.addons.base.models.ir_ui_view') def test_domain_in_filter(self): arch = """