Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> git-subtree-dir: gti-maquina-comercial git-subtree-mainline:93ca82979egit-subtree-split:b77484946f
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);
|
|
});
|