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} |