fix: estabilização do sistema de lembretes preventivos e correções de formatação

This commit is contained in:
Sidney 2026-05-08 09:07:31 -03:00
parent a667368ce3
commit db7b79fe87
2 changed files with 38 additions and 22 deletions

View File

@ -106,8 +106,13 @@
- **Estado Atual:** Pipeline 100% estabilizado no GitHub Actions usando `self-hosted` runner (Oracle ARM64 nativo). - **Estado Atual:** Pipeline 100% estabilizado no GitHub Actions usando `self-hosted` runner (Oracle ARM64 nativo).
- **Melhoria:** O build agora ocorre diretamente na arquitetura de destino, sem emulação QEMU, garantindo velocidade e estabilidade total. - **Melhoria:** O build agora ocorre diretamente na arquitetura de destino, sem emulação QEMU, garantindo velocidade e estabilidade total.
### 📢 Automação de Mensagens
- [x] **Estabilização de Lembretes:** Sistema de avisos preventivos e de inadimplência agora é 100% confiável, com tracking preciso de envios e suporte a múltiplos templates dinâmicos.
## 📋 Próximos Passos Pendentes ## 📋 Próximos Passos Pendentes
1. **Concluída a Arquitetura de Storage Local (MinIO):** Todo o sistema (Tanto portal quanto manager) agora utiliza `FormData` para envio físico de arquivos aos servidores, salvando apenas a `URL pública` no banco de dados. 1. **Módulo Financeiro SQL:** Iniciar a migração total do financeiro para PostgreSQL (padrão `notas_boletim`).
2. **Otimização de Build:** Re-explorar o cache do Docker ou considerar a remoção do suporte nativo ARM64 se não for estritamente necessário para o servidor final. 2. **Otimização de Build:** Re-explorar o cache do Docker.
3. **Financeiro:** Implementar visualização de extrato detalhado e integração com gateway de pagamento direto via cartão. 3. **Financeiro:** Implementar visualização de extrato detalhado.
**Nota Técnica:** O arquivo `server.js` deve ser mantido como espelho ou ignorado conforme orientação do usuário, com foco total no `server.selfhosted.js`.

View File

