refactor: restaura alterações do createTickets após hotfix
This commit is contained in:
parent
14949bf4df
commit
2cd00c65c5
@ -0,0 +1,55 @@
|
|||||||
|
// src/modules/createTickets/controller/createTickets.controller.js
|
||||||
|
const mundialeService = require('../services/mundiale.service.js');
|
||||||
|
const implantacaoService = require('../services/implantacao.service.js');
|
||||||
|
const sacService = require('../services/sac.service.js');
|
||||||
|
const ticketShared = require('../services/createTickets.service.js');
|
||||||
|
|
||||||
|
const { logInfo } = require('../../../utils/logger.js');
|
||||||
|
|
||||||
|
async function processAtendimentos() {
|
||||||
|
logInfo("[CONTROLLER] Iniciando processamento");
|
||||||
|
|
||||||
|
// 1️⃣ Buscar por fonte
|
||||||
|
const mundiale = await mundialeService.fetchNew();
|
||||||
|
logInfo(`Encontrados ${mundiale.length} tickets Mundiale para processar.`);
|
||||||
|
const implantacao = await implantacaoService.fetchNew();
|
||||||
|
logInfo(`Encontrados ${implantacao.length} tickets de Implantação para processar.`);
|
||||||
|
//const sac = await sacService.fetchNew();
|
||||||
|
|
||||||
|
// 2️⃣ Salvar no hubglpi
|
||||||
|
await mundialeService.saveHubGlpi(mundiale);
|
||||||
|
await implantacaoService.saveHubGlpi(implantacao);
|
||||||
|
//await sacService.saveHubGlpi(sac);
|
||||||
|
|
||||||
|
// 3️⃣ Buscar pendentes que foram salvos no banco hubglpi
|
||||||
|
const pendentes = await ticketShared.fetchPendingTickets();
|
||||||
|
|
||||||
|
// 4️⃣ Roteamento por tipo
|
||||||
|
for (const ticket of pendentes) {
|
||||||
|
|
||||||
|
let glpiId;
|
||||||
|
|
||||||
|
if (ticket.ticket_type === 'MUNDIALE') {
|
||||||
|
glpiId = await mundialeService.sendToGlpi(ticket);
|
||||||
|
|
||||||
|
} else if (ticket.ticket_type === 'IMPLANTACAO') {
|
||||||
|
glpiId = await implantacaoService.sendToGlpi(ticket);
|
||||||
|
|
||||||
|
} else if (ticket.ticket_type === 'SAC') {
|
||||||
|
glpiId = await sacService.sendToGlpi(ticket);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logInfo(`Tipo desconhecido, ignorando ticket id=${ticket.id}`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticketShared.insertCreateComment(ticket.id_atendimento, glpiId);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
logInfo("[CONTROLLER] Finalizado.");
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { processAtendimentos };
|
||||||
|
|
||||||
|
|
||||||
73
src/modules/createTickets/services/createTickets.service.js
Normal file
73
src/modules/createTickets/services/createTickets.service.js
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
// src/modules/createTickets/services/createTickets.service.js
|
||||||
|
const repositoryHubGlpi = require('../../../shared/repositories/hubglpi.repository.js');
|
||||||
|
const repositoryGlpi = require('../../../shared/repositories/glpi.repository.js');
|
||||||
|
const repositoryHubSoft = require('../../../shared/repositories/hubsoftAPI.repository.js');
|
||||||
|
const modelHubsoft = require('../../../shared/model/hubsoft.model.js');
|
||||||
|
const { hubglpi } = require('../../../config/dbConfig.js');
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Funções principais do serviço
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
async function fetchPendingTickets() {
|
||||||
|
return repositoryHubGlpi.fetchPendingTickets();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function resolveEntityId(ticketData) {
|
||||||
|
|
||||||
|
const entityByService = await repositoryGlpi.getEntitiesByService(
|
||||||
|
ticketData.codigo_cliente,
|
||||||
|
ticketData.codigo_servico
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entityByService) {
|
||||||
|
ticketData.entities_id = entityByService;
|
||||||
|
return ticketData;
|
||||||
|
}
|
||||||
|
|
||||||
|
const entityByClient = await repositoryGlpi.getEntitiesByClient(
|
||||||
|
ticketData.codigo_cliente
|
||||||
|
);
|
||||||
|
|
||||||
|
if (entityByClient) {
|
||||||
|
ticketData.entities_id = entityByClient;
|
||||||
|
return ticketData;
|
||||||
|
}
|
||||||
|
|
||||||
|
ticketData.entities_id = 0;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function insertCreateComment(ticketData, glpiId) {
|
||||||
|
|
||||||
|
const message = `Atendimento ${glpiId} criado com sucesso`;
|
||||||
|
|
||||||
|
await repositoryHubSoft.sendMessage(ticketData.id_atendimento, message);
|
||||||
|
|
||||||
|
await repositoryHubGlpi.sendMessage(glpiId, message);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchPendingTickets,
|
||||||
|
resolveEntityId,
|
||||||
|
setAsCreated,
|
||||||
|
createEntity
|
||||||
|
}
|
||||||
254
src/modules/createTickets/services/implantacao.service.js
Normal file
254
src/modules/createTickets/services/implantacao.service.js
Normal file
@ -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/hubsoftDB.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, 'IMPLANTACAO');
|
||||||
|
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.nome_razaosocial} - ${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.nome_razaosocial}</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.cliente_nome || "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
|
||||||
|
};
|
||||||
128
src/modules/createTickets/services/mundiale.service.js
Normal file
128
src/modules/createTickets/services/mundiale.service.js
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
// 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/hubsoftDB.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, logError, logWarning } = require('../../../utils/logger.js');
|
||||||
|
const { log } = require('winston');
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// Funções principais do serviço
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
async function fetchNew() {
|
||||||
|
return repositoryHubsoft.getMundialeTickets();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveHubGlpi(tickets) {
|
||||||
|
if (!tickets.length) return;
|
||||||
|
|
||||||
|
const ticketsFormatted = tickets.map(ticket => modelHubGlpi.mapHubsoftToHubglpi(ticket, 'MUNDIALE'));
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
formatGlpiPayload(ticketsResolved);
|
||||||
|
|
||||||
|
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, 'MUNDIALE');
|
||||||
|
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}`);
|
||||||
|
|
||||||
|
return glpiId;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------
|
||||||
|
// 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
|
||||||
|
// --------------------------------------
|
||||||
|
|
||||||
|
function formatGlpiPayload(ticket) {
|
||||||
|
|
||||||
|
ticket.status = statusAtendimentoGLPI[ticket.status_atendimento] || 1;
|
||||||
|
|
||||||
|
ticket.name = `Mundiale - Protocolo: ${ticket.ticket_mundiale} - ${ticket.cliente_nome}`;
|
||||||
|
|
||||||
|
ticket.content = formatDescription(ticket);
|
||||||
|
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const formatDescription = (ticketData) => {
|
||||||
|
|
||||||
|
let htmlDescription = `
|
||||||
|
<table style="width:100%; border-collapse: collapse;">
|
||||||
|
<tr style="background-color:#f2f2f2;">
|
||||||
|
<th style="padding: 8px; border: 1px solid #ddd; text-align: left;">Campo</th>
|
||||||
|
<th style="padding: 8px; border: 1px solid #ddd; text-align: left;">Valor</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Nome:</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticketData.cliente_nome}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Codigo:</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticketData.codigo_cliente}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Serviço:</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticketData.servico_nome}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Ticket Mundiale</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticketData.ticket_mundiale}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Protocolo Hub:</strong></td>
|
||||||
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticketData.protocolo_hub || 'N/A'}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
`;
|
||||||
|
|
||||||
|
return htmlDescription;
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchNew,
|
||||||
|
saveHubGlpi,
|
||||||
|
sendToGlpi
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @module CreateTickets/MundialeService
|
||||||
|
* @description Serviço responsável por interagir com o Hubsoft e GLPI criação de tickets que provêm da Mundiale.
|
||||||
|
*/
|
||||||
20
src/shared/infra/api/hubsoft.auth.js
Normal file
20
src/shared/infra/api/hubsoft.auth.js
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// src/shared/infra/api/hubsoft.auth.js
|
||||||
|
|
||||||
|
const getAuthToken = async () => {
|
||||||
|
try {
|
||||||
|
const response = await axios.post(
|
||||||
|
apiConfig.hubsoft.authUrl,
|
||||||
|
qs.stringify(apiConfig.hubsoft.authPayload),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/x-www-form-urlencoded'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.data.access_token;
|
||||||
|
} catch (error) {
|
||||||
|
logError('Erro ao obter token de autenticação:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
19
src/shared/infra/api/hubsoft.config.js
Normal file
19
src/shared/infra/api/hubsoft.config.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// src/shared/infra/api/hubsoft.config.js
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
hubsoft: {
|
||||||
|
baseUrl: process.env.HUBSOFT_BASE_URL,
|
||||||
|
|
||||||
|
authUrl: `${process.env.HUBSOFT_BASE_URL}/oauth/token`,
|
||||||
|
|
||||||
|
authPayload: {
|
||||||
|
grant_type: 'password',
|
||||||
|
client_id: process.env.HUBSOFT_CLIENT_ID,
|
||||||
|
client_secret: process.env.HUBSOFT_CLIENT_SECRET,
|
||||||
|
username: process.env.HUBSOFT_USER,
|
||||||
|
password: process.env.HUBSOFT_PASS
|
||||||
|
},
|
||||||
|
|
||||||
|
atendimentosUrl: `${process.env.HUBSOFT_BASE_URL}/atendimentos/`
|
||||||
|
}
|
||||||
|
};
|
||||||
0
src/shared/model/hubsoft.model.js
Normal file
0
src/shared/model/hubsoft.model.js
Normal file
38
src/shared/repositories/hubsoftAPI.repository.js
Normal file
38
src/shared/repositories/hubsoftAPI.repository.js
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
// src/shared/repositories/hubsoftAPI.repository.js
|
||||||
|
|
||||||
|
const axios = require('axios');
|
||||||
|
const {getAuthToken} = require('../infra/api/hubsoft.auth.js');
|
||||||
|
const apiConfig = require('../infra/api/hubsoft.config');
|
||||||
|
const { logError, logInfo } = require('../../utils/logger');
|
||||||
|
|
||||||
|
async function sendMessage(idAtendimento, mensagem) {
|
||||||
|
try {
|
||||||
|
const token = await getAuthToken();
|
||||||
|
|
||||||
|
const url = `${apiConfig.hubsoft.atendimentosUrl}adicionar_mensagem/${idAtendimento}`;
|
||||||
|
|
||||||
|
logInfo(`[HubSoft API] Enviando comentário para atendimento ${idAtendimento}`);
|
||||||
|
|
||||||
|
await axios.post(
|
||||||
|
url,
|
||||||
|
{ mensagem },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${token}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
logError(
|
||||||
|
`[HubSoft API] Erro ao enviar comentário`,
|
||||||
|
error.response?.data || error.message
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
sendMessage
|
||||||
|
};
|
||||||
118
src/shared/repositories/hubsoftDB.repository.js
Normal file
118
src/shared/repositories/hubsoftDB.repository.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// src/shared/repositories/hubsoft.repository.js
|
||||||
|
const { get } = require('pm2');
|
||||||
|
const { hubsoft } = require("../infra/database/index.js");
|
||||||
|
const { logInfo, logError } = require('../../utils/logger.js');
|
||||||
|
|
||||||
|
|
||||||
|
async function getMundialeTickets() {
|
||||||
|
|
||||||
|
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 { rows } = await hubsoft.query(query);
|
||||||
|
return rows;
|
||||||
|
} catch (error) {
|
||||||
|
logError("Erro ao buscar tickets Mundiale:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getImplantacaoTickets() {
|
||||||
|
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,
|
||||||
|
|
||||||
|
-- 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;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
logError("Erro ao buscar tickets Implantação:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getCancelamentoTickets() {
|
||||||
|
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 { rows } = await hubsoft.query(query);
|
||||||
|
return rows;
|
||||||
|
} catch (error) {
|
||||||
|
logError("Erro ao buscar tickets Cancelamento:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSacTickets() {
|
||||||
|
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 { rows } = await hubsoft.query(query);
|
||||||
|
return rows;
|
||||||
|
} catch (error) {
|
||||||
|
logError("Erro ao buscar tickets SAC:", error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getMundialeTickets,
|
||||||
|
getImplantacaoTickets,
|
||||||
|
getCancelamentoTickets,
|
||||||
|
getSacTickets
|
||||||
|
|
||||||
|
};
|
||||||
Loading…
Reference in New Issue
Block a user