git-subtree-dir: relatorio git-subtree-mainline:e322cec92bgit-subtree-split:34bcb132f3
194 lines
6.0 KiB
JavaScript
194 lines
6.0 KiB
JavaScript
'use strict';
|
|
|
|
/**
|
|
* Montagem das mensagens finais.
|
|
*
|
|
* formatFallbackMessage: PORTA quase literal da mensagem da V1 (node
|
|
* "Code - Preparar indicadores" dos dois workflows *-SQL-Slack.n8n.json).
|
|
* Usada em dois lugares na V2:
|
|
* 1. Como fallback real quando a IA falha/timeout/JSON invalido.
|
|
* 2. Como "mensagem V1" no payload de comparacao do shadow mode.
|
|
*
|
|
* formatShortMessage: mensagem curta da V2 (secoes 16 e 18 da missao).
|
|
*/
|
|
|
|
function formatDataBr(isoDate) {
|
|
const [ano, mes, dia] = isoDate.split('-');
|
|
return `${dia}/${mes}`;
|
|
}
|
|
|
|
function formatSaldo(saldo) {
|
|
return saldo > 0 ? `+${saldo}` : String(saldo);
|
|
}
|
|
|
|
/** Igual ao texto que a V1 ja envia hoje (nao mudar sem motivo). */
|
|
function formatFallbackMessage(row) {
|
|
const ehSemanal = row.tipo_periodo === 'semanal';
|
|
const titulo = ehSemanal
|
|
? '*Resumo semanal do suporte GLPI*'
|
|
: '*Resumo diario do suporte GLPI*';
|
|
const escopo = ehSemanal ? 'Periodo do relatorio' : 'Data do relatorio';
|
|
const unidade = ehSemanal ? 'no periodo' : 'no dia';
|
|
|
|
const linhas = [
|
|
titulo,
|
|
'',
|
|
`${escopo}: ${row.periodo_label}`,
|
|
'',
|
|
'*Resumo geral*',
|
|
`- Chamados abertos ${unidade}: ${row.abertos}`,
|
|
`- Chamados fechados ${unidade}: ${row.fechados}`,
|
|
`- Pendentes atuais: ${row.pendentes}`,
|
|
`- Alta prioridade ainda pendentes: ${row.alta_prioridade_pendentes}`,
|
|
`- Saldo fechados - abertos: ${row.saldo}`,
|
|
'',
|
|
'*Categorias mais recorrentes*',
|
|
...String(row.categorias_recorrentes || 'Sem registros')
|
|
.split('\n')
|
|
.map((l) => `- ${l}`),
|
|
'',
|
|
'*Clientes com maior volume*',
|
|
...String(row.clientes_volume || 'Sem registros')
|
|
.split('\n')
|
|
.map((l) => `- ${l}`),
|
|
'',
|
|
'*Observacao*',
|
|
`- Chamados fechados ${unidade} podem ter sido abertos em datas anteriores.`,
|
|
];
|
|
|
|
return linhas.join('\n');
|
|
}
|
|
|
|
/**
|
|
* Status operacional (semaforo interno, secao 21). So aparece na mensagem
|
|
* quando agrega valor (usado hoje apenas para escolher o tom da linha de
|
|
* tendencia/leitura).
|
|
*/
|
|
function computeOperationalStatus({ insightsAceitos, tendenciaBacklog }) {
|
|
const temAlta = insightsAceitos.some((i) => i.severity === 'high');
|
|
if (temAlta) return 'CRITICAL';
|
|
|
|
const temMedia = insightsAceitos.some((i) => i.severity === 'medium');
|
|
if (temMedia || tendenciaBacklog.direcao === 'aumentando') return 'ATTENTION';
|
|
|
|
return 'NORMAL';
|
|
}
|
|
|
|
function buildDestaques({ topCategoria, concentracoesCliente, altaPrioridadeDelta, insightsAceitos, unidade }, config) {
|
|
const destaques = [];
|
|
|
|
if (topCategoria && topCategoria.total > 0) {
|
|
destaques.push(`${topCategoria.nome} liderou ${unidade} com ${topCategoria.total} chamados.`);
|
|
}
|
|
|
|
for (const c of concentracoesCliente || []) {
|
|
destaques.push(`${c.cliente} concentrou ${c.total} chamados (${Math.round(c.share * 100)}% ${unidade}).`);
|
|
}
|
|
|
|
if (altaPrioridadeDelta && altaPrioridadeDelta.anterior !== null && altaPrioridadeDelta.atual !== altaPrioridadeDelta.anterior) {
|
|
const verbo = altaPrioridadeDelta.atual > altaPrioridadeDelta.anterior ? 'subiram' : 'cairam';
|
|
destaques.push(
|
|
`Chamados de alta prioridade ${verbo} de ${altaPrioridadeDelta.anterior} para ${altaPrioridadeDelta.atual}.`
|
|
);
|
|
}
|
|
|
|
for (const insight of insightsAceitos) {
|
|
const ocorrencia = insight.occurrenceText;
|
|
destaques.push(`${insight.title}${ocorrencia ? ` (${ocorrencia})` : ''}.`);
|
|
}
|
|
|
|
return destaques.slice(0, config.MAX_REPORT_INSIGHTS);
|
|
}
|
|
|
|
function buildTrendLine({ status, tendenciaBacklog, tipoPeriodo }) {
|
|
const rotuloBacklog =
|
|
tendenciaBacklog.direcao === 'aumentando'
|
|
? 'aumento do backlog no periodo'
|
|
: tendenciaBacklog.direcao === 'diminuindo'
|
|
? 'reducao do backlog no periodo'
|
|
: tendenciaBacklog.direcao === 'indisponivel'
|
|
? 'backlog sem historico suficiente para comparacao'
|
|
: 'backlog estavel no periodo';
|
|
|
|
const abertura =
|
|
status === 'CRITICAL'
|
|
? 'Operacao requer atencao'
|
|
: status === 'ATTENTION'
|
|
? tipoPeriodo === 'semanal'
|
|
? 'Semana com pontos de atencao'
|
|
: 'Operacao com pontos de atencao'
|
|
: tipoPeriodo === 'semanal'
|
|
? 'Semana equilibrada'
|
|
: 'Operacao estavel';
|
|
|
|
return `${abertura}, com ${rotuloBacklog}.`;
|
|
}
|
|
|
|
/**
|
|
* Monta a mensagem curta final da V2.
|
|
*
|
|
* @param {object} dados - numeros deterministicos + insights ja sanitizados
|
|
* @param {object} config
|
|
*/
|
|
function formatShortMessage(dados, config) {
|
|
const ehSemanal = dados.tipo_periodo === 'semanal';
|
|
const unidade = ehSemanal ? 'no periodo' : 'no dia';
|
|
const tituloData = ehSemanal
|
|
? `${formatDataBr(dados.data_inicio)} a ${formatDataBr(dados.data_fim)}`
|
|
: formatDataBr(dados.data_inicio);
|
|
const titulo = ehSemanal
|
|
? `Resumo semanal do suporte — ${tituloData}`
|
|
: `Resumo do suporte — ${tituloData}`;
|
|
|
|
const status = computeOperationalStatus({
|
|
insightsAceitos: dados.insightsAceitos,
|
|
tendenciaBacklog: dados.tendenciaBacklog,
|
|
});
|
|
|
|
const destaques = buildDestaques(
|
|
{
|
|
topCategoria: dados.topCategoria,
|
|
concentracoesCliente: dados.concentracoesCliente,
|
|
altaPrioridadeDelta: dados.altaPrioridadeDelta,
|
|
insightsAceitos: dados.insightsAceitos,
|
|
unidade,
|
|
},
|
|
config
|
|
);
|
|
|
|
const linhaTendencia = buildTrendLine({
|
|
status,
|
|
tendenciaBacklog: dados.tendenciaBacklog,
|
|
tipoPeriodo: dados.tipo_periodo,
|
|
});
|
|
|
|
const blocos = [
|
|
titulo,
|
|
'',
|
|
`${dados.abertos} abertos | ${dados.fechados} fechados | saldo ${formatSaldo(dados.saldo)}`,
|
|
`${dados.pendentes} pendentes | ${dados.alta_prioridade_pendentes} alta prioridade`,
|
|
'',
|
|
ehSemanal ? 'Destaques' : 'Destaques',
|
|
];
|
|
|
|
if (destaques.length === 0) {
|
|
blocos.push('• Sem anomalias relevantes no periodo.');
|
|
} else {
|
|
for (const d of destaques) blocos.push(`• ${d}`);
|
|
}
|
|
|
|
blocos.push('', ehSemanal ? 'Leitura' : 'Tendencia', `→ ${linhaTendencia}`);
|
|
|
|
return { texto: blocos.join('\n'), status };
|
|
}
|
|
|
|
module.exports = {
|
|
formatDataBr,
|
|
formatSaldo,
|
|
formatFallbackMessage,
|
|
computeOperationalStatus,
|
|
buildDestaques,
|
|
buildTrendLine,
|
|
formatShortMessage,
|
|
};
|