Skip to content

Payments, Invoices & Pay Links Flow

This page covers payments beyond subscriptions: invoices and pay links. These flows are separate from Stripe subscription billing and are used for one-off jobs, deposits, and ad‑hoc payments.


Screens

Payments hub (/payments)

File: src/pages/Payments.tsx

Responsibilities:

  • Landing page for non-subscription payments.
  • Explains that Workbench uses Greyhaven Payments for processing.
  • Shows a support/activation alert:
    • Merchants must contact merchantsupport@greyhavengroup.com to enable invoices and pay links.
  • Provides two primary actions:
    • Invoice Creation/payments/invoice.
    • Pay Link Creation/payments/pay-link.

The page itself is read-only navigation and messaging; the actual flows live on the subpages.

Invoice creation (/payments/invoice)

File: src/pages/payments/InvoiceCreation.tsx

Responsibilities:

  • Create invoices for a client based on:
    • Existing orders and their line items.
    • Manually added line items (inventory-backed or custom).
  • Generate a PDF invoice and store it in Supabase Storage.
  • Link the invoice to an order (so the order disappears from the Kanban board).

Key elements:

  • Client selection via ClientSelect.
  • Optional order selection via OrderSelect.
  • Line item entry via InvoiceItemAutocomplete and a table of editable rows.
  • Invoice metadata:
    • Auto-generated invoice number via generate_next_invoice_number RPC.
    • Due date.
    • Tax percentage (applied to subtotal).
    • Fee amount (used as discount_amount field; semantics depend on usage).

File: src/pages/payments/PayLinkCreation.tsx

Responsibilities:

  • Create payment links for one-off payments.
  • Support linking to an existing order or just a client.
  • Generate a link code and URL (current implementation uses a temporary URL pattern; future versions will integrate gateway URLs).

Key elements:

  • Client selection via ClientSelect.
  • Optional order selection via OrderSelect.
  • Line item entry similar to invoices, using InvoiceItemAutocomplete over inventory.
  • Pay link metadata:
    • Auto-generated link code via generate_next_pay_link_code RPC.
    • Expiration in days (converted to expires_at).
    • Tax percentage and fee.
    • Recipient email.

Invoices: data & behavior

useInvoices hook

File: src/hooks/useInvoices.ts

The primary API:

  • createInvoice(input, client, companyInfo, orderEmail, skipOrderCreation?)Invoice
    • Creates an invoices row.
    • Links an order to the invoice (if order_id present).
    • Inserts invoice_line_items rows.
    • Generates a PDF and uploads it to the library bucket.
    • Inserts a library_files_new row for the PDF.

Key behaviors:

  1. Tenant verification

    • Uses useAuth().tenantId and supabase.auth.getUser() to ensure the tenant_id used matches user_profiles.tenant_id.
  2. Invoice record

    • Inserts into invoices:
    • tenant_id, order_id, client_id.
    • invoice_number (caller must supply, typically from generate_next_invoice_number).
    • issue_date, due_date.
    • subtotal, tax_amount, discount_amount, total_amount.
    • currency, notes, terms.
  3. Order linkage

    • If input.order_id is present:
    • Updates orders.invoice_id = invoice.id.
    • This hides the order from the Kanban board and ties it to the invoice.
  4. Line items

    • Inserts invoice_line_items using input.line_items:
    • invoice_id, order_line_item_id (optional), item_name, description.
    • quantity, unit_price, line_total, position.
  5. PDF generation and storage

    • Loads the full invoice with line_items via a join.
    • Calls generateInvoicePDF(invoice, client, companyInfo, orderEmail).
    • Uploads PDF to library bucket at {tenant_id}/invoice-{invoice_number}-{invoice.id}.pdf.
    • Gets a public URL and inserts a library_files_new record with:
    • tenant_id, user_id, title, description, tags: ['invoice','auto_generated','pdf'].

Invoices schema

Migration: 20250208000005_create_invoices_table.sql

  • invoices

    • id, tenant_id, order_id, client_id.
    • invoice_number (unique per tenant).
    • status (draft, sent, paid, overdue, cancelled).
    • issue_date, due_date.
    • subtotal, tax_amount, discount_amount, total_amount.
    • currency.
    • notes, terms.
    • pdf_url, pdf_storage_path.
    • created_at, updated_at.
  • invoice_line_items

    • id, invoice_id.
    • order_line_item_id (link to order_line_items, if derived from an order).
    • item_name, description.
    • quantity, unit_price, line_total.
    • position.

Both tables have RLS enabled.


File: src/hooks/usePayLinks.ts

