bootstrap_connector.rst 6.33 KB
Newer Older
François C. committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
.. _bootstrap-connector:


########################
Boostrapping a connector
########################

We'll see the steps to bootstrap a new connector.

Besides that, you may want to use the existing connectors to have some
real implementation examples:

* `Odoo Magento Connector`_
* `Odoo Prestashop Connector`_

Some boilerplate is necessary, so this document will guide you through
some steps. Please also take a look on the :ref:`naming-convention`.

For the sake of the example, we'll imagine we have to synchronize
Odoo with a coffee machine.

*************
Odoo Manifest
*************

As we want to synchronize Odoo with a coffee machine, we'll name
our connector connector_coffee.

First, we need to create the Odoo addons itself, editing the
``connector_coffee/__openerp__.py`` manifest.


.. code-block:: python
   :emphasize-lines: 4,5

    # -*- coding: utf-8 -*-
    {'name': 'Coffee Connector',
     'version': '1.0.0',
     'category': 'Connector',
     'depends': ['connector',
                 ],
     'author': 'Myself',
     'license': 'AGPL-3',
     'description': """
    Coffee Connector
    ================

    Connect Odoo to my coffee machine.

    Features:

    * Poor a coffee when Odoo is busy for too long
    """,
     'data': [],
     'installable': True,
     'application': False,
    }

Nothing special but 2 things to note:

* It depends from ``connector``.
* The module category should be ``Connector``.

Of course, we also need to create the ``__init__.py`` file where we will
put the imports of our python modules.


********************
Declare the backends
********************

Our module is compatible with the coffee machines:

 * Coffee 1900
 * Coffee 2900

So we'll declare a backend `coffee`, the generic entity,
and a backend per version.

Put this in ``connector_coffee/backend.py``::

    import openerp.addons.connector.backend as backend


    coffee = backend.Backend('coffee')
    coffee1900 = backend.Backend(parent=coffee, version='1900')
    coffee2900 = backend.Backend(parent=coffee, version='2900')


*************
Backend Model
*************

We declared the backends, but we need a model to configure them.

We create a model ``coffee.backend`` which is an ``_inherit`` of
``connector.backend``. In ``connector_coffee/coffee_model.py``::

    from openerp import fields, models, api


    class CoffeeBackend(models.Model):
        _name = 'coffee.backend'
        _description = 'Coffee Backend'
        _inherit = 'connector.backend'

        _backend_type = 'coffee'

        @api.model
        def _select_versions(self):
            """ Available versions

            Can be inherited to add custom versions.
            """
            return [('1900', 'Version 1900'),
                    ('2900', 'Version 2900')]

        version = fields.Selection(
            selection='_select_versions',
            string='Version',
            required=True,
        )
        location = fields.Char(string='Location')
        username = fields.Char(string='Username')
        password = fields.Char(string='Password')
        default_lang_id = fields.Many2one(
            comodel_name='res.lang',
            string='Default Language',
        )

Notes:

* The ``_backend_type`` must be the same than the name in the backend in
  `Declare the backends`_.
* the versions should be the same than the ones declared in `Declare the backends`_.
* We may want to add as many fields as we want to configure our
  connection or configuration regarding the backend in that model.


****************
Abstract Binding
****************

If we have many :ref:`binding`,
we may want to create an abstract model for them.

It can be as follows (in ``connector_coffee/connector.py``)::

    from openerp import models, fields


    class CoffeeBinding(models.AbstractModel):
        _name = 'coffee.binding'
        _inherit = 'external.binding'
        _description = 'Coffee Binding (abstract)'

        # 'openerp_id': openerp-side id must be declared in concrete model
        backend_id = fields.Many2one(
            comodel_name='coffee.backend',
            string='Coffee Backend',
            required=True,
            ondelete='restrict',
        )
        # fields.char because 0 is a valid coffee ID
        coffee_id = fields.Char(string='ID in the Coffee Machine',
                                select=True)


***********
Environment
***********

We'll often need to create a new environment to work with.
I propose to create a helper method which build it for us (in
``connector_coffee/connector.py``::

    from openerp.addons.connector.connector import Environment


    def get_environment(session, model_name, backend_id):
        """ Create an environment to work with. """
        backend_record = session.env['coffee.backend'].browse(backend_id)
        env = Environment(backend_record, session, model_name)
        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

Note that the part regarding the language definition is totally
optional but I left it as an example.


***********
Checkpoints
***********

Record checkpoint
-----------------

When new records are imported and need a review, :ref:`checkpoint` are
created. You can add it like this::

    backend_record.add_checkpoint(
        model='res.partner', record_id=1, message='VAT number can be missing')


Message only checkpoint
-----------------------

When you need to show a warning message to a user
you can create a :ref:`checkpoint`. You can add it like this::

    backend_record.add_checkpoint(message='VAT number can be missing')

A typical use case for this is:

* you have a batch import of CSV file;
* you don't want to break a whole batch job just because some line failed;
* you want to notify the user with a nice warning message.


*********************
ConnectorUnit classes
*********************

We'll probably need to create synchronizers, mappers, backend adapters,
binders and maybe our own types of ConnectorUnit classes.

Their implementation can vary a lot. Have a look on the
`Odoo Magento Connector`_ and `Odoo Prestashop Connector`_ projects.


.. _`Odoo Magento Connector`: https://github.com/OCA/connector-magento
.. _`Odoo Prestashop Connector`: https://github.com/OCA/connector-prestashop