diff --git a/app.js b/app.js
index a383ef8..8eb42df 100644
--- a/app.js
+++ b/app.js
@@ -1,4 +1,4 @@
const hubsoftController = require('./controller/processController.js');
// Inicia o processamento dos atendimentos
-hubsoftController.processaAtendimentos();
\ No newline at end of file
+hubsoftController.processaAtendimentos(skipHubSoft = true);
\ No newline at end of file
diff --git a/controller/processController.js b/controller/processController.js
index 4863541..514c368 100644
--- a/controller/processController.js
+++ b/controller/processController.js
@@ -1,47 +1,224 @@
// controller/processController.js
const hubsoftModel = require('../model/hubsoftModel.js');
const hubglpiModel = require('../model/hubglpiModel.js');
-const { logError, logInfo} = require('../utils/logger');
+const glpiModel = require('../model/glpiModel.js');
+const { logError, logInfo } = require('../utils/logger');
-const processaAtendimentos = async () => {
-
+// ================================================================================
+// Constantes e Configurações
+// ================================================================================
- try {
- const atendimentosDB = await hubsoftModel.getAtendimentosFromDB();
-
- // Insere os dados do banco do Hubsoft nas tabelas hubsoft_tickets e sync_data
- for (const atendimento of atendimentosDB) {
- console.log('Processando atendimento:', atendimento);
- const ticketData = {
- id_atendimento: atendimento.id_atendimento,
- id_atendimento_status: atendimento.id_atendimento_status,
- protocolo_hub: atendimento.protocolo,
- descricao_abertura: atendimento.descricao_abertura,
- data_cadastro: atendimento.data_cadastro,
- cliente_nome: atendimento.nome_contato,
- codigo_cliente: atendimento.codigo_cliente,
- descricao: atendimento.descricao
- };
-
-
- const insertedTicket = await hubglpiModel.insertTicket(ticketData);
- console.log('Ticket inserido:', insertedTicket);
-
-
-
- console.log('Inserindo Sync Data para o atendimento ID:', ticketData.id_atendimento);
-
- const insertSyncData = await hubglpiModel.insertSyncData(ticketData.id_atendimento)
- console.log('Sync Data inserido:', insertSyncData);
-
-
-
- }
- } catch (error) {
- console.error('Erro ao processar atendimentos:', error);
-}
-
-}
-module.exports = {
- processaAtendimentos
+const statusAtendimentoHubGlpi = {
+ 1: 'Pendente',
+ 2: 'Em atendimento',
+ 3: 'Resolvido',
+ 31: 'Pendente',
+ 32: 'Pendente',
+ 33: 'Novo'
};
+
+const statusAtendimentoGLPI = {
+ 'Novo': 1,
+ 'Pendente': 4,
+ 'Em atendimento': 2,
+ 'Resolvido': 5
+};
+
+// ================================================================================
+// Funções Utilitárias
+// ================================================================================
+
+
+// Formata a descrição do ticket em HTML
+const formatDescription = (ticketData) => {
+ const { cliente_nome, codigo_cliente, servico_nome, ticket_mundiale, protocolo_hub, description } = ticketData;
+
+ const tableRows = `
+
| Nome do Cliente: | ${cliente_nome} |
+ | Codigo Cliente: | ${codigo_cliente} |
+ | Serviço: | ${servico_nome} |
+ | Ticket Number (Mundiale): | ${ticket_mundiale || 'N/A'} |
+ | Protocolo Hub: | ${protocolo_hub || 'N/A'} |
+ `;
+
+ const htmlDescription = `
+
+
+ | Campo |
+ Valor |
+
+ ${tableRows}
+
+
+ Descrição:
+
+ ${description || 'N/A'}
+ `;
+
+
+ console.log(htmlDescription);
+
+ return htmlDescription;
+};
+
+
+// Gera o entity_Name baseado nos campos do ticket
+const generateEntityName = (ticketData) => {
+ const codigoClienteParts = (ticketData.codigo_cliente || '').split('-');
+ const codigoServicoFirstPart = (ticketData.codigo_servico || '').split('-')[0]?.trim() || '';
+ const clienteNome = ticketData.cliente_nome || '';
+
+ return [...codigoClienteParts, codigoServicoFirstPart, clienteNome].join('');
+};
+
+
+// Formata os dados do ticket para o GLPI
+const formatTicketDataForGlpi = async (ticketData) => {
+ const formattedData = {
+ ...ticketData,
+ status_atendimento: statusAtendimentoGLPI[ticketData.status_atendimento] || 1,
+ date_mod: new Date(),
+ user_id_recipient: 971,
+ descricao_abertura: toString(formatDescription(ticketData)),
+ urgency: 3,
+ impact: 3,
+ priority: 3,
+ type: 1,
+ itilcategories_id: 1,
+ date_creation: new Date(),
+ entidades_id: await glpiModel.selectEntityId() //TODO: Implementar a busca da entidade
+ };
+ return formattedData;
+};
+
+// ================================================================================
+// Funções de Integração
+// ================================================================================
+
+const createGlpiTicket = async (ticketData) => {
+ try {
+ const formattedTicketData = await formatTicketDataForGlpi(ticketData);
+ console.log('Dados do ticket formatados para GLPI:', formattedTicketData);
+
+ // const glpiTicket = await glpiModel.insertTicket(formattedTicketData);
+ // console.log('Ticket criado no GLPI:', glpiTicket);
+
+ // const updateSyncData = await hubglpiModel.update_syncData(glpiTicket.id, ticketData.id_atendimento);
+ // logInfo('Sync Data atualizado com o ID do ticket do GLPI:', updateSyncData);
+
+ } catch (error) {
+ console.error('Erro ao criar ticket no GLPI:', error);
+ // const updateSyncDataError = await //hubglpiModel.update_syncaDataError(error.message, ticketData.id_atendimento)
+ logError('Erro ao criar ticket no GLPI. Sync Data atualizado com a mensagem de erro: ', /*updateSyncDataError*/ error);
+ }
+};
+
+const processTicketFromHubSoft = async (atendimento) => {
+ const ticketData = {
+ id_atendimento: atendimento.id_atendimento,
+ id_atendimento_status: atendimento.id_atendimento_status,
+ codigo_servico: String(atendimento.id_cliente_servico || ''), // Garante que seja uma string
+ protocolo_hub: atendimento.protocolo,
+ servico_nome: atendimento.descricao,
+ descricao_abertura: atendimento.descricao_abertura,
+ data_cadastro: atendimento.data_cadastro,
+ cliente_nome: atendimento.nome_contato,
+ codigo_cliente: atendimento.codigo_cliente,
+ descricao: atendimento.descricao
+ };
+
+ ticketData.status_atendimento = statusAtendimentoHubGlpi[ticketData.id_atendimento_status] || ticketData.id_atendimento_status;
+
+ console.log(typeof ticketData.descricao_abertura)
+ console.log(ticketData.descricao_abertura)
+
+
+ ticketData.descricao_abertura = ticketData.descricao_abertura.replace(/[^0-9]/g, '');
+ ticketData.ticket_mundiale = parseInt(ticketData.descricao_abertura) || null;
+
+ return ticketData;
+};
+
+const saveTicketToHubGlpi = async (ticketData) => {
+ try {
+ const insertedTicket = await hubglpiModel.insertTicket(ticketData);
+ console.log('Ticket inserido/atualizado na tabela hubsoft_tickets:', insertedTicket);
+
+ const insertSyncData = await hubglpiModel.insertSyncData(ticketData.id_atendimento);
+ console.log('Dados inseridos/atualizados na tabela sync_data:', insertSyncData);
+
+ return insertedTicket;
+ } catch (error) {
+ console.error('Erro ao salvar ticket no hubglpi:', error);
+ throw error; // Rejeita a promise para que o erro seja tratado no nível superior
+ }
+};
+
+const processAtendimento = async (ticketData) => {
+ try {
+
+ await createGlpiTicket(ticketData);
+
+ } catch (error) {
+ console.error(`Erro ao processar atendimento ${id_atendimento}:`, error);
+ }
+};
+
+// ================================================================================
+// Função Principal (com opção de pular a etapa do HubSoft)
+// ================================================================================
+
+const processaAtendimentos = async (skipHubSoft = false) => {
+ try {
+ let atendimentosDB = [];
+
+ if (!skipHubSoft) {
+ // Esta parte depende da VPN
+ console.log('Buscando atendimentos do HubSoft...');
+ atendimentosDB = await hubsoftModel.getAtendimentosFromDB();
+ console.log(`Total de atendimentos obtidos do HubSoft: ${atendimentosDB.length}`);
+
+ for (const atendimento of atendimentosDB) {
+ try {
+ // Processa o ticket do HubSoft
+ const ticketData = await processTicketFromHubSoft(atendimento);
+ // Salva no banco intermediário (hubglpi)
+ await saveTicketToHubGlpi(ticketData);
+ }
+ catch (error) {
+ console.error(`Erro ao processar atendimento ${atendimento.id_atendimento}:`, error);
+ }
+ }
+
+ } else {
+ console.log('Pulando a busca de atendimentos do HubSoft (skipHubSoft = true).');
+ }
+
+ // Coletando atendimentos do banco intermediário (hubglpi)
+ atendimentosDB = await hubglpiModel.getTicketDataPending();
+
+
+ for (const atendimento of atendimentosDB) {
+ try {
+ // Processa o atendimento para o GLPI
+
+ console.log(atendimento.id_atendimento)
+ console.log(atendimento)
+ await processAtendimento(atendimento);
+
+ } catch (error) {
+ console.error(`Erro ao processar atendimento ${atendimento.id_atendimento}:`, error);
+ }
+ }
+
+ } catch (error) {
+ console.error('Erro ao processar atendimentos:', error);
+ }
+};
+
+module.exports = {
+ processaAtendimentos,
+ processAtendimento,
+ formatTicketDataForGlpi,
+ formatDescription
+};
\ No newline at end of file
diff --git a/model/glpiModel.js b/model/glpiModel.js
new file mode 100644
index 0000000..50510ac
--- /dev/null
+++ b/model/glpiModel.js
@@ -0,0 +1,77 @@
+// src/models/hubglpiModel.js
+const dbConfig = require('../config/dbConfig.js');
+const { logError, logInfo} = require('../utils/logger');
+
+const { Pool } = require('pg');
+const pool = new Pool({
+ host: dbConfig.glpi.databaseHost,
+ port: dbConfig.glpi.databasePort,
+ database: dbConfig.glpi.databaseName,
+ user: dbConfig.glpi.databaseUser,
+ password: dbConfig.glpi.databasePassword
+});
+
+
+class HubglpiModel {
+
+ static async insertTicket(ticketData) {
+
+ const query = `
+ INSERT INTO glpi_tickets(
+ entities_id,
+ name,
+ date,
+ date_mod,
+ status,
+ user_id_recipient,
+ content,
+ urgency,
+ impact,
+ priority,
+ type,
+ itilcategories_id,
+ date_creation,
+ slas_id_ttr
+ )
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
+ RETURNING *;
+ `;
+
+ const values = [
+ ticketData.entidades_id,
+ ticketData.cliente_nome,
+ ticketData.data_cadastro,
+ ticketData.date_mod,
+ ticketData.status_atendimento,
+ ticketData.user_id_recipient,
+ ticketData.descricao_abertura,
+ ticketData.urgency,
+ ticketData.impact,
+ ticketData.priority,
+ ticketData.type,
+ ticketData.itilcategories_id,
+ ticketData.date_creation,
+ ];
+
+
+ }
+
+ static async selectEntityId(entity_name) {
+
+ const query = `SELECT id FROM glpi_entities WHERE name = $1;`;
+ const values = [entity_name];
+
+ try {
+ const res = await pool.query
+ (query, values);
+ logInfo('Entidade encontrada:', res.rows[0]);
+ return res.rows[0];
+ } catch (err) {
+ logError('Erro ao buscar entidade', err);
+ throw err;
+ }
+
+ }
+}
+
+module.exports = HubglpiModel;
diff --git a/model/hubglpiModel.js b/model/hubglpiModel.js
index 8ed19d4..1813667 100644
--- a/model/hubglpiModel.js
+++ b/model/hubglpiModel.js
@@ -1,4 +1,5 @@
-// src/models/hubglpiModel.js
+// src/models/hubsoft_ticketsModel.js
+const { log } = require('winston');
const dbConfig = require('../config/dbConfig.js');
const { logError, logInfo} = require('../utils/logger');
@@ -14,86 +15,84 @@ const pool = new Pool({
class HubglpiModel {
- static async insertTicket(ticketData) {
- const query = `
- INSERT INTO hubsoft_tickets (
+ static async insertTicket(ticketData) {
+ const query = `
+ INSERT INTO hubsoft_tickets (
id_atendimento,
- codigo_cliente,
- status_atendimento,
+ codigo_cliente,
+ status_atendimento,
+ codigo_servico,
servico_nome,
protocolo_hub,
ticket_mundiale,
cliente_nome,
created_at
- )
- VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
- RETURNING *;
- `;
-
- // Criando dicionario para traduzir status de atendimento
- const statusAtendimentoMap = {
- 1 : 'Pendente',
- 2 : 'Em atendimento',
- 3 : 'Resolvido',
- 31 : 'Pendente',
- 32 : 'Pendente',
- 33 : 'Novo'};
-
- // Substituindo o status do atendimento pelo valor correspondente
- const status_atendimento = statusAtendimentoMap[ticketData.id_atendimento_status] || ticketData.id_atendimento_status;
+ )
+ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
+ ON CONFLICT (id_atendimento)
+ DO UPDATE SET
+ codigo_cliente = $2,
+ status_atendimento = $3,
+ codigo_servico = $4,
+ servico_nome = $5,
+ protocolo_hub = $6,
+ ticket_mundiale = $7,
+ cliente_nome = $8,
+ created_at = $9
+ RETURNING *;
+ `;
- // Limpando todos os caracteres que não sao numeros e convertendo ticket_mundiale para int
- ticketData.descricao_abertura = ticketData.descricao_abertura.replace(/[^0-9]/g, '');
- ticketData.ticket_mundiale = parseInt(ticketData.descricao_abertura) || null;
+ const values = [
+ ticketData.id_atendimento,
+ ticketData.codigo_cliente,
+ ticketData.status_atendimento,
+ ticketData.codigo_servico,
+ ticketData.servico_nome,
+ ticketData.protocolo_hub,
+ ticketData.ticket_mundiale,
+ ticketData.cliente_nome,
+ ticketData.data_cadastro
+ ];
- ticketData.codigo_cliente = parseInt(ticketData.codigo_cliente) || null;
+ console.log('Executando query de inserção/atualização na tabela hubsoft_tickets:', query, values);
-
- const values = [
- ticketData.id_atendimento,
- ticketData.codigo_cliente,
- status_atendimento,
- ticketData.descricao,
- ticketData.protocolo_hub,
- ticketData.ticket_mundiale,
- ticketData.cliente_nome,
- ticketData.data_cadastro
- ];
-
- console.log('Valores para inserção do ticket:', values);
-
-
- try {
- const res = await pool.query(query, values);
- logInfo('Ticket Inserido na tabela hubsoft_tickets com sucesso:', res.rows[0]);
- return res.rows[0];
- } catch (err) {
- logError('Erro ao inserir ticket na tabela hubsoft_tickets', err);
- throw err;
- }
-
+ try {
+ const res = await pool.query(query, values);
+ logInfo('Ticket Inserido/Atualizado na tabela hubsoft_tickets com sucesso:', res.rows[0]);
+ return res.rows[0];
+ } catch (err) {
+ logError('Erro ao inserir/atualizar ticket na tabela hubsoft_tickets', err);
+ throw err;
}
+}
+
static async insertSyncData(syncData) {
- const query = `
- INSERT INTO sync_data (
- hubsoft_ticket_id
- )VALUES ($1)
- RETURNING *;
- `;
- const values = [
- syncData
- ];
- try {
- const res = await pool.query(query, values);
- logInfo('Dados inseridos na tabela sync_data com sucesso:', res.rows[0]);
- return res.rows[0];
- } catch (err) {
- logError('Erro ao inserir dados na tabela sync_data', err);
- throw err;
- }
+
+ const query = `
+ INSERT INTO sync_data (
+ hubsoft_ticket_id
+ )
+ VALUES ($1)
+ ON CONFLICT (hubsoft_ticket_id)
+ DO UPDATE SET
+ hubsoft_ticket_id = $1
+ RETURNING *;
+ `;
+ const values = [
+ syncData
+ ];
+
+ try {
+ const res = await pool.query(query, values);
+ logInfo('Dados inseridos/atualizados na tabela sync_data com sucesso:', res.rows[0]);
+ return res.rows[0];
+ } catch (err) {
+ logError('Erro ao inserir/atualizar dados na tabela sync_data', err);
+ throw err;
+ }
}
static async update_syncData(sync_update) {
@@ -165,9 +164,26 @@ class HubglpiModel {
}
}
+
+ static async getTicketDataPending() {
+ const query = ` SELECT ht.id_atendimento, ht.codigo_cliente, ht.status_atendimento, ht.codigo_servico, ht.servico_nome, ht.protocolo_hub, ht.ticket_mundiale, ht.cliente_nome, ht.created_at, sd.id AS sync_data_id, sd.glpi_ticket_id, sd.status_sync, sd.sync_metadata, sd.last_sync_attempt, sd.sync_error_message, sd.created_at AS sync_created_at, sd.updated_at AS sync_updated_at
+ FROM hubsoft_tickets AS ht
+ LEFT JOIN sync_data AS sd ON ht.id_atendimento = sd.hubsoft_ticket_id
+ WHERE sd.status_sync IS NULL OR sd.status_sync = 'pending_create'
+ ORDER BY ht.created_at ASC; `;
+
+ try {
+ const res = await pool.query(query);
+ logInfo('Tickets pendentes obtidos com sucesso:', res.rows);
+ return res.rows;
+ } catch (err) {
+ logError('Erro ao obter tickets pendentes', err);
+ throw err;
+
+ }
+
+ }
}
-
-
module.exports = HubglpiModel;
diff --git a/model/hubsoftModel.js b/model/hubsoftModel.js
index 42cbf27..6812bec 100644
--- a/model/hubsoftModel.js
+++ b/model/hubsoftModel.js
@@ -10,7 +10,7 @@ const pool = new Pool({
});
const getAtendimentosFromDB = async () => {
- const query = 'SELECT a.id_atendimento, a.id_usuario_abertura, a.id_atendimento_status, a.protocolo, a.descricao_abertura, a.data_cadastro, a.nome_contato, c.codigo_cliente, s.descricao FROM atendimento AS a INNER JOIN cliente_servico AS cs ON a.id_cliente_servico = cs.id_cliente_servico INNER JOIN cliente AS c ON cs.id_cliente = c.id_cliente INNER JOIN servico AS s ON cs.id_servico = s.id_servico WHERE a.id_tipo_atendimento = 4 AND a.id_usuario_abertura = 248 AND a.id_atendimento_status IN (1, 2, 33) AND s.ativo = true;';
+ const query = 'SELECT a.id_atendimento, a.id_usuario_abertura, a.id_atendimento_status, a.protocolo, a.descricao_abertura, a.data_cadastro, a.nome_contato, c.codigo_cliente, s.descricao, cs.id_cliente_servico FROM atendimento AS a INNER JOIN cliente_servico AS cs ON a.id_cliente_servico = cs.id_cliente_servico INNER JOIN cliente AS c ON cs.id_cliente = c.id_cliente INNER JOIN servico AS s ON cs.id_servico = s.id_servico WHERE a.id_tipo_atendimento = 4 AND a.id_usuario_abertura = 248 AND a.id_atendimento_status IN (1, 2, 33) AND s.ativo = true;';
const { rows } = await pool.query(query);
return rows;
diff --git a/model/sync_dataModel.js b/model/sync_dataModel.js
deleted file mode 100644
index e69de29..0000000