mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
stock_reserve_rule: add full empty bin removal strategy
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.
This commit is contained in:
@@ -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",
|
||||
@@ -142,7 +143,8 @@ 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"
|
||||
"Full Bin: take goods from a location if it reserves all its content",
|
||||
)
|
||||
|
||||
packaging_type_ids = fields.Many2many(
|
||||
@@ -296,3 +298,38 @@ class StockReserveRuleRemoval(models.Model):
|
||||
# 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
|
||||
|
||||
@@ -435,6 +435,45 @@ class TestReserveRule(common.SavepointCase):
|
||||
)
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user