-- ============================================================================= -- MC Cars - Booking flow enhancements: weekend pricing, daily KM limits, -- lead attachments, customer attachments, email-based customer upsert. -- Idempotent. -- ============================================================================= -- ----------------------------------------------------------------------------- -- 1. Add weekend_price_eur and max_daily_km to vehicles -- ----------------------------------------------------------------------------- alter table public.vehicles add column if not exists weekend_price_eur integer not null default 0; alter table public.vehicles add column if not exists max_daily_km integer not null default 0; -- Backfill existing vehicles with sensible defaults (weekend = daily * 1.2) update public.vehicles set weekend_price_eur = ceil(daily_price_eur * 1.2), max_daily_km = 150 where weekend_price_eur = 0; -- ----------------------------------------------------------------------------- -- 2. Lead attachments: documents uploaded during booking flow -- ----------------------------------------------------------------------------- create table if not exists public.lead_attachments ( id uuid primary key default gen_random_uuid(), lead_id uuid not null references public.leads(id) on delete cascade, bucket text not null default 'customer-documents', file_path text not null, file_name text not null default '', mime_type text not null default 'application/octet-stream', kind text not null default 'other' check (kind in ('id_document', 'income_proof', 'other')), created_at timestamptz not null default now() ); create index if not exists lead_attachments_lead_idx on public.lead_attachments (lead_id); alter table public.lead_attachments enable row level security; drop policy if exists "lead_attach_anon_insert" on public.lead_attachments; drop policy if exists "lead_attach_admin_all" on public.lead_attachments; -- Anon can insert (they upload during booking) create policy "lead_attach_anon_insert" on public.lead_attachments for insert to anon with check (true); -- Authenticated admins can do everything create policy "lead_attach_admin_all" on public.lead_attachments for all to authenticated using (true) with check (true); grant insert on public.lead_attachments to anon; grant all on public.lead_attachments to authenticated; grant all on public.lead_attachments to service_role; -- ----------------------------------------------------------------------------- -- 3. Customer attachments: transferred from leads on qualification -- ----------------------------------------------------------------------------- create table if not exists public.customer_attachments ( id uuid primary key default gen_random_uuid(), customer_id uuid not null references public.customers(id) on delete cascade, lead_id uuid references public.leads(id) on delete set null, bucket text not null default 'customer-documents', file_path text not null, file_name text not null default '', mime_type text not null default 'application/octet-stream', kind text not null default 'other' check (kind in ('id_document', 'income_proof', 'other')), created_at timestamptz not null default now() ); create index if not exists customer_attachments_cust_idx on public.customer_attachments (customer_id); alter table public.customer_attachments enable row level security; drop policy if exists "cust_attach_admin_all" on public.customer_attachments; create policy "cust_attach_admin_all" on public.customer_attachments for all to authenticated using (true) with check (true); grant all on public.customer_attachments to authenticated; grant all on public.customer_attachments to service_role; -- ----------------------------------------------------------------------------- -- 4. Allow multiple leads per customer: drop UNIQUE on lead_id, add email index -- ----------------------------------------------------------------------------- -- Drop the unique index on customers.lead_id so multiple leads can map to one customer drop index if exists customers_lead_unique; -- Create unique index on email for upsert create unique index if not exists customers_email_unique on public.customers (lower(email)); -- ----------------------------------------------------------------------------- -- 5. Replace qualify_lead() with email-based upsert + attachment transfer -- ----------------------------------------------------------------------------- create or replace function public.qualify_lead(p_lead_id uuid, p_notes text default '') returns public.customers language plpgsql security invoker as $$ declare v_lead public.leads; v_customer public.customers; v_user uuid := auth.uid(); begin -- Lock the lead row select * into v_lead from public.leads where id = p_lead_id for update; if not found then raise exception 'lead % not found', p_lead_id; end if; -- If already qualified, just return the associated customer if v_lead.status = 'qualified' then select * into v_customer from public.customers where lead_id = v_lead.id limit 1; if not found then select * into v_customer from public.customers where lower(email) = lower(v_lead.email) limit 1; end if; return v_customer; end if; -- Mark lead as qualified update public.leads set status = 'qualified', is_active = false, qualified_at = now(), qualified_by = v_user, admin_notes = coalesce(nullif(p_notes, ''), admin_notes) where id = v_lead.id; -- Upsert customer by email insert into public.customers (lead_id, name, email, phone, notes, created_by) values (v_lead.id, v_lead.name, v_lead.email, v_lead.phone, coalesce(p_notes,''), v_user) on conflict ((lower(email))) do update set name = excluded.name, phone = excluded.phone, notes = case when excluded.notes <> '' then excluded.notes else public.customers.notes end, updated_at = now() returning * into v_customer; -- Transfer lead attachments to customer insert into public.customer_attachments (customer_id, lead_id, bucket, file_path, file_name, mime_type, kind, created_at) select v_customer.id, la.lead_id, la.bucket, la.file_path, la.file_name, la.mime_type, la.kind, la.created_at from public.lead_attachments la where la.lead_id = v_lead.id and not exists ( select 1 from public.customer_attachments ca where ca.customer_id = v_customer.id and ca.file_path = la.file_path ); return v_customer; end; $$; revoke all on function public.qualify_lead(uuid, text) from public; grant execute on function public.qualify_lead(uuid, text) to authenticated;