From 42331b3fb59f7c2a2f3a8d1bb407bd4b2b7699fc Mon Sep 17 00:00:00 2001 From: Adrien Widart Date: Fri, 19 Nov 2021 07:36:15 +0000 Subject: [PATCH] [FIX] mrp: fully cancel MO even if no component When cancelling a manufacturing order that does not include any component, the associated moves won't be cancelled. To reproduce the issue: 1. Create a storable product P 2. Create & Confirm a MO for 1 x P 3. Cancel the MO 4. Consult the form page of P Error: The forecasted quantity of P is 1 instead of 0 The finished move associated to the MO hasn't been cancelled. Since [1], we have the possibility to process MOs without any component, so the cancellation process shouldn't be bypassed anymore. [1] bf5e1debf9c684c1bbf3ca440a87001fd7faf9fa OPW-2691422 closes odoo/odoo#80407 X-original-commit: 2adff866a598fc8fb872fb8127875fbb7cc7335c Signed-off-by: Arnold Moyaux Signed-off-by: Adrien Widart --- addons/mrp/models/mrp_production.py | 5 +---- addons/mrp/models/stock_move.py | 7 +++---- addons/mrp/tests/test_cancel_mo.py | 15 +++++++++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/addons/mrp/models/mrp_production.py b/addons/mrp/models/mrp_production.py index 4df7ce239d2..592b67d808c 100644 --- a/addons/mrp/models/mrp_production.py +++ b/addons/mrp/models/mrp_production.py @@ -456,7 +456,7 @@ class MrpProduction(models.Model): for production in self: if not production.state: production.state = 'draft' - elif production.state == 'cancel' or (production.move_raw_ids and all(move.state == 'cancel' for move in production.move_raw_ids)): + elif production.state == 'cancel' or (production.move_finished_ids and all(move.state == 'cancel' for move in production.move_finished_ids)): production.state = 'cancel' elif production.state == 'done' or (production.move_raw_ids and all(move.state in ('cancel', 'done') for move in production.move_raw_ids)): production.state = 'done' @@ -1359,9 +1359,6 @@ class MrpProduction(models.Model): def action_cancel(self): """ Cancels production order, unfinished stock moves and set procurement orders in exception """ - if not self.move_raw_ids: - self.state = 'cancel' - return True self._action_cancel() return True diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py index 508d5e65740..a263b26c8e7 100644 --- a/addons/mrp/models/stock_move.py +++ b/addons/mrp/models/stock_move.py @@ -312,10 +312,9 @@ class StockMove(models.Model): def _action_cancel(self): res = super(StockMove, self)._action_cancel() - for production in self.mapped('raw_material_production_id'): - if production.state != 'cancel': - continue - production._action_cancel() + mo_to_cancel = self.mapped('raw_material_production_id').filtered(lambda p: all(m.state == 'cancel' for m in p.move_raw_ids)) + if mo_to_cancel: + mo_to_cancel._action_cancel() return res def _prepare_move_split_vals(self, qty): diff --git a/addons/mrp/tests/test_cancel_mo.py b/addons/mrp/tests/test_cancel_mo.py index d305571c8b9..51ec47fe22c 100644 --- a/addons/mrp/tests/test_cancel_mo.py +++ b/addons/mrp/tests/test_cancel_mo.py @@ -101,3 +101,18 @@ class TestMrpCancelMO(TestMrpCommon): self.assertEqual(manufacturing_order.exists().state, 'progress') with self.assertRaises(UserError): manufacturing_order.unlink() + + def test_cancel_mo_without_component(self): + product_form = Form(self.env['product.product']) + product_form.name = "SuperProduct" + product = product_form.save() + + mo_form = Form(self.env['mrp.production']) + mo_form.product_id = product + mo = mo_form.save() + + mo.action_confirm() + mo.action_cancel() + + self.assertEqual(mo.move_finished_ids.state, 'cancel') + self.assertEqual(mo.state, 'cancel')