From 7d040c8cb9c353f2a4b3e59d8097593c108cf659 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Mon, 9 Feb 2026 18:13:34 +0100 Subject: [PATCH] Check button states when testing access Closes #14591 --- trytond/CHANGELOG | 1 + trytond/trytond/ir/message.xml | 3 +++ trytond/trytond/model/modelview.py | 13 ++++++++++++- trytond/trytond/tests/modelview.py | 16 ++++++++++++++++ trytond/trytond/tests/test_modelview.py | 19 +++++++++++++++++++ 5 files changed, 51 insertions(+), 1 deletion(-) diff --git a/trytond/CHANGELOG b/trytond/CHANGELOG index 12db347f84..aa3e6f7b01 100644 --- a/trytond/CHANGELOG +++ b/trytond/CHANGELOG @@ -1,3 +1,4 @@ +* Check button states when testing access * Remove the files of Binary fields from the Filestore * Add delete and delete_many to Filestore * Deprecate ``grouped_slice`` without size diff --git a/trytond/trytond/ir/message.xml b/trytond/trytond/ir/message.xml index b968d16f68..6b79de940d 100644 --- a/trytond/trytond/ir/message.xml +++ b/trytond/trytond/ir/message.xml @@ -282,6 +282,9 @@ this repository contains the full copyright notices and license terms. --> Calling button "%(button)s on "%(model)s" is not allowed. + + You can not call "%(button)s" on "%(record)s" of "%(model)s". + Invalid XML for view "%(name)s". diff --git a/trytond/trytond/model/modelview.py b/trytond/trytond/model/modelview.py index c99384f5e9..f2f53ae3c9 100644 --- a/trytond/trytond/model/modelview.py +++ b/trytond/trytond/model/modelview.py @@ -19,6 +19,7 @@ from . import fields from .fields import on_change_result from .fields.field import _set_value from .model import Model +from .modelstorage import _pyson_encoder, _record_eval_pyson __all__ = ['ModelView'] @@ -764,10 +765,20 @@ class ModelView(Model): raise AccessButtonError( gettext('ir.msg_access_button_error', button=func.__name__, - model=cls.__name__)) + **cls.__names__())) else: ModelAccess.check(cls.__name__, 'write') + states = cls._buttons.get(func.__name__, {}) + for state_name in {'invisible', 'readonly'} & states.keys(): + state = _pyson_encoder.encode(states[state_name]) + for record in records: + if _record_eval_pyson(record, state, encoded=True): + raise AccessButtonError( + gettext('ir.msg_button_state_record', + button=func.__name__, + **cls.__names__(record=record))) + if (transaction.user != 0) and check_access: button_rules = Button.get_rules( cls.__name__, func.__name__) diff --git a/trytond/trytond/tests/modelview.py b/trytond/trytond/tests/modelview.py index 50c7dc8a0b..38f81dd1b4 100644 --- a/trytond/trytond/tests/modelview.py +++ b/trytond/trytond/tests/modelview.py @@ -68,6 +68,12 @@ class ModelViewButton(ModelView): super().__setup__() cls._buttons = { 'test': {}, + 'test_invisible': { + 'invisible': Eval('value', 0) == 42, + }, + 'test_readonly': { + 'readonly': Eval('value', 0) == 42, + }, } @classmethod @@ -79,6 +85,16 @@ class ModelViewButton(ModelView): def test_non_decorated(cls, records): pass + @classmethod + @ModelView.button + def test_invisible(cls, records): + pass + + @classmethod + @ModelView.button + def test_readonly(cls, records): + pass + class ModelViewButtonDepends(ModelView): __name__ = 'test.modelview.button_depends' diff --git a/trytond/trytond/tests/test_modelview.py b/trytond/trytond/tests/test_modelview.py index d17c5e2255..5fb454e9fe 100644 --- a/trytond/trytond/tests/test_modelview.py +++ b/trytond/trytond/tests/test_modelview.py @@ -454,6 +454,25 @@ class ModelView(TestCase): with self.assertRaises(AccessButtonError): TestModel.test([test]) + @with_transaction(context={'_check_access': True}) + def test_button_access_state(self): + "Test Button Access with states" + pool = Pool() + Model = pool.get('test.modelview.button') + + record = Model() + + Model.test_invisible([record]) + Model.test_readonly([record]) + + record = Model(value=42) + + with self.assertRaises(AccessButtonError): + Model.test_invisible([record]) + + with self.assertRaises(AccessButtonError): + Model.test_readonly([record]) + @with_transaction(context={'_check_access': True}) def test_button_no_rule(self): "Test no Button Rule"