diff --git a/rma/models/rma_order_line.py b/rma/models/rma_order_line.py index 6ad55456f..f9d148a2d 100644 --- a/rma/models/rma_order_line.py +++ b/rma/models/rma_order_line.py @@ -692,12 +692,19 @@ def check_cancel(self): def action_rma_cancel(self): for order in self: order.check_cancel() + # cancel ongoing orig moves + # dest move cancelation can be managed with propagate_cancel option + # on stock rules. + moves = order.move_ids + to_cancel_orig_moves = self.env["stock.move"] + while moves: + moves = moves.move_orig_ids.filtered( + lambda m: m.state not in ("done", "cancel") and m.picking_id + ) + to_cancel_orig_moves |= moves + to_cancel_orig_moves._action_cancel() order.write({"state": "canceled"}) order.move_ids._action_cancel() - shipments = order._get_in_pickings() - shipments |= order._get_out_pickings() - for ship in shipments: - ship.action_cancel() return True def _get_price_unit(self): diff --git a/rma/tests/test_rma.py b/rma/tests/test_rma.py index 5ab4bbd40..21a1f9631 100644 --- a/rma/tests/test_rma.py +++ b/rma/tests/test_rma.py @@ -1093,3 +1093,93 @@ def test_09_rma_state(self): self.assertEqual( rma.rma_line_ids.mapped("state"), ["approved", "approved", "approved"] ) + + def test_10_rma_cancel_line(self): + # configure a new rule to make reception and expedition in 2 steps + rma_route = self.env.ref("rma.route_rma_customer") + rma_loc = self.env.ref("rma.location_rma") + rma_customer_rule = self.env.ref("rma.rule_rma_customer_out_pull") + rma_customer_rule.write({"procure_method": "make_to_order"}) + self.env["stock.rule"].create( + { + "name": "reception => rma", + "action": "pull", + "picking_type_id": self.wh.int_type_id.id, + "location_src_id": self.wh.wh_input_stock_loc_id.id, + "location_dest_id": rma_loc.id, + "procure_method": "make_to_stock", + "route_id": rma_route.id, + "warehouse_id": self.wh.id, + "company_id": self.wh.company_id.id, + } + ) + self.env["stock.rule"].create( + { + "name": "rma => reception", + "action": "push", + "picking_type_id": self.wh.int_type_id.id, + "location_src_id": rma_loc.id, + "location_dest_id": self.wh.wh_input_stock_loc_id.id, + "procure_method": "make_to_stock", + "route_id": rma_route.id, + "warehouse_id": self.wh.id, + "company_id": self.wh.company_id.id, + } + ) + # Generate expedition for the rma group + self.rma_customer_id.rma_line_ids.action_rma_to_approve() + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": self.rma_customer_id.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + "active_id": 1, + } + ).create({}) + wizard._create_picking() + self.rma_customer_id.rma_line_ids.action_view_in_shipments() + # cancel first line and check it cancel the dest moves, but leave the picking + # ongoing for the 2 other lines + first_rma_line = self.rma_customer_id.rma_line_ids[0] + second_rma_line = self.rma_customer_id.rma_line_ids[1] + first_line_in_move = first_rma_line.move_ids.filtered( + lambda m: m.location_dest_id == rma_loc + ) + first_line_in_dest_move = first_line_in_move.move_dest_ids + reception_picking = first_line_in_move.picking_id + self.assertEqual(first_line_in_dest_move.state, "waiting") + first_rma_line.action_rma_cancel() + self.assertEqual(first_line_in_dest_move.state, "cancel") + self.assertEqual(first_line_in_move.state, "cancel") + self.assertEqual(reception_picking.state, "assigned") + second_line_in_move = second_rma_line.move_ids.filtered( + lambda m: m.location_dest_id == rma_loc + ) + self.assertEqual(second_line_in_move.state, "assigned") + + # generate 2 step expedition for the 2 remaining lines + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": self.rma_customer_id.rma_line_ids.filtered( + lambda rol: rol.state != "canceled" + ).ids, + "active_model": "rma.order.line", + "picking_type": "outgoing", + "active_id": 1, + } + ).create({}) + for line in wizard.item_ids: + line.qty_to_deliver = line.product_qty + wizard._create_picking() + # cancel first line, check both chained move are canceled + second_rma_out_move = second_rma_line.move_ids.filtered( + lambda m: m.picking_id.picking_type_code == "outgoing" + ) + second_rma_out_move_orig = second_rma_out_move.move_orig_ids + self.assertTrue(second_rma_out_move_orig) + self.assertEqual(second_rma_out_move.state, "waiting") + second_rma_line.action_rma_cancel() + self.assertEqual(second_rma_out_move.state, "cancel") + self.assertEqual(second_rma_out_move_orig.state, "cancel") + # check picking is not canceled because third line has not been yet. + self.assertEqual(second_rma_out_move.picking_id.state, "waiting")