@ -562,7 +562,7 @@ async function sendEvolutionMessage(asaasPaymentId, eventType, paymentPayload =
.replace(/{nome_aluno}/g, aluno.name) .replace(/{nome_aluno}/g, aluno.name)
.replace(/{matricula}/g, aluno.enrollmentNumber || aluno.matricula || '—') .replace(/{matricula}/g, aluno.enrollmentNumber || aluno.matricula || '—')
.replace(/{valor}/g, parseFloat(fallbackValor).toFixed(2).replace('.', ',')) .replace(/{valor}/g, parseFloat(fallbackValor).toFixed(2).replace('.', ','))
.replace(/{vencimento}/g, formatCobrancaDate(typeof fallbackVencimento === 'string' ? fallbackVencimento : '')) .replace(/{vencimento}/g, formatCobrancaDate(typeof fallbackVencimento === 'string' ? fallbackVencimento : (fallbackVencimento instanceof Date ? fallbackVencimento.toISOString().split('T')[0] : '')))
.replace(/{link_boleto}/g, pdfUrl) .replace(/{link_boleto}/g, pdfUrl)
.replace(/{descricao}/g, descricao); .replace(/{descricao}/g, descricao);
@ -593,7 +593,7 @@ async function sendEvolutionMessage(asaasPaymentId, eventType, paymentPayload =
} }
} }
if ((isCreationEvent || isPaymentConfirmation || eventType === 'PAYMENT_UPDATED') && !base64Pdf && pdfUrl) { if ((isCreationEvent || isPaymentConfirmation || eventType === 'PAYMENT_UPDATED' || eventType === 'PAYMENT_UPCOMING') && !base64Pdf && pdfUrl) {
msgFinal += `\n\n📄 Acesse aqui sua cobrança:\n${pdfUrl}`; msgFinal += `\n\n📄 Acesse aqui sua cobrança:\n${pdfUrl}`;
} }
@ -613,10 +613,16 @@ async function sendEvolutionMessage(asaasPaymentId, eventType, paymentPayload =
const url = `${evoConfig.apiUrl.replace(/\/$/, '')}/message/${endpoint}/${evoConfig.instanceName}`; const url = `${evoConfig.apiUrl.replace(/\/$/, '')}/message/${endpoint}/${evoConfig.instanceName}`;
const sendResp = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'apikey': evoConfig.apiKey }, body: JSON.stringify(payload) }); const sendResp = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/json', 'apikey': evoConfig.apiKey }, body: JSON.stringify(payload) });
if (sendResp.ok) console.log(`[WhatsApp] ✅ Enviado para ${cleanPhone}`); if (sendResp.ok) {
else console.error(`[WhatsApp] ❌ Erro:`, sendResp.status); console.log(`[WhatsApp] ✅ Enviado para ${cleanPhone}`);
return true;
} else {
console.error(`[WhatsApp] ❌ Erro:`, sendResp.status);
return false;
}
} catch (error) { } catch (error) {
console.error('[WhatsApp] Erro interno:', error.message); console.error('[WhatsApp] Erro interno:', error.message);
return false;
} }
} }
@ -1133,15 +1139,17 @@ async function executarRotinaCobrancas(tipo = 'ambos') {
const jaEnviadoHoje = lastWarn && lastWarn.getTime() === hoje.getTime(); const jaEnviadoHoje = lastWarn && lastWarn.getTime() === hoje.getTime();
if (!jaEnviadoHoje && (diasDesdeUltimoAviso === null || diasDesdeUltimoAviso >= repeatEveryDays)) { if (!jaEnviadoHoje && (diasDesdeUltimoAviso === null || diasDesdeUltimoAviso >= repeatEveryDays)) {
await sendEvolutionMessage(cob.asaas_payment_id, 'PAYMENT_OVERDUE'); const sent = await sendEvolutionMessage(cob.asaas_payment_id, 'PAYMENT_OVERDUE');
const currentCount = parseInt(cob.overdue_warnings_count) || 0; if (sent) {
await pool.query( const currentCount = parseInt(cob.overdue_warnings_count) || 0;
'UPDATE alunos_cobrancas SET overdue_warnings_count = $1, last_overdue_warning_at = NOW() WHERE asaas_payment_id = $2', await pool.query(
[currentCount + 1, cob.asaas_payment_id] 'UPDATE alunos_cobrancas SET overdue_warnings_count = $1, last_overdue_warning_at = NOW() WHERE asaas_payment_id = $2',
); [currentCount + 1, cob.asaas_payment_id]
);
enviadasAtraso++; enviadasAtraso++;
}
} }
} }
} }
@ -1160,8 +1168,9 @@ async function executarRotinaCobrancas(tipo = 'ambos') {
vencimento.setHours(0,0,0,0); vencimento.setHours(0,0,0,0);
const diffDias = Math.ceil((vencimento.getTime() - hoje.getTime()) / (1000 * 60 * 60 * 24)); const diffDias = Math.ceil((vencimento.getTime() - hoje.getTime()) / (1000 * 60 * 60 * 24));
const sendOnDueDate = rules.sendOnDueDate !== false;
if (diffDias > 0 && diffDias <= sendDaysBefore) { if ((diffDias > 0 && diffDias <= sendDaysBefore) || (diffDias === 0 && sendOnDueDate)) {
const currentCount = parseInt(cob.pre_warnings_count) || 0; const currentCount = parseInt(cob.pre_warnings_count) || 0;
if (currentCount < maxPreWarnings) { if (currentCount < maxPreWarnings) {
@ -1169,13 +1178,15 @@ async function executarRotinaCobrancas(tipo = 'ambos') {
const jaEnviadoHoje = lastWarn && lastWarn.toDateString() === hoje.toDateString(); const jaEnviadoHoje = lastWarn && lastWarn.toDateString() === hoje.toDateString();
if (!jaEnviadoHoje) { if (!jaEnviadoHoje) {
await sendEvolutionMessage(cob.asaas_payment_id, 'PAYMENT_UPCOMING'); const sent = await sendEvolutionMessage(cob.asaas_payment_id, 'PAYMENT_UPCOMING');
await pool.query( if (sent) {
'UPDATE alunos_cobrancas SET pre_warnings_count = $1, last_pre_warning_at = NOW() WHERE asaas_payment_id = $2', await pool.query(
[currentCount + 1, cob.asaas_payment_id] 'UPDATE alunos_cobrancas SET pre_warnings_count = $1, last_pre_warning_at = NOW() WHERE asaas_payment_id = $2',
); [currentCount + 1, cob.asaas_payment_id]
enviadasAviso++; );
enviadasAviso++;
}
} }
} }
} }