Files

124 lines
4.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use strict'
/**
* reativacaoClientes.js — WPP-09
*
* Job que roda periodicamente (padrão: 1× por dia às 10h)
* para re-engajar clientes que não fazem pedidos há N dias.
*
* Fluxo:
* 1. Lista clientes inativos (sem pedido nos últimos 60 dias)
* 2. Para cada um, envia mensagem via NewWhats
* 3. Registra envio na tabela wpp_reativacao_log
*
* Ativação: chamado em server.js via setInterval ou node-cron
*/
const { query, execute, queryOne } = require('../database/postgres')
const DIAS_INATIVO = 60 // dias sem pedido para considerar inativo
const BATCH_SIZE = 20 // máx clientes por execução
const INTERVALO_MS = 24 * 60 * 60 * 1000 // 24h
const JANELA_REATIVACAO = 30 // dias entre reativações do mesmo cliente
async function getConfig() {
try {
const rows = await query(`SELECT key, value FROM plugin_configs WHERE plugin_id = 'newwhats'`)
const cfg = {}
for (const r of rows) cfg[r.key] = r.value
return cfg
} catch { return {} }
}
async function enviarWhatsApp(motorUrl, integKey, phone, mensagem) {
if (!motorUrl || !integKey) return false
try {
const res = await fetch(`${motorUrl}/api/ext/v1/inbox/55${phone}/send`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'x-nw-key': integKey },
body: JSON.stringify({ text: mensagem }),
})
return res.ok
} catch { return false }
}
async function runReativacao() {
console.log('[reativacao] Iniciando job de reativação de clientes...')
const cfg = await getConfig()
if (!cfg.newwhats_url || !cfg.integration_key) {
console.warn('[reativacao] Motor não configurado — job pulado')
return
}
if (cfg.auto_reply_mode === 'off') {
console.log('[reativacao] auto_reply_mode=off — job pulado')
return
}
try {
// Lista clientes inativos que ainda não foram reativados recentemente
const clientes = await query(
`SELECT c.id AS cliente_id, c.nome, ct.numero AS telefone,
MAX(p.created_at) AS ultimo_pedido
FROM clientes c
JOIN cliente_telefones ct ON ct.cliente_id = c.id AND ct.aceita_whatsapp = true
LEFT JOIN pedidos p ON p.cliente_id = c.id
WHERE c.status = 'ativo'
AND c.id NOT IN (
SELECT cliente_id FROM wpp_reativacao_log
WHERE enviada_em > NOW() - ($1 || ' days')::INTERVAL
AND cliente_id IS NOT NULL
)
GROUP BY c.id, c.nome, ct.numero
HAVING MAX(p.created_at) < NOW() - ($2 || ' days')::INTERVAL
OR MAX(p.created_at) IS NULL
ORDER BY ultimo_pedido ASC NULLS FIRST
LIMIT $3`,
[JANELA_REATIVACAO, DIAS_INATIVO, BATCH_SIZE]
)
console.log(`[reativacao] ${clientes.length} clientes inativos encontrados`)
for (const cl of clientes) {
const nome = cl.nome?.split(' ')[0] || 'Cliente'
const telefone = cl.telefone.replace(/\D/g, '')
const mensagem = `Olá, *${nome}*! 👋\nFaz um tempo que não vemos você por aqui no *Alemão Conveniências*.\n\nTemos novidades e promoções esperando por você! Bora fazer um pedido? 😊\n\nDigite *OI* para ver nossas ofertas do dia.`
const enviado = await enviarWhatsApp(cfg.newwhats_url, cfg.integration_key, telefone, mensagem)
if (enviado) {
await execute(
`INSERT INTO wpp_reativacao_log (cliente_id, chat_id, mensagem) VALUES ($1,$2,$3)`,
[cl.cliente_id, `55${telefone}@s.whatsapp.net`, mensagem]
)
console.log(`[reativacao] ✅ ${nome} (${telefone})`)
} else {
console.warn(`[reativacao] ⚠ Falha ao enviar para ${telefone}`)
}
// Pausa entre envios para não sobrecarregar
await new Promise(r => setTimeout(r, 2000))
}
console.log('[reativacao] Job concluído')
} catch (err) {
console.error('[reativacao] Erro inesperado:', err.message)
}
}
/**
* Inicia o job com agendamento automático.
* @param {number} intervalMs — intervalo em ms (padrão 24h)
* @param {number} initialDelayMs — atraso inicial antes do primeiro disparo (padrão 2min)
*/
function startReativacaoJob(intervalMs = INTERVALO_MS, initialDelayMs = 2 * 60 * 1000) {
console.log(`[reativacao] Job agendado — intervalo: ${Math.round(intervalMs / 3600000)}h, delay inicial: ${initialDelayMs / 1000}s`)
setTimeout(() => {
runReativacao()
setInterval(runReativacao, intervalMs)
}, initialDelayMs)
}
module.exports = { startReativacaoJob, runReativacao }