-- RV/Boat renter insurance: mirror of the vendor insurance request flow. -- Adds insurance fields to rentals, a token-based request table, and the -- public lookup/submit RPCs used by the renter-facing submission page. alter table public.rv_boat_lot_rentals add column if not exists insurance_carrier text, add column if not exists insurance_policy_number text, add column if not exists insurance_expiration_date date, add column if not exists insurance_document_url text; create table if not exists public.rv_renter_insurance_requests ( id uuid primary key default gen_random_uuid(), rental_id uuid not null references public.rv_boat_lot_rentals(id) on delete cascade, token text not null default encode(gen_random_bytes(24), 'hex'), sent_to_email text, sent_at timestamptz default now(), submitted_at timestamptz, expires_at timestamptz default (now() + interval '30 days'), created_by uuid, created_at timestamptz default now() ); create index if not exists idx_rv_renter_ins_req_token on public.rv_renter_insurance_requests(token); create index if not exists idx_rv_renter_ins_req_rental on public.rv_renter_insurance_requests(rental_id); alter table public.rv_renter_insurance_requests enable row level security; drop policy if exists "Staff manage rv renter insurance requests" on public.rv_renter_insurance_requests; create policy "Staff manage rv renter insurance requests" on public.rv_renter_insurance_requests for all to authenticated using (has_role(auth.uid(), 'admin'::app_role) or has_role(auth.uid(), 'manager'::app_role) or has_role(auth.uid(), 'association_management'::app_role)) with check (has_role(auth.uid(), 'admin'::app_role) or has_role(auth.uid(), 'manager'::app_role) or has_role(auth.uid(), 'association_management'::app_role)); -- Public, token-scoped lookup (no direct table access needed by the renter). create or replace function public.lookup_rv_renter_insurance_request(p_token text) returns table(request_id uuid, rental_id uuid, renter_name text, expires_at timestamptz, submitted_at timestamptz) language sql stable security definer set search_path to 'public' as $$ select r.id, rn.id, rn.renter_name, r.expires_at, r.submitted_at from public.rv_renter_insurance_requests r join public.rv_boat_lot_rentals rn on rn.id = r.rental_id where r.token = p_token limit 1; $$; create or replace function public.submit_rv_renter_insurance( p_token text, p_carrier text, p_policy_number text, p_expiration_date date, p_document_url 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.rv_renter_insurance_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.rv_boat_lot_rentals set insurance_carrier = p_carrier, insurance_policy_number = p_policy_number, insurance_expiration_date = p_expiration_date, insurance_document_url = coalesce(p_document_url, insurance_document_url), updated_at = now() where id = v_request.rental_id; update public.rv_renter_insurance_requests set submitted_at = now() where id = v_request.id; return true; end; $$; grant execute on function public.lookup_rv_renter_insurance_request(text) to anon, authenticated; grant execute on function public.submit_rv_renter_insurance(text, text, text, date, text) to anon, authenticated;