Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,4 @@
from . import test_advisory_lock
from . import test_listener
from . import test_locker
from . import test_mapper

View file

@ -0,0 +1,67 @@
# Copyright 2017 Camptocamp SA
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
from unittest import mock
from odoo import api
from odoo.modules.registry import Registry
from odoo.tests import common
from odoo.addons.component.core import WorkContext
from odoo.addons.component.tests.common import TransactionComponentCase
from odoo.addons.connector.database import pg_try_advisory_lock
from odoo.addons.queue_job.exception import RetryableJobError
class TestAdvisoryLock(TransactionComponentCase):
def setUp(self):
super().setUp()
self.registry2 = Registry(common.get_db_name())
self.cr2 = self.registry2.cursor()
self.env2 = api.Environment(self.cr2, self.env.uid, {})
@self.addCleanup
def reset_cr2():
# rollback and close the cursor, and reset the environments
self.env2.reset()
self.cr2.rollback()
self.cr2.close()
def test_concurrent_lock(self):
"""2 concurrent transactions cannot acquire the same lock"""
# the lock is based on a string, a second transaction trying
# to acquire the same lock won't be able to acquire it
lock = "import_record({}, {}, {}, {})".format(
"backend.name", 1, "res.partner", "999999"
)
acquired = pg_try_advisory_lock(self.env, lock)
self.assertTrue(acquired)
# we test the base function
inner_acquired = pg_try_advisory_lock(self.env2, lock)
self.assertFalse(inner_acquired)
def test_concurrent_import_lock(self):
"""A 2nd concurrent transaction must retry"""
# the lock is based on a string, a second transaction trying
# to acquire the same lock won't be able to acquire it
lock = "import_record({}, {}, {}, {})".format(
"backend.name", 1, "res.partner", "999999"
)
backend = mock.MagicMock()
backend.env = self.env
work = WorkContext(model_name="res.partner", collection=backend)
# we test the function through a Component instance
component = work.component_by_name("base.connector")
# acquire the lock
component.advisory_lock_or_retry(lock)
# instanciate another component using a different odoo env
# hence another PG transaction
backend2 = mock.MagicMock()
backend2.env = self.env2
work2 = WorkContext(model_name="res.partner", collection=backend2)
component2 = work2.component_by_name("base.connector")
with self.assertRaises(RetryableJobError) as cm:
component2.advisory_lock_or_retry(lock, retry_seconds=3)
self.assertEqual(cm.exception.seconds, 3)

View file

@ -0,0 +1,59 @@
# Copyright 2017 Camptocamp SA
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
from unittest import mock
from odoo.tools import frozendict
from odoo.addons.component.core import Component
from odoo.addons.component.tests.common import TransactionComponentRegistryCase
from odoo.addons.component_event.components.event import skip_if
from odoo.addons.component_event.core import EventWorkContext
from odoo.addons.connector import components
class TestEventListener(TransactionComponentRegistryCase):
"""Test Connecter Listener"""
def setUp(self):
super().setUp()
self._setup_registry(self)
def test_skip_if_no_connector_export(self):
class MyEventListener(Component):
_name = "my.event.listener"
_inherit = "base.event.listener"
def on_record_create(self, record, fields=None):
assert True
class MyOtherEventListener(Component):
_name = "my.other.event.listener"
_inherit = "base.connector.listener"
@skip_if(lambda self, record, fields=None: self.no_connector_export(record))
def on_record_create(self, record, fields=None):
raise AssertionError()
self.env.context = frozendict(self.env.context, no_connector_export=True)
work = EventWorkContext(
model_name="res.users", env=self.env, components_registry=self.comp_registry
)
# get the collecter to notify the event
# we don't mind about the collection and the model here,
# the events we test are global
self.collecter = self.comp_registry["base.event.collecter"](work)
self._build_components(
components.core.BaseConnectorComponent,
components.listener.ConnectorListener,
MyEventListener,
MyOtherEventListener,
)
# collect the event and notify it
record = mock.Mock(name="record")
collected = self.collecter.collect_events("on_record_create")
self.assertEqual(2, len(collected.events))
collected.notify(record)

View file

@ -0,0 +1,44 @@
# Copyright 2018 Camptocamp SA
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl).
from unittest import mock
from odoo import api
from odoo.modules.registry import Registry
from odoo.tests import common
from odoo.addons.component.core import WorkContext
from odoo.addons.component.tests.common import TransactionComponentRegistryCase
from odoo.addons.queue_job.exception import RetryableJobError
class TestLocker(TransactionComponentRegistryCase):
def setUp(self):
super().setUp()
self.backend = mock.MagicMock(name="backend")
self.backend.env = self.env
self.registry2 = Registry(common.get_db_name())
self.cr2 = self.registry2.cursor()
self.env2 = api.Environment(self.cr2, self.env.uid, {})
self.backend2 = mock.MagicMock(name="backend2")
self.backend2.env = self.env2
@self.addCleanup
def reset_cr2():
# rollback and close the cursor, and reset the environments
self.env2.reset()
self.cr2.rollback()
self.cr2.close()
def test_lock(self):
"""Lock a record"""
main_partner = self.env.ref("base.main_partner")
work = WorkContext(model_name="res.partner", collection=self.backend)
work.component("record.locker").lock(main_partner)
main_partner2 = self.env2.ref("base.main_partner")
work2 = WorkContext(model_name="res.partner", collection=self.backend2)
locker2 = work2.component("record.locker")
with self.assertRaises(RetryableJobError):
locker2.lock(main_partner2)

View file

@ -0,0 +1,935 @@
# Copyright 2013 Camptocamp SA
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
from unittest import mock
from odoo.addons.component.core import Component, WorkContext
from odoo.addons.component.tests.common import TransactionComponentRegistryCase
from odoo.addons.connector.components.mapper import (
MapOptions,
MappingDefinition,
changed_by,
convert,
external_to_m2o,
follow_m2o_relations,
m2o_to_external,
mapping,
none,
only_create,
)
class TestMapper(TransactionComponentRegistryCase):
def setUp(self):
super().setUp()
self._setup_registry(self)
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={"name", "city"}, only_create=True)
email_def = MappingDefinition(changed_by={"email"}, only_create=False)
street_def = MappingDefinition(changed_by={"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={"name", "city"}, only_create=False)
zapp_def = MappingDefinition(changed_by={"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
# pylint: disable=R7980
class FryMapperInherit(Component):
_inherit = "fry.mapper"
@changed_by("email")
@mapping
def email(self):
pass
self._build_components(FryMapper, FryMapperInherit)
name_def = MappingDefinition(changed_by={"name", "city"}, only_create=False)
email_def = MappingDefinition(changed_by={"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 = ( # pylint: disable=consider-merging-classes-inherited
"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={"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={"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={"name", "city", "email", "street"}, only_create=False
)
street_def = MappingDefinition(changed_by=set(), only_create=True)
city_def = MappingDefinition(changed_by={"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)
# pylint: disable=W8110
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().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 # noqa: E741
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(),
{"street", "in_t", "in_f", "name", "city", "email"},
)
class TestMapperRecordsets(TransactionComponentRegistryCase):
"""Test mapper with "real" records instead of mocks"""
def setUp(self):
super().setUp()
self._setup_registry(self)
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": "Deco Addict"}
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().setUp()
self._setup_registry(self)
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": 0.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": 0.5}),
(0, 0, {"name": "2013-11-08", "rate": 40, "test": 0.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": 0.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": 0.5}),
("ABC", {"name": "2013-11-08", "rate": 40, "test": 0.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)