FEAT: Integração ServiceNow + PostgreSQL com salvamento automático

- Implementa conexão API ServiceNow → PostgreSQL
- Salva automaticamente tickets e requisições
- Resultado: 673 tickets sincronizados
- Créditos: @TulioCastro pelo GET da API
This commit is contained in:
Rafael Alves Lopes 2025-09-03 21:40:04 -03:00
parent 56cb7b4c91
commit cb73486caa
8 changed files with 94 additions and 32 deletions

View File

2
package-lock.json generated
View File

@ -9,7 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.4",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"pg": "^8.7.1" "pg": "^8.7.1"
} }

View File

@ -9,7 +9,7 @@
"test": "echo \"No tests specified\" && exit 0" "test": "echo \"No tests specified\" && exit 0"
}, },
"dependencies": { "dependencies": {
"axios": "^0.21.1", "axios": "^0.21.4",
"dotenv": "^10.0.0", "dotenv": "^10.0.0",
"pg": "^8.7.1" "pg": "^8.7.1"
}, },

View File

@ -1,8 +1,24 @@
// config/database.js // src/data/database.js
module.exports = { // Configuração da conexão com o banco de dados PostgreSQL
const { Pool } = require('pg');
const pool = new Pool({
host: '10.0.120.75', host: '10.0.120.75',
port: 5432, port: 5432,
database: 'snglpi', database: 'snglpi',
user: 'desenvolvimento', user: 'desenvolvimento',
password: 'Ut@2S@$M9Xs@@W' password: 'Ut@2S@$M9Xs@@W'
}; });
// testa a conexao
pool.on('connect', () => {
console.log('Conectado ao PostgreSQL');
});
pool.on('error', (err) => {
console.error('Erro de conexão PostgreSQL:', err);
});
//exporta o pool para ser usado em outros arquivos
module.exports = pool;

View File

@ -1,28 +1,53 @@
const { Sequelize } = require('sequelize'); //Conetnando ao banco de dados
require('dotenv').config(); const pool = require('../data/database');
// Database connection configuration class TicketSnModel {
const dbConfig = {
host: process.env.DB_HOST,
dialect: process.env.DB_DIALECT || 'mysql', // Default to MySQL if not specified
logging: false, // Disable logging; enable for debugging
};
// Create a new Sequelize instance // Salvar os tickets
const sequelize = new Sequelize(process.env.DB_NAME, process.env.DB_USER, process.env.DB_PASSWORD, dbConfig); static async saveTickets(ticketData, typeTicket) {
// Test the database connection //Query SQL
const testConnection = async () => { const query = `INSERT INTO tickets_sn
(ticket_number, short_description, description, caller_email,
location_name, ramal, telefone, opened_at, tipo)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
ON CONFLICT (ticket_number)
DO UPDATE SET
short_description = EXCLUDED.short_description,
description = EXCLUDED.description,
location_name = EXCLUDED.location_name,
updated_at = NOW()
RETURNING id
`;
// Dados do ticket
const values = [
ticketData.number?.value || null,
ticketData.short_description?.value || null,
ticketData.description?.value || null,
ticketData.caller_email?.value || null,
ticketData.location_name?.value || null,
ticketData.u_ramal?.value || null,
ticketData.u_telefone?.value || null,
ticketData.opened_at?.value || null,
typeTicket
];
// Executa a query
try { try {
await sequelize.authenticate(); console.log('Salvando ticket:', values[0]);
console.log('Connection to the database has been established successfully.'); const result = await pool.query(query, values);
console.log('Ticket salvo com sucesso, ID:', result.rows[0].id);
return result.rows[0].id;
} catch (error) { } catch (error) {
console.error('Unable to connect to the database:', error); console.error('Erro ao salvar ticket:', error);
throw error;
}
} }
};
// Export the sequelize instance and the test function // Poderemos adicionar mais métodos aqui para outras operações no banco de dados, se necessário.
module.exports = { // Exemplo: buscar tickets, atualizar tickets.
sequelize,
testConnection, }
};
module.exports = TicketSnModel;

