FEAT: Chamados de troca de titularidade também são coletados
This commit is contained in:
parent
37205d7e23
commit
6a22bf652a
@ -11,6 +11,7 @@ async function getTicketsByTipo({
|
|||||||
try {
|
try {
|
||||||
const isImplantacao = Number(tipoAtendimento) === 21;
|
const isImplantacao = Number(tipoAtendimento) === 21;
|
||||||
const isCancelamento = Number(tipoAtendimento) === 27;
|
const isCancelamento = Number(tipoAtendimento) === 27;
|
||||||
|
const istrocaTitularidade = Number(tipoAtendimento) === 60;
|
||||||
|
|
||||||
let select = `
|
let select = `
|
||||||
a.id_atendimento,
|
a.id_atendimento,
|
||||||
@ -32,7 +33,7 @@ async function getTicketsByTipo({
|
|||||||
INNER JOIN servico AS s ON cs.id_servico = s.id_servico
|
INNER JOIN servico AS s ON cs.id_servico = s.id_servico
|
||||||
`;
|
`;
|
||||||
|
|
||||||
if (isImplantacao || isCancelamento) {
|
if (isImplantacao || isCancelamento || istrocaTitularidade) {
|
||||||
select += `,
|
select += `,
|
||||||
u.name AS vendedor,
|
u.name AS vendedor,
|
||||||
c.nome_razaosocial,
|
c.nome_razaosocial,
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
// 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) {
|
|
||||||
|
|
||||||
if (ticket.ticket_type === 'MUNDIALE') {
|
|
||||||
await mundialeService.sendToGlpi(ticket);
|
|
||||||
|
|
||||||
} else if (ticket.ticket_type === 'IMPLANTACAO') {
|
|
||||||
await implantacaoService.sendToGlpi(ticket);
|
|
||||||
|
|
||||||
} else if (ticket.ticket_type === 'SAC') {
|
|
||||||
await sacService.sendToGlpi(ticket);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
logInfo(`Tipo desconhecido, ignorando ticket id=${ticket.id}`);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
logInfo("[CONTROLLER] Finalizado.");
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { processAtendimentos };
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,60 +0,0 @@
|
|||||||
// src/modules/createTickets/services/createTickets.service.js
|
|
||||||
const repositoryHubGlpi = require('../../../shared/repositories/hubglpi.repository.js');
|
|
||||||
const repositoryGlpi = require('../../../shared/repositories/glpi.repository.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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
fetchPendingTickets,
|
|
||||||
resolveEntityId,
|
|
||||||
setAsCreated,
|
|
||||||
createEntity
|
|
||||||
}
|
|
||||||
@ -1,126 +0,0 @@
|
|||||||
// 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, 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}`);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// --------------------------------------
|
|
||||||
// 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.
|
|
||||||
*/
|
|
||||||
@ -1,113 +1,44 @@
|
|||||||
// src/modules/createTickets/services/mundiale.service.js
|
// src/modules/tickets/models/glpi/implantacao.model.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');
|
|
||||||
|
|
||||||
// --------------------------------------
|
function toGlpiPayload(ticket) {
|
||||||
// Funções principais do serviço
|
return {
|
||||||
// --------------------------------------
|
entities_id: ticket.entities_id || 0,
|
||||||
|
name: buildTitle(ticket),
|
||||||
async function fetchNew() {
|
content: buildHtml(ticket),
|
||||||
return repositoryHubsoft.getImplantacaoTickets();
|
status: resolveGlpiStatus(ticket.status_atendimento),
|
||||||
|
date: ticket.created_at,
|
||||||
|
date_mod: new Date(),
|
||||||
|
users_id_recipient: process.env.GLPI_USER_ID || 0,
|
||||||
|
urgency: 3,
|
||||||
|
impact: 3,
|
||||||
|
priority: 3,
|
||||||
|
type: 2,
|
||||||
|
date_creation: ticket.created_at || new Date(),
|
||||||
|
itilcategories_id: 0,
|
||||||
|
slas_id_ttr: 37,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveHubGlpi(tickets) {
|
function resolveGlpiStatus(status) {
|
||||||
if (!tickets.length) return;
|
const map = {
|
||||||
|
'Novo': 1,
|
||||||
const ticketsFormatted = tickets.map(ticket =>
|
'Pendente': 4,
|
||||||
modelHubGlpi.mapHubsoftToHubglpi(ticket, 'IMPLANTACAO')
|
'Em atendimento': 2,
|
||||||
);
|
'Resolvido': 5
|
||||||
|
}
|
||||||
const inserted = await repositoryHubGlpi.insertTickets(ticketsFormatted);
|
return map[status] || 1
|
||||||
|
|
||||||
if (inserted) {
|
|
||||||
await repositoryHubGlpi.insertSyncData(
|
|
||||||
ticketsFormatted.map(ticket => ticket.id_atendimento)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return inserted;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendToGlpi(ticket) {
|
function buildTitle(ticket) {
|
||||||
|
return `TROCA DE TITULARIDADE - ${ticket.codigo_cliente}-${ticket.codigo_servico} - ${ticket.nome_razaosocial} - ${ticket.servico_nome}`
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildHtml(ticket) {
|
||||||
|
const docLabel = ticket.tipo_pessoa === 'pf' ? 'CPF' : 'CNPJ'
|
||||||
|
const documento = formatDocument(ticket.cpf_cnpj, ticket.tipo_pessoa)
|
||||||
|
const servico = resolveService(ticket.servico_nome)
|
||||||
|
|
||||||
// --------------------------------------
|
return `
|
||||||
// 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;">
|
<table style="width:100%; border-collapse: collapse;">
|
||||||
|
|
||||||
<!-- ===== CABEÇALHO DADOS COMERCIAL ===== -->
|
<!-- ===== CABEÇALHO DADOS COMERCIAL ===== -->
|
||||||
@ -124,7 +55,7 @@ const formatDescription = (ticket) => {
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Gerente Responsável</strong></td>
|
<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>
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.vendedor || "N/A"}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -141,17 +72,17 @@ const formatDescription = (ticket) => {
|
|||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Cliente</strong></td>
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Cliente</strong></td>
|
||||||
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.cliente_nome}</td>
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.nome_razaosocial}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>${docLabel}</strong></td>
|
<td style="padding: 8px; border: 1px solid #ddd;"><strong>${docLabel}</strong></td>
|
||||||
<td style="padding: 8px; border: 1px solid #ddd;">${documentoFormatado}</td>
|
<td style="padding: 8px; border: 1px solid #ddd;">${documento}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td style="padding: 8px; border: 1px solid #ddd;"><strong>Nome Contato</strong></td>
|
<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>
|
<td style="padding: 8px; border: 1px solid #ddd;">${ticket.cliente_nome || "N/A"}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
@ -201,54 +132,62 @@ const formatDescription = (ticket) => {
|
|||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2" style="padding: 8px; border: 1px solid #ddd;">${ticket.descricao_abertura || "N/A"}</td>
|
<td colspan="2" style="padding: 8px; border: 1px solid #ddd;">
|
||||||
|
${nl2br(ticket.descricao_abertura) || "N/A"}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
</table>
|
</table>
|
||||||
`;
|
`
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------
|
|
||||||
// Formatadores de Documento
|
|
||||||
// --------------------------------------
|
|
||||||
|
|
||||||
function formatCPF(cpf) {
|
function formatCPF(cpf) {
|
||||||
cpf = cpf.replace(/\D/g, "");
|
return cpf?.replace(/\D/g, '')
|
||||||
return cpf.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, "$1.$2.$3-$4");
|
.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4')
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatCNPJ(cnpj) {
|
function formatCNPJ(cnpj) {
|
||||||
cnpj = cnpj.replace(/\D/g, "");
|
return cnpj?.replace(/\D/g, '')
|
||||||
return cnpj.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, "$1.$2.$3/$4-$5");
|
.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5')
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDocument(doc, tipo) {
|
function formatDocument(doc, tipo) {
|
||||||
if (!doc) return "N/A";
|
if (!doc) return 'N/A'
|
||||||
return tipo === "pf" ? formatCPF(doc) : formatCNPJ(doc);
|
return tipo === 'pf' ? formatCPF(doc) : formatCNPJ(doc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 de Internet Dedicado 20 Mbps Full Duplex":
|
||||||
// Resolve Serviço
|
{ produto: "Link de Internet Dedicado", qtd: 1, descricao: "20 Mbps Full Duplex" },
|
||||||
// --------------------------------------
|
|
||||||
|
|
||||||
function resolveService(servicoNome) {
|
"Link de Internet Dedicado 100 Mbps Full Duplex":
|
||||||
return serviceDictionary[servicoNome] || {
|
{ produto: "Link de Internet Dedicado", qtd: 1, descricao: "100 Mbps Full Duplex" },
|
||||||
produto: servicoNome,
|
|
||||||
qtd: 1,
|
|
||||||
descricao: null
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
"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":
|
||||||
// Exportação
|
{ produto: "Link de Internet Dedicado", qtd: 1, descricao: "2 Gbps Full Duplex" },
|
||||||
// --------------------------------------
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
fetchNew,
|
|
||||||
saveHubGlpi,
|
|
||||||
sendToGlpi
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function resolveService(name) {
|
||||||
|
return serviceDictionary[name] || { produto: name, qtd: 1, descricao: null }
|
||||||
|
}
|
||||||
|
|
||||||
|
function nl2br(text) {
|
||||||
|
if (!text) return ''
|
||||||
|
return text.replace(/\r\n|\n|\r/g, '<br>')
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { toGlpiPayload }
|
||||||
@ -60,7 +60,10 @@ async function getSacTickets(watermark) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getTrocaTTickets(watermark) {
|
async function getTrocaTTickets(watermark) {
|
||||||
return hubsoftTicketsRepo.get(watermark)
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
|
tipoAtendimento: TYPES.TITULARIDADE,
|
||||||
|
watermark
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insertTicketsHubGlpi(tickets){
|
async function insertTicketsHubGlpi(tickets){
|
||||||
|
|||||||
@ -8,7 +8,7 @@ async function fetchPendingTickets() {
|
|||||||
|
|
||||||
async function notifyTicketCreated(hubId, glpiId) {
|
async function notifyTicketCreated(hubId, glpiId) {
|
||||||
const message = `Atendimento ${glpiId} criado com sucesso`
|
const message = `Atendimento ${glpiId} criado com sucesso`
|
||||||
//await repository.sendHubsoftMessage(hubId, message)
|
await repository.sendHubsoftMessage(hubId, message)
|
||||||
await repository.sendHubglpiMessage(hubId, message)
|
await repository.sendHubglpiMessage(hubId, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
43
src/modules/tickets/services/trocaTitularidade.service.js
Normal file
43
src/modules/tickets/services/trocaTitularidade.service.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// src/modules/tickets/services/trocaTitularidade.service.js
|
||||||
|
|
||||||
|
const repository = require('../repositories/ticket.repository.js')
|
||||||
|
const modelHubGlpi = require('../models/hubglpi/model.js')
|
||||||
|
const ticketEntityResolver = require('./resolveTicketEntity.service.js')
|
||||||
|
const ttmodel = require('../models/glpi/titularidade.model.js')
|
||||||
|
const { logInfo, logError } = require('../../../shared/utils/logger.js')
|
||||||
|
|
||||||
|
async function fetchNew(watermark) {
|
||||||
|
logInfo('[TROCA_TITULARIDADE] Coletando novos chamados')
|
||||||
|
const raw = await repository.getTrocaTTickets(watermark)
|
||||||
|
return raw.map(t => modelHubGlpi.fromHubsoft(t, 'TITULARIDADE'))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveHubGlpi(tickets) {
|
||||||
|
if (!tickets.length) return
|
||||||
|
logInfo('[TROCA_TITULARIDADE] Salvando tickets no HubGLPI')
|
||||||
|
await repository.insertTicketsHubGlpi(tickets)
|
||||||
|
await repository.insertSyncDataByIds(tickets.map(t => t.id_atendimento))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendToGlpi(ticket) {
|
||||||
|
logInfo(`[TROCA_TITULARIDADE] Enviando ticket ${ticket.id_atendimento} para GLPI`)
|
||||||
|
try {
|
||||||
|
const resolved = await ticketEntityResolver.resolveEntityId(ticket)
|
||||||
|
const payload = ttmodel.toGlpiPayload(resolved)
|
||||||
|
|
||||||
|
const glpiId = await repository.insertTicketGlpi(payload)
|
||||||
|
await repository.insertGroupTicket(glpiId, 'TITULARIDADE')
|
||||||
|
await repository.updateSyncDataCreated(ticket.id_atendimento, glpiId)
|
||||||
|
|
||||||
|
return glpiId
|
||||||
|
} catch (err) {
|
||||||
|
logError(err, `[TROCA_TITULARIDADE] Erro ao enviar ticket ${ticket.id_atendimento}`)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchNew,
|
||||||
|
saveHubGlpi,
|
||||||
|
sendToGlpi
|
||||||
|
}
|
||||||
@ -6,6 +6,7 @@ const mundialeService = require('../services/mundiale.service.js')
|
|||||||
const implantacaoService = require('../services/implantacao.service.js')
|
const implantacaoService = require('../services/implantacao.service.js')
|
||||||
const cancelamentoService = require('../services/cancelamento.service.js')
|
const cancelamentoService = require('../services/cancelamento.service.js')
|
||||||
//const sacService = require('../services/sac.service.js') //TODO
|
//const sacService = require('../services/sac.service.js') //TODO
|
||||||
|
const trocaTitularidadeService = require('../services/trocaTitularidade.service.js') //TODO
|
||||||
|
|
||||||
const getAuthToken = require('../../../infra/api/hubsoft.auth.js')
|
const getAuthToken = require('../../../infra/api/hubsoft.auth.js')
|
||||||
|
|
||||||
@ -30,16 +31,25 @@ async function syncTicketsUseCase() {
|
|||||||
const cancelamento = await cancelamentoService.fetchNew(waterMark)
|
const cancelamento = await cancelamentoService.fetchNew(waterMark)
|
||||||
logInfo(`[USECASE] ${cancelamento.length} tickets Cancelamento encontrados`)
|
logInfo(`[USECASE] ${cancelamento.length} tickets Cancelamento encontrados`)
|
||||||
|
|
||||||
|
//const sac = await sacService.fetchNew(waterMark) //TODO
|
||||||
|
//logInfo(`[USECASE] ${sac.length} tickets SAC encontrados`)
|
||||||
|
|
||||||
|
const trocaTitularidade = await trocaTitularidadeService.fetchNew(waterMark) //TODO
|
||||||
|
logInfo(`[USECASE] ${trocaTitularidade.length} tickets Troca de Titularidade encontrados`)
|
||||||
|
|
||||||
|
|
||||||
await mundialeService.saveHubGlpi(mundiale)
|
//await mundialeService.saveHubGlpi(mundiale)
|
||||||
await implantacaoService.saveHubGlpi(implantacao)
|
//await implantacaoService.saveHubGlpi(implantacao)
|
||||||
await cancelamentoService.saveHubGlpi(cancelamento)
|
//await cancelamentoService.saveHubGlpi(cancelamento)
|
||||||
|
//await sacService.saveHubGlpi(sac) //TODO
|
||||||
|
await trocaTitularidadeService.saveHubGlpi(trocaTitularidade) //TODO
|
||||||
|
|
||||||
const allFetchedTickets = [
|
const allFetchedTickets = [
|
||||||
...mundiale,
|
...mundiale,
|
||||||
...implantacao,
|
...implantacao,
|
||||||
...cancelamento
|
...cancelamento,
|
||||||
|
//...sac,
|
||||||
|
...trocaTitularidade
|
||||||
]
|
]
|
||||||
|
|
||||||
const newWaterMark = resolveNewWatermark(allFetchedTickets, waterMark)
|
const newWaterMark = resolveNewWatermark(allFetchedTickets, waterMark)
|
||||||
@ -73,7 +83,7 @@ function resolveTicketService(type) {
|
|||||||
IMPLANTACAO: implantacaoService,
|
IMPLANTACAO: implantacaoService,
|
||||||
CANCELAMENTO: cancelamentoService,
|
CANCELAMENTO: cancelamentoService,
|
||||||
//SAC: sacService, //TODO
|
//SAC: sacService, //TODO
|
||||||
//TITULARIDADE: trocaTitularidadeService //TODO
|
TITULARIDADE: trocaTitularidadeService //TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[type]
|
return map[type]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user