Stock Moves Built

A stock move is a single planned movement of a product's quantity from one stock location to another. This screen is where you review every move in the system and step in when one needs to be held or stopped — it is not where moves are created.

What a stock move is

Every physical or logical movement of stock — an order line being released for despatch, a stock transfer between warehouses, a closing-stock adjustment, a returned package coming back in — is recorded as one StockMove row: a product, a quantity, a source location, a destination location, and a state. The state tracks the move through its life, and the console's job is to let you see that history and intervene when something needs to be suspended or cancelled.

Almost every move is created for you

There is no Create button here. Delivery moves are generated automatically once an approved order's product is released for despatch (a background job creates one move per order line, already Confirmed, and advances the order to In Despatch); other moves are created behind the scenes by stock transfers, closing-stock reconciliation, goods receipts and returns processing. The one move you can raise by hand is a manual adjustment, from the New adjustment button above the list — see New adjustment below. Everything else on this page is about what your team does after a move exists — reviewing it, and, when necessary, suspending or cancelling it.

Where to find it & who can see it

Open Inventory › Stock move in the left navigation. The list is visible to anyone holding stock_move.view (or a super administrator). There is no create, edit or delete page for this resource — every column and every action described below appears on the list itself, including the New adjustment button in the page header, which needs stock_move.create.

The state machine

StockMoveState has nine cases, but a single move only ever follows one of two short paths through them, plus the exception actions this screen exposes.

In practice a move follows one of two short routes:

Picked and Packed exist, but nothing sets them

StockMoveState has nine cases, but Picked and Packed are not reached by any move today — no service, job or console action assigns them. They are shown here for completeness and because the enum's badge colours are defined for them, but you will never see a move sitting in either state.

A move can ship in parts — and the state badge will not tell you

A move can be split across several packages that leave on different days (see Packages). When that happens, each despatch decrements only the stock its own parcel carries, and the move is marked Shipped only once all of it has gone. Until then it keeps the state it already had — usually Reserved — while a separate shipped_quantity figure records how much has actually left, and the remainder stays reserved.

So a move showing Reserved may already have had part of its stock physically despatched. There is deliberately no "partly shipped" state: whether AIR wants one is still an open decision, and inventing it here would have pre-empted that call.

Columns

ColumnShows
referenceThe move's identifying number, shown as a badge. Searchable and sortable.
operation_typeBadge showing what kind of move this is — Receipt, Delivery, ReturnIn, ReturnOut, Adjustment or Internal.
Productproduct.code — the product code being moved. Searchable.
Qtyproduct_qty — the quantity on the move.
From → ToA computed column reading sourceLocation.location_name and destLocation.location_name as "From → To" (an em-dash on either side stands in for a missing location).
StateA coloured badge — see the diagram above for the colour key.
Carriercarrier.name, toggleable — the delivery carrier assigned to the move, where relevant.
Hold reasonsuspendReason.name, toggleable, blank when the move has never been suspended.
scheduled_dateThe date the move is due to happen. Sortable, toggleable.
created_atDate and time the move was created. Sortable, hidden by default.

Filters

Select Filters to open three drop-downs: Product (search by product code), State (all nine StockMoveState values) and Operation type (all six OperationType values). Combine them with the search box, which matches the move's reference or product code. The Stock moves link on a product's Inventory tab opens this list with the Product filter already set.

Screenshot placeholderThe Stock Moves list: Reference, Operation type, Product, Qty, From → To, State, Carrier and Hold reason columns, with the State and Operation type filter panel open, and Suspend/Cancel row actions visible on a Confirmed move.

Actions

Permissions

New adjustment needs stock_move.create. Suspend and Unsuspend both need stock_move.suspend. Cancel needs the separate stock_move.edit permission — a colleague can hold up despatch by suspending moves without also being able to cancel them outright, and vice versa. All three additionally require stock_move.view to see the list at all.

  1. New adjustment Form

    The one button in the page header rather than on a row. Use it to correct a location's stock against a physical count outside the closing-stock cycle — books found in the back room, or written off as damaged. It posts a single Adjustment move that is confirmed and completed in one step, so Stock on hand changes the moment you submit; the move appears in the list already Done and cannot be undone (post a second, opposite adjustment to correct a mistake).

    FieldTypeRequiredNotes
    LocationSelectYesOnly real, in-use storage locations are listed, shown as Warehouse — Location. The virtual endpoints (Suppliers, Customers, In-Transit, Inventory Loss) never appear; the adjustment picks the right one for you.
    ProductSelectYesSearchable by code or name.
    DirectionRadioYesAdd stock brings the quantity in from the warehouse's supplier/production endpoint; Reduce stock writes it off to Inventory Loss. Same convention closing-stock reconciliation uses for a counted discrepancy.
    QuantityNumberYesAlways a positive number — direction decides the sign.
    ReasonTextareaYesMax 500 characters. Stored on the move as its notes; this is the only record of why the position changed, so write it for whoever audits the count later.

    A reduction that would take the location below zero is refused outright — you get an Cannot post adjustment message and nothing changes. If neither the warehouse nor the global endpoint list has a supplier/loss location configured, the adjustment is refused the same way.

  2. Suspend Form

    Available on any move that is not already Done, Cancelled or Suspended — that covers Draft, Confirmed, Reserved and even Shipped. Selecting it opens a form rather than a plain confirmation dialog:

    FieldTypeRequiredNotes
    ReasonSelectYesDrawn from active StockMoveSuspendReason records that are flagged for manual selection — the list is curated by an administrator, not free text.
    RemarkTextareaNoMax 500 characters — add context for whoever unsuspends it later.

    Submitting the form is the confirmation — there is no separate "are you sure?" step. If the move was Reserved, its reservation is released immediately (the reserved quantity on Stock on hand drops back to available) before the state changes to Suspended.

  3. Unsuspend Confirmation required

    Available only on a Suspended move. It returns the move to whichever state it held immediately before it was suspended (recorded on its move log) — typically Confirmed or Reserved. If that prior state was Reserved, unsuspending re-attempts the reservation there and then; if there is no longer enough available stock to reserve, the move settles at Confirmed instead rather than failing outright.

  4. Cancel Confirmation required

    Available on any move that is not already Done or Cancelled — notably, unlike Suspend, this includes a move that is currently Suspended; you do not need to unsuspend something before cancelling it. A confirmation dialog is all it asks for — no reason field. If the move was Reserved at the time, its reservation is released as part of cancelling.

Why the buttons you see change from row to row

Each action is only offered when the move is in a state its underlying service will actually accept — the same safety rule as everywhere else in the console (see Getting started). A Done or Cancelled move never shows any action at all; it has reached the end of its life.

Why a move is held

The Hold reason column tells you why a move stopped. A hold comes from one of two places: a colleague pressed Suspend by hand, or the nightly auto-reservation job checked the move against AIR's credit-control rules and refused to reserve stock for it. The automatic checks run strictest first and only the first failure is recorded — so the reason shown is the one thing you have to fix, not necessarily the only thing wrong.

Hold reasonWhat it meansWhat to do
Delivery pincode not serviceable by the assigned carrier
carrier_unserviceable
The carrier on this move is recorded as not delivering to the pincode on the order's delivery address, so sending it would only produce a return.Either assign a carrier that serves that pincode, or correct the serviceability record if the carrier does in fact deliver there. If the customer's address is wrong, fix the address on the order. Note: when no serviceability record exists at all for that pincode and carrier, the move is not held — a missing record is never read as "unserviceable", so this reason only ever appears where someone has explicitly marked the pincode as not served.
A pending return for this customer holds further parts
return_pending
A return from this customer is still open, and whoever inspected it ticked suspend further parts. Nothing more should go out until that return is settled.Finish the return: inspect, reconcile or cancel it. If the return was flagged in error, change the "further parts" decision on the return item.
Too many unremitted COD packages already out
cod_in_transit
The customer already has more cash-on-delivery packages out, with the money not yet received, than the configured limit allows.Chase and record the outstanding COD remittances; each one marked received brings the customer back under the limit. This check is off by default — it does nothing at all until an administrator sets reservation.cod_in_transit_limit in System Configuration to a number above zero.
Full set not yet paid
full_set_payment
This product is marked withhold until paid in full: not a single part of the set leaves until payment covers the whole order line. The customer is notified by SMS and email when this hold is applied.Collect and allocate the remaining payment against that order line. Once the line is fully covered, the hold no longer applies.
Minimum payment allocation not reached
min_payment_allocation
The product has a minimum payment allocation %, and the payment allocated to this order line, or to the order as a whole, is still below it. Every part of the line waits, not just this one. The customer is notified by SMS and email when this hold is applied.Collect and allocate payment against the order line (or other lines of the order, for the overall %). Once both percentages are reached, the hold clears on the next nightly run. The percentages are on the product's Discounts & Credits tab.
Payment not received/allocated
payment_pending
Two situations share this reason. Either the product is marked send strictly against payment and the money received against the order line doesn't yet cover this part's share of it, or the order as a whole hasn't settled. Both are the same job for you: get the payment in and allocated. The customer is notified by SMS and email.Record the payment and allocate it to the right order line. A part's share is the line's net amount split across its parts — for a twelve-part Full Set, one twelfth of the line per part, so each further payment releases roughly one more part.
Parts-on-credit limit reached for this set
parts_on_credit_limit
This part belongs to a set with a parts-on-credit limit, the part isn't paid for, and the customer already has that many unpaid parts of the same set reserved or sent. The customer is notified by SMS and email when this hold is applied.Collect and allocate payment against the order line, for this part or the earlier ones. The hold then clears on the next nightly run. You can also raise or blank the limit on the set's Discounts & Credits tab.
Credit limit exceeded
credit_limit
Credit checking is switched on for this customer and what they currently owe is above their ceiling.Collect payment to bring the balance down, or have the customer's credit_limit reviewed on their customer record.
Manually held by admin/manager
manual_hold
A colleague suspended this move by hand. This is the only reason a person can pick from the Suspend dropdown — every other reason above is applied by the system.Read the remark left on the move, resolve whatever it describes, then Unsuspend.
Some holds clear themselves — the money ones do not

Six of the automatic holds release on their own once their cause is gone: full_set_payment, min_payment_allocation, parts_on_credit_limit, cod_in_transit, return_pending and carrier_unserviceable. The nightly job re-checks held moves before it does anything else, so when the set is paid in full, the minimum payment is reached, payment covers the held part, the COD money comes in, the return is reconciled or the serviceability record is corrected, the move is released and reserved in that same run. For these six, fix the cause and leave it — nobody has to press anything.

Three holds wait for a person, even though two of them were applied by the system. payment_pending and credit_limit are not re-checked by the nightly job: recording the payment or raising the credit limit does not release the move by itself — someone still has to open it and press Unsuspend. manual_hold is the same by design, since a person applied it deliberately. If you have collected money against a held part and it is still suspended the next morning, this is why: clear the cause, then release it by hand.

Out-of-stock is not on this list, and never appears as a hold reason. A move that can't be reserved for lack of stock is simply left Confirmed and retried on the next nightly run — no suspension, nothing for you to clear.

Bulk actions and forms

There are no bulk actions on this list — every move is actioned one row at a time. This is a read-only base resource: no create page, no edit page, no delete. The only forms are the small ones opened by Suspend described above; Unsuspend and Cancel are single-click confirmations.

Related pages

See Stock on hand to watch qty_reserved rise and fall as moves are reserved, suspended, unsuspended or cancelled; Picking Waves for how a wave's Despatch action ships every one of its reserved moves in one cascade; and Schedulers for the daily auto-reservation job that advances Confirmed delivery moves to Reserved.