diff --git a/stock_vertical_lift/models/vertical_lift_operation_put.py b/stock_vertical_lift/models/vertical_lift_operation_put.py index a0a4261e11ba..5c0dade313b8 100644 --- a/stock_vertical_lift/models/vertical_lift_operation_put.py +++ b/stock_vertical_lift/models/vertical_lift_operation_put.py @@ -118,11 +118,41 @@ def _find_move_line(self, barcode): if product: return self._find_move_line_for_product(product) + def _check_move_lines_to_merge(self, lines): + check_fields = ["product_id", "lot_id", "product_uom_id"] + for field in check_fields: + values = lines.mapped(field) + if len(values) > 1: + return False + if len(values) == 1 and lines.filtered(lambda line: not line[field]): + return False + return True + def _find_move_line_for_package(self, package): domain = AND( [self._domain_move_lines_to_do_all(), [("package_id", "in", package.ids)]] ) - return self.env["stock.move.line"].search(domain, limit=1) + lines = self.env["stock.move.line"].search(domain) + if len(lines) > 1: + # Multiple move lines in the same package, they need to be merged if possible + # Or Odoo will raise an exception because the move is done one line at at time + picking = fields.first(lines.picking_id) + if picking._check_move_lines_map_quant_package(package): + # Fist merge all lines in the same move + move = lines.move_id._merge_moves() + if len(move) == 1 and len(move.move_line_ids) > 1: + # Now we have one move, let's merge the move lines together + lines = move.move_line_ids + line_keep = fields.first(lines) + if self._check_move_lines_to_merge(lines): + values = { + "product_uom_qty": sum(lines.mapped("product_uom_qty")), + } + line_keep.write(values) + other_lines = lines - line_keep + other_lines.unlink() + lines = line_keep + return fields.first(lines) def _find_move_line_for_lot(self, lot): domain = AND( diff --git a/stock_vertical_lift/tests/test_put.py b/stock_vertical_lift/tests/test_put.py index 4b383a6eae64..f62aa612d404 100644 --- a/stock_vertical_lift/tests/test_put.py +++ b/stock_vertical_lift/tests/test_put.py @@ -158,3 +158,50 @@ def test_transition_button_release(self): operation.button_release() self.assertEqual(operation.state, "scan_source") self.assertFalse(operation.current_move_line_id) + + def test_put_package_with_multiple_move_lines(self): + """Check moving a package linked to multiple move lines. + + Even when scanning a package, the module moves one move line at a time + And not the whole package. + If the package is spread on multiple move lines an exception is raised. + + The module will try to merge the move lines. + + """ + pick = self.picking_in + # split the move in 2 move lines + line1 = pick.move_line_ids + # Add two quants in a package + pack = self.env["stock.quant.package"].create({"name": "test"}) + # Update the available stock necessary for the move + self._update_qty_in_location(pick.location_id, line1.product_id, 14, pack) + # The stock for the 2nd move line must be on a different quant + self.env["stock.quant"].create( + { + "product_id": line1.product_id.id, + "location_id": pick.location_id.id, + "quantity": 1, + "package_id": pack.id, + } + ) + # Split the move line to have 2 + line2 = line1.copy({"product_uom_qty": 1, "picking_id": pick.id}) + line1.with_context(bypass_reservation_update=True).product_uom_qty = 14 + line1.package_id = pack + line2.package_id = pack + + # Do the full put workflow + operation = self._open_screen("put") + line = operation._find_move_line(pack.name) + operation.current_move_line_id = line + operation.current_move_line_id.location_dest_id = self.location_1a_x1y1 + operation.state = "save" + operation.button_save() + self.assertEqual(line1.state, "done") + # Check the lines quantity has been merged + self.assertEqual(line1.qty_done, 15) + # Check there is no more move lines to do for the pack + line_left = operation._find_move_line(pack.name) + self.assertFalse(line_left) + self.assertEqual(pick.state, "done")