From ea340afafa90bc6bc421a83d3ae1977efac808f4 Mon Sep 17 00:00:00 2001 From: Arnold Moyaux Date: Thu, 2 Jan 2020 09:42:12 +0000 Subject: [PATCH] [FIX] mrp_subcontracting: cancel a PO should cancel delivery When subcontracting a product via a purchase order and not a simple receipt. Then the cancelation of the receipt will not only cancel the receipt of the finished product but not the delivery for the components. It happens because button_cancel on purchase order will call _action_cancel the stock.move linked to purchase order line. It will not call action_cancel on the stock.picking. However the part responsible for the cancelation of components delivery is in the stock.picking action_cancel method. Move the stock.picking action_cancel logic in the stock.move _action_cancel method since it's always call for both usecase. Fixes #42551 closes odoo/odoo#42653 X-original-commit: 841305f271411c3a67af271ac09da9ce0922f100 Signed-off-by: Simon Lejeune (sle) --- .../mrp_subcontracting/models/stock_move.py | 6 ++++ .../models/stock_picking.py | 5 --- .../tests/test_subcontracting.py | 35 +++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/addons/mrp_subcontracting/models/stock_move.py b/addons/mrp_subcontracting/models/stock_move.py index 21884eb269e..a6d8a61dd91 100644 --- a/addons/mrp_subcontracting/models/stock_move.py +++ b/addons/mrp_subcontracting/models/stock_move.py @@ -93,6 +93,12 @@ class StockMove(models.Model): 'domain': [('id', 'in', moves.ids)], } + def _action_cancel(self): + for move in self: + if move.is_subcontract: + move.move_orig_ids.production_id._action_cancel() + return super()._action_cancel() + def _action_confirm(self, merge=True, merge_into=False): subcontract_details_per_picking = defaultdict(list) for move in self: diff --git a/addons/mrp_subcontracting/models/stock_picking.py b/addons/mrp_subcontracting/models/stock_picking.py index e3040792084..29c44aec51b 100644 --- a/addons/mrp_subcontracting/models/stock_picking.py +++ b/addons/mrp_subcontracting/models/stock_picking.py @@ -36,11 +36,6 @@ class StockPicking(models.Model): # ------------------------------------------------------------------------- # Action methods # ------------------------------------------------------------------------- - def action_cancel(self): - for picking in self: - picking._get_subcontracted_productions()._action_cancel() - return super(StockPicking, self).action_cancel() - def _action_done(self): res = super(StockPicking, self)._action_done() productions = self.env['mrp.production'] diff --git a/addons/mrp_subcontracting/tests/test_subcontracting.py b/addons/mrp_subcontracting/tests/test_subcontracting.py index fc8e01d1a18..8f7a2b2abf7 100644 --- a/addons/mrp_subcontracting/tests/test_subcontracting.py +++ b/addons/mrp_subcontracting/tests/test_subcontracting.py @@ -540,6 +540,41 @@ class TestSubcontractingFlows(TestMrpSubcontractingCommon): backorder._action_done() self.assertTrue(picking_receipt.move_lines.move_orig_ids.production_id.state == 'done') + def test_flow_9(self): + """Ensure that cancel the subcontract moves will also delete the + components need for the subcontractor. + """ + resupply_sub_on_order_route = self.env['stock.location.route'].search([ + ('name', '=', 'Resupply Subcontractor on Order') + ]) + (self.comp1 + self.comp2).write({ + 'route_ids': [(4, resupply_sub_on_order_route.id)] + }) + + picking_form = Form(self.env['stock.picking']) + picking_form.picking_type_id = self.env.ref('stock.picking_type_in') + picking_form.partner_id = self.subcontractor_partner1 + with picking_form.move_ids_without_package.new() as move: + move.product_id = self.finished + move.product_uom_qty = 5 + picking_receipt = picking_form.save() + picking_receipt.action_confirm() + + picking_delivery = self.env['stock.move'].search([ + ('product_id', 'in', (self.comp1 | self.comp2).ids) + ]).picking_id + self.assertTrue(picking_delivery) + self.assertEqual(picking_delivery.state, 'confirmed') + self.assertEqual(self.comp1.virtual_available, -5) + self.assertEqual(self.comp2.virtual_available, -5) + # action_cancel is not call on the picking in order + # to test behavior from other source than picking (e.g. puchase). + picking_receipt.move_lines._action_cancel() + self.assertEqual(picking_delivery.state, 'cancel') + self.assertEqual(self.comp1.virtual_available, 0.0) + self.assertEqual(self.comp1.virtual_available, 0.0) + + class TestSubcontractingTracking(TransactionCase): def setUp(self): super(TestSubcontractingTracking, self).setUp()