Files
COMERCIAL-GTI/src/export/export-job.mjs
T
DESKTOP-F2O4A80\UserandClaude b8d10b210c 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>
2026-07-12 14:22:21 -03:00

94 lines
3.0 KiB
JavaScript

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);
});