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 6cb379478cd..b55129e6ac5 100644
--- a/odoo/addons/test_new_api/models/test_new_api.py
+++ b/odoo/addons/test_new_api/models/test_new_api.py
@@ -457,12 +457,27 @@ class Move(models.Model):
quantity = fields.Integer(compute='_compute_quantity', store=True)
tag_id = fields.Many2one('test_new_api.multi.tag')
tag_name = fields.Char(related='tag_id.name')
+ tag_repeat = fields.Integer()
+ tag_string = fields.Char(compute='_compute_tag_string')
+
+ # This field can fool the ORM during onchanges! When editing a payment
+ # record, modified fields are assigned to the parent record. When
+ # determining the dependent records, the ORM looks for the payments related
+ # to this record by the field `move_id`. As this field is an inverse of
+ # `move_id`, it uses it. If that field was not initialized properly, the
+ # ORM determines its value to be... empty (instead of the payment record.)
+ payment_ids = fields.One2many('test_new_api.payment', 'move_id')
@api.depends('line_ids.quantity')
def _compute_quantity(self):
for record in self:
record.quantity = sum(line.quantity for line in record.line_ids)
+ @api.depends('tag_name', 'tag_repeat')
+ def _compute_tag_string(self):
+ for record in self:
+ record.tag_string = (record.tag_name or "") * record.tag_repeat
+
class MoveLine(models.Model):
_name = 'test_new_api.move_line'
diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py
index 424a88c71f9..0d5b94495b0 100644
--- a/odoo/addons/test_new_api/tests/test_onchange.py
+++ b/odoo/addons/test_new_api/tests/test_onchange.py
@@ -548,6 +548,8 @@ class TestOnChange(SavepointCaseWithUserDemo):
+
+
""",
})
@@ -556,19 +558,32 @@ class TestOnChange(SavepointCaseWithUserDemo):
# assigning 'tag_id' should modify 'move_id.tag_id' accordingly, which
# should in turn recompute `move.tag_name` and `tag_name`
form = Form(self.env['test_new_api.payment'], view)
+ self.assertEqual(form.tag_name, False)
form.tag_id = foo
self.assertEqual(form.tag_name, 'Foo')
+ self.assertEqual(form.tag_string, '')
+ form.tag_repeat = 2
+ self.assertEqual(form.tag_name, 'Foo')
+ self.assertEqual(form.tag_string, 'FooFoo')
payment = form.save()
self.assertEqual(payment.tag_id, foo)
self.assertEqual(payment.tag_name, 'Foo')
+ self.assertEqual(payment.tag_repeat, 2)
+ self.assertEqual(payment.tag_string, 'FooFoo')
with Form(payment, view) as form:
form.tag_id = bar
self.assertEqual(form.tag_name, 'Bar')
+ self.assertEqual(form.tag_string, 'BarBar')
+ form.tag_repeat = 3
+ self.assertEqual(form.tag_name, 'Bar')
+ self.assertEqual(form.tag_string, 'BarBarBar')
self.assertEqual(payment.tag_id, bar)
self.assertEqual(payment.tag_name, 'Bar')
+ self.assertEqual(payment.tag_repeat, 3)
+ self.assertEqual(payment.tag_string, 'BarBarBar')
class TestComputeOnchange(common.TransactionCase):
diff --git a/odoo/fields.py b/odoo/fields.py
index f916a741b19..1ba2fb16d66 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -1122,8 +1122,10 @@ class Field(MetaField('DummyField', (object,), {})):
for name, value in record._cache.items()
if is_inherited_field(name)
})
- value = self.convert_to_cache(parent, record)
- env.cache.set(record, self, value)
+ # in case the delegate field has inverse one2many fields, this
+ # updates the inverse fields as well
+ record._update_cache({self.name: parent}, validate=False)
+ value = env.cache.get(record, self)
else:
# non-stored field or stored field on new record: default value
diff --git a/odoo/models.py b/odoo/models.py
index dda5837c306..8c519fdc52f 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -6395,13 +6395,22 @@ Fields:
initial_values = dict(values, **dict.fromkeys(names, False))
# do not force delegate fields to False
- for name in self._inherits.values():
- if not initial_values.get(name, True):
- initial_values.pop(name)
+ for parent_name in self._inherits.values():
+ if not initial_values.get(parent_name, True):
+ initial_values.pop(parent_name)
# create a new record with values
record = self.new(initial_values, origin=self)
+ # make parent records match with the form values; this ensures that
+ # computed fields on parent records have all their dependencies at
+ # their expected value
+ for name in initial_values:
+ field = self._fields.get(name)
+ if field and field.inherited:
+ parent_name, name = field.related.split('.', 1)
+ record[parent_name]._update_cache({name: record[name]})
+
# make a snapshot based on the initial values of record
snapshot0 = Snapshot(record, nametree, fetch=(not first_call))