mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
@@ -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