Skip to content

Orders Flow

This page explains how orders work end-to-end: screens, columns/board, line items, inventory links, and Supabase tables.


Screens & views

Orders main screen (/orders)

File: src/pages/Orders.tsx

Responsibilities:

  • Main entry point for order management.
  • Provides two views:
    • Kanban board (default) – orders grouped by custom columns.
    • List view – table of all orders (including invoiced).
  • Handles order creation, editing, deletion, file attachments, and column management.

Key UI pieces:

  • Tabs / view toggle

    • Uses view query param to switch between:
    • kanban (default) – board view.
    • list – tabular view via OrdersListView.
  • Kanban board

    • Component: src/components/orders/OrderBoard.tsx.
    • Columns:
    • Backed by the order_columns table (per-tenant).
    • Drag-and-drop reordering of columns.
    • Can be renamed, deleted, or collapsed.
    • Cards:
    • Each card represents an order in a given column.
    • Cards can be dragged between columns to change status.
  • List view

    • Component: src/components/orders/OrdersListView.tsx.
    • Shows all orders, including those linked to invoices.
    • Displays key info: client, status (Paid/Invoiced/Column/Unassigned), amount, date.
  • Order form

    • Component: src/components/orders/OrderForm.tsx.
    • Used for creating and editing orders.
    • Supports:
    • Client selection/creation.
    • Line items (inventory + quantities + prices).
    • Attachments.
  • Order details drawer/modal

    • Component: src/components/orders/OrderDetailsModal.tsx.
    • Shows full order details, line items, attachments.
    • Entry-point for editing or marking as paid.
  • Order filters & column settings

    • OrderFilters and ColumnSettingsDialog components manage advanced filtering and column configuration.

Hooks & operations

useOrders

File: src/hooks/useOrders.ts

Provides the core API for interacting with orders:

  • Queries

    • fetchOrders(silent?) – main board view:
    • Fetches orders for the current tenant_id.
    • Excludes orders with invoice_id (those are hidden from the board).
    • Includes joins:
    • clients, inventory_items, product_variations, order_columns.
    • Fetches order_attachments and order_line_items per order.
    • fetchAllOrders(silent?) – list view:
    • Same as above, but includes orders with invoice_id.
    • Also looks up invoice info (invoices table) when invoice_id is present.
    • fetchOrdersByClient(clientId) – all orders for a given client.
    • fetchOrderById(orderId) – single order + attachments + line items.
  • Board operations

    • moveOrderToColumn(orderId, columnId, position?) – moves card to a column with server-side position calculation.
    • updateOrderPosition(orderId, columnId, position, silent?) – updates card position within a column.
  • CRUD

    • createOrder(input)
    • updateOrder(input)
    • deleteOrder(id)
  • Line items & totals

    • addOrderLineItem(orderId, lineItem) – inserts order_line_items row and recalculates order total.
    • deleteOrderLineItem(lineItemId) – deletes line item, recalculates total, and restores inventory stock.
  • Attachments

    • uploadOrderAttachment(orderId, file) – uploads to Supabase Storage (order-attachments bucket) and creates order_attachments row.
    • deleteOrderAttachment(attachmentId) – removes from storage and DB.
  • Status helpers

    • markOrderAsPaid(orderId, paidDate?) – sets is_paid = true, paid_at on orders.

Order creation & inventory interaction

Create flow

When createOrder(input) is called:

  1. Stock validation

    • For each line_items entry with inventory_item_id:
    • If track_variant_inventory is true and product_variation_id is set:
    • Checks product_variations.current_stock_qty to ensure sufficient stock.
    • Otherwise:
    • Checks inventory_items.current_stock_qty.
    • Throws an error if requested quantity exceeds available stock (per item or variation).
  2. Client auto-creation

    • If no client_id but first_name, last_name, and phone are provided:
    • Uses useClients().createClient() to create a client.
    • Uses the order’s email (if provided) for the client.
    • Sets client_id on the order.
  3. Column assignment

    • If no column_id and no invoice_id:
    • Finds the first order_columns row for the current tenant.
    • Assigns its id as column_id.
    • If invoice_id is present:
    • Leaves column_id null (order is hidden from board, considered part of invoicing flow).
  4. Card position

    • If no card_position is given and a column_id is set:
    • Looks at existing orders in that column.
    • Sets card_position to the next available slot (max + 1).
  5. Total price

    • If line_items are provided:
    • Computes price = sum(quantity * unit_price).
    • Otherwise uses input.price as the order total.
  6. Insert order

    • Inserts into orders with:
    • tenant_id, client_id, first_name, last_name, phone, email.
    • price, piece_description, inventory_item_id, product_variation_id (legacy fields).
    • column_id, card_position, invoice_id.
  7. Insert line items & deduct stock

    • For each entry in line_items:
    • Inserts row into order_line_items with line_total = quantity * unit_price.
    • Calls deduct_inventory_stock RPC to adjust stock.
    • For legacy single-item orders (inventory_item_id without line_items):
    • Calls deduct_inventory_stock once.

