~camptocamp/openerp-connector-magento/7.0-update-stock-1330450

822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
1
# -*- coding: utf-8 -*-
2
##############################################################################
3
#
4
#    Author: Guewen Baconnier
5
#    Copyright 2013 Camptocamp SA
6
#
7
#    This program is free software: you can redistribute it and/or modify
8
#    it under the terms of the GNU Affero General Public License as
9
#    published by the Free Software Foundation, either version 3 of the
10
#    License, or (at your option) any later version.
11
#
12
#    This program is distributed in the hope that it will be useful,
13
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
14
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
#    GNU Affero General Public License for more details.
16
#
17
#    You should have received a copy of the GNU Affero General Public License
18
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
#
20
##############################################################################
21
22
import logging
873 by Guewen Baconnier
[IMP] handle cases when the Magento ID on which we are working is missing in Magento, raise a IDMissingInBackend error
23
import xmlrpclib
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
24
from openerp.osv import orm, fields
25
from openerp.addons.connector.unit.mapper import (mapping,
26
                                                  ImportMapper
27
                                                  )
873 by Guewen Baconnier
[IMP] handle cases when the Magento ID on which we are working is missing in Magento, raise a IDMissingInBackend error
28
from openerp.addons.connector.exception import IDMissingInBackend
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
29
from .unit.backend_adapter import GenericAdapter
30
from .unit.import_synchronizer import (DelayedBatchImport,
31
                                       MagentoImportSynchronizer,
32
                                       TranslationImporter,
840.1.1 by Guewen Baconnier
[ADD] create a connector.checkpoint for the imported product and product categories
33
                                       AddCheckpoint,
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
34
                                       )
35
from .backend import magento
36
37
_logger = logging.getLogger(__name__)
38
39
40
class magento_product_category(orm.Model):
41
    _name = 'magento.product.category'
42
    _inherit = 'magento.binding'
43
    _inherits = {'product.category': 'openerp_id'}
840 by Guewen Baconnier
[FIX] add missing _description on new models
44
    _description = 'Magento Product Category'
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
45
46
    _columns = {
47
        'openerp_id': fields.many2one('product.category',
48
                                      string='Product Category',
49
                                      required=True,
50
                                      ondelete='cascade'),
51
        'description': fields.text('Description', translate=True),
52
        'magento_parent_id': fields.many2one(
53
            'magento.product.category',
54
             string='Magento Parent Category',
55
             ondelete='cascade'),
56
        'magento_child_ids': fields.one2many(
57
            'magento.product.category',
58
             'magento_parent_id',
59
             string='Magento Child Categories'),
60
    }
61
62
    _sql_constraints = [
63
        ('magento_uniq', 'unique(backend_id, magento_id)',
64
         'A product category with same ID on Magento already exists.'),
65
    ]
66
67
68
class product_category(orm.Model):
69
    _inherit = 'product.category'
70
71
    _columns = {
72
        'magento_bind_ids': fields.one2many(
73
            'magento.product.category', 'openerp_id',
74
            string="Magento Bindings"),
75
    }
76
891.1.1 by Guewen Baconnier
[FIX] duplicating objects with a magento_bind_ids should not duplicate the magento.* records
77
    def copy_data(self, cr, uid, id, default=None, context=None):
78
        if default is None:
79
            default = {}
80
        default['magento_bind_ids'] = False
81
        return super(product_category, self).copy_data(cr, uid, id,
82
                                                       default=default,
83
                                                       context=context)
84
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
85
86
@magento
87
class ProductCategoryAdapter(GenericAdapter):
88
    _model_name = 'magento.product.category'
89
    _magento_model = 'catalog_category'
992 by Guewen Baconnier
Implements Related Actions
90
    _admin_path = '/{model}/index/'
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
91
873 by Guewen Baconnier
[IMP] handle cases when the Magento ID on which we are working is missing in Magento, raise a IDMissingInBackend error
92
    def _call(self, method, arguments):
93
        try:
94
            return super(ProductCategoryAdapter, self)._call(method, arguments)
95
        except xmlrpclib.Fault as err:
96
            # 101 is the error in the Magento API
97
            # when the category does not exist
98
            if err.faultCode == 102:
99
                raise IDMissingInBackend
100
            else:
101
                raise
102
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
103
    def search(self, filters=None, from_date=None):
104
        """ Search records according to some criterias and returns a
105
        list of ids
106
107
        :rtype: list
108
        """
109
        if filters is None:
110
            filters = {}
111
112
        if from_date is not None:
113
            # updated_at include the created records
114
            filters['updated_at'] = {'from': from_date.strftime('%Y/%m/%d %H:%M:%S')}
115
849.1.1 by Guewen Baconnier
[IMP] _call method on the magento BackendAdapter, the adapter methods have to use it instead of directly call the api
116
        # the search method is on ol_customer instead of customer
117
        return self._call('oerp_catalog_category.search',
118
                          [filters] if filters else [{}])
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
119
120
    def read(self, id, storeview_id=None, attributes=None):
121
        """ Returns the information of a record
122
123
        :rtype: dict
124
        """
