[FIX] mrp: prevent from merging other products' SM

To reproduce the issue:
1. In Settings, enable:
   - Multi-Routes
2. Unarchive the route MTO
3. Create three storable product P1, P2, P3:
   - P2:
     - With route MTO
4. Create and confirm a MO:
   - Product: P1
   - Components:
     - 1 x P2
     - 1 x P3
     - 1 x P3
5. Set the produced/consumed quantities:
   - For P2, set 1.5
6. Mark the MO as done

Error: an error message is displayed: "Record does not exist or has
been deleted."

In `SM._action_done`, we create some extra moves:
https://github.com/odoo/odoo/blob/e029abe649573350e633999e42ab040c57b8fe4e/addons/stock/models/stock_move.py#L1705-L1710
Because of the exceed quantity on the first components line, we
create a new SM (qty 0.5). There is a difference between both SM:
the `procure_method` (MTO for the initial SM, MTS for the new one).
Because of that difference, when confirming the new SM, we don't
provide any `merge_into` (the `else` block):
https://github.com/odoo/odoo/blob/e029abe649573350e633999e42ab040c57b8fe4e/addons/stock/models/stock_move.py#L1684-L1690
Confirming the new SM leads to the `_merge_moves` method. In this
method, because we didn't provide any `merge_into`, we first try to
get some candidates:
https://github.com/odoo/odoo/blob/e029abe649573350e633999e42ab040c57b8fe4e/addons/stock/models/stock_move.py#L866-L868
And at that point, we will provide with all components SMs:
https://github.com/odoo/odoo/blob/e029abe649573350e633999e42ab040c57b8fe4e/addons/mrp/models/stock_move.py#L494-L497
So, we will also provide the two SM of C02. Therefore, the method
will merge these SMs and unlink the second one. Then, back to the
extra moves creation in `SM._action_done`, the for loop will iterate
on the deleted record, hence the error.

OPW-3454899

closes odoo/odoo#135305

X-original-commit: 2674851f66253efea19b86eb9d428dd6e85fa06d
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
Signed-off-by: Adrien Widart (awt) <awt@odoo.com>
This commit is contained in:
Adrien Widart (awt)
2023-09-14 09:57:50 +00:00
parent 3c55228015
commit 7ed1c1a074
2 changed files with 46 additions and 2 deletions
+2 -2
View File
@@ -551,9 +551,9 @@ class StockMove(models.Model):
def _update_candidate_moves_list(self, candidate_moves_set):
super()._update_candidate_moves_list(candidate_moves_set)
for production in self.mapped('raw_material_production_id'):
candidate_moves_set.add(production.move_raw_ids)
candidate_moves_set.add(production.move_raw_ids.filtered(lambda m: m.product_id in self.product_id))
for production in self.mapped('production_id'):
candidate_moves_set.add(production.move_finished_ids)
candidate_moves_set.add(production.move_finished_ids.filtered(lambda m: m.product_id in self.product_id))
# this will include sibling pickings as a result of merging MOs
for picking in self.move_dest_ids.raw_material_production_id.picking_ids:
candidate_moves_set.add(picking.move_ids)
+44
View File
@@ -3303,3 +3303,47 @@ class TestMrpOrder(TestMrpCommon):
consumption.action_set_qty()
self.assertEqual(mo.move_raw_ids[0].product_uom_qty, 30)
self.assertEqual(mo.move_raw_ids[0].quantity_done, 30)
def test_exceeded_consumed_qty_and_duplicated_lines(self):
"""
Two components C01, C02. C01 has the MTO route.
MO with 1 x C01, 1 x C02, 1 x C02.
Process the MO and set a high consumed qty for C01.
Ensure that the MO can still be processed and that the consumed quantities
are correct.
"""
warehouse = self.env['stock.warehouse'].search([('company_id', '=', self.env.company.id)], limit=1)
mto_route = warehouse.mto_pull_id.route_id
manufacture_route = warehouse.manufacture_pull_id.route_id
mto_route.active = True
product01, product02, product03 = self.env['product.product'].create([{
'name': 'Product %s' % (i + 1),
'type': 'product',
} for i in range(3)])
product02.route_ids = [(6, 0, (mto_route | manufacture_route).ids)]
mo_form = Form(self.env['mrp.production'])
mo_form.product_id = product01
mo_form.product_qty = 1
for component in (product02, product03, product03):
with mo_form.move_raw_ids.new() as line:
line.product_id = component
line.product_uom_qty = 1
mo = mo_form.save()
mo.action_confirm()
mo_form = Form(mo)
mo_form.qty_producing = 1.0
mo = mo_form.save()
mo.move_raw_ids[0].move_line_ids.qty_done = 1.5
mo.button_mark_done()
self.assertEqual(mo.state, 'done')
p02_raws = mo.move_raw_ids.filtered(lambda m: m.product_id == product02)
p03_raws = mo.move_raw_ids.filtered(lambda m: m.product_id == product03)
self.assertEqual(sum(p02_raws.mapped('quantity_done')), 1.5)
self.assertEqual(sum(p03_raws.mapped('quantity_done')), 2)