Merge lp:~camptocamp/openerp-connector-magento/7.0-update-stock-1330450 into lp:~openerp-connector-core-editors/openerp-connector-magento/7.0

Proposed by Guewen Baconnier @ Camptocamp
Status: Rejected
Rejected by: Guewen Baconnier @ Camptocamp
Proposed branch: lp:~camptocamp/openerp-connector-magento/7.0-update-stock-1330450
Merge into: lp:~openerp-connector-core-editors/openerp-connector-magento/7.0
Diff against target: 124 lines (+71/-14)
1 file modified
magentoerpconnect/product.py (+71/-14)
To merge this branch: bzr merge lp:~camptocamp/openerp-connector-magento/7.0-update-stock-1330450
Reviewer Review Type Date Requested Status
OpenERP Connector Core Editors Pending
Review via email: mp+223393@code.launchpad.net

Commit message

Update of Magento stock quantity: reduced the memory footprint and improved
performance by using read() instead of browse() and proceeding by steps of 1000 records at a time.

Description of the change

To post a comment you must log in.
Revision history for this message
Guewen Baconnier @ Camptocamp (gbaconnier-c2c) wrote :

Unmerged revisions

1003. By Guewen Baconnier @ Camptocamp

Update of Magento stock quantity: reduced the memory footprint and improved
performance by using read() instead of browse() and proceeding by steps of 1000
records at a time.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'magentoerpconnect/product.py'
2--- magentoerpconnect/product.py 2014-06-14 20:30:26 +0000
3+++ magentoerpconnect/product.py 2014-06-17 12:15:30 +0000
4@@ -25,6 +25,7 @@
5 import base64
6 import xmlrpclib
7 import sys
8+from collections import defaultdict
9 from openerp.osv import orm, fields
10 from openerp.tools.translate import _
11 from openerp.addons.connector.queue.job import job, related_action
12@@ -54,6 +55,11 @@
13 _logger = logging.getLogger(__name__)
14
15
16+def chunks(items, length):
17+ for index in xrange(0, len(items), length):
18+ yield items[index:index + length]
19+
20+
21 class magento_product_product(orm.Model):
22 _name = 'magento.product.product'
23 _inherit = 'magento.binding'
24@@ -123,35 +129,86 @@
25 "A product with the same ID on Magento already exists")
26 ]
27
28+ RECOMPUTE_QTY_STEP = 1000 # products at a time
29+
30 def recompute_magento_qty(self, cr, uid, ids, context=None):
31+ """ Check if the quantity in the stock location configured
32+ on the backend has changed since the last export.
33+
34+ If it has changed, write the updated quantity on `magento_qty`.
35+ The write on `magento_qty` will trigger an `on_record_write`
36+ event that will create an export job.
37+
38+ It groups the products by backend to avoid to read the backend
39+ informations for each product.
40+ """
41 if not hasattr(ids, '__iter__'):
42 ids = [ids]
43
44- for product in self.browse(cr, uid, ids, context=context):
45- new_qty = self._magento_qty(cr, uid, product, context=context)
46- if new_qty != product.magento_qty:
47- self.write(cr, uid, product.id,
48- {'magento_qty': new_qty},
49- context=context)
50+ # group products by backend
51+ backends = defaultdict(list)
52+ for product in self.read(cr, uid, ids, ['backend_id', 'magento_qty'],
53+ context=context):
54+ backends[product['backend_id'][0]].append(product)
55+
56+ for backend_id, products in backends.iteritems():
57+ backend_obj = self.pool['magento.backend']
58+ backend = backend_obj.browse(cr, uid, backend_id, context=context)
59+ self._recompute_magento_qty_backend(cr, uid, backend, products,
60+ context=context)
61 return True
62
63- def _magento_qty(self, cr, uid, product, context=None):
64+ def _recompute_magento_qty_backend(self, cr, uid, backend, products,
65+ read_fields=None, context=None):
66+ """ Recompute the products quantity for one backend.
67+
68+ If field names are passed in ``read_fields`` (as a list), they
69+ will be read in the product that is used in
70+ :meth:`~._magento_qty`.
71+
72+ """
73 if context is None:
74 context = {}
75- backend = product.backend_id
76- stock = backend.warehouse_id.lot_stock_id
77
78 if backend.product_stock_field_id:
79 stock_field = backend.product_stock_field_id.name
80 else:
81 stock_field = 'virtual_available'
82
83+ location = backend.warehouse_id.lot_stock_id
84 location_ctx = context.copy()
85- location_ctx['location'] = stock.id
86- product_stk = self.read(cr, uid, product.id,
87- [stock_field],
88- context=location_ctx)
89- return product_stk[stock_field]
90+ location_ctx['location'] = location.id
91+
92+ product_fields = ['magento_qty', stock_field]
93+ if read_fields:
94+ product_fields += read_fields
95+
96+ product_ids = [product['id'] for product in products]
97+ for chunk_ids in chunks(product_ids, self.RECOMPUTE_QTY_STEP):
98+ for product in self.read(cr, uid, chunk_ids, product_fields,
99+ context=location_ctx):
100+ new_qty = self._magento_qty(cr, uid, product,
101+ backend,
102+ location,
103+ stock_field,
104+ context=location_ctx)
105+ if new_qty != product['magento_qty']:
106+ self.write(cr, uid, product['id'],
107+ {'magento_qty': new_qty},
108+ context=context)
109+
110+ def _magento_qty(self, cr, uid, product, backend, location,
111+ stock_field, context=None):
112+ """ Return the current quantity for one product.
113+
114+ Can be inherited to change the way the quantity is computed,
115+ according to a backend / location.
116+
117+ If you need to read additional fields on the product, see the
118+ ``read_fields`` argument of :meth:`~._recompute_magento_qty_backend`
119+
120+ """
121+ return product[stock_field]
122
123
124 class product_product(orm.Model):