From bfadcdd5d6cd7e2a081efcc5f537d80be3812be8 Mon Sep 17 00:00:00 2001 From: Julien Legros Date: Fri, 28 Nov 2014 13:39:37 +0100 Subject: [PATCH] [FIX] stock: compute average price on action_done The average price computation is now deduplicated and moved to a separate function called in stock_move action_done. This makes sure it is always called when a stock.move is processed, even without going through the partial picking wizard. Fixes #2991 Closes #3949 OPW-615491 --- addons/stock/stock.py | 114 ++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 64 deletions(-) diff --git a/addons/stock/stock.py b/addons/stock/stock.py index 7dc39c150a2..23c72379919 100644 --- a/addons/stock/stock.py +++ b/addons/stock/stock.py @@ -1233,8 +1233,6 @@ class stock_picking(osv.osv): context = dict(context) res = {} move_obj = self.pool.get('stock.move') - product_obj = self.pool.get('product.product') - currency_obj = self.pool.get('res.currency') uom_obj = self.pool.get('product.uom') sequence_obj = self.pool.get('ir.sequence') wf_service = netsvc.LocalService("workflow") @@ -1263,40 +1261,12 @@ class stock_picking(osv.osv): else: too_many.append(move) - # Average price computation if (pick.type == 'in') and (move.product_id.cost_method == 'average'): - product = product_obj.browse(cr, uid, move.product_id.id) - move_currency_id = move.company_id.currency_id.id - context['currency_id'] = move_currency_id - qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id) - - if product.id not in product_avail: - # keep track of stock on hand including processed lines not yet marked as done - product_avail[product.id] = product.qty_available - - if qty > 0: - new_price = currency_obj.compute(cr, uid, product_currency, - move_currency_id, product_price, round=False) - new_price = uom_obj._compute_price(cr, uid, product_uom, new_price, - product.uom_id.id) - if product_avail[product.id] <= 0: - product_avail[product.id] = 0 - new_std_price = new_price - else: - # Get the standard price - amount_unit = product.price_get('standard_price', context=context)[product.id] - new_std_price = ((amount_unit * product_avail[product.id])\ - + (new_price * qty))/(product_avail[product.id] + qty) - # Write the field according to price type field - product_obj.write(cr, uid, [product.id], {'standard_price': new_std_price}) - - # Record the values that were chosen in the wizard, so they can be - # used for inventory valuation if real-time valuation is enabled. - move_obj.write(cr, uid, [move.id], - {'price_unit': product_price, - 'price_currency_id': product_currency}) - - product_avail[product.id] += qty + # Record the values that were chosen in the wizard, so they can be + # used for average price computation and inventory valuation + move_obj.write(cr, uid, [move.id], + {'price_unit': product_price, + 'price_currency_id': product_currency}) # every line of the picking is empty, do not generate anything empty_picking = not any(q for q in move_product_qty.values() if q > 0) @@ -2343,6 +2313,44 @@ class stock_move(osv.osv): return reference_amount, reference_currency_id + def _update_average_price(self, cr, uid, move, context=None): + product_obj = self.pool.get('product.product') + currency_obj = self.pool.get('res.currency') + uom_obj = self.pool.get('product.uom') + product_avail = {} + + if (move.picking_id.type == 'in') and (move.product_id.cost_method == 'average'): + product = product_obj.browse(cr, uid, move.product_id.id) + move_currency_id = move.company_id.currency_id.id + context['currency_id'] = move_currency_id + + product_qty = move.product_qty + product_uom = move.product_uom.id + product_price = move.price_unit + product_currency = move.price_currency_id.id + + if product.id not in product_avail: + # keep track of stock on hand including processed lines not yet marked as done + product_avail[product.id] = product.qty_available + + qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id) + if qty > 0: + new_price = currency_obj.compute(cr, uid, product_currency, + move_currency_id, product_price, round=False) + new_price = uom_obj._compute_price(cr, uid, product_uom, new_price, + product.uom_id.id) + if product_avail[product.id] <= 0: + product_avail[product.id] = 0 + new_std_price = new_price + else: + # Get the standard price + amount_unit = product.price_get('standard_price', context=context)[product.id] + new_std_price = ((amount_unit * product_avail[product.id])\ + + (new_price * qty))/(product_avail[product.id] + qty) + + product_obj.write(cr, uid, [product.id],{'standard_price': new_std_price}) + + product_avail[product.id] += qty def _create_product_valuation_moves(self, cr, uid, move, context=None): """ @@ -2430,6 +2438,7 @@ class stock_move(osv.osv): if move.move_dest_id.auto_validate: self.action_done(cr, uid, [move.move_dest_id.id], context=context) + self._update_average_price(cr, uid, move, context=context) self._create_product_valuation_moves(cr, uid, move, context=context) if move.state not in ('confirmed','done','assigned'): todo.append(move.id) @@ -2692,9 +2701,6 @@ class stock_move(osv.osv): """ res = {} picking_obj = self.pool.get('stock.picking') - product_obj = self.pool.get('product.product') - currency_obj = self.pool.get('res.currency') - uom_obj = self.pool.get('product.uom') wf_service = netsvc.LocalService("workflow") if context is None: @@ -2721,33 +2727,13 @@ class stock_move(osv.osv): else: too_many.append(move) - # Average price computation if (move.picking_id.type == 'in') and (move.product_id.cost_method == 'average'): - product = product_obj.browse(cr, uid, move.product_id.id) - move_currency_id = move.company_id.currency_id.id - context['currency_id'] = move_currency_id - qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id) - if qty > 0: - new_price = currency_obj.compute(cr, uid, product_currency, - move_currency_id, product_price, round=False) - new_price = uom_obj._compute_price(cr, uid, product_uom, new_price, - product.uom_id.id) - if product.qty_available <= 0: - new_std_price = new_price - else: - # Get the standard price - amount_unit = product.price_get('standard_price', context=context)[product.id] - new_std_price = ((amount_unit * product.qty_available)\ - + (new_price * qty))/(product.qty_available + qty) - - product_obj.write(cr, uid, [product.id],{'standard_price': new_std_price}) - - # Record the values that were chosen in the wizard, so they can be - # used for inventory valuation if real-time valuation is enabled. - self.write(cr, uid, [move.id], - {'price_unit': product_price, - 'price_currency_id': product_currency, - }) + # Record the values that were chosen in the wizard, so they can be + # used for average price computation and inventory valuation + self.write(cr, uid, [move.id], + {'price_unit': product_price, + 'price_currency_id': product_currency, + }) for move in too_few: product_qty = move_product_qty[move.id]