Skip to content

Commit

Permalink
stock_reserve_rule: add full empty bin removal strategy
Browse files Browse the repository at this point in the history
The full empty bin rule is like the empty bin rule, but it should take
everything. That means there can not be any pre existing reservations.
  • Loading branch information
TDu committed Sep 6, 2023
1 parent c675bb2 commit 0c30a35
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 1 deletion.
40 changes: 39 additions & 1 deletion stock_reserve_rule/models/stock_reserve_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ class StockReserveRuleRemoval(models.Model):
("default", "Default Removal Strategy"),
("empty_bin", "Empty Bins"),
("packaging", "Full Packaging"),
("full_bin", "Full Bin"),
],
required=True,
default="default",
Expand All @@ -142,7 +143,9 @@ class StockReserveRuleRemoval(models.Model):
"Empty Bins: take goods from a location only if the bin is"
" empty afterwards.\n"
"Full Packaging: take goods from a location only if the location "
"quantity matches a packaging quantity (do not open boxes).",
"quantity matches a packaging quantity (do not open boxes).\n"
"Fully Empty Bin: like empty bin but only if there is no reservation"
" on the bin.",
)

packaging_type_ids = fields.Many2many(
Expand Down Expand Up @@ -296,3 +299,38 @@ def is_greater_eq(value, other):
# compute how much packaging we can get
take = (need // pack_quantity) * pack_quantity
need = yield location, location_quantity, take, None, None

def _apply_strategy_full_bin(self, quants):
need = yield
# Only location with nothing reserved can be fully emptied
quants = quants.filtered(lambda q: q.reserved_quantity == 0)
# Group by location (in this removal strategies, we want to consider
# the total quantity held in a location).
quants_per_bin = quants._group_by_location()
# We take goods only if we empty the bin.
# The original ordering (fefo, fifo, ...) must be kept.
product = fields.first(quants).product_id
rounding = product.uom_id.rounding
locations_with_other_quants = [
group["location_id"][0]
for group in quants.read_group(
[
("location_id", "in", quants.location_id.ids),
("product_id", "not in", quants.product_id.ids),
("quantity", ">", 0),
],
["location_id"],
"location_id",
)
]
for location, location_quants in quants_per_bin:
if location.id in locations_with_other_quants:
continue

location_quantity = sum(location_quants.mapped("quantity"))

if location_quantity <= 0:
continue

if float_compare(need, location_quantity, rounding) != -1:
need = yield location, location_quantity, need, None, None
39 changes: 39 additions & 0 deletions stock_reserve_rule/tests/test_reserve_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,45 @@ def test_quant_domain_lot_and_owner(self):
)
self.assertEqual(move.state, "assigned")

def test_rule_full_bin(self):
self._create_rule(
{},
[
{
"location_id": self.loc_zone1.id,
"sequence": 1,
"removal_strategy": "full_bin",
},
{"location_id": self.loc_zone2.id, "sequence": 2},
],
)
# 100 on location and reserving it with picking 1
self._update_qty_in_location(self.loc_zone1_bin1, self.product1, 100)
picking1 = self._create_picking(self.wh, [(self.product1, 100)])
picking1.action_assign()
self.assertEqual(picking1.state, "assigned")
# Add 300 on location
# There is 400 but 100 is reserved
self._update_qty_in_location(self.loc_zone1_bin1, self.product1, 300)
# A move for 300 will no be allowed (not fully empty)
picking2 = self._create_picking(self.wh, [(self.product1, 300)])
picking2.action_assign()
self.assertEqual(picking2.state, "confirmed")
# But when picking 1 is done, no more reserved quantity
picking1.move_line_ids.qty_done = picking1.move_line_ids.product_uom_qty
picking1._action_done()
# Bin is fully emptied
picking2.action_assign()
move = picking2.move_lines
ml = move.move_line_ids
self.assertRecordValues(
ml,
[
{"location_id": self.loc_zone1_bin1.id, "product_qty": 300.0},
],
)
self.assertEqual(move.state, "assigned")

def test_rule_empty_bin(self):
self._update_qty_in_location(self.loc_zone1_bin1, self.product1, 300)
self._update_qty_in_location(self.loc_zone1_bin2, self.product1, 150)
Expand Down

0 comments on commit 0c30a35

Please sign in to comment.