snglpi/src/controllers/processErrorController.js
Rafael Lopes 0cc27df2cf FEAT: Implementa sincronização bidirecional de status e ciclo de vida de tickets
- **Sincronização Inteligente:** O sistema agora detecta mudanças de estado em qualquer uma das plataformas e propaga a atualização para a outra, respeitando a 'fonte da verdade' (`source_last`).
- **Regra 'Fora do Escopo':** Implementada a regra de negócio para tickets marcados como 'Fora do Escopo' no GLPI (solutiontypes_id = 27). Esses tickets agora são ignorados na sincronização, têm seu status finalizado no GLPI e uma nota informativa é adicionada no ServiceNow.
- **Watermark (Marca d'água):** A coleta de novos tickets do ServiceNow foi otimizada com um sistema de marca d'água, buscando apenas registros atualizados desde a última execução bem-sucedida, o que melhora significativamente a performance.
- **Resiliência:** Adicionado um `processErrorController` que reseta tickets com status de erro, permitindo que sejam reprocessados automaticamente no próximo ciclo.

Testes de fluxo foram realizados com sucesso, validando a criação, resolução (SN <-> GLPI) e a regra 'Fora do Escopo'.

Pendências para a próxima fase:
1. Validar melhor o fluxo de reabertura de chamados em ambas as direções.
2. Garantir que a `work_note` enviada para o ServiceNow na regra 'Fora do Escopo' seja devidamente sanitizada."
2025-10-23 17:30:03 -03:00

48 lines
1.9 KiB
JavaScript

// src/controllers/processErrorController.js
const TicketSyncModel = require('../models/ticketSyncModel');
const { logInfo, logError, logWarning } = require('../utils/logger');
const processErrorController = async () => {
logInfo('Iniciando verificação de tickets com erro...');
try {
const errorTickets = await TicketSyncModel.getTicketsInErrorState();
if (errorTickets.length === 0) {
logInfo('Nenhum ticket com erro encontrado para reprocessamento.');
return;
}
logWarning(`Encontrados ${errorTickets.length} tickets com erro. Tentando reprocessar...`);
for (const ticket of errorTickets) {
let newSnStatus = ticket.sn_sync_status;
let newGlpiStatus = ticket.glpi_sync_status;
// Reset 'error' na criação do GLPI para tentar de novo
if (ticket.glpi_sync_status === 'error') {
newGlpiStatus = 'pending_check';
}
// Reset 'error_sync' para tentar sincronizar status/comentários de novo
if (ticket.sn_sync_status === 'error_sync') newSnStatus = 'synced';
if (ticket.glpi_sync_status === 'error_sync') newGlpiStatus = 'synced';
// Reset 'error_closing' para tentar fechar de novo
if (ticket.sn_sync_status === 'error_closing') newSnStatus = 'pending_close';
if (ticket.glpi_sync_status === 'error_closing') newGlpiStatus = 'pending_close';
// Atualiza o status para que o ticket reentre no fluxo normal
await TicketSyncModel.updateStatus(ticket.sn_ticket_id, newGlpiStatus, newSnStatus);
logInfo(`Ticket SN ID ${ticket.sn_ticket_id} resetado para reprocessamento (SN: ${newSnStatus}, GLPI: ${newGlpiStatus}).`);
}
} catch (error) {
logError(error, 'Erro ao processar tickets com falha.');
}
};
module.exports = {
processErrorController
};