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,85 @@
|
||||
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);
|
||||
});
|
||||
Reference in New Issue
Block a user