-- Add vendor profile fields ALTER TABLE public.vendors ADD COLUMN IF NOT EXISTS remittance_address text, ADD COLUMN IF NOT EXISTS w9_document_url text, ADD COLUMN IF NOT EXISTS ach_bank_name text, ADD COLUMN IF NOT EXISTS ach_account_holder text, ADD COLUMN IF NOT EXISTS ach_routing_number text, ADD COLUMN IF NOT EXISTS ach_account_number text, ADD COLUMN IF NOT EXISTS ach_account_type text, ADD COLUMN IF NOT EXISTS profile_last_submitted_at timestamptz; -- Vendor profile requests table CREATE TABLE IF NOT EXISTS public.vendor_profile_requests ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), vendor_id uuid NOT NULL REFERENCES public.vendors(id) ON DELETE CASCADE, token text NOT NULL UNIQUE DEFAULT encode(extensions.gen_random_bytes(24), 'hex'), sent_to_email text, sent_at timestamptz NOT NULL DEFAULT now(), submitted_at timestamptz, expires_at timestamptz NOT NULL DEFAULT (now() + interval '30 days'), created_by uuid, created_at timestamptz NOT NULL DEFAULT now() ); CREATE INDEX IF NOT EXISTS idx_vendor_profile_requests_token ON public.vendor_profile_requests(token); CREATE INDEX IF NOT EXISTS idx_vendor_profile_requests_vendor ON public.vendor_profile_requests(vendor_id); ALTER TABLE public.vendor_profile_requests ENABLE ROW LEVEL SECURITY; CREATE POLICY "Staff manage vendor profile requests" ON public.vendor_profile_requests FOR ALL TO authenticated USING (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)) WITH CHECK (has_role(auth.uid(), 'admin'::app_role) OR has_role(auth.uid(), 'manager'::app_role)); -- Lookup RPC (public, by token) CREATE OR REPLACE FUNCTION public.lookup_vendor_profile_request(p_token text) RETURNS TABLE(request_id uuid, vendor_id uuid, vendor_name text, vendor_email text, expires_at timestamptz, submitted_at timestamptz) LANGUAGE sql STABLE SECURITY DEFINER SET search_path TO 'public' AS $$ SELECT r.id, v.id, v.name, v.email, r.expires_at, r.submitted_at FROM public.vendor_profile_requests r JOIN public.vendors v ON v.id = r.vendor_id WHERE r.token = p_token LIMIT 1; $$; -- Submit RPC (public, by token) CREATE OR REPLACE FUNCTION public.submit_vendor_profile( p_token text, p_remittance_address text, p_tax_id text, p_is_1099_eligible boolean, p_w9_document_url text DEFAULT NULL, p_insurance_carrier text DEFAULT NULL, p_insurance_policy_number text DEFAULT NULL, p_insurance_expiration_date date DEFAULT NULL, p_insurance_document_url text DEFAULT NULL, p_ach_bank_name text DEFAULT NULL, p_ach_account_holder text DEFAULT NULL, p_ach_routing_number text DEFAULT NULL, p_ach_account_number text DEFAULT NULL, p_ach_account_type text DEFAULT NULL ) RETURNS boolean LANGUAGE plpgsql SECURITY DEFINER SET search_path TO 'public' AS $$ DECLARE v_request RECORD; BEGIN SELECT * INTO v_request FROM public.vendor_profile_requests WHERE token = p_token AND expires_at > now() AND submitted_at IS NULL LIMIT 1; IF v_request IS NULL THEN RETURN FALSE; END IF; UPDATE public.vendors SET remittance_address = COALESCE(NULLIF(p_remittance_address, ''), remittance_address), tax_id = COALESCE(NULLIF(p_tax_id, ''), tax_id), is_1099_eligible = COALESCE(p_is_1099_eligible, is_1099_eligible), w9_document_url = COALESCE(p_w9_document_url, w9_document_url), insurance_carrier = COALESCE(NULLIF(p_insurance_carrier, ''), insurance_carrier), insurance_policy_number = COALESCE(NULLIF(p_insurance_policy_number, ''), insurance_policy_number), insurance_expiration_date = COALESCE(p_insurance_expiration_date, insurance_expiration_date), insurance_document_url = COALESCE(p_insurance_document_url, insurance_document_url), ach_bank_name = COALESCE(NULLIF(p_ach_bank_name, ''), ach_bank_name), ach_account_holder = COALESCE(NULLIF(p_ach_account_holder, ''), ach_account_holder), ach_routing_number = COALESCE(NULLIF(p_ach_routing_number, ''), ach_routing_number), ach_account_number = COALESCE(NULLIF(p_ach_account_number, ''), ach_account_number), ach_account_type = COALESCE(NULLIF(p_ach_account_type, ''), ach_account_type), profile_last_submitted_at = now(), updated_at = now() WHERE id = v_request.vendor_id; UPDATE public.vendor_profile_requests SET submitted_at = now() WHERE id = v_request.id; RETURN TRUE; END; $$; -- Allow anonymous to call the RPCs (they validate token internally) GRANT EXECUTE ON FUNCTION public.lookup_vendor_profile_request(text) TO anon, authenticated; GRANT EXECUTE ON FUNCTION public.submit_vendor_profile(text, text, text, boolean, text, text, text, date, text, text, text, text, text, text) TO anon, authenticated;