901 lines
23 KiB
ReStructuredText
901 lines
23 KiB
ReStructuredText
.. _migration-guide:
|
|
|
|
########################################
|
|
Migration Guide to the new Connector API
|
|
########################################
|
|
|
|
During the year 2017, the connector evolved greatly.
|
|
We can recognize three different aspect of the framework, they all have been
|
|
rewritten:
|
|
|
|
* The Job Queue API (:ref:`api-queue`)
|
|
* The Event API (:ref:`api-event`)
|
|
* The ``ConnectorUnit`` API, which is the core of the composability
|
|
of the Connector. It has been replaced by a standalone addon
|
|
called ``component``. (:ref:`api-component`)
|
|
|
|
The Connector has been splitted in different addons:
|
|
|
|
* ``queue_job`` in https://github.com/OCA/queue
|
|
* ``component`` in the same repository
|
|
* ``component_event`` in the same repository
|
|
* ``connector`` uses the 3 addons and the parts specifics to the connectors
|
|
|
|
This guide will show how to migrate from the old API to the new one.
|
|
|
|
The previous API will stay until the migration to Odoo 11.0.
|
|
|
|
.. contents:: Sections:
|
|
:local:
|
|
:backlinks: top
|
|
:depth: 2
|
|
|
|
**************
|
|
Migrating Jobs
|
|
**************
|
|
|
|
Jobs are now more integrated within the Odoo API. They are no longer
|
|
standalone functions but are applied on methods of Models. Another change is
|
|
that they have been extracted into their own addon, so obviously the Python
|
|
paths change.
|
|
|
|
Declaration of a job
|
|
====================
|
|
|
|
Before
|
|
------
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.connector.queue.job import job, related_action
|
|
from ..related_action import unwrap_binding, link
|
|
|
|
# function at module-level
|
|
@job(default_channel='root.magento')
|
|
@related_action(action=link)
|
|
def import_record(session, model_name, backend_id, magento_id, force=False):
|
|
""" Import a record from Magento """
|
|
# ...
|
|
|
|
@job(default_channel='root.magento')
|
|
@related_action(action=unwrap_binding)
|
|
def export_record(session, model_name, binding_id, fields=None):
|
|
""" Import a record from Magento """
|
|
# ...
|
|
|
|
|
|
After
|
|
-----
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.queue_job.job import job, related_action
|
|
from odoo import api, models
|
|
|
|
|
|
class MagentoBinding(models.AbstractModel):
|
|
_name = 'magento.binding'
|
|
_inherit = 'external.binding'
|
|
_description = 'Magento Binding (abstract)'
|
|
|
|
@job(default_channel='root.magento')
|
|
@related_action(action='related_action_magento_link')
|
|
@api.model
|
|
def import_record(self, backend, external_id, force=False):
|
|
""" Import a Magento record """
|
|
backend.ensure_one()
|
|
# ...
|
|
|
|
@job(default_channel='root.magento')
|
|
@related_action(action='related_action_unwrap_binding')
|
|
@api.multi
|
|
def export_record(self, fields=None):
|
|
""" Export a record on Magento """
|
|
self.ensure_one()
|
|
# ...
|
|
|
|
|
|
Observations
|
|
------------
|
|
|
|
* The job is declared on the generic abstract binding model from which all
|
|
bindings inherit. This is not a requirement, but for this kind of job it is
|
|
the perfect fit.
|
|
* ``session``, ``model_name`` and ``binding_id`` are no longer required as they
|
|
are already known in ``self``. Jobs can be used as well on ``@api.multi`` and
|
|
``@api.model``.
|
|
* Passing arguments as records is supported, in the new version of
|
|
``import_record``, no need to browse on the backend if a record was passed
|
|
* The action of a related action is now the name of a method on the
|
|
``queue.job`` model.
|
|
* If you need to share a job between several models, put them in an
|
|
AbstractModel and add an ``_inherit`` on the models.
|
|
|
|
Links
|
|
-----
|
|
|
|
* :meth:`odoo.addons.queue_job.job.job`
|
|
* :meth:`odoo.addons.queue_job.job.related_action`
|
|
|
|
|
|
Invocation of a job
|
|
===================
|
|
|
|
Before
|
|
------
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.connector.session import ConnectorSession
|
|
from .unit.export_synchronizer import export_record
|
|
|
|
|
|
class MyBinding(models.Model):
|
|
_name = 'my.binding'
|
|
_inherit = 'magento.binding'
|
|
|
|
@api.multi
|
|
def button_trigger_export_sync(self):
|
|
session = ConnectorSession.from_env(self.env)
|
|
export_record(session, binding._name, self.id, fields=['name'])
|
|
|
|
@api.multi
|
|
def button_trigger_export_async(self):
|
|
session = ConnectorSession.from_env(self.env)
|
|
export_record.delay(session, self._name, self.id,
|
|
fields=['name'], priority=12)
|
|
|
|
|
|
After
|
|
-----
|
|
|
|
.. code-block:: python
|
|
|
|
class MyBinding(models.Model):
|
|
_name = 'my.binding'
|
|
|
|
@api.multi
|
|
def button_trigger_export_sync(self):
|
|
self.export_record(fields=['name'])
|
|
|
|
@api.multi
|
|
def button_trigger_export_async(self):
|
|
self.with_delay(priority=12).export_record(fields=['name'])
|
|
|
|
Observations
|
|
------------
|
|
|
|
* No more imports are needed for the invocation
|
|
* ``ConnectorSession`` is now dead
|
|
* Arguments for the job (such as ``priority``) are no longer mixed with the
|
|
arguments passed to the method
|
|
* When the job is called on a "browse" record, the job will be executed
|
|
on an instance of this record:
|
|
|
|
.. code-block:: python
|
|
|
|
>>> binding = self.env['my.binding'].browse(1)
|
|
>>> binding.button_trigger_export_async()
|
|
|
|
In the execution of the job:
|
|
|
|
.. code-block:: python
|
|
|
|
@job
|
|
def export_record(self, fields=None):
|
|
print self
|
|
print fields
|
|
# =>
|
|
# my.binding,1
|
|
# ['name']
|
|
|
|
Links
|
|
-----
|
|
|
|
* :meth:`odoo.addons.queue_job.job.job`
|
|
* :meth:`odoo.addons.queue_job.models.base.Base.with_delay`
|
|
|
|
****************
|
|
Migrating Events
|
|
****************
|
|
|
|
Events are now handled by the ``component_event`` addon.
|
|
|
|
Triggering an event
|
|
===================
|
|
|
|
Before
|
|
------
|
|
|
|
First you had to create an :class:`~odoo.addons.connector.event.Event` instance:
|
|
|
|
.. code-block:: python
|
|
|
|
on_record_create = Event()
|
|
|
|
And then import and trigger it, passing a lot of arguments to it:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.connector.event import on_record_create
|
|
|
|
class Base(models.AbstractModel):
|
|
""" The base model, which is implicitly inherited by all models. """
|
|
_inherit = 'base'
|
|
|
|
@api.model
|
|
def create(self, vals):
|
|
record = super(Base, self).create(vals)
|
|
on_record_create.fire(self.env, self._name, record.id, vals)
|
|
return record
|
|
|
|
|
|
After
|
|
-----
|
|
|
|
.. code-block:: python
|
|
|
|
class Base(models.AbstractModel):
|
|
_inherit = 'base'
|
|
|
|
@api.model
|
|
def create(self, vals):
|
|
record = super(Base, self).create(vals)
|
|
self._event('on_record_create').notify(record, fields=vals.keys())
|
|
return record
|
|
|
|
Observations
|
|
------------
|
|
|
|
* No more imports are needed for the invocation
|
|
Only the arguments you want to pass should be passed to
|
|
:meth:`odoo.addons.component_event.components.event.CollectedEvents.notify`.
|
|
* The name of the event must start with ``'on_'``
|
|
|
|
Links
|
|
-----
|
|
|
|
* :mod:`odoo.addons.component_event.components.event`
|
|
|
|
|
|
Listening to an event
|
|
=====================
|
|
|
|
Before
|
|
------
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.connector.event import on_record_create
|
|
|
|
@on_record_create
|
|
def delay_export(env, model_name, record_id, vals):
|
|
if session.context.get('connector_no_export'):
|
|
return
|
|
fields = vals.keys()
|
|
export_record.delay(session, model_name, record_id, fields=fields)
|
|
|
|
@on_something
|
|
def do_anything(env, model_name, record_id):
|
|
# ...
|
|
|
|
After
|
|
-----
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
from odoo.addons.component_event import skip_if
|
|
|
|
class MagentoListener(Component):
|
|
_name = 'magento.event.listener'
|
|
_inherit = 'base.connector.listener'
|
|
|
|
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
|
def on_record_create(self, record, fields=None):
|
|
""" Called when a record is created """
|
|
record.with_delay().export_record(fields=fields)
|
|
|
|
def on_something(self, record):
|
|
# ...
|
|
|
|
Observations
|
|
------------
|
|
|
|
* The listeners are now components
|
|
* The name of the method is the same than the one notified in the previous
|
|
section
|
|
* A listener Component might container several listener methods
|
|
* It must inherit from ``'base.event.listener'``, or one of its descendants.
|
|
* The check of the key ``connector_no_export`` in the context can
|
|
be replaced by the decorator :func:`odoo.addons.component_event.skip_if`
|
|
|
|
Links
|
|
-----
|
|
|
|
* :mod:`odoo.addons.component_event.components.event`
|
|
|
|
|
|
Listening to an event only for some Models
|
|
==========================================
|
|
|
|
Before
|
|
------
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.connector.event import on_record_create
|
|
|
|
@on_record_create(model_names=['magento.address', 'magento.res.partner'])
|
|
def delay_export(env, model_name, record_id, vals):
|
|
if session.context.get('connector_no_export'):
|
|
return
|
|
fields = vals.keys()
|
|
export_record.delay(session, model_name, record_id, fields=fields)
|
|
|
|
After
|
|
-----
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
from odoo.addons.component_event import skip_if
|
|
|
|
class MagentoListener(Component):
|
|
_name = 'magento.event.listener'
|
|
_inherit = 'base.event.listener'
|
|
_apply_on = ['magento.address', 'magento.res.partner']
|
|
|
|
@skip_if(lambda self, record, **kwargs: self.no_connector_export(record))
|
|
def on_record_create(self, record, fields=None):
|
|
""" Called when a record is created """
|
|
record.with_delay().export_record(fields=fields)
|
|
|
|
Observations
|
|
------------
|
|
|
|
* Same than previous example but we added ``_apply_on`` on the Component.
|
|
|
|
Links
|
|
-----
|
|
|
|
* :mod:`odoo.addons.component_event.components.event`
|
|
|
|
|
|
********************
|
|
Migrating Components
|
|
********************
|
|
|
|
Backends
|
|
========
|
|
|
|
Before
|
|
------
|
|
|
|
You could have several versions for a backend:
|
|
|
|
.. code-block:: python
|
|
|
|
magento = backend.Backend('magento')
|
|
""" Generic Magento Backend """
|
|
|
|
magento1700 = backend.Backend(parent=magento, version='1.7')
|
|
""" Magento Backend for version 1.7 """
|
|
|
|
magento1900 = backend.Backend(parent=magento, version='1.9')
|
|
""" Magento Backend for version 1.9 """
|
|
|
|
|
|
|
|
It was linked with a Backend model such as:
|
|
|
|
.. code-block:: python
|
|
|
|
class MagentoBackend(models.Model):
|
|
_name = 'magento.backend'
|
|
_description = 'Magento Backend'
|
|
_inherit = 'connector.backend'
|
|
|
|
_backend_type = 'magento'
|
|
|
|
@api.model
|
|
def select_versions(self):
|
|
""" Available versions in the backend.
|
|
Can be inherited to add custom versions. Using this method
|
|
to add a version from an ``_inherit`` does not constrain
|
|
to redefine the ``version`` field in the ``_inherit`` model.
|
|
"""
|
|
return [('1.7', '1.7+')]
|
|
|
|
version = fields.Selection(selection='select_versions', required=True)
|
|
|
|
|
|
|
|
After
|
|
-----
|
|
|
|
All the :class:`backend.Backend` instances must be deleted.
|
|
|
|
And the ``_backend_type`` must be removed from the Backend model.
|
|
|
|
.. code-block:: python
|
|
|
|
class MagentoBackend(models.Model):
|
|
_name = 'magento.backend'
|
|
_description = 'Magento Backend'
|
|
_inherit = 'connector.backend'
|
|
|
|
@api.model
|
|
def select_versions(self):
|
|
""" Available versions in the backend.
|
|
Can be inherited to add custom versions. Using this method
|
|
to add a version from an ``_inherit`` does not constrain
|
|
to redefine the ``version`` field in the ``_inherit`` model.
|
|
"""
|
|
return [('1.7', '1.7+')]
|
|
|
|
version = fields.Selection(selection='select_versions', required=True)
|
|
|
|
|
|
Observations
|
|
------------
|
|
|
|
* The version is now optional in the Backend Models.
|
|
* Backend Models are based on Component's Collections:
|
|
:class:`odoo.addons.component.models.collection.Collection`
|
|
|
|
Links
|
|
-----
|
|
|
|
* :ref:`api-component`
|
|
* :class:`odoo.addons.component.models.collection.Collection`
|
|
|
|
|
|
Inheritance
|
|
===========
|
|
|
|
Before
|
|
------
|
|
|
|
You could inherit a ``ConnectorUnit`` by creating a custom Backend
|
|
version and decorating your class with it
|
|
|
|
.. code-block:: python
|
|
|
|
magento_custom = backend.Backend(parent=magento1700, version='custom')
|
|
""" Custom Magento Backend """
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
# base one
|
|
@magento
|
|
class MagentoPartnerAdapter(GenericAdapter):
|
|
# ...
|
|
|
|
# other file...
|
|
|
|
from .backend import magento_custom
|
|
|
|
# custom one
|
|
@magento_custom
|
|
class MyPartnerAdapter(MagentoPartnerAdapter):
|
|
# ...
|
|
|
|
def do_something(self):
|
|
# do it this way
|
|
|
|
You could also replace an existing class, this is mentionned in `Replace or
|
|
unregister a component`_.
|
|
|
|
|
|
After
|
|
-----
|
|
|
|
For an existing component:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class MagentoPartnerAdapter(Component):
|
|
_name = 'magento.partner.adapter'
|
|
_inherit = 'magento.adapter'
|
|
|
|
def do_something(self):
|
|
# do it this way
|
|
|
|
You can extend it:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class MyPartnerAdapter(Component):
|
|
_inherit = 'magento.partner.adapter'
|
|
|
|
def do_something(self):
|
|
# do it this way
|
|
|
|
Or create a new different component with the existing one as base:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class MyPartnerAdapter(Component):
|
|
_name = 'my.magento.partner.adapter'
|
|
_inherit = 'magento.partner.adapter'
|
|
|
|
def do_something(self):
|
|
# do it this way
|
|
|
|
|
|
Observations
|
|
------------
|
|
|
|
* The inheritance is similar to the Odoo's one (without ``_inherits``.
|
|
* All components have a Python inheritance on
|
|
:class:`~odoo.addons.component.core.AbstractComponent` or
|
|
:class:`~odoo.addons.component.core.Component`
|
|
* The names are global (as in Odoo), so you should prefix them with a namespace
|
|
* The name of the classes has no effect
|
|
* As in Odoo Models, a Component can ``_inherit`` from a list of Components
|
|
* All components implicitly inherits from a ``'base'`` component
|
|
|
|
Links
|
|
-----
|
|
|
|
* :ref:`api-component`
|
|
* :class:`odoo.addons.component.core.AbstractComponent`
|
|
|
|
|
|
|
|
Entrypoint for working with components
|
|
======================================
|
|
|
|
Before
|
|
------
|
|
|
|
Previously, when you had to work with ``ConnectorUnit`` from a Model or from a job,
|
|
depending of the Odoo version you to:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.connector.connector import ConnectorEnvironment
|
|
|
|
# ...
|
|
|
|
backend_record = session.env['magento.backend'].browse(backend_id)
|
|
env = ConnectorEnvironment(backend_record, 'magento.res.partner')
|
|
importer = env.get_connector_unit(MagentoImporter)
|
|
importer.run(magento_id, force=force)
|
|
|
|
Or:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.connector.connector import ConnectorEnvironment
|
|
from odoo.addons.connector.session import ConnectorSession
|
|
|
|
#...
|
|
|
|
backend_record = session.env['magento.backend'].browse(backend_id)
|
|
session = ConnectorSession.from_env(self.env)
|
|
env = ConnectorEnvironment(backend_record, session, 'magento.res.partner')
|
|
importer = env.get_connector_unit(MagentoImporter)
|
|
importer.run(external_id, force=force)
|
|
|
|
Which was commonly abstracted in a helper function such as:
|
|
|
|
|
|
.. code-block:: python
|
|
|
|
def get_environment(session, model_name, backend_id):
|
|
""" Create an environment to work with. """
|
|
backend_record = session.env['magento.backend'].browse(backend_id)
|
|
env = ConnectorEnvironment(backend_record, session, 'magento.res.partner')
|
|
lang = backend_record.default_lang_id
|
|
lang_code = lang.code if lang else 'en_US'
|
|
if lang_code == session.context.get('lang'):
|
|
return env
|
|
else:
|
|
with env.session.change_context(lang=lang_code):
|
|
return env
|
|
|
|
After
|
|
-----
|
|
|
|
.. code-block:: python
|
|
|
|
# ...
|
|
backend_record = self.env['magento.backend'].browse(backend_id)
|
|
with backend_record.work_on('magento.res.partner') as work:
|
|
importer = work.component(usage='record.importer')
|
|
importer.run(external_id, force=force)
|
|
|
|
Observations
|
|
------------
|
|
|
|
* And when you are already in a Component, refer to `Find a component`_
|
|
|
|
Links
|
|
-----
|
|
|
|
* :class:`~odoo.addons.component.core.WorkContext`
|
|
|
|
|
|
Find a component
|
|
================
|
|
|
|
Before
|
|
------
|
|
|
|
To find a ``ConnectorUnit``, you had to ask for given class or subclass:
|
|
|
|
.. code-block:: python
|
|
|
|
# our ConnectorUnit to find
|
|
@magento
|
|
class MagentoPartnerAdapter(GenericAdapter):
|
|
_model_name = ['magent.res.partner']
|
|
|
|
# other file...
|
|
|
|
def run(self, record):
|
|
backend_adapter = self.unit_for(GenericAdapter)
|
|
|
|
It was searched for the current model and the current backend.
|
|
|
|
After
|
|
-----
|
|
|
|
For an existing component:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class MagentoPartnerAdapter(Component):
|
|
_name = 'magento.partner.adapter'
|
|
_inherit = 'magento.adapter'
|
|
|
|
_usage = 'backend.adapter'
|
|
_collection = 'magento.backend'
|
|
_apply_on = ['res.partner']
|
|
|
|
# other file...
|
|
|
|
def run(self, record):
|
|
backend_adapter = self.component(usage='backend.adapter')
|
|
|
|
|
|
|
|
Observations
|
|
------------
|
|
|
|
* The model is compared with the ``_apply_on`` attribute
|
|
* The Backend is compared with the ``_collection`` attribute, it must
|
|
have the same name than the Backend Model.
|
|
* The ``_usage`` indicates what the purpose of the component is, and
|
|
allow to find the correct one for our task. It allow more dynamic
|
|
usages than the previous usage of a class.
|
|
* Usually, the ``_usage`` and the ``_collection`` will be ``_inherit`` 'ed from
|
|
a component (here from ``'magento.adapter``), so they won't need to be
|
|
repeated in all Components.
|
|
* A good idea is to have a base abstract Component for the Collection, then
|
|
an abstract Component for every usage::
|
|
|
|
class BaseMagentoConnectorComponent(AbstractComponent):
|
|
|
|
_name = 'base.magento.connector'
|
|
_inherit = 'base.connector'
|
|
_collection = 'magento.backend'
|
|
|
|
class MagentoBaseExporter(AbstractComponent):
|
|
""" Base exporter for Magento """
|
|
|
|
_name = 'magento.base.exporter'
|
|
_inherit = ['base.exporter', 'base.magento.connector']
|
|
_usage = 'record.exporter'
|
|
|
|
class MagentoImportMapper(AbstractComponent):
|
|
_name = 'magento.import.mapper'
|
|
_inherit = ['base.magento.connector', 'base.import.mapper']
|
|
_usage = 'import.mapper'
|
|
|
|
# ...
|
|
|
|
* The main usages are:
|
|
* import.mapper
|
|
* export.mapper
|
|
* backend.adapter
|
|
* importer
|
|
* exporter
|
|
* binder
|
|
* event.listener
|
|
* But for the importer and exporter, I recommend to use more precise ones in
|
|
the connectors: record.importer, record.exporter, batch.importer,
|
|
batch.exporter
|
|
* You are allowed to be creative with the ``_usage``, it's the key that will
|
|
allow you to find the right one component you need. (e.g. on
|
|
``stock.picking`` you need to 1. export the record, 2. export the tracking.
|
|
Then use ``record.exporter`` and ``tracking.exporter``).
|
|
* AbstractComponent will never be returned by a lookup
|
|
|
|
|
|
Links
|
|
-----
|
|
|
|
* :ref:`api-component`
|
|
* :class:`odoo.addons.component.core.AbstractComponent`
|
|
|
|
|
|
Backend Versions
|
|
================
|
|
|
|
Before
|
|
------
|
|
|
|
You could have several versions for a backend:
|
|
|
|
.. code-block:: python
|
|
|
|
magento = backend.Backend('magento')
|
|
""" Generic Magento Backend """
|
|
|
|
magento1700 = backend.Backend(parent=magento, version='1.7')
|
|
""" Magento Backend for version 1.7 """
|
|
|
|
magento1900 = backend.Backend(parent=magento, version='1.9')
|
|
""" Magento Backend for version 1.9 """
|
|
|
|
|
|
And use them for a class-level dynamic dispatch
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.magentoerpconnect.backend import magento1700, magento1900
|
|
|
|
@magento1700
|
|
class PartnerAdapter1700(GenericAdapter):
|
|
# ...
|
|
|
|
def do_something(self):
|
|
# do it this way
|
|
|
|
@magento1900
|
|
class PartnerAdapter1900(GenericAdapter):
|
|
# ...
|
|
|
|
def do_something(self):
|
|
# do it that way
|
|
|
|
|
|
After
|
|
-----
|
|
|
|
This feature has been removed, it introduced a lot of complexity (notably
|
|
regarding inheritance) for few gain. The version is now optional on the
|
|
backends and the version dispatch, if needed, should be handled manually.
|
|
|
|
In methods:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class PartnerAdapter(Component):
|
|
# ...
|
|
|
|
def do_something(self):
|
|
if self.backend_record.version == '1.7':
|
|
# do it this way
|
|
else:
|
|
# do it that way
|
|
|
|
Or with a factory:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class PartnerAdapterFactory(Component):
|
|
# ...
|
|
|
|
def get_component(self, version):
|
|
if self.backend_record.version == '1.7':
|
|
return self.component(usage='backend.adapter.1.7')
|
|
else:
|
|
return self.component(usage='backend.adapter.1.9')
|
|
|
|
Observations
|
|
------------
|
|
|
|
* None
|
|
|
|
Links
|
|
-----
|
|
|
|
* :ref:`api-component`
|
|
|
|
|
|
Replace or unregister a component
|
|
=================================
|
|
|
|
Before
|
|
------
|
|
|
|
You could replace a ``ConnectorUnit`` with the ``replace`` argument passed to
|
|
the backend decorator:
|
|
|
|
.. code-block:: python
|
|
|
|
@magento(replacing=product.ProductImportMapper)
|
|
class ProductImportMapper(product.ProductImportMapper):
|
|
|
|
|
|
After
|
|
-----
|
|
|
|
First point: this should hardly be needed now, as you can inherit a component
|
|
like Odoo Models. Still, if you need to totally replace a component by
|
|
another, let's say there is this component:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class ProductImportMapper(Component):
|
|
_name = 'magento.product.import.mapper'
|
|
_inherit = 'magento.import.mapper'
|
|
|
|
_apply_on = ['magento.product.product']
|
|
# normally the following attrs are inherited from the _inherit
|
|
_usage = 'import.mapper'
|
|
_collection = 'magento.backend'
|
|
|
|
|
|
Then you can remove the usage of the component: it will never be used:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class ProductImportMapper(Component):
|
|
_inherit = 'magento.product.import.mapper'
|
|
_usage = None
|
|
|
|
And create your own, that will be picked up instead of the base one:
|
|
|
|
.. code-block:: python
|
|
|
|
from odoo.addons.component.core import Component
|
|
|
|
class MyProductImportMapper(Component):
|
|
_name = 'my.magento.product.import.mapper'
|
|
_inherit = 'magento.import.mapper'
|
|
|
|
_apply_on = ['magento.product.product']
|
|
# normally the following attrs are inherited from the _inherit
|
|
_usage = 'import.mapper'
|
|
_collection = 'magento.backend'
|
|
|
|
|
|
Observations
|
|
------------
|
|
|
|
* None
|
|
|
|
Links
|
|
-----
|
|
|
|
* :ref:`api-component`
|
|
|
|
|
|
Various hints
|
|
=============
|
|
|
|
* The components and the jobs know how to work with Model instances,
|
|
so prefer them over ids in parameters.
|