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.comto enable invoices and pay links.
- Merchants must contact
- Provides two primary actions:
- Invoice Creation →
/payments/invoice. - Pay Link Creation →
/payments/pay-link.
- Invoice Creation →
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
InvoiceItemAutocompleteand a table of editable rows. - Invoice metadata:
- Auto-generated invoice number via
generate_next_invoice_numberRPC. - Due date.
- Tax percentage (applied to subtotal).
- Fee amount (used as
discount_amountfield; semantics depend on usage).
- Auto-generated invoice number via
Pay link creation (/payments/pay-link)¶
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
InvoiceItemAutocompleteover inventory. - Pay link metadata:
- Auto-generated link code via
generate_next_pay_link_codeRPC. - Expiration in days (converted to
expires_at). - Tax percentage and fee.
- Recipient email.
- Auto-generated link code via
Invoices: data & behavior¶
useInvoices hook¶
File: src/hooks/useInvoices.ts
The primary API:
createInvoice(input, client, companyInfo, orderEmail, skipOrderCreation?)→Invoice- Creates an
invoicesrow. - Links an order to the invoice (if
order_idpresent). - Inserts
invoice_line_itemsrows. - Generates a PDF and uploads it to the
librarybucket. - Inserts a
library_files_newrow for the PDF.
- Creates an
Key behaviors:
-
Tenant verification
- Uses
useAuth().tenantIdandsupabase.auth.getUser()to ensure thetenant_idused matchesuser_profiles.tenant_id.
- Uses
-
Invoice record
- Inserts into
invoices: tenant_id,order_id,client_id.invoice_number(caller must supply, typically fromgenerate_next_invoice_number).issue_date,due_date.subtotal,tax_amount,discount_amount,total_amount.currency,notes,terms.
- Inserts into
-
Order linkage
- If
input.order_idis present: - Updates
orders.invoice_id = invoice.id. - This hides the order from the Kanban board and ties it to the invoice.
- If
-
Line items
- Inserts
invoice_line_itemsusinginput.line_items: invoice_id,order_line_item_id(optional),item_name,description.quantity,unit_price,line_total,position.
- Inserts
-
PDF generation and storage
- Loads the full invoice with
line_itemsvia a join. - Calls
generateInvoicePDF(invoice, client, companyInfo, orderEmail). - Uploads PDF to
librarybucket at{tenant_id}/invoice-{invoice_number}-{invoice.id}.pdf. - Gets a public URL and inserts a
library_files_newrecord with: tenant_id,user_id,title,description,tags: ['invoice','auto_generated','pdf'].
- Loads the full invoice with
Invoices schema¶
Migration: 20250208000005_create_invoices_table.sql
-
invoicesid,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_itemsid,invoice_id.order_line_item_id(link toorder_line_items, if derived from an order).item_name,description.quantity,unit_price,line_total.position.
Both tables have RLS enabled.
Pay links: data & behavior¶
usePayLinks hook¶
File: src/hooks/usePayLinks.ts
The primary APIs:
createPayLink(input)→PayLinkfetchPayLink(id)→PayLink | nullupdatePayLink(id, updates)→PayLinkdeletePayLink(id)→void
createPayLink(input):
-
Tenant verification
- Uses
useAuth().tenantIdand user’stenant_idfromuser_profilesto ensure correct scoping.
- Uses
-
pay_linksinsert- 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).
-
Line items
- Inserts
pay_link_line_itemsrows for each entry ininput.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.
- Inserts
-
Return value
- Fetches full pay link with joins to
clients,orders, andpay_link_line_items.
- Fetches full pay link with joins to
Pay links schema¶
Migrations: 20250211000005_create_pay_links_table.sql, 20250211000006_create_pay_link_line_items_table.sql
-
pay_linksid,tenant_id,order_id,client_id.link_code(unique per tenant, e.g.PAY-001-1).link_url– external payment 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 integration).
-
pay_link_line_itemsid,pay_link_id.order_line_item_id(optional link toorder_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_idandorders.invoice_idcreate a two-way link.pay_links.order_idassociates a pay link with a job.
order_line_itemscan 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:
- User selects an order and/or client, adds/edits line items.
useInvoices.createInvoicewritesinvoicesandinvoice_line_items.- The linked order’s
invoice_idis set. - A PDF is generated and stored in the
librarybucket andlibrary_files_new. - The invoice is now available for download and tracking.
Pay link creation¶
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:
- User selects a client and optionally an order.
- User configures link code, expiration, tax/fees, and line items.
usePayLinks.createPayLinkwritespay_linksandpay_link_line_items.- The app shows the link code and URL to copy/share.
- In the future, external gateway events will update
link_statustopaidorexpired.
Related docs¶
- Billing & Stripe Flow – subscription billing.
- Orders Flow – orders and line items powering invoices/pay links.
- Inventory Flow – how line items reference inventory.
- Supabase Architecture – tables and RLS.
- Design Studio & Library Flow – how invoice PDFs are stored in the Library.