summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaphael Collet <rco@odoo.com>2018-06-19 12:15:39 +0200
committerRaphael Collet <rco@odoo.com>2018-07-24 16:58:14 +0200
commitfdeeedc2b92fee7e18648cbcf646e2df48902972 (patch)
tree4a5b233c393b3952c76803c753c3f354efaa143b
parent3b710ed6408a9c7b92c00dec02c3c61767524c15 (diff)
[FIX] models: inverse fields in dependency order
The result of inversing several fields on a record is non-deterministic if one of those fields depend on another one.
-rw-r--r--odoo/models.py25
1 files changed, 19 insertions, 6 deletions
diff --git a/odoo/models.py b/odoo/models.py
index 4d54eaf1f9b..433a3db1632 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -3184,8 +3184,13 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
if inverse_vals:
self.modified(set(inverse_vals) - set(store_vals))
- # in case several fields use the same inverse method, call it once
- for _inv, fields in groupby(inverse_fields, attrgetter('inverse')):
+ # group fields by inverse method (to call it once), and order
+ # groups by dependence (in case they depend on each other)
+ field_groups = sorted(
+ (fields for _inv, fields in groupby(inverse_fields, attrgetter('inverse'))),
+ key=lambda fields: min(pycompat.imap(self.pool.field_sequence, fields)),
+ )
+ for fields in field_groups:
# If a field is not stored, its inverse method will probably
# write on its dependencies, which will invalidate the field
# on all records. We therefore inverse the field one record
@@ -3202,7 +3207,6 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
self.modified(set(inverse_vals) - set(store_vals))
-
# check Python constraints for inversed fields
self._validate_fields(set(inverse_vals) - set(store_vals))
@@ -3414,12 +3418,21 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
# determine which fields to protect on which records
protected = [(data['protected'], data['record']) for data in data_list]
with self.env.protecting(protected):
- # in case several fields use the same inverse method, call it once
- for _inv, fields in groupby(inversed_fields, attrgetter('inverse')):
+ # group fields by inverse method (to call it once), and order groups
+ # by dependence (in case they depend on each other)
+ field_groups = sorted(
+ (fields for _inv, fields in groupby(inversed_fields, attrgetter('inverse'))),
+ key=lambda fields: min(pycompat.imap(self.pool.field_sequence, fields)),
+ )
+ for fields in field_groups:
# determine which records to inverse for those fields
inv_names = {field.name for field in fields}
rec_vals = [
- (data['record'], data['inversed'])
+ (data['record'], {
+ name: data['inversed'][name]
+ for name in inv_names
+ if name in data['inversed']
+ })
for data in data_list
if not inv_names.isdisjoint(data['inversed'])
]