View File

@ -3,6 +3,7 @@ CREATE TABLE tickets_sn (
ticket_number VARCHAR(32) NOT NULL UNIQUE, -- Número do ticket (INC0140378) - ÚNICO ticket_number VARCHAR(32) NOT NULL UNIQUE, -- Número do ticket (INC0140378) - ÚNICO
sn_ticket_id VARCHAR(64), -- ID interno do ServiceNow sn_ticket_id VARCHAR(64), -- ID interno do ServiceNow
short_description TEXT, -- Resumo do problema short_description TEXT, -- Resumo do problema
tipo VARCHAR(10), -- Requisição ou incidente
description TEXT, -- Descrição completa description TEXT, -- Descrição completa
caller_id VARCHAR(255), -- ID de quem abriu o ticket caller_id VARCHAR(255), -- ID de quem abriu o ticket
caller_email VARCHAR(255), -- Email do solicitante caller_email VARCHAR(255), -- Email do solicitante
@ -13,4 +14,5 @@ CREATE TABLE tickets_sn (
opened_at TIMESTAMP, -- Quando o ticket foi aberto opened_at TIMESTAMP, -- Quando o ticket foi aberto
created_at TIMESTAMP DEFAULT NOW(), -- Quando registramos no BD created_at TIMESTAMP DEFAULT NOW(), -- Quando registramos no BD
updated_at TIMESTAMP DEFAULT NOW() -- Quando atualizamos pela última vez updated_at TIMESTAMP DEFAULT NOW() -- Quando atualizamos pela última vez
); );

View File

View File

@ -1,16 +1,27 @@
const axios = require('axios'); const axios = require('axios');
const apiConfig = require('../../config/apiConfig'); const apiConfig = require('../../config/apiConfig');
const fs = require('fs'); const fs = require('fs');
const TicketSnModel = require('../models/databaseModel');
const { Console } = require('console');
const fetchTicketsFromServiceNow = async () => { const fetchTicketsFromServiceNow = async () => {
try { try {
const ticketsResponse = await axios.get(apiConfig.snIncidentConfig.baseUrl, { const ticketsResponse = await axios.get(apiConfig.snIncidentConfig.baseUrl, {
auth: apiConfig.servicenowAuthentication.auth auth: apiConfig.servicenowAuthentication.auth
}); });
// gerar um JSON das respostas da API // gerar um JSON das respostas da API //Mantive o json enquanto testo a integração com o banco
fs.writeFileSync('servicenow_tickets.json', JSON.stringify(ticketsResponse.data, null, 2)); fs.writeFileSync('servicenow_tickets.json', JSON.stringify(ticketsResponse.data, null, 2));
// Salvar os tickets no banco de dados
console.log('Iniciando salvamento dos tickets no banco de dados...');
for (const ticket of ticketsResponse.data.result) {
await TicketSnModel.saveTickets(ticket, 'incidente');
}
} catch (error) { } catch (error) {
console.log('SERVICE NOW Tickets error: ', error.message); console.log('SERVICE NOW Tickets error: ', error.message);
} }
@ -22,9 +33,17 @@ const fetchRequestsFromServiceNow = async () => {
auth: apiConfig.servicenowAuthentication.auth auth: apiConfig.servicenowAuthentication.auth
}); });
// gerar um JSON das respostas da API // gerar um JSON das respostas da API //Mantive o json enquanto testo a integração com o banco
fs.writeFileSync('servicenow_requests.json', JSON.stringify(requestsResponse.data, null, 2)); fs.writeFileSync('servicenow_requests.json', JSON.stringify(requestsResponse.data, null, 2));
// Salvar os tickets no banco de dados
console.log('Iniciando salvamento das requisições no banco de dados...');
for (const request of requestsResponse.data.result) {
await TicketSnModel.saveTickets(request, 'requisicao');
}
} catch (error) { } catch (error) {
console.log('SERVICE NOW Requests error: ', error.message); console.log('SERVICE NOW Requests error: ', error.message);
} }