The primary APIs:

  • createPayLink(input)PayLink
  • fetchPayLink(id)PayLink | null
  • updatePayLink(id, updates)PayLink
  • deletePayLink(id)void

createPayLink(input):

  1. Tenant verification

    • Uses useAuth().tenantId and user’s tenant_id from user_profiles to ensure correct scoping.
  2. pay_links insert

    • Inserts row with:
    • tenant_id, order_id, client_id.
    • link_code (unique per tenant), link_url.
    • link_status (active, expired, paid, cancelled).
    • expires_at.
    • payment_subtotal, payment_tax, payment_fee, payment_total.
    • currency.
    • recipient_email, link_description.
    • gateway_payment_id, gateway_link_id (future gateway integration).
  3. Line items

    • Inserts pay_link_line_items rows for each entry in input.line_items:
    • pay_link_id.
    • order_line_item_id, inventory_item_id, product_variation_id (optional links).
    • item_name, description.
    • quantity, unit_price, line_total, position.
  4. Return value

    • Fetches full pay link with joins to clients, orders, and pay_link_line_items.

Migrations: 20250211000005_create_pay_links_table.sql, 20250211000006_create_pay_link_line_items_table.sql

  • pay_links

    • id, tenant_id, order_id, client_id.
    • link_code (unique per tenant, e.g. PAY-001-1).
    • link_url – external payment URL.
    • link_statusactive, expired, paid, cancelled.
    • expires_at.
    • payment_subtotal, payment_tax, payment_fee, payment_total.
    • currency.
    • recipient_email.
    • link_description.
    • gateway_payment_id, gateway_link_id (future integration).
  • pay_link_line_items

    • id, pay_link_id.
    • order_line_item_id (optional link to order_line_items).
    • inventory_item_id, product_variation_id.
    • item_name, description.
    • quantity, unit_price, line_total.
    • position.

Relationship to orders & inventory

Orders

  • Invoices and pay links both optionally link back to orders:
    • invoices.order_id and orders.invoice_id create a two-way link.
    • pay_links.order_id associates a pay link with a job.
  • order_line_items can be carried through:
    • invoice_line_items.order_line_item_id.
    • pay_link_line_items.order_line_item_id.

Inventory

  • Line items reference inventory when applicable:
    • order_line_items.inventory_item_id.
    • pay_link_line_items.inventory_item_id.
  • Stock adjustments still flow through the Orders layer (via deduct_inventory_stock / restore_inventory_stock), not directly via invoices/pay links.

End-to-end payment flows

Invoice creation (from an order)

flowchart LR
  U[User] --> INVUI[/Invoice Creation screen/]
  INVUI --> ORDSEL[OrderSelect]
  INVUI --> LINES[Line items table]
  INVUI --> INVHOOK[useInvoices]

  subgraph Supabase
    ORD[(orders)]
    OLI[(order_line_items)]
    INV[(invoices)]
    INVL[(invoice_line_items)]
    LIB[(library_files_new + storage)]
  end

  ORDSEL --> ORD
  LINES --> OLI
  INVHOOK --> INV
  INVHOOK --> INVL
  INVHOOK --> ORD
  INVHOOK --> LIB

  click INVUI "../architecture/frontend/" "Invoice UI components"
  click INV "../architecture/supabase/" "Invoices schema"
  click OLI "./orders.md" "Orders & line items"

Narrative:

  1. User selects an order and/or client, adds/edits line items.
  2. useInvoices.createInvoice writes invoices and invoice_line_items.
  3. The linked order’s invoice_id is set.
  4. A PDF is generated and stored in the library bucket and library_files_new.
  5. The invoice is now available for download and tracking.
flowchart LR
  U[User] --> PLUI[/Pay Link Creation screen/]
  PLUI --> ORDSEL[OrderSelect]
  PLUI --> LINES[Line items table]
  PLUI --> PLHOOK[usePayLinks]

  subgraph Supabase
    ORD[(orders)]
    OLI[(order_line_items)]
    PL[(pay_links)]
    PLL[(pay_link_line_items)]
  end

  ORDSEL --> ORD
  LINES --> OLI
  PLHOOK --> PL
  PLHOOK --> PLL

  click PLUI "../architecture/frontend/" "Pay link UI"
  click PL "../architecture/supabase/" "Pay links schema"
  click OLI "./orders.md" "Orders & line items"

Narrative:

  1. User selects a client and optionally an order.
  2. User configures link code, expiration, tax/fees, and line items.
  3. usePayLinks.createPayLink writes pay_links and pay_link_line_items.
  4. The app shows the link code and URL to copy/share.
  5. In the future, external gateway events will update link_status to paid or expired.