# Order allocation, dispatch and delivery

The fourth Phase 4 milestone extends Orders on staff web, iOS and Android. It supports one complete shipment per accepted order, with explicit administrator review at each step. Recording acceptance still reserves nothing; the separate-administrator order confirmation rule is unchanged.

## Workflow

1. **Prepare inventory before quoting.** Register IMEIs and confirm each device's physical warehouse location using Devices & reservations → Device details → Warehouse location. Every device needs an active location for allocation and dispatch. If an already-reserved order contains unlocated devices, cancel it, assign locations, revise/reapprove the quotation, then obtain/record fresh acceptance. Location changes advance source versions; accepted snapshots are never silently rewritten.
2. **Allocate order devices.** From a reserved order, an administrator reviews the entire order, exact IMEIs, warehouse readiness and notes, ticks the review acknowledgement and confirms allocation. All live holds become allocations in one transaction. Devices remain unavailable and no longer become available when the original hold deadline passes.
3. **Record complete dispatch.** After physical handover, record the actual event time with timezone, carrier or collection method, tracking/handover reference, named recipient, full delivery address and evidence notes. Explicitly confirm that every listed IMEI physically left its warehouse for that destination. The application records the event; it does not book a courier, validate the address or send a notification.
4. **Record a shipment update if needed.** For delays, failed delivery attempts or other problems, save a descriptive update from a dispatched order. It advances the order version and appends history, without recording delivery or releasing devices.
5. **Record complete delivery.** After checking receipt evidence, record the recipient, actual receipt time, evidence reference and notes, then explicitly confirm that every order device was received. Stock stays allocated and the order becomes delivered. Payment status is not implied.

Only active administrators can allocate, dispatch, record shipment updates or record delivery. Traders and viewers can inspect the shared order, evidence and history. No extra second-person requirement is introduced for fulfilment actions: the original separate administrator already confirmed the order. The quote approval requirement also remains unchanged.

Evidence is staff-recorded text and source references, not uploaded signed documents, verified signatures or carrier API status. Check and retain the original source using the existing document process. Dispatch time must be after allocation and no later than now; delivery time must follow physical dispatch and be no later than now. Server recording times and actor names are retained separately from reported event times. Enter an earlier actual event time when recording after the fact, within these bounds.

## Inventory and custody

Allocation verifies every frozen line and reservation: exact quantity, accepted customer/currency/sale price, unexpired live holds, current device association, original primary/secondary IMEIs, no returned/retired/quarantined/in-transit devices, active customer, active stock and confirmed active warehouse locations. One failed line leaves all lines unchanged. A changed or expired hold cannot be converted into an allocation.

Dispatch requires the same exact allocated devices, active customer and warehouse locations. It snapshots each device's primary/secondary IMEIs and warehouse ID/name, then clears its on-hand location. The allocation remains attached. Warehouse on-hand counts and lists exclude those devices after dispatch; inventory labels them **Dispatched to customer** with their order reference. They cannot be reassigned, internally transferred or sold again. No internal warehouse transfer is invented; customer shipment origins live in the order's immutable dispatch history.

The original hold deadline remains visible for context but does not expire an allocation. Quote expiry after valid order confirmation does not undo the accepted order. Stock expiry after allocation does not release allocated devices or prevent recording their physical dispatch. A later directory rename cannot change frozen customer or shipment details. An archived customer blocks allocation/dispatch; it does not prevent recording an actual subsequent delivery against an already dispatched order.

Active/allocated/dispatched/delivered orders keep the quotation locked against revision and cancellation. Pending and reserved orders retain the existing administrator cancellation workflow. Once allocated, cancellation and standalone inventory release are blocked. Order returns and recalls now use the explicit physical receipt workflow in ORDER-RETURNS.md. The older wanted-list return workflow still rejects order allocations; use Orders to receive these devices into a confirmed warehouse and quarantine.

## History, retries and conflicts

States are `pending`, `reserved`, `allocated`, `dispatched`, `delivered`, `returning`, `returned` and `cancelled`; `expired` remains a filter for reserved orders with expired holds. Filters and history work on both clients. Shipment updates leave the state `dispatched`.

Every fulfilment action requires the version the administrator reviewed. Transaction locks and version checks permit one winner for concurrent allocation/cancellation, duplicate dispatch and duplicate delivery. Repeated requests with a stale version cannot duplicate the transition or release stock. If a response is uncertain, reload the order before retrying. Both clients retain unsaved notes after a conflict and ask before discarding them on reload/close. Editing any field clears its review acknowledgement.

Allocation, dispatch, shipment updates and delivery append immutable order history and audit events. The accepted quote/evidence stays unchanged; previous history snapshots are not retroactively filled with later shipment or delivery details. There is no edit/delete endpoint for recorded fulfilment; physical reversals use ORDER-RETURNS.md; editing recorded shipment evidence remains future work.

## API and schema

- `POST /v1/orders/{id}/allocate`: reviewed allocation of all current held devices.
- `POST /v1/orders/{id}/dispatch`: physical handover evidence and exact warehouse departures.
- `POST /v1/orders/{id}/shipment-note`: append a reviewed shipment update.
- `POST /v1/orders/{id}/deliver`: full receipt evidence.

Order responses include fulfilment details, readiness warnings and action eligibility. Old history entries can omit fulfilment details. Device responses include a customer-order reference when dispatched/delivered. The authenticated web proxy enforces same-origin mutations; native uses the existing secure staff session.

Migration `d92a1068bc43` follows `c81f9045a7d2`, adding default-empty `sales_orders.fulfilment_json` and extending its state constraint. It creates no shipments, changes no previous data and requires no new account. Back up and pause writers before migration. Downgrade refuses to discard recorded fulfilment evidence. Existing reservation/wanted associations and account credentials remain intact.

## Release boundaries and next work

This is a local development milestone. Physical iOS/Android screens, nested sheets, keyboard and confirmation dialogs, signed builds and PostgreSQL contention still need validation. Browser tests use synthetic devices and an isolated database. No production deployment, courier booking, email or WhatsApp messages occur. Live email testing remains deferred and WhatsApp remains disabled pending Meta setup.

Order returns/recall into quarantine are now available; see ORDER-RETURNS.md. Next add financial documents and payments. Partial allocation/shipment/delivery, split shipments, lost-stock write-offs, automatic carrier tracking, editable shipping details, document uploads, invoices, taxes, refunds and payment reconciliation are not included here.

Invoice drafts and the reviewed receipt ledger are now built locally; see BILLING.md. Formal issuance remains disabled pending company/tax details and jurisdiction-specific setup. Credit notes and actual refunds are not implemented.
