snglpi/src/models/ticketSyncModel.js

316 lines
12 KiB
JavaScript
Raw Normal View History

const pool = require('../data/database');
const { logError, logInfo } = require('../utils/logger');
class TicketSyncModel {
2025-10-13 06:06:52 -03:00
static async createSyncRecord(data) {
try {
2025-10-13 06:06:52 -03:00
const query = `INSERT INTO ticket_sync (
sn_ticket_id,
glpi_ticket_id,
last_sn_sync,
last_glpi_sync,
created_at,
updated_at,
sn_sync_status,
glpi_sync_status,
source_last
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
ON CONFLICT (sn_ticket_id) DO NOTHING
RETURNING id`;
2025-10-13 06:06:52 -03:00
const values = [
data.sn_ticket_id,
data.glpi_ticket_id,
data.last_sn_sync,
data.last_glpi_sync,
data.created_at,
data.updated_at,
data.sn_sync_status,
data.glpi_sync_status,
data.source_last
]
await pool.query(query, values);
2025-10-13 06:06:52 -03:00
} catch (error) {
logError(error, 'ERRO: Erro ao criar registro de sincronizacao');
2025-10-13 06:06:52 -03:00
throw error;
}
}
static async getTicketsToSync(glpi_sync_status, sn_sync_status) {
try {
const query = 'SELECT id, glpi_ticket_id, sn_ticket_id FROM ticket_sync WHERE glpi_sync_status = $1 AND sn_sync_status = $2';
const values =[glpi_sync_status , sn_sync_status];
const { rows } = await pool.query(query, values);
return rows;
} catch (error) {
logError(error, 'ERRO: Erro ao buscar tickets para sincronizar');
throw error;
}
}
static async updateSourceLast(snTicketId, source) {
try {
const query = 'UPDATE ticket_sync SET source_last = $1 WHERE sn_ticket_id = $2';
await pool.query(query, [source, snTicketId]);
} catch (error) {
logError(error, `ERRO: Erro ao atualizar source_last para o ticket SN ID: ${snTicketId}`);
throw error;
}
}
static async updateStatus(ticketSyncId, glpiStatus, snStatus) {
try {
const query = 'UPDATE ticket_sync SET glpi_sync_status = $1, sn_sync_status = $2 WHERE sn_ticket_id = $3';
await pool.query(query, [glpiStatus, snStatus, ticketSyncId]);
} catch (error) {
logError(`${error} ERRO: Erro ao atualizar status de sincronizacao para o ID: ${ticketSyncId}`);
throw error;
}
}
static async updateStatusAndSourceLast(ticketSyncId, glpiStatus, snStatus, source_last) {
try {
const query = 'UPDATE ticket_sync SET glpi_sync_status = $1, sn_sync_status= $2, source_last = $4 WHERE sn_ticket_id = $3';
await pool.query(query, [glpiStatus, snStatus, ticketSyncId, source_last]);
} catch (error) {
logError(`${error} ERRO: Erro ao atualizar status de sincronizacao para o ID: ${ticketSyncId}`);
throw error;
}
}
static async updateStatusAndGlpiTicket(ticketSyncId, glpiStatus, snStatus, glpiTicketId) {
try {
const query = 'UPDATE ticket_sync SET glpi_sync_status = $1, sn_sync_status = $2, glpi_ticket_id = $4 WHERE sn_ticket_id = $3';
await pool.query(query, [glpiStatus, snStatus, ticketSyncId, glpiTicketId]);
} catch (error) {
logError(error, `ERRO: Erro ao atualizar status de sincronizacao para o ID: ${ticketSyncId}`);
throw error;
}
}
2025-10-10 08:12:26 -03:00
static async getIdSyncByGlpiId(glpiTicketId) {
try {
const query = 'SELECT id FROM ticket_sync WHERE glpi_ticket_id = $1';
const { rows } = await pool.query(query, [glpiTicketId]);
return rows[0] ? rows[0].id : null;
} catch (error) {
logError(error, `ERRO: Erro ao buscar ID de sincronizacao por GLPI ID: ${glpiTicketId}`);
throw error;
}
}
static async getBySysId(sysId) {
try {
const query = `
SELECT tsync.* FROM ticket_sync tsync
JOIN tickets_sn tsn ON tsync.sn_ticket_id = tsn.id
WHERE tsn.sys_id = $1`;
const { rows } = await pool.query(query, [sysId]);
return rows[0] || null;
} catch (error) {
logError(error, `ERRO: Erro ao buscar registro de sincronizacao por sys_id: ${sysId}`);
throw error;
}
}
2025-10-10 08:12:26 -03:00
static async getIdSyncBySnId(snTicketId) {
try {
const query = 'SELECT id FROM ticket_sync WHERE sn_ticket_id = $1';
const { rows } = await pool.query(query, [snTicketId]);
return rows[0] ? rows[0].id : null;
} catch (error) {
logError(error, `ERRO: Erro ao buscar ID de sincronizacao por SN ID: ${snTicketId}`);
2025-10-10 08:12:26 -03:00
throw error;
}
}
2025-10-13 06:06:52 -03:00
static async getByTicketNumber(ticketNumber) {
try {
const query = 'SELECT * FROM ticket_sync WHERE sn_ticket_id = $1';
const { rows } = await pool.query(query, [ticketNumber]);
return rows[0] || null;
2025-10-10 08:12:26 -03:00
2025-10-13 06:06:52 -03:00
} catch (error) {
logError(`${error}, ERRO: Erro ao buscar ticket ${ticketNumber}}` )
2025-10-13 06:06:52 -03:00
}
}
2025-10-10 08:12:26 -03:00
static async getTicketsSynced() {
try {
const query = `
SELECT
tsync.id,
tsync.glpi_ticket_id,
tsync.sn_ticket_id,
tsn.sys_id,
tsync.source_last
FROM ticket_sync tsync
JOIN tickets_sn tsn ON tsync.sn_ticket_id = tsn.id
WHERE tsync.glpi_sync_status = 'synced' AND tsync.sn_sync_status = 'synced'`;
const { rows } = await pool.query(query);
return rows;
} catch (error) {
logError(error, 'ERRO: Erro ao buscar tickets para sincronizar');
throw error;
}
}
static async getTicketsToMonitor() {
try {
const query = `
SELECT
tsync.id,
tsync.glpi_ticket_id,
tsync.sn_ticket_id,
tsn.sys_id,
tsync.source_last,
tsync.sn_sync_status,
tsync.glpi_sync_status
FROM ticket_sync tsync
JOIN tickets_sn tsn ON tsync.sn_ticket_id = tsn.id
WHERE (tsync.glpi_sync_status IN ('synced', 'solved') OR tsync.sn_sync_status IN ('synced', 'solved'))
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
AND (tsync.glpi_sync_status != 'closed' AND tsync.sn_sync_status != 'closed')
AND (tsync.glpi_sync_status != 'error_permanent' AND tsync.sn_sync_status != 'error_permanent')`;
const { rows } = await pool.query(query);
return rows;
} catch (error) {
logError(error, 'ERRO: Erro ao buscar tickets para monitorar');
throw error;
}
}
static async getTicketsForClosureMonitor() {
try {
const query = `
SELECT
tsync.id,
tsync.glpi_ticket_id,
tsync.sn_ticket_id,
tsync.source_last,
tsync.sn_sync_status,
tsync.glpi_sync_status
FROM ticket_sync tsync
WHERE tsync.glpi_ticket_id IS NOT NULL
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
AND tsync.glpi_sync_status NOT IN ('closed', 'ignored', 'error_permanent')
AND tsync.sn_sync_status NOT IN ('closed', 'ignored', 'error_permanent')
`;
const { rows } = await pool.query(query);
return rows;
} catch (error) {
logError(error, 'ERRO: Falha ao buscar tickets para monitoramento de fechamento GLPI');
throw error;
}
}
static async getTicketsPendingSolve() {
try {
const query = `
SELECT
tsync.id,
tsync.glpi_ticket_id,
tsync.sn_ticket_id,
tsync.glpi_sync_status,
tsync.sn_sync_status,
tsn.sys_id,
tsn.tipo
FROM ticket_sync tsync
JOIN tickets_sn tsn ON tsync.sn_ticket_id = tsn.id
WHERE tsync.glpi_sync_status = 'pending_solve' OR tsync.sn_sync_status = 'pending_solve'`;
const { rows } = await pool.query(query);
return rows;
} catch (error) {
logError(error, 'ERRO: Erro ao buscar tickets pendentes de fechamento');
throw error;
}
}
static async getTicketsInErrorState() {
try {
const query = `
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
SELECT id, sn_ticket_id, glpi_ticket_id, sn_sync_status, glpi_sync_status, error_retry_count
FROM ticket_sync
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
WHERE (sn_sync_status LIKE '%error%' AND sn_sync_status != 'error_permanent')
OR (glpi_sync_status LIKE '%error%' AND glpi_sync_status != 'error_permanent')
`;
const { rows } = await pool.query(query);
return rows;
} catch (error) {
logError(error, 'ERRO: Erro ao buscar tickets em estado de erro');
throw error;
}
}
FEAT: Motor de regras único de status/fechamento + mandante configurável Consolida os dois controladores legados que decidiam status/fechamento de forma concorrente (processGlpiClosureController + processStatusController) em um único processTicketLifecycleController, eliminando a dependência do campo source_last (mantido só como rastro de auditoria) e a flag ENABLE_STATUS_SYNC (removida). Isso corrige o bug de reabertura: chamados reabertos no SN voltavam a ser fechados no GLPI porque a regra de precedência de finalização do fluxo legado forçava o status do GLPI de volta pro SN. Correções de bugs encontrados em teste (Frente 1): - Constraint UNIQUE em ticket_sync.sn_ticket_id + ON CONFLICT DO NOTHING na criação do registro, prevenindo duplicação de tickets. - Fechamento no SN agora é confirmado por leitura ao vivo do status antes de marcar o ticket como solved/closed, em vez de confiar só no HTTP 200 (a API do SN pode retornar sucesso e silenciosamente ignorar um valor de estado inválido — descoberto e corrigido também no mandante). - Nota de encerramento do SN pro GLPI agora é idempotente e criada uma única vez por ticket. - Erros de sincronização passam a ter um limite de tentativas (MAX_ERROR_RETRIES) antes de marcar o ticket como error_permanent, exigindo intervenção manual em vez de tentar para sempre. - Chamados criados no GLPI passam a gravar o número do ticket do SN no campo externalid. Nova funcionalidade (Frente 2): quando o SN resolve/encerra um chamado por conta própria antes do GLPI, além da nota informativa no GLPI (agora com o nome de quem encerrou, buscado ao vivo via resolved_by/closed_by/ sys_updated_by), o próprio SN recebe um aviso de que a Sothis não vai mais atender aquele chamado e ele é transferido pra fila de TI da CAOA. Nova funcionalidade (Mandante, regras 19-22): espelhamento opcional e configurável de status intermediário (Aguardando Atendimento/Em Atendimento/Em Espera) entre os dois sistemas, controlado pela env MANDANTE=GLPI|SNOW. Sem essa env configurada, mantém o comportamento atual (nenhum espelhamento de status intermediário). Nunca afeta os status finais (resolvido/encerrado/fora de escopo), que continuam regidos pelas regras fixas de fechamento. Corrigido também o workflow de deploy (.gitea/workflows/deploy-production.yml), que ainda validava os controladores antigos (já removidos) e exigia ENABLE_STATUS_SYNC=true, o que quebraria o próximo deploy em produção. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-10 09:45:34 -03:00
static async bumpErrorRetryCount(snTicketId) {
try {
const query = 'UPDATE ticket_sync SET error_retry_count = error_retry_count + 1 WHERE sn_ticket_id = $1 RETURNING error_retry_count';
const { rows } = await pool.query(query, [snTicketId]);
return rows[0] ? rows[0].error_retry_count : null;
} catch (error) {
logError(error, `ERRO: Erro ao incrementar error_retry_count para o ticket SN ID: ${snTicketId}`);
throw error;
}
}
static async markPermanentError(snTicketId) {
try {
const query = "UPDATE ticket_sync SET glpi_sync_status = 'error_permanent', sn_sync_status = 'error_permanent' WHERE sn_ticket_id = $1";
await pool.query(query, [snTicketId]);
} catch (error) {
logError(error, `ERRO: Erro ao marcar error_permanent para o ticket SN ID: ${snTicketId}`);
throw error;
}
}
static async updateLastSync(snTicketId, system) {
try {
let fieldToUpdate;
if (system === 'servicenow') {
fieldToUpdate = 'last_sn_sync';
} else if (system === 'glpi') {
fieldToUpdate = 'last_glpi_sync';
} else {
return;
}
const query = `UPDATE ticket_sync SET ${fieldToUpdate} = NOW() WHERE sn_ticket_id = $1`;
await pool.query(query, [snTicketId]);
} catch (error) {
logError(`${error} ERRO: Erro ao atualizar last_sync para o ID: ${snTicketId}`);
}
}
static async updateStatusByGlpiId(glpiTicketId, snStatus, glpiStatus) {
try {
const query = 'UPDATE ticket_sync SET sn_sync_status = $1, glpi_sync_status = $2 WHERE glpi_ticket_id = $3';
await pool.query(query, [snStatus, glpiStatus, glpiTicketId]);
} catch (error) {
logError(`${error} ERRO: Erro ao atualizar status de sincronizacao para o GLPI ID: ${glpiTicketId}`);
throw error;
}
}
2025-10-10 08:12:26 -03:00
}
/**
* @module TicketSyncModel
* @description Este modulo e a camada de acesso a tabela `ticket_sync`, que atua como o cerebro do processo de sincronizacao.
* Ele armazena o estado de cada ticket em ambos os sistemas (GLPI e ServiceNow) e controla o fluxo de atualizacoes.
*
* Principais Funcionalidades:
* - **Gerenciamento de Estado**: Metodos como `updateStatus`, `updateStatusAndSourceLast` e `updateStatusAndGlpiTicket` sao usados para modificar os status de sincronizacao (ex: 'pending_check', 'synced', 'solved', 'closed', 'error').
* - **Controle de Fluxo (`source_last`)**: A coluna `source_last` e gerenciada por este modelo para indicar qual sistema realizou a ultima modificacao, prevenindo atualizacoes conflitantes (race conditions).
* - **Selecao de Tickets para Processamento**: Metodos como `getTicketsToMonitor`, `getTicketsInErrorState`, e `getTicketsSynced` fornecem listas de tickets para os diferentes controladores processarem, com base em seus status atuais.
* - **Criacao e Consulta**: `createSyncRecord` cria o registro inicial de um ticket, e varias funcoes de busca (`getBySysId`, `getIdSyncByGlpiId`, etc.) permitem localizar registros de sincronizacao.
*
* A tabela `ticket_sync` e a fonte da verdade para o estado da integracao de cada ticket individualmente.
*/
module.exports = TicketSyncModel;