2025-12-10 07:10:37 -03:00
|
|
|
// 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}.`);
|
|
|
|
|
|
2025-12-11 11:48:24 -03:00
|
|
|
await repositoryGlpi.insertGroupTicket(glpiId, 'IMPLANTACAO');
|
2025-12-10 07:10:37 -03:00
|
|
|
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
|
|
|
|
|
};
|