60 lines
2.0 KiB
SQL
60 lines
2.0 KiB
SQL
DO $$
|
|
BEGIN
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM users
|
|
WHERE billing_customer_id IS NOT NULL AND billing_customer_id <> ''
|
|
GROUP BY billing_customer_id
|
|
HAVING COUNT(*) > 1
|
|
) THEN
|
|
RAISE EXCEPTION 'duplicate users.billing_customer_id values require Stripe reconciliation before migration 017';
|
|
END IF;
|
|
|
|
IF EXISTS (
|
|
SELECT 1
|
|
FROM subscriptions
|
|
WHERE provider = 'stripe' AND status <> 'canceled'
|
|
GROUP BY user_id
|
|
HAVING COUNT(*) > 1
|
|
) THEN
|
|
RAISE EXCEPTION 'multiple open Stripe subscriptions per user require reconciliation before migration 017';
|
|
END IF;
|
|
END $$;
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_users_billing_customer_unique
|
|
ON users(billing_customer_id)
|
|
WHERE billing_customer_id IS NOT NULL AND billing_customer_id <> '';
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_subscriptions_user_open_stripe_unique
|
|
ON subscriptions(user_id)
|
|
WHERE provider = 'stripe' AND status <> 'canceled';
|
|
|
|
CREATE TABLE IF NOT EXISTS billing_checkout_sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
plan_id UUID NOT NULL REFERENCES plans(id),
|
|
stripe_customer_id VARCHAR(200),
|
|
stripe_session_id VARCHAR(200),
|
|
checkout_url TEXT,
|
|
status VARCHAR(20) NOT NULL DEFAULT 'pending',
|
|
expires_at TIMESTAMPTZ NOT NULL,
|
|
lease_owner UUID,
|
|
lease_until TIMESTAMPTZ,
|
|
error_message TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
completed_at TIMESTAMPTZ,
|
|
CONSTRAINT billing_checkout_sessions_status_check
|
|
CHECK (status IN ('pending', 'completed', 'expired', 'failed', 'canceled')),
|
|
CONSTRAINT billing_checkout_sessions_stripe_session_unique
|
|
UNIQUE (stripe_session_id)
|
|
);
|
|
|
|
CREATE UNIQUE INDEX IF NOT EXISTS idx_billing_checkout_sessions_user_pending
|
|
ON billing_checkout_sessions(user_id)
|
|
WHERE status = 'pending';
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_billing_checkout_sessions_expiry
|
|
ON billing_checkout_sessions(expires_at)
|
|
WHERE status = 'pending';
|