From a9ac985b95a6d081503194766ba69cf67e2936a2 Mon Sep 17 00:00:00 2001 From: Jordi Ballester Alomar Date: Mon, 26 Feb 2024 16:01:54 +0100 Subject: [PATCH] [IMP] introduce fields in_force_same_lot and out_force_same_lot Those fields in the rma.operation allows us to control if we want to ensure that the same lot as the one indicated in the RMA should be used in deliveries to customers and receipts from suppliers --- rma/__manifest__.py | 2 +- rma/data/rma_operation.xml | 4 +++ rma/migrations/16.0.1.1.0/post-migration.py | 28 +++++++++++++++++++++ rma/models/rma_operation.py | 19 ++++++++++++++ rma/models/stock_move.py | 2 ++ rma/views/rma_operation_view.xml | 8 ++++++ rma/wizards/rma_make_picking.py | 16 ++++++------ rma_put_away/tests/test_rma_put_away.py | 4 +++ 8 files changed, 73 insertions(+), 10 deletions(-) create mode 100644 rma/migrations/16.0.1.1.0/post-migration.py diff --git a/rma/__manifest__.py b/rma/__manifest__.py index 015ed11d..9993ce8f 100644 --- a/rma/__manifest__.py +++ b/rma/__manifest__.py @@ -3,7 +3,7 @@ { "name": "RMA (Return Merchandise Authorization)", - "version": "16.0.1.0.0", + "version": "16.0.1.1.0", "license": "LGPL-3", "category": "RMA", "summary": "Introduces the return merchandise authorization (RMA) process in odoo", diff --git a/rma/data/rma_operation.xml b/rma/data/rma_operation.xml index 92e3fec0..fb642255 100644 --- a/rma/data/rma_operation.xml +++ b/rma/data/rma_operation.xml @@ -8,6 +8,8 @@ customer + True + False @@ -18,6 +20,8 @@ supplier + False + True diff --git a/rma/migrations/16.0.1.1.0/post-migration.py b/rma/migrations/16.0.1.1.0/post-migration.py new file mode 100644 index 00000000..55cf245b --- /dev/null +++ b/rma/migrations/16.0.1.1.0/post-migration.py @@ -0,0 +1,28 @@ +# Copyright 2024 ForgeFlow S.L. (https://www.forgeflow.com) +import logging + +_logger = logging.getLogger(__name__) + + +def _update_rma_operations(cr): + _logger.info( + "Updating rma operations to preset in_force_same_lot and out_force_same_lot" + ) + cr.execute( + """ + UPDATE rma_operation + SET in_force_same_lot=True + WHERE type='customer'; + """ + ) + cr.execute( + """ + UPDATE rma_operation + SET out_force_same_lot=True + WHERE type='supplier'; + """ + ) + + +def migrate(cr, version): + _update_rma_operations(cr) diff --git a/rma/models/rma_operation.py b/rma/models/rma_operation.py index bd3d0f16..2806fcb3 100644 --- a/rma/models/rma_operation.py +++ b/rma/models/rma_operation.py @@ -94,3 +94,22 @@ class RmaOperation(models.Model): required=True, default=lambda self: self.env.user.company_id, ) + in_force_same_lot = fields.Boolean( + string="Force same lot in incoming shipments", + help="Forces the same lot to be used " + "in incoming pickings as the one indicated in the RMA", + ) + out_force_same_lot = fields.Boolean( + string="Force same lot in outgoing shipments", + help="Forces the same lot to be used " + "in outgoing pickings as the one indicated in the RMA", + ) + + @api.onchange("type") + def _onchange_type(self): + if self.type == "customer": + self.in_force_same_lot = True + self.out_force_same_lot = False + elif self.type == "supplier": + self.in_force_same_lot = False + self.out_force_same_lot = True diff --git a/rma/models/stock_move.py b/rma/models/stock_move.py index 9a839f18..52cbf72f 100644 --- a/rma/models/stock_move.py +++ b/rma/models/stock_move.py @@ -62,6 +62,7 @@ class StockMove(models.Model): not lot_id and self.rma_line_id.lot_id and self.location_id.usage == "internal" + and self.rma_line_id.operation_id.out_force_same_lot ): # In supplier RMA deliveries we can only send the RMA lot/serial. lot_id = self.rma_line_id.lot_id @@ -88,6 +89,7 @@ class StockMove(models.Model): not lot_id and self.rma_line_id.lot_id and self.location_id.usage == "internal" + and self.rma_line_id.operation_id.out_force_same_lot ): # In supplier RMA deliveries we can only send the RMA lot/serial. lot_id = self.rma_line_id.lot_id diff --git a/rma/views/rma_operation_view.xml b/rma/views/rma_operation_view.xml index c2bb1b59..08a00f28 100644 --- a/rma/views/rma_operation_view.xml +++ b/rma/views/rma_operation_view.xml @@ -53,6 +53,10 @@ name="customer_to_supplier" attrs="{'invisible':[('type', '=', 'supplier')]}" /> + @@ -61,6 +65,10 @@ name="supplier_to_customer" attrs="{'invisible':[('type', '=', 'customer')]}" /> + diff --git a/rma/wizards/rma_make_picking.py b/rma/wizards/rma_make_picking.py index 637caea9..2982b75f 100644 --- a/rma/wizards/rma_make_picking.py +++ b/rma/wizards/rma_make_picking.py @@ -210,15 +210,16 @@ class RmaMakePicking(models.TransientModel): else: pickings = self.mapped("item_ids.line_id")._get_in_pickings() action = self.item_ids.line_id.action_view_in_shipments() - # Force the reservation of the RMA specific lot for incoming shipments. - # FIXME: still needs fixing, not reserving appropriate serials. + for move in pickings.move_ids.filtered( lambda x: x.state not in ("draft", "cancel", "done", "waiting") and x.rma_line_id and x.product_id.tracking in ("lot", "serial") and x.rma_line_id.lot_id + and x.rma_line_id.operation_id.in_force_same_lot + and x.location_dest_id.usage == "internal" ): - # Force the reservation of the RMA specific lot for incoming shipments. + # Force the reservation of the RMA specific lot for incoming shipments if required. move.move_line_ids.unlink() if move.product_id.tracking == "serial": move.write( @@ -226,14 +227,10 @@ class RmaMakePicking(models.TransientModel): "lot_ids": [(6, 0, move.rma_line_id.lot_id.ids)], } ) - quants = self.env["stock.quant"]._gather( - move.product_id, move.location_id, lot_id=move.rma_line_id.lot_id - ) move.move_line_ids.write( { - "reserved_uom_qty": 1 if picking_type == "incoming" else 0, + "reserved_uom_qty": 1, "qty_done": 0, - "package_id": len(quants) == 1 and quants.package_id.id, } ) elif move.product_id.tracking == "lot": @@ -251,10 +248,11 @@ class RmaMakePicking(models.TransientModel): "lot_id": move.rma_line_id.lot_id.id, "product_uom_id": move.product_id.uom_id.id, "qty_done": 0, - "reserved_uom_qty": qty if picking_type == "incoming" else 0, + "reserved_uom_qty": qty, } ) move_line_model.create(move_line_data) + pickings.with_context(force_no_bypass_reservation=True).action_assign() return action diff --git a/rma_put_away/tests/test_rma_put_away.py b/rma_put_away/tests/test_rma_put_away.py index b3bec91e..16d3514e 100644 --- a/rma_put_away/tests/test_rma_put_away.py +++ b/rma_put_away/tests/test_rma_put_away.py @@ -84,6 +84,8 @@ class TestRmaPutAway(common.SingleTransactionCase): "put_away_location_id": cls.put_away_loc.id, "in_route_id": cls.rma_route_cust.id, "out_route_id": cls.rma_route_cust.id, + "out_force_same_lot": True, + "in_force_same_lot": True, } ) cls.operation_2 = cls.rma_op_obj.create( @@ -97,6 +99,8 @@ class TestRmaPutAway(common.SingleTransactionCase): "put_away_location_id": cls.put_away_loc.id, "in_route_id": cls.rma_route_cust.id, "out_route_id": cls.rma_route_cust.id, + "out_force_same_lot": True, + "in_force_same_lot": True, } )