Commit inicial: GTI Maquina Comercial
App local (Node + SQLite) para captura, tratamento e exportacao de leads comerciais, com dashboard de gestao, login/usuarios e integracao Z-PRO. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import path from 'node:path';
|
||||
import { loadDotEnv, paths } from '../env.mjs';
|
||||
import { openDb, transaction } from '../db.mjs';
|
||||
import { createJobIO } from '../jobs/protocol.mjs';
|
||||
import { exportExcel } from './excel.mjs';
|
||||
import { exportOportunidades, exportBulkDataInput } from './zpro.mjs';
|
||||
|
||||
// Processo filho de exportacao: gera os arquivos do tipo pedido e, ao final,
|
||||
// numa unica transacao, registra os leads exportados (export_leads) e marca
|
||||
// exported_at (para o filtro "ainda nao exportado" excluir esses leads).
|
||||
|
||||
await loadDotEnv();
|
||||
|
||||
const args = new Map(
|
||||
process.argv.slice(2).map((arg) => {
|
||||
const [key, value = 'true'] = arg.replace(/^--/, '').split('=');
|
||||
return [key, value];
|
||||
})
|
||||
);
|
||||
|
||||
const io = createJobIO();
|
||||
|
||||
const GENERATORS = {
|
||||
excel: exportExcel,
|
||||
'zpro-oportunidades': exportOportunidades,
|
||||
'zpro-bulk': exportBulkDataInput
|
||||
};
|
||||
|
||||
async function main() {
|
||||
const exportId = Number(args.get('export-id'));
|
||||
if (!exportId) throw new Error('export-job: --export-id obrigatorio');
|
||||
|
||||
const db = openDb();
|
||||
const row = db.prepare('SELECT * FROM exports WHERE id = ?').get(exportId);
|
||||
if (!row) throw new Error(`export #${exportId} nao encontrado`);
|
||||
|
||||
const generator = GENERATORS[row.tipo];
|
||||
if (!generator) throw new Error(`tipo de exportacao desconhecido: ${row.tipo}`);
|
||||
|
||||
const filtro = JSON.parse(row.filtro_json || '{}');
|
||||
const params = JSON.parse(row.params_json || '{}');
|
||||
|
||||
db.prepare("UPDATE exports SET status = 'running' WHERE id = ?").run(exportId);
|
||||
io.emit({ phase: row.tipo, message: 'gerando arquivos...' });
|
||||
|
||||
const dir = path.join(paths.exports, `export-${exportId}`);
|
||||
const baseName = params.baseName || `leads-${row.tipo}`;
|
||||
const leadIds = [];
|
||||
|
||||
try {
|
||||
const result = await generator({
|
||||
db,
|
||||
filtro,
|
||||
params,
|
||||
dir,
|
||||
baseName,
|
||||
collectIds: leadIds,
|
||||
onProgress: (p) => io.emit({ phase: row.tipo, ...p })
|
||||
});
|
||||
|
||||
const marcar = params.marcarExportado !== false;
|
||||
io.emit({ phase: row.tipo, message: `registrando ${leadIds.length} leads exportados...` });
|
||||
|
||||
transaction(db, () => {
|
||||
const insertLink = db.prepare('INSERT OR IGNORE INTO export_leads (export_id, lead_id) VALUES (?, ?)');
|
||||
const mark = marcar
|
||||
? db.prepare("UPDATE leads SET exported_at = COALESCE(exported_at, datetime('now')), updated_at = datetime('now') WHERE id = ?")
|
||||
: null;
|
||||
|
||||
for (const leadId of leadIds) {
|
||||
insertLink.run(exportId, leadId);
|
||||
if (mark) mark.run(leadId);
|
||||
}
|
||||
|
||||
db.prepare(
|
||||
"UPDATE exports SET status = 'done', total_leads = ?, arquivos_json = ?, finished_at = datetime('now') WHERE id = ?"
|
||||
).run(result.total, JSON.stringify(result.files), exportId);
|
||||
});
|
||||
|
||||
io.done({ total: result.total, arquivos: result.files });
|
||||
} catch (error) {
|
||||
db.prepare("UPDATE exports SET status = 'error', error = ?, finished_at = datetime('now') WHERE id = ?")
|
||||
.run(String(error.message || error), exportId);
|
||||
throw error;
|
||||
} finally {
|
||||
db.close();
|
||||
}
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
io.fail(error);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user