FEAT: Chamados de implantação agora são criados automaticamente
This commit is contained in:
parent
4b2d26e469
commit
692ad0b583
@ -46,3 +46,4 @@ GLPI_DB_USER=
|
|||||||
GLPI_DB_PASSWORD=
|
GLPI_DB_PASSWORD=
|
||||||
GLPI_DB_NAME=glpi_data
|
GLPI_DB_NAME=glpi_data
|
||||||
GLPI_DB_CHARSET=utf8mb4
|
GLPI_DB_CHARSET=utf8mb4
|
||||||
|
GLPI_USER_ID=
|
||||||
@ -2,7 +2,7 @@
|
|||||||
const hubsoftModel = require('../model/hubsoftModel.js');
|
const hubsoftModel = require('../model/hubsoftModel.js');
|
||||||
const hubglpiModel = require('../model/hubglpiModel.js');
|
const hubglpiModel = require('../model/hubglpiModel.js');
|
||||||
const glpiModel = require('../model/glpiModel.js');
|
const glpiModel = require('../model/glpiModel.js');
|
||||||
const { logError, logInfo } = require('../utils/logger');
|
const { logError, logInfo } = require('../shared/utils/logger.js');
|
||||||
|
|
||||||
|
|
||||||
// ================================================================================
|
// ================================================================================
|
||||||
|
|||||||
@ -2,7 +2,7 @@ const loadEnv = require('./config/envLoader');
|
|||||||
loadEnv();
|
loadEnv();
|
||||||
|
|
||||||
const cron = require('node-cron');
|
const cron = require('node-cron');
|
||||||
const { processaAtendimentos } = require('./controller/processController.js');
|
const { processAtendimentos}= require('./modules/createTickets/controller/createTickets.controller.js');
|
||||||
const commentService = require('./services/commentService.js'); // 1. Importar o novo serviço
|
const commentService = require('./services/commentService.js'); // 1. Importar o novo serviço
|
||||||
const { logInfo, logError } = require('./utils/logger.js');
|
const { logInfo, logError } = require('./utils/logger.js');
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ cron.schedule('* * * * *', async () => {
|
|||||||
try {
|
try {
|
||||||
// --- Tarefa 1: Sincronizar criação de tickets ---
|
// --- Tarefa 1: Sincronizar criação de tickets ---
|
||||||
logInfo('CRON (Etapa 1/2): Processando criação de tickets...');
|
logInfo('CRON (Etapa 1/2): Processando criação de tickets...');
|
||||||
await processaAtendimentos();
|
await processAtendimentos();
|
||||||
logInfo('CRON (Etapa 1/2): Criação de tickets concluída.');
|
logInfo('CRON (Etapa 1/2): Criação de tickets concluída.');
|
||||||
|
|
||||||
// --- Tarefa 2: Sincronizar comentários ---
|
// --- Tarefa 2: Sincronizar comentários ---
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// src/models/glpiModel.js
|
// src/models/glpiModel.js
|
||||||
const dbConfig = require('../config/dbConfig.js');
|
const dbConfig = require('../config/dbConfig.js');
|
||||||
const { logError, logInfo} = require('../utils/logger');
|
const { logError, logInfo} = require('../utils/logger.js');
|
||||||
const mysql = require('mysql2/promise');
|
const mysql = require('mysql2/promise');
|
||||||
|
|
||||||
const pool = mysql.createPool({
|
const pool = mysql.createPool({
|
||||||
@ -63,7 +63,6 @@ class GlpiModel {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async selectEntityIdCodCliente(id) {
|
static async selectEntityIdCodCliente(id) {
|
||||||
|
|
||||||
const query = `SELECT id FROM glpi_entities WHERE name LIKE ? LIMIT 1;`;
|
const query = `SELECT id FROM glpi_entities WHERE name LIKE ? LIMIT 1;`;
|
||||||
@ -85,7 +84,6 @@ class GlpiModel {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async selectEntityIdCodServico(idCliente, idServico) {
|
static async selectEntityIdCodServico(idCliente, idServico) {
|
||||||
|
|
||||||
const query = `SELECT id FROM glpi_entities WHERE name LIKE ? LIMIT 1;`;
|
const query = `SELECT id FROM glpi_entities WHERE name LIKE ? LIMIT 1;`;
|
||||||
@ -107,7 +105,6 @@ class GlpiModel {
|
|||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async insertGroupTickets(glpiTicketId) {
|
static async insertGroupTickets(glpiTicketId) {
|
||||||
const query = `
|
const query = `
|
||||||
INSERT INTO glpi_groups_tickets (tickets_id, groups_id, type)
|
INSERT INTO glpi_groups_tickets (tickets_id, groups_id, type)
|
||||||
@ -122,18 +119,18 @@ class GlpiModel {
|
|||||||
logError(`Erro ao Adicionar Grupo Operação NOC: ${err}`);
|
logError(`Erro ao Adicionar Grupo Operação NOC: ${err}`);
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
static async insertComment(commentData) {
|
||||||
|
const query = `INSERT INTO glpi_itilfollowups(itemtype, items_id, date, users_id, content, date_creation, date_mod) VALUES('Ticket',? , NOW(), ?, ?, NOW(), NOW())`;
|
||||||
|
const values = [commentData.tickets_id, parseInt(process.env.GLPI_USER_ID), commentData.content];
|
||||||
|
try {
|
||||||
|
const [rows] = await pool.query(query, values);
|
||||||
|
return rows && rows.insertId ? { id: rows.insertId } : null;
|
||||||
}
|
}
|
||||||
static async insertComment(commentData) {
|
catch (err) {
|
||||||
const query = `INSERT INTO glpi_itilfollowups(itemtype, items_id, date, users_id, content, date_creation, date_mod) VALUES('Ticket',? , NOW(), ?, ?, NOW(), NOW())`;
|
logError(`Erro ao inserir comentário no GLPI: ${err}`);
|
||||||
const values = [commentData.tickets_id, parseInt(process.env.GLPI_USER), commentData.content];
|
throw err;
|
||||||
try {
|
|
||||||
const [rows] = await pool.query(query, values);
|
|
||||||
return rows && rows.insertId ? { id: rows.insertId } : null;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
logError(`Erro ao inserir comentário no GLPI: ${err}`);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
module.exports = GlpiModel;
|
module.exports = GlpiModel;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
const dbConfig = require('../config/dbConfig.js');
|
const dbConfig = require('../config/dbConfig.js');
|
||||||
const { logError, logInfo } = require('../utils/logger');
|
const { logError, logInfo } = require('../utils/logger.js');
|
||||||
|
|
||||||
const hubsoftDbConfig = {
|
const hubsoftDbConfig = {
|
||||||
host: dbConfig.hubsoft.databaseHost,
|
host: dbConfig.hubsoft.databaseHost,
|
||||||
|
|||||||
@ -1,46 +1,51 @@
|
|||||||
// src/modules/createTickets/controller/createTickets.controller.js
|
// src/modules/createTickets/controller/createTickets.controller.js
|
||||||
const mundialeService = require('../services/mundiale.service.js');
|
const mundialeService = require('../services/mundiale.service.js');
|
||||||
const implantacaoService = require('../services/implantacao.service.js');
|
const implantacaoService = require('../services/implantacao.service.js');
|
||||||
const appMobileService = require('../services/appMobile.service.js');
|
const sacService = require('../services/sac.service.js');
|
||||||
const ticketShared = require('../services/createTickets.service.js');
|
const ticketShared = require('../services/createTickets.service.js');
|
||||||
|
|
||||||
const { logInfo } = require('../../utils/logger.js');
|
const { logInfo } = require('../../../utils/logger.js');
|
||||||
|
|
||||||
async function processaAtendimentos() {
|
async function processAtendimentos() {
|
||||||
logInfo("[CONTROLLER] Iniciando processamento");
|
logInfo("[CONTROLLER] Iniciando processamento");
|
||||||
|
|
||||||
// 1️⃣ Buscar por fonte
|
// 1️⃣ Buscar por fonte
|
||||||
const mundiale = await mundialeService.fetchNew();
|
const mundiale = await mundialeService.fetchNew();
|
||||||
|
logInfo(`Encontrados ${mundiale.length} tickets Mundiale para processar.`);
|
||||||
const implantacao = await implantacaoService.fetchNew();
|
const implantacao = await implantacaoService.fetchNew();
|
||||||
const app = await appMobileService.fetchNew();
|
logInfo(`Encontrados ${implantacao.length} tickets de Implantação para processar.`);
|
||||||
|
//const sac = await sacService.fetchNew();
|
||||||
|
|
||||||
// 2️⃣ Salvar no hubglpi
|
// 2️⃣ Salvar no hubglpi
|
||||||
await mundialeService.saveHubGlpi(mundiale);
|
await mundialeService.saveHubGlpi(mundiale);
|
||||||
await implantacaoService.saveHubglpi(implantacao);
|
await implantacaoService.saveHubGlpi(implantacao);
|
||||||
await appMobileService.saveHubglpi(app);
|
//await sacService.saveHubGlpi(sac);
|
||||||
|
|
||||||
// 3️⃣ Buscar pendentes que foram salvos no banco hubglpi
|
// 3️⃣ Buscar pendentes que foram salvos no banco hubglpi
|
||||||
const pendentes = await ticketShared.buscarPendentesHubglpi();
|
const pendentes = await ticketShared.fetchPendingTickets();
|
||||||
|
|
||||||
// 4️⃣ Roteamento por tipo
|
// 4️⃣ Roteamento por tipo
|
||||||
for (const ticket of pendentes) {
|
for (const ticket of pendentes) {
|
||||||
|
|
||||||
if (ticket.ticket_type === 'MUNDIALE') {
|
if (ticket.ticket_type === 'MUNDIALE') {
|
||||||
await mundialeService.sendToGlpi(ticket);
|
await mundialeService.sendToGlpi(ticket);
|
||||||
|
|
||||||
} else if (ticket.ticket_type === 'IMPLANTACAO') {
|
} else if (ticket.ticket_type === 'IMPLANTACAO') {
|
||||||
await implantacaoService.sendToGlpi(ticket);
|
await implantacaoService.sendToGlpi(ticket);
|
||||||
|
|
||||||
} else if (ticket.ticket_type === 'APP_MOBILE') {
|
} else if (ticket.ticket_type === 'SAC') {
|
||||||
await appMobileService.sendToGlpi(ticket);
|
await sacService.sendToGlpi(ticket);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
logInfo(`Tipo desconhecido, ignorando ticket id=${ticket.id}`);
|
logInfo(`Tipo desconhecido, ignorando ticket id=${ticket.id}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
await ticketShared.marcarComoProcessado(ticket.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logInfo("[CONTROLLER] Finalizado.");
|
logInfo("[CONTROLLER] Finalizado.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = { processAtendimentos };
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,18 @@
|
|||||||
// src/modules/createTickets/services/createTickets.service.js
|
// src/modules/createTickets/services/createTickets.service.js
|
||||||
const repositoryHubGlpi = require('../../../shared/repositories/hubglpi.repository.js');
|
const repositoryHubGlpi = require('../../../shared/repositories/hubglpi.repository.js');
|
||||||
|
const repositoryGlpi = require('../../../shared/repositories/glpi.repository.js');
|
||||||
|
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
// Funções principais do serviço
|
// Funções principais do serviço
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
|
|
||||||
async function fetcPendingTickets() {
|
async function fetchPendingTickets() {
|
||||||
return repositoryHubGlpi.fetchPendingTickets();
|
return repositoryHubGlpi.fetchPendingTickets();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resolveEntityId(ticketData, glpiModel) {
|
async function resolveEntityId(ticketData) {
|
||||||
|
|
||||||
const entityByService = await glpiModel.selectEntityIdCodServico(
|
const entityByService = await repositoryGlpi.getEntitiesByService(
|
||||||
ticketData.codigo_cliente,
|
ticketData.codigo_cliente,
|
||||||
ticketData.codigo_servico
|
ticketData.codigo_servico
|
||||||
);
|
);
|
||||||
@ -21,8 +22,7 @@ async function resolveEntityId(ticketData, glpiModel) {
|
|||||||
return ticketData;
|
return ticketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tenta entidade pelo cliente
|
const entityByClient = await repositoryGlpi.getEntitiesByClient(
|
||||||
const entityByClient = await glpiModel.selectEntityIdCodCliente(
|
|
||||||
ticketData.codigo_cliente
|
ticketData.codigo_cliente
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -31,14 +31,30 @@ async function resolveEntityId(ticketData, glpiModel) {
|
|||||||
return ticketData;
|
return ticketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback
|
|
||||||
ticketData.entities_id = 0;
|
ticketData.entities_id = 0;
|
||||||
return ticketData;
|
return ticketData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Funcao para definir ticket como processado
|
||||||
|
async function setAsCreated(dataTicket) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Cria uma nova entidade no GLPI
|
||||||
|
async function createEntity(ticketData) {
|
||||||
|
|
||||||
|
const entity_name = `${ticketData.codigo_cliente} - ${ticketData.nome_razao_social}`;
|
||||||
|
|
||||||
|
await repositoryGlpi.insertEntity(entity_name);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fetcPendingTickets,
|
fetchPendingTickets,
|
||||||
resolveEntityId
|
resolveEntityId,
|
||||||
|
setAsCreated,
|
||||||
|
createEntity
|
||||||
}
|
}
|
||||||
@ -0,0 +1,254 @@
|
|||||||
|
// src/modules/createTickets/services/mundiale.service.js
|
||||||
|
const repositoryHubGlpi = require('../../../shared/repositories/hubglpi.repository.js');
|
||||||
|
const repositoryGlpi = require('../../../shared/repositories/glpi.repository.js');
|
||||||
|
const repositoryHubsoft = require('../../../shared/repositories/hubsoft.repository.js');
|
||||||
|
const modelHubGlpi = require('../../../shared/model/hubglpi.model.js');
|
||||||
|
const modelGlpi = require('../../../shared/model/glpi.model.js');
|
||||||
|
const ticketShared = require('./createTickets.service.js');
|
||||||
|
const { logInfo, logWarning } = require('../../../utils/logger.js');
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Funções principais do serviço
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
async function fetchNew() {
|
||||||
|
return repositoryHubsoft.getImplantacaoTickets();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveHubGlpi(tickets) {
|
||||||
|
if (!tickets.length) return;
|
||||||
|
|
||||||
|
const ticketsFormatted = tickets.map(ticket =>
|
||||||
|
modelHubGlpi.mapHubsoftToHubglpi(ticket, 'IMPLANTACAO')
|
||||||
|
);
|
||||||
|
|
||||||
|
const inserted = await repositoryHubGlpi.insertTickets(ticketsFormatted);
|
||||||
|
|
||||||
|
if (inserted) {
|
||||||
|
await repositoryHubGlpi.insertSyncData(
|
||||||
|
ticketsFormatted.map(ticket => ticket.id_atendimento)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return inserted;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendToGlpi(ticket) {
|
||||||
|
|
||||||
|
const ticketsResolved = await ticketShared.resolveEntityId(ticket);
|
||||||
|
|
||||||
|
if (ticketsResolved.entities_id === 0) {
|
||||||
|
logWarning(`Entidade não encontrada para o ticket id=${ticket.id_atendimento}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
formatGlpiPayload(ticketsResolved);
|
||||||
|
|
||||||
|
const payload = modelGlpi.mapHubGlpiToGlpi(ticketsResolved);
|
||||||
|
|
||||||
|
const glpiId = await repositoryGlpi.insertTicket(payload);
|
||||||
|
logInfo(`Ticket GLPI criado com ID=${glpiId} para o ticket id=${ticket.id_atendimento}.`);
|
||||||
|
|
||||||
|
await repositoryGlpi.insertGroupTicket(glpiId);
|
||||||
|
await repositoryHubGlpi.updateSyncDataCreated(ticket.id_atendimento, glpiId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Formatar dados antes de enviar para o GLPI
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
function formatGlpiPayload(ticket) {
|
||||||
|
const title = `IMPLANTAÇÃO - ${ticket.codigo_cliente}-${ticket.codigo_servico}-${ticket.cliente_nome} - ${ticket.servico_nome}`;
|
||||||
|
const description = formatDescription(ticket);
|
||||||
|
ticket.name = title;
|
||||||
|
ticket.content = description;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Dicionário de Serviços
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
const serviceDictionary = {
|
||||||
|
// ---------- LAN-TO-LAN ----------
|
||||||
|
"Lan-to-Lan 50 Mbps": { produto: "Lan-to-Lan", qtd: 1, descricao: "50 Mbps" },
|
||||||
|
"Lan-to-Lan 100 Mbps": { produto: "Lan-to-Lan", qtd: 1, descricao: "100 Mbps" },
|
||||||
|
"Lan-to-Lan 200 Mbps": { produto: "Lan-to-Lan", qtd: 1, descricao: "200 Mbps" },
|
||||||
|
"Lan-to-Lan 300 Mbps": { produto: "Lan-to-Lan", qtd: 1, descricao: "300 Mbps" },
|
||||||
|
"Lan-to-Lan 500 Mbps": { produto: "Lan-to-Lan", qtd: 1, descricao: "500 Mbps" },
|
||||||
|
"Lan-to-Lan 700 Mbps": { produto: "Lan-to-Lan", qtd: 1, descricao: "700 Mbps" },
|
||||||
|
"Lan-to-Lan": { produto: "Lan-to-Lan", qtd: 1, descricao: null },
|
||||||
|
|
||||||
|
// ---------- LINK DEDICADO ----------
|
||||||
|
"Link de Internet Dedicado 20 Mbps Full Duplex":
|
||||||
|
{ produto: "Link de Internet Dedicado", qtd: 1, descricao: "20 Mbps Full Duplex" },
|
||||||
|
|
||||||
|
"Link de Internet Dedicado 100 Mbps Full Duplex":
|
||||||
|
{ produto: "Link de Internet Dedicado", qtd: 1, descricao: "100 Mbps Full Duplex" },
|
||||||
|
|
||||||
|
"Link de Internet Dedicado 1Gbps Full Duplex":
|
||||||
|
{ produto: "Link de Internet Dedicado", qtd: 1, descricao: "1 Gbps Full Duplex" },
|
||||||
|
|
||||||
|
"Link de Internet Dedicado 2 Gbps Full Duplex":
|
||||||
|
{ produto: "Link de Internet Dedicado", qtd: 1, descricao: "2 Gbps Full Duplex" },
|
||||||
|
|
||||||
|
// Default genérico caso venha coisa nova
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Tabela HTML da descrição
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
const formatDescription = (ticket) => {
|
||||||
|
|
||||||
|
const documentoFormatado = formatDocument(ticket.cpf_cnpj, ticket.tipo_pessoa);
|
||||||
|
const docLabel = ticket.tipo_pessoa === "pf" ? "CPF" : "CNPJ";
|
||||||
|
const servico = resolveService(ticket.servico_nome);
|
||||||
|
|
||||||
|
return `
|
||||||
|
<table style="width:100%; border-collapse: collapse;">
|
||||||
|
|
||||||
|
<!-- ===== CABEÇALHO DADOS COMERCIAL ===== -->
|
||||||
|
<tr style="background-color:#f2f2f2;">
|
||||||
|
<th colspan="2" style="padding: 8px; border: 1px solid #ddd; text-align:left;">
|
||||||
|
Dados Comercial
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Nº de Operação</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.protocolo_hub || "N/A"}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Gerente Responsável</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.usuario_que_abriu || "N/A"}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Código do Cliente</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.codigo_cliente}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- ===== CABEÇALHO DADOS CLIENTE ===== -->
|
||||||
|
<tr style="background-color:#f2f2f2;">
|
||||||
|
<th colspan="2" style="padding: 8px; border: 1px solid #ddd; text-align:left;">
|
||||||
|
Dados Cliente
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Cliente</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.cliente_nome}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>${docLabel}</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${documentoFormatado}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Nome Contato</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.nome_razaosocial || "N/A"}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Email Contato</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.email || "N/A"}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Telefone Contato</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.telefone || "N/A"}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Endereço Instalação</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.endereco || "N/A"}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- ===== CABEÇALHO DADOS DO SERVIÇO ===== -->
|
||||||
|
<tr style="background-color:#f2f2f2;">
|
||||||
|
<th colspan="2" style="padding: 8px; border: 1px solid #ddd; text-align:left;">
|
||||||
|
Dados do Serviço Contratado
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" style="padding: 0; border: 1px solid #ddd;">
|
||||||
|
<table style="width:100%; border-collapse: collapse;">
|
||||||
|
<tr style="background-color:#fafafa;">
|
||||||
|
<th style="padding: 8px; border: 1px solid #ddd; text-align:left;">Produto</th>
|
||||||
|
<th style="padding: 8px; border: 1px solid #ddd; text-align:left;">Quantidade</th>
|
||||||
|
<th style="padding: 8px; border: 1px solid #ddd; text-align:left;">Descrição</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${servico.produto}</td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${servico.qtd}</td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${servico.descricao || ""}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<!-- ===== OBSERVAÇÕES ===== -->
|
||||||
|
<tr style="background-color:#f2f2f2;">
|
||||||
|
<th colspan="2" style="padding: 8px; border: 1px solid #ddd; text-align:left;">
|
||||||
|
Observações
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td colspan="2" style="padding: 8px; border: 1px solid #ddd;">${ticket.descricao_abertura || "N/A"}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Formatadores de Documento
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
function formatCPF(cpf) {
|
||||||
|
cpf = cpf.replace(/\D/g, "");
|
||||||
|
return cpf.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, "$1.$2.$3-$4");
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCNPJ(cnpj) {
|
||||||
|
cnpj = cnpj.replace(/\D/g, "");
|
||||||
|
return cnpj.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, "$1.$2.$3/$4-$5");
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDocument(doc, tipo) {
|
||||||
|
if (!doc) return "N/A";
|
||||||
|
return tipo === "pf" ? formatCPF(doc) : formatCNPJ(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Resolve Serviço
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
function resolveService(servicoNome) {
|
||||||
|
return serviceDictionary[servicoNome] || {
|
||||||
|
produto: servicoNome,
|
||||||
|
qtd: 1,
|
||||||
|
descricao: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Exportação
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchNew,
|
||||||
|
saveHubGlpi,
|
||||||
|
sendToGlpi
|
||||||
|
};
|
||||||
@ -1,11 +1,12 @@
|
|||||||
// src/modules/createTickets/services/mundiale.service.js
|
// src/modules/createTickets/services/mundiale.service.js
|
||||||
const repositoryHubGlpi = require('../../../shared/repositories/hubglpi.repository.js');
|
const repositoryHubGlpi = require('../../../shared/repositories/hubglpi.repository.js');
|
||||||
const repositoryGlpi = require('../../../repositories/glpi.repository.js');
|
const repositoryGlpi = require('../../../shared/repositories/glpi.repository.js');
|
||||||
const repositoryHubsoft = require('../../../shared/repositories/hubsoft.repository.js');
|
const repositoryHubsoft = require('../../../shared/repositories/hubsoft.repository.js');
|
||||||
const modelHubGlpi = require('../../../shared/model/hubglpi.model.js');
|
const modelHubGlpi = require('../../../shared/model/hubglpi.model.js');
|
||||||
const modelGlpi = require('../../../shared/model/glpi.model.js');
|
const modelGlpi = require('../../../shared/model/glpi.model.js');
|
||||||
const ticketShared = require('./createTickets.service.js');
|
const ticketShared = require('./createTickets.service.js');
|
||||||
const { logInfo, logError, logWarning } = require('../../../utils/logger.js');
|
const { logInfo, logError, logWarning } = require('../../../utils/logger.js');
|
||||||
|
const { log } = require('winston');
|
||||||
|
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
// Funções principais do serviço
|
// Funções principais do serviço
|
||||||
@ -31,18 +32,36 @@ async function saveHubGlpi(tickets) {
|
|||||||
|
|
||||||
async function sendToGlpi(ticket) {
|
async function sendToGlpi(ticket) {
|
||||||
|
|
||||||
const ticketsResolved = await ticketShared.resolveEntityId(ticket, modelGlpi);
|
const ticketsResolved = await ticketShared.resolveEntityId(ticket);
|
||||||
|
|
||||||
const formattedTickets = formatGlpiPayload(ticketsResolved);
|
formatGlpiPayload(ticketsResolved);
|
||||||
|
|
||||||
const payload = modelGlpi.mapHubGlpiToGlpi(formattedTickets);
|
const payload = modelGlpi.mapHubGlpiToGlpi(ticketsResolved);
|
||||||
|
|
||||||
|
const glpiId = await repositoryGlpi.insertTicket(payload);
|
||||||
|
logInfo(`Ticket GLPI criado com ID: ${glpiId} para ticket Hubsoft ID: ${ticket.id_atendimento}`);
|
||||||
|
|
||||||
|
await repositoryGlpi.insertGroupTicket(glpiId);
|
||||||
|
logInfo(`Grupo padrão atribuído ao ticket GLPI ID: ${glpiId}`);
|
||||||
|
|
||||||
|
await repositoryHubGlpi.updateSyncDataCreated(ticket.id_atendimento, glpiId);
|
||||||
|
logInfo(`Ticket HubGlpi ID: ${ticket.id_atendimento} marcado como criado no Banco intermediario com ID: ${glpiId}`);
|
||||||
|
|
||||||
const glpiId = await repositoryGlpi.insertTickets([payload]);
|
|
||||||
|
|
||||||
await repositoryHubGlpi.updateSyncDataCreated(ticket.id_atendimento, glpiId[0]);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Mapeamento e formatação de dados
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
const statusAtendimentoGLPI = {
|
||||||
|
'Novo': 1,
|
||||||
|
'Pendente': 4,
|
||||||
|
'Em atendimento': 2,
|
||||||
|
'Resolvido': 5
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------
|
// --------------------------------------
|
||||||
// Formatar dados antes de enviar para o GLPI
|
// Formatar dados antes de enviar para o GLPI
|
||||||
@ -50,22 +69,14 @@ async function sendToGlpi(ticket) {
|
|||||||
|
|
||||||
function formatGlpiPayload(ticket) {
|
function formatGlpiPayload(ticket) {
|
||||||
|
|
||||||
const statusTexto = statusAtendimentoHubGlpi[ticket.status_atendimento] || 'Novo';
|
ticket.status = statusAtendimentoGLPI[ticket.status_atendimento] || 1;
|
||||||
const statusGlpi = statusAtendimentoGLPI[statusTexto] || 1;
|
|
||||||
|
|
||||||
const categoria = categoriaGLPI[ticket.servico_nome] || 0;
|
ticket.name = `Mundiale - Protocolo: ${ticket.ticket_mundiale} - ${ticket.cliente_nome}`;
|
||||||
|
|
||||||
const title = `[Mundiale] ${ticket.cliente_nome} - ${ticket.servico_nome} - ${ticket.ticket_mundiale}`;
|
ticket.content = formatDescription(ticket);
|
||||||
|
|
||||||
const description = formatDescription(ticket);
|
|
||||||
|
|
||||||
return {
|
return;
|
||||||
name: title,
|
|
||||||
content: description,
|
|
||||||
status: statusGlpi,
|
|
||||||
itilcategories_id: categoria,
|
|
||||||
created_at: ticket.created_at,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -89,7 +89,18 @@ INSERT INTO sync_control (job_name, last_run_timestamp) VALUES ('hubsoft_comment
|
|||||||
-- ALTERAÇÕES NA TABELA hubsoft_tickets
|
-- ALTERAÇÕES NA TABELA hubsoft_tickets
|
||||||
-- =============================================
|
-- =============================================
|
||||||
ALTER TABLE hubsoft_tickets
|
ALTER TABLE hubsoft_tickets
|
||||||
ADD COLUMN ticket_type VARCHAR(50) NOT NULL DEFAULT 'MUNDIALE';
|
ADD COLUMN ticket_type VARCHAR(50) NOT NULL DEFAULT 'MUNDIALE',
|
||||||
|
ADD COLUMN ticket_type VARCHAR(50),
|
||||||
|
ADD COLUMN descricao_abertura TEXT;
|
||||||
|
ADD COLUMN endereco TEXT,
|
||||||
|
ADD COLUMN telefone VARCHAR(25),
|
||||||
|
ADD COLUMN cpf_cnpj VARCHAR(30),
|
||||||
|
ADD COLUMN tipo_pessoa CHAR(2),
|
||||||
|
ADD COLUMN email VARCHAR(150),
|
||||||
|
ADD COLUMN nome_razaosocial VARCHAR(255);;
|
||||||
|
|
||||||
ALTER TABLE hubsoft_tickets
|
ALTER TABLE hubsoft_tickets
|
||||||
ADD CONSTRAINT hubsoft_id_atendimento_unique UNIQUE (id_atendimento);
|
ADD CONSTRAINT hubsoft_id_atendimento_unique UNIQUE (id_atendimento);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
17
src/shared/infra/database/glpi.pool.js
Normal file
17
src/shared/infra/database/glpi.pool.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// src/shared/infra/database/glpi.pool.js
|
||||||
|
// MySQL / MariaDB - GLPI
|
||||||
|
const mysql = require('mysql2/promise');
|
||||||
|
const { Pool } = require('pg');
|
||||||
|
|
||||||
|
const pool = mysql.createPool({
|
||||||
|
host: process.env.GLPI_DB_HOST,
|
||||||
|
port: process.env.GLPI_DB_PORT,
|
||||||
|
user: process.env.GLPI_DB_USER,
|
||||||
|
password: process.env.GLPI_DB_PASSWORD,
|
||||||
|
database: process.env.GLPI_DB_NAME,
|
||||||
|
waitForConnections: true,
|
||||||
|
connectionLimit: 20,
|
||||||
|
queueLimit: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = pool;
|
||||||
15
src/shared/infra/database/hubglpi.pool.js
Normal file
15
src/shared/infra/database/hubglpi.pool.js
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// src/shared/infra/database/hubglpi.pool.js
|
||||||
|
// PostgreSQL - HUBSOFT
|
||||||
|
const { Pool } = require("pg");
|
||||||
|
|
||||||
|
const hubglpiPool = new Pool({
|
||||||
|
host: process.env.HUBGLPI_DB_HOST,
|
||||||
|
port: process.env.HUBGLPI_DB_PORT,
|
||||||
|
user: process.env.HUBGLPI_DB_USER,
|
||||||
|
password: process.env.HUBGLPI_DB_PASSWORD,
|
||||||
|
database: process.env.HUBGLPI_DB_NAME,
|
||||||
|
max: 20,
|
||||||
|
idleTimeoutMillis: 30000,
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = hubglpiPool;
|
||||||
14
src/shared/infra/database/hubsoft.pool.js
Normal file
14
src/shared/infra/database/hubsoft.pool.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// PostgreSQL - HUBSOFT
|
||||||
|
const { Pool } = require("pg");
|
||||||
|
|
||||||
|
const hubsoftPool = new Pool({
|
||||||
|
host: process.env.HUBSOFT_DATABASE_HOST,
|
||||||
|
port: process.env.HUBSOFT_DATABASE_PORT,
|
||||||
|
user: process.env.HUBSOFT_DATABASE_USER,
|
||||||
|
password: process.env.HUBSOFT_DATABASE_PASSWORD,
|
||||||
|
database: process.env.HUBSOFT_DATABASE_NAME,
|
||||||
|
max: 20,
|
||||||
|
idleTimeoutMillis: 30000,
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = hubsoftPool;
|
||||||
7
src/shared/infra/database/index.js
Normal file
7
src/shared/infra/database/index.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// src/shared/infra/database/index.js
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
hubsoft: require("./hubsoft.pool"),
|
||||||
|
hubglpi: require("./hubglpi.pool"),
|
||||||
|
glpi: require("./glpi.pool")
|
||||||
|
};
|
||||||
@ -5,15 +5,16 @@ function mapHubGlpiToGlpi(ticket) {
|
|||||||
entities_id: ticket.entities_id || 0,
|
entities_id: ticket.entities_id || 0,
|
||||||
name: ticket.name,
|
name: ticket.name,
|
||||||
date: ticket.created_at,
|
date: ticket.created_at,
|
||||||
date_mod: Now(),
|
status: defineStatusGlpi(ticket.status),
|
||||||
status: defineStatusGlpi(ticket.status_atendimento),
|
users_id_recipient: parseInt(process.env.GLPI_USER_ID) || 0,
|
||||||
users_id_recipient: process.env.GLPI_USER_ID || 0,
|
|
||||||
content: ticket.content,
|
content: ticket.content,
|
||||||
urgency: 3,
|
urgency: 3,
|
||||||
impact: 3,
|
impact: 3,
|
||||||
priority: 3,
|
priority: 3,
|
||||||
type: 2,
|
type: 2,
|
||||||
date_creation : ticket.date_creation || Now(),
|
requesttypes_id: 2,
|
||||||
|
date_creation : ticket.date_creation || new Date(),
|
||||||
|
itilcategories_id: 1,
|
||||||
slas_id_ttr: 37
|
slas_id_ttr: 37
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -26,7 +27,7 @@ function defineStatusGlpi(Status) {
|
|||||||
'Resolvido': 5
|
'Resolvido': 5
|
||||||
};
|
};
|
||||||
|
|
||||||
return mapStatusDBtoGLPI[Status] || 'Novo';
|
return mapStatusDBtoGLPI[Status] || 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,33 +1,99 @@
|
|||||||
// src/shared/model/hubglpi.model.js
|
// src/shared/model/hubglpi.model.js
|
||||||
|
|
||||||
function mapHubsoftToHubglpi(ticket, type) {
|
function mapHubsoftToHubglpi(ticket, type) {
|
||||||
return {
|
return {
|
||||||
id_atendimento: ticket.id_atendimento,
|
id_atendimento: ticket.id_atendimento,
|
||||||
codigo_cliente: ticket.codigo_cliente,
|
codigo_cliente: ticket.codigo_cliente,
|
||||||
status_atendimento: defineStatusHubglpi(ticket.id_atendimento_status),
|
status_atendimento: defineStatusHubglpi(ticket.id_atendimento_status),
|
||||||
servico_nome: ticket.descricao,
|
servico_nome: ticket.descricao,
|
||||||
protocolo_hub: ticket.protocolo,
|
protocolo_hub: ticket.protocolo,
|
||||||
ticket_mundiale: parseInt(ticket.descricao_abertura.replace(/[^0-9]/g, ''))|| null,
|
|
||||||
|
// Extrai número do protocolo do Mundiale
|
||||||
|
ticket_mundiale: extractMundiale(ticket.descricao_abertura, type),
|
||||||
|
|
||||||
codigo_servico: ticket.id_cliente_servico,
|
codigo_servico: ticket.id_cliente_servico,
|
||||||
cliente_nome: ticket.nome_contato,
|
cliente_nome: ticket.nome_contato,
|
||||||
descricao_fechamento: ticket.descricao_fechamento || null,
|
descricao_fechamento: ticket.descricao_fechamento || null,
|
||||||
data_fechamento: ticket.data_fechamento || null,
|
data_fechamento: ticket.data_fechamento || null,
|
||||||
created_at: ticket.data_cadastro,
|
created_at: ticket.data_cadastro,
|
||||||
ticket_type: type
|
ticket_type: type,
|
||||||
|
descricao_abertura: ticket.descricao_abertura || null,
|
||||||
|
endereco: endereco(ticket),
|
||||||
|
telefone: sanitizePhone(ticket.telefone),
|
||||||
|
|
||||||
|
cpf_cnpj: sanitizeCpfCnpj(ticket.cpf_cnpj),
|
||||||
|
|
||||||
|
tipo_pessoa: ticket.tipo_pessoa || null,
|
||||||
|
email: ticket.email || null,
|
||||||
|
nome_razaosocial: ticket.nome_razaosocial || null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -----------------
|
||||||
|
Sanitização
|
||||||
|
------------------ */
|
||||||
|
|
||||||
|
function sanitizeCpfCnpj(value) {
|
||||||
|
if (!value) return null;
|
||||||
|
|
||||||
|
// Se vier número gigantesco do JS tipo 3.2e+22 → converte pra string
|
||||||
|
const str = String(value);
|
||||||
|
|
||||||
|
// Remove qualquer coisa que não seja número
|
||||||
|
const clean = str.replace(/\D/g, "");
|
||||||
|
|
||||||
|
return clean.length > 0 ? clean : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitizePhone(phone) {
|
||||||
|
if (!phone) return null;
|
||||||
|
const clean = String(phone).replace(/\D/g, "");
|
||||||
|
return clean || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractMundiale(descricao, type) {
|
||||||
|
if (type === 'IMPLANTACAO') return null;
|
||||||
|
|
||||||
|
if (!descricao) return null;
|
||||||
|
|
||||||
|
// Extrai apenas dígitos
|
||||||
|
const num = descricao.replace(/\D/g, "");
|
||||||
|
|
||||||
|
// Previne NaN
|
||||||
|
return num ? parseInt(num, 10) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------
|
||||||
|
Endereço
|
||||||
|
------------------ */
|
||||||
|
|
||||||
|
function endereco(ticket) {
|
||||||
|
if (!ticket.endereco || !ticket.numero || !ticket.cidade || !ticket.estado) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const complemento = ticket.complemento ? ` - ${ticket.complemento}` : "";
|
||||||
|
const bairro = ticket.bairro ? `${ticket.bairro}` : "";
|
||||||
|
const cep = ticket.cep ? ticket.cep : "";
|
||||||
|
|
||||||
|
return `${ticket.endereco}, ${ticket.numero}${complemento}, ${bairro} - ${ticket.cidade}/${ticket.estado} - CEP ${cep}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -----------------
|
||||||
|
Status Mapper
|
||||||
|
------------------ */
|
||||||
|
|
||||||
function defineStatusHubglpi(hubsoftStatus) {
|
function defineStatusHubglpi(hubsoftStatus) {
|
||||||
const statusMap = {
|
const statusMap = {
|
||||||
1: 'Pendente',
|
1: "Pendente",
|
||||||
2: 'Em atendimento',
|
2: "Em atendimento",
|
||||||
3: 'Resolvido',
|
3: "Resolvido",
|
||||||
31: 'Pendente',
|
31: "Pendente",
|
||||||
32: 'Pendente',
|
32: "Pendente",
|
||||||
33: 'Novo'
|
33: "Novo"
|
||||||
}
|
};
|
||||||
return statusMap[hubsoftStatus] || 'Novo';
|
return statusMap[hubsoftStatus] || "Novo";
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mapHubsoftToHubglpi
|
mapHubsoftToHubglpi
|
||||||
|
|||||||
@ -1,40 +1,86 @@
|
|||||||
// src/shared/repositories/glpi.repository.js
|
// src/shared/repositories/glpi.repository.js
|
||||||
const db = require('../../../config/database.js');
|
const { glpi } = require("../../shared/infra/database");
|
||||||
const { logInfo, logError } = require('../../utils/logger.js');
|
const { logInfo, logError } = require('../../utils/logger.js');
|
||||||
|
|
||||||
async function insertTickets(tickets) {
|
async function insertTicket(ticket) {
|
||||||
|
|
||||||
const values = tickets.map(t => [
|
|
||||||
t.status,
|
|
||||||
t.content,
|
|
||||||
t.users_id_recipient,
|
|
||||||
t.entities_id,
|
|
||||||
t.type,
|
|
||||||
t.requesttypes_id,
|
|
||||||
t.urgency,
|
|
||||||
t.impact,
|
|
||||||
t.priority,
|
|
||||||
t.date,
|
|
||||||
t.name
|
|
||||||
]);
|
|
||||||
|
|
||||||
const placeholders = values
|
|
||||||
.map(() => "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)")
|
|
||||||
.join(",");
|
|
||||||
|
|
||||||
const sql = `
|
const sql = `
|
||||||
INSERT INTO glpi_tickets
|
INSERT INTO glpi_tickets
|
||||||
(status, content, users_id_recipient, entities_id, type, requesttypes_id,
|
(entities_id, name, date, date_mod, status, users_id_recipient, content, urgency, impact, priority, type, itilcategories_id, date_creation, slas_id_ttr)
|
||||||
urgency, impact, priority, date, name)
|
VALUES (?, ?, ?, NOW(), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
VALUES ${placeholders}
|
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const result = await mariadb.execute(sql, values.flat());
|
const values = [
|
||||||
|
ticket.entities_id,
|
||||||
|
ticket.name,
|
||||||
|
ticket.date,
|
||||||
|
ticket.status,
|
||||||
|
ticket.users_id_recipient,
|
||||||
|
ticket.content,
|
||||||
|
ticket.urgency,
|
||||||
|
ticket.impact,
|
||||||
|
ticket.priority,
|
||||||
|
ticket.type,
|
||||||
|
ticket.itilcategories_id,
|
||||||
|
ticket.date_creation,
|
||||||
|
ticket.slas_id_ttr
|
||||||
|
];
|
||||||
|
|
||||||
return result.insertId ? [result.insertId] : [];
|
const [result] = await glpi.execute(sql, values);
|
||||||
|
return result.insertId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function getEntitiesByService(codigoCliente, codigoServico) {
|
||||||
|
try {
|
||||||
|
const sql = `SELECT id FROM glpi_entities WHERE name LIKE ? or name LIKE ? or name LIKE ? LIMIT 1;`;
|
||||||
|
const values = [`${codigoCliente}-${codigoServico}-%`, `${codigoCliente} -${codigoServico}-%`, `${codigoCliente} - ${codigoServico} -%`];
|
||||||
|
const [rows] = await glpi.execute(sql, values);
|
||||||
|
if (rows.length > 0) {
|
||||||
|
return rows[0].id;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
logError(`Erro ao buscar entidade por código de serviço: ${error}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getEntitiesByClient(codigoCliente) {
|
||||||
|
try {
|
||||||
|
const sql = `SELECT id FROM glpi_entities WHERE name LIKE ? or name LIKE ? LIMIT 1;`;
|
||||||
|
const values = [`${codigoCliente}-%`, `${codigoCliente} -%`];
|
||||||
|
const [rows] = await glpi.execute(sql, values);
|
||||||
|
if (rows.length > 0) {
|
||||||
|
return rows[0].id;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (error) {
|
||||||
|
logError(`Erro ao buscar entidade por código de cliente: ${error}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertEntity(entity_name){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertGroupTicket(ticketId) {
|
||||||
|
try {
|
||||||
|
const sql = ` INSERT INTO glpi_groups_tickets (tickets_id, groups_id, type)
|
||||||
|
VALUES (?, 25, 2)
|
||||||
|
`;
|
||||||
|
const values = [ticketId];
|
||||||
|
await glpi.execute(sql, values);
|
||||||
|
logInfo(`Grupo associado ao ticket GLPI ID: ${ticketId}`);
|
||||||
|
} catch (error) {
|
||||||
|
logError(`Erro ao associar grupo ao ticket GLPI ID ${ticketId}: ${error}`);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
insertTickets
|
insertTicket,
|
||||||
|
getEntitiesByService,
|
||||||
|
getEntitiesByClient,
|
||||||
|
insertGroupTicket
|
||||||
};
|
};
|
||||||
@ -1,92 +1,125 @@
|
|||||||
// src/shared/repositories/hubglpi.repository.js
|
// src/shared/repositories/hubglpi.repository.js
|
||||||
const { get } = require('pm2');
|
|
||||||
const db = require('../../../config/database.js');
|
const { hubglpi } = require("../../shared/infra/database");
|
||||||
const { logInfo, logError } = require('../../utils/logger.js');
|
const { logInfo, logError } = require("../../utils/logger.js");
|
||||||
const { query } = require('winston');
|
|
||||||
const { hubsoft } = require('../../config/dbConfig.js');
|
|
||||||
|
|
||||||
async function insertTickets(tickets) {
|
async function insertTickets(tickets) {
|
||||||
try {
|
try {
|
||||||
const values = tickets.map(t => [
|
const values = tickets.map(t => [
|
||||||
t.id_atendimento,
|
t.id_atendimento,
|
||||||
t.codigo_cliente,
|
t.codigo_cliente,
|
||||||
t.status_atendimento,
|
t.status_atendimento,
|
||||||
t.servico_nome,
|
t.servico_nome,
|
||||||
t.protocolo_hub,
|
t.protocolo_hub,
|
||||||
t.ticket_mundiale,
|
t.ticket_mundiale,
|
||||||
t.codigo_servico,
|
t.codigo_servico,
|
||||||
t.cliente_nome,
|
t.cliente_nome,
|
||||||
t.descricao_fechamento,
|
t.descricao_fechamento,
|
||||||
t.data_fechamento,
|
t.data_fechamento,
|
||||||
t.created_at,
|
t.created_at,
|
||||||
t.updated_at,
|
t.updated_at,
|
||||||
t.ticket_type
|
t.ticket_type,
|
||||||
]);
|
t.descricao_abertura,
|
||||||
|
t.endereco,
|
||||||
|
t.telefone,
|
||||||
|
t.cpf_cnpj,
|
||||||
|
t.tipo_pessoa,
|
||||||
|
t.email,
|
||||||
|
t.nome_razaosocial
|
||||||
|
]);
|
||||||
|
|
||||||
const rowPlaceholders = values
|
const totalColumns = 20;
|
||||||
.map(
|
|
||||||
(_, i) =>
|
|
||||||
`(${Array(13)
|
|
||||||
.fill(0)
|
|
||||||
.map((_, j) => `$${i * 13 + j + 1}`)
|
|
||||||
.join(", ")})`
|
|
||||||
)
|
|
||||||
.join(", ");
|
|
||||||
|
|
||||||
const query = `
|
const rowPlaceholders = values
|
||||||
INSERT INTO hubsoft_tickets
|
.map(
|
||||||
(id_atendimento, codigo_cliente, status_atendimento, servico_nome, protocolo_hub, ticket_mundiale,
|
(_, rowIndex) =>
|
||||||
codigo_servico, cliente_nome, descricao_fechamento, data_fechamento, created_at, updated_at, type)
|
`(${Array.from({ length: totalColumns })
|
||||||
VALUES ${rowPlaceholders}
|
.map((_, colIndex) => `$${rowIndex * totalColumns + colIndex + 1}`)
|
||||||
ON CONFLICT (id_atendimento)
|
.join(", ")})`
|
||||||
DO UPDATE SET
|
)
|
||||||
codigo_cliente = EXCLUDED.codigo_cliente,
|
.join(", ");
|
||||||
status_atendimento = EXCLUDED.status_atendimento,
|
|
||||||
servico_nome = EXCLUDED.servico_nome,
|
|
||||||
protocolo_hub = EXCLUDED.protocolo_hub,
|
|
||||||
ticket_mundiale = EXCLUDED.ticket_mundiale,
|
|
||||||
codigo_servico = EXCLUDED.codigo_servico,
|
|
||||||
cliente_nome = EXCLUDED.cliente_nome,
|
|
||||||
descricao_fechamento = EXCLUDED.descricao_fechamento,
|
|
||||||
data_fechamento = EXCLUDED.data_fechamento,
|
|
||||||
updated_at = EXCLUDED.updated_at,
|
|
||||||
type = EXCLUDED.type
|
|
||||||
`;
|
|
||||||
|
|
||||||
const flattened = values.flat();
|
const query = `
|
||||||
|
INSERT INTO public.hubsoft_tickets
|
||||||
|
(
|
||||||
|
id_atendimento,
|
||||||
|
codigo_cliente,
|
||||||
|
status_atendimento,
|
||||||
|
servico_nome,
|
||||||
|
protocolo_hub,
|
||||||
|
ticket_mundiale,
|
||||||
|
codigo_servico,
|
||||||
|
cliente_nome,
|
||||||
|
descricao_fechamento,
|
||||||
|
data_fechamento,
|
||||||
|
created_at,
|
||||||
|
updated_at,
|
||||||
|
ticket_type,
|
||||||
|
descricao_abertura,
|
||||||
|
endereco,
|
||||||
|
telefone,
|
||||||
|
cpf_cnpj,
|
||||||
|
tipo_pessoa,
|
||||||
|
email,
|
||||||
|
nome_razaosocial
|
||||||
|
)
|
||||||
|
VALUES ${rowPlaceholders}
|
||||||
|
ON CONFLICT (id_atendimento)
|
||||||
|
DO UPDATE SET
|
||||||
|
codigo_cliente = EXCLUDED.codigo_cliente,
|
||||||
|
status_atendimento = EXCLUDED.status_atendimento,
|
||||||
|
servico_nome = EXCLUDED.servico_nome,
|
||||||
|
protocolo_hub = EXCLUDED.protocolo_hub,
|
||||||
|
ticket_mundiale = EXCLUDED.ticket_mundiale,
|
||||||
|
codigo_servico = EXCLUDED.codigo_servico,
|
||||||
|
cliente_nome = EXCLUDED.cliente_nome,
|
||||||
|
descricao_fechamento = EXCLUDED.descricao_fechamento,
|
||||||
|
data_fechamento = EXCLUDED.data_fechamento,
|
||||||
|
updated_at = EXCLUDED.updated_at,
|
||||||
|
ticket_type = EXCLUDED.ticket_type,
|
||||||
|
descricao_abertura = EXCLUDED.descricao_abertura,
|
||||||
|
endereco = EXCLUDED.endereco,
|
||||||
|
telefone = EXCLUDED.telefone,
|
||||||
|
cpf_cnpj = EXCLUDED.cpf_cnpj,
|
||||||
|
tipo_pessoa = EXCLUDED.tipo_pessoa,
|
||||||
|
email = EXCLUDED.email,
|
||||||
|
nome_razaosocial = EXCLUDED.nome_razaosocial
|
||||||
|
`;
|
||||||
|
|
||||||
await db.query(query, flattened);
|
const flattened = values.flat();
|
||||||
|
|
||||||
return { success: true, ids: tickets.map(t => t.id_atendimento) };
|
await hubglpi.query(query, flattened);
|
||||||
|
|
||||||
} catch (error) {
|
logInfo(`Tickets salvos/atualizados: ${tickets.length}`);
|
||||||
logError("Erro ao inserir tickets no HubGLPI:", error);
|
|
||||||
throw error;
|
return { success: true, ids: tickets.map(t => t.id_atendimento) };
|
||||||
}
|
|
||||||
|
} catch (error) {
|
||||||
|
logError("Erro ao inserir tickets no HubGLPI:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insertSyncData(ids) {
|
async function insertSyncData(ids) {
|
||||||
try {
|
try {
|
||||||
const values = ids.map(id => [id]);
|
const rowPlaceholders = ids
|
||||||
|
|
||||||
const rowPlaceholders = values
|
|
||||||
.map((_, i) => `($${i + 1})`)
|
.map((_, i) => `($${i + 1})`)
|
||||||
.join(", ");
|
.join(", ");
|
||||||
|
|
||||||
const query = `
|
const query = `
|
||||||
INSERT INTO hubsoft_sync_data (hubsoft_ticket_id)
|
INSERT INTO sync_data (hubsoft_ticket_id)
|
||||||
VALUES ${rowPlaceholders}
|
VALUES ${rowPlaceholders}
|
||||||
ON CONFLICT (hubsoft_ticket_id) DO UPDATE SET
|
ON CONFLICT (hubsoft_ticket_id)
|
||||||
hubsoft_ticket_id = $1
|
DO UPDATE SET hubsoft_ticket_id = EXCLUDED.hubsoft_ticket_id
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const flattened = ids;
|
await hubglpi.query(query, ids);
|
||||||
|
|
||||||
await db.query(query, flattened);
|
logInfo(`Sync data criada/atualizada para ${ids.length} tickets.`);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
catch (error) {
|
} catch (error) {
|
||||||
logError("Erro ao inserir dados de sincronização no HubGLPI:", error);
|
logError("Erro ao inserir dados de sincronização no HubGLPI:", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@ -94,39 +127,79 @@ async function insertSyncData(ids) {
|
|||||||
|
|
||||||
async function fetchPendingTickets() {
|
async function fetchPendingTickets() {
|
||||||
try {
|
try {
|
||||||
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, ht.ticket_type as ticket_type
|
const query = `
|
||||||
FROM hubsoft_tickets AS ht
|
SELECT
|
||||||
LEFT JOIN sync_data AS sd ON ht.id_atendimento = sd.hubsoft_ticket_id
|
ht.id_atendimento,
|
||||||
WHERE sd.status_sync IS NULL OR sd.status_sync = 'pending_create'
|
ht.codigo_cliente,
|
||||||
ORDER BY ht.created_at ASC;`
|
ht.status_atendimento,
|
||||||
const result = await db.query(query);
|
ht.codigo_servico,
|
||||||
return result.rows
|
ht.servico_nome,
|
||||||
|
ht.protocolo_hub,
|
||||||
|
ht.ticket_mundiale,
|
||||||
|
ht.cliente_nome,
|
||||||
|
ht.created_at,
|
||||||
|
ht.ticket_type,
|
||||||
|
|
||||||
|
-- NOVOS CAMPOS
|
||||||
|
ht.descricao_abertura,
|
||||||
|
ht.endereco,
|
||||||
|
ht.telefone,
|
||||||
|
ht.cpf_cnpj,
|
||||||
|
ht.tipo_pessoa,
|
||||||
|
ht.email,
|
||||||
|
ht.nome_razaosocial,
|
||||||
|
|
||||||
|
-- CAMPOS DA SYNC_DATA
|
||||||
|
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;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const result = await hubglpi.query(query);
|
||||||
|
return result.rows;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError("Erro ao buscar tickets pendentes no HubGLPI:", error);
|
logError("Erro ao buscar tickets pendentes no HubGLPI:", error);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function updateSyncDataCreated(hubsoftTicketId, glpiId) {
|
async function updateSyncDataCreated(hubsoftTicketId, glpiId) {
|
||||||
const sql = `
|
try {
|
||||||
UPDATE sync_data
|
const sql = `
|
||||||
SET
|
UPDATE sync_data
|
||||||
status_sync = 'created_glpi',
|
SET
|
||||||
updated_at = NOW(),
|
status_sync = 'created_glpi',
|
||||||
last_sync_attempt = NOW(),
|
updated_at = NOW(),
|
||||||
glpi_ticket_id = ?
|
last_sync_attempt = NOW(),
|
||||||
WHERE hubsoft_ticket_id = ?
|
glpi_ticket_id = $1
|
||||||
`;
|
WHERE hubsoft_ticket_id = $2
|
||||||
|
`;
|
||||||
|
|
||||||
await db.query(sql, [glpiId, hubsoftTicketId]);
|
await hubglpi.query(sql, [glpiId, hubsoftTicketId]);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
logError("Erro ao atualizar sync_data para ticket criado no GLPI:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
insertTickets,
|
insertTickets,
|
||||||
insertSyncData,
|
insertSyncData,
|
||||||
fetchPendingTickets,
|
fetchPendingTickets,
|
||||||
updateSyncDataCreated
|
updateSyncDataCreated
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
// src/shared/repositories/hubsoft.repository.js
|
// src/shared/repositories/hubsoft.repository.js
|
||||||
const { get } = require('pm2');
|
const { get } = require('pm2');
|
||||||
const db = require('../../../config/database.js');
|
const { hubsoft } = require("../../shared/infra/database");
|
||||||
const { logInfo, logError } = require('../../utils/logger.js');
|
const { logInfo, logError } = require('../../utils/logger.js');
|
||||||
|
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ async function getMundialeTickets() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
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 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 db.query(query);
|
const { rows } = await hubsoft.query(query);
|
||||||
return rows;
|
return rows;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError("Erro ao buscar tickets Mundiale:", error);
|
logError("Erro ao buscar tickets Mundiale:", error);
|
||||||
@ -18,8 +18,67 @@ async function getMundialeTickets() {
|
|||||||
|
|
||||||
async function getImplantacaoTickets() {
|
async function getImplantacaoTickets() {
|
||||||
try {
|
try {
|
||||||
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 = 21 AND a.id_atendimento_status IN (1, 2, 33) AND s.ativo = true;`;
|
const query = `
|
||||||
const { rows } = await db.query(query);
|
SELECT
|
||||||
|
a.id_atendimento,
|
||||||
|
a.id_usuario_abertura,
|
||||||
|
a.id_atendimento_status,
|
||||||
|
a.protocolo,
|
||||||
|
a.descricao_abertura,
|
||||||
|
a.data_cadastro,
|
||||||
|
a.nome_contato,
|
||||||
|
|
||||||
|
-- DADOS DO CLIENTE (novos)
|
||||||
|
c.nome_razaosocial,
|
||||||
|
c.telefone_primario AS telefone,
|
||||||
|
c.cpf_cnpj,
|
||||||
|
c.tipo_pessoa,
|
||||||
|
c.email_principal AS email,
|
||||||
|
|
||||||
|
c.codigo_cliente,
|
||||||
|
s.descricao AS descricao,
|
||||||
|
cs.id_cliente_servico,
|
||||||
|
|
||||||
|
-- ENDEREÇO DE INSTALAÇÃO
|
||||||
|
en.endereco,
|
||||||
|
en.numero,
|
||||||
|
en.complemento,
|
||||||
|
en.bairro,
|
||||||
|
en.cep,
|
||||||
|
ci.nome AS cidade,
|
||||||
|
es.sigla AS estado
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
-- endereço do cliente
|
||||||
|
INNER JOIN cliente_servico_endereco AS cse
|
||||||
|
ON cse.id_cliente_servico = cs.id_cliente_servico
|
||||||
|
AND cse.tipo = 'instalacao'
|
||||||
|
|
||||||
|
INNER JOIN endereco_numero AS en
|
||||||
|
ON en.id_endereco_numero = cse.id_endereco_numero
|
||||||
|
|
||||||
|
INNER JOIN cidade AS ci
|
||||||
|
ON ci.id_cidade = en.id_cidade
|
||||||
|
|
||||||
|
INNER JOIN estado AS es
|
||||||
|
ON es.id_estado = ci.id_estado
|
||||||
|
|
||||||
|
WHERE
|
||||||
|
a.id_tipo_atendimento = 21
|
||||||
|
AND a.id_atendimento_status IN (1, 2, 33)
|
||||||
|
AND s.ativo = TRUE;
|
||||||
|
`;
|
||||||
|
const { rows } = await hubsoft.query(query);
|
||||||
return rows;
|
return rows;
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -31,7 +90,7 @@ async function getImplantacaoTickets() {
|
|||||||
async function getCancelamentoTickets() {
|
async function getCancelamentoTickets() {
|
||||||
try {
|
try {
|
||||||
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 = 27 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 = 27 AND a.id_atendimento_status IN (1, 2, 33) AND s.ativo = true;`;
|
||||||
const { rows } = await db.query(query);
|
const { rows } = await hubsoft.query(query);
|
||||||
return rows;
|
return rows;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError("Erro ao buscar tickets Cancelamento:", error);
|
logError("Erro ao buscar tickets Cancelamento:", error);
|
||||||
@ -42,7 +101,7 @@ async function getCancelamentoTickets() {
|
|||||||
async function getSacTickets() {
|
async function getSacTickets() {
|
||||||
try {
|
try {
|
||||||
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 = 41 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 = 41 AND a.id_atendimento_status IN (1, 2, 33) AND s.ativo = true;`;
|
||||||
const { rows } = await db.query(query);
|
const { rows } = await hubsoft.query(query);
|
||||||
return rows;
|
return rows;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logError("Erro ao buscar tickets SAC:", error);
|
logError("Erro ao buscar tickets SAC:", error);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user