summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2017-08-09 15:38:29 +0200
committerChristophe Matthieu <chm@odoo.com>2017-08-30 14:38:29 +0200
commit6cf98c4c87d644928897a76b9985947ab2ebc607 (patch)
treefed1b52989b4b6731926ba080b790d0c222050ac
parent7e3f8f2140fb174c7dcd3b970862966690de4252 (diff)
[IMP] models: in `onchange`, keep track of virtual ids of new records
The x2many "create" command is now like: `(0, ref, vals)`, where `ref` is an arbitrary reference that may be used to identify a new line in the relation. The reference is returned in a similar command by the method `onchange`. `onchange` now supports self-modifying x2many fields.
-rw-r--r--odoo/addons/test_new_api/tests/test_onchange.py45
-rw-r--r--odoo/fields.py4
-rw-r--r--odoo/models.py21
3 files changed, 59 insertions, 11 deletions
diff --git a/odoo/addons/test_new_api/tests/test_onchange.py b/odoo/addons/test_new_api/tests/test_onchange.py
index a6e2bff1b35..dfeafd99805 100644
--- a/odoo/addons/test_new_api/tests/test_onchange.py
+++ b/odoo/addons/test_new_api/tests/test_onchange.py
@@ -157,6 +157,51 @@ class TestOnChange(common.TransactionCase):
}),
])
+ def test_onchange_one2many_reference(self):
+ """ test the effect of onchange() on one2many fields with line references """
+ BODY = "What a beautiful day!"
+ USER = self.env.user
+ REFERENCE = "virtualid42"
+
+ field_onchange = self.Discussion._onchange_spec()
+ self.assertEqual(field_onchange.get('name'), '1')
+ self.assertEqual(field_onchange.get('messages'), '1')
+ self.assertItemsEqual(
+ strip_prefix('messages.', field_onchange),
+ ['author', 'body', 'name', 'size', 'important'],
+ )
+
+ # modify discussion name, and check that the reference of the new line
+ # is returned
+ values = {
+ 'name': "Foo",
+ 'categories': [],
+ 'moderator': False,
+ 'participants': [],
+ 'messages': [
+ (0, REFERENCE, {
+ 'name': "[%s] %s" % ('', USER.name),
+ 'body': BODY,
+ 'author': USER.id,
+ 'size': len(BODY),
+ 'important': False,
+ }),
+ ],
+ }
+ self.env.invalidate_all()
+ result = self.Discussion.onchange(values, 'name', field_onchange)
+ self.assertIn('messages', result['value'])
+ self.assertItemsEqual(result['value']['messages'], [
+ (5,),
+ (0, REFERENCE, {
+ 'name': "[%s] %s" % ("Foo", USER.name),
+ 'body': BODY,
+ 'author': USER.name_get()[0],
+ 'size': len(BODY),
+ 'important': False,
+ }),
+ ])
+
def test_onchange_one2many_multi(self):
""" test the effect of multiple onchange methods on one2many fields """
partner = self.env.ref('base.res_partner_1')
diff --git a/odoo/fields.py b/odoo/fields.py
index 43ee8edbad1..d5638541b48 100644
--- a/odoo/fields.py
+++ b/odoo/fields.py
@@ -2028,7 +2028,7 @@ class _RelationalMulti(_Relational):
for command in value:
if isinstance(command, (tuple, list)):
if command[0] == 0:
- ids.add(comodel.new(command[2]).id)
+ ids.add(comodel.new(command[2], command[1]).id)
elif command[0] == 1:
comodel.browse(command[1]).update(command[2])
ids.add(command[1])
@@ -2085,7 +2085,7 @@ class _RelationalMulti(_Relational):
for record in value:
vals = {name: convert(record[name], record) for name, convert in converters}
if not record.id:
- result.append((0, 0, vals))
+ result.append((0, record.id.ref or 0, vals))
elif vals:
result.append((1, record.id, vals))
else:
diff --git a/odoo/models.py b/odoo/models.py
index c589d4805fd..4e0ca389651 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -168,7 +168,12 @@ class MetaModel(api.Meta):
class NewId(object):
- """ Pseudo-ids for new records. """
+ """ Pseudo-ids for new records, encapsulating an optional reference. """
+ __slots__ = ['ref']
+
+ def __init__(self, ref=None):
+ self.ref = ref
+
def __bool__(self):
return False
__nonzero__ = __bool__
@@ -4445,14 +4450,17 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
#
@api.model
- def new(self, values={}):
+ def new(self, values={}, ref=None):
""" new([values]) -> record
Return a new record instance attached to the current environment and
initialized with the provided ``value``. The record is *not* created
in database, it only exists in memory.
+
+ One can pass a reference value to identify the record among other new
+ records. The reference is encapsulated in the ``id`` of the record.
"""
- record = self.browse([NewId()])
+ record = self.browse([NewId(ref)])
record._cache.update(record._convert_to_cache(values, update=True))
if record.env.in_onchange:
@@ -4978,12 +4986,6 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
todo.append(name)
dirty.add(name)
- # At the moment, the client does not support updates on a *2many field
- # while this one is modified by the user.
- if isinstance(field_name, pycompat.string_types) and \
- self._fields[field_name].type in ('one2many', 'many2many'):
- dirty.discard(field_name)
-
# collect values from dirty fields
result['value'] = {
name: self._fields[name].convert_to_onchange(record[name], record, subfields[name])
@@ -4991,6 +4993,7 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
}
return result
+
collections.Set.register(BaseModel)
# not exactly true as BaseModel doesn't have __reversed__, index or count
collections.Sequence.register(BaseModel)