b8ea292ef1
=== 8.2 Botão "Lembrar paciente" na agenda ===
Edge nova send-session-reminder-manual:
- Recebe {event_id}, autoriza (member ativo do tenant), resolve template
lembrete_sessao (custom → default global), envia via Evolution, registra
outbound em conversation_messages + log em session_reminder_logs com
reminder_type='manual'.
- Reusa lógica do cron reminders (sanitização, fmt datas, render template)
mas sem janela/dedup — terapeuta pode redisparar quantas vezes quiser
(log usa UPSERT; UNIQUE (event_id, reminder_type) sobrescreve).
Migration 20260423000008 adiciona 'manual' ao CHECK constraint de
session_reminder_logs.reminder_type.
UI: botão verde pi-whatsapp no footer do AgendaEventDialog (só em edit
de sessão com paciente vinculado). Confirm dialog + toast + erros
amigáveis (no_phone, invalid_phone, no_active_channel, template_not_found,
forbidden, send_failed).
=== 8.3 Status sessão dispara mensagem ===
Migration 20260423000009 cria trigger AFTER UPDATE OF status em
agenda_eventos: quando status muda pra cancelado/remarcado/confirmado,
dispara edge send-session-status-notification via pg_net (não bloqueia
o UPDATE). Settings app.settings.supabase_url/service_role_key reusadas.
Edge nova send-session-status-notification:
- Body {event_id, old_status, new_status}
- STATUS_TEMPLATE_MAP: cancelado→cancelamento_sessao, remarcado→
remarcacao_sessao, confirmado→confirmacao_sessao.
- Respeita opt-out (conversation_optouts), canal ativo, template
existente (tenant-specific → global default). Skip silencioso em
caso de falta de config.
- Insere outbound em conversation_messages (sem log unique — múltiplas
mudanças de status geram múltiplas mensagens por design).
=== 8.4 Intake abandonado vira lead no CRM ===
Migration 20260423000010:
- Adiciona 'in_progress' e 'abandoned_lead' ao CHECK de
patient_intake_requests.status. Colunas last_progress_at e
lead_thread_key.
- RPC convert_abandoned_intake_to_lead(intake_id): cria mensagem
placeholder inbound no CRM do tenant (thread_key anon:{phone}) +
conversation_notes com resumo dos dados coletados + marca status.
Edge save-intake-progress:
- POST {token, nome_completo?, telefone?, email_principal?, ...}
- Whitelist de campos (ALLOWED_FIELDS) pra proteger contra POST
malicioso tentar setar status/owner/etc.
- Busca por token, set status='in_progress' se era 'new', atualiza
campos enviados + last_progress_at.
Edge convert-abandoned-intakes (cron):
- Body opcional {idle_minutes} (default 30).
- Varre patient_intake_requests status='in_progress' + last_progress_at
mais antigo que cutoff. Filtra só os com nome_completo OU telefone
(contato mínimo pra valer lead). Chama RPC pra cada um.
Hook no form público CadastroPacienteExterno:
- Watch em nome_completo, telefone, email_principal, onde_nos_conheceu
dispara scheduleProgressSave() com debounce 1.5s.
- savePartialProgress só chama a edge se tem nome OU telefone.
- Silent fail — autosave não é crítico.
Cron do convert-abandoned-intakes NÃO ativado automaticamente (igual
heartbeat/SLA). Template comentado não está na migration — admin
descomenta SELECT cron.schedule manualmente quando quiser ligar.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
3.0 KiB
PL/PgSQL
85 lines
3.0 KiB
PL/PgSQL
-- ==========================================================================
|
|
-- Agencia PSI — Migracao: Trigger agenda_eventos → notificacao WhatsApp (8.3)
|
|
-- ==========================================================================
|
|
-- Quando um agenda_evento muda de status (ex: agendado → cancelado), dispara
|
|
-- a edge send-session-status-notification que resolve template e envia
|
|
-- mensagem WhatsApp ao paciente.
|
|
--
|
|
-- Transicoes que disparam (controlado na propria edge via STATUS_TEMPLATE_MAP):
|
|
-- - cancelado → cancelamento_sessao
|
|
-- - remarcado → remarcacao_sessao
|
|
-- - confirmado → confirmacao_sessao
|
|
--
|
|
-- O trigger nao bloqueia o UPDATE (pg_net e assincrono). Se a edge falhar,
|
|
-- o evento ja foi salvo — so a notificacao sera perdida.
|
|
--
|
|
-- Pre-requisito: settings app.settings.supabase_url e app.settings.service_role_key
|
|
-- configuradas (mesmas usadas pelo cron do heartbeat e SLA).
|
|
-- ==========================================================================
|
|
|
|
CREATE OR REPLACE FUNCTION public.fn_notify_agenda_status_change()
|
|
RETURNS TRIGGER
|
|
LANGUAGE plpgsql
|
|
SECURITY DEFINER
|
|
SET search_path = public
|
|
AS $$
|
|
DECLARE
|
|
v_url TEXT;
|
|
v_key TEXT;
|
|
BEGIN
|
|
-- So dispara se status realmente mudou
|
|
IF NEW.status IS NOT DISTINCT FROM OLD.status THEN
|
|
RETURN NEW;
|
|
END IF;
|
|
|
|
-- So dispara pra status "interessantes". Outros sao silenciosamente ignorados
|
|
-- (a edge tambem tem essa logica, mas economizamos chamada HTTP aqui)
|
|
IF NEW.status NOT IN ('cancelado', 'remarcado', 'confirmado') THEN
|
|
RETURN NEW;
|
|
END IF;
|
|
|
|
-- Precisa de paciente vinculado (senao nao tem telefone)
|
|
IF NEW.patient_id IS NULL THEN
|
|
RETURN NEW;
|
|
END IF;
|
|
|
|
-- Busca settings
|
|
BEGIN
|
|
v_url := current_setting('app.settings.supabase_url', true);
|
|
v_key := current_setting('app.settings.service_role_key', true);
|
|
EXCEPTION WHEN OTHERS THEN
|
|
-- Settings nao configuradas — silencioso
|
|
RETURN NEW;
|
|
END;
|
|
|
|
IF v_url IS NULL OR v_key IS NULL THEN
|
|
RETURN NEW;
|
|
END IF;
|
|
|
|
-- Fire and forget (pg_net)
|
|
PERFORM net.http_post(
|
|
url := v_url || '/functions/v1/send-session-status-notification',
|
|
headers := jsonb_build_object(
|
|
'Authorization', 'Bearer ' || v_key,
|
|
'Content-Type', 'application/json'
|
|
),
|
|
body := jsonb_build_object(
|
|
'event_id', NEW.id,
|
|
'old_status', OLD.status,
|
|
'new_status', NEW.status
|
|
)
|
|
);
|
|
|
|
RETURN NEW;
|
|
END;
|
|
$$;
|
|
|
|
DROP TRIGGER IF EXISTS trg_agenda_status_notify ON public.agenda_eventos;
|
|
CREATE TRIGGER trg_agenda_status_notify
|
|
AFTER UPDATE OF status ON public.agenda_eventos
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION public.fn_notify_agenda_status_change();
|
|
|
|
COMMENT ON FUNCTION public.fn_notify_agenda_status_change() IS
|
|
'Dispara edge send-session-status-notification quando status de agenda_eventos muda. So pra status mapeados (cancelado/remarcado/confirmado). Nao bloqueia UPDATE.';
|