From 4de2ec280c4c5769bfc1336ab185e8949acf879e Mon Sep 17 00:00:00 2001 From: Raphael Collet Date: Mon, 11 Jan 2021 15:49:38 +0000 Subject: [PATCH] [FIX] core: compute editable field with a default should not recompute Consider a model with a field F and a computed editable field G that depends on F. Assume we open a form view, and both F and G have a default value. The first onchange should return F and G with their respective default values. In other words, the field G should not be recomputed even if its dependency F was assigned a default value. The use-case that showed the issue is batch payments. When adding a new payment in the one2many field of a batch, the new payment should use the batch's payment method by default. The default value for the payment's method is assigned by context on the one2many field in the view. Before this patch, the new payment's method was given by the computation of the field, and its default value was ignored. Side note: another test was fixed, but that's because the test was not consistent with the way Odoo 14.0 manages defaults and onchanges. X-original-commit: 2ccc735253405b03927e2b08eab57427e65e4050 --- odoo/addons/test_new_api/tests/test_onchange.py | 14 ++++++++++++-- odoo/models.py | 14 ++++---------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py index ea7d64d2676..57526d83fb3 100644 --- a/odoo/addons/test_new_api/tests/test_onchange.py +++ b/odoo/addons/test_new_api/tests/test_onchange.py @@ -498,13 +498,13 @@ class TestOnChange(SavepointCaseWithUserDemo): self.env.cache.invalidate() Message = self.env['test_new_api.related'] - result = Message.onchange(value, ['message', 'message_name', 'message_currency'], field_onchange) + result = Message.onchange(value, 'message', field_onchange) self.assertEqual(result['value'], onchange_result) self.env.cache.invalidate() Message = self.env(user=self.user_demo.id)['test_new_api.related'] - result = Message.onchange(value, ['message', 'message_name', 'message_currency'], field_onchange) + result = Message.onchange(value, 'message', field_onchange) self.assertEqual(result['value'], onchange_result) @@ -743,6 +743,16 @@ class TestComputeOnchange(common.TransactionCase): self.assertEqual(form.bar, "foo6r") self.assertEqual(form.baz, "baz5") + def test_onchange_default(self): + form = common.Form(self.env['test_new_api.compute.onchange'].with_context( + default_active=True, default_foo="foo", default_baz="baz", + )) + # 'baz' is computed editable, so when given a default value it should + # 'not be recomputed, even if a dependency also has a default value + self.assertEqual(form.foo, "foo") + self.assertEqual(form.bar, "foor") + self.assertEqual(form.baz, "baz") + def test_onchange_once(self): """ Modifies `foo` field which will trigger an onchange method and checks it was triggered only one time. """ diff --git a/odoo/models.py b/odoo/models.py index 5aaff716a02..4c06ea5b9b9 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -6216,16 +6216,10 @@ Fields: todo = list(unique(itertools.chain(names, nametree))) if first_call else list(names) done = set() - # dummy assignment: trigger invalidations on the record - for name in todo: - if name == 'id': - continue - value = record[name] - field = self._fields[name] - if field.type == 'many2one' and field.delegate and not value: - # do not nullify all fields of parent record for new records - continue - record[name] = value + # mark fields to do as modified to trigger recomputations + protected = [self._fields[name] for name in names] + with self.env.protecting(protected, record): + record.modified(todo) result = {'warnings': OrderedSet()}