From e409ba64ef1d50b0c27d5f5904a18353df03d80f Mon Sep 17 00:00:00 2001 From: Leonardo Date: Thu, 23 Apr 2026 09:25:03 -0300 Subject: [PATCH] =?UTF-8?q?Saldo=20baixo=20WhatsApp:=20trigger=20dispara?= =?UTF-8?q?=20notifica=C3=A7=C3=A3o=20ao=20cruzar=20threshold?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fecha o loop do Marco B — tenant não zera mais saldo sem aviso. Nova função fn_whatsapp_low_balance_notify + trigger BEFORE UPDATE em whatsapp_credits_balance: - Dispara quando NEW.balance < NEW.low_balance_threshold e NEW.low_balance_alerted_at IS NULL - Insere system_alert pros stakeholders do tenant (owner do canal WhatsApp ativo + clinic_admin + tenant_admin, deduplicado via UNION) - Deeplink direto pra /configuracoes/creditos-whatsapp - Seta NEW.low_balance_alerted_at = now() pra anti-spam Reset do anti-spam já existia: add_whatsapp_credits seta low_balance_alerted_at=NULL ao creditar (purchase/topup/refund). Assim o ciclo completo funciona: cai abaixo → alerta → compra recrédita → cai de novo futuramente → alerta de novo. Toast no frontend já é sticky vermelho pra type='system_alert' (commit anterior). Config de threshold já existia na UI em /configuracoes/creditos-whatsapp. Co-Authored-By: Claude Opus 4.7 (1M context) --- ...0423000004_whatsapp_low_balance_notify.sql | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 database-novo/migrations/20260423000004_whatsapp_low_balance_notify.sql diff --git a/database-novo/migrations/20260423000004_whatsapp_low_balance_notify.sql b/database-novo/migrations/20260423000004_whatsapp_low_balance_notify.sql new file mode 100644 index 0000000..8ea04e7 --- /dev/null +++ b/database-novo/migrations/20260423000004_whatsapp_low_balance_notify.sql @@ -0,0 +1,96 @@ +-- ========================================================================== +-- Agencia PSI — Migracao: Alerta de saldo baixo WhatsApp +-- ========================================================================== +-- Criado por: Leonardo Nohama +-- Data: 2026-04-23 · Sao Carlos/SP — Brasil +-- +-- Fecha o loop do Marco B: tenant compra creditos → usa → saldo zera sem +-- aviso → PIX recusado surpresa. Agora o tenant e admins recebem +-- notificacao quando saldo cai abaixo do threshold configurado. +-- +-- Modelo: +-- - whatsapp_credits_balance ja tem: +-- low_balance_threshold (default 20) +-- low_balance_alerted_at (anti-spam; reset via add_whatsapp_credits) +-- - Falta so o trigger que dispara a notificacao. +-- +-- Fluxo: +-- 1. UPDATE em whatsapp_credits_balance (via deduct/adjust) +-- 2. Trigger BEFORE UPDATE detecta balance < threshold E alerted_at IS NULL +-- 3. Insere system_alert pros stakeholders (owner do canal WhatsApp +-- ativo + clinic_admin + tenant_admin do tenant, deduplicado) +-- 4. Seta NEW.low_balance_alerted_at = now() pra nao realertar +-- 5. Reset do alerted_at acontece em add_whatsapp_credits / topup +-- (ja existe: "low_balance_alerted_at = NULL" na RPC) +-- ========================================================================== + +CREATE OR REPLACE FUNCTION public.fn_whatsapp_low_balance_notify() +RETURNS TRIGGER +LANGUAGE plpgsql +SECURITY DEFINER +SET search_path = public +AS $$ +DECLARE + v_detail TEXT; +BEGIN + -- So alerta na transicao (alerted_at NULL) E se esta abaixo do threshold + IF NEW.balance < NEW.low_balance_threshold + AND NEW.low_balance_alerted_at IS NULL THEN + + v_detail := format( + 'Saldo atual: %s credito(s). Alerta configurado em %s. ' + 'Compre mais na loja para nao interromper envios via WhatsApp Oficial.', + NEW.balance, + NEW.low_balance_threshold + ); + + -- Stakeholders: owner do canal WhatsApp ativo + admins ativos do tenant + INSERT INTO public.notifications + (owner_id, tenant_id, type, ref_id, ref_table, payload) + SELECT + u.user_id, + NEW.tenant_id, + 'system_alert', + NEW.tenant_id, + 'whatsapp_credits_balance', + jsonb_build_object( + 'title', 'Saldo de WhatsApp baixo', + 'detail', v_detail, + 'severity', 'warn', + 'deeplink', '/configuracoes/creditos-whatsapp' + ) + FROM ( + SELECT owner_id AS user_id + FROM public.notification_channels + WHERE tenant_id = NEW.tenant_id + AND channel = 'whatsapp' + AND is_active = true + AND deleted_at IS NULL + UNION + SELECT user_id + FROM public.tenant_members + WHERE tenant_id = NEW.tenant_id + AND role IN ('clinic_admin', 'tenant_admin') + AND status = 'active' + ) u + WHERE u.user_id IS NOT NULL; + + -- Anti-spam: so alerta de novo depois que add_whatsapp_credits + -- reseta alerted_at pra NULL (acontece em purchase/topup) + NEW.low_balance_alerted_at := now(); + END IF; + + RETURN NEW; +END; +$$; + +COMMENT ON FUNCTION public.fn_whatsapp_low_balance_notify() IS + 'Trigger BEFORE UPDATE em whatsapp_credits_balance. Dispara notificacao system_alert quando saldo cruza low_balance_threshold pra baixo. Anti-spam via low_balance_alerted_at (resetado pelo add_whatsapp_credits).'; + +DROP TRIGGER IF EXISTS trg_whatsapp_low_balance_notify + ON public.whatsapp_credits_balance; + +CREATE TRIGGER trg_whatsapp_low_balance_notify + BEFORE UPDATE ON public.whatsapp_credits_balance + FOR EACH ROW + EXECUTE FUNCTION public.fn_whatsapp_low_balance_notify();