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 015ed11d1..9993ce8f2 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 92e3fec00..fb642255a 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 000000000..55cf245b8 --- /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 bd3d0f167..2806fcb32 100644 --- a/rma/models/rma_operation.py +++ b/rma/models/rma_operation.py @@ -94,3 +94,22 @@ def _default_routes(self): 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 9a839f180..52cbf72fe 100644 --- a/rma/models/stock_move.py +++ b/rma/models/stock_move.py @@ -62,6 +62,7 @@ def _get_available_quantity( 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 @@ def _update_reserved_quantity( 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 c2bb1b59e..08a00f286 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 637caea9b..2982b75f0 100644 --- a/rma/wizards/rma_make_picking.py +++ b/rma/wizards/rma_make_picking.py @@ -210,15 +210,16 @@ def action_create_picking(self): 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 @@ def action_create_picking(self): "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 @@ def action_create_picking(self): "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 b3bec91e2..16d3514e1 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 @@ def setUpClass(cls): "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 @@ def setUpClass(cls): "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, } )