import test from 'node:test'; import assert from 'node:assert/strict'; import { openDb, createLeadInserter } from '../src/db.mjs'; import { createCampaign } from '../src/outreach/campaign-store.mjs'; import { generateCampaignQueue, listQueue, approveQueueRows, cancelQueueRows } from '../src/outreach/campaign-queue.mjs'; function inserirLead(db, overrides = {}) { const inserir = createLeadInserter(db); const dedup = overrides.dedup_key || `lead-${Math.random()}`; inserir({ dedup_key: dedup, empresa: 'Oficina Teste', legal_name: '', whatsapp: '5511999990001', ddd: '11', email: '', cidade: 'SP', uf: 'SP', segmento: 'oficinas_mecanicas', segmento_label: '', interesse: '', cnpj: '', cnae: '', endereco: '', website: '', pains_json: '[]', origem: 'teste', telefone_valido: 1, cnpj_valido: 0, empresa_valida: 1, score: 80, classificacao: 'bom', motivo_classificacao: '', score_qualidade: 80, score_comercial: 80, prioridade: 1, produto_principal: 'ERP', produtos_json: '[]', capture_run_id: null, captured_at: null, exported_at: null, ...overrides }); return db.prepare('SELECT * FROM leads WHERE dedup_key = ?').get(dedup); } function campanhaComVariantes(db, overrides = {}) { return createCampaign(db, { nome: 'ERP oficinas', produto: 'ERP', segmentos: ['oficinas_mecanicas'], variantes: [{ code: 'A', mensagem: 'Ola {empresa}' }], ...overrides }); } test('generateCampaignQueue cria linhas preview so para leads do produto/segmento certos', () => { const db = openDb(':memory:'); inserirLead(db, { dedup_key: 'l1', whatsapp: '5511999990001' }); inserirLead(db, { dedup_key: 'l2', segmento: 'outro_segmento', whatsapp: '5511999990002' }); const campanha = campanhaComVariantes(db); const resultado = generateCampaignQueue(db, campanha.id); assert.equal(resultado.candidatosEncontrados, 1); assert.equal(resultado.adicionadosNaFila, 1); const fila = listQueue(db, campanha.id); assert.equal(fila.length, 1); assert.equal(fila[0].status, 'preview'); assert.equal(fila[0].rendered_message, 'Ola Oficina Teste'); db.close(); }); test('generateCampaignQueue exclui lead com envio ja enviado para o mesmo produto (por lead_id)', () => { const db = openDb(':memory:'); const lead = inserirLead(db); db.prepare( `INSERT INTO outreach_sends (lead_id, produto, numero, mensagem_enviada, status) VALUES (?, 'ERP', ?, 'oi', 'enviado')` ).run(lead.id, lead.whatsapp); const campanha = campanhaComVariantes(db); const resultado = generateCampaignQueue(db, campanha.id); assert.equal(resultado.candidatosEncontrados, 0); db.close(); }); test('generateCampaignQueue exclui numero com envio manual ja enviado (sem lead_id) para o mesmo produto', () => { const db = openDb(':memory:'); inserirLead(db, { whatsapp: '5511999990009' }); db.prepare( `INSERT INTO outreach_sends (lead_id, produto, numero, mensagem_enviada, status, origem) VALUES (NULL, 'ERP', '5511999990009', 'oi', 'enviado', 'manual')` ).run(); const campanha = campanhaComVariantes(db); const resultado = generateCampaignQueue(db, campanha.id); assert.equal(resultado.candidatosEncontrados, 0); db.close(); }); test('generateCampaignQueue exclui numero em opt-out', () => { const db = openDb(':memory:'); inserirLead(db, { whatsapp: '5511999990001' }); db.prepare(`INSERT INTO outreach_opt_out (numero) VALUES ('5511999990001')`).run(); const campanha = campanhaComVariantes(db); const resultado = generateCampaignQueue(db, campanha.id); assert.equal(resultado.candidatosEncontrados, 0); db.close(); }); test('generateCampaignQueue nao duplica lead ja na fila (preview/approved/sent) de outra campanha do mesmo produto', () => { const db = openDb(':memory:'); inserirLead(db, { dedup_key: 'unico', whatsapp: '5511999990001' }); const campanha1 = campanhaComVariantes(db, { nome: 'Campanha 1' }); generateCampaignQueue(db, campanha1.id); const campanha2 = campanhaComVariantes(db, { nome: 'Campanha 2' }); const resultado = generateCampaignQueue(db, campanha2.id); assert.equal(resultado.candidatosEncontrados, 0); db.close(); }); test('generateCampaignQueue respeita o parametro quantidade', () => { const db = openDb(':memory:'); for (let i = 0; i < 5; i += 1) { inserirLead(db, { dedup_key: `lead-${i}`, whatsapp: `551199999000${i}` }); } const campanha = campanhaComVariantes(db); const resultado = generateCampaignQueue(db, campanha.id, { quantidade: 3 }); assert.equal(resultado.adicionadosNaFila, 3); db.close(); }); test('approveQueueRows so aprova linhas em preview da campanha certa', () => { const db = openDb(':memory:'); inserirLead(db, { whatsapp: '5511999990001' }); const campanha = campanhaComVariantes(db); generateCampaignQueue(db, campanha.id); const [linha] = listQueue(db, campanha.id); const total = approveQueueRows(db, campanha.id, [linha.id]); assert.equal(total, 1); assert.equal(listQueue(db, campanha.id, 'approved').length, 1); }); test('cancelQueueRows cancela e registra motivo', () => { const db = openDb(':memory:'); inserirLead(db, { whatsapp: '5511999990001' }); const campanha = campanhaComVariantes(db); generateCampaignQueue(db, campanha.id); const [linha] = listQueue(db, campanha.id); const total = cancelQueueRows(db, campanha.id, [linha.id], 'nao interessa'); assert.equal(total, 1); const cancelada = listQueue(db, campanha.id, 'cancelled')[0]; assert.equal(cancelada.cancel_reason, 'nao interessa'); }); test('approveQueueRows/cancelQueueRows com lista vazia nao lanca erro', () => { const db = openDb(':memory:'); const campanha = campanhaComVariantes(db); assert.equal(approveQueueRows(db, campanha.id, []), 0); assert.equal(cancelQueueRows(db, campanha.id, []), 0); db.close(); });