backfillCancelamento.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. // Reseta atendimentos já avaliados (Avaliavel=true) para pendente, para que a próxima
  2. // rodada de avaliação também extraia StatusCancelamento/MotivoCancelamento (campos novos).
  3. // Não faz a reavaliação em si — só o reset. Depois de rodar com --apply, drenar a fila
  4. // com scripts/avaliarTudo.js (idempotente entre reinícios, ao contrário deste script).
  5. //
  6. // Uso: node scripts/backfillCancelamento.js [--dias 90] [--apply] [--limite N]
  7. // --dias N : só atendimentos com Abertura nos últimos N dias (omitir = todo o histórico Avaliavel=true)
  8. // --apply : executa de fato (sem essa flag, é dry-run)
  9. // --limite N : limita quantos IDs entram no backfill (teste)
  10. import fs from "node:fs";
  11. import path from "node:path";
  12. import { fileURLToPath } from "node:url";
  13. import { AtendimentoAvaliacao } from "../src/models/AtendimentoAvaliacao.model.js";
  14. import { contarPendentes } from "../src/services/atendimentoAvaliacaoService.js";
  15. const __dirname = path.dirname(fileURLToPath(import.meta.url));
  16. const APLICAR = process.argv.includes("--apply");
  17. const diasIdx = process.argv.indexOf("--dias");
  18. const DIAS = diasIdx > -1 ? Number(process.argv[diasIdx + 1]) : null;
  19. const limiteIdx = process.argv.indexOf("--limite");
  20. const LIMITE = limiteIdx > -1 ? Number(process.argv[limiteIdx + 1]) : null;
  21. async function buscarCandidatos() {
  22. const query = AtendimentoAvaliacao.query()
  23. .where("Avaliavel", true)
  24. .join("atendimentos as a", "a.Id", "atendimento_avaliacoes.AtendimentoId")
  25. .select(
  26. "atendimento_avaliacoes.AtendimentoId",
  27. "atendimento_avaliacoes.StatusCancelamento",
  28. "atendimento_avaliacoes.MotivoCancelamento",
  29. "a.Abertura"
  30. )
  31. .orderBy("a.Abertura", "desc");
  32. if (DIAS) {
  33. const cutoff = new Date(Date.now() - DIAS * 24 * 60 * 60 * 1000);
  34. query.where("a.Abertura", ">=", cutoff);
  35. }
  36. return query;
  37. }
  38. async function main() {
  39. const candidatos = await buscarCandidatos();
  40. const alvos = LIMITE ? candidatos.slice(0, LIMITE) : candidatos;
  41. console.log(
  42. `[backfill-cancelamento] ${candidatos.length} candidatos` +
  43. `${DIAS ? ` (Abertura nos últimos ${DIAS} dias)` : " (todo o histórico Avaliavel=true)"}.`
  44. );
  45. console.log(`[backfill-cancelamento] ${alvos.length} avaliações serão resetadas para pendente${LIMITE ? ` (--limite ${LIMITE})` : ""}.`);
  46. if (!APLICAR) {
  47. console.log("[backfill-cancelamento] dry-run (nenhuma alteração feita). Use --apply para executar.");
  48. process.exit(0);
  49. }
  50. if (alvos.length === 0) {
  51. console.log("[backfill-cancelamento] nada para reavaliar.");
  52. process.exit(0);
  53. }
  54. const backupDir = path.resolve(__dirname, "logs");
  55. fs.mkdirSync(backupDir, { recursive: true });
  56. const backupPath = path.join(backupDir, `backfill-cancelamento-${new Date().toISOString().replace(/[:.]/g, "-")}.json`);
  57. fs.writeFileSync(backupPath, JSON.stringify(alvos, null, 2));
  58. console.log(`[backfill-cancelamento] backup dos valores antigos salvo em ${backupPath}`);
  59. const ids = alvos.map((a) => a.AtendimentoId);
  60. const pendentesAntes = await contarPendentes();
  61. await AtendimentoAvaliacao.query().whereIn("AtendimentoId", ids).patch({ UltimaMensagemId: null });
  62. const pendentesDepois = await contarPendentes();
  63. console.log(`[backfill-cancelamento] resetados ${ids.length} — fila de pendentes ${pendentesAntes} -> ${pendentesDepois}.`);
  64. console.log("[backfill-cancelamento] pronto. Agora rode scripts/avaliarTudo.js para drenar a fila.");
  65. process.exit(0);
  66. }
  67. main().catch((e) => {
  68. console.error("[backfill-cancelamento] falha:", e.message);
  69. process.exit(1);
  70. });