diff --git a/odoo/addons/test_new_api/models/test_new_api.py b/odoo/addons/test_new_api/models/test_new_api.py index 70bbe1ecd77..5fe041b102c 100644 --- a/odoo/addons/test_new_api/models/test_new_api.py +++ b/odoo/addons/test_new_api/models/test_new_api.py @@ -556,13 +556,13 @@ class ComputeOnchange(models.Model): @api.depends('foo') def _compute_bar(self): for record in self: - record.bar = record.foo + record.bar = (record.foo or "") + "r" @api.depends('active', 'foo') def _compute_baz(self): for record in self: if record.active: - record.baz = record.foo + record.baz = (record.foo or "") + "z" @api.depends('foo') def _compute_line_ids(self): @@ -590,9 +590,14 @@ class ComputeOnchangeLine(models.Model): _name = 'test_new_api.compute.onchange.line' _description = "Line-like model for test_new_api.compute.onchange" + record_id = fields.Many2one('test_new_api.compute.onchange', ondelete='cascade') foo = fields.Char() - record_id = fields.Many2one('test_new_api.compute.onchange', - required=True, ondelete='cascade') + bar = fields.Char(compute='_compute_bar') + + @api.depends('foo') + def _compute_bar(self): + for line in self: + line.bar = (line.foo or "") + "r" class ComputeDynamicDepends(models.Model): diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py index c417ef9dba5..735d4ffc62c 100644 --- a/odoo/addons/test_new_api/tests/test_onchange.py +++ b/odoo/addons/test_new_api/tests/test_onchange.py @@ -543,24 +543,29 @@ class TestComputeOnchange(common.TransactionCase): def test_create(self): model = self.env['test_new_api.compute.onchange'] + # compute 'bar' (readonly) and 'baz' (editable) + record = model.create({'active': True}) + self.assertEqual(record.bar, "r") + self.assertEqual(record.baz, "z") + # compute 'bar' and 'baz' record = model.create({'active': True, 'foo': "foo"}) - self.assertEqual(record.bar, "foo") - self.assertEqual(record.baz, "foo") + self.assertEqual(record.bar, "foor") + self.assertEqual(record.baz, "fooz") # compute 'bar' but not 'baz' record = model.create({'active': True, 'foo': "foo", 'bar': "bar", 'baz': "baz"}) - self.assertEqual(record.bar, "foo") + self.assertEqual(record.bar, "foor") self.assertEqual(record.baz, "baz") # compute 'bar' and 'baz', but do not change its value record = model.create({'active': False, 'foo': "foo"}) - self.assertEqual(record.bar, "foo") + self.assertEqual(record.bar, "foor") self.assertEqual(record.baz, False) # compute 'bar' but not 'baz' record = model.create({'active': False, 'foo': "foo", 'bar': "bar", 'baz': "baz"}) - self.assertEqual(record.bar, "foo") + self.assertEqual(record.bar, "foor") self.assertEqual(record.baz, "baz") def test_copy(self): @@ -572,10 +577,10 @@ class TestComputeOnchange(common.TransactionCase): {'name': 'bar1'}, ]) - # compute 'bar', 'baz', 'line_ids' and 'tag_ids' + # compute 'bar' (readonly), 'baz', 'line_ids' and 'tag_ids' (editable) record = Model.create({'active': True, 'foo': "foo1"}) - self.assertEqual(record.bar, "foo1") - self.assertEqual(record.baz, "foo1") + self.assertEqual(record.bar, "foo1r") + self.assertEqual(record.baz, "foo1z") self.assertEqual(record.line_ids.mapped('foo'), ['foo1']) self.assertEqual(record.tag_ids, tag_foo) @@ -585,7 +590,7 @@ class TestComputeOnchange(common.TransactionCase): 'line_ids': [Command.create({'foo': 'bar'})], 'tag_ids': [Command.link(tag_bar.id)], }) - self.assertEqual(record.bar, "foo1") + self.assertEqual(record.bar, "foo1r") self.assertEqual(record.baz, "baz1") self.assertEqual(record.line_ids.mapped('foo'), ['foo1', 'bar']) self.assertEqual(record.tag_ids, tag_foo + tag_bar) @@ -593,7 +598,7 @@ class TestComputeOnchange(common.TransactionCase): # copy the record, and check results copied = record.copy() self.assertEqual(copied.foo, "foo1 (copy)") # copied and modified - self.assertEqual(copied.bar, "foo1 (copy)") # computed + self.assertEqual(copied.bar, "foo1 (copy)r") # computed self.assertEqual(copied.baz, "baz1") # copied self.assertEqual(record.line_ids.mapped('foo'), ['foo1', 'bar']) # copied self.assertEqual(record.tag_ids, tag_foo + tag_bar) # copied @@ -601,128 +606,141 @@ class TestComputeOnchange(common.TransactionCase): def test_write(self): model = self.env['test_new_api.compute.onchange'] record = model.create({'active': True, 'foo': "foo"}) - self.assertEqual(record.bar, "foo") - self.assertEqual(record.baz, "foo") + self.assertEqual(record.bar, "foor") + self.assertEqual(record.baz, "fooz") - # recompute 'bar' and 'baz' + # recompute 'bar' (readonly) and 'baz' (editable) record.write({'foo': "foo1"}) - self.assertEqual(record.bar, "foo1") - self.assertEqual(record.baz, "foo1") + self.assertEqual(record.bar, "foo1r") + self.assertEqual(record.baz, "foo1z") # recompute 'bar' but not 'baz' record.write({'foo': "foo2", 'bar': "bar2", 'baz': "baz2"}) - self.assertEqual(record.bar, "foo2") + self.assertEqual(record.bar, "foo2r") self.assertEqual(record.baz, "baz2") # recompute 'bar' and 'baz', but do not change its value record.write({'active': False, 'foo': "foo3"}) - self.assertEqual(record.bar, "foo3") + self.assertEqual(record.bar, "foo3r") self.assertEqual(record.baz, "baz2") # recompute 'bar' but not 'baz' record.write({'active': False, 'foo': "foo4", 'bar': "bar4", 'baz': "baz4"}) - self.assertEqual(record.bar, "foo4") + self.assertEqual(record.bar, "foo4r") self.assertEqual(record.baz, "baz4") def test_set(self): model = self.env['test_new_api.compute.onchange'] record = model.create({'active': True, 'foo': "foo"}) - self.assertEqual(record.bar, "foo") - self.assertEqual(record.baz, "foo") + self.assertEqual(record.bar, "foor") + self.assertEqual(record.baz, "fooz") - # recompute 'bar' and 'baz' + # recompute 'bar' (readonly) and 'baz' (editable) record.foo = "foo1" - self.assertEqual(record.bar, "foo1") - self.assertEqual(record.baz, "foo1") + self.assertEqual(record.bar, "foo1r") + self.assertEqual(record.baz, "foo1z") # do not recompute 'baz' record.baz = "baz2" - self.assertEqual(record.bar, "foo1") + self.assertEqual(record.bar, "foo1r") self.assertEqual(record.baz, "baz2") # recompute 'baz', but do not change its value record.active = False - self.assertEqual(record.bar, "foo1") + self.assertEqual(record.bar, "foo1r") self.assertEqual(record.baz, "baz2") # recompute 'baz', but do not change its value record.foo = "foo3" - self.assertEqual(record.bar, "foo3") + self.assertEqual(record.bar, "foo3r") self.assertEqual(record.baz, "baz2") # do not recompute 'baz' record.baz = "baz4" - self.assertEqual(record.bar, "foo3") + self.assertEqual(record.bar, "foo3r") self.assertEqual(record.baz, "baz4") def test_set_new(self): model = self.env['test_new_api.compute.onchange'] - record = model.new({'active': True, 'foo': "foo"}) - self.assertEqual(record.bar, "foo") - self.assertEqual(record.baz, "foo") + record = model.new({'active': True}) + self.assertEqual(record.bar, "r") + self.assertEqual(record.baz, "z") - # recompute 'bar' and 'baz' + # recompute 'bar' (readonly) and 'baz' (editable) record.foo = "foo1" - self.assertEqual(record.bar, "foo1") - self.assertEqual(record.baz, "foo1") + self.assertEqual(record.bar, "foo1r") + self.assertEqual(record.baz, "foo1z") # do not recompute 'baz' record.baz = "baz2" - self.assertEqual(record.bar, "foo1") + self.assertEqual(record.bar, "foo1r") self.assertEqual(record.baz, "baz2") # recompute 'baz', but do not change its value record.active = False - self.assertEqual(record.bar, "foo1") + self.assertEqual(record.bar, "foo1r") self.assertEqual(record.baz, "baz2") # recompute 'baz', but do not change its value record.foo = "foo3" - self.assertEqual(record.bar, "foo3") + self.assertEqual(record.bar, "foo3r") self.assertEqual(record.baz, "baz2") # do not recompute 'baz' record.baz = "baz4" - self.assertEqual(record.bar, "foo3") + self.assertEqual(record.bar, "foo3r") self.assertEqual(record.baz, "baz4") def test_onchange(self): + # check computations of 'bar' (readonly) and 'baz' (editable) form = common.Form(self.env['test_new_api.compute.onchange']) + self.assertEqual(form.bar, "r") + self.assertEqual(form.baz, False) form.active = True + self.assertEqual(form.bar, "r") + self.assertEqual(form.baz, "z") form.foo = "foo1" - self.assertEqual(form.bar, "foo1") - self.assertEqual(form.baz, "foo1") + self.assertEqual(form.bar, "foo1r") + self.assertEqual(form.baz, "foo1z") form.baz = "baz2" - self.assertEqual(form.bar, "foo1") + self.assertEqual(form.bar, "foo1r") self.assertEqual(form.baz, "baz2") form.active = False - self.assertEqual(form.bar, "foo1") + self.assertEqual(form.bar, "foo1r") self.assertEqual(form.baz, "baz2") form.foo = "foo3" - self.assertEqual(form.bar, "foo3") + self.assertEqual(form.bar, "foo3r") self.assertEqual(form.baz, "baz2") form.active = True - self.assertEqual(form.bar, "foo3") - self.assertEqual(form.baz, "foo3") + self.assertEqual(form.bar, "foo3r") + self.assertEqual(form.baz, "foo3z") + + with form.line_ids.new() as line: + # check computation of 'bar' (readonly) + self.assertEqual(line.foo, False) + self.assertEqual(line.bar, "r") + line.foo = "foo" + self.assertEqual(line.foo, "foo") + self.assertEqual(line.bar, "foor") record = form.save() - self.assertEqual(record.bar, "foo3") - self.assertEqual(record.baz, "foo3") + self.assertEqual(record.bar, "foo3r") + self.assertEqual(record.baz, "foo3z") form = common.Form(record) - self.assertEqual(form.bar, "foo3") - self.assertEqual(form.baz, "foo3") + self.assertEqual(form.bar, "foo3r") + self.assertEqual(form.baz, "foo3z") form.foo = "foo4" - self.assertEqual(form.bar, "foo4") - self.assertEqual(form.baz, "foo4") + self.assertEqual(form.bar, "foo4r") + self.assertEqual(form.baz, "foo4z") form.baz = "baz5" - self.assertEqual(form.bar, "foo4") + self.assertEqual(form.bar, "foo4r") self.assertEqual(form.baz, "baz5") form.active = False - self.assertEqual(form.bar, "foo4") + self.assertEqual(form.bar, "foo4r") self.assertEqual(form.baz, "baz5") form.foo = "foo6" - self.assertEqual(form.bar, "foo6") + self.assertEqual(form.bar, "foo6r") self.assertEqual(form.baz, "baz5") def test_onchange_one2many(self): diff --git a/odoo/models.py b/odoo/models.py index 66b97640e36..99f45406d8b 100644 --- a/odoo/models.py +++ b/odoo/models.py @@ -6162,8 +6162,11 @@ Fields: for name in names: snapshot0.fetch(name) - # determine which field(s) should be triggered an onchange - todo = list(names or nametree) + # Determine which field(s) should be triggered an onchange. On the first + # call, 'names' only contains fields with a default. If 'self' is a new + # line in a one2many field, 'names' also contains the one2many's inverse + # field, and that field may not be in nametree. + todo = list(names) + list(nametree) if first_call else list(names) done = set() # dummy assignment: trigger invalidations on the record