[IMP] stock: performance improvement:

* rewriten '_product_value' method ('multi' function field)
 * removed '_product_qty_available' method (not used anymore): fields are now computed in '_product_value'

bzr revid: olt@tinyerp.com-20100928092445-4apj6d8ai4n2ze3z
This commit is contained in:
olt@tinyerp.com 2010-09-28 11:24:45 +02:00
parent ccb069187b
commit e49a06c518
1 changed files with 36 additions and 58 deletions

View File

@ -21,6 +21,8 @@
from datetime import datetime
from dateutil.relativedelta import relativedelta
import time
from operator import itemgetter
from itertools import groupby
from osv import fields, osv
from tools.translate import _
@ -103,66 +105,42 @@ class stock_location(osv.osv):
res[m.id] = _get_one_full_name(m)
return res
def _product_qty_available(self, cr, uid, ids, field_names, arg, context=None):
""" Finds real and virtual quantity for product available at particular location.
@return: Dictionary of values
"""
res = {}
for id in ids:
res[id] = {}.fromkeys(field_names, 0.0)
if ('product_id' not in context) or not ids:
return res
for loc in ids:
context['location'] = [loc]
prod = self.pool.get('product.product').browse(cr, uid, context['product_id'], context)
if 'stock_real' in field_names:
res[loc]['stock_real'] = prod.qty_available
if 'stock_virtual' in field_names:
res[loc]['stock_virtual'] = prod.virtual_available
return res
def product_detail(self, cr, uid, id, field, context=None):
""" Finds detail of product like price type, currency and then calculates its price.
@param field: Field name
@return: Calculated price
"""
res = {}
res[id] = {}
final_value = 0.0
field_to_read = 'virtual_available'
if context is None:
context = {}
if field == 'stock_real_value':
field_to_read = 'qty_available'
cr.execute('select distinct product_id from stock_move where (location_id=%s) or (location_dest_id=%s)', (id, id))
result = cr.dictfetchall()
if result:
# Choose the right filed standard_price to read
# Take the user company
price_type_id = self.pool.get('res.users').browse(cr,uid,uid).company_id.property_valuation_price_type.id
pricetype = self.pool.get('product.price.type').browse(cr, uid, price_type_id, context=context)
for r in result:
c = (context or {}).copy()
c['location'] = id
product = self.pool.get('product.product').read(cr, uid, r['product_id'], [field_to_read], context=c)
# Compute the amount_unit in right currency
context['currency_id'] = self.pool.get('res.users').browse(cr,uid,uid).company_id.currency_id.id
amount_unit = self.pool.get('product.product').browse(cr,uid,r['product_id']).price_get(pricetype.field, context)[r['product_id']]
final_value += (product[field_to_read] * amount_unit)
return final_value
def _product_value(self, cr, uid, ids, field_names, arg, context=None):
""" Calculates real and virtual stock value of a product.
"""Computes stock value (real and virtual) for a product, as well as stock qty (real and virtual).
@param field_names: Name of field
@return: Dictionary of values
"""
result = {}
for id in ids:
result[id] = {}.fromkeys(field_names, 0.0)
for field_name in field_names:
for loc in ids:
ret_dict = self.product_detail(cr, uid, loc, field=field_name)
result[loc][field_name] = ret_dict
result = dict([(i, {}.fromkeys(field_names, 0.0)) for i in ids])
product_product_obj = self.pool.get('product.product')
cr.execute('select distinct product_id, location_id from stock_move where location_id in %s or location_dest_id in %s', (tuple(ids), tuple(ids)))
res_products_by_location = sorted(cr.dictfetchall(), key=itemgetter('location_id'))
products_by_location = dict((k, [v['product_id'] for v in itr]) for k, itr in groupby(res_products_by_location, itemgetter('location_id')))
currency_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.currency_id.id
currency_obj = self.pool.get('res.currency')
currency = self.pool.get('res.currency').browse(cr, uid, currency_id)
currency_obj.round(cr, uid, currency, 300)
for loc_id, product_ids in products_by_location.items():
c = (context or {}).copy()
c['location'] = loc_id
for prod in product_product_obj.browse(cr, uid, product_ids, context=c):
for f in field_names:
if f == 'stock_real':
result[loc_id][f] += prod.qty_available
elif f == 'stock_virtual':
result[loc_id][f] += prod.virtual_available
elif f == 'stock_real_value':
amount = prod.qty_available * prod.standard_price
amount = currency_obj.round(cr, uid, currency, amount)
result[loc_id][f] += amount
elif f == 'stock_virtual_value':
amount = prod.virtual_available * prod.standard_price
amount = currency_obj.round(cr, uid, currency, amount)
result[loc_id][f] += amount
return result
_columns = {
@ -180,8 +158,8 @@ class stock_location(osv.osv):
# temporarily removed, as it's unused: 'allocation_method': fields.selection([('fifo', 'FIFO'), ('lifo', 'LIFO'), ('nearest', 'Nearest')], 'Allocation Method', required=True),
'complete_name': fields.function(_complete_name, method=True, type='char', size=100, string="Location Name"),
'stock_real': fields.function(_product_qty_available, method=True, type='float', string='Real Stock', multi="stock"),
'stock_virtual': fields.function(_product_qty_available, method=True, type='float', string='Virtual Stock', multi="stock"),
'stock_real': fields.function(_product_value, method=True, type='float', string='Real Stock', multi="stock"),
'stock_virtual': fields.function(_product_value, method=True, type='float', string='Virtual Stock', multi="stock"),
'location_id': fields.many2one('stock.location', 'Parent Location', select=True, ondelete='cascade'),
'child_ids': fields.one2many('stock.location', 'location_id', 'Contains'),