b767a00b5f
- Add invoice_status and payment_method enums to schema - Add invoices table: appointmentId, clientId, subtotal/tax/tip/total cents, status (draft/pending/paid/void), paymentMethod, paidAt, notes - Add invoice_line_items table: invoiceId, description, qty, unitPrice, total - Migration 0002_invoices.sql with FK constraints and journal entry - POST /api/invoices — create invoice with line items - POST /api/invoices/from-appointment/:id — one-click invoice from appointment, pre-populated with service name and price; returns 409 if already invoiced - GET /api/invoices — list with optional ?status/clientId/appointmentId filters - GET /api/invoices/:id — invoice with line items - PATCH /api/invoices/:id — update status, payment method, tip, notes; auto-sets paidAt when marking paid; blocks edits on voided invoices - Add Invoice/InvoiceLineItem types to @groombook/types - InvoicesPage: list view with status filter, create from appointment modal, detail modal with tip input, payment method selector, Mark as Paid/Void actions - Add Invoices nav link in App.tsx Co-authored-by: Groom Book CTO <cto@groombook.app> Co-authored-by: Paperclip <noreply@paperclip.ing>
32 lines
1.7 KiB
SQL
32 lines
1.7 KiB
SQL
CREATE TYPE "public"."invoice_status" AS ENUM('draft', 'pending', 'paid', 'void');--> statement-breakpoint
|
|
CREATE TYPE "public"."payment_method" AS ENUM('cash', 'card', 'check', 'other');--> statement-breakpoint
|
|
CREATE TABLE "invoices" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"appointment_id" uuid,
|
|
"client_id" uuid NOT NULL,
|
|
"subtotal_cents" integer NOT NULL,
|
|
"tax_cents" integer DEFAULT 0 NOT NULL,
|
|
"tip_cents" integer DEFAULT 0 NOT NULL,
|
|
"total_cents" integer NOT NULL,
|
|
"status" "invoice_status" DEFAULT 'draft' NOT NULL,
|
|
"payment_method" "payment_method",
|
|
"paid_at" timestamp,
|
|
"notes" text,
|
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
"updated_at" timestamp DEFAULT now() NOT NULL
|
|
);
|
|
--> statement-breakpoint
|
|
CREATE TABLE "invoice_line_items" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"invoice_id" uuid NOT NULL,
|
|
"description" text NOT NULL,
|
|
"quantity" integer DEFAULT 1 NOT NULL,
|
|
"unit_price_cents" integer NOT NULL,
|
|
"total_cents" integer NOT NULL,
|
|
"created_at" timestamp DEFAULT now() NOT NULL
|
|
);
|
|
--> statement-breakpoint
|
|
ALTER TABLE "invoices" ADD CONSTRAINT "invoices_appointment_id_appointments_id_fk" FOREIGN KEY ("appointment_id") REFERENCES "public"."appointments"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "invoices" ADD CONSTRAINT "invoices_client_id_clients_id_fk" FOREIGN KEY ("client_id") REFERENCES "public"."clients"("id") ON DELETE restrict ON UPDATE no action;--> statement-breakpoint
|
|
ALTER TABLE "invoice_line_items" ADD CONSTRAINT "invoice_line_items_invoice_id_invoices_id_fk" FOREIGN KEY ("invoice_id") REFERENCES "public"."invoices"("id") ON DELETE cascade ON UPDATE no action;
|