-- 003_discount_codes.sql -- Discount and referral code system. -- Supports percentage and flat discounts, usage limits, expiration, -- referral partner tracking, and per-service or global application. BEGIN; -- Discount / referral codes CREATE TABLE IF NOT EXISTS discount_codes ( id SERIAL PRIMARY KEY, code TEXT NOT NULL UNIQUE, -- e.g. 'SAVE20', 'PARTNER-ACME', 'REDDIT10' description TEXT, -- internal note -- Discount type: 'percent' or 'flat' discount_type TEXT NOT NULL CHECK (discount_type IN ('percent', 'flat')), discount_value INTEGER NOT NULL, -- percent (0-100) or flat amount in cents -- e.g. percent=20 means 20% off service fee; flat=10000 means $100 off total -- Scope: which services does this code apply to? -- NULL = all services; otherwise comma-separated slugs applies_to TEXT DEFAULT NULL, -- NULL=all, or 'formation,llc,corporation' -- Referral partner info (for payout tracking) referral_partner TEXT, -- partner name or ID referral_email TEXT, -- partner payout email referral_pct INTEGER DEFAULT 0, -- % of service fee paid to partner (0-100) -- Limits max_uses INTEGER DEFAULT NULL, -- NULL = unlimited max_uses_per_email INTEGER DEFAULT 1, -- per customer email current_uses INTEGER DEFAULT 0, -- Validity active BOOLEAN DEFAULT TRUE, starts_at TIMESTAMPTZ DEFAULT now(), expires_at TIMESTAMPTZ DEFAULT NULL, -- NULL = never expires -- Metadata created_at TIMESTAMPTZ DEFAULT now(), updated_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_discount_codes_code ON discount_codes(code); CREATE INDEX IF NOT EXISTS idx_discount_codes_partner ON discount_codes(referral_partner); -- Usage log: track every time a code is used CREATE TABLE IF NOT EXISTS discount_usage ( id SERIAL PRIMARY KEY, discount_code_id INTEGER NOT NULL REFERENCES discount_codes(id), code TEXT NOT NULL, order_type TEXT NOT NULL, -- 'formation', 'service', 'quote' order_id INTEGER, -- FK to formation_orders.id or orders.id customer_email TEXT NOT NULL, discount_amount INTEGER NOT NULL, -- actual discount applied in cents referral_payout INTEGER DEFAULT 0, -- amount owed to referral partner in cents ip_address TEXT, created_at TIMESTAMPTZ DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_discount_usage_code ON discount_usage(code); CREATE INDEX IF NOT EXISTS idx_discount_usage_email ON discount_usage(customer_email); CREATE INDEX IF NOT EXISTS idx_discount_usage_partner ON discount_usage(discount_code_id); -- Seed some example codes INSERT INTO discount_codes (code, description, discount_type, discount_value, applies_to, max_uses, active) VALUES ('LAUNCH25', 'Launch promotion — 25% off service fee', 'percent', 25, NULL, 100, TRUE), ('FIRST50', 'First-time customer — $50 off', 'flat', 5000, NULL, NULL, TRUE), ('FORMATION100', '$100 off business formation', 'flat', 10000, 'formation', NULL, TRUE), ('REDDIT10', 'Reddit community — 10% off', 'percent', 10, NULL, NULL, TRUE) ON CONFLICT (code) DO NOTHING; -- Example referral partner code INSERT INTO discount_codes (code, description, discount_type, discount_value, referral_partner, referral_email, referral_pct, max_uses, active) VALUES ('REF-EXAMPLE', 'Example referral partner', 'percent', 15, 'Example CPA Firm', 'partner@example.com', 20, NULL, TRUE) ON CONFLICT (code) DO NOTHING; COMMIT;