2025-09-23 21:01:01 -03:00
// src/services/servicenowService.js
2025-08-30 19:04:35 -03:00
const axios = require ( 'axios' ) ;
2025-09-03 11:13:23 -03:00
const apiConfig = require ( '../../config/apiConfig' ) ;
const fs = require ( 'fs' ) ;
2025-09-05 20:28:15 -03:00
const TicketSnModel = require ( '../models/ticketSnModel' ) ;
const { logInfo , logError , logSync } = require ( '../utils/logger' ) ;
2025-09-25 15:59:52 -03:00
const TicketUpdateModel = require ( '../models/ticketUpdateModel' ) ;
2025-08-30 19:04:35 -03:00
2025-09-03 11:13:23 -03:00
const fetchTicketsFromServiceNow = async ( ) => {
2025-08-30 19:04:35 -03:00
try {
2025-09-05 20:28:15 -03:00
logInfo ( '📡 Buscando incidentes do ServiceNow...' , { service : 'servicenow' } ) ;
2025-09-03 21:40:04 -03:00
2025-09-03 16:11:30 -03:00
const ticketsResponse = await axios . get ( apiConfig . snIncidentConfig . baseUrl , {
auth : apiConfig . servicenowAuthentication . auth
2025-09-03 11:13:23 -03:00
} ) ;
2025-09-05 20:28:15 -03:00
// comentado para evitar muitos arquivos
2025-09-15 20:55:19 -03:00
//fs.writeFileSync('servicenow_tickets.json', JSON.stringify(ticketsResponse.data, null, 2));
2025-09-05 20:28:15 -03:00
//logInfo('💾 Backup JSON de incidentes salvo', { count: ticketsResponse.data.result.length });
2025-09-03 21:40:04 -03:00
// Salvar os tickets no banco de dados
2025-09-05 20:28:15 -03:00
logInfo ( '💾 Iniciando salvamento de incidentes no banco...' ) ;
2025-09-03 21:40:04 -03:00
for ( const ticket of ticketsResponse . data . result ) {
2025-09-05 20:28:15 -03:00
await TicketSnModel . saveTicket ( ticket , 'incidente' ) ;
2025-09-03 21:40:04 -03:00
}
2025-09-05 20:28:15 -03:00
logSync ( 'ServiceNow' , ticketsResponse . data . result . length , 'incidentes' ) ;
2025-09-03 21:40:04 -03:00
2025-09-03 16:11:30 -03:00
} catch ( error ) {
2025-09-05 20:28:15 -03:00
logError ( error , 'SERVICE NOW Tickets' ) ;
2025-09-03 16:11:30 -03:00
}
}
const fetchRequestsFromServiceNow = async ( ) => {
try {
2025-09-05 20:28:15 -03:00
logInfo ( '📡 Buscando requisições do ServiceNow...' , { service : 'servicenow' } ) ;
2025-09-03 16:11:30 -03:00
const requestsResponse = await axios . get ( apiConfig . snRequestConfig . baseUrl , {
auth : apiConfig . servicenowAuthentication . auth
} ) ;
2025-09-05 20:28:15 -03:00
// Comentado para evitar muitos arquivos
2025-09-15 20:55:19 -03:00
//fs.writeFileSync('servicenow_requests.json', JSON.stringify(requestsResponse.data, null, 2));
2025-09-05 20:28:15 -03:00
//logInfo('💾 Backup JSON de requisições salvo', { count: requestsResponse.data.result.length });
2025-09-03 16:11:30 -03:00
2025-09-05 20:28:15 -03:00
// Salvar as requisições no banco de dados
logInfo ( '💾 Iniciando salvamento de requisições no banco...' ) ;
2025-09-03 21:40:04 -03:00
for ( const request of requestsResponse . data . result ) {
2025-09-05 20:28:15 -03:00
await TicketSnModel . saveTicket ( request , 'requisicao' ) ;
2025-09-03 21:40:04 -03:00
}
2025-09-05 20:28:15 -03:00
logSync ( 'ServiceNow' , requestsResponse . data . result . length , 'requisições' ) ;
2025-09-03 21:40:04 -03:00
2025-08-30 19:04:35 -03:00
} catch ( error ) {
2025-09-05 20:28:15 -03:00
logError ( error , 'SERVICE NOW Requests' ) ;
2025-08-30 19:04:35 -03:00
}
2025-09-03 11:13:23 -03:00
}
2025-08-30 19:04:35 -03:00
2025-09-25 15:59:52 -03:00
// Função para obter o sys_id de um ticket pela tabela de sincronização do banco de dados local
2025-10-02 10:16:56 -03:00
const getTicketSysId = async ( ticketId ) => {
2025-09-25 15:59:52 -03:00
try {
2025-10-02 10:16:56 -03:00
const ticket = await TicketSnModel . findById ( ticketId ) ;
2025-09-25 15:59:52 -03:00
return ticket . sys _id ;
} catch ( error ) {
logError ( error , '🚨Falha ao obter sys_id do ticket' ) ;
return null ;
}
}
2025-10-02 10:16:56 -03:00
const getTicketTypeById = async ( ticketId ) => {
try {
const ticket = await TicketSnModel . findById ( ticketId ) ;
const ticketType = ticket . tipo ;
logInfo ( ` ⚠️ Tipo do ticket ${ ticketId } - Tipo: ${ ticketType } ` , { ticketId , ticketType } ) ;
return ticketType ;
} catch ( error ) {
logError ( error , '🚨Falha ao obter tipo do ticket' ) ;
return null ;
}
}
2025-09-25 15:59:52 -03:00
// Função para obter o código de um comentário dentro de um ticket do ServiceNow
const getCommentId = async ( sysId , comment ) => {
try {
// Exemplo de requisição GET para buscar comentários:
// GET https://SEU_INSTANCE.service-now.com/api/now/table/sys_journal_field?sysparm_query=name=incident^element=comments^element_id={SYS_ID_DO_INCIDENTE}&sysparm_fields=sys_id,sys_created_on,sys_created_by,value&sysparm_orderby_desc=sys_created_on&sysparm_limit=1&sysparm_orderby_desc=sys_created_on&sysparm_limit=1
2025-10-02 10:16:56 -03:00
//https://caoadev.service-now.com/api/now/table/sys_journal_field?sysparm_query=element_id=493386721b2c9a90c5e163923b4bcb4a^element=comments^ORDERBYDESCsys_created_on&sysparm_fields=sys_id,element,value,sys_created_on,sys_created_by,element_id&sysparm_limit=1
// exemplo de resposta da API:
/ *
"result" : [
{
"sys_id" : "5070ca12fb107290ef1ffe316eefdc28" ,
"sys_created_on" : "2025-10-02 12:24:19" ,
"element_id" : "493386721b2c9a90c5e163923b4bcb4a" ,
"value" : "Teste fora do código" ,
"sys_created_by" : "SOTHIS.CAOA" ,
"element" : "comments"
} * /
const url = ` ${ apiConfig . snTableJournalConfig . baseUrl } ?sysparm_query=element_id= ${ sysId } ^element=comments^ORDERBYDESCsys_created_on&sysparm_fields=sys_id,element,value,sys_created_on,sys_created_by,element_id ` ;
2025-09-25 15:59:52 -03:00
const response = await axios . get ( url , {
auth : apiConfig . servicenowAuthentication . auth
} ) ;
2025-10-02 10:16:56 -03:00
const data = response . data ;
const comments = data . result ;
// Procurar o comentário exato na lista retornada
for ( const item of comments ) {
if ( item . value && item . value . includes ( comment ) ) {
return item . sys _id ; // Retorna o sys_id do comentário encontrado
2025-09-25 15:59:52 -03:00
}
}
} catch ( error ) {
logError ( error , '🚨Falha ao obter ID do comentário no ServiceNow' ) ;
return null ;
}
}
// Função para criar um comentário em um ticket no ServiceNow
2025-10-02 10:16:56 -03:00
const createCommentInServiceNow = async ( sysId , comment , ticketType ) => {
2025-09-25 15:59:52 -03:00
try {
// Exemplo de requisição PATCH para atualizar um ticket:
// curl -u user:pass \
// -H "Content-Type: application/json" \
// -X PATCH "https://SEU_INSTANCE.service-now.com/api/now/table/incident/{SYS_ID_DO_INCIDENTE}" \
// -d '{"comments":"Estamos analisando seu chamado. Retorno em breve."}'
2025-10-02 10:16:56 -03:00
let url = '' ;
let payload = { } ;
if ( ticketType == 'incidente' ) {
url = ` ${ apiConfig . snTableIncidentConfig . baseUrl } ${ sysId } ` ;
payload = {
comments : comment
} ;
} else if ( ticketType == 'requisicao' ) {
url = ` ${ apiConfig . snTableRequestConfig . baseUrl } ${ sysId } ` ;
payload = {
comments : comment
} ;
} else {
logError ( ` Tipo de ticket desconhecido: ${ ticketType } ` , { sysId , ticketType } ) ;
return null ;
}
2025-09-25 15:59:52 -03:00
2025-10-02 10:16:56 -03:00
const response = await axios . patch ( url , payload , {
2025-09-25 15:59:52 -03:00
auth : apiConfig . servicenowAuthentication . auth
} ) ;
2025-10-02 10:16:56 -03:00
// Verificar se retorna status 200 para sucesso
if ( response . status !== 200 ) {
logError ( ` ❌ Falha ao criar comentário. Status: ${ response . status } ` , { sysId , ticketType } ) ;
return null ;
}
2025-09-25 15:59:52 -03:00
// retornar id do comentário criado
const commentId = await getCommentId ( sysId , comment ) ;
2025-10-02 10:16:56 -03:00
if ( ! commentId ) {
logError ( '❌ Comentário criado, mas não foi possível obter o ID do comentário' , { sysId } ) ;
return null ;
}
logInfo ( ` ✅ Comentário criado com sucesso no ServiceNow. Comment ID: ${ commentId } ` , { sysId , ticketType } ) ;
2025-09-25 15:59:52 -03:00
return commentId ;
} catch ( error ) {
logError ( error , '🚨Falha ao criar comentário no ServiceNow' ) ;
}
}
2025-10-02 10:16:56 -03:00
const syncCommentToServiceNow = async ( ticketId , comment ) => {
logInfo ( ` Iniciando sincronização do comentário para o ticket SN Ticket: ${ ticketId } ` ) ;
const snSysId = await getTicketSysId ( ticketId ) ;
const ticketType = await getTicketTypeById ( ticketId ) ;
if ( ! snSysId ) {
logError ( ` ❌ sys_id do ServiceNow não encontrado para o ticket SN Ticket: ${ ticketId } ` ) ;
return null ;
}
const snCommentId = await createCommentInServiceNow ( snSysId , comment , ticketType ) ;
return snCommentId ;
}
// Função que verifica se o comentário já existe no ServiceNow antes de criar
const existingCommentInServiceNow = async ( ticketId , comment ) => {
try {
const sys _id = await getTicketSysId ( ticketId ) ;
const commentExists = await getCommentId ( sys _id , comment ) ;
return commentExists ;
} catch ( error ) {
logError ( error , '🚨Falha ao verificar existência do comentário no ServiceNow' ) ;
return false ;
}
}
2025-08-30 19:04:35 -03:00
module . exports = {
2025-09-03 16:11:30 -03:00
fetchTicketsFromServiceNow ,
2025-09-25 15:59:52 -03:00
fetchRequestsFromServiceNow ,
getTicketSysId ,
createCommentInServiceNow ,
getCommentId ,
2025-10-02 10:16:56 -03:00
existingCommentInServiceNow ,
syncCommentToServiceNow
2025-09-05 20:28:15 -03:00
}