Skip to main content

Lifecycle

A transfer has one status at a time. Every transition is guarded β€” a call that does not match the current status is refused rather than silently ignored.

Statuses​

StatusWire valueMeaning
CreatedCREATEDa draft. Only the store that raised it can see it; lines can still be added, changed and removed
RequestedREQUESTEDsent to the other store. The stock is now reserved at the sending store and on order at the receiving one
In progressIN-PROGRESSthe sending store has started picking
CompletedCOMPLETEDpicked and sent. Stock has moved and a Goods Received delivery exists
DeletedDELETEDabandoned before it was sent. The row is kept, not removed

πŸ›‘ IN-PROGRESS is spelled with a hyphen on the wire, unlike every other value. If you are matching statuses as strings, match IN-PROGRESS β€” an IN_PROGRESS comparison will silently never be true.

Transitions​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ CREATED β”‚ draft β€” created by either store
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
:send-requestβ”‚ └──────────────► DELETED
β–Ό (only from CREATED)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ REQUESTED β”‚ reserved at the sending store
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜
picking started β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β–Ό β”‚ β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”‚ β”‚
β”‚ IN-PROGRESS β”‚β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜β”‚ β”‚
β”‚ β”‚ β”‚
β–Ό β–Ό β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ COMPLETED β”‚β—„β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
from REQUESTED or IN-PROGRESS
TransitionTriggerGuard
CREATED β†’ REQUESTED:send-requestmust be CREATED, have at least one line, and be called by the receiving store
CREATED β†’ DELETEDDELETE the transfermust be CREATED, and be called by the receiving store
REQUESTED β†’ IN-PROGRESSthe sending store starts pickingmust be REQUESTED
REQUESTED or IN-PROGRESS β†’ COMPLETED:submit, or picking finishingmust be REQUESTED or IN-PROGRESS, and the caller must be the sending store

What each store may do​

Both stores can reach the transfer, but they cannot do the same things to it. The business unit in the URL is what decides, and a call from the wrong one is refused β€” usually as a 404, because the guard is written into the lookup rather than applied afterwards.

Receiving store (toBusinessUnitId)Sending store (fromBusinessUnitId)
Create the transferβœ…βœ…
Change the transfer's commentβœ…βœ…
Add or change a lineβœ… β€” sets quantityRequestedβœ… β€” sets quantityApproved ⁽ⁱ⁾
Add or change batch / serial detailβœ… β½β±βΎβœ… ⁽ⁱ⁾
Remove a lineβœ…βŒ
Send the requestβœ…βŒ
Delete the draftβœ…βŒ
Pick the goods❌ β€” it does not hold themβœ… in Click and Collect
Complete the transfer❌ refusedβœ… ⁽ⁱ⁾, or automatically when the pick finishes

⁽ⁱ⁾ Integration-only. Supported over REST, but nothing in the supplied flow calls it β€” a store's staff never do these things. See the API.

Two asymmetries are worth remembering, and they point in opposite directions:

πŸ›‘ Sending the request belongs to the receiving store alone. Either store may create a transfer, but only the store named in toBusinessUnitId can call :send-request. A store that raises a transfer to push stock away from itself therefore cannot send it β€” the receiving store has to. If you are building a push flow, create the transfer with the receiving store as the URL business unit.

Completion belongs to the sending store alone. A :submit whose URL business unit is not the transfer's fromBusinessUnitId is rejected, because the store that does not hold the goods cannot assert they were sent.

⚠ The same line endpoint writes a different field depending on who calls it. PUT …/lines takes a single quantity; called by the receiving store it becomes quantityRequested, called by the sending store it becomes quantityApproved, and calling as the wrong one silently writes the wrong field. See the API.

Once completed, it is final​

There is no transition out of COMPLETED. A transfer that shipped the wrong goods is not reopened β€” the correction happens on the receiving side, in Goods Received, where the delivery can be received short or over. See Stock and Goods Received.

Likewise DELETED is only reachable from CREATED. Once the other store has been told to expect goods, the transfer cannot be made to disappear.