[FIX] stock_account: price_unit after edit
- Product category: FIFO (real_time) / Automatic - Product: storable, nvoicing based on delivered quantity, FIFO category - Receive 3 units @ 30 - Create and confirm a SO for 1 unit - Deliver requested qty to customer - Unlock the picking, update the qty done to 3, lock. - Invoice delivered qty In the journal entry of the customer invoice, the COGS entry is 180 instead of 90. The root cause of this is the incorrect price unit on the modified stock move, which equals to -60 instead of -30. The price unit should compute the weigthed average of the already delivered quantity with the extra quantity. opw-2047719 closes odoo/odoo#36065 Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
This commit is contained in:
@@ -272,6 +272,7 @@ class StockMove(models.Model):
|
||||
qty_to_take_on_candidates = quantity or valued_quantity
|
||||
candidates = move.product_id._get_fifo_candidates_in_move_with_company(move.company_id.id)
|
||||
new_standard_price = 0
|
||||
tmp_qty = 0
|
||||
tmp_value = 0 # to accumulate the value taken on the candidates
|
||||
for candidate in candidates:
|
||||
new_standard_price = candidate.price_unit
|
||||
@@ -292,6 +293,7 @@ class StockMove(models.Model):
|
||||
candidate.write(candidate_vals)
|
||||
|
||||
qty_to_take_on_candidates -= qty_taken_on_candidate
|
||||
tmp_qty += qty_taken_on_candidate
|
||||
tmp_value += value_taken_on_candidate
|
||||
if qty_to_take_on_candidates == 0:
|
||||
break
|
||||
@@ -305,9 +307,18 @@ class StockMove(models.Model):
|
||||
# negative stock use case. We chose to value the out move at the price of the
|
||||
# last out and a correction entry will be made once `_fifo_vacuum` is called.
|
||||
if qty_to_take_on_candidates == 0:
|
||||
# If the move is not valued yet we compute the price_unit based on the value taken on
|
||||
# the candidates.
|
||||
# If the move has already been valued, it means that we editing the qty_done on the
|
||||
# move. In this case, the price_unit computation should take into account the quantity
|
||||
# already valued and the new quantity taken.
|
||||
if not move.value:
|
||||
price_unit = -tmp_value / (move.product_qty or quantity)
|
||||
else:
|
||||
price_unit = (-(tmp_value) + move.value) / (tmp_qty + move.product_qty)
|
||||
move.write({
|
||||
'value': -tmp_value if not quantity else move.value or -tmp_value, # outgoing move are valued negatively
|
||||
'price_unit': -tmp_value / (move.product_qty or quantity),
|
||||
'price_unit': price_unit,
|
||||
})
|
||||
elif qty_to_take_on_candidates > 0:
|
||||
last_fifo_price = new_standard_price or move.product_id.standard_price
|
||||
|
||||
@@ -2152,6 +2152,7 @@ class TestStockValuation(TransactionCase):
|
||||
|
||||
# stock values for move3
|
||||
self.assertEqual(move3.value, -80.0)
|
||||
self.assertAlmostEqual(move3.price_unit, -10.0)
|
||||
self.assertEqual(move3.remaining_qty, 0.0)
|
||||
self.assertEqual(move3.remaining_value, 0.0)
|
||||
|
||||
@@ -2183,6 +2184,7 @@ class TestStockValuation(TransactionCase):
|
||||
# old value: -80 -(8@10)
|
||||
# new value: -148 => -(10@10 + 4@12)
|
||||
self.assertEqual(move3.value, -148)
|
||||
self.assertAlmostEqual(move3.price_unit, -148.0/14.0)
|
||||
|
||||
# older move
|
||||
self.assertEqual(move1.remaining_value, 0) # before, 20
|
||||
@@ -2271,6 +2273,7 @@ class TestStockValuation(TransactionCase):
|
||||
|
||||
# stock values for move2
|
||||
self.assertEqual(move2.value, -100.0)
|
||||
self.assertAlmostEqual(move2.price_unit, -10.0)
|
||||
self.assertEqual(move2.remaining_qty, 0.0)
|
||||
self.assertEqual(move2.remaining_value, 0.0)
|
||||
|
||||
@@ -2280,6 +2283,7 @@ class TestStockValuation(TransactionCase):
|
||||
move2.quantity_done = 8
|
||||
|
||||
self.assertEqual(move2.value, -80.0) # the move actually sent 8@10
|
||||
self.assertAlmostEqual(move2.price_unit, -10.0)
|
||||
self.assertEqual(move2.remaining_qty, 0.0)
|
||||
self.assertEqual(move2.remaining_value, 0.0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user