Update flow

When updateOrder(input) is called:

  • Builds a partial update payload with only fields present.
  • Updates orders row.
  • If line_items is provided:
    • Fetches existing order_line_items for the order.
    • Deletes items not present in the new list and restores their inventory via restore_inventory_stock RPC.
    • Updates existing items and adjusts stock based on quantity differences.
    • Inserts new items and deducts stock via deduct_inventory_stock.

Status & columns

Board columns

  • Table: order_columns
  • Per-tenant list of columns used on the Kanban board.
  • Fields (from code and usage):
    • id, tenant_id.
    • name – column name (e.g. "New", "In Progress", "Completed").
    • position – ordering on the board.
    • color – hex color used in list view badges.

Columns can be:

  • Created with createColumn(name).
  • Updated with updateColumn(id, updates).
  • Reordered with reorderColumns(columnIds).
  • Deleted with deleteColumn(id).

Order status

Orders don’t use a single status field; they derive status from:

  • Column:

    • Column placement on the board indicates logical status.
    • Example flow:
    • New order appears in the first column.
    • Orders move across columns as work progresses.
  • Invoicing:

    • Orders with invoice_id are considered invoiced and hidden from the board.
    • List view shows an "Invoiced" badge and invoice number if available.
  • Payment:

    • is_paid and paid_at on the orders table reflect payment status.
    • List view shows a "Paid" badge for such orders.

In OrdersListView, the priority is:

  1. Paid (is_paid = true).
  2. Invoiced (invoice_id present or invoice object loaded).
  3. Column name (if assigned).
  4. "Unassigned" (no column, not invoiced, not paid).

Tables & relationships

Key tables involved:

  • orders

    • Core order record per job.
    • Important fields:
    • id, tenant_id, client_id.
    • first_name, last_name, phone, email (for quick capture on forms).
    • piece_description.
    • price – total order amount.
    • inventory_item_id, product_variation_id (legacy direct link).
    • column_id, card_position – board placement.
    • invoice_id – link to invoices table.
    • is_paid, paid_at.
    • Timestamps (created_at, updated_at).
  • order_line_items

    • One-to-many per order.
    • Fields:
    • order_id (FK → orders.id).
    • inventory_item_id (FK → inventory_items.id).
    • product_variation_id (FK → product_variations.id).
    • item_name, description.
    • quantity, unit_price, line_total.
    • position.
  • order_attachments

    • Files attached to orders.
    • Fields:
    • order_id.
    • file_url, storage_path, file_name, file_type, file_size.
  • order_columns

    • Kanban columns as described above.
  • invoices (linked to orders but documented in payments/checkout flow).

  • inventory_items & product_variations

    • Referenced from line items.
    • Stock mutations via deduct_inventory_stock and restore_inventory_stock RPCs.

Flow diagram

flowchart LR
  U[User] --> ORD[/Orders screen/]
  ORD --> HOOK[useOrders]
  HOOK --> ORDERS[(orders)]
  HOOK --> LINES[(order_line_items)]
  HOOK --> COLS[(order_columns)]
  LINES --> INV[(inventory_items & product_variations)]

  click ORD "../architecture/frontend/" "Orders page & components"
  click HOOK "../architecture/frontend/" "Frontend hooks (useOrders)"
  click ORDERS "../architecture/supabase/" "Orders table (Supabase)"
  click LINES "../architecture/supabase/" "Order line items & inventory links"
  click INV "./inventory.md" "Inventory flow & stock rules"

Narrative:

  1. User opens /orders and sees either Kanban or list view.
  2. useOrders fetches orders, line items, columns, attachments, and invoice links via Supabase.
  3. Drag-and-drop and form actions call back into useOrders to update orders, order_line_items, and order_columns.
  4. Inventory stock is enforced and updated via RPCs whenever line items change.
  5. Downstream flows (invoices, payments) use orders and order_line_items as their starting point.