Code Overview¶
Here is an overview of some of the concepts in the framework.
As an example, we’ll see the steps for exporting an invoice to Magento. The steps won’t show all the steps, but a simplified excerpt of a real use case exposing the main ideas.
Backends¶
All start with the declaration of the Backend
:
import openerp.addons.connector.backend as backend
magento = backend.Backend('magento')
""" Generic Magento Backend """
magento1700 = backend.Backend(parent=magento, version='1.7')
""" Magento Backend for version 1.7 """
As you see, Magento is the parent of Magento 1.7. We can define a hierarchy of backends.
Bindings¶
The binding
is the link between an Odoo record and an external
record. There is no forced implementation for the bindings
. The most
straightforward techniques are: storing the external ID in the same
model (account.invoice
), in a new link model or in a new link model
which _inherits
account.invoice
. Here we choose the latter
solution:
class MagentoAccountInvoice(models.Model):
_name = 'magento.account.invoice'
_inherits = {'account.invoice': 'openerp_id'}
_description = 'Magento Invoice'
backend_id = fields.Many2one(comodel_name='magento.backend', string='Magento Backend', required=True, ondelete='restrict')
openerp_id = fields.Many2one(comodel_name='account.invoice', string='Invoice', required=True, ondelete='cascade')
magento_id = fields.Char(string='ID on Magento') # fields.char because 0 is a valid Magento ID
sync_date = fields.Datetime(string='Last synchronization date')
magento_order_id = fields.Many2one(comodel_name='magento.sale.order', string='Magento Sale Order', ondelete='set null')
# we can also store additional data related to the Magento Invoice
Session¶
The framework uses ConnectorSession
objects to store the cr
, uid
and context
in a
openerp.api.Environment
. So from a session, we can access to
the usual self.env
(new API) or self.pool
(old API).
Events¶
We can create Event
on which we’ll be able
to subscribe consumers. The connector already integrates the most
generic ones:
on_record_create()
,
on_record_write()
,
on_record_unlink()
When we create a magento.account.invoice
record, we want to delay a
job to export it to Magento, so we subscribe a new consumer on
on_record_create()
:
@on_record_create(model_names='magento.account.invoice')
def delay_export_account_invoice(session, model_name, record_id):
"""
Delay the job to export the magento invoice.
"""
export_invoice.delay(session, model_name, record_id)
On the last line, you can notice an export_invoice.delay
. We’ll
discuss about that in Jobs
Jobs¶
A Job
is a task to execute later.
In that case: create the invoice on Magento.
Any function decorated with job()
can
be posted in the queue of jobs using a delay()
function
and will be run as soon as possible:
@job
def export_invoice(session, model_name, record_id):
""" Export a validated or paid invoice. """
invoice = session.env[model_name].browse(record_id)
backend_id = invoice.backend_id.id
env = get_environment(session, model_name, backend_id)
invoice_exporter = env.get_connector_unit(MagentoInvoiceSynchronizer)
return invoice_exporter.run(record_id)
There is a few things happening there:
- We find the backend on which we’ll export the invoice.
- We build an
Environment
with the currentConnectorSession
, the model we work with and the target backend. - We get the
ConnectorUnit
responsible for the work usingget_connector_unit()
(according the backend version and the model) and we callrun()
on it.
ConnectorUnit¶
These are all classes which are responsible for a specific work.
The main types of ConnectorUnit
are
(the implementation of theses classes belongs to the connectors):
Thebinders
give the external ID or Odoo ID from respectively an Odoo ID or an external ID. A default implementation is available.
Themappers
transform a external record into an Odoo record or conversely.
Theadapters
implements the discussion with thebackend's
APIs. They usually adapt their APIs to a common interface (CRUD).
Thesynchronizers
are the main piece of a synchronization. They define the flow of a synchronization and use the otherConnectorUnit
(the ones above or specific ones).
For the export of the invoice, we just need an adapter
and a
synchronizer
(the real implementation is more complete):
@magento
class AccountInvoiceAdapter(GenericAdapter):
""" Backend Adapter for the Magento Invoice """
_model_name = 'magento.account.invoice'
_magento_model = 'sales_order_invoice'
def create(self, order_increment_id, items, comment, email, include_comment):
""" Create a record on the external system """
return self._call('%s.create' % self._magento_model,
[order_increment_id, items, comment,
email, include_comment])
@magento
class MagentoInvoiceSynchronizer(Exporter):
""" Export invoices to Magento """
_model_name = ['magento.account.invoice']
def _export_invoice(self, magento_id, lines_info, mail_notification):
# use the ``backend adapter`` to create the invoice
return self.backend_adapter.create(magento_id, lines_info,
_("Invoice Created"),
mail_notification, False)
def _get_lines_info(self, invoice):
[...]
def run(self, binding_id):
""" Run the job to export the validated/paid invoice """
invoice = self.model.browse(binding_id)
magento_order = invoice.magento_order_id
magento_id = self._export_invoice(magento_order.magento_id, lines_info, True)
# use the ``binder`` to write the external ID
self.binder.bind(magento_id, binding_id)