From 4cbce5729ef32e9b9a3597fac404ee94d6ded607 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 --- trytond/trytond/model/modelview.py | 11 ++++++++++ trytond/trytond/tests/test_field_depends.py | 23 +++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/trytond/trytond/model/modelview.py b/trytond/trytond/model/modelview.py index 745184c8d4..4e20803fa1 100644 --- a/trytond/trytond/model/modelview.py +++ b/trytond/trytond/model/modelview.py @@ -150,6 +150,17 @@ 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_'):] + if dep_field := getattr(cls, depend, None): + 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 a76d04f8a6..c90c47d5b4 100644 --- a/trytond/trytond/tests/test_field_depends.py +++ b/trytond/trytond/tests/test_field_depends.py @@ -263,3 +263,26 @@ class FieldDependsTestCase(TestCase): ]: with self.subTest(value=value): self.assertEqual(fields.get_eval_fields(value), result) + + 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'})