[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
This commit is contained in:
parent
13d0934f34
commit
bfadcdd5d6
|
@ -1233,8 +1233,6 @@ class stock_picking(osv.osv):
|
||||||
context = dict(context)
|
context = dict(context)
|
||||||
res = {}
|
res = {}
|
||||||
move_obj = self.pool.get('stock.move')
|
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')
|
uom_obj = self.pool.get('product.uom')
|
||||||
sequence_obj = self.pool.get('ir.sequence')
|
sequence_obj = self.pool.get('ir.sequence')
|
||||||
wf_service = netsvc.LocalService("workflow")
|
wf_service = netsvc.LocalService("workflow")
|
||||||
|
@ -1263,40 +1261,12 @@ class stock_picking(osv.osv):
|
||||||
else:
|
else:
|
||||||
too_many.append(move)
|
too_many.append(move)
|
||||||
|
|
||||||
# Average price computation
|
|
||||||
if (pick.type == 'in') and (move.product_id.cost_method == 'average'):
|
if (pick.type == 'in') and (move.product_id.cost_method == 'average'):
|
||||||
product = product_obj.browse(cr, uid, move.product_id.id)
|
# Record the values that were chosen in the wizard, so they can be
|
||||||
move_currency_id = move.company_id.currency_id.id
|
# used for average price computation and inventory valuation
|
||||||
context['currency_id'] = move_currency_id
|
move_obj.write(cr, uid, [move.id],
|
||||||
qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
|
{'price_unit': product_price,
|
||||||
|
'price_currency_id': product_currency})
|
||||||
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
|
|
||||||
|
|
||||||
# every line of the picking is empty, do not generate anything
|
# 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)
|
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
|
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):
|
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:
|
if move.move_dest_id.auto_validate:
|
||||||
self.action_done(cr, uid, [move.move_dest_id.id], context=context)
|
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)
|
self._create_product_valuation_moves(cr, uid, move, context=context)
|
||||||
if move.state not in ('confirmed','done','assigned'):
|
if move.state not in ('confirmed','done','assigned'):
|
||||||
todo.append(move.id)
|
todo.append(move.id)
|
||||||
|
@ -2692,9 +2701,6 @@ class stock_move(osv.osv):
|
||||||
"""
|
"""
|
||||||
res = {}
|
res = {}
|
||||||
picking_obj = self.pool.get('stock.picking')
|
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")
|
wf_service = netsvc.LocalService("workflow")
|
||||||
|
|
||||||
if context is None:
|
if context is None:
|
||||||
|
@ -2721,33 +2727,13 @@ class stock_move(osv.osv):
|
||||||
else:
|
else:
|
||||||
too_many.append(move)
|
too_many.append(move)
|
||||||
|
|
||||||
# Average price computation
|
|
||||||
if (move.picking_id.type == 'in') and (move.product_id.cost_method == 'average'):
|
if (move.picking_id.type == 'in') and (move.product_id.cost_method == 'average'):
|
||||||
product = product_obj.browse(cr, uid, move.product_id.id)
|
# Record the values that were chosen in the wizard, so they can be
|
||||||
move_currency_id = move.company_id.currency_id.id
|
# used for average price computation and inventory valuation
|
||||||
context['currency_id'] = move_currency_id
|
self.write(cr, uid, [move.id],
|
||||||
qty = uom_obj._compute_qty(cr, uid, product_uom, product_qty, product.uom_id.id)
|
{'price_unit': product_price,
|
||||||
if qty > 0:
|
'price_currency_id': product_currency,
|
||||||
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,
|
|
||||||
})
|
|
||||||
|
|
||||||
for move in too_few:
|
for move in too_few:
|
||||||
product_qty = move_product_qty[move.id]
|
product_qty = move_product_qty[move.id]
|
||||||
|
|
Loading…
Reference in New Issue