[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
This commit is contained in:
Raphael Collet
2021-01-13 16:19:13 +00:00
parent d1361d9e3a
commit 4de2ec280c
2 changed files with 16 additions and 12 deletions
@@ -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. """
+4 -10
View File
@@ -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()}