Saldo baixo WhatsApp: trigger dispara notificação ao cruzar threshold
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) <noreply@anthropic.com>
This commit is contained in:
@@ -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();
|
||||
Reference in New Issue
Block a user