[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
This commit is contained in:
Denis Ledoux 2015-06-15 16:21:52 +02:00
parent 0d5b01543e
commit 55b7f15ee2
1 changed files with 29 additions and 11 deletions

View File

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