2025-10-23 17:30:03 -03:00
const TicketSyncModel = require ( '../models/ticketSyncModel' ) ;
const { logInfo , logError , logWarning } = require ( '../utils/logger' ) ;
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
const MAX _ERROR _RETRIES = Number ( process . env . MAX _ERROR _RETRIES || 5 ) ;
2025-10-23 17:30:03 -03:00
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 ) {
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
const retryCount = await TicketSyncModel . bumpErrorRetryCount ( ticket . sn _ticket _id ) ;
if ( retryCount > MAX _ERROR _RETRIES ) {
await TicketSyncModel . markPermanentError ( ticket . sn _ticket _id ) ;
logWarning ( ` Ticket SN ID ${ ticket . sn _ticket _id } excedeu ${ MAX _ERROR _RETRIES } tentativas de reprocessamento. Marcado como 'error_permanent' (requer intervencao manual). ` ) ;
continue ;
}
2025-10-23 17:30:03 -03:00
let newSnStatus = ticket . sn _sync _status ;
let newGlpiStatus = ticket . glpi _sync _status ;
if ( ticket . glpi _sync _status === 'error' ) {
newGlpiStatus = 'pending_check' ;
}
if ( ticket . sn _sync _status === 'error_sync' ) newSnStatus = 'synced' ;
if ( ticket . glpi _sync _status === 'error_sync' ) newGlpiStatus = 'synced' ;
if ( ticket . sn _sync _status === 'error_closing' ) newSnStatus = 'pending_close' ;
if ( ticket . glpi _sync _status === 'error_closing' ) newGlpiStatus = 'pending_close' ;
await TicketSyncModel . updateStatus ( ticket . sn _ticket _id , newGlpiStatus , newSnStatus ) ;
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
logInfo ( ` Ticket SN ID ${ ticket . sn _ticket _id } resetado para reprocessamento (SN: ${ newSnStatus } , GLPI: ${ newGlpiStatus } , tentativa ${ retryCount } / ${ MAX _ERROR _RETRIES } ). ` ) ;
2025-10-23 17:30:03 -03:00
}
} catch ( error ) {
logError ( error , 'Erro ao processar tickets com falha.' ) ;
}
} ;
module . exports = {
processErrorController
} ;
2025-10-29 14:20:21 -03:00
/ * *
* @ file processErrorController . js
* @ description Este controlador é responsável por gerenciar tickets que entraram em estado de erro durante o processo de sincronização .
* Ele busca todos os tickets marcados com status de erro ( ex : 'error' , 'error_sync' ) e os reseta para um estado anterior válido
* ( ex : 'pending_check' , 'synced' ) . Isso permite que os tickets sejam automaticamente reprocessados na próxima execução do ciclo de sincronização ,
* aumentando a resiliência do sistema .
* /