Skip to content

Commit

Permalink
backend: Fix issue on stock out endpoints
Browse files Browse the repository at this point in the history
When we create a stock issue, create an inventory with the quantity
of units to keep. The quantity to keep is the quantity of products
which have been picked (qty_done > 0). To do so, we unreserve the move
lines in the location where qty_done == 0, so remain only the picked
ones, and when creating the inventory, we sum the move lines quantities.

As the state of a move line is a related to the move, we have to include
"partially_available" ones.

It is important to keep the domain on the state to exclude cancel and
done moves, and it should be more efficient to filter on
assigned/partially_available than to exclude all the others.

A scenario where it was observed is:

In a location, we have 2 packages:

* Pack1: 2 units
* Pack2: 100 units

We create a move for 100 units, it creates 2 move lines:

* 2 units from Pack1
* 98 units from Pack2

In the application, we scan Pack1, move only 1 unit to a destination
Bin. The next line is shown for the remaining unit of Pack1, we use the
"stock out" button.

At this point, what we expect:

* The inventory for Pack1 is created with 1 unit (to satisfy the first
  unit put in the destination Bin)

Before the correction:

* The inventory for Pack1 is created with 0 unit, because the move is
  "partially_available", so the move line for the picked unit is ignored.

I researched for other occurrences where we do not search for
"partially_available" on move lines and fixed them.
  • Loading branch information
guewen committed Sep 25, 2020
1 parent 2a8769b commit 43d3d38
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 3 deletions.
2 changes: 1 addition & 1 deletion shopfloor/actions/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ def _stock_issue_get_related_move_lines(self, move, location, package, lot):
("product_id", "=", move.product_id.id),
("package_id", "=", package.id),
("lot_id", "=", lot.id),
("state", "=", "assigned"),
("state", "in", ("assigned", "partially_available")),
]
return self.env["stock.move.line"].search(domain)

Expand Down
4 changes: 2 additions & 2 deletions shopfloor/services/cluster_picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ def _lines_to_pick(self, picking_batch):
return self._lines_for_picking_batch(
picking_batch,
filter_func=lambda l: (
l.state == "assigned"
l.state in ("assigned", "partially_available")
# On 'StockPicking.action_assign()', result_package_id is set to
# the same package as 'package_id'. Here, we need to exclude lines
# that were already put into a bin, i.e. the destination package
Expand Down Expand Up @@ -657,7 +657,7 @@ def _data_for_unload_single(self, batch, package):

def _filter_for_unload(self, line):
return (
line.state == "assigned"
line.state in ("assigned", "partially_available")
and line.qty_done > 0
and line.result_package_id
and not line.shopfloor_unloaded
Expand Down
52 changes: 52 additions & 0 deletions shopfloor/tests/test_cluster_picking_stock_issue.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,55 @@ def test_stock_issue_reserve_elsewhere(self):
),
self.shelf2,
)

def test_stock_issue_similar_move_with_picked_line(self):
"""Stock issue on the remaining of a line on partial move
We have a move with 10 units.
2 are reserved in a package. The remaining in another package.
We pick 1 of the first package and put it in a bin.
A new move line of 1 is created to pick in the first package: we
declare a stock out on it.
The first move line must be untouched, the second line for the remaining
should pick one more item in the other package.
"""
package1 = self.env["stock.quant.package"].create({"name": "PACKAGE_1"})
package2 = self.env["stock.quant.package"].create({"name": "PACKAGE_2"})
self._update_qty_in_location(self.shelf1, self.product_a, 2, package=package1)
self._update_qty_in_location(self.shelf1, self.product_a, 200, package=package2)
self.move1._action_assign()
self.move2._action_assign()
self.move3._action_assign()
self._simulate_batch_selected(self.batch, fill_stock=False)
self.assertEqual(set(self.batch.picking_ids.mapped("state")), {"assigned"})

pick_line1, pick_line2 = self.move1.move_line_ids
new_line, __ = pick_line1._split_qty_to_be_done(1)
self._set_dest_package_and_done(pick_line1, self.dest_package)

self.assertEqual(pick_line1.product_qty, 1.0)
self.assertEqual(new_line.product_qty, 1.0)
self.assertEqual(pick_line2.product_qty, 8.0)
# on the third move, the operator can't pick anymore in shelf1
# because there is nothing inside, they declare a stock issue
self._stock_issue(new_line, next_line_func=lambda: pick_line2)

self.assertRecordValues(
# check that the first move line of the move was not altered
pick_line1,
[
{
"location_id": self.shelf1.id,
"qty_done": 1.0,
"result_package_id": self.dest_package.id,
}
],
)
# the line on which we declared stock out does not exists
self.assertFalse(new_line.exists())
# the second line to pick has been raised to 9 instead of 8
# initially, to compensate the stock out
self.assertEqual(pick_line2.product_qty, 9.0)

# quant with stock out has been updated
self.assertEqual(package1.quant_ids.quantity, 1.0)

0 comments on commit 43d3d38

Please sign in to comment.