From e8df6310b168a8ec2f16ceb4f1fed724617cf325 Mon Sep 17 00:00:00 2001 From: sbejaoui Date: Thu, 13 Jun 2024 14:45:13 +0200 Subject: [PATCH] [IMP] shopfloor, zone picking: Allow partial transfer when scanning a location. In the zone picking scenario, operators can choose to pick less than the reserved quantity. Previously, the system required them, in this case, to place the goods in a package first. This restriction was unnecessary, as it forced operators to perform an extra step that they do not actually do in real life. We trust them to know what they're doing, so let's keep it simple. With this fix, if a user scans a location, they can move the products directly to the scanned location. --- shopfloor/services/zone_picking.py | 71 +++++++++---------- .../test_zone_picking_set_line_destination.py | 43 +++++++---- 2 files changed, 63 insertions(+), 51 deletions(-) diff --git a/shopfloor/services/zone_picking.py b/shopfloor/services/zone_picking.py index 17b184b9c7..59a7d35164 100644 --- a/shopfloor/services/zone_picking.py +++ b/shopfloor/services/zone_picking.py @@ -1169,43 +1169,40 @@ def set_destination( ) extra_message = "" - if moving_full_quantity: - # When the barcode is a location, - # only allow it if moving the full qty. - location = search.location_from_scan(barcode) - if location: - package = None - if handle_complete_mix_pack: - package = move_line.package_id - if self._pick_pack_same_time(): - ( - good_for_packing, - message, - ) = self._handle_pick_pack_same_time_for_location(move_line) - # TODO: we should append the msg instead. - # To achieve this, we should refactor `response.message` to a list - # or, to no break backward compat, we could add `extra_messages` - # to allow backend to send a main message and N additional messages. - extra_message = message - if not good_for_packing: - return self._response_for_set_line_destination( - move_line, message=message, qty_done=quantity - ) - pkg_moved, response = self._set_destination_location( - move_line, - package, - quantity, - confirmation, - location, - barcode, - ) - if response: - if extra_message: - if response.get("message"): - response["message"]["body"] += "\n" + extra_message["body"] - else: - response["message"] = extra_message - return response + location = search.location_from_scan(barcode) + if location: + package = None + if handle_complete_mix_pack: + package = move_line.package_id + if self._pick_pack_same_time(): + ( + good_for_packing, + message, + ) = self._handle_pick_pack_same_time_for_location(move_line) + # TODO: we should append the msg instead. + # To achieve this, we should refactor `response.message` to a list + # or, to no break backward compat, we could add `extra_messages` + # to allow backend to send a main message and N additional messages. + extra_message = message + if not good_for_packing: + return self._response_for_set_line_destination( + move_line, message=message, qty_done=quantity + ) + pkg_moved, response = self._set_destination_location( + move_line, + package, + quantity, + confirmation, + location, + barcode, + ) + if response: + if extra_message: + if response.get("message"): + response["message"]["body"] += "\n" + extra_message["body"] + else: + response["message"] = extra_message + return response # When the barcode is a package package = search.package_from_scan(barcode) diff --git a/shopfloor/tests/test_zone_picking_set_line_destination.py b/shopfloor/tests/test_zone_picking_set_line_destination.py index 3b6dfd9ab5..b3ce74c785 100644 --- a/shopfloor/tests/test_zone_picking_set_line_destination.py +++ b/shopfloor/tests/test_zone_picking_set_line_destination.py @@ -187,15 +187,15 @@ def test_set_destination_location_no_other_move_line_partial_qty(self): move qty 10 (assigned): -> move_line qty 10 from location X - Then the operator move 6 qty on 10, we get: - - an error because we can move only full qty by location - and only a package barcode is allowed on scan. + Then the operator move 6 qty on 10: + -> move_line qty 6 from location X (done) + -> move_line qty 4 from location X (assigned) """ zone_location = self.zone_location picking_type = self.picking3.picking_type_id barcode = self.packing_location.barcode moves_before = self.picking3.move_ids + self.assertEqual(moves_before.product_uom_qty, 10) self.assertEqual(len(moves_before), 1) self.assertEqual(len(moves_before.move_line_ids), 1) move_line = moves_before.move_line_ids @@ -210,14 +210,21 @@ def test_set_destination_location_no_other_move_line_partial_qty(self): "confirmation": None, }, ) - self.assert_response_set_line_destination( + move_lines = self.service._find_location_move_lines() + move_lines = move_lines.sorted(lambda l: l.move_id.priority, reverse=True) + self.assert_response_select_line( response, zone_location, picking_type, - move_line, - qty_done=6, - message=self.service.msg_store.package_not_found_for_barcode(barcode), + move_lines, + message=self.service.msg_store.confirm_pack_moved(), ) + done_move = move_line.move_id + assigned_move = moves_before + self.assertEqual(done_move.state, "done") + self.assertEqual(done_move.product_uom_qty, 6) + self.assertEqual(assigned_move.state, "assigned") + self.assertEqual(assigned_move.product_uom_qty, 4) def test_set_destination_location_several_move_line_full_qty(self): """Scanned barcode is the destination location. @@ -297,8 +304,8 @@ def test_set_destination_location_several_move_line_partial_qty(self): Then the operator move 4 qty on 6 (from the first move line), we get: - an error because we can move only full qty by location - and only a package barcode is allowed on scan. + -> move_line qty 6 from location X (assigned) + -> move_line qty 4 from location Y (done) """ zone_location = self.zone_location picking_type = self.picking4.picking_type_id @@ -318,14 +325,22 @@ def test_set_destination_location_several_move_line_partial_qty(self): "confirmation": None, }, ) - self.assert_response_set_line_destination( + # Check response + move_lines = self.service._find_location_move_lines() + move_lines = move_lines.sorted(lambda l: l.move_id.priority, reverse=True) + self.assert_response_select_line( response, zone_location, picking_type, - move_line, - qty_done=4, - message=self.service.msg_store.package_not_found_for_barcode(barcode), + move_lines, + message=self.service.msg_store.confirm_pack_moved(), ) + done_move = move_line.move_id + assigned_move = moves_before + self.assertEqual(done_move.state, "done") + self.assertEqual(done_move.product_uom_qty, 4) + self.assertEqual(assigned_move.state, "assigned") + self.assertEqual(assigned_move.product_uom_qty, 6) def test_set_destination_location_zero_check(self): """Scanned barcode is the destination location.