Survol du code

Voici un survol de certains concepts du framework.

Comme exemple, nous allons voir les étapes pour exporter une facture vers Magento. Ce n’est pas un exemple complet mais un aperçu d’un cas réel pour exposer les idée principales.

Backends

Tout commence par une déclaration du 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 """

Comme vous pouvez voir, Magento est parent de Magento 1.7. Nous pouvons donc définir une hiérarchie de backends.

Bindings (Liaisons)

Un binding est ce qui permet de lier un enregistrement Odoo et un enregistrement externe. Il n’y a pas d’obligation pour l’implémentation des liaisons. Les techniques les plus évidentes sont: stocker les ID externes dans le même modèle (account.invoice), dans un modèle de liaison ou dans un modèle de laison qui _inherits account.invoice. Ici nous choisissons la dernière 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

Le framework utilise des objets ConnectorSession pour stocker les cr, uid et context dans un openerp.api.Environment. Donc depuis une session, nous pouvons accéder aux habituels self.env (nouvelle API) ou self.pool (ancienne API).

Événements

Nous pouvons créer un Event sur lequel nous pouvons abonner des consommateurs. Le connecteur fournit d’origine les plus génériques: on_record_create(), on_record_write(), on_record_unlink()

À la création d’un enregistrement magento.account.invoice, nous voulons lancer un job déporté pour l’exporter vers Magento, donc nous abonnons un nouveau consommateur à l’événement 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)

Sur la dernière ligne, vous pouvez notez un export_invoice.delay. Nous parlerons de ceci dans Jobs

Jobs

Un Job est une tâche à exécuter plus tard. Dans le cas présent: créer une facture dans Magento.

N’importe quelle fonction décorée avec job() peut être envoyée dans la queue de jobs en utilisant la fonction delay() et sera lancée aussi tôt que 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)

Voici les choses qui se passent à ce moment :

  • Nous trouvons le backend vers lequel exporter la facture.

  • Nous construisons un Environment avec la ConnectorSession actuelle, le modèle avec lequel on travaille et le backend cible.

  • Nous récupérons la ConnectorUnit responsable du travail grâce à get_connector_unit() (en fonction de la version du backend et du modèle) et nous appelons sa méthode run().

ConnectorUnit

Voici toutes les classes qui sont responsables d’un travail particulier. Les principaux types de ConnectorUnit sont (l’implémentation de ces classes fait partie des connecteurs):

Binder

The binders give the external ID or Odoo ID from respectively an Odoo ID or an external ID. A default implementation is available.

Mapper

Les mappeurs transforment un enregistrement externe en enregistrement Odoo ou l’inverse.

BackendAdapter

Les adaptateurs implémentent le dialogue avec les API du backend. Elles adaptent habituellement leurs APIs à une interface commune (CRUD).

Synchronizer

Les synchroniseurs sont la partie principale d’une synchronisation. Ils définissent le flux de synchronisation et utilisent les ConnectorUnit (ceux ci-dessus ou des spécifiques).

Pour l’export de la facture, nous avons juste besoin d’un adaptateur et d’un synchroniseur (l’implémentation réelle est plus complexe):

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