849.1.1 by Guewen Baconnier
[IMP] _call method on the magento BackendAdapter, the adapter methods have to use it instead of directly call the api
125
        return self._call('%s.info' % self._magento_model,
849.1.9 by Guewen Baconnier
[FIX] convert the id to integer when sent to magento, they are str because the ids 0 are allowed in magento and openerp can't store 0 (interpreted as null...)
126
                          [int(id), storeview_id, attributes])
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
127
832 by Guewen Baconnier
[ADD] import the main image of the products
128
    def tree(self, parent_id=None, storeview_id=None):
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
129
        """ Returns a tree of product categories
130
131
        :rtype: dict
132
        """
133
        def filter_ids(tree):
134
            children = {}
135
            if tree['children']:
136
                for node in tree['children']:
137
                    children.update(filter_ids(node))
138
            category_id = {tree['category_id']: children}
139
            return category_id
849.1.9 by Guewen Baconnier
[FIX] convert the id to integer when sent to magento, they are str because the ids 0 are allowed in magento and openerp can't store 0 (interpreted as null...)
140
        if parent_id:
141
            parent_id = int(parent_id)
849.1.1 by Guewen Baconnier
[IMP] _call method on the magento BackendAdapter, the adapter methods have to use it instead of directly call the api
142
        tree = self._call('%s.tree' % self._magento_model,
143
                          [parent_id, storeview_id])
144
        return filter_ids(tree)
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
145
146
147
@magento
148
class ProductCategoryBatchImport(DelayedBatchImport):
149
    """ Import the Magento Product Categories.
150
151
    For every product category in the list, a delayed job is created.
152
    A priority is set on the jobs according to their level to rise the
153
    chance to have the top level categories imported first.
154
    """
155
    _model_name = ['magento.product.category']
156
157
    def _import_record(self, magento_id, priority=None):
158
        """ Delay a job for the import """
159
        super(ProductCategoryBatchImport, self)._import_record(
160
                magento_id, priority=priority)
161
162
    def run(self, filters=None):
163
        """ Run the synchronization """
164
        from_date = filters.pop('from_date', None)
165
        if from_date is not None:
166
            updated_ids = self.backend_adapter.search(filters, from_date)
167
        else:
168
            updated_ids = None
169
170
        base_priority = 10
171
        def import_nodes(tree, level=0):
172
            for node_id, children in tree.iteritems():
173
                # By changing the priority, the top level category has
174
                # more chance to be imported before the childrens.
175
                # However, importers have to ensure that their parent is
176
                # there and import it if it doesn't exist
177
                if updated_ids is None or node_id in updated_ids:
178
                    self._import_record(node_id, priority=base_priority+level)
179
                import_nodes(children, level=level+1)
180
        tree = self.backend_adapter.tree()
181
        import_nodes(tree)
182
183
184
@magento
185
class ProductCategoryImport(MagentoImportSynchronizer):
186
    _model_name = ['magento.product.category']
187
188
    def _import_dependencies(self):
189
        """ Import the dependencies for the record"""
190
        record = self.magento_record
191
        env = self.environment
192
        # import parent category
193
        # the root category has a 0 parent_id
194
        if record.get('parent_id'):
195
            binder = self.get_binder_for_model()
196
            parent_id = record['parent_id']
197
            if binder.to_openerp(parent_id) is None:
198
                importer = env.get_connector_unit(MagentoImportSynchronizer)
199
                importer.run(parent_id)
200
840.1.1 by Guewen Baconnier
[ADD] create a connector.checkpoint for the imported product and product categories
201
    def _create(self, data):
202
        openerp_binding_id = super(ProductCategoryImport, self)._create(data)
203
        checkpoint = self.get_connector_unit_for_model(AddCheckpoint)
204
        checkpoint.run(openerp_binding_id)
205
        return openerp_binding_id
206
845 by Guewen Baconnier
[REF] rename variables openerp_id to binding_id where it refers to the id of a magento.* record, leave the openerp_id when the id refers to a base model
207
    def _after_import(self, binding_id):
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
208
        """ Hook called at the end of the import """
209
        translation_importer = self.get_connector_unit_for_model(
210
                TranslationImporter, self.model._name)
845 by Guewen Baconnier
[REF] rename variables openerp_id to binding_id where it refers to the id of a magento.* record, leave the openerp_id when the id refers to a base model
211
        translation_importer.run(self.magento_id, binding_id)
822.1.8 by Guewen Baconnier
[REF] extract from unit the code related to product categories to product_category.py
212
213
214
@magento
215
class ProductCategoryImportMapper(ImportMapper):
216
    _model_name = 'magento.product.category'
217
218
    direct = [
219
            ('description', 'description'),
220
            ]
221
222
    @mapping
223
    def name(self, record):
224
        if record['level'] == '0':  # top level category; has no name
225
            return {'name': self.backend_record.name}
226
        if record['name']:  # may be empty in storeviews
227
            return {'name': record['name']}
228
229
    @mapping
230
    def magento_id(self, record):
231
        return {'magento_id': record['category_id']}
232
233
    @mapping
234
    def backend_id(self, record):
235
        return {'backend_id': self.backend_record.id}
236
237
    @mapping
238
    def parent_id(self, record):
239
        if not record.get('parent_id'):
240
            return
241
        binder = self.get_binder_for_model()
242
        category_id = binder.to_openerp(record['parent_id'], unwrap=True)
243
        mag_cat_id = binder.to_openerp(record['parent_id'])
244
245
        if category_id is None:
246
            raise MappingError("The product category with "
247
                               "magento id %s is not imported." %
248
                               record['parent_id'])
249
        return {'parent_id': category_id, 'magento_parent_id': mag_cat_id}