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