Merge lp:~arthru/prestashoperpconnect/import-product-combinations into lp:prestashoperpconnect
- import-product-combinations
- Merge into 7.0
Proposed by
arthru
Status: | Merged |
---|---|
Merged at revision: | 286 |
Proposed branch: | lp:~arthru/prestashoperpconnect/import-product-combinations |
Merge into: | lp:prestashoperpconnect |
Diff against target: |
668 lines (+525/-17) 8 files modified
prestashoperpconnect/__init__.py (+1/-0) prestashoperpconnect/__openerp__.py (+4/-0) prestashoperpconnect/product.py (+47/-12) prestashoperpconnect/product_combination.py (+397/-0) prestashoperpconnect/security/ir.model.access.csv (+3/-1) prestashoperpconnect/unit/binder.py (+3/-0) prestashoperpconnect/unit/import_synchronizer.py (+56/-0) prestashoperpconnect/unit/mapper.py (+14/-4) |
To merge this branch: | bzr merge lp:~arthru/prestashoperpconnect/import-product-combinations |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Guewen Baconnier @ Camptocamp | code review | Pending | |
arthru | Pending | ||
Review via email: mp+193021@code.launchpad.net |
This proposal supersedes a proposal from 2013-10-25.
Commit message
Description of the change
This permits to import a product by combination in prestashop
To post a comment you must log in.
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote : Posted in a previous version of this proposal | # |
review:
Needs Fixing
(code review)
Revision history for this message
arthru (arthru) wrote : Posted in a previous version of this proposal | # |
I made most of the changes. Thanks a lot for these advice, I'll try to apply them in the code that already exist !
review:
Needs Resubmitting
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'prestashoperpconnect/__init__.py' |
2 | --- prestashoperpconnect/__init__.py 2013-08-12 17:37:07 +0000 |
3 | +++ prestashoperpconnect/__init__.py 2014-02-05 11:04:06 +0000 |
4 | @@ -27,6 +27,7 @@ |
5 | import prestashop_model |
6 | import partner |
7 | import product |
8 | +import product_combination |
9 | import sale |
10 | import setting |
11 | import delivery |
12 | |
13 | === modified file 'prestashoperpconnect/__openerp__.py' |
14 | --- prestashoperpconnect/__openerp__.py 2013-10-08 14:32:58 +0000 |
15 | +++ prestashoperpconnect/__openerp__.py 2014-02-05 11:04:06 +0000 |
16 | @@ -32,7 +32,11 @@ |
17 | "product_m2mcategories", |
18 | "connector_ecommerce", |
19 | "product_images", |
20 | + "product_custom_attributes", |
21 | ], |
22 | + "external_dependencies": { |
23 | + 'python': ["unidecode"], |
24 | + }, |
25 | "author": "PrestashopERPconnect Core Editors", |
26 | "description": """This module connects OpenERP and Prestashop. |
27 | |
28 | |
29 | === modified file 'prestashoperpconnect/product.py' |
30 | --- prestashoperpconnect/product.py 2013-10-29 15:23:23 +0000 |
31 | +++ prestashoperpconnect/product.py 2014-02-05 11:04:06 +0000 |
32 | @@ -205,6 +205,24 @@ |
33 | return {'date_upd': datetime.datetime.now()} |
34 | return {'date_upd': record['date_upd']} |
35 | |
36 | + def has_combinations(self, record): |
37 | + combinations = record.get('associations', {}).get( |
38 | + 'combinations', {}).get('combinations', []) |
39 | + return len(combinations) != 0 |
40 | + |
41 | + @mapping |
42 | + def attribute_set_id(self, record): |
43 | + if self.has_combinations(record) and 'attribute_set_id' in record: |
44 | + return {'attribute_set_id': record['attribute_set_id']} |
45 | + return {} |
46 | + |
47 | + def _product_code_exists(self, code): |
48 | + model = self.session.pool.get('product.product') |
49 | + product_ids = model.search(self.session.cr, self.session.uid, [ |
50 | + ('default_code', '=', code) |
51 | + ]) |
52 | + return len(product_ids) > 0 |
53 | + |
54 | @mapping |
55 | def image(self, record): |
56 | if record['id_default_image']['value'] == '': |
57 | @@ -222,9 +240,17 @@ |
58 | |
59 | @mapping |
60 | def default_code(self, record): |
61 | - if record.get('reference'): |
62 | - return {'default_code': record.get('reference')} |
63 | - return {} |
64 | + if not record.get('reference'): |
65 | + return {} |
66 | + code = record.get('reference') |
67 | + if not self._product_code_exists(code): |
68 | + return {'default_code': code} |
69 | + i = 1 |
70 | + current_code = '%s_%d' % (code, i) |
71 | + while self._product_code_exists(current_code): |
72 | + i += 1 |
73 | + current_code = '%s_%d' % (code, i) |
74 | + return {'default_code': current_code} |
75 | |
76 | @mapping |
77 | def active(self, record): |
78 | @@ -232,7 +258,11 @@ |
79 | |
80 | @mapping |
81 | def sale_ok(self, record): |
82 | - return {'sale_ok': record['available_for_order'] == '1'} |
83 | + # if this product has combinations, we do not want to sell this product, |
84 | + # but its combinations (so sale_ok = False in that case). |
85 | + sale_ok = (record['available_for_order'] == '1' |
86 | + and not self.has_combinations(record)) |
87 | + return {'sale_ok': sale_ok} |
88 | |
89 | @mapping |
90 | def categ_id(self, record): |
91 | @@ -292,10 +322,14 @@ |
92 | |
93 | @mapping |
94 | def type(self, record): |
95 | - product_type = {"type": 'product'} |
96 | - if record['type']['value'] and record['type']['value'] == 'virtual': |
97 | - product_type = {"type": 'consu'} |
98 | - return product_type |
99 | + # If the product has combinations, this main product is not a real |
100 | + # product. So it is set to a 'service' kind of product. Should better be |
101 | + # a 'virtual' product... but it does not exist... |
102 | + # The same if the product is a virtual one in prestashop. |
103 | + if ((record['type']['value'] and record['type']['value'] == 'virtual') |
104 | + or self.has_combinations(record)): |
105 | + return {"type": 'service'} |
106 | + return {"type": 'product'} |
107 | |
108 | |
109 | class product_product(orm.Model): |
110 | @@ -334,10 +368,6 @@ |
111 | 'always_available': fields.boolean( |
112 | 'Active', |
113 | help='if check, this object is always available'), |
114 | - 'sale_ok': fields.boolean( |
115 | - 'For sale', |
116 | - help='see parent field' |
117 | - ), |
118 | 'quantity': fields.float( |
119 | 'Computed Quantity', |
120 | help="Last computed quantity to send on Prestashop." |
121 | @@ -369,6 +399,11 @@ |
122 | translate=True, |
123 | required=True, |
124 | ), |
125 | + 'combinations_ids': fields.one2many( |
126 | + 'prestashop.product.combination', |
127 | + 'main_product_id', |
128 | + string='Combinations' |
129 | + ), |
130 | } |
131 | |
132 | _sql_constraints = [ |
133 | |
134 | === added file 'prestashoperpconnect/product_combination.py' |
135 | --- prestashoperpconnect/product_combination.py 1970-01-01 00:00:00 +0000 |
136 | +++ prestashoperpconnect/product_combination.py 2014-02-05 11:04:06 +0000 |
137 | @@ -0,0 +1,397 @@ |
138 | +''' |
139 | +A product combination is a product with different attributes in prestashop. |
140 | +In prestashop, we can sell a product or a combination of a product with some |
141 | +attributes. |
142 | + |
143 | +For example, for the iPod product we can found in demo data, it has some |
144 | +combinations with different colors and different storage size. |
145 | + |
146 | +We map that in OpenERP to a product.product with an attribute.set defined for |
147 | +the main product. |
148 | +''' |
149 | + |
150 | +from unidecode import unidecode |
151 | + |
152 | +from openerp.osv import fields, orm |
153 | +from backend import prestashop |
154 | +from .unit.backend_adapter import GenericAdapter |
155 | +from .unit.import_synchronizer import PrestashopImportSynchronizer |
156 | +from .unit.import_synchronizer import TranslatableRecordImport |
157 | +from .unit.mapper import PrestashopImportMapper |
158 | +from openerp.addons.connector.unit.backend_adapter import BackendAdapter |
159 | +from openerp.addons.connector.unit.mapper import mapping |
160 | + |
161 | + |
162 | +class product_product(orm.Model): |
163 | + _inherit = 'product.product' |
164 | + |
165 | + _columns = { |
166 | + 'prestashop_combinations_bind_ids': fields.one2many( |
167 | + 'prestashop.product.combination', |
168 | + 'openerp_id', |
169 | + string='PrestaShop Bindings (combinations)' |
170 | + ), |
171 | + } |
172 | + |
173 | + |
174 | +class prestashop_product_combination(orm.Model): |
175 | + _name = 'prestashop.product.combination' |
176 | + _inherit = 'prestashop.binding' |
177 | + _inherits = {'product.product': 'openerp_id'} |
178 | + |
179 | + _columns = { |
180 | + 'openerp_id': fields.many2one( |
181 | + 'product.product', |
182 | + string='Product', |
183 | + required=True, |
184 | + ondelete='cascade' |
185 | + ), |
186 | + 'main_product_id': fields.many2one( |
187 | + 'prestashop.product.product', |
188 | + string='Main product', |
189 | + required=True, |
190 | + ondelete='cascade' |
191 | + ), |
192 | + } |
193 | + |
194 | + |
195 | +@prestashop |
196 | +class ProductCombinationAdapter(GenericAdapter): |
197 | + _model_name = 'prestashop.product.combination' |
198 | + _prestashop_model = 'combinations' |
199 | + |
200 | + |
201 | +@prestashop |
202 | +class ProductCombinationRecordImport(PrestashopImportSynchronizer): |
203 | + _model_name = 'prestashop.product.combination' |
204 | + |
205 | + def _import_dependencies(self): |
206 | + record = self.prestashop_record |
207 | + option_values = record.get('associations', {}).get( |
208 | + 'product_option_values', {}).get('product_option_value', []) |
209 | + if not isinstance(option_values, list): |
210 | + option_values = [option_values] |
211 | + for option_value in option_values: |
212 | + backend_adapter = self.get_connector_unit_for_model( |
213 | + BackendAdapter, |
214 | + 'prestashop.product.combination.option.value' |
215 | + ) |
216 | + option_value = backend_adapter.read(option_value['id']) |
217 | + self._check_dependency( |
218 | + option_value['id_attribute_group'], |
219 | + 'prestashop.product.combination.option', |
220 | + ) |
221 | + |
222 | + self.check_location(option_value) |
223 | + |
224 | + def check_location(self, option_value): |
225 | + option_binder = self.get_binder_for_model( |
226 | + 'prestashop.product.combination.option') |
227 | + attribute_id = option_binder.to_openerp( |
228 | + option_value['id_attribute_group'], unwrap=True) |
229 | + product = self.mapper.main_product(self.prestashop_record) |
230 | + attribute_group_id = product.attribute_set_id.attribute_group_ids[0].id |
231 | + |
232 | + attribute_location_ids = self.session.search( |
233 | + 'attribute.location', |
234 | + [ |
235 | + ('attribute_id', '=', attribute_id), |
236 | + ('attribute_group_id', '=', attribute_group_id) |
237 | + ] |
238 | + ) |
239 | + if not attribute_location_ids: |
240 | + self.session.create( |
241 | + 'attribute.location', |
242 | + { |
243 | + 'attribute_id': attribute_id, |
244 | + 'attribute_group_id': attribute_group_id, |
245 | + } |
246 | + ) |
247 | + |
248 | + |
249 | +@prestashop |
250 | +class ProductCombinationMapper(PrestashopImportMapper): |
251 | + _model_name = 'prestashop.product.combination' |
252 | + |
253 | + direct = [ |
254 | + ('weight', 'weight'), |
255 | + ('wholesale_price', 'standard_price'), |
256 | + ('price', 'lst_price'), |
257 | + ] |
258 | + |
259 | + from_main = [ |
260 | + 'name', |
261 | + 'categ_id', |
262 | + 'categ_ids', |
263 | + 'taxes_ids', |
264 | + 'type', |
265 | + 'company_id', |
266 | + ] |
267 | + |
268 | + @mapping |
269 | + def from_main_product(self, record): |
270 | + main_product = self.main_product(record) |
271 | + result = {} |
272 | + for attribute in self.from_main: |
273 | + if attribute not in main_product: |
274 | + continue |
275 | + if hasattr(main_product[attribute], 'id'): |
276 | + result[attribute] = main_product[attribute].id |
277 | + elif isinstance(main_product[attribute]), list): |
278 | + ids = [] |
279 | + for element in main_product[attribute]: |
280 | + ids.append(element.id) |
281 | + result[attribute] = [(6, 0, ids)] |
282 | + else: |
283 | + result[attribute] = main_product[attribute] |
284 | + return result |
285 | + |
286 | + def main_product(self, record): |
287 | + if hasattr(self, '_main_product'): |
288 | + return self._main_product |
289 | + product_id = self.get_main_product_id(record) |
290 | + self._main_product = self.session.browse( |
291 | + 'prestashop.product.product', |
292 | + product_id |
293 | + ) |
294 | + return self._main_product |
295 | + |
296 | + def get_main_product_id(self, record): |
297 | + product_binder = self.get_binder_for_model( |
298 | + 'prestashop.product.product') |
299 | + return product_binder.to_openerp(record['id_product']) |
300 | + |
301 | + @mapping |
302 | + def attribute_set_id(self, record): |
303 | + product = self.main_product(record) |
304 | + if 'attribute_set_id' in product: |
305 | + return {'attribute_set_id': product.attribute_set_id.id} |
306 | + return {} |
307 | + |
308 | + @mapping |
309 | + def attributes_values(self, record): |
310 | + option_values = record['associations']['product_option_values'][ |
311 | + 'product_option_value'] |
312 | + if isinstance(option_values, dict): |
313 | + option_values = [option_values] |
314 | + |
315 | + results = {} |
316 | + for option_value in option_values: |
317 | + |
318 | + option_value_binder = self.get_binder_for_model( |
319 | + 'prestashop.product.combination.option.value') |
320 | + option_value_openerp_id = option_value_binder.to_openerp( |
321 | + option_value['id']) |
322 | + |
323 | + option_value_object = self.session.browse( |
324 | + 'prestashop.product.combination.option.value', |
325 | + option_value_openerp_id |
326 | + ) |
327 | + field_name = option_value_object.attribute_id.name |
328 | + results[field_name] = option_value_object.id |
329 | + return results |
330 | + |
331 | + @mapping |
332 | + def main_product_id(self, record): |
333 | + return {'main_product_id': self.get_main_product_id(record)} |
334 | + |
335 | + def _product_code_exists(self, code): |
336 | + product_ids = self.session.search('product.product', |
337 | + [('default_code', '=', code)]) |
338 | + return len(product_ids) > 0 |
339 | + |
340 | + @mapping |
341 | + def default_code(self, record): |
342 | + if not record.get('reference'): |
343 | + return {} |
344 | + code = record.get('reference') |
345 | + if not self._product_code_exists(code): |
346 | + return {'default_code': code} |
347 | + i = 1 |
348 | + current_code = '%s_%d' % (code, i) |
349 | + while self._product_code_exists(current_code): |
350 | + i += 1 |
351 | + current_code = '%s_%d' % (code, i) |
352 | + return {'default_code': current_code} |
353 | + |
354 | + ##@mapping |
355 | + ##def active(self, record): |
356 | + ## return {'always_available': bool(int(record['active']))} |
357 | + |
358 | + ##@mapping |
359 | + ##def sale_ok(self, record): |
360 | + ## return {'sale_ok': record['available_for_order'] == '1'} |
361 | + |
362 | + @mapping |
363 | + def backend_id(self, record): |
364 | + return {'backend_id': self.backend_record.id} |
365 | + |
366 | + @mapping |
367 | + def ean13(self, record): |
368 | + if record['ean13'] == '0': |
369 | + return {} |
370 | + return {'ean13': record['ean13']} |
371 | + |
372 | + |
373 | +class attribute_attribute(orm.Model): |
374 | + _inherit = 'attribute.attribute' |
375 | + |
376 | + _columns = { |
377 | + 'prestashop_bind_ids': fields.one2many( |
378 | + 'prestashop.product.combination.option', |
379 | + 'openerp_id', |
380 | + string='PrestaShop Bindings (combinations)' |
381 | + ), |
382 | + } |
383 | + |
384 | + |
385 | +class prestashop_product_combination_option(orm.Model): |
386 | + _name = 'prestashop.product.combination.option' |
387 | + _inherit = 'prestashop.binding' |
388 | + _inherits = {'attribute.attribute': 'openerp_id'} |
389 | + |
390 | + _columns = { |
391 | + 'openerp_id': fields.many2one( |
392 | + 'attribute.attribute', |
393 | + string='Attribute', |
394 | + required=True, |
395 | + ondelete='cascade' |
396 | + ), |
397 | + } |
398 | + |
399 | + |
400 | +@prestashop |
401 | +class ProductCombinationOptionAdapter(GenericAdapter): |
402 | + _model_name = 'prestashop.product.combination.option' |
403 | + _prestashop_model = 'product_options' |
404 | + |
405 | + |
406 | +@prestashop |
407 | +class ProductCombinationOptionRecordImport(PrestashopImportSynchronizer): |
408 | + _model_name = 'prestashop.product.combination.option' |
409 | + |
410 | + def _import_values(self): |
411 | + record = self.prestashop_record |
412 | + option_values = record.get('associations', {}).get( |
413 | + 'product_option_values', {}).get('product_option_value', []) |
414 | + if not isinstance(option_values, list): |
415 | + option_values = [option_values] |
416 | + for option_value in option_values: |
417 | + self._check_dependency( |
418 | + option_value['id'], |
419 | + 'prestashop.product.combination.option.value' |
420 | + ) |
421 | + |
422 | + def run(self, ext_id): |
423 | + super(ProductCombinationOptionRecordImport, self).run(ext_id) |
424 | + |
425 | + self._import_values() |
426 | + |
427 | + |
428 | +@prestashop |
429 | +class ProductCombinationOptionMapper(PrestashopImportMapper): |
430 | + _model_name = 'prestashop.product.combination.option' |
431 | + |
432 | + @mapping |
433 | + def attribute_type(self, record): |
434 | + return {'attribute_type': 'select'} |
435 | + |
436 | + @mapping |
437 | + def model_id(self, record): |
438 | + ids = self.session.search('ir.model', |
439 | + [('model', '=', 'product.product')]) |
440 | + assert len(ids) == 1 |
441 | + return {'model_id': ids[0], 'model': 'product.product'} |
442 | + |
443 | + @mapping |
444 | + def backend_id(self, record): |
445 | + return {'backend_id': self.backend_record.id} |
446 | + |
447 | + @mapping |
448 | + def name(self, record): |
449 | + name = None |
450 | + if 'language' in record['name']: |
451 | + language_binder = self.get_binder_for_model('prestashop.res.lang') |
452 | + languages = record['name']['language'] |
453 | + if not isinstance(languages, list): |
454 | + languages = [languages] |
455 | + for lang in languages: |
456 | + erp_language_id = language_binder.to_openerp( |
457 | + lang['attrs']['id']) |
458 | + erp_lang = self.session.read( |
459 | + 'prestashop.res.lang', |
460 | + erp_language_id, |
461 | + ) |
462 | + if erp_lang['code'] == 'en_US': |
463 | + name = lang['value'] |
464 | + break |
465 | + if name is None: |
466 | + name = languages[0]['value'] |
467 | + else: |
468 | + name = record['name'] |
469 | + field_name = 'x_' + unidecode(name.replace(' ', '')) |
470 | + return {'name': field_name, 'field_description': name} |
471 | + |
472 | + |
473 | +class attribute_option(orm.Model): |
474 | + _inherit = 'attribute.option' |
475 | + |
476 | + _columns = { |
477 | + 'prestashop_bind_ids': fields.one2many( |
478 | + 'prestashop.product.combination.option.value', |
479 | + 'openerp_id', |
480 | + string='PrestaShop Bindings' |
481 | + ), |
482 | + } |
483 | + |
484 | + |
485 | +class prestashop_product_combination_option_value(orm.Model): |
486 | + _name = 'prestashop.product.combination.option.value' |
487 | + _inherit = 'prestashop.binding' |
488 | + _inherits = {'attribute.option': 'openerp_id'} |
489 | + |
490 | + _columns = { |
491 | + 'openerp_id': fields.many2one( |
492 | + 'attribute.option', |
493 | + string='Attribute', |
494 | + required=True, |
495 | + ondelete='cascade' |
496 | + ), |
497 | + } |
498 | + |
499 | + |
500 | +@prestashop |
501 | +class ProductCombinationOptionValueAdapter(GenericAdapter): |
502 | + _model_name = 'prestashop.product.combination.option.value' |
503 | + _prestashop_model = 'product_option_values' |
504 | + |
505 | + |
506 | +@prestashop |
507 | +class ProductCombinationOptionValueRecordImport(TranslatableRecordImport): |
508 | + _model_name = 'prestashop.product.combination.option.value' |
509 | + |
510 | + _translatable_fields = { |
511 | + 'prestashop.product.combination.option.value': ['name'], |
512 | + } |
513 | + |
514 | + |
515 | +@prestashop |
516 | +class ProductCombinationOptionValueMapper(PrestashopImportMapper): |
517 | + _model_name = 'prestashop.product.combination.option.value' |
518 | + |
519 | + direct = [ |
520 | + ('name', 'name'), |
521 | + ('position', 'sequence'), |
522 | + ] |
523 | + |
524 | + @mapping |
525 | + def attribute_id(self, record): |
526 | + binder = self.get_binder_for_model( |
527 | + 'prestashop.product.combination.option') |
528 | + attribute_id = binder.to_openerp(record['id_attribute_group'], |
529 | + unwrap=True) |
530 | + return {'attribute_id': attribute_id} |
531 | + |
532 | + @mapping |
533 | + def backend_id(self, record): |
534 | + return {'backend_id': self.backend_record.id} |
535 | |
536 | === modified file 'prestashoperpconnect/security/ir.model.access.csv' |
537 | --- prestashoperpconnect/security/ir.model.access.csv 2013-08-13 08:22:25 +0000 |
538 | +++ prestashoperpconnect/security/ir.model.access.csv 2014-02-05 11:04:06 +0000 |
539 | @@ -20,4 +20,6 @@ |
540 | access_prestashop_product_category_full,Full access on prestashop.product.category,model_prestashop_product_category,connector.group_connector_manager,1,1,1,1 |
541 | access_prestashop_product_image_full,Full access on prestashop.product.image,model_prestashop_product_image,connector.group_connector_manager,1,1,1,1 |
542 | access_prestashop_product_product_full,Full access on prestashop.product.product,model_prestashop_product_product,connector.group_connector_manager,1,1,1,1 |
543 | - |
544 | +access_prestashop_product_combination_full,Full access on prestashop.product.combination,model_prestashop_product_combination,connector.group_connector_manager,1,1,1,1 |
545 | +access_prestashop_product_combination_option_full,Full access on prestashop.product.combination.option,model_prestashop_product_combination_option,connector.group_connector_manager,1,1,1,1 |
546 | +access_prestashop_product_combination_option_value_full,Full access on prestashop.product.combination.option.value,model_prestashop_product_combination_option_value,connector.group_connector_manager,1,1,1,1 |
547 | |
548 | === modified file 'prestashoperpconnect/unit/binder.py' |
549 | --- prestashoperpconnect/unit/binder.py 2013-07-12 13:35:45 +0000 |
550 | +++ prestashoperpconnect/unit/binder.py 2014-02-05 11:04:06 +0000 |
551 | @@ -51,6 +51,9 @@ |
552 | 'prestashop.product.category', |
553 | 'prestashop.product.image', |
554 | 'prestashop.product.product', |
555 | + 'prestashop.product.combination', |
556 | + 'prestashop.product.combination.option', |
557 | + 'prestashop.product.combination.option.value', |
558 | 'prestashop.sale.order', |
559 | 'prestashop.sale.order.state', |
560 | 'prestashop.delivery.carrier', |
561 | |
562 | === modified file 'prestashoperpconnect/unit/import_synchronizer.py' |
563 | --- prestashoperpconnect/unit/import_synchronizer.py 2013-11-14 19:53:00 +0000 |
564 | +++ prestashoperpconnect/unit/import_synchronizer.py 2014-02-05 11:04:06 +0000 |
565 | @@ -554,6 +554,20 @@ |
566 | |
567 | prestashop_record = self._get_prestashop_data() |
568 | associations = prestashop_record.get('associations', {}) |
569 | + |
570 | + combinations = associations.get('combinations', {}).get( |
571 | + 'combinations', {}) |
572 | + if not isinstance(combinations, list): |
573 | + combinations = [combinations] |
574 | + for combination in combinations: |
575 | + if 'id' in combination: |
576 | + import_record( |
577 | + self.session, |
578 | + 'prestashop.product.combination', |
579 | + self.backend_record.id, |
580 | + combination['id'] |
581 | + ) |
582 | + |
583 | images = associations.get('images', {}).get('image', {}) |
584 | if not isinstance(images, list): |
585 | images = [images] |
586 | @@ -569,11 +583,53 @@ |
587 | ) |
588 | |
589 | def _import_dependencies(self): |
590 | + self._import_default_category() |
591 | + self._import_categories() |
592 | + self._import_attribute_set() |
593 | + |
594 | + def _import_attribute_set(self): |
595 | + record = self.prestashop_record |
596 | + |
597 | + combinations = record.get('associations', {}).get( |
598 | + 'combinations', {}).get('combinations', []) |
599 | + if len(combinations) == 0: |
600 | + return |
601 | + |
602 | + splitted_record = self._split_per_language(self.prestashop_record) |
603 | + if self._default_language in splitted_record: |
604 | + name = splitted_record[self._default_language]['name'] |
605 | + else: |
606 | + name = splitted_record.values()[0]['name'] |
607 | + |
608 | + product_model_id = self.get_product_model_id() |
609 | + attribute_group = { |
610 | + 'model_id': product_model_id, |
611 | + 'name': 'Combinations options', |
612 | + 'sequence': 0, |
613 | + } |
614 | + attribute_set = { |
615 | + 'model_id': product_model_id, |
616 | + 'name': name + ' Options', |
617 | + 'attribute_group_ids': [(0, 0, attribute_group)], |
618 | + } |
619 | + attribute_set_id = self.session.create('attribute.set', attribute_set) |
620 | + self.prestashop_record['attribute_set_id'] = attribute_set_id |
621 | + |
622 | + def get_product_model_id(self): |
623 | + ids = self.session.search('ir.model', [ |
624 | + ('model', '=', 'product.product')] |
625 | + ) |
626 | + assert len(ids) == 1 |
627 | + return ids[0] |
628 | + |
629 | + def _import_default_category(self): |
630 | record = self.prestashop_record |
631 | if int(record['id_category_default']): |
632 | self._check_dependency(record['id_category_default'], |
633 | 'prestashop.product.category') |
634 | |
635 | + def _import_categories(self): |
636 | + record = self.prestashop_record |
637 | associations = record.get('associations', {}) |
638 | categories = associations.get('categories', {}).get('category', []) |
639 | if not isinstance(categories, list): |
640 | |
641 | === modified file 'prestashoperpconnect/unit/mapper.py' |
642 | --- prestashoperpconnect/unit/mapper.py 2013-11-15 14:35:42 +0000 |
643 | +++ prestashoperpconnect/unit/mapper.py 2014-02-05 11:04:06 +0000 |
644 | @@ -440,10 +440,20 @@ |
645 | |
646 | @mapping |
647 | def product_id(self, record): |
648 | - return {'product_id': self.get_openerp_id( |
649 | - 'prestashop.product.product', |
650 | - record['product_id'] |
651 | - )} |
652 | + if ('product_attribute_id' in record and |
653 | + record['product_attribute_id'] != '0'): |
654 | + combination_binder = self.get_binder_for_model( |
655 | + 'prestashop.product.combination') |
656 | + product_id = combination_binder.to_openerp( |
657 | + record['product_attribute_id'], |
658 | + unwrap=True |
659 | + ) |
660 | + else: |
661 | + product_id = self.get_openerp_id( |
662 | + 'prestashop.product.product', |
663 | + record['product_id'] |
664 | + ) |
665 | + return {'product_id': product_id} |
666 | |
667 | @mapping |
668 | def backend_id(self, record): |
Good piece of work Arthur,
Some comments:
--
What is a "product combination". At least a few words (in the docstring of the Python module product_ combination. py) to explain this concept could be useful.
--
l.44-47, l.217ff. l.226ff (and other places, possibly on methods search, browse, read, create, unlink)
model = self.session. pool.get( 'product. product' ) self.session. cr, self.session.uid, [
('default_ code', '=', code)
product_ids = model.search(
])
A better idiom is:
product_ids = self.session. search( 'product. product' , [('default_code', '=', code)])
(side note on the alignment: "Arguments on first line forbidden when not using vertical alignment", source http:// www.python. org/dev/ peps/pep- 0008/#indentati on)
--
l.134 dependencies" in __openerp__.py
"unidecode" is to add in the "external_
--
l.212 (and each time you use the unwrap keyword argument of to_openerp())
Please use the keyword when calling a keyword argument, so instead of
attribute_id = option_ binder. to_openerp(
option_ value[' id_attribute_ group'] , True)
Use
attribute_id = option_ binder. to_openerp(
option_ value[' id_attribute_ group'] , unwrap=True)
--
l.264, l.302, l.453
Instead of:
type( main_product[ attribute] ) is list
Use:
isinstance( main_product[ attribute] , list)
--
l.306-321:
suggestion (as you want): externalize the part which get the option value in another ConnectorUnit, allowing to customize the way the options values are get.
--
l.599
if len(combinations) == 0:
=>
if not combinations:
--
Thanks!