927 lines
32 KiB
Python
927 lines
32 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Copyright 2013-2017 Camptocamp SA
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
|
|
|
|
import mock
|
|
from odoo.addons.component.core import Component, WorkContext
|
|
from odoo.addons.component.tests.common import (
|
|
ComponentRegistryCase,
|
|
TransactionComponentRegistryCase,
|
|
)
|
|
|
|
from odoo.addons.connector.components.mapper import (
|
|
MappingDefinition,
|
|
changed_by,
|
|
only_create,
|
|
convert,
|
|
follow_m2o_relations,
|
|
m2o_to_external,
|
|
external_to_m2o,
|
|
none,
|
|
MapOptions,
|
|
mapping,
|
|
)
|
|
|
|
|
|
class TestMapper(ComponentRegistryCase):
|
|
|
|
def setUp(self):
|
|
super(TestMapper, self).setUp()
|
|
self.comp_registry.load_components('connector')
|
|
|
|
def test_mapping_decorator(self):
|
|
class KifKrokerMapper(Component):
|
|
_name = 'kif.kroker.mapper'
|
|
_inherit = 'base.mapper'
|
|
|
|
@changed_by('name', 'city')
|
|
@mapping
|
|
@only_create
|
|
def name(self):
|
|
pass
|
|
|
|
@changed_by('email')
|
|
@mapping
|
|
def email(self):
|
|
pass
|
|
|
|
@changed_by('street')
|
|
@mapping
|
|
def street(self):
|
|
pass
|
|
|
|
def no_decorator(self):
|
|
pass
|
|
|
|
# build our mapper component
|
|
KifKrokerMapper._build_component(self.comp_registry)
|
|
|
|
# what mappings we expect
|
|
name_def = MappingDefinition(changed_by=set(('name', 'city')),
|
|
only_create=True)
|
|
email_def = MappingDefinition(changed_by=set(('email',)),
|
|
only_create=False)
|
|
street_def = MappingDefinition(changed_by=set(('street',)),
|
|
only_create=False)
|
|
|
|
# get our component by name in the components registry
|
|
comp = self.comp_registry['kif.kroker.mapper']
|
|
# _map_methods contains the aggregated mapping methods for a Mapper
|
|
self.assertEqual(comp._map_methods,
|
|
{'name': name_def,
|
|
'email': email_def,
|
|
'street': street_def,
|
|
})
|
|
|
|
def test_mapping_decorator_cross_classes(self):
|
|
""" Mappings should not propagate to other classes"""
|
|
class MomMapper(Component):
|
|
_name = 'mom.mapper'
|
|
_inherit = 'base.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('name', 'city')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
class ZappMapper(Component):
|
|
_name = 'zapp.mapper'
|
|
_inherit = 'base.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('email')
|
|
@only_create
|
|
@mapping
|
|
def email(self):
|
|
pass
|
|
|
|
self._build_components(MomMapper, ZappMapper)
|
|
|
|
mom_def = MappingDefinition(changed_by=set(('name', 'city')),
|
|
only_create=False)
|
|
zapp_def = MappingDefinition(changed_by=set(('email',)),
|
|
only_create=True)
|
|
|
|
comp = self.comp_registry['mom.mapper']
|
|
self.assertEqual(comp._map_methods, {'name': mom_def})
|
|
comp = self.comp_registry['zapp.mapper']
|
|
self.assertEqual(comp._map_methods, {'email': zapp_def})
|
|
|
|
def test_mapping_decorator_cumul(self):
|
|
""" Mappings should cumulate the ``super`` mappings
|
|
and the local mappings."""
|
|
class FryMapper(Component):
|
|
_name = 'fry.mapper'
|
|
_inherit = 'base.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('name', 'city')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
class FryMapperInherit(Component):
|
|
_inherit = 'fry.mapper'
|
|
|
|
@changed_by('email')
|
|
@mapping
|
|
def email(self):
|
|
pass
|
|
|
|
self._build_components(FryMapper, FryMapperInherit)
|
|
|
|
name_def = MappingDefinition(changed_by=set(('name', 'city')),
|
|
only_create=False)
|
|
email_def = MappingDefinition(changed_by=set(('email',)),
|
|
only_create=False)
|
|
|
|
comp = self.comp_registry['fry.mapper']
|
|
self.assertEqual(comp._map_methods,
|
|
{'name': name_def,
|
|
'email': email_def})
|
|
|
|
def test_mapping_decorator_cumul_changed_by(self):
|
|
""" Mappings should cumulate the changed_by fields of the
|
|
``super`` mappings and the local mappings """
|
|
class FryMapper(Component):
|
|
_name = 'fry.mapper'
|
|
_inherit = 'base.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('name', 'city')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
class FryMapperInherit(Component):
|
|
_inherit = 'fry.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('email')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
class ThirdMapper(Component):
|
|
_name = 'third.mapper'
|
|
_inherit = 'fry.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('email', 'street')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
self._build_components(FryMapper, FryMapperInherit, ThirdMapper)
|
|
|
|
name_def = MappingDefinition(changed_by=set(('name', 'city', 'email')),
|
|
only_create=False)
|
|
|
|
comp = self.comp_registry['fry.mapper']
|
|
self.assertEqual(comp._map_methods, {'name': name_def})
|
|
|
|
name_def = MappingDefinition(changed_by=set(('name', 'city',
|
|
'email', 'street')),
|
|
only_create=False)
|
|
comp = self.comp_registry['third.mapper']
|
|
self.assertEqual(comp._map_methods, {'name': name_def})
|
|
|
|
def test_several_bases_cumul(self):
|
|
class FryMapper(Component):
|
|
_name = 'fry.mapper'
|
|
_inherit = 'base.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('name', 'city')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
@only_create
|
|
@mapping
|
|
def street(self):
|
|
pass
|
|
|
|
@only_create
|
|
@mapping
|
|
def zip(self):
|
|
pass
|
|
|
|
class FarnsworthMapper(Component):
|
|
_name = 'farnsworth.mapper'
|
|
_inherit = 'base.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('email')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
@changed_by('street')
|
|
@mapping
|
|
def city(self):
|
|
pass
|
|
|
|
@mapping
|
|
def zip(self):
|
|
pass
|
|
|
|
class ThirdMapper(Component):
|
|
_name = 'third.mapper'
|
|
_inherit = ['fry.mapper', 'farnsworth.mapper']
|
|
_apply_on = 'res.users'
|
|
|
|
@changed_by('email', 'street')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
@mapping
|
|
def email(self):
|
|
pass
|
|
|
|
self._build_components(FryMapper, FarnsworthMapper, ThirdMapper)
|
|
|
|
name_def = MappingDefinition(changed_by=set(('name', 'city',
|
|
'email', 'street')),
|
|
only_create=False)
|
|
street_def = MappingDefinition(changed_by=set([]),
|
|
only_create=True)
|
|
city_def = MappingDefinition(changed_by=set(('street',)),
|
|
only_create=False)
|
|
email_def = MappingDefinition(changed_by=set([]),
|
|
only_create=False)
|
|
zip_def = MappingDefinition(changed_by=set([]),
|
|
only_create=True)
|
|
|
|
comp = self.comp_registry['third.mapper']
|
|
self.assertEqual(comp._map_methods['name'], name_def)
|
|
self.assertEqual(comp._map_methods['street'], street_def)
|
|
self.assertEqual(comp._map_methods['city'], city_def)
|
|
self.assertEqual(comp._map_methods['email'], email_def)
|
|
self.assertEqual(comp._map_methods['zip'], zip_def)
|
|
|
|
def test_mapping_record(self):
|
|
""" Map a record and check the result """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
direct = [('name', 'out_name')]
|
|
|
|
@mapping
|
|
def street(self, record):
|
|
return {'out_street': record['street'].upper()}
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': 'Guewen', 'street': 'street'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 'Guewen', 'out_street': 'STREET'}
|
|
self.assertEqual(map_record.values(), expected)
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_mapping_record_on_create(self):
|
|
""" Map a record and check the result for creation of record """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.users'
|
|
|
|
direct = [('name', 'out_name')]
|
|
|
|
@mapping
|
|
def street(self, record):
|
|
return {'out_street': record['street'].upper()}
|
|
|
|
@only_create
|
|
@mapping
|
|
def city(self, record):
|
|
return {'out_city': 'city'}
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': 'Guewen', 'street': 'street'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 'Guewen', 'out_street': 'STREET'}
|
|
self.assertEqual(map_record.values(), expected)
|
|
expected = {'out_name': 'Guewen',
|
|
'out_street': 'STREET',
|
|
'out_city': 'city'}
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_mapping_update(self):
|
|
""" Force values on a map record """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [('name', 'out_name')]
|
|
|
|
@mapping
|
|
def street(self, record):
|
|
return {'out_street': record['street'].upper()}
|
|
|
|
@only_create
|
|
@mapping
|
|
def city(self, record):
|
|
return {'out_city': 'city'}
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': 'Guewen', 'street': 'street'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
map_record.update({'test': 1}, out_city='forced')
|
|
expected = {'out_name': 'Guewen',
|
|
'out_street': 'STREET',
|
|
'out_city': 'forced',
|
|
'test': 1}
|
|
self.assertEqual(map_record.values(), expected)
|
|
expected = {'out_name': 'Guewen',
|
|
'out_street': 'STREET',
|
|
'out_city': 'forced',
|
|
'test': 1}
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_finalize(self):
|
|
""" Inherit finalize to modify values """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [('name', 'out_name')]
|
|
|
|
def finalize(self, record, values):
|
|
result = super(MyMapper, self).finalize(record, values)
|
|
result['test'] = 'abc'
|
|
return result
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': 'Guewen',
|
|
'street': 'street'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 'Guewen',
|
|
'test': 'abc'}
|
|
self.assertEqual(map_record.values(), expected)
|
|
expected = {'out_name': 'Guewen',
|
|
'test': 'abc'}
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_some_fields(self):
|
|
""" Map only a selection of fields """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [('name', 'out_name'),
|
|
('street', 'out_street'),
|
|
]
|
|
|
|
@changed_by('country')
|
|
@mapping
|
|
def country(self, record):
|
|
return {'country': 'country'}
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': 'Guewen',
|
|
'street': 'street',
|
|
'country': 'country'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 'Guewen',
|
|
'country': 'country'}
|
|
self.assertEqual(map_record.values(fields=['name', 'country']),
|
|
expected)
|
|
expected = {'out_name': 'Guewen',
|
|
'country': 'country'}
|
|
self.assertEqual(map_record.values(for_create=True,
|
|
fields=['name', 'country']),
|
|
expected)
|
|
|
|
def test_mapping_modifier(self):
|
|
""" Map a direct record with a modifier function """
|
|
|
|
def do_nothing(field):
|
|
def transform(self, record, to_attr):
|
|
return record[field]
|
|
return transform
|
|
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [(do_nothing('name'), 'out_name')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': 'Guewen'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 'Guewen'}
|
|
self.assertEqual(map_record.values(), expected)
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_mapping_direct_property(self):
|
|
""" Map a direct record with 'direct' being a property """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
@property
|
|
def direct(self):
|
|
return [('name', 'out_name')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': 'Foo'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 'Foo'}
|
|
self.assertEqual(map_record.values(), expected)
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_mapping_convert(self):
|
|
""" Map a direct record with the convert modifier function """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [(convert('name', int), 'out_name')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': '300'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 300}
|
|
self.assertEqual(map_record.values(), expected)
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_mapping_modifier_none(self):
|
|
""" Pipeline of modifiers """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [(none('in_f'), 'out_f'),
|
|
(none('in_t'), 'out_t')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'in_f': False, 'in_t': True}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_f': None, 'out_t': True}
|
|
self.assertEqual(map_record.values(), expected)
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_mapping_modifier_pipeline(self):
|
|
""" Pipeline of modifiers """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [(none(convert('in_f', bool)), 'out_f'),
|
|
(none(convert('in_t', bool)), 'out_t')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'in_f': 0, 'in_t': 1}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_f': None, 'out_t': True}
|
|
self.assertEqual(map_record.values(), expected)
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_modifier_import_filter_field(self):
|
|
""" A direct mapping with a modifier must still be considered
|
|
from the list of fields
|
|
"""
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [('field', 'field2'),
|
|
('no_field', 'no_field2'),
|
|
(convert('name', int), 'out_name')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': '300', 'field': 'value', 'no_field': 'no_value'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 300, 'field2': 'value'}
|
|
self.assertEqual(map_record.values(fields=['field', 'name']), expected)
|
|
self.assertEqual(map_record.values(for_create=True,
|
|
fields=['field', 'name']), expected)
|
|
|
|
def test_modifier_export_filter_field(self):
|
|
""" A direct mapping with a modifier on an export mapping """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.export.mapper'
|
|
|
|
direct = [('field', 'field2'),
|
|
('no_field', 'no_field2'),
|
|
(convert('name', int), 'out_name')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'name': '300', 'field': 'value', 'no_field': 'no_value'}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'out_name': 300, 'field2': 'value'}
|
|
self.assertEqual(map_record.values(fields=['field', 'name']), expected)
|
|
self.assertEqual(map_record.values(for_create=True,
|
|
fields=['field', 'name']), expected)
|
|
|
|
def test_mapping_custom_option(self):
|
|
""" Usage of custom options in mappings """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
@mapping
|
|
def any(self, record):
|
|
if self.options.custom:
|
|
res = True
|
|
else:
|
|
res = False
|
|
return {'res': res}
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'res': True}
|
|
self.assertEqual(map_record.values(custom=True), expected)
|
|
|
|
def test_mapping_custom_option_not_defined(self):
|
|
""" Usage of custom options not defined raise AttributeError """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
@mapping
|
|
def any(self, record):
|
|
if self.options.custom is None:
|
|
res = True
|
|
else:
|
|
res = False
|
|
return {'res': res}
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {}
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'res': True}
|
|
self.assertEqual(map_record.values(), expected)
|
|
|
|
def test_map_options(self):
|
|
""" Test MapOptions """
|
|
options = MapOptions({'xyz': 'abc'}, k=1)
|
|
options.l = 2
|
|
self.assertEqual(options['xyz'], 'abc')
|
|
self.assertEqual(options['k'], 1)
|
|
self.assertEqual(options['l'], 2)
|
|
self.assertEqual(options.xyz, 'abc')
|
|
self.assertEqual(options.k, 1)
|
|
self.assertEqual(options.l, 2)
|
|
self.assertEqual(options['undefined'], None)
|
|
self.assertEqual(options.undefined, None)
|
|
|
|
def test_changed_by_fields(self):
|
|
""" Test attribute ``_changed_by_fields`` on Mapper."""
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.export.mapper'
|
|
|
|
direct = [('street', 'out_street'),
|
|
(none('in_t'), 'out_t'),
|
|
(none(convert('in_f', bool)), 'out_f')]
|
|
|
|
@changed_by('name', 'city')
|
|
@mapping
|
|
def name(self):
|
|
pass
|
|
|
|
@changed_by('email')
|
|
@mapping
|
|
def email(self):
|
|
pass
|
|
|
|
def no_decorator(self):
|
|
pass
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
work = mock.MagicMock(name='WorkContext()')
|
|
mapper = self.comp_registry['my.mapper'](work)
|
|
|
|
self.assertEqual(
|
|
mapper.changed_by_fields(),
|
|
set(['street', 'in_t', 'in_f', 'name', 'city', 'email']))
|
|
|
|
|
|
class TestMapperRecordsets(TransactionComponentRegistryCase):
|
|
""" Test mapper with "real" records instead of mocks """
|
|
|
|
def setUp(self):
|
|
super(TestMapperRecordsets, self).setUp()
|
|
self.comp_registry.load_components('connector')
|
|
|
|
backend_record = mock.Mock()
|
|
backend_record.env = self.env
|
|
self.work = WorkContext(model_name='res.partner',
|
|
collection=backend_record,
|
|
components_registry=self.comp_registry)
|
|
|
|
def test_mapping_modifier_follow_m2o_relations(self):
|
|
""" Map with the follow_m2o_relations modifier """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
|
|
direct = [
|
|
(follow_m2o_relations('parent_id.name'), 'parent_name'),
|
|
]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
partner = self.env.ref('base.res_partner_address_4')
|
|
mapper = self.comp_registry['my.mapper'](self.work)
|
|
map_record = mapper.map_record(partner)
|
|
expected = {'parent_name': 'Agrolait'}
|
|
self.assertEqual(map_record.values(), expected)
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
|
|
class TestMapperBinding(TransactionComponentRegistryCase):
|
|
""" Test Mapper with Bindings"""
|
|
|
|
def setUp(self):
|
|
super(TestMapperBinding, self).setUp()
|
|
self.comp_registry.load_components('connector')
|
|
|
|
backend_record = mock.Mock()
|
|
backend_record.env = self.env
|
|
backend_record._name = 'my.collection'
|
|
self.work = WorkContext(model_name='res.partner',
|
|
collection=backend_record,
|
|
components_registry=self.comp_registry)
|
|
|
|
self.country_binder = mock.MagicMock(name='country_binder')
|
|
self.country_binder.return_value = self.country_binder
|
|
self.country_binder._name = 'test.binder'
|
|
self.country_binder._inherit = 'base.binder'
|
|
self.country_binder.apply_on_models = ['res.country']
|
|
self.country_binder._usage = 'binder'
|
|
self.country_binder._collection = 'my.collection'
|
|
self.country_binder._abstract = False
|
|
self.comp_registry['test.binder'] = self.country_binder
|
|
|
|
def test_mapping_m2o_to_external(self):
|
|
""" Map a direct record with the m2o_to_external modifier function """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.partner'
|
|
|
|
direct = [(m2o_to_external('country_id'), 'country')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
partner = self.env.ref('base.main_partner')
|
|
partner.write({'country_id': self.env.ref('base.ch').id})
|
|
self.country_binder.to_external.return_value = 10
|
|
|
|
mapper = self.comp_registry['my.mapper'](self.work)
|
|
map_record = mapper.map_record(partner)
|
|
self.assertEqual(map_record.values(), {'country': 10})
|
|
self.country_binder.to_external.assert_called_once_with(
|
|
partner.country_id.id, wrap=False)
|
|
|
|
def test_mapping_backend_to_m2o(self):
|
|
""" Map a direct record with the backend_to_m2o modifier function """
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.partner'
|
|
|
|
direct = [(external_to_m2o('country'), 'country_id')]
|
|
|
|
self._build_components(MyMapper)
|
|
|
|
record = {'country': 10}
|
|
ch = self.env.ref('base.ch')
|
|
self.country_binder.to_internal.return_value = ch
|
|
mapper = self.comp_registry['my.mapper'](self.work)
|
|
map_record = mapper.map_record(record)
|
|
self.assertEqual(map_record.values(), {'country_id': ch.id})
|
|
self.country_binder.to_internal.assert_called_once_with(
|
|
10, unwrap=False)
|
|
|
|
def test_mapping_record_children_no_map_child(self):
|
|
""" Map a record with children, using default MapChild """
|
|
# we need these components which make the 'link' between
|
|
# the main mapper and the line mapper
|
|
|
|
class LineMapper(Component):
|
|
_name = 'line.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.currency.rate'
|
|
|
|
direct = [('name', 'name')]
|
|
|
|
@mapping
|
|
def price(self, record):
|
|
return {'rate': record['rate'] * 2}
|
|
|
|
@only_create
|
|
@mapping
|
|
def discount(self, record):
|
|
return {'test': .5}
|
|
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.currency'
|
|
|
|
direct = [('name', 'name')]
|
|
|
|
children = [('lines', 'line_ids', 'res.currency.rate')]
|
|
|
|
self._build_components(LineMapper, MyMapper)
|
|
|
|
record = {'name': 'SO1',
|
|
'lines': [{'name': '2013-11-07',
|
|
'rate': 10},
|
|
{'name': '2013-11-08',
|
|
'rate': 20}]}
|
|
mapper = self.comp_registry['my.mapper'](self.work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'name': 'SO1',
|
|
'line_ids': [(0, 0, {'name': '2013-11-07',
|
|
'rate': 20}),
|
|
(0, 0, {'name': '2013-11-08',
|
|
'rate': 40})]
|
|
}
|
|
self.assertEqual(map_record.values(), expected)
|
|
expected = {'name': 'SO1',
|
|
'line_ids': [(0, 0, {'name': '2013-11-07',
|
|
'rate': 20,
|
|
'test': .5}),
|
|
(0, 0, {'name': '2013-11-08',
|
|
'rate': 40,
|
|
'test': .5})]
|
|
}
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_mapping_record_children(self):
|
|
""" Map a record with children, using defined MapChild """
|
|
# we need these components which make the 'link' between
|
|
# the main mapper and the line mapper
|
|
|
|
class LineMapper(Component):
|
|
_name = 'line.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.currency.rate'
|
|
|
|
direct = [('name', 'name')]
|
|
|
|
@mapping
|
|
def price(self, record):
|
|
return {'rate': record['rate'] * 2}
|
|
|
|
@only_create
|
|
@mapping
|
|
def discount(self, record):
|
|
return {'test': .5}
|
|
|
|
class LineImportMapChild(Component):
|
|
_name = 'line.map.child.import'
|
|
_inherit = 'base.map.child.import'
|
|
_apply_on = 'res.currency.rate'
|
|
|
|
def format_items(self, items_values):
|
|
return [('ABC', values) for values in items_values]
|
|
|
|
class MyMapper(Component):
|
|
_name = 'my.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.currency'
|
|
|
|
direct = [('name', 'name')]
|
|
|
|
children = [('lines', 'line_ids', 'res.currency.rate')]
|
|
|
|
self._build_components(LineMapper, LineImportMapChild, MyMapper)
|
|
|
|
record = {'name': 'SO1',
|
|
'lines': [{'name': '2013-11-07',
|
|
'rate': 10},
|
|
{'name': '2013-11-08',
|
|
'rate': 20}]}
|
|
mapper = self.comp_registry['my.mapper'](self.work)
|
|
map_record = mapper.map_record(record)
|
|
expected = {'name': 'SO1',
|
|
'line_ids': [('ABC', {'name': '2013-11-07',
|
|
'rate': 20}),
|
|
('ABC', {'name': '2013-11-08',
|
|
'rate': 40})]
|
|
}
|
|
self.assertEqual(map_record.values(), expected)
|
|
expected = {'name': 'SO1',
|
|
'line_ids': [('ABC', {'name': '2013-11-07',
|
|
'rate': 20,
|
|
'test': .5}),
|
|
('ABC', {'name': '2013-11-08',
|
|
'rate': 40,
|
|
'test': .5})]
|
|
}
|
|
self.assertEqual(map_record.values(for_create=True), expected)
|
|
|
|
def test_mapping_record_children_void(self):
|
|
""" Map a record with children, using defined MapChild """
|
|
|
|
class LineMapper(Component):
|
|
_name = 'line.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.currency.rate'
|
|
|
|
@mapping
|
|
def price(self, record):
|
|
rate = record.get('rate')
|
|
if rate and rate < 40:
|
|
return {'rate': record['rate'] * 2}
|
|
|
|
class SaleLineImportMapChild(Component):
|
|
_name = 'sale.line.mapper'
|
|
_inherit = 'base.map.child.import'
|
|
_apply_on = 'res.currency.rate'
|
|
|
|
def format_items(self, items_values):
|
|
return [('ABC', values) for values in items_values]
|
|
|
|
class ObjectMapper(Component):
|
|
_name = 'currency.mapper'
|
|
_inherit = 'base.import.mapper'
|
|
_apply_on = 'res.currency'
|
|
|
|
direct = [('name', 'name')]
|
|
|
|
children = [('lines', 'line_ids', 'res.currency.rate')]
|
|
|
|
self._build_components(
|
|
ObjectMapper,
|
|
SaleLineImportMapChild,
|
|
LineMapper
|
|
)
|
|
|
|
# Test with an excluded child record
|
|
record = {
|
|
'name': 'SO1',
|
|
'lines': [
|
|
{'rate': 10},
|
|
{'rate': 20},
|
|
{'rate': 30},
|
|
{'rate': 40},
|
|
]
|
|
}
|
|
mapper = self.comp_registry['currency.mapper'](self.work)
|
|
map_record = mapper.map_record(record)
|
|
|
|
expected = {
|
|
'name': 'SO1',
|
|
'line_ids': [
|
|
('ABC', {'rate': 20}),
|
|
('ABC', {'rate': 40}),
|
|
('ABC', {'rate': 60}),
|
|
]
|
|
}
|
|
self.assertEqual(map_record.values(), expected)
|