From 55b7f15ee2427e4c99edf05a5a61b069a5395bab Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Mon, 15 Jun 2015 16:21:52 +0200 Subject: [PATCH] [FIX] stock_account: stock valuation report performances Basically, computation of the `inventory_value` is now done in batch instead of one by one. In a real use case, the computation of the stock valuation passed from 20+ minutes to less than a minute. This revision contains an unusual SQL request: `SELECT DISTINCT ON` Basically, it returns the most recent line of table product_price_history for each tuple `(product_template_id, company_id)` which is actually what we want, with good performances. See postgresql doc for more information: http://www.postgresql.org/docs/9.0/static/sql-select.html#SQL-DISTINCT opw-641154 --- .../wizard/stock_valuation_history.py | 40 ++++++++++++++----- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/addons/stock_account/wizard/stock_valuation_history.py b/addons/stock_account/wizard/stock_valuation_history.py index 1a90a580348..66b670c2a75 100644 --- a/addons/stock_account/wizard/stock_valuation_history.py +++ b/addons/stock_account/wizard/stock_valuation_history.py @@ -46,21 +46,39 @@ class stock_history(osv.osv): if context is None: context = {} date = context.get('history_date') - prod_dict = {} if 'inventory_value' in fields: + group_lines = {} + for line in res: + domain = line.get('__domain', []) + group_lines.setdefault(str(domain), self.search(cr, uid, domain, context=context)) + line_ids = set() + for ids in group_lines.values(): + for product_id in ids: + line_ids.add(product_id) + line_ids = list(line_ids) + cr.execute('SELECT id, product_id, price_unit_on_quant, company_id, quantity FROM stock_history WHERE id in %s', (tuple(line_ids),)) + lines_rec = cr.dictfetchall() + lines_dict = dict((line['id'], line) for line in lines_rec) + product_ids = list(set(line_rec['product_id'] for line_rec in lines_rec)) + products_rec = self.pool['product.product'].read(cr, uid, product_ids, ['cost_method', 'product_tmpl_id'], context=context) + products_dict = dict((product['id'], product) for product in products_rec) + cost_method_product_tmpl_ids = list(set(product['product_tmpl_id'][0] for product in products_rec if product['cost_method'] != 'real')) + cr.execute('SELECT DISTINCT ON (product_template_id, company_id) product_template_id, company_id, cost FROM product_price_history WHERE product_template_id in %s AND datetime <= %s ORDER BY product_template_id, company_id, datetime DESC', (tuple(cost_method_product_tmpl_ids), date)) + histories = cr.dictfetchall() + histories_dict = {} + for history in histories: + histories_dict[(history['product_template_id'], history['company_id'])] = history['cost'] for line in res: - lines = self.search(cr, uid, line.get('__domain', []), context=context) inv_value = 0.0 - product_tmpl_obj = self.pool.get("product.template") - lines_rec = self.browse(cr, uid, lines, context=context) - for line_rec in lines_rec: - if line_rec.product_id.cost_method == 'real': - price = line_rec.price_unit_on_quant + lines = group_lines.get(str(line.get('__domain', []))) + for line_id in lines: + line_rec = lines_dict[line_id] + product = products_dict[line_rec['product_id']] + if product['cost_method'] == 'real': + price = line_rec['price_unit_on_quant'] else: - if not line_rec.product_id.id in prod_dict: - prod_dict[line_rec.product_id.id] = product_tmpl_obj.get_history_price(cr, uid, line_rec.product_id.product_tmpl_id.id, line_rec.company_id.id, date=date, context=context) - price = prod_dict[line_rec.product_id.id] - inv_value += price * line_rec.quantity + price = histories_dict.get((product['product_tmpl_id'][0], line_rec['company_id']), 0.0) + inv_value += price * line_rec['quantity'] line['inventory_value'] = inv_value return res