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)
 |