diff options
| author | Raphael Collet <rco@odoo.com> | 2017-08-09 15:38:29 +0200 |
|---|---|---|
| committer | Christophe Matthieu <chm@odoo.com> | 2017-08-30 14:38:29 +0200 |
| commit | 6cf98c4c87d644928897a76b9985947ab2ebc607 (patch) | |
| tree | fed1b52989b4b6731926ba080b790d0c222050ac /odoo | |
| parent | 7e3f8f2140fb174c7dcd3b970862966690de4252 (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.
Diffstat (limited to 'odoo')
| -rw-r--r-- | odoo/addons/test_new_api/tests/test_onchange.py | 45 | ||||
| -rw-r--r-- | odoo/fields.py | 4 | ||||
| -rw-r--r-- | odoo/models.py | 21 |
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) |
