From 48c2fedd9efe9c9533bf171934da640ce18dbf35 Mon Sep 17 00:00:00 2001 From: Florian da Costa Date: Thu, 7 Nov 2024 16:17:11 +0100 Subject: [PATCH] [FIX] rma: qty received and shipped in case of multiple step reception/expedition Now the moves are filtered and only 1 move of the chain is selected to compute the quantity (the first one for reception and last one for expedition), so we should no longer ignore those to compute the quantities --- rma/models/rma_order_line.py | 7 +- rma/tests/test_rma.py | 132 ++++++++++++++++++++++++++--------- 2 files changed, 99 insertions(+), 40 deletions(-) diff --git a/rma/models/rma_order_line.py b/rma/models/rma_order_line.py index fd53d9ae..ea97ce6d 100644 --- a/rma/models/rma_order_line.py +++ b/rma/models/rma_order_line.py @@ -125,11 +125,6 @@ class RmaOrderLine(models.Model): ) ) for move in moves: - # If the move is part of a chain don't count it - if direction == "out" and move.move_orig_ids: - continue - elif direction == "in" and move.move_dest_ids: - continue qty += product_obj._compute_quantity(move.product_uom_qty, rec.uom_id) return qty @@ -184,7 +179,7 @@ class RmaOrderLine(models.Model): def _compute_qty_outgoing(self): for rec in self: qty = rec._get_rma_move_qty( - ("draft", "confirmed", "assigned"), direction="out" + ("draft", "confirmed", "assigned", "waiting"), direction="out" ) rec.qty_outgoing = qty diff --git a/rma/tests/test_rma.py b/rma/tests/test_rma.py index 20c1caa4..489e4017 100644 --- a/rma/tests/test_rma.py +++ b/rma/tests/test_rma.py @@ -78,6 +78,51 @@ class TestRma(common.TransactionCase): cls.rma_supplier_id = cls._create_rma_from_move( products2move, "supplier", cls.env.ref("base.res_partner_2"), dropship=False ) + # create rules to have multi step reception/shipment, unactive by default + cls.test_rma_loc = cls.stock_rma_location.copy({"name": "rma loc shipping"}) + rma_route = cls.env.ref("rma.route_rma_customer") + cls.second_step_incoming_rule = cls.env["stock.rule"].create( + { + "name": "reception => rma loc shipping", + "action": "pull", + "picking_type_id": cls.wh.int_type_id.id, + "location_src_id": cls.wh.wh_input_stock_loc_id.id, + "location_dest_id": cls.test_rma_loc.id, + "procure_method": "make_to_stock", + "route_id": rma_route.id, + "warehouse_id": cls.wh.id, + "company_id": cls.wh.company_id.id, + "active": False, + "sequence": 0, + } + ) + cls.second_step_outgoing_rule = cls.env["stock.rule"].create( + { + "name": "rma => reception", + "action": "push", + "picking_type_id": cls.wh.int_type_id.id, + "location_src_id": cls.stock_rma_location.id, + "location_dest_id": cls.wh.wh_input_stock_loc_id.id, + "procure_method": "make_to_stock", + "route_id": rma_route.id, + "warehouse_id": cls.wh.id, + "company_id": cls.wh.company_id.id, + "active": False, + } + ) + + @classmethod + def _configure_2_steps_incoming_outgoing(cls): + cls.second_step_incoming_rule.write({"active": True}) + cls.second_step_outgoing_rule.write({"active": True}) + rma_customer_rule = cls.env.ref("rma.rule_rma_customer_out_pull") + rma_customer_rule.write( + { + "procure_method": "make_to_order", + "sequence": 0, + "location_src_id": cls.test_rma_loc.id, + } + ) @classmethod def _create_user(cls, login, groups, company): @@ -1096,37 +1141,7 @@ class TestRma(common.TransactionCase): 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_loc2 = rma_loc.copy({"name": "rma loc shipping"}) - rma_customer_rule = self.env.ref("rma.rule_rma_customer_out_pull") - rma_customer_rule.write({"procure_method": "make_to_order", "sequence": 0}) - self.env["stock.rule"].create( - { - "name": "reception => rma loc shipping", - "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_loc2.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, - } - ) + self._configure_2_steps_incoming_outgoing() # Generate expedition for the rma group self.rma_customer_id.rma_line_ids.action_rma_to_approve() wizard = self.rma_make_picking.with_context( @@ -1138,13 +1153,12 @@ class TestRma(common.TransactionCase): } ).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 + lambda m: m.location_dest_id == self.stock_rma_location ) first_line_in_dest_move = first_line_in_move.move_dest_ids reception_picking = first_line_in_move.picking_id @@ -1154,7 +1168,7 @@ class TestRma(common.TransactionCase): 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 + lambda m: m.location_dest_id == self.stock_rma_location ) self.assertEqual(second_line_in_move.state, "assigned") @@ -1184,3 +1198,53 @@ class TestRma(common.TransactionCase): 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") + + def test_11_rma_received_shipped_quantities_multiple_step(self): + # configure a new rule to make reception and expedition in 2 steps + self._configure_2_steps_incoming_outgoing() + rma_customer = self._create_rma_from_move( + [(self.product_1, 3)], + "customer", + self.env.ref("base.res_partner_2"), + dropship=False, + ) + rma_customer.rma_line_ids.action_rma_to_approve() + # Generate reception for the rma group and check incoming quantities + rma_line = rma_customer.rma_line_ids + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": rma_customer.rma_line_ids.ids, + "active_model": "rma.order.line", + "picking_type": "incoming", + "active_id": 1, + } + ).create({}) + wizard._create_picking() + in_pickings = rma_line._get_in_pickings() + first_in_picking = in_pickings.filtered(lambda p: p.state == "assigned") + self.assertEqual(rma_line.qty_incoming, 3.0) + self.assertEqual(rma_line.qty_received, 0.0) + for mv in first_in_picking.move_line_ids: + mv.qty_done = mv.reserved_uom_qty + first_in_picking._action_done() + self.assertEqual(rma_line.qty_incoming, 0.0) + self.assertEqual(rma_line.qty_received, 3.0) + + # generate 2 step expedition and check quantities + wizard = self.rma_make_picking.with_context( + **{ + "active_ids": rma_line.ids, + "active_model": "rma.order.line", + "picking_type": "outgoing", + "active_id": 1, + } + ).create({}) + wizard.with_context(test=True)._create_picking() + out_picking = rma_line._get_out_pickings() + self.assertEqual(rma_line.qty_outgoing, 3.0) + self.assertEqual(rma_line.qty_delivered, 0.0) + for mv in out_picking.move_ids: + mv.quantity_done = 3.0 + out_picking._action_done() + self.assertEqual(rma_line.qty_outgoing, 0.0) + self.assertEqual(rma_line.qty_delivered, 3.0)