chore: import maquina-comercial-pessoal history via subtree
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> git-subtree-dir: maquina-comercial-pessoal git-subtree-mainline:f5af038e19git-subtree-split:a9ef4d776d
This commit is contained in:
@@ -0,0 +1,161 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { openDb } from '../src/db.mjs';
|
||||
import {
|
||||
CAMPAIGN_DEFINITIONS,
|
||||
CAMPAIGN_PRODUCTS,
|
||||
CAMPAIGN_STAGES
|
||||
} from '../src/outreach/campaign-catalog.mjs';
|
||||
import {
|
||||
getCampaign,
|
||||
getLeadCommercialState,
|
||||
listCampaigns,
|
||||
seedCampaigns,
|
||||
setLeadCommercialStage
|
||||
} from '../src/outreach/campaign-store.mjs';
|
||||
|
||||
function insertLead(db) {
|
||||
db.prepare("INSERT INTO leads (dedup_key, empresa) VALUES ('campaign-test-lead', 'Empresa Teste')").run();
|
||||
return Number(db.prepare('SELECT id FROM leads').get().id);
|
||||
}
|
||||
|
||||
test('catalogo fixa produtos, etapas e os tres grupos de segmentos aprovados', () => {
|
||||
assert.deepEqual(CAMPAIGN_PRODUCTS, ['GTI Vendas', 'G-Delivery']);
|
||||
assert.deepEqual(CAMPAIGN_STAGES, [
|
||||
'fila_preparada',
|
||||
'aprovado_para_envio',
|
||||
'enviado',
|
||||
'respondeu',
|
||||
'interessado_gti_vendas',
|
||||
'interessado_g_delivery',
|
||||
'demonstracao_agendada',
|
||||
'teste_g_delivery_iniciado',
|
||||
'sem_interesse',
|
||||
'opt_out',
|
||||
'venda_fechada'
|
||||
]);
|
||||
assert.deepEqual(CAMPAIGN_DEFINITIONS.map(({ code, produto, segments }) => ({ code, produto, segments })), [
|
||||
{
|
||||
code: 'gdelivery-food',
|
||||
produto: 'G-Delivery',
|
||||
segments: ['hamburguerias', 'pizzarias', 'acaiterias', 'marmitarias', 'lanchonetes']
|
||||
},
|
||||
{
|
||||
code: 'gti-food',
|
||||
produto: 'GTI Vendas',
|
||||
segments: ['restaurantes', 'mercados_de_bairro', 'mercearias', 'minimercados', 'padarias', 'conveniencias']
|
||||
},
|
||||
{
|
||||
code: 'gti-retail',
|
||||
produto: 'GTI Vendas',
|
||||
segments: ['lojas_de_roupa', 'material_de_construcao', 'autopecas', 'oficinas_mecanicas']
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
test('seed cria tres campanhas e nove variantes usando seis textos unicos', () => {
|
||||
const db = openDb(':memory:');
|
||||
|
||||
seedCampaigns(db);
|
||||
seedCampaigns(db);
|
||||
|
||||
const campaigns = listCampaigns(db);
|
||||
assert.deepEqual(campaigns.map(({ code, produto }) => ({ code, produto })), [
|
||||
{ code: 'gdelivery-food', produto: 'G-Delivery' },
|
||||
{ code: 'gti-food', produto: 'GTI Vendas' },
|
||||
{ code: 'gti-retail', produto: 'GTI Vendas' }
|
||||
]);
|
||||
assert.equal(db.prepare('SELECT COUNT(*) total FROM outreach_campaign_variants').get().total, 9);
|
||||
assert.equal(db.prepare('SELECT COUNT(DISTINCT mensagem) total FROM outreach_campaign_variants').get().total, 6);
|
||||
assert.deepEqual(campaigns.map(({ variants }) => variants.map(({ code }) => code)), [
|
||||
['A', 'B', 'C'],
|
||||
['A', 'B', 'C'],
|
||||
['A', 'B', 'C']
|
||||
]);
|
||||
const gDeliveryMessages = {
|
||||
A: 'Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Queria entender como voces recebem os pedidos de delivery hoje: possuem um canal proprio ou dependem de aplicativos que cobram comissao? Se nao fizer sentido para sua empresa, e so me avisar que nao volto a entrar em contato.',
|
||||
B: 'Ola! Aqui e Gustavo, do Grupo GTI. Voces ja possuem um link proprio para receber pedidos, sem pagar comissao por venda a aplicativos? Se nao fizer sentido para sua empresa, e so me avisar que nao volto a entrar em contato.',
|
||||
C: 'Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Trabalho com uma solucao de pedidos online por canal proprio e queria primeiro entender como funciona o delivery de voces hoje. Se nao fizer sentido para sua empresa, e so me avisar que nao volto a entrar em contato.'
|
||||
};
|
||||
const gtiVendasMessages = {
|
||||
A: 'Ola, tudo bem? Sou Gustavo, representante comercial do Grupo GTI. Hoje voces controlam {foco_gestao} em um unico sistema? Se nao fizer sentido para sua empresa, e so me avisar que nao volto a entrar em contato.',
|
||||
B: 'Ola! Aqui e Gustavo, do Grupo GTI. Trabalhamos com gestao para empresas de Santo Antonio de Jesus e regiao. Como voces organizam hoje {foco_gestao}? Se nao fizer sentido para sua empresa, e so me avisar que nao volto a entrar em contato.',
|
||||
C: 'Ola, tudo bem? Sou Gustavo, do Grupo GTI. Ha mais de 7 anos atendemos empresas da regiao e ja temos mais de 100 clientes. Voces utilizam algum sistema para {foco_gestao}? Se nao fizer sentido para sua empresa, e so me avisar que nao volto a entrar em contato.'
|
||||
};
|
||||
assert.deepEqual(Object.fromEntries(campaigns[0].variants.map(({ code, mensagem }) => [code, mensagem])), gDeliveryMessages);
|
||||
assert.deepEqual(Object.fromEntries(campaigns[1].variants.map(({ code, mensagem }) => [code, mensagem])), gtiVendasMessages);
|
||||
assert.deepEqual(Object.fromEntries(campaigns[2].variants.map(({ code, mensagem }) => [code, mensagem])), gtiVendasMessages);
|
||||
db.close();
|
||||
});
|
||||
|
||||
test('seed completa ausencias sem sobrescrever controles editados pelo operador', () => {
|
||||
const db = openDb(':memory:');
|
||||
seedCampaigns(db);
|
||||
const campaign = listCampaigns(db)[0];
|
||||
db.prepare("UPDATE outreach_campaigns SET status = 'running', week_number = 3, approved_daily_limit = 15 WHERE id = ?")
|
||||
.run(campaign.id);
|
||||
db.prepare("DELETE FROM outreach_campaign_variants WHERE campaign_id = ? AND code = 'C'").run(campaign.id);
|
||||
|
||||
seedCampaigns(db);
|
||||
|
||||
const reloaded = getCampaign(db, campaign.id);
|
||||
assert.equal(reloaded.status, 'running');
|
||||
assert.equal(reloaded.week_number, 3);
|
||||
assert.equal(reloaded.approved_daily_limit, 15);
|
||||
assert.deepEqual(reloaded.variants.map(({ code }) => code), ['A', 'B', 'C']);
|
||||
assert.equal(getCampaign(db, 999999), null);
|
||||
db.close();
|
||||
});
|
||||
|
||||
test('seed recria campanha excluida e preserva controles das campanhas sobreviventes', () => {
|
||||
const db = openDb(':memory:');
|
||||
seedCampaigns(db);
|
||||
const removed = listCampaigns(db).find(({ code }) => code === 'gdelivery-food');
|
||||
const survivor = listCampaigns(db).find(({ code }) => code === 'gti-food');
|
||||
db.prepare("UPDATE outreach_campaigns SET status = 'running', week_number = 4, approved_daily_limit = 18 WHERE id = ?")
|
||||
.run(survivor.id);
|
||||
db.prepare('DELETE FROM outreach_campaigns WHERE id = ?').run(removed.id);
|
||||
|
||||
assert.equal(getCampaign(db, removed.id), null);
|
||||
assert.equal(db.prepare('SELECT COUNT(*) total FROM outreach_campaign_variants WHERE campaign_id = ?').get(removed.id).total, 0);
|
||||
seedCampaigns(db);
|
||||
|
||||
const restored = listCampaigns(db).find(({ code }) => code === 'gdelivery-food');
|
||||
const unchanged = getCampaign(db, survivor.id);
|
||||
assert.notEqual(restored.id, removed.id);
|
||||
assert.deepEqual(restored.variants.map(({ code }) => code), ['A', 'B', 'C']);
|
||||
assert.equal(unchanged.status, 'running');
|
||||
assert.equal(unchanged.week_number, 4);
|
||||
assert.equal(unchanged.approved_daily_limit, 18);
|
||||
assert.equal(db.prepare('SELECT COUNT(*) total FROM outreach_campaigns').get().total, 3);
|
||||
assert.equal(db.prepare('SELECT COUNT(*) total FROM outreach_campaign_variants').get().total, 9);
|
||||
db.close();
|
||||
});
|
||||
|
||||
test('mudanca de etapa atualiza estado comercial e registra historico', () => {
|
||||
const db = openDb(':memory:');
|
||||
seedCampaigns(db);
|
||||
const leadId = insertLead(db);
|
||||
const campaignId = listCampaigns(db)[0].id;
|
||||
|
||||
assert.equal(getLeadCommercialState(db, leadId), null);
|
||||
const state = setLeadCommercialStage(db, {
|
||||
leadId,
|
||||
campaignId,
|
||||
stage: 'respondeu',
|
||||
note: 'Resposta recebida no WhatsApp'
|
||||
});
|
||||
|
||||
assert.equal(state.lead_id, leadId);
|
||||
assert.equal(state.stage, 'respondeu');
|
||||
assert.deepEqual(db.prepare(
|
||||
'SELECT lead_id, campaign_id, stage, note FROM outreach_stage_events'
|
||||
).all().map((row) => ({ ...row })), [{
|
||||
lead_id: leadId,
|
||||
campaign_id: campaignId,
|
||||
stage: 'respondeu',
|
||||
note: 'Resposta recebida no WhatsApp'
|
||||
}]);
|
||||
assert.throws(() => setLeadCommercialStage(db, { leadId, stage: 'etapa_invalida' }), /etapa comercial invalida/i);
|
||||
db.close();
|
||||
});
|
||||
Reference in New Issue
Block a user