backfillErpProtocoloTodos.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. // Re-sincroniza TODOS os atendimentos já salvos no oráculo (não só SUP, abertos e
  2. // fechados) contra /protocolos/:id/mensagens do ifbot, atualizando ErpProtocolo/
  3. // ErpVinculoConfirmadoEm/IdClienteIxc quando o vínculo existir. Ao final, grava em
  4. // scripts/logs/ a lista dos atendimentos que GANHARAM ErpProtocolo novo (não tinham
  5. // antes) — essa lista alimenta scripts/reavaliarNovosVinculosErp.js.
  6. //
  7. // Uso: node scripts/backfillErpProtocoloTodos.js [--setor SUP] [--limite N]
  8. import fs from "node:fs";
  9. import path from "node:path";
  10. import { fileURLToPath } from "node:url";
  11. import { config } from "../src/config/index.js";
  12. import { Atendimento } from "../src/models/Atendimento.model.js";
  13. import { importarProtocolo } from "../src/services/atendimentosService.js";
  14. const __dirname = path.dirname(fileURLToPath(import.meta.url));
  15. const setorIdx = process.argv.indexOf("--setor");
  16. const SETOR = setorIdx > -1 ? process.argv[setorIdx + 1] : null;
  17. const limiteIdx = process.argv.indexOf("--limite");
  18. const LIMITE = limiteIdx > -1 ? Number(process.argv[limiteIdx + 1]) : null;
  19. const CONCORRENCIA = 4;
  20. async function main() {
  21. let query = Atendimento.query()
  22. .withGraphFetched("cliente")
  23. .orderBy("Abertura", "desc");
  24. if (SETOR) query = query.where("Setor", SETOR);
  25. if (LIMITE) query = query.limit(LIMITE);
  26. const atendimentos = await query;
  27. const total = atendimentos.length;
  28. console.log(`[backfill-erp-todos] iniciando: ${total} atendimentos${SETOR ? ` (setor ${SETOR})` : " (todos os setores)"}`);
  29. const baseUrl = config.ifbot.baseUrl.replace(/\/+$/, "");
  30. let processados = 0;
  31. let comVinculo = 0;
  32. let erros = 0;
  33. const novosVinculos = [];
  34. const t0 = Date.now();
  35. async function processar(a) {
  36. const erpAntes = a.cliente?.ErpProtocolo ?? null;
  37. try {
  38. const item = {
  39. Id: a.Id,
  40. Codigo: a.Codigo,
  41. Abertura: a.Abertura,
  42. Cliente: { Id: a.cliente?.Id, Nome: a.cliente?.Nome, Telefone: a.cliente?.Telefone }
  43. };
  44. await importarProtocolo(item, baseUrl);
  45. const atualizado = await Atendimento.query()
  46. .findById(a.Id)
  47. .withGraphFetched("cliente(soVinculo)")
  48. .modifiers({ soVinculo: (q) => q.select("ErpProtocolo", "ErpVinculoConfirmadoEm", "IdClienteIxc") });
  49. const erpDepois = atualizado?.cliente?.ErpProtocolo ?? null;
  50. if (erpDepois) {
  51. comVinculo += 1;
  52. if (!erpAntes) {
  53. novosVinculos.push({
  54. Id: a.Id,
  55. Codigo: a.Codigo,
  56. Setor: a.Setor,
  57. ErpProtocolo: erpDepois,
  58. IdClienteIxc: atualizado.cliente.IdClienteIxc ?? null
  59. });
  60. }
  61. }
  62. } catch (err) {
  63. erros += 1;
  64. console.warn(`[backfill-erp-todos] erro em ${a.Codigo}: ${err.message}`);
  65. } finally {
  66. processados += 1;
  67. if (processados % 100 === 0 || processados === total) {
  68. const decorridoS = Math.round((Date.now() - t0) / 1000);
  69. const ritmo = decorridoS / processados;
  70. const restamMin = Math.round(((total - processados) * ritmo) / 60);
  71. console.log(
  72. `[backfill-erp-todos] progresso: ${processados}/${total} | com vínculo: ${comVinculo} | novos: ${novosVinculos.length} | erros: ${erros} | ${decorridoS}s decorridos | ~${restamMin}min restantes`
  73. );
  74. }
  75. }
  76. }
  77. let idx = 0;
  78. async function worker() {
  79. while (idx < atendimentos.length) {
  80. const a = atendimentos[idx++];
  81. await processar(a);
  82. }
  83. }
  84. await Promise.all(Array.from({ length: CONCORRENCIA }, worker));
  85. const totalS = Math.round((Date.now() - t0) / 1000);
  86. console.log(
  87. `[backfill-erp-todos] concluído: ${processados}/${total} | com vínculo: ${comVinculo} | novos vínculos: ${novosVinculos.length} | erros: ${erros} | ${totalS}s total`
  88. );
  89. const outDir = path.resolve(__dirname, "logs");
  90. fs.mkdirSync(outDir, { recursive: true });
  91. const outPath = path.join(outDir, `backfill-erp-todos-novos-vinculos-${new Date().toISOString().replace(/[:.]/g, "-")}.json`);
  92. fs.writeFileSync(outPath, JSON.stringify(novosVinculos, null, 2));
  93. console.log(`[backfill-erp-todos] ${novosVinculos.length} novos vínculos salvos em ${outPath}`);
  94. console.log(`[backfill-erp-todos] próximo passo: node scripts/reavaliarNovosVinculosErp.js --arquivo ${outPath}`);
  95. process.exit(0);
  96. }
  97. main().catch((err) => {
  98. console.error("[backfill-erp-todos] falha fatal:", err);
  99. process.exit(1);
  100. });