[IMP] core: import-compatible export of m2m fields

When performing an import-compatible export, m2m values would be
exported as a record per cell unless the `id` subfield was the first
to be exported. Which is not the case when using the export UI (as it
always adds the field itself before any subfield). This would make the
m2m not actually export-compatible in most cases.

* export m2m "display name" in an import compatible format as well
* re-prioritise exporting xids when there are multiple m2m exports in
  import-compatible mode
* never fall back on the o2m / non-import-compatible m2m path for m2ms
  in import-compatible mode

Note: if multiple m2m fields are specified only one of them gets filled.

Task 2065428

closes odoo/odoo#37407

Signed-off-by: Xavier Morel (xmo) <xmo@odoo.com>
Co-authored-by: Ravi Singh <ras@odoo.com>
Co-authored-by: Mohammed Shekha <msh@odoo.com>
Co-authored-by: Xavier Morel <xmo@odoo.com>
This commit is contained in:
Ravi Singh
2020-02-21 12:12:19 +00:00
committed by Xavier Morel
co-authored by Mohammed Shekha Xavier Morel
parent 3ecea2c934
commit 574d7f0d4c
2 changed files with 41 additions and 11 deletions
+15 -3
View File
@@ -606,18 +606,20 @@ class test_m2m(CreatorCase):
def test_single_subfield(self):
self.assertEqual(
self.export([(0, False, {'value': 42})],
fields=['value', 'value/value']),
fields=['value', 'value/value'],
context={'import_compat': False}),
[[u'export.many2many.other:42', 42]])
def test_integrate_one_in_parent(self):
self.assertEqual(
self.export([(0, False, {'value': 42})],
fields=['const', 'value/value']),
fields=['const', 'value/value'],
context={'import_compat': False}),
[[4, 42]])
def test_multiple_records(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value/value']),
self.export(self.commands, fields=['const', 'value/value'], context={'import_compat': False}),
[
[4, 4],
[u'', 42],
@@ -629,6 +631,12 @@ class test_m2m(CreatorCase):
def test_multiple_records_name(self):
self.assertEqual(
self.export(self.commands, fields=['const', 'value']),
[
[4, 'export.many2many.other:4,export.many2many.other:42,export.many2many.other:36,export.many2many.other:4,export.many2many.other:13'],
])
self.assertEqual(
self.export(self.commands, fields=['const', 'value'], context={'import_compat': False}),
[
[4, u'export.many2many.other:4'],
['', u'export.many2many.other:42'],
@@ -664,6 +672,10 @@ class test_m2m(CreatorCase):
r.with_context(import_compat=True)._export_rows([['value', 'id']]),
[['__t__.record000,__t__.record001,__t__.record010,__t__.record011,__t__.record100']]
)
self.assertEqual(
r.with_context(import_compat=True)._export_rows([['value'], ['value', 'id']]),
[['', '__t__.record000,__t__.record001,__t__.record010,__t__.record011,__t__.record100']]
)
self.assertEqual(
r.with_context(import_compat=False)._export_rows([['id'], ['value', 'id'], ['value', 'value']]),
+26 -8
View File
@@ -22,6 +22,7 @@
"""
import collections
import contextlib
import datetime
import dateutil
import fnmatch
@@ -838,18 +839,35 @@ class BaseModel(MetaModel('DummyModel', (object,), {'_register': False})):
current[i] = field.convert_to_export(value, record)
else:
primary_done.append(name)
# in import_compat mode, m2m should always be exported as
# a comma-separated list of xids in a single cell
if import_compatible and field.type == 'many2many' and len(path) > 1 and path[1] == 'id':
xml_ids = [xid for _, xid in value.__ensure_xml_id()]
current[i] = ','.join(xml_ids) or False
continue
# recursively export the fields that follow name; use
# 'display_name' where no subfield is exported
fields2 = [(p[1:] or ['display_name'] if p and p[0] == name else [])
for p in fields]
# in import_compat mode, m2m should always be exported as
# a comma-separated list of xids or names in a single cell
if import_compatible and field.type == 'many2many':
index = None
# find out which subfield the user wants & its
# location as we might not get it as the first
# column we encounter
for name in ['id', 'name', 'display_name']:
with contextlib.suppress(ValueError):
index = fields2.index([name])
break
if index is None:
# not found anything, assume we just want the
# name_get in the first column
name = None
index = i
if name == 'id':
xml_ids = [xid for _, xid in value.__ensure_xml_id()]
current[index] = ','.join(xml_ids) or False
else:
current[index] = field.convert_to_export(value, record) or False
continue
lines2 = value._export_rows(fields2, _is_toplevel_call=False)
if lines2:
# merge first line with record's main line