Skip to main content

Influence: Holds and Location State

Allocation never takes held stock, and nobody can confirm a hold away. Two things remove stock from the list: a hold that covers the stock row, and a location that is not in the state Ok. This page shows both routes, and what a hold does to a reservation that already exists.

1. Route A: a hold row covers the stock row​

What this shows. When a hold row removes the whole stock row from the available quantity. The check runs twice: when stock is read, and again under the row lock when it is reserved.

Setting (screen label)ColumnWhat it changesVisible outcome
Hold scope: lot, location or LPNinventory_hold.lot, inventory_hold.loc, inventory_hold.lpnWhich stock rows the hold covers. A hold of a lot covers that lot in every location. A hold has no quantity and no SKUThe whole row counts as held. There is no partial hold
Hold is oninventory_hold.is_hold_onOnly a hold that is on countsRelease (button, API, or the auto-release) brings the stock back
Hold code activeinventory_hold_code.activeA switched-off code blocks nothingStock of holds with that code is available again
Blocks takinginventory_hold_code.block_outbound_flowOnly a code that blocks taking removes stock from allocationDamaged blocks taking and does not block putting
Code missing from the catalog(no row)Blocks. This is the fail-safeA hold with an unknown code removes stock
Auto-release timeinventory_hold.auto_release_dateA loop releases holds whose time has passed. Without a value the time is 100 years aheadThe hold ends by itself

Reading notes.

  • The columns enforce and overridable of the hold code are not read here. A hold row with a code that does not enforce (None, Ok, NotHold) still removes the stock, because Blocks taking is on for these codes. Do not place holds with those codes.
  • Blocks putting (block_inbound_flow) is not read by route A. It is read by receiving and by moves. Route B reads it only to decide whether a code enforces at all.
  • The auto-release loop runs every 5 minutes.
  • Nothing allocates again when a hold ends. Somebody must press Allocate or Release, or a retry must fire.

Where it comes from​

RuleCode
Available quantity and held quantity in the view, LEFT JOIN on the code catalog, active, block_outbound_flowcrates/libs/wms-lib-sql/sql/wms-app/migrations/011_a_hold_says_what_it_forbids.sql:77-114
Seed: Damaged blocks taking and not puttingcrates/libs/wms-lib-sql/sql/wms-app/migrations/011_a_hold_says_what_it_forbids.sql:67-70
Reserve re-check uses the same predicatecrates/libs/wms-lib-core/src/model/inventory/inventory_hold.rs:223-232, crates/libs/wms-lib-core/src/model/inventory/inventory_hold.rs:399-418
Reserve step: held counts as available 0crates/libs/wms-outbound/src/allocation/reserve.rs:168-183
Candidate read uses the view column atpcrates/libs/wms-lib-core/src/model/inventory/inventory_balance_atp.rs:454-455
enforce and overridable are not part of that predicatecrates/libs/wms-lib-core/src/model/inventory/inventory_hold.rs:381-394
Seeded hold codescrates/libs/wms-lib-sql/sql/wms-app/migrations/001_baseline.sql:8227-8243
A hold row has exactly one of lot, location, LPN; default auto-release 36500 dayscrates/libs/wms-inventory/src/service/hold.rs:370-400
Auto-release loop, every 5 minutescrates/services/app-server/src/services/cleanup_tasks.rs:113, crates/services/app-server/src/services/cleanup_tasks.rs:458-485, crates/services/app-server/src/services/cleanup_tasks.rs:540-578
API: place and release holds (Admin, Manager)crates/services/app-server/src/web/rpcs/hold_rpc.rs:24-27
API: edit hold codescrates/services/app-server/src/web/rpcs/inventory_hold_code_rpc.rs:14

2. Route B: a location hold changes the location state​

What this shows. A hold on a location also changes the status of the location. Allocation reads only locations with status Ok and no flag.

Setting (screen label)ColumnWhat it changesVisible outcome
Hold code enforceinventory_hold_code.enforceA code that does not enforce does not change the location statusLocation stays Ok. Route A can still remove the stock
Hold code activeinventory_hold_code.activeA switched-off code is treated as not enforcingSame as above
Blocks putting or Blocks takinginventory_hold_code.block_inbound_flow, inventory_hold_code.block_outbound_flowA code enforces if it blocks at least one directionLocation becomes Hold or Damage. All its stock is out of allocation
Location statuslocation.status (Ok, Hold, Damage)Only Ok is offeredStock in a Hold or Damage location is not reserved
Location flaglocation.loc_flag (None, CycleCountActive, SanitationActive, MaintenanceActive, ReceivingHoldoff)Only None is offeredA short pick with BlockSourceLocation sets CycleCountActive and so closes the location for allocation

Reading notes.

  • Only a location hold changes the location status. A hold on a lot or an LPN uses route A only.
  • A hold on a location of type InTransit is refused: location {loc} holds only open pick pallets: it takes no location hold.
  • Release of the hold recomputes the status again.

Where it comes from​

RuleCode
Recompute after place or releasecrates/libs/wms-inventory/src/service/hold.rs:216-245, crates/libs/wms-inventory/src/service/hold.rs:439-482
Damage, Hold, Ok from the enforcing codescrates/libs/wms-inventory/src/service/hold.rs:495-516
A code enforces if it blocks either direction; active lowers enforcecrates/libs/wms-inventory/src/movement/hold_policy.rs:150-190, crates/libs/wms-inventory/src/movement/hold_policy.rs:209-221
Allocation filters status = 'Ok' and loc_flag = 'None'crates/libs/wms-lib-core/src/model/inventory/inventory_balance_atp.rs:457
BlockSourceLocation sets the flagcrates/libs/wms-lib-core/src/model/location.rs:1239-1252
Location hold on an InTransit location is refusedcrates/libs/wms-inventory/src/service/hold.rs:278-298
Location flag valuescrates/libs/wms-lib-core/src/model/location.rs:248-254

3. A hold after the reservation​

What this shows. A reservation is not removed when a hold arrives later. The hold stops the pick at three later gates.

Reading notes.

  • Allocation does not look at an existing reservation again. The stock stays reserved for the order, but the picker cannot take it until the hold is released, or until somebody unallocates the pick.
  • The dispatch gate also checks the location: status Ok and flag None. It tolerates the flag CycleCountActive only for a picker who finishes work that was already started at that location.

Where it comes from​

GateCode
Dispatch: location status and flag, then holdcrates/libs/wms-outbound/src/picking/infrastructure/dispatch.rs:156-176
Reason codes of the dispatch gatecrates/libs/wms-outbound/src/picking/infrastructure/dispatch.rs:44-62
Source confirmation refuses a held sourcecrates/libs/wms-outbound/src/picking/confirmation/at_commit.rs:139-145, crates/libs/wms-outbound/src/domain/pick_confirmation/refusal.rs:71-91
Reserved move refuses a held sourcecrates/libs/wms-inventory/src/picking/reserved_pick.rs:315-328