What an order status does to fulfillment
Listener. order.status.changed → OrderFulfillmentListener → FulfillmentOrderSyncService.applyStatusTransition.
The handler is idempotent (fulfillment.order-status-changed.v1). It returns immediately when the order row’s status is no longer the event’s toStatus.
order.created does not use this method. It calls applyCreatedOrder, which reserves stock only when the order is still PENDING and the mode allocates owned stock. See Move warehouse.
Who holds the stock
allocatesOwnedStock is false for CHANNEL_FULFILLED and VENDOR_DROPSHIP.
resolveFulfillmentMode sets CHANNEL_FULFILLED when the channel descriptor is one of afn, fba, amazon, amazon_na, smart_fulfilment, smart_fulfillment, fbf, flipkart_smart (case-insensitive). Anything else uses the channel default, which is OMS_MANAGED when the channel has none.
CHANNEL_FULFILLED (Amazon AFN and the other descriptors above) does not reserve owned stock. The comment says those units are already in the marketplace building. VENDOR_DROPSHIP also skips the reservation, and when the order is PENDING it still creates a fulfillment worksheet.
Acceptance policy
allocateOrder routes with WarehouseRouterService, then reconcileOrderReservations. It enqueues stock.sync.requested after the hold so a concurrent sync does not publish availability before the reservation exists.
applyAcceptancePolicy reads TenantSetting.blockOversell and autoConfirmOrders. If there is no settings row, it returns. It does not throw.
| blockOversell | autoConfirmOrders | Covered | What the code does |
|---|---|---|---|
| true | either | no | Sets exceptionReason and exceptionAt. Does not confirm |
| false | false | either | Leaves the order PENDING |
| true or false | true | yes, and address is not AWAITING_CUSTOMER_RESOLUTION or INVALID | ensureForConfirmation, then transitions the order to CONFIRMED with note Auto-confirmed: fully allocated and address validated |
| false | true | no | Returns without confirming |
Status transitions
| To status | Fulfillment effect |
|---|---|
CONFIRMED | If no fulfillment orders exist, createFromOrder. If they exist, ON_HOLD worksheets return to OPEN unless the address is still AWAITING_CUSTOMER_RESOLUTION |
ON_HOLD | Worksheets that are not SHIPPED, DELIVERED, CANCELLED, or already ON_HOLD move to ON_HOLD. Reservations are not released. Hold reason: Held due to commercial order being placed on hold |
PENDING | If no worksheet exists yet, this is treated as the first time the order is pending (payment hold releasing). Owned-stock modes call allocateOrder. Dropship calls createFromOrder. If worksheets exist, holds are released the same way as confirm, unless the address is still awaiting the customer |
CANCELLED | Every worksheet that is not already CANCELLED is cancelled and its reservations are released. Reservations held on the order itself are released even when no worksheet exists |
FULFILLED or DELIVERED | If no worksheet exists, consumeOrderReservationsAndStock. If worksheets exist and are not already SHIPPED, DELIVERED, or CANCELLED, they are set to SHIPPED and stock is consumed with shortfall reconciled (CHANNEL_DISPATCH). The comment says this path cannot refuse, because the channel already shipped |
Other target statuses do not enter these branches.
Cancelling a partially fulfilled order does release reservations on worksheets that are not yet CANCELLED, including ones that were already picked, because the cancel loop does not look at pick progress. Whether picked units are put back on the shelf is whatever releaseReservations writes. That method was not expanded here.