From 2ededea81ff0e2080e1883aff23ba7b71dd8abf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 5 Dec 2024 16:25:16 +0100 Subject: [PATCH] Include the depends of the getter function when depending on a Function field Since c47b3642f1a6, the getter of a Function field may be called if there is no value set for it on the instance. In the on_change context, this may set the missing fields to None if they were not defined in the depends of the method called. In addition to compute a wrong value, those fields are then returned as modified. Closes #13735 (grafted from 1b815539165a1212fc5c415c8920d8f5f0c55236) --HG-- branch : 6.0 --- trytond/trytond/model/modelview.py | 12 +++++++++++ trytond/trytond/tests/test_field_depends.py | 23 +++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/trytond/trytond/model/modelview.py b/trytond/trytond/model/modelview.py index 4c4d24da8a..73c00cd92a 100644 --- a/trytond/trytond/model/modelview.py +++ b/trytond/trytond/model/modelview.py @@ -179,6 +179,18 @@ class ModelView(Model): meth_names = list(methods['depend_methods'][function_name]) meth_done = set() + + for depend in getattr(field, attribute): + if '.' in depend: + depend, _ = depend.split('.', 1) + if depend.startswith('_parent_'): + depend = depend[len('_parent_'):] + dep_field = getattr(cls, depend, None) + if dep_field: + if (isinstance(dep_field, fields.Function) + and dep_field.getter.startswith('on_change_with')): + meth_names.append(dep_field.getter) + while meth_names: meth_name = meth_names.pop() method = getattr(cls, meth_name) diff --git a/trytond/trytond/tests/test_field_depends.py b/trytond/trytond/tests/test_field_depends.py index 7165663712..170c684f27 100644 --- a/trytond/trytond/tests/test_field_depends.py +++ b/trytond/trytond/tests/test_field_depends.py @@ -248,6 +248,29 @@ class FieldDependsTestCase(unittest.TestCase): self.assertEqual(Model.bar.on_change, {'foo', 'bar'}) + def test_depends_function_getter(self): + "Tests depends on Function field with on_change_with getter" + + class Model(ModelView): + __name__ = 'test.modelview.function_getter_depends' + + test = fields.Char("Test") + foo = fields.Function(fields.Char("Foo"), 'on_change_with_foo') + bar = fields.Char("Bar") + + @fields.depends('foo') + def on_change_test(self): + pass + + @fields.depends('bar') + def on_change_with_foo(self, name=None): + pass + + Model.__setup__() + Model.__post_setup__() + + self.assertEqual(Model.test.on_change, {'foo', 'bar'}) + def suite(): return unittest.TestLoader().loadTestsFromTestCase(FieldDependsTestCase)