# Order Workflow Rules ## Quote to Order - A quote remains in `quotes`. - Quote items remain in `quote_items`. - Creating an order from a quote creates one new `orders` record. - The new order links back to the quote through `orders.quote`. - Each quote item is copied into `order_items`. - Each copied order item links back to its source quote item through `order_items.quote_item`. - Creating an order from the same quote twice returns the existing order instead of duplicating it. - Quote status is not changed by order creation. ## Order Items as Source of Truth `order_items` is the operational source of truth after an order is created. **No order-level `status` field exists.** Items are the only authoritative lifecycle record; the order-level "Complete" badge in the UI is derived client-side from the items (see "Order Completion" below). Order items move through: - supplier ordering / purchase order - driver list / collection pool - collected (back at office) - picking - ready for delivery - delivered Driver/collection fields use `drv_*` naming where possible, for example `drv_status` and `drv_id`. ## Item Status Lifecycle `order_items.item_status` takes one of: | Status | Meaning | | ----------------- | -------------------------------------------------------------------- | | `pending` | Item created, not yet sent to a supplier. | | `processed` | Operator has reviewed/edited the line. | | `po_generated` | PO created; in_stock flag determines next step. | | `driver_pool` | Queued for collection (in_stock=false path). | | `assigned` | A driver has picked it up. | | `collected` | Back at the office (in_stock=true jumps straight here from PO). | | `stock_verified` | Verified against stock count. | | `picking` | Being pulled for delivery. | | `ready_delivery` | Packed, on the delivery vehicle. | | `delivered` | Signed for at the customer (terminal for the item). | | `cancelled` | Cancelled (terminal for the item). | ## Orders List — Item-Status Tabs The `/orders` page tabs are filtered by **item status**, not order status. There are six tab groups; each one is the set of item statuses that "live" on that tab. An order appears on tab X iff it has at least one item whose `item_status` is in X (so an order with items in both `pending` and `delivered` shows on both tabs). | Tab | Item statuses in this tab | | ---------------- | ------------------------------------------------------------------------------- | | New | `pending` | | Processing | `processed`, `po_generated` | | Collection Pool | `driver_pool`, `assigned` | | Collected | `collected`, `stock_verified`, `picking`, `ready_delivery` | | Delivered | `delivered` | | Cancelled | `cancelled` | The mapping lives in `src/lib/item-status-ui.ts` (`TAB_GROUP_ITEM_STATUSES`) and is the single source of truth for both the tab labels and the underlying PB filter strings. By default each row shows only items in the active tab. A "Show all items" toggle per row expands to the full item list. ## Order Completion (derived, not stored) A small helper `isOrderComplete(items)` in `src/lib/server/order-completion.ts` answers the only order-level question the UI still asks: "is this order done?". It returns true iff `items.length > 0 && every item is delivered`. The green "Complete" badge on `/orders/[id]` and the order row header is driven entirely by this helper — there is no `orders.status` field to keep in sync, and therefore no flip-flop bug on refresh. Invoiced is a separate boolean (`orders.invoiced`, set by the invoicing action), intentionally independent from item lifecycle — an order can be marked invoiced before, during, or after the items are all delivered. ## In-Stock Items Each `order_items` row carries an `in_stock: bool` flag. When `true`, the line bypasses the driver collection pool entirely after PO generation: - `in_stock = false` → on PO send, item transitions to `driver_pool` and a `collection_pool` row is created. - `in_stock = true` → on PO send, item transitions to `collected` (skipping the pool). Invoices and delivery notes ignore the flag — the item is still part of the order and counted in totals. ## Driver List and Collection Pool The old Django `driver_list` workflow is represented by the new `collection_pool` concept. `collection_pool` tracks assignment and collection work, while `order_items` keeps the item lifecycle state. ## Future Stock Collection Later we will add a dedicated `stock` collection. Stock is used when: - more items are collected than the order requires - stock is ordered and arrives at the office - collected items should be booked into stock instead of moving to invoicing Until that collection exists, stock-related operational movement stays on `order_items`. ## Delivery Notes Delivery notes should be generated from order items that are ready, loaded, or delivered. ## Repairs Repairs will be rebuilt only where they connect to the practical order/quote/repair flow.