snglpi/src/models/syncControlModel.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

38 lines
1.4 KiB
JavaScript

// src/models/syncControlModel.js
const pool = require('../data/database');
const { logError, logInfo } = require('../utils/logger');
class SyncControlModel {
static async getWatermark(systemName) {
try {
const query = 'SELECT last_watermark FROM sync_control WHERE system_name = $1';
const { rows } = await pool.query(query, [systemName]);
if (rows.length === 0) {
throw new Error(`Watermark para o sistema '${systemName}' não encontrada no banco de dados.`);
}
// Retorna no formato que o ServiceNow espera: 'YYYY-MM-DD HH:MM:SS'
return rows[0].last_watermark.toISOString().replace('T', ' ').substring(0, 19);
} catch (error) {
logError(error, `Erro ao buscar watermark para ${systemName}`);
throw error;
}
}
static async setWatermark(systemName, watermark) {
try {
const query = `
UPDATE sync_control
SET last_watermark = $1, last_run_at = NOW(), last_run_status = 'success'
WHERE system_name = $2
`;
await pool.query(query, [watermark, systemName]);
logInfo(`🌊 Nova marca d'água para '${systemName}' definida para: ${watermark}`);
} catch (error) {
logError(error, `Erro ao definir watermark para ${systemName}`);
throw error;
}
}
}
module.exports = SyncControlModel;