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.
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.
The binding is the link between an OpenERP 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 magento_account_invoice(orm.Model):
_name = 'magento.account.invoice'
_inherits = {'account.invoice': 'openerp_id'}
_description = 'Magento Invoice'
_columns = {
'backend_id': fields.many2one('magento.backend', 'Magento Backend', required=True, ondelete='restrict'),
'openerp_id': fields.many2one('account.invoice', string='Invoice', required=True, ondelete='cascade'),
'magento_id': fields.char('ID on Magento'), # fields.char because 0 is a valid Magento ID
'sync_date': fields.datetime('Last synchronization date'),
'magento_order_id': fields.many2one('magento.sale.order', string='Magento Sale Order', ondelete='set null'),
# we can also store additional data related to the Magento Invoice
}
The framework uses ConnectorSession objects to store the cr, uid and context as well as the current pool. A session object also features shortcuts to the most used ORM methods like:
invoice = session.browse('magento.account.invoice', record_id)
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
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.browse(model_name, 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:
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):
The binders give the external ID or OpenERP ID from respectively an OpenERP ID or an external ID.
The mappers transform a external record into an OpenERP record or conversely.
The adapters implements the discussion with the backend's APIs. They usually adapt their APIs to a common interface (CRUD).
The synchronizers are the main piece of a synchronization. They define the flow of a synchronization and use the other ConnectorUnit (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(ExportSynchronizer):
""" 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 """
sess = self.session
invoice = sess.browse(self.model._name, 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)