Fulfillment Orders
List Fulfillment Orders for a Sales Order
Lists every FulfillmentOrder attached to a SalesOrder with eager-loaded lines + warehouse. Powers the Pending sub-tab in the application UI SO detail page.
Get Fulfillment Order Detail
Returns a single FulfillmentOrder with its lines and warehouse eager-loaded. Each line exposes its `quantity` (the original budget) and `remaining_quantity` (the over-fulfilment backstop — units still available to consume via a SalesOrderFulfillmentLine).
Create Fulfillment Order
Creates a new FulfillmentOrder + its line budgets in a single transaction. Each line's `remaining_quantity` is initialized to `quantity`.
List Active Fulfillment Orders (Dispatch Feed, capped)
Cross-order **dispatch board** feed: every ACTIVE fulfillment order across all sales orders (excludes `closed` and `cancelled`), with `salesOrder` (for `sales_order_number`), `warehouse`, and `lines` eager-loaded. The frontend groups these into Kanban columns by `request_status` / `status` (Awaiting dispatch → Submitting → Submitted/Accepted → In progress → Needs attention).
Preview Fulfillment Order Move (Coverage)
Read-only coverage check for a prospective whole-FO move. Reports, per line that would move, whether the target warehouse can ship it from on-hand stock or would backorder it — so the UI can warn before committing. Mutates nothing.
Move Fulfillment Order to Different Warehouse
Pre-submit warehouse re-route. Relocates the WHOLE fulfillment order to a new warehouse: every line on the FO has its sales-order-line warehouse moved and its committed stock re-allocated at the target, and the FO itself is re-pointed there (the shipping provider follows the warehouse). It is the FO-level equivalent of moving each line individually. To move a single line instead, use the per-line move on the sales order.
Submit Fulfillment Order to Provider
Transitions `request_status` from `unsubmitted` → `submitting` and stamps `submitted_at` to the moment of hand-off (NOT when the carrier confirms — see Stage 2 for the carrier-callback flow that flips `submitting` → `submitted`/`accepted`).
Cancel Fulfillment Order
Cancels the fulfillment order, releases its line budgets back to the parent sales-order lines (so a different fulfillment order can pick them up), and optionally records a reason. Sets `status=cancelled` + `cancelled_at`.
Mark Fulfillment Order Picked Up
Records an in-person Click & Collect collection. Creates the execution `SalesOrderFulfillment` (status=`fulfilled`) directly from the awaiting-pickup FulfillmentOrder — driving the inventory deduction at create-time — and advances the FO `request_status` to `picked_up`. No SalesOrderFulfillment exists before this point; the awaiting-pickup state lives entirely on the FO.
Unmark Fulfillment Order Picked Up
Reverses a Click & Collect collection. Voids the collected pickup `SalesOrderFulfillment` (reversing its inventory movements + allocations and restoring the FulfillmentOrderLine budget) and returns the FO `request_status` to `awaiting_pickup`.
Split Fulfillment Order
Manually carve an **unsubmitted (proforma)** FulfillmentOrder into a NEW open/unsubmitted FO sized to the supplied per-line quantities. The original FO keeps the remainder. This is pure FulfillmentOrderLine budget redistribution — **neither FO is submitted** as a result (split and submit are separate concerns). To dispatch part of an order, split it then submit/hold each piece.
Retry Fulfillment Order Submission
Operator recovery action for a FO that is **stuck submitting** — i.e. `request_status=submitting` for longer than the stuck threshold (`config('fulfillment.stuck_submitting_threshold_minutes')`, default 15) without the provider confirming. Resets `request_status` back to `unsubmitted` and clears `submitted_at`, so the operator (or the dispatcher) can re-attempt the hand-off.
Force-Fail Fulfillment Order Submission
Operator recovery action for a FO that is **stuck submitting** when retrying is not appropriate (e.g. confirmed provider/carrier outage). Transitions `request_status` to `rejected` and records the supplied reason on `rejection_reason`. The FO drops out of the in-flight set so it can be cancelled or re-routed.
Get Dispatch Board Counts
Active-FO counts per dispatch-board lifecycle (+ `all`) for the board tab badges. Computed from the FULL active set (not the per-tab capped feed), so a badge reflects the true total even when its tab's column list is capped. Uses the same lifecycle classification as the board feed's `lifecycle` filter + the FO-table lifecycle filter, so the badge count and the loaded tab agree.
List Merge Candidates
Returns sibling pre-dispatch fulfillment orders on OTHER sales orders that could dispatch together with the anchor as ONE provider order (cross-order merge). Powers the 'Mergeable orders found' nudge on the sales order fulfillment tab.
List Post-Submission Merge Candidates
Returns sibling fulfillment orders on OTHER sales orders that this ALREADY-DISPATCHED fulfillment order could still be merged with at the shipping provider (post-submission cross-order merge). Same customer/address/warehouse/provider consensus as the pre-dispatch merge candidates, but for the window after auto-dispatch has already sent the orders to the provider.
Preflight Post-Submission Merge
Returns the read-only PLAN for merging two or more already-dispatched fulfillment orders into one provider order (post-submission cross-order merge). No provider call and no data is changed — this is the plan the operator confirms before the merge runs.
Execute Post-Submission Merge
Runs a post-submission cross-order merge for already-dispatched fulfillment orders. The plan is re-validated first; if it can still run, a background job cancels the absorbed orders at the shipping provider, adds their items to the master order, and then records the merge in SKU (each sales order keeps its own tracking). Returns a job handle to track progress.
Merge Fulfillment Orders
Fold a sibling fulfillment order (`source_fulfillment_order_id`) INTO the route FO (the target). The source's lines are merged into the target per sales order line, the emptied source FO is deleted, and the target is returned. One fulfillment order → one submission → one shipment.
Get Fulfillment Order Activity Log
Paginated audit trail for a single fulfillment order — created, warehouse move, shipping-method change, submit, merge, cancel — newest first. The same events also roll up onto the parent sales order's Activity tab (`GET /api/v2/sales-orders/{salesOrder}/activity-log`).
Edit Fulfillment Order Shipping Details
Edit the **requested** shipping params on a proforma fulfillment order before it is submitted — the shipping method, requested ship date, and provider-specific metadata (e.g. notes). These travel with the FO into the submission payload.
Record Shipment
Record a REAL shipment (one SalesOrderFulfillment) against this fulfillment order — the operator fallback for the intent/execution split. A fulfillment order is the provider's order; shipments come back as 1..N SalesOrderFulfillments over time.
Accept Fulfillment Order Discrepancy
Self-heal a shipping-provider ↔ fulfillment-order line discrepancy. Use this when the shipping provider marked the order shipped but one line's product cannot be fulfilled (no on-hand to deduct) — a permanent mismatch between what the provider shipped and what can actually leave the warehouse.
Reopen Fulfillment Order Discrepancy
Reverse a prior discrepancy acceptance and re-open the discrepancy alert for a fulfillment order. This clears the accepted stamp (`discrepancy_accepted_at` / `discrepancy_accepted_by`) and re-fires the discrepancy alert so the mismatch is surfaced again.
List Fulfillment Orders
Paginated, filtered, sorted list of FulfillmentOrders across ALL sales orders — the data source for the top-level **Fulfillment Orders** list view (a sibling of the Fulfillments table). Distinct from `GET /api/fulfillment-orders` (the active dispatch board): this `list` endpoint includes closed/cancelled FOs and supports the full filter/sort/paginate surface.
Get Fulfillment Order Line Items
The FO's lines (sku / name / product_id / quantity / remaining_quantity) for the list view's lazily-loaded expandable rows. Mirrors the SOF / PO line-items endpoints. `quantity` is the FOL budget; `remaining_quantity` is the amount still to be fulfilled.
Get Shipping Provider Options
The shipping-provider options for the Edit Shipping Details picker (per-FO provider override). Lists the configured shipping-provider integration instances in the tenant PLUS a synthetic Manual option, each with whether it's mapped to this FO's warehouse (`is_mapped`) and whether it's the warehouse's preferred default (`is_warehouse_default`). The dialog pre-selects `default_integration_instance_id`.
Bulk Submit Fulfillment Orders
Bulk submitted many FulfillmentOrders at once. Accepts `ids[]` (required without apply_to_all; each must exist in fulfillment_orders) OR `apply_to_all=true`.
Bulk Cancel Fulfillment Orders
Bulk cancelled many FulfillmentOrders at once. Accepts `ids[]` (required without apply_to_all; each must exist in fulfillment_orders) OR `apply_to_all=true`, optional `reason` (string, max 1000) recorded on each cancelled FO.
Print Packing Slips
Render (and combine, when several) packing slips for the given FulfillmentOrders and return the resulting file URL. The FO is the warehouse work package, so its slip lists the FO's planned line quantities.
Get Fulfillment Order Packing Slip Cache Status
Report whether a rendered packing-slip PDF is cached for this FulfillmentOrder (and when it was generated) so the UI can surface a 'cached' indicator and offer a one-click clear. Reports the newer of the legacy Jasper (`<fo_id>.pdf`) and Snappy (fingerprinted `<fo_id>_<fp>.pdf`) cache entries.
Clear Fulfillment Order Packing Slip Cache
Operator self-serve: drop the cached packing-slip PDF so the next print regenerates from current data. Wipes BOTH engines' caches — the legacy Jasper `<fo_id>.pdf` and every Snappy fingerprinted `<fo_id>_<fp>.pdf`. Idempotent — clearing a slip that was never cached is a no-op.
Create Fulfillment Order Merge Group
Merge two or more pre-dispatch fulfillment orders from DIFFERENT sales orders into one merged shipment group. The group dispatches to the shipping provider as a single order keyed on the primary member; at ship time each member's sales order records its own fulfillment carrying the shared tracking. If one of the given fulfillment orders already belongs to a group, the others are added to that group.
Delete Fulfillment Order Merge Group
Dissolve a merged shipment group entirely: every member fulfillment order reverts to an independent pre-dispatch fulfillment order. Only allowed while the group is still pre-dispatch — once dispatched to the provider the group can no longer be dissolved (409).
Remove Fulfillment Order from Merge Group
Remove this fulfillment order from its merged shipment group (pre-dispatch only). If the removal leaves fewer than two members, the whole group dissolves automatically.
Sync Fulfillment Order from Provider
Pull the shipping provider's latest data for the whole fulfillment order and reconcile the shipments it may have produced. An awaiting fulfillment order that the provider now reports shipped gets its shipment created; existing shipments have their tracking and status refreshed.
Sync Fulfillment Order to Provider
Push the fulfillment order's current order-level state (items, quantities, customer address) to the shipping provider. When shipments already exist each one is reconciled and re-sent; when none exist yet the registered provider order is updated in place — the primary use while the order is still awaiting fulfillment.
Apply Fulfillment Order Line Update
Apply a quantity change to a submitted fulfillment order in place. When a quantity increase created a separate fulfillment order for the extra units, this absorbs that fulfillment order back into this one and pushes the enlarged line set to the shipping provider as an update.
Bulk Sync Fulfillment Orders from Provider
Update tracking for many fulfillment orders at once by polling each one's registered provider order. Accepts an explicit `ids` selection, or `apply_to_all=true` — in which case the entire filtered set is resolved server-side from the request query string's current `filter[...]` / `filter_groups` parameters (the same filters as the fulfillment orders list endpoint). There is no body `filters` parameter.
Get FBA Fulfillment Preview
For a still-unsubmitted Amazon FBA fulfillment order, fetch Amazon's fulfillment preview: one estimate per available shipping speed (fulfillability, estimated fees, estimated shipping weight, and the ship/arrival window) WITHOUT creating a Multi-Channel Fulfillment order. Use it to compare speeds and costs before submitting.
Export Fulfillment Orders
Export the Fulfillment Orders list view as an XLSX or CSV file (sibling of the Fulfillments export). Requires a Bearer token.
List Fulfillment Order Packing Slip Print Events
Newest-first paginated history of every time this fulfillment order's packing slip was printed: who printed it, when, the render engine used, a print-time context snapshot (order reference, warehouse, line count), and whether an exact copy of the printed PDF is retained (`has_stored_copy`). Each event's exact printed PDF is retrievable via the download endpoint.
Download Fulfillment Order Packing Slip Print Copy
Return a signed URL to the byte-identical copy of the exact PDF that was printed for this event. The stored copy is never re-rendered, so it reflects the document exactly as it was printed even if the order has since changed. Returns 404 when the event does not belong to this fulfillment order, or when no copy was retained for it.
Update Packing Slip Print Event Reprint Reason
Set or clear an optional free-text reason on a packing-slip print event (for example, explaining why a slip was reprinted). Pass `reprint_reason` as a string (max 255 characters) or null to clear it.