[FIX] mrp: create a stock move without price_unit in MO

Steps to reproduce the bug:
- Create a storable product C1:
  - standard_price: $10
  - Update the quantity to 2 units

- Create a storable product P1 with BoM:
  - Component: 1 unit of C1

- Create a MO to produce 1 unit of P1:
  - Confirm it

- Update the price of C1 to $20

- Go back to the MO and set the quantity consumed of C1 to 2

- Mark the MO as done
- Confirm the difference in consumption

Problem:
Another move is created with 1 unit of C1 consumed but is not merged
with the first move because the two moves were created with different
prices, making them incompatible for merging.

Solution:
There's no need to create the moves with `price_unit`.

OPW-3791816

closes odoo/odoo#163175

Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
Djamel Touati
2024-04-29 08:07:27 +00:00
parent 69b2c89165
commit 14836d4084
4 changed files with 35 additions and 3 deletions
-1
View File
@@ -1192,7 +1192,6 @@ class MrpProduction(models.Model):
'raw_material_production_id': self.id,
'company_id': self.company_id.id,
'operation_id': operation_id,
'price_unit': product_id.standard_price,
'procure_method': 'make_to_stock',
'origin': self._get_origin(),
'state': 'draft',
-1
View File
@@ -309,7 +309,6 @@ class StockMove(models.Model):
product = product.browse(values['product_id'])
product_id_to_product[values['product_id']] = product
values['location_dest_id'] = mo.production_location_id.id
values['price_unit'] = product.standard_price
if not values.get('location_id'):
values['location_id'] = mo.location_src_id.id
continue
@@ -237,3 +237,37 @@ class TestManualConsumption(TestMrpCommon):
mo = self.env[action['res_model']].browse(action['res_id'])
self.assertTrue(mo.move_raw_ids.filtered(lambda m: m.product_id == p1).manual_consumption)
self.assertFalse(mo.move_raw_ids.filtered(lambda m: m.product_id == p2).manual_consumption)
def test_manual_consumption_with_different_component_price(self):
"""
Test that the moves are merged correctly, even if the products have been used with different prices:
- Create a product with a price of $10 and use it in a BoM with 1 unit.
- Create a MO with this BoM and confirm it.
- Update the price of the component to $20 and adjust the consumed quantity to 2.
- Mark the MO as done.
- Another move should be created and merged with the first move.
"""
self.bom_4.consumption = 'warning'
component = self.bom_4.bom_line_ids.product_id
component.write({
'type': 'product',
'standard_price': 10,
})
self.env['stock.quant']._update_available_quantity(component, self.stock_location, 2)
mo = self.env['mrp.production'].create({
'product_qty': 1,
'bom_id': self.bom_4.id,
})
mo.action_confirm()
self.assertEqual(mo.state, 'confirmed')
component.standard_price = 20
mo.move_raw_ids.quantity = 2.0
mo.move_raw_ids.picked = True
mo.move_raw_ids.manual_consumption = True
self.assertEqual(mo.state, 'progress')
action = mo.button_mark_done()
consumption_warning = Form(self.env['mrp.consumption.warning'].with_context(**action['context']))
action = consumption_warning.save().action_confirm()
self.assertEqual(len(mo.move_raw_ids), 1)
self.assertEqual(mo.move_raw_ids.quantity, 2)
@@ -23,7 +23,7 @@ class StockMove(models.Model):
# In case of standard price, the component cost is the cost of the product
# the subcontracting service cost may not represent the real cost of the subcontracting service
# the difference should be posted in price difference account in the end
component_cost = currency.round(sum(m.price_unit * m.product_uom_qty for m in subcontract_production.move_raw_ids))
component_cost = abs(currency.round(sum(subcontract_production.move_raw_ids.stock_valuation_layer_ids.mapped('value'))))
subcontract_service_cost = credit_value - component_cost
else:
subcontract_service_cost = currency.round(subcontract_production.extra_cost * qty)