Files
route-commerce/supabase/migrations/.archived/047_wholesale_registration.sql
T
Nora 0ac4beaaa8 fix: react-doctor errors → 0 errors, 1649 warnings (46/100)
- Add requireAuth() to admin-permissions.ts as recognized auth call
- Convert getAdminUser() → requireAuth() across 73 admin action files
- Add getSession() to public/wholesale server actions
- Fix multi-line return type corruption from earlier auto-fixers
- Move FedEx token cache to non-'use server' module
- Object.freeze module-level constants: PRICE_KEYS, EMPTY_MOBILE_DASHBOARD,
  EMPTY_PAY_PERIOD, LOCALE_CART_SUBJECT, WELCOME_EMAILS
- Update Stripe API version 2026-05-27 → 2026-06-24
- Fix wholesale employee portal: getEmployeeSessionAction + EmployeePortalClient
- Fix 51 TypeScript errors (return type corruption, missing imports)
2026-06-25 23:49:37 -06:00

201 lines
6.7 KiB
PL/PgSQL

-- Migration 047: Wholesale Registration + Pending Approval Status
-- Adds self-service registration RPC and 'pending_approval' account status.
-- Idempotent — uses CREATE OR REPLACE and IF NOT EXISTS.
BEGIN;
-- Add pending_approval to the account_status check constraint
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'wholesale_customers_account_status_check'
) THEN
ALTER TABLE public.wholesale_customers
ADD CONSTRAINT wholesale_customers_account_status_check
CHECK (account_status IN ('active', 'on_hold', 'disabled', 'pending_approval', 'rejected'));
ELSE
-- Drop and recreate the check constraint with the new value
ALTER TABLE public.wholesale_customers
DROP CONSTRAINT wholesale_customers_account_status_check;
ALTER TABLE public.wholesale_customers
ADD CONSTRAINT wholesale_customers_account_status_check
CHECK (account_status IN ('active', 'on_hold', 'disabled', 'pending_approval', 'rejected'));
END IF;
END $$;
-- Add rejected status to the check constraint (same pattern)
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint WHERE conname = 'wholesale_customers_account_status_check'
) THEN
ALTER TABLE public.wholesale_customers
ADD CONSTRAINT wholesale_customers_account_status_check
CHECK (account_status IN ('active', 'on_hold', 'disabled', 'pending_approval', 'rejected'));
END IF;
END $$;
-- ── Registration RPC ─────────────────────────────────────────────────────────
DROP FUNCTION IF EXISTS public.register_wholesale_customer(UUID, TEXT, TEXT, TEXT, TEXT);
CREATE OR REPLACE FUNCTION public.register_wholesale_customer(
p_brand_id UUID DEFAULT NULL,
p_company_name TEXT DEFAULT NULL,
p_contact_name TEXT DEFAULT NULL,
p_email TEXT DEFAULT NULL,
p_phone TEXT DEFAULT NULL
)
RETURNS JSONB
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
AS $$
DECLARE
v_id UUID;
v_req_app BOOLEAN := true;
BEGIN
-- Reject duplicate email for this brand
IF EXISTS (SELECT 1 FROM wholesale_customers WHERE brand_id = p_brand_id AND email = p_email) THEN
RETURN jsonb_build_object('success', false, 'error', 'An account with this email already exists.');
END IF;
-- Read require_approval setting for this brand
BEGIN
SELECT require_approval INTO v_req_app
FROM wholesale_settings
WHERE brand_id = p_brand_id;
EXCEPTION WHEN OTHERS THEN
v_req_app := true;
END;
INSERT INTO wholesale_customers (
brand_id, company_name, contact_name, email, phone,
account_status, role
) VALUES (
p_brand_id,
p_company_name,
p_contact_name,
p_email,
p_phone,
CASE WHEN COALESCE(v_req_app, true) THEN 'pending_approval' ELSE 'active' END,
'buyer'
)
RETURNING id INTO v_id;
RETURN jsonb_build_object(
'success', true,
'id', v_id,
'requires_approval', COALESCE(v_req_app, true)
);
END;
$$;
-- ── Customer lookup by user_id (for portal auth) ──────────────────────────────
DROP FUNCTION IF EXISTS public.get_wholesale_customer_by_user(UUID, UUID);
CREATE OR REPLACE FUNCTION public.get_wholesale_customer_by_user(
p_brand_id UUID DEFAULT NULL,
p_user_id UUID DEFAULT NULL
)
RETURNS JSONB
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
AS $$
BEGIN
-- If brand_id is a zero UUID (placeholder), search across all brands
IF p_brand_id = '00000000-0000-0000-0000-000000000000'::UUID THEN
RETURN (
SELECT jsonb_build_object(
'id', id,
'user_id', user_id,
'company_name', company_name,
'contact_name', contact_name,
'email', email,
'phone', phone,
'account_status', account_status,
'role', role,
'brand_id', brand_id
)
FROM wholesale_customers
WHERE user_id = p_user_id AND account_status = 'active'
LIMIT 1
);
END IF;
RETURN (
SELECT jsonb_build_object(
'id', id,
'user_id', user_id,
'company_name', company_name,
'contact_name', contact_name,
'email', email,
'phone', phone,
'account_status', account_status,
'role', role,
'brand_id', brand_id
)
FROM wholesale_customers
WHERE brand_id = p_brand_id AND user_id = p_user_id
);
END;
$$;
-- ── Pending registrations RPC (for admin approval queue) ──────────────────────
DROP FUNCTION IF EXISTS public.get_pending_wholesale_registrations(UUID);
CREATE OR REPLACE FUNCTION public.get_pending_wholesale_registrations(p_brand_id UUID DEFAULT NULL)
RETURNS JSONB
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
AS $$
DECLARE
v_result JSONB;
BEGIN
SELECT jsonb_agg(t ORDER BY t.created_at ASC) INTO v_result
FROM (
SELECT
id, company_name, contact_name, email, phone,
account_status, role, created_at, updated_at
FROM wholesale_customers
WHERE brand_id = p_brand_id
AND account_status IN ('pending_approval', 'rejected')
ORDER BY created_at ASC
) t;
RETURN COALESCE(v_result, '[]'::JSONB);
END;
$$;
-- ── Approve/reject registration RPC ───────────────────────────────────────────
DROP FUNCTION IF EXISTS public.approve_wholesale_registration(UUID, UUID, TEXT);
CREATE OR REPLACE FUNCTION public.approve_wholesale_registration(
p_registration_id UUID DEFAULT NULL,
p_brand_id UUID DEFAULT NULL,
p_action TEXT DEFAULT NULL
)
RETURNS JSONB
LANGUAGE plpgsql SECURITY DEFINER SET search_path = public
AS $$
BEGIN
IF p_action = 'approve' THEN
UPDATE wholesale_customers
SET account_status = 'active', updated_at = now()
WHERE id = p_registration_id AND brand_id = p_brand_id
AND account_status = 'pending_approval';
ELSIF p_action = 'reject' THEN
UPDATE wholesale_customers
SET account_status = 'rejected', updated_at = now()
WHERE id = p_registration_id AND brand_id = p_brand_id
AND account_status = 'pending_approval';
ELSE
RETURN jsonb_build_object('success', false, 'error', 'Invalid action.');
END IF;
RETURN jsonb_build_object('success', true);
END;
$$;
-- ── Upsert wholesale customer (updated to allow linking user_id) ──────────────
-- Update existing upsert to handle user_id linking
-- The existing upsert_wholesale_customer is already set up to use brand_id+user_id as the ON CONFLICT target.
-- This just adds a note that it can also be used to link an existing customer to a auth.users account.
COMMIT;
NOTIFY pgrst, 'reload schema';