--- tags: [projeto, intranet, mensagens-agendadas, whatsapp, sessao, multi-tenant] date: 2026-04-28 --- # Mensagens Agendadas — Seleção de Sessão (Principal vs Financeiro) Adicionada possibilidade de escolher por qual número WhatsApp cada mensagem agendada vai sair (GotechBr Principal vs GotechBr Financeiro). Antes tudo saía pela financeiro hardcoded. ## O que mudou ### Banco ```sql ALTER TABLE mensagens_agendadas ADD COLUMN whatsapp_sessao ENUM('principal','financeiro') NOT NULL DEFAULT 'financeiro' AFTER telefone; ``` Default `financeiro` preserva comportamento das mensagens já existentes. ### Código - `app/Models/MensagemAgendadaModel.php` — `whatsapp_sessao` no `allowedFields` - `app/Controllers/MensagensAgendadas.php` - `setupTables()` cria a coluna se não existir (idempotente) - `save()` valida `whatsapp_sessao` em `[principal, financeiro]` e normaliza CRLF→LF - `enviarMensagemWhatsApp()` (botão "Enviar agora") respeita a sessão da mensagem - `app/Controllers/CronMensagensAgendadas.php` — resolve sessão **dentro do loop** (cache por tipo) - 3 views (form/index/show) — seletor visual + badges + bloco "Enviado a partir de" ### Resolução de sessão (preserva env override) ```php $sessionName = ($tipoSessao === 'financeiro') ? $sessionModel->resolveKey('financeiro', 'COBRANCA_WHATSAPP_SESSION') : $sessionModel->getInstanceKeyByTipo($tipoSessao); ``` **Por quê o `if`:** `.env` de produção tem `COBRANCA_WHATSAPP_SESSION` setado. O código antigo priorizava env sobre DB via `resolveKey()`. Para não quebrar esse override, mantive `resolveKey` só pro financeiro. Principal vai direto pro DB (não tem env equivalente). ## Bug que pegou de surpresa: dois controllers separados A primeira tentativa de fix corrigiu apenas `MensagensAgendadas::enviarMensagemWhatsApp` (usado pelo botão "Enviar agora"). **Não notei** que o CRON automático usa um controller **diferente**: `CronMensagensAgendadas::processar`. Resultado: entre o 1º e 2º deploy, mensagens marcadas como "Principal" continuaram saindo via Financeiro porque o cron-controller ainda tinha hardcoded: ```php $sessionName = $sessionModel->resolveKey('financeiro', 'COBRANCA_WHATSAPP_SESSION'); ``` **Lição:** sempre que tiver feature WhatsApp/notificação, conferir se existe um `Cron*.php` correspondente que duplica a lógica de envio. Os crons são endpoints separados (`cron/mensagens-agendadas/processar`) que rodam sem auth e tendem a copiar/colar trecho do controller principal. ## Bug bônus: CRLF → "espaço enorme em cima" no WhatsApp Textarea HTML envia quebras como `\r\n` (CRLF). WhatsApp renderiza `\r\n\r\n` como ~4 linhas em branco em vez de 2, criando aparência de "espaço enorme" entre parágrafos. ### Fix 1. No `save()`: `str_replace(["\r\n", "\r"], "\n", $request->getPost('mensagem'))` 2. UPDATE one-shot pra normalizar 17 mensagens já existentes: ```sql UPDATE mensagens_agendadas SET mensagem = REPLACE(REPLACE(mensagem, CHAR(13,10), CHAR(10)), CHAR(13), CHAR(10)) WHERE mensagem LIKE CONCAT('%', CHAR(13), '%'); ``` **Lição:** sempre normalizar entrada de textarea antes de mandar pra WhatsApp/SMS. Inclusive vale checar se outras features que enviam mensagem (cobrança, propostas, demandas) têm o mesmo problema. (TODO: auditar) ## Timeline da sessão | Hora | Evento | |------|--------| | ~17:30 | 1º deploy (form/views/Model/Controller principal) | | 17:45 | Cron rodou, msg 14 (Jabes) saiu via financeiro ❌ | | 17:48 | Cron, msg 16 (Mislene 1ª) financeiro ❌ | | 17:50 | Cron, msg 15 (Gisele) financeiro ❌ | | ~17:53 | 2º deploy (CronMensagensAgendadas + CRLF fix) | | 17:55 | Cron, msg 16 (Mislene 2ª) Principal ✅ | | 17:55+ | Pausados 17/18/19, normalizado CRLF no DB | ## Estado pendente - **Reenvio manual** para Jabes (14) e Gisele (15) via Principal — usuário avaliando - Mensagens 17 (Juliana), 18 (Kauã), 19 (Tiago) **pausadas** — precisa reativar pro cron disparar nos horários originais OU reenviar agora - Script `_reenviar_principal.php` escrito mas **não executado** (aguardando confirmação) ## Arquivos críticos - `app/Controllers/MensagensAgendadas.php:411` — `enviarMensagemWhatsApp()` - `app/Controllers/CronMensagensAgendadas.php:67` — loop com cache por tipo de sessão - `app/Models/WhatsappSessionModel.php:229` — `resolveKey()` (env tem prioridade sobre DB) ## Sessões relacionadas - [[sessao-2026-04-28]] — blog imagens + NFSe CEP (mesmo dia) - [[whatsapp-chat-modulo]] — instâncias Baileys