mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
Ask to scan a tray type when no storage type is configured
The use cases we want to cover are: 1. Putaway for a package/good without storage type 2. Putaway for a package with a storage type configured to be stored in a tray (associated with a tray type) 3. Putaway for a package with a storage type NOT configured on a tray type The case 1. is implement in "stock_vertical_lift", the 2. was already implement in this module, this commit implements the case 3. A typical flow is: * We configure a generic Kardex Box storage type, not associated with any tray type, that is set on the package at reception (the reception person doesn't know the tray type at this point). this Kardex Box storage type is set on the Vertical Lift view (above the shuttles). * On the putaway transfer, as per the configuration above, the putaway changes the destination location to the Vertical Lift view. * When we scan the package in the shuttle's screen, as we have a storage type which is not configured on any locations in the shuttle (reminder, if we had, it would select the tray automatically), the user is asked to scan a tray type of the correct size.
This commit is contained in:
committed by
Hai Lang
parent
48f3d60102
commit
e83ea033c2
@@ -57,10 +57,44 @@ class VerticalLiftOperationPut(models.Model):
|
||||
|
||||
return tuple(updated_transitions)
|
||||
|
||||
def _has_storage_type(self):
|
||||
def _has_storage_type_domain(self):
|
||||
move_line = self.current_move_line_id
|
||||
storage_type = move_line.package_id.package_storage_type_id
|
||||
return bool(storage_type)
|
||||
package_storage_type = move_line.package_id.package_storage_type_id
|
||||
# When a put-away is done based on the package's storage type and no
|
||||
# destination is found, we can have 2 reasons:
|
||||
#
|
||||
# 1. No location is available according to the storage types rules,
|
||||
# for instance because they are full
|
||||
# 2. The storage type of the package doesn't have any location
|
||||
# configured in the shuttle's locations
|
||||
#
|
||||
# We want to differentiate the 2 cases and handle them differently.
|
||||
# For 2. we consider the storage type is not meant to be in any
|
||||
# shuttle's tray but the user still tries: act the same way as if we
|
||||
# had no storage type at all, the user has to scan the tray type.
|
||||
# For 1. we try to find a destination location and if none is found,
|
||||
# a notification indicates that the shuttle is full.
|
||||
# In any case, the user should always be able to scan a different
|
||||
# tray type.
|
||||
return [
|
||||
("id", "!=", self.location_id.id),
|
||||
("id", "child_of", self.location_id.id),
|
||||
(
|
||||
"allowed_location_storage_type_ids",
|
||||
"in",
|
||||
package_storage_type.location_storage_type_ids.ids,
|
||||
),
|
||||
]
|
||||
|
||||
def _has_storage_type(self):
|
||||
domain = self._has_storage_type_domain()
|
||||
# we don't care about order and count, only if we have at least one
|
||||
# configured location for the storage type: sorting by id and limit by
|
||||
# 1 will give the best explain plan
|
||||
compatible_locations = self.env["stock.location"].search(
|
||||
domain, limit=1, order="id"
|
||||
)
|
||||
return bool(compatible_locations)
|
||||
|
||||
def _putaway_with_storage_type(self):
|
||||
move_line = self.current_move_line_id
|
||||
@@ -74,6 +108,8 @@ class VerticalLiftOperationPut(models.Model):
|
||||
move_line.package_level_id.location_dest_id = new_destination
|
||||
self.fetch_tray()
|
||||
return True
|
||||
# no destination found: all the trays for this tray type are full, or rejected
|
||||
# by the location storage type rules
|
||||
return False
|
||||
|
||||
def _put_away_with_storage_type_failed(self):
|
||||
|
||||
@@ -21,8 +21,24 @@ class TestPut(VerticalLiftCase):
|
||||
{"name": "Small 8x", "only_empty": True}
|
||||
)
|
||||
|
||||
# storage type used for Tray 1A
|
||||
PackageStorageType = cls.env["stock.package.storage.type"]
|
||||
# package storage type used only to putaway a package temporarily in
|
||||
# the vertical lift view location before being put in a shuttle, which
|
||||
# will not be configured in any shuttle's locations, we'll use when
|
||||
# the operator knows that a good has to go in a shuttle, but doesn't
|
||||
# know yet in which tray type: when the first putaway is done, the good
|
||||
# stays in the vertical lift view (above the shuttles), then, when the
|
||||
# user scans the package in a shuttle, they have to scan a tray type.
|
||||
cls.package_storage_type_buffer = PackageStorageType.create(
|
||||
{
|
||||
"name": "VLift Box",
|
||||
"location_storage_type_ids": [
|
||||
(4, cls.location_storage_type_buffer.id),
|
||||
],
|
||||
}
|
||||
)
|
||||
# storage type used for Tray 1A, user won't have to scan a tray type
|
||||
# when this storage type is already set on the package
|
||||
cls.package_storage_type_small_8x = PackageStorageType.create(
|
||||
{
|
||||
"name": "Small 8x",
|
||||
@@ -58,9 +74,7 @@ class TestPut(VerticalLiftCase):
|
||||
}
|
||||
)
|
||||
|
||||
cls.package = cls.env["stock.quant.package"].create(
|
||||
{"package_storage_type_id": cls.package_storage_type_small_8x.id}
|
||||
)
|
||||
cls.package = cls.env["stock.quant.package"].create({})
|
||||
cls._update_qty_in_location(
|
||||
cls.wh.wh_input_stock_loc_id, cls.product_socks, 10, package=cls.package
|
||||
)
|
||||
@@ -97,6 +111,7 @@ class TestPut(VerticalLiftCase):
|
||||
)
|
||||
|
||||
def test_storage_type_put_away(self):
|
||||
self.package.package_storage_type_id = self.package_storage_type_small_8x
|
||||
move_line = self.int_picking.move_line_ids
|
||||
self.assertEqual(move_line.location_dest_id, self.vertical_lift_loc)
|
||||
self.assertEqual(
|
||||
@@ -113,8 +128,38 @@ class TestPut(VerticalLiftCase):
|
||||
# the dest location was Vertical Lift, it has been change to Vertical
|
||||
# Lift/Shuttle 1, and the computation from there took the first cell
|
||||
# available, we should be the pos x1 and y1 in the tray A.
|
||||
self.assertTrue(move_line.location_dest_id, self.location_1a_x1y1)
|
||||
self.assertEqual(move_line.location_dest_id, self.location_1a_x1y1)
|
||||
self.assertEqual(
|
||||
move_line.package_level_id.location_dest_id, self.location_1a_x1y1
|
||||
)
|
||||
|
||||
# the state goes straight to "save", as we don't need to scan the tray type
|
||||
# when a putaway is available
|
||||
self.assertEqual(operation.state, "save")
|
||||
|
||||
def test_storage_type_not_configured(self):
|
||||
# if we do have a storage type, but the storage type is not used in the
|
||||
# shuttle (although it may be used on the lift view location, so we can have an
|
||||
# initial putaway rule that puts the package in the lift view location first),
|
||||
# we have to ask to scan a tray type
|
||||
self.package.package_storage_type_id = self.package_storage_type_buffer
|
||||
move_line = self.int_picking.move_line_ids
|
||||
self.assertEqual(move_line.location_dest_id, self.vertical_lift_loc)
|
||||
self.assertEqual(
|
||||
move_line.package_level_id.location_dest_id, self.vertical_lift_loc
|
||||
)
|
||||
|
||||
operation = self._open_screen("put")
|
||||
# we begin with an empty screen, user has to scan a package, product,
|
||||
# or lot
|
||||
self.assertEqual(operation.state, "scan_source")
|
||||
operation.on_barcode_scanned(self.package.name)
|
||||
|
||||
self.assertEqual(operation.current_move_line_id, move_line)
|
||||
# it stays here, as the put-away has no rule to put the "buffer box" in
|
||||
# any location
|
||||
self.assertEqual(move_line.location_dest_id, self.vertical_lift_loc)
|
||||
|
||||
# and the user has to scan a tray type (so we are back to the normal
|
||||
# flow, tested in stock_vertical_lift)
|
||||
self.assertEqual(operation.state, "scan_tray_type")
|
||||
|
||||
Reference in New Issue
Block a user