Tracks the app that was already in place (capture, treatment, outreach, WhatsApp integration, server, frontend, tests, docs) so future feature work can branch and use isolated worktrees.
86 lines
3.0 KiB
JavaScript
86 lines
3.0 KiB
JavaScript
import { loadDotEnv } from '../src/env.mjs';
|
|
import { openDb, transaction } from '../src/db.mjs';
|
|
import { scoreQualidade, scoreComercial, scoreGeral, classificarScoreGeral } from '../src/scoring.mjs';
|
|
|
|
// Recalcula score_qualidade/score_comercial/score/classificacao/prioridade/
|
|
// produto_principal de TODOS os leads a partir dos dados ja gravados + da
|
|
// afinidade/produtos configurados por nicho (tabela segments). Nao e um
|
|
// script de uso unico: roda de novo (`npm run recalc-scores`) sempre que o
|
|
// catalogo de afinidade/produtos em prospeccao/config.json mudar.
|
|
//
|
|
// Roda com o servidor parado (evita concorrencia de escrita no WAL).
|
|
|
|
await loadDotEnv();
|
|
|
|
const BATCH_SIZE = 2000;
|
|
|
|
function produtoPrincipalDe(produtos) {
|
|
return produtos.length ? [...produtos].sort((a, b) => b.estrelas - a.estrelas)[0].nome : '';
|
|
}
|
|
|
|
async function main() {
|
|
const db = openDb();
|
|
|
|
const segmentos = new Map(
|
|
db.prepare('SELECT name, affinity, products_json FROM segments').all()
|
|
.map((row) => [row.name, { affinity: row.affinity, products: JSON.parse(row.products_json) }])
|
|
);
|
|
|
|
const update = db.prepare(`
|
|
UPDATE leads SET
|
|
score = ?, classificacao = ?, motivo_classificacao = ?,
|
|
score_qualidade = ?, score_comercial = ?, prioridade = ?,
|
|
produto_principal = ?, produtos_json = ?, updated_at = datetime('now')
|
|
WHERE id = ?
|
|
`);
|
|
|
|
const total = db.prepare('SELECT COUNT(*) AS t FROM leads').get().t;
|
|
const porPrioridade = { 1: 0, 2: 0, 3: 0, 4: 0 };
|
|
let processed = 0;
|
|
let lastId = 0;
|
|
|
|
const page = db.prepare('SELECT * FROM leads WHERE id > ? ORDER BY id LIMIT ?');
|
|
|
|
while (true) {
|
|
const rows = page.all(lastId, BATCH_SIZE);
|
|
if (!rows.length) break;
|
|
|
|
transaction(db, () => {
|
|
for (const lead of rows) {
|
|
const info = segmentos.get(lead.segmento) || { affinity: 'media', products: [] };
|
|
const qualidade = scoreQualidade({
|
|
whatsapp: lead.whatsapp, cnpj: lead.cnpj, empresa: lead.empresa,
|
|
cidade: lead.cidade, segmento: lead.segmento, cnae: lead.cnae, website: lead.website
|
|
});
|
|
const comercial = scoreComercial({
|
|
whatsapp: lead.whatsapp, cnpj: lead.cnpj, website: lead.website,
|
|
email: lead.email, affinity: info.affinity
|
|
});
|
|
const geral = scoreGeral(qualidade.score, comercial);
|
|
const tier = classificarScoreGeral(geral);
|
|
const produtoPrincipal = produtoPrincipalDe(info.products);
|
|
|
|
update.run(
|
|
geral, tier.id, `score geral ${geral} (qualidade ${qualidade.score}, comercial ${comercial})`,
|
|
qualidade.score, comercial, tier.prioridade,
|
|
produtoPrincipal, JSON.stringify(info.products),
|
|
lead.id
|
|
);
|
|
porPrioridade[tier.prioridade] += 1;
|
|
}
|
|
});
|
|
|
|
processed += rows.length;
|
|
lastId = rows[rows.length - 1].id;
|
|
console.log(`${processed}/${total} leads recalculados...`);
|
|
}
|
|
|
|
console.log('Concluido. Distribuicao por prioridade:', porPrioridade);
|
|
db.close();
|
|
}
|
|
|
|
main().catch((error) => {
|
|
console.error('Erro no recalculo de scores:', error);
|
|
process.exit(1);
|
|
});
|