Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions stock_move_line_change_lot/models/stock_move_line.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ def _change_lot_free_other_lines(self, need, location, product, lot, package):
],
order="quantity desc",
)
# Favor lines from non-printed pickings.
other_lines.sorted(
lambda ml: (
ml.picking_id == self.picking_id or not ml.picking_id.printed,
-ml.quantity,
)
# collect and skip lines from the same picking
other_lines_same_picking = other_lines.filtered(
lambda x: x.picking_id == self.picking_id
)
other_lines -= other_lines_same_picking
# Favor lines from non-printed pickings.
other_lines.sorted(lambda ml: (not ml.picking_id.printed, -ml.quantity))
# Stop when required quantity is reached
for line in other_lines:
freed_quantity += line.quantity_product_uom
Expand All @@ -58,7 +58,15 @@ def _change_lot_free_other_lines(self, need, location, product, lot, package):
if not is_lesser(freed_quantity, need, rounding):
# We reached the required quantity
break

# Lines from the same picking should:
# * count qty as available
# * be swapped to original lot
# * re-assigned
freed_quantity += sum(other_lines_same_picking.mapped("quantity_product_uom"))
to_reassign_moves |= other_lines_same_picking.move_id
other_lines_same_picking.with_context(
bypass_reservation_update=True
).lot_id = self.lot_id
return (freed_quantity, to_reassign_moves)

def write(self, vals):
Expand Down Expand Up @@ -159,15 +167,13 @@ def _do_change_lot(self, vals):
available_quantity, move_line.quantity_product_uom, rounding
):
need = move_line.quantity_product_uom - available_quantity
(
freed_quantity,
to_reassign_moves,
) = move_line._change_lot_free_other_lines(
need, location, product, lot, package
(freed_quantity, to_reassign_moves) = (
move_line._change_lot_free_other_lines(
need, location, product, lot, package
)
)
available_quantity += freed_quantity
to_reassign_moves |= to_reassign_moves

if is_lesser(
available_quantity, move_line.quantity_product_uom, rounding
) and is_bigger(available_quantity, 0, rounding):
Expand Down
36 changes: 35 additions & 1 deletion stock_move_line_change_lot/tests/test_change_lot.py
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,40 @@ def test_change_lot_reserved_qty(self):
line2, lambda: line2.quantity_product_uom, lot=initial_lot
)

def test_change_lot_reserved_qty_same_picking(self):
"""Scan a lot already reserved by other lines in the same picking.
It should NOT unreserve the other line, use the lot for the current line,
and swap the lot to the other move.
"""
initial_lot1 = self._create_lot(self.product_a)
initial_lot2 = self._create_lot(self.product_a)
self._update_qty_in_location(self.shelf1, self.product_a, 10, lot=initial_lot1)
self._update_qty_in_location(self.shelf1, self.product_a, 10, lot=initial_lot2)
picking = self._create_picking(lines=[(self.product_a, 20)])
picking.action_assign()
line1 = picking.move_line_ids[0]
line2 = picking.move_line_ids[1]
self.assertEqual(line1.lot_id, initial_lot1)
self.assertEqual(line2.lot_id, initial_lot2)

# swap lot 2 on line 1
self._change_lot(line1, initial_lot2)
self.assertRecordValues(
line1, [{"lot_id": initial_lot2.id, "quantity_product_uom": 10}]
)
# line 2 has been assigned to lot 1
self.assertRecordValues(
line2, [{"lot_id": initial_lot1.id, "quantity_product_uom": 10}]
)
# check that reservations have been updated
self.assert_quant_reserved_qty(
line1, lambda: line1.quantity_product_uom, lot=initial_lot2
)
self.assert_quant_reserved_qty(
line2, lambda: line2.quantity_product_uom, lot=initial_lot1
)

def test_change_lot_reserved_partial_qty(self):
"""Scan a lot already reserved by other lines and can only be reserved
partially
Expand Down Expand Up @@ -340,7 +374,7 @@ def test_change_lot_reserved_qty_done(self):
)

def test_change_lot_different_location(self):
"If the scanned lot is in a different location, we cannot process it"
"""If the scanned lot is in a different location, we cannot process it"""
initial_lot = self._create_lot(self.product_a)
self._update_qty_in_location(self.shelf1, self.product_a, 10, lot=initial_lot)
picking = self._create_picking(lines=[(self.product_a, 10)])
Expand Down