From a8f1eea2060da0a1bc36acdf40dee81ffcbd7bc2 Mon Sep 17 00:00:00 2001 From: Tulio Castro Date: Thu, 25 Sep 2025 15:59:52 -0300 Subject: [PATCH] =?UTF-8?q?FEAT:=20Adiciona=20novas=20URLs=20de=20API=20no?= =?UTF-8?q?=20.env=20e=20implementa=20fun=C3=A7=C3=B5es=20para=20sincroniz?= =?UTF-8?q?a=C3=A7=C3=A3o=20de=20coment=C3=A1rios=20no=20ServiceNow?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env | 2 + config/apiConfig.js | 10 ++++ src/models/ticketSyncModel.js | 1 + src/models/ticketUpdateModel.js | 2 +- src/services/glpiCommentService.js | 17 +++++++ src/services/servicenowService.js | 74 +++++++++++++++++++++++++++++- 6 files changed, 104 insertions(+), 2 deletions(-) diff --git a/.env b/.env index efed84d..1e926fa 100644 --- a/.env +++ b/.env @@ -5,6 +5,8 @@ # ServiceNow API Configuration SERVICENOW_INCIDENT_URL="https://caoadev.service-now.com/api/now/table/incident?sysparm_display_value=all&sysparm_limit=20&sysparm_query=ORDERBYDESCsys_created_on&sysparm_fields=number%2state%2Copened_by%2Copened_at%2Clocation%2Cshort_description%2Cdescription%2Cvariables.caller_id%2Cvariables.location%2Cvariables.telephone_favorecido_rh%2Cvariables.numero_ramal%2Copened_by.email%2Csys_id%5Eassignment_group%3D46d44f91c611227500713c12f0b7c78d" SERVICENOW_REQUEST_URL="https://caoadev.service-now.com/api/now/table/sc_req_item?sysparm_fields=number%2Cstate%2Crequest%2Copened_by%2Copened_at%2Clocation%2Cshort_description%2Cdescription%2Cassignment_group%2Csys_id&sysparm_display_value=all&sysparm_query=assignment_group%3D1132c9e01bfad410e77eb9121b4bcbab" +SERVICENOW_TABLE_INCIDENT_URL="https://caoadev.service-now.com/api/now/table/incident/" +SERVICENOW_TABLE_JOURNAL_URL="https://caoadev.service-now.com/api/now/table/sys_journal_field" SERVICENOW_USERNAME=SOTHIS.CAOA SERVICENOW_PASSWORD=#Sothis20 diff --git a/config/apiConfig.js b/config/apiConfig.js index e991af2..f112240 100644 --- a/config/apiConfig.js +++ b/config/apiConfig.js @@ -28,10 +28,20 @@ const snRequestConfig = { baseUrl: process.env.SERVICENOW_REQUEST_URL, } +const snTableIncidentConfig = { + baseUrl: process.env.SERVICENOW_TABLE_INCIDENT_URL, +} + +const snTableJournalConfig = { + baseUrl: process.env.SERVICENOW_TABLE_JOURNAL_URL, +} + module.exports = { // configuração do ServiceNow e outras já existentes podem permanecer glpiDbConfig, snIncidentConfig, snRequestConfig, + snTableIncidentConfig, + snTableJournalConfig, servicenowAuthentication }; \ No newline at end of file diff --git a/src/models/ticketSyncModel.js b/src/models/ticketSyncModel.js index 45ebb79..4beee2b 100644 --- a/src/models/ticketSyncModel.js +++ b/src/models/ticketSyncModel.js @@ -38,6 +38,7 @@ class TicketSyncModel { throw error; } } + } /** * @module TicketSyncModel diff --git a/src/models/ticketUpdateModel.js b/src/models/ticketUpdateModel.js index 6156584..b0158b7 100644 --- a/src/models/ticketUpdateModel.js +++ b/src/models/ticketUpdateModel.js @@ -13,7 +13,7 @@ class TicketUpdateModel { const values = [ updateData.ticket_sync_id, 'note', - 'glpi', + updateData.source_system, updateData.content, 'Sothis', updateData.created_at, diff --git a/src/services/glpiCommentService.js b/src/services/glpiCommentService.js index 545aedc..2418698 100644 --- a/src/services/glpiCommentService.js +++ b/src/services/glpiCommentService.js @@ -4,11 +4,22 @@ const TicketGlpiModel = require('../models/ticketGlpiModel'); const TicketSyncModel = require('../models/ticketSyncModel'); const TicketUpdateModel = require('../models/ticketUpdateModel'); const { logInfo, logError } = require('../utils/logger'); +const { getTicketSysId, createCommentInServiceNow } = require('./servicenowService'); // Sincroniza comentários do GLPI para o Banco de Dados local const syncCommentsGlpi = async () => { try { + + // Função interna para sincronizar comentário no ServiceNow + const syncCommentToServiceNow = async (ticketNumber, comment) => { + const snSysId = await getTicketSysId(ticketNumber); + if (!snSysId) { + logError(`❌ sys_id do ServiceNow não encontrado para o ticket SN Ticket: ${ticketNumber}`); + return null; + } + return await createCommentInServiceNow(snSysId, comment.content); + }; logInfo('🔄 Iniciando sincronização de comments do GLPI para o Service Now iniciada...'); const effectiveTickets = await TicketSyncModel.getTicketsToSync(); @@ -29,10 +40,13 @@ const syncCommentsGlpi = async () => { continue; } + const snCommentId = await syncCommentToServiceNow(ticket.sn_ticket_id, comment); + const sync_id = await TicketSyncModel.getIdSyncByGlpiId(ticket.glpi_ticket_id); const commentData = { ticket_sync_id: sync_id, + source_system: 'glpi', content: comment.content, created_at: new Date(comment.date_creation), updated_at: new Date(comment.date_mod), @@ -59,6 +73,9 @@ const syncCommentsGlpi = async () => { } } + + + /** * @module glpiCommentService * @description Este módulo fornece serviços para sincronizar comentários do GLPI para o banco de dados local. diff --git a/src/services/servicenowService.js b/src/services/servicenowService.js index 3295cc0..27ec8c5 100644 --- a/src/services/servicenowService.js +++ b/src/services/servicenowService.js @@ -4,6 +4,7 @@ const apiConfig = require('../../config/apiConfig'); const fs = require('fs'); const TicketSnModel = require('../models/ticketSnModel'); const { logInfo, logError, logSync } = require('../utils/logger'); +const TicketUpdateModel = require('../models/ticketUpdateModel'); const fetchTicketsFromServiceNow = async () => { try { @@ -55,7 +56,78 @@ const fetchRequestsFromServiceNow = async () => { } } +// Função para obter o sys_id de um ticket pela tabela de sincronização do banco de dados local + +const getTicketSysId = async (ticketNumber) => { + try { + const ticket = await TicketSnModel.findByTicketNumber(ticketNumber); + return ticket.sys_id; + } catch (error) { + logError(error, '🚨Falha ao obter sys_id do ticket'); + return null; + } +} + +// 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 + + const url = `${apiConfig.snTableJournalConfig.baseUrl}?sysparm_query=name=incident^element=comments^element_id=${sysId}&sysparm_fields=sys_id,sys_created_on,sys_created_by,value&sysparm_orderby_desc=sys_created_on&sysparm_limit=1`; + + const response = await axios.get(url, { + auth: apiConfig.servicenowAuthentication.auth + }); + + for (const entry of response.data.result) { + if (entry.value.includes(comment)) { + return entry.sys_id; + } else { + logInfo('Comentário não encontrado no ticket', { sysId }); + } + } + + } 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 +const createCommentInServiceNow = async (sysId, comment) => { + 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."}' + + const url = `${apiConfig.snTableIncidentConfig.baseUrl}${sysId}`; + const payload = { + comments: comment + }; + + await axios.patch(url, payload, { + auth: apiConfig.servicenowAuthentication.auth + }); + + logInfo('💬 Comentário criado com sucesso no ServiceNow', { sysId, comment }); + + // retornar id do comentário criado + const commentId = await getCommentId(sysId, comment); + return commentId; + + } catch (error) { + logError(error, '🚨Falha ao criar comentário no ServiceNow'); + } +} + module.exports = { fetchTicketsFromServiceNow, - fetchRequestsFromServiceNow + fetchRequestsFromServiceNow, + getTicketSysId, + createCommentInServiceNow, + getCommentId, + updateTicketInServiceNow } \ No newline at end of file