Skip to content

Commit 4fcae3b

Browse files
committed
stock_move_line_change_lot: fix unreserve lines from same picking
Makes no sense to unreserve lines that are in the same picking. In this case the lines should simply swap the lots.
1 parent 0445ae8 commit 4fcae3b

File tree

2 files changed

+54
-14
lines changed

2 files changed

+54
-14
lines changed

stock_move_line_change_lot/models/stock_move_line.py

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,13 @@ def _change_lot_free_other_lines(self, need, location, product, lot, package):
3939
],
4040
order="quantity desc",
4141
)
42-
# Favor lines from non-printed pickings.
43-
other_lines.sorted(
44-
lambda ml: (
45-
ml.picking_id == self.picking_id or not ml.picking_id.printed,
46-
-ml.quantity,
47-
)
42+
# collect and skip lines from the same picking
43+
other_lines_same_picking = other_lines.filtered(
44+
lambda x: x.picking_id == self.picking_id
4845
)
46+
other_lines -= other_lines_same_picking
47+
# Favor lines from non-printed pickings.
48+
other_lines.sorted(lambda ml: (not ml.picking_id.printed, -ml.quantity))
4949
# Stop when required quantity is reached
5050
for line in other_lines:
5151
freed_quantity += line.quantity_product_uom
@@ -58,7 +58,15 @@ def _change_lot_free_other_lines(self, need, location, product, lot, package):
5858
if not is_lesser(freed_quantity, need, rounding):
5959
# We reached the required quantity
6060
break
61-
61+
# Lines from the same picking should:
62+
# * count qty as available
63+
# * be swapped to original lot
64+
# * re-assigned
65+
freed_quantity += sum(other_lines_same_picking.mapped("quantity_product_uom"))
66+
to_reassign_moves |= other_lines_same_picking.move_id
67+
other_lines_same_picking.with_context(
68+
bypass_reservation_update=True
69+
).lot_id = self.lot_id
6270
return (freed_quantity, to_reassign_moves)
6371

6472
def write(self, vals):
@@ -159,15 +167,13 @@ def _do_change_lot(self, vals):
159167
available_quantity, move_line.quantity_product_uom, rounding
160168
):
161169
need = move_line.quantity_product_uom - available_quantity
162-
(
163-
freed_quantity,
164-
to_reassign_moves,
165-
) = move_line._change_lot_free_other_lines(
166-
need, location, product, lot, package
170+
(freed_quantity, to_reassign_moves) = (
171+
move_line._change_lot_free_other_lines(
172+
need, location, product, lot, package
173+
)
167174
)
168175
available_quantity += freed_quantity
169176
to_reassign_moves |= to_reassign_moves
170-
171177
if is_lesser(
172178
available_quantity, move_line.quantity_product_uom, rounding
173179
) and is_bigger(available_quantity, 0, rounding):

stock_move_line_change_lot/tests/test_change_lot.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,40 @@ def test_change_lot_reserved_qty(self):
256256
line2, lambda: line2.quantity_product_uom, lot=initial_lot
257257
)
258258

259+
def test_change_lot_reserved_qty_same_picking(self):
260+
"""Scan a lot already reserved by other lines in the same picking.
261+
262+
It should NOT unreserve the other line, use the lot for the current line,
263+
and swap the lot to the other move.
264+
"""
265+
initial_lot1 = self._create_lot(self.product_a)
266+
initial_lot2 = self._create_lot(self.product_a)
267+
self._update_qty_in_location(self.shelf1, self.product_a, 10, lot=initial_lot1)
268+
self._update_qty_in_location(self.shelf1, self.product_a, 10, lot=initial_lot2)
269+
picking = self._create_picking(lines=[(self.product_a, 20)])
270+
picking.action_assign()
271+
line1 = picking.move_line_ids[0]
272+
line2 = picking.move_line_ids[1]
273+
self.assertEqual(line1.lot_id, initial_lot1)
274+
self.assertEqual(line2.lot_id, initial_lot2)
275+
276+
# swap lot 2 on line 1
277+
self._change_lot(line1, initial_lot2)
278+
self.assertRecordValues(
279+
line1, [{"lot_id": initial_lot2.id, "quantity_product_uom": 10}]
280+
)
281+
# line 2 has been assigned to lot 1
282+
self.assertRecordValues(
283+
line2, [{"lot_id": initial_lot1.id, "quantity_product_uom": 10}]
284+
)
285+
# check that reservations have been updated
286+
self.assert_quant_reserved_qty(
287+
line1, lambda: line1.quantity_product_uom, lot=initial_lot2
288+
)
289+
self.assert_quant_reserved_qty(
290+
line2, lambda: line2.quantity_product_uom, lot=initial_lot1
291+
)
292+
259293
def test_change_lot_reserved_partial_qty(self):
260294
"""Scan a lot already reserved by other lines and can only be reserved
261295
partially
@@ -340,7 +374,7 @@ def test_change_lot_reserved_qty_done(self):
340374
)
341375

342376
def test_change_lot_different_location(self):
343-
"If the scanned lot is in a different location, we cannot process it"
377+
"""If the scanned lot is in a different location, we cannot process it"""
344378
initial_lot = self._create_lot(self.product_a)
345379
self._update_qty_in_location(self.shelf1, self.product_a, 10, lot=initial_lot)
346380
picking = self._create_picking(lines=[(self.product_a, 10)])

0 commit comments

Comments
 (0)