summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlase@odoo.com <lase@odoo.com>2025-02-04 07:37:49 +0000
committerlase@odoo.com <lase@odoo.com>2025-02-07 12:41:02 +0000
commitfd5e49305b7f2dcdf05b16c28fab6469a079b604 (patch)
tree23dee021d4a44d2c4b7db16629eb60d2b5fcc59e
parent68c1a13d73176273f54686ebbad2cc9bffb24c86 (diff)
[FIX] mrp{,_workorder}: ignore move raws without demand in reservation state
Issue: Curently, the reservation state of a production is computed from the status of the move raws that are not picked. This includes moves wihtout demands which should not infer with the reservation state at all. Steps to reproduce: - In the settings, Enable "Multi-Step Routes" - Go to Inventory > Configuration > Warehouse Management > Warehouses - Put your warehouse in 2 steps-manufacturing - Create a final product (FP) tracked by Serial number, and 2 storable components: COMP1 and COMP2 - Create a BOM for FP: - Component lines: - 1 x COMP1 - 0 x COMP2 !! - Operations: - OP1 with an instruction of type "register production" 1. Create an MO for 1 x FP > Confirm 2. Validate the pick transfer for 1 unit of COMP1 > Currently OP1 is marked as ready 3. Mark the component line of COMP1 as "picked" > OP1 is in waiting status Same result as 3: 3'. Go to the shopfloor > register production from the MO card > This will pick the COMP1 raw move and OP1 will disappear because of > the "ready" filter Cause of the issue: Since you manufacture in 2 steps, the state of the raw move of COMP2 is waiting even though its demand is 0 (before and after you validated the pick move for COMP1). However, only non picked moves are considered to be relevant in the computation of the reservation state of the MO: https://github.com/odoo/odoo/blob/d8fc04f5875dbd3098e58f382d0cea3c7c7c38af/addons/mrp/models/mrp_production.py#L613-L621 Once you pick the COMP1 move which should be the only relevant one the reservation state of the MO becomes computed solely based on the state of the COMP2 raw move and becomes "waiting". In turns, this triggers a recomputation of the state of the workorders and flagging it as waiting: https://github.com/odoo/odoo/blob/d8fc04f5875dbd3098e58f382d0cea3c7c7c38af/addons/mrp/models/mrp_workorder.py#L148-L165 opw-4383004 closes odoo/odoo#196682 X-original-commit: 88235a0fd3415a608ac1b0322a6b1f048f8bcaed Signed-off-by: William Henrotin (whe) <whe@odoo.com> Signed-off-by: Lancelot Semal (lase) <lase@odoo.com>
-rw-r--r--addons/mrp/models/mrp_production.py2
-rw-r--r--addons/mrp/tests/test_manual_consumption.py26
2 files changed, 27 insertions, 1 deletions
diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py
index dd03e8be1ed..e1998138a3b 100644
--- a/addons/mrp/models/mrp_production.py
+++ b/addons/mrp/models/mrp_production.py
@@ -619,7 +619,7 @@ class MrpProduction(models.Model):
if production.state in ('draft', 'done', 'cancel'):
production.reservation_state = False
continue
- relevant_move_state = production.move_raw_ids.filtered(lambda m: not m.picked)._get_relevant_state_among_moves()
+ relevant_move_state = production.move_raw_ids.filtered(lambda m: not (m.picked or float_is_zero(m.product_uom_qty, precision_rounding=m.product_uom.rounding)))._get_relevant_state_among_moves()
# Compute reservation state according to its component's moves.
if relevant_move_state == 'partially_available':
if production.workorder_ids.operation_id and production.bom_id.ready_to_produce == 'asap':
diff --git a/addons/mrp/tests/test_manual_consumption.py b/addons/mrp/tests/test_manual_consumption.py
index f2e81eb6e45..b6e78165a2b 100644
--- a/addons/mrp/tests/test_manual_consumption.py
+++ b/addons/mrp/tests/test_manual_consumption.py
@@ -276,3 +276,29 @@ class TestManualConsumption(TestMrpCommon):
self.assertEqual(mo.move_raw_ids.mapped('manual_consumption'), [True, False])
self.assertEqual(components[0].stock_quant_ids.reserved_quantity, 3.0)
self.assertRecordValues(mo.move_raw_ids, [{'quantity': 3.0, 'picked': True}, {'quantity': 2.0, 'picked': True}])
+
+ def test_reservation_state_with_manual_consumption(self):
+ """
+ Check that the reservation state of an MO is not influenced by moves without demand.
+ """
+ self.warehouse_1.manufacture_steps = "pbm"
+ bom = self.bom_1
+ components = bom.bom_line_ids.mapped('product_id')
+ components.is_storable = True
+ # make the second component optional
+ bom.bom_line_ids[-1].product_qty = 0.0
+ self.env['stock.quant']._update_available_quantity(components[0], self.warehouse_1.lot_stock_id, 10.0)
+ mo_form = Form(self.env['mrp.production'])
+ mo_form.picking_type_id = self.warehouse_1.manu_type_id
+ mo_form.bom_id = bom
+ mo_form.product_qty = 4
+ mo = mo_form.save()
+ mo.action_confirm()
+ self.assertRecordValues(mo.picking_ids.move_ids, [
+ { "product_id": components[0].id, "product_uom_qty": 2.0}
+ ])
+ self.assertEqual(mo.reservation_state, "waiting")
+ mo.picking_ids.button_validate()
+ self.assertEqual(mo.reservation_state, "assigned")
+ mo.move_raw_ids.filtered(lambda m: m.product_id == components[0]).picked = True
+ self.assertEqual(mo.reservation_state, "assigned")