[FIX] core: first onchange on new one2many line
Consider models `M` and `L`, with a one2many field `M.l_ids` with inverse `L.m_id`. Consider also a computed field `L.foo` that depends on `L.m_id`. The field `L.foo` is not computed correctly by `onchange` on a new line in the form view of `M`: its value is forced to `False` because it has no default, and is not recomputed by `onchange` since the field `L.m_id` is never triggered an `onchange`. Modify the method `onchange` to not force fields without a default to `False`, and return all fields.
This commit is contained in:
@@ -244,7 +244,7 @@ class MultiLine(models.Model):
|
||||
|
||||
multi = fields.Many2one('test_new_api.multi', ondelete='cascade')
|
||||
name = fields.Char()
|
||||
partner = fields.Many2one('res.partner')
|
||||
partner = fields.Many2one(related='multi.partner', store=True)
|
||||
tags = fields.Many2many('test_new_api.multi.tag')
|
||||
|
||||
|
||||
|
||||
@@ -378,6 +378,19 @@ class TestOnChange(SavepointCaseWithUserDemo):
|
||||
result = Foo.onchange(values, 'value1', field_onchange)
|
||||
self.assertEqual(result['value'], {})
|
||||
|
||||
def test_onchange_one2many_first(self):
|
||||
partner = self.env['res.partner'].create({
|
||||
'name': 'X',
|
||||
'country_id': self.env.ref('base.be').id,
|
||||
})
|
||||
with common.Form(self.env['test_new_api.multi']) as form:
|
||||
form.partner = partner
|
||||
self.assertEqual(form.partner, partner)
|
||||
self.assertEqual(form.name, partner.name)
|
||||
with form.lines.new() as line:
|
||||
# the first onchange() must have computed partner
|
||||
self.assertEqual(line.partner, partner)
|
||||
|
||||
def test_onchange_one2many_value(self):
|
||||
""" test the value of the one2many field inside the onchange """
|
||||
discussion = self.env.ref('test_new_api.discussion_0')
|
||||
|
||||
+8
-1
@@ -963,7 +963,14 @@ class Field(MetaField('DummyField', (object,), {})):
|
||||
self.compute_value(recs)
|
||||
except (AccessError, MissingError):
|
||||
self.compute_value(record)
|
||||
value = env.cache.get(record, self)
|
||||
try:
|
||||
value = env.cache.get(record, self)
|
||||
except CacheMiss:
|
||||
if self.readonly:
|
||||
raise
|
||||
# fallback to null value if compute gives nothing
|
||||
value = self.convert_to_cache(False, record, validate=False)
|
||||
env.cache.set(record, self, value)
|
||||
|
||||
elif self.type == 'many2one' and self.delegate and not record.id:
|
||||
# parent record of a new record: new record, with the same
|
||||
|
||||
+10
-10
@@ -5859,8 +5859,8 @@ Fields:
|
||||
on_change attribute
|
||||
|
||||
When ``field_name`` is falsy, the method first adds default values
|
||||
to ``values``, applies onchange methods to them, and return all the
|
||||
fields in ``field_onchange``.
|
||||
to ``values``, computes the remaining fields, applies onchange
|
||||
methods to them, and return all the fields in ``field_onchange``.
|
||||
"""
|
||||
# this is for tests using `Form`
|
||||
self.flush()
|
||||
@@ -5902,11 +5902,12 @@ Fields:
|
||||
""" A dict with the values of a record, following a prefix tree. """
|
||||
__slots__ = ()
|
||||
|
||||
def __init__(self, record, tree):
|
||||
def __init__(self, record, tree, fetch=True):
|
||||
# put record in dict to include it when comparing snapshots
|
||||
super(Snapshot, self).__init__({'<record>': record, '<tree>': tree})
|
||||
for name in tree:
|
||||
self.fetch(name)
|
||||
if fetch:
|
||||
for name in tree:
|
||||
self.fetch(name)
|
||||
|
||||
def fetch(self, name):
|
||||
""" Set the value of field ``name`` from the record's value. """
|
||||
@@ -5920,6 +5921,8 @@ Fields:
|
||||
|
||||
def has_changed(self, name):
|
||||
""" Return whether a field on record has changed. """
|
||||
if name not in self:
|
||||
return True
|
||||
record = self['<record>']
|
||||
subnames = self['<tree>'][name]
|
||||
if record._fields[name].type not in ('one2many', 'many2many'):
|
||||
@@ -5977,14 +5980,11 @@ Fields:
|
||||
nametree = PrefixTree(self.browse(), field_onchange)
|
||||
|
||||
if first_call:
|
||||
names = list(nametree)
|
||||
values.update(self.default_get([
|
||||
name
|
||||
for name in names
|
||||
for name in nametree
|
||||
if name not in values
|
||||
]))
|
||||
for name in names:
|
||||
values.setdefault(name, False)
|
||||
|
||||
# prefetch x2many lines without data (for the initial snapshot)
|
||||
for name, subnames in nametree.items():
|
||||
@@ -6032,7 +6032,7 @@ Fields:
|
||||
record = self.new(initial_values, origin=self)
|
||||
|
||||
# make a snapshot based on the initial values of record
|
||||
snapshot0 = Snapshot(record, nametree)
|
||||
snapshot0 = Snapshot(record, nametree, fetch=(not first_call))
|
||||
|
||||
# store changed values in cache; also trigger recomputations based on
|
||||
# subfields (e.g., line.a has been modified, line.b is computed stored
|
||||
|
||||
Reference in New Issue
Block a user