FEAT: Criação de fluxo para novos tipos de atendimento.
This commit is contained in:
parent
d7d2c2d626
commit
eba3366230
767
package-lock.json
generated
767
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -21,9 +21,9 @@
|
|||||||
"express": "^5.1.0",
|
"express": "^5.1.0",
|
||||||
"mysql2": "^3.15.2",
|
"mysql2": "^3.15.2",
|
||||||
"node-cron": "^4.2.1",
|
"node-cron": "^4.2.1",
|
||||||
"nodemailer": "^7.0.12",
|
"nodemailer": "^8.0.7",
|
||||||
"pg": "^8.16.3",
|
"pg": "^8.16.3",
|
||||||
"pm2": "^6.0.13",
|
"pm2": "^7.0.1",
|
||||||
"qs": "^6.14.0",
|
"qs": "^6.14.0",
|
||||||
"winston": "^3.18.3",
|
"winston": "^3.18.3",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
|
|||||||
@ -11,9 +11,8 @@ async function getTicketsByTipo({
|
|||||||
watermark = null
|
watermark = null
|
||||||
}) {
|
}) {
|
||||||
try {
|
try {
|
||||||
const isImplantacao = Number(tipoAtendimento) === 21;
|
const TIPOS_COM_DADOS_COMPLETOS = [4, 21, 27, 41, 60, 22, 25, 7, 61, 63];
|
||||||
const isCancelamento = Number(tipoAtendimento) === 27;
|
const temDadosCompletos = TIPOS_COM_DADOS_COMPLETOS.includes(Number(tipoAtendimento));
|
||||||
const istrocaTitularidade = Number(tipoAtendimento) === 60;
|
|
||||||
|
|
||||||
let select = `
|
let select = `
|
||||||
a.id_atendimento,
|
a.id_atendimento,
|
||||||
@ -35,7 +34,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 || istrocaTitularidade) {
|
if (temDadosCompletos) {
|
||||||
select += `,
|
select += `,
|
||||||
u.name AS vendedor,
|
u.name AS vendedor,
|
||||||
c.nome_razaosocial,
|
c.nome_razaosocial,
|
||||||
|
|||||||
193
src/modules/tickets/models/glpi/consultaBaseAtiva.model.js
Normal file
193
src/modules/tickets/models/glpi/consultaBaseAtiva.model.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
// src/modules/tickets/models/glpi/consultaBaseAtiva.model.js
|
||||||
|
|
||||||
|
function toGlpiPayload(ticket) {
|
||||||
|
return {
|
||||||
|
entities_id: ticket.entities_id || 0,
|
||||||
|
name: buildTitle(ticket),
|
||||||
|
content: buildHtml(ticket),
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveGlpiStatus(status) {
|
||||||
|
const map = {
|
||||||
|
'Novo': 1,
|
||||||
|
'Pendente': 4,
|
||||||
|
'Em atendimento': 2,
|
||||||
|
'Resolvido': 5
|
||||||
|
}
|
||||||
|
return map[status] || 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTitle(ticket) {
|
||||||
|
return `CONSULTA BASE ATIVA - ${ticket.codigo_cliente}-${ticket.codigo_servico} - ${ticket.nome_razaosocial} - ${ticket.servico_nome}`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 `
|
||||||
|
<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.vendedor || "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;">${documento}</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;">
|
||||||
|
${nl2br(ticket.descricao_abertura) || "N/A"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatCPF(cpf) {
|
||||||
|
return cpf?.replace(/\D/g, '')
|
||||||
|
.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCNPJ(cnpj) {
|
||||||
|
return cnpj?.replace(/\D/g, '')
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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":
|
||||||
|
{ 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" },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
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 }
|
||||||
193
src/modules/tickets/models/glpi/downgrade.model.js
Normal file
193
src/modules/tickets/models/glpi/downgrade.model.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
// src/modules/tickets/models/glpi/downgrade.model.js
|
||||||
|
|
||||||
|
function toGlpiPayload(ticket) {
|
||||||
|
return {
|
||||||
|
entities_id: ticket.entities_id || 0,
|
||||||
|
name: buildTitle(ticket),
|
||||||
|
content: buildHtml(ticket),
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveGlpiStatus(status) {
|
||||||
|
const map = {
|
||||||
|
'Novo': 1,
|
||||||
|
'Pendente': 4,
|
||||||
|
'Em atendimento': 2,
|
||||||
|
'Resolvido': 5
|
||||||
|
}
|
||||||
|
return map[status] || 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTitle(ticket) {
|
||||||
|
return `DOWNGRADE - ${ticket.codigo_cliente}-${ticket.codigo_servico} - ${ticket.nome_razaosocial} - ${ticket.servico_nome}`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 `
|
||||||
|
<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.vendedor || "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;">${documento}</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;">
|
||||||
|
${nl2br(ticket.descricao_abertura) || "N/A"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatCPF(cpf) {
|
||||||
|
return cpf?.replace(/\D/g, '')
|
||||||
|
.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCNPJ(cnpj) {
|
||||||
|
return cnpj?.replace(/\D/g, '')
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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":
|
||||||
|
{ 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" },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
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 }
|
||||||
193
src/modules/tickets/models/glpi/mudancaEndereco.model.js
Normal file
193
src/modules/tickets/models/glpi/mudancaEndereco.model.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
// src/modules/tickets/models/glpi/mudancaEndereco.model.js
|
||||||
|
|
||||||
|
function toGlpiPayload(ticket) {
|
||||||
|
return {
|
||||||
|
entities_id: ticket.entities_id || 0,
|
||||||
|
name: buildTitle(ticket),
|
||||||
|
content: buildHtml(ticket),
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveGlpiStatus(status) {
|
||||||
|
const map = {
|
||||||
|
'Novo': 1,
|
||||||
|
'Pendente': 4,
|
||||||
|
'Em atendimento': 2,
|
||||||
|
'Resolvido': 5
|
||||||
|
}
|
||||||
|
return map[status] || 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTitle(ticket) {
|
||||||
|
return `MUDANCA DE ENDERECO - ${ticket.codigo_cliente}-${ticket.codigo_servico} - ${ticket.nome_razaosocial} - ${ticket.servico_nome}`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 `
|
||||||
|
<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.vendedor || "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;">${documento}</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;">
|
||||||
|
${nl2br(ticket.descricao_abertura) || "N/A"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatCPF(cpf) {
|
||||||
|
return cpf?.replace(/\D/g, '')
|
||||||
|
.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCNPJ(cnpj) {
|
||||||
|
return cnpj?.replace(/\D/g, '')
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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":
|
||||||
|
{ 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" },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
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 }
|
||||||
193
src/modules/tickets/models/glpi/portabilidade.model.js
Normal file
193
src/modules/tickets/models/glpi/portabilidade.model.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
// src/modules/tickets/models/glpi/portabilidade.model.js
|
||||||
|
|
||||||
|
function toGlpiPayload(ticket) {
|
||||||
|
return {
|
||||||
|
entities_id: ticket.entities_id || 0,
|
||||||
|
name: buildTitle(ticket),
|
||||||
|
content: buildHtml(ticket),
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveGlpiStatus(status) {
|
||||||
|
const map = {
|
||||||
|
'Novo': 1,
|
||||||
|
'Pendente': 4,
|
||||||
|
'Em atendimento': 2,
|
||||||
|
'Resolvido': 5
|
||||||
|
}
|
||||||
|
return map[status] || 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTitle(ticket) {
|
||||||
|
return `PORTABILIDADE - ${ticket.codigo_cliente}-${ticket.codigo_servico} - ${ticket.nome_razaosocial} - ${ticket.servico_nome}`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 `
|
||||||
|
<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.vendedor || "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;">${documento}</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;">
|
||||||
|
${nl2br(ticket.descricao_abertura) || "N/A"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatCPF(cpf) {
|
||||||
|
return cpf?.replace(/\D/g, '')
|
||||||
|
.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCNPJ(cnpj) {
|
||||||
|
return cnpj?.replace(/\D/g, '')
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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":
|
||||||
|
{ 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" },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
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 }
|
||||||
193
src/modules/tickets/models/glpi/upgrade.model.js
Normal file
193
src/modules/tickets/models/glpi/upgrade.model.js
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
// src/modules/tickets/models/glpi/upgrade.model.js
|
||||||
|
|
||||||
|
function toGlpiPayload(ticket) {
|
||||||
|
return {
|
||||||
|
entities_id: ticket.entities_id || 0,
|
||||||
|
name: buildTitle(ticket),
|
||||||
|
content: buildHtml(ticket),
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveGlpiStatus(status) {
|
||||||
|
const map = {
|
||||||
|
'Novo': 1,
|
||||||
|
'Pendente': 4,
|
||||||
|
'Em atendimento': 2,
|
||||||
|
'Resolvido': 5
|
||||||
|
}
|
||||||
|
return map[status] || 1
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildTitle(ticket) {
|
||||||
|
return `UPGRADE - ${ticket.codigo_cliente}-${ticket.codigo_servico} - ${ticket.nome_razaosocial} - ${ticket.servico_nome}`
|
||||||
|
}
|
||||||
|
|
||||||
|
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 `
|
||||||
|
<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.vendedor || "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;">${documento}</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;">
|
||||||
|
${nl2br(ticket.descricao_abertura) || "N/A"}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function formatCPF(cpf) {
|
||||||
|
return cpf?.replace(/\D/g, '')
|
||||||
|
.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4')
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatCNPJ(cnpj) {
|
||||||
|
return cnpj?.replace(/\D/g, '')
|
||||||
|
.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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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":
|
||||||
|
{ 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" },
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
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 }
|
||||||
@ -26,18 +26,23 @@ const TYPES = Object.freeze({
|
|||||||
IMPLANTACAO: 21,
|
IMPLANTACAO: 21,
|
||||||
CANCELAMENTO: 27,
|
CANCELAMENTO: 27,
|
||||||
SAC: 41,
|
SAC: 41,
|
||||||
TITULARIDADE: 60
|
TITULARIDADE: 60,
|
||||||
|
UPGRADE: 22,
|
||||||
|
DOWNGRADE: 25,
|
||||||
|
MUDANCA_ENDERECO: 7,
|
||||||
|
PORTABILIDADE: 61,
|
||||||
|
CONSULTA_BASE_ATIVA: 63
|
||||||
});
|
});
|
||||||
|
|
||||||
const RESPONSAVEL_LOOKBACK_DAYS = parsePositiveIntegerEnv(
|
const RESPONSAVEL_LOOKBACK_DAYS = parsePositiveIntegerEnv(
|
||||||
process.env.HUBSOFT_RESPONSAVEL_LOOKBACK_DAYS,
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
365
|
365
|
||||||
);
|
);
|
||||||
|
|
||||||
async function getMundialeTickets(watermark) {
|
async function getMundialeTickets(watermark) {
|
||||||
return hubsoftTicketsRepo.getTicketsByTipo({
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
tipoAtendimento: TYPES.MUNDIALE,
|
tipoAtendimento: TYPES.MUNDIALE,
|
||||||
usuarioAbertura: process.env.HUBSOFT_MUNDIALE_USER_ID,
|
usuarioAbertura: process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
watermark
|
watermark
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -46,7 +51,7 @@ async function getImplantacaoTickets(watermark) {
|
|||||||
return hubsoftTicketsRepo.getTicketsByTipo({
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
tipoAtendimento: TYPES.IMPLANTACAO,
|
tipoAtendimento: TYPES.IMPLANTACAO,
|
||||||
usuariosResponsaveisIds: parseCsvNumberEnv(
|
usuariosResponsaveisIds: parseCsvNumberEnv(
|
||||||
process.env.HUBSOFT_IMPLANTACAO_RESPONSAVEL_USER_IDS,
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
[142]
|
[142]
|
||||||
),
|
),
|
||||||
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
||||||
@ -58,7 +63,7 @@ async function getCancelamentoTickets(watermark) {
|
|||||||
return hubsoftTicketsRepo.getTicketsByTipo({
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
tipoAtendimento: TYPES.CANCELAMENTO,
|
tipoAtendimento: TYPES.CANCELAMENTO,
|
||||||
usuariosResponsaveisIds: parseCsvNumberEnv(
|
usuariosResponsaveisIds: parseCsvNumberEnv(
|
||||||
process.env.HUBSOFT_CANCELAMENTO_RESPONSAVEL_USER_IDS,
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
[142]
|
[142]
|
||||||
),
|
),
|
||||||
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
||||||
@ -77,7 +82,66 @@ async function getTrocaTTickets(watermark) {
|
|||||||
return hubsoftTicketsRepo.getTicketsByTipo({
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
tipoAtendimento: TYPES.TITULARIDADE,
|
tipoAtendimento: TYPES.TITULARIDADE,
|
||||||
usuariosResponsaveisIds: parseCsvNumberEnv(
|
usuariosResponsaveisIds: parseCsvNumberEnv(
|
||||||
process.env.HUBSOFT_TITULARIDADE_RESPONSAVEL_USER_IDS,
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
|
[142]
|
||||||
|
),
|
||||||
|
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
||||||
|
watermark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUpgradeTickets(watermark) {
|
||||||
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
|
tipoAtendimento: TYPES.UPGRADE,
|
||||||
|
usuariosResponsaveisIds: parseCsvNumberEnv(
|
||||||
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
|
[142] ),
|
||||||
|
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
||||||
|
watermark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getDowngradeTickets(watermark) {
|
||||||
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
|
tipoAtendimento: TYPES.DOWNGRADE,
|
||||||
|
usuariosResponsaveisIds: parseCsvNumberEnv(
|
||||||
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
|
[142]
|
||||||
|
),
|
||||||
|
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
||||||
|
watermark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getMudancaEnderecoTickets(watermark) {
|
||||||
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
|
tipoAtendimento: TYPES.MUDANCA_ENDERECO,
|
||||||
|
usuariosResponsaveisIds: parseCsvNumberEnv(
|
||||||
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
|
[142]
|
||||||
|
),
|
||||||
|
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
||||||
|
watermark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getPortabilidadeTickets(watermark) {
|
||||||
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
|
tipoAtendimento: TYPES.PORTABILIDADE,
|
||||||
|
usuariosResponsaveisIds: parseCsvNumberEnv(
|
||||||
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
|
[142]
|
||||||
|
),
|
||||||
|
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
||||||
|
watermark
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getConsultaBaseAtivaTickets(watermark) {
|
||||||
|
return hubsoftTicketsRepo.getTicketsByTipo({
|
||||||
|
tipoAtendimento: TYPES.CONSULTA_BASE_ATIVA,
|
||||||
|
usuariosResponsaveisIds: parseCsvNumberEnv(
|
||||||
|
process.env.HUBSOFT_SUPORTE_USER_ID,
|
||||||
[142]
|
[142]
|
||||||
),
|
),
|
||||||
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
lookbackDays: RESPONSAVEL_LOOKBACK_DAYS,
|
||||||
@ -177,7 +241,11 @@ module.exports = {
|
|||||||
getCancelamentoTickets,
|
getCancelamentoTickets,
|
||||||
getSacTickets,
|
getSacTickets,
|
||||||
getTrocaTTickets,
|
getTrocaTTickets,
|
||||||
|
getUpgradeTickets,
|
||||||
|
getDowngradeTickets,
|
||||||
|
getMudancaEnderecoTickets,
|
||||||
|
getPortabilidadeTickets,
|
||||||
|
getConsultaBaseAtivaTickets,
|
||||||
// hubglpi
|
// hubglpi
|
||||||
insertTicketsHubGlpi,
|
insertTicketsHubGlpi,
|
||||||
insertSyncDataByIds,
|
insertSyncDataByIds,
|
||||||
|
|||||||
43
src/modules/tickets/services/consultaBaseAtiva.service.js
Normal file
43
src/modules/tickets/services/consultaBaseAtiva.service.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// src/modules/tickets/services/consultaBaseAtiva.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/consultaBaseAtiva.model.js')
|
||||||
|
const { logInfo, logError } = require('../../../shared/utils/logger.js')
|
||||||
|
|
||||||
|
async function fetchNew(watermark) {
|
||||||
|
logInfo('[CONSULTA_BASE_ATIVA] Coletando novos chamados')
|
||||||
|
const raw = await repository.getConsultaBaseAtivaTickets(watermark)
|
||||||
|
return raw.map(t => modelHubGlpi.fromHubsoft(t, 'CONSULTA_BASE_ATIVA'))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveHubGlpi(tickets) {
|
||||||
|
if (!tickets.length) return
|
||||||
|
logInfo('[CONSULTA_BASE_ATIVA] Salvando tickets no HubGLPI')
|
||||||
|
await repository.insertTicketsHubGlpi(tickets)
|
||||||
|
await repository.insertSyncDataByIds(tickets.map(t => t.id_atendimento))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendToGlpi(ticket) {
|
||||||
|
logInfo(`[CONSULTA_BASE_ATIVA] 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, 'CONSULTA_BASE_ATIVA')
|
||||||
|
await repository.updateSyncDataCreated(ticket.id_atendimento, glpiId)
|
||||||
|
|
||||||
|
return glpiId
|
||||||
|
} catch (err) {
|
||||||
|
logError(err, `[CONSULTA_BASE_ATIVA] Erro ao enviar ticket ${ticket.id_atendimento}`)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchNew,
|
||||||
|
saveHubGlpi,
|
||||||
|
sendToGlpi
|
||||||
|
}
|
||||||
43
src/modules/tickets/services/downgrade.service.js
Normal file
43
src/modules/tickets/services/downgrade.service.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// src/modules/tickets/services/downgrade.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/downgrade.model.js')
|
||||||
|
const { logInfo, logError } = require('../../../shared/utils/logger.js')
|
||||||
|
|
||||||
|
async function fetchNew(watermark) {
|
||||||
|
logInfo('[DOWNGRADE] Coletando novos chamados')
|
||||||
|
const raw = await repository.getDowngradeTickets(watermark)
|
||||||
|
return raw.map(t => modelHubGlpi.fromHubsoft(t, 'DOWNGRADE'))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveHubGlpi(tickets) {
|
||||||
|
if (!tickets.length) return
|
||||||
|
logInfo('[DOWNGRADE] Salvando tickets no HubGLPI')
|
||||||
|
await repository.insertTicketsHubGlpi(tickets)
|
||||||
|
await repository.insertSyncDataByIds(tickets.map(t => t.id_atendimento))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendToGlpi(ticket) {
|
||||||
|
logInfo(`[DOWNGRADE] 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, 'DOWNGRADE')
|
||||||
|
await repository.updateSyncDataCreated(ticket.id_atendimento, glpiId)
|
||||||
|
|
||||||
|
return glpiId
|
||||||
|
} catch (err) {
|
||||||
|
logError(err, `[DOWNGRADE] Erro ao enviar ticket ${ticket.id_atendimento}`)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchNew,
|
||||||
|
saveHubGlpi,
|
||||||
|
sendToGlpi
|
||||||
|
}
|
||||||
43
src/modules/tickets/services/mudancaEndereco.service.js
Normal file
43
src/modules/tickets/services/mudancaEndereco.service.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// src/modules/tickets/services/mudancaEndereco.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/mudancaEndereco.model.js')
|
||||||
|
const { logInfo, logError } = require('../../../shared/utils/logger.js')
|
||||||
|
|
||||||
|
async function fetchNew(watermark) {
|
||||||
|
logInfo('[MUDANCA_ENDERECO] Coletando novos chamados')
|
||||||
|
const raw = await repository.getMudancaEnderecoTickets(watermark)
|
||||||
|
return raw.map(t => modelHubGlpi.fromHubsoft(t, 'MUDANCA_ENDERECO'))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveHubGlpi(tickets) {
|
||||||
|
if (!tickets.length) return
|
||||||
|
logInfo('[MUDANCA_ENDERECO] Salvando tickets no HubGLPI')
|
||||||
|
await repository.insertTicketsHubGlpi(tickets)
|
||||||
|
await repository.insertSyncDataByIds(tickets.map(t => t.id_atendimento))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendToGlpi(ticket) {
|
||||||
|
logInfo(`[MUDANCA_ENDERECO] 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, 'MUDANCA_ENDERECO')
|
||||||
|
await repository.updateSyncDataCreated(ticket.id_atendimento, glpiId)
|
||||||
|
|
||||||
|
return glpiId
|
||||||
|
} catch (err) {
|
||||||
|
logError(err, `[MUDANCA_ENDERECO] Erro ao enviar ticket ${ticket.id_atendimento}`)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchNew,
|
||||||
|
saveHubGlpi,
|
||||||
|
sendToGlpi
|
||||||
|
}
|
||||||
43
src/modules/tickets/services/portabilidade.service.js
Normal file
43
src/modules/tickets/services/portabilidade.service.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// src/modules/tickets/services/portabilidade.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/portabilidade.model.js')
|
||||||
|
const { logInfo, logError } = require('../../../shared/utils/logger.js')
|
||||||
|
|
||||||
|
async function fetchNew(watermark) {
|
||||||
|
logInfo('[PORTABILIDADE] Coletando novos chamados')
|
||||||
|
const raw = await repository.getPortabilidadeTickets(watermark)
|
||||||
|
return raw.map(t => modelHubGlpi.fromHubsoft(t, 'PORTABILIDADE'))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveHubGlpi(tickets) {
|
||||||
|
if (!tickets.length) return
|
||||||
|
logInfo('[PORTABILIDADE] Salvando tickets no HubGLPI')
|
||||||
|
await repository.insertTicketsHubGlpi(tickets)
|
||||||
|
await repository.insertSyncDataByIds(tickets.map(t => t.id_atendimento))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendToGlpi(ticket) {
|
||||||
|
logInfo(`[PORTABILIDADE] 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, 'PORTABILIDADE')
|
||||||
|
await repository.updateSyncDataCreated(ticket.id_atendimento, glpiId)
|
||||||
|
|
||||||
|
return glpiId
|
||||||
|
} catch (err) {
|
||||||
|
logError(err, `[PORTABILIDADE] Erro ao enviar ticket ${ticket.id_atendimento}`)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchNew,
|
||||||
|
saveHubGlpi,
|
||||||
|
sendToGlpi
|
||||||
|
}
|
||||||
43
src/modules/tickets/services/upgrade.service.js
Normal file
43
src/modules/tickets/services/upgrade.service.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// src/modules/tickets/services/upgrade.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/upgrade.model.js')
|
||||||
|
const { logInfo, logError } = require('../../../shared/utils/logger.js')
|
||||||
|
|
||||||
|
async function fetchNew(watermark) {
|
||||||
|
logInfo('[UPGRADE] Coletando novos chamados')
|
||||||
|
const raw = await repository.getUpgradeTickets(watermark)
|
||||||
|
return raw.map(t => modelHubGlpi.fromHubsoft(t, 'UPGRADE'))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function saveHubGlpi(tickets) {
|
||||||
|
if (!tickets.length) return
|
||||||
|
logInfo('[UPGRADE] Salvando tickets no HubGLPI')
|
||||||
|
await repository.insertTicketsHubGlpi(tickets)
|
||||||
|
await repository.insertSyncDataByIds(tickets.map(t => t.id_atendimento))
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendToGlpi(ticket) {
|
||||||
|
logInfo(`[UPGRADE] 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, 'UPGRADE')
|
||||||
|
await repository.updateSyncDataCreated(ticket.id_atendimento, glpiId)
|
||||||
|
|
||||||
|
return glpiId
|
||||||
|
} catch (err) {
|
||||||
|
logError(err, `[UPGRADE] Erro ao enviar ticket ${ticket.id_atendimento}`)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
fetchNew,
|
||||||
|
saveHubGlpi,
|
||||||
|
sendToGlpi
|
||||||
|
}
|
||||||
@ -7,6 +7,11 @@ 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 trocaTitularidadeService = require('../services/trocaTitularidade.service.js') //TODO
|
||||||
|
const upgradeService = require('../services/upgrade.service.js')
|
||||||
|
const downgradeService = require('../services/downgrade.service.js')
|
||||||
|
const mudancaEnderecoService = require('../services/mudancaEndereco.service.js')
|
||||||
|
const portabilidadeService = require('../services/portabilidade.service.js')
|
||||||
|
const consultaBaseAtivaService = require('../services/consultaBaseAtiva.service.js')
|
||||||
|
|
||||||
const ticketShared = require('../services/createTickets.service.js')
|
const ticketShared = require('../services/createTickets.service.js')
|
||||||
const { logInfo, logError } = require('../../../shared/utils/logger.js')
|
const { logInfo, logError } = require('../../../shared/utils/logger.js')
|
||||||
@ -34,19 +39,44 @@ async function syncTicketsUseCase() {
|
|||||||
const trocaTitularidade = await trocaTitularidadeService.fetchNew(waterMark)
|
const trocaTitularidade = await trocaTitularidadeService.fetchNew(waterMark)
|
||||||
logInfo(`[USECASE] ${trocaTitularidade.length} tickets Troca de Titularidade encontrados`)
|
logInfo(`[USECASE] ${trocaTitularidade.length} tickets Troca de Titularidade encontrados`)
|
||||||
|
|
||||||
|
const upgrade = await upgradeService.fetchNew(waterMark)
|
||||||
|
logInfo(`[USECASE] ${upgrade.length} tickets Upgrade encontrados`)
|
||||||
|
|
||||||
|
const downgrade = await downgradeService.fetchNew(waterMark)
|
||||||
|
logInfo(`[USECASE] ${downgrade.length} tickets Downgrade encontrados`)
|
||||||
|
|
||||||
|
const mudancaEndereco = await mudancaEnderecoService.fetchNew(waterMark)
|
||||||
|
logInfo(`[USECASE] ${mudancaEndereco.length} tickets Mudança de Endereço encontrados`)
|
||||||
|
|
||||||
|
const portabilidade = await portabilidadeService.fetchNew(waterMark)
|
||||||
|
logInfo(`[USECASE] ${portabilidade.length} tickets Portabilidade encontrados`)
|
||||||
|
|
||||||
|
const consultaBaseAtiva = await consultaBaseAtivaService.fetchNew(waterMark)
|
||||||
|
logInfo(`[USECASE] ${consultaBaseAtiva.length} tickets Consulta Base Ativa 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 sacService.saveHubGlpi(sac) //TODO
|
||||||
await trocaTitularidadeService.saveHubGlpi(trocaTitularidade)
|
await trocaTitularidadeService.saveHubGlpi(trocaTitularidade)
|
||||||
|
await upgradeService.saveHubGlpi(upgrade)
|
||||||
|
await downgradeService.saveHubGlpi(downgrade)
|
||||||
|
await mudancaEnderecoService.saveHubGlpi(mudancaEndereco)
|
||||||
|
await portabilidadeService.saveHubGlpi(portabilidade)
|
||||||
|
await consultaBaseAtivaService.saveHubGlpi(consultaBaseAtiva)
|
||||||
|
|
||||||
const allFetchedTickets = [
|
const allFetchedTickets = [
|
||||||
...mundiale,
|
...mundiale,
|
||||||
...implantacao,
|
...implantacao,
|
||||||
...cancelamento,
|
...cancelamento,
|
||||||
//...sac,
|
//...sac,
|
||||||
...trocaTitularidade
|
...trocaTitularidade,
|
||||||
|
...upgrade,
|
||||||
|
...downgrade,
|
||||||
|
...mudancaEndereco,
|
||||||
|
...portabilidade,
|
||||||
|
...consultaBaseAtiva
|
||||||
]
|
]
|
||||||
|
|
||||||
const newWaterMark = resolveNewWatermark(allFetchedTickets, waterMark)
|
const newWaterMark = resolveNewWatermark(allFetchedTickets, waterMark)
|
||||||
@ -86,7 +116,12 @@ function resolveTicketService(type) {
|
|||||||
IMPLANTACAO: implantacaoService,
|
IMPLANTACAO: implantacaoService,
|
||||||
CANCELAMENTO: cancelamentoService,
|
CANCELAMENTO: cancelamentoService,
|
||||||
//SAC: sacService, //TODO
|
//SAC: sacService, //TODO
|
||||||
TITULARIDADE: trocaTitularidadeService
|
TITULARIDADE: trocaTitularidadeService,
|
||||||
|
UPGRADE: upgradeService,
|
||||||
|
DOWNGRADE: downgradeService,
|
||||||
|
MUDANCA_ENDERECO: mudancaEnderecoService,
|
||||||
|
PORTABILIDADE: portabilidadeService,
|
||||||
|
CONSULTA_BASE_ATIVA: consultaBaseAtivaService
|
||||||
}
|
}
|
||||||
|
|
||||||
return map[type]
|
return map[type]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user