diagnostico: adicionada função (TESTING)
Signed-off-by: Rodrigo Bertoldo de Sousa Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
1 parent
7f38d16821
commit
0dbab52aa1
3 files changed
+430
-1
No files matched your search
@@ -226,6 +226,11 @@ class BotHandler {
|
||||
await this.handleListarServicos(chatId, target);
|
||||
break;
|
||||
|
||||
case 'diagnosticar':
|
||||
console.log(`🩺 Executando handleDiagnosticarCliente com target: ${target}`);
|
||||
await this.handleDiagnosticarCliente(chatId, target);
|
||||
break;
|
||||
|
||||
case 'dados_cliente':
|
||||
case 'dados_cadastrais':
|
||||
console.log(`📋 Executando handleDadosClientePorBusca com target: ${target}`);
|
||||
@@ -871,6 +876,355 @@ Digite /help para ver todos os comandos disponíveis!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diagnóstico completo de um cliente: TopSapp + Juniper PPPoE + ONU
|
||||
*/
|
||||
async handleDiagnosticarCliente(chatId, query) {
|
||||
if (!query) {
|
||||
await this.bot.sendMessage(chatId,
|
||||
`🩺 *Diagnóstico de Cliente*\n\n` +
|
||||
`💡 *Como usar:*\n` +
|
||||
`• "diagnosticar João da Silva"\n` +
|
||||
`• "diagnosticar 123.456.789-10"\n\n` +
|
||||
`O diagnóstico verifica: status no TopSapp, sessão PPPoE no concentrador e status da ONU.`,
|
||||
{ parse_mode: 'Markdown' }
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
|
||||
|
||||
let location = '';
|
||||
let searchQuery = query;
|
||||
|
||||
if (/guarai|colmeia/i.test(query)) {
|
||||
location = 'Guarai/Colmeia';
|
||||
searchQuery = query.replace(/(guarai|colmeia)/gi, '').trim();
|
||||
} else if (/pedro afonso/i.test(query)) {
|
||||
location = 'Pedro Afonso';
|
||||
searchQuery = query.replace(/pedro afonso/gi, '').trim();
|
||||
}
|
||||
|
||||
const resultado = await this.topsapp.buscarCliente(searchQuery, location);
|
||||
|
||||
if (!resultado.success) {
|
||||
await this.bot.sendMessage(chatId, `❌ Erro na busca: ${resultado.error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!resultado.clientes || resultado.clientes.length === 0) {
|
||||
await this.bot.sendMessage(chatId, `🔍 Nenhum cliente encontrado para: "${searchQuery}"`);
|
||||
return;
|
||||
}
|
||||
|
||||
const instancia = resultado.instancia || location;
|
||||
|
||||
if (resultado.clientes.length === 1) {
|
||||
await this._mostrarServicosParaDiagnostico(chatId, resultado.clientes[0].id, instancia);
|
||||
return;
|
||||
}
|
||||
|
||||
// Múltiplos clientes → exibir teclado de seleção
|
||||
let message = `🔍 *${resultado.clientes.length} clientes encontrados*\n\n`;
|
||||
const keyboard = [];
|
||||
|
||||
resultado.clientes.slice(0, 8).forEach((cliente, index) => {
|
||||
message += `*${index + 1}.* ${cliente.nome}`;
|
||||
if (cliente.cpf) message += ` — CPF: \`${cliente.cpf}\``;
|
||||
message += `\n`;
|
||||
|
||||
keyboard.push([{
|
||||
text: `🩺 Diagnosticar: ${cliente.nome.substring(0, 30)}`,
|
||||
callback_data: `diag_cliente_${cliente.id}_${instancia}`
|
||||
}]);
|
||||
});
|
||||
|
||||
await this.bot.sendMessage(chatId, message, {
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: { inline_keyboard: keyboard }
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro em handleDiagnosticarCliente:', error);
|
||||
await this.bot.sendMessage(chatId, `❌ Erro: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async _mostrarServicosParaDiagnostico(chatId, idCliente, location) {
|
||||
const servicosResult = await this.topsapp.obterServicosCliente(idCliente, location);
|
||||
|
||||
if (!servicosResult.success) {
|
||||
await this.bot.sendMessage(chatId, `❌ Erro ao buscar serviços: ${servicosResult.error}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const servicos = (servicosResult.servicos || []).filter(s => {
|
||||
const st = (s.id_status || s.statusNumerico);
|
||||
return st === 1 || st === '1' || String(s.status).toLowerCase() === 'liberado' || String(s.status).toLowerCase() === 'ativo';
|
||||
});
|
||||
|
||||
if (servicos.length === 0) {
|
||||
await this.bot.sendMessage(chatId, `⚠️ Cliente sem serviços ativos para diagnosticar.`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (servicos.length === 1) {
|
||||
await this.runDiagnosticoServico(chatId, idCliente, servicos[0].id_servico || servicos[0].id, location, servicos[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
let message = `🩺 *Selecione o serviço para diagnosticar:*\n\n`;
|
||||
const keyboard = [];
|
||||
|
||||
servicos.forEach((s, i) => {
|
||||
const nome = s.descricao || s.nome || `Serviço ${i + 1}`;
|
||||
const login = s.usuario || s.pppoe_login || s.login || '';
|
||||
message += `*${i + 1}.* ${nome}${login ? ` — \`${login}\`` : ''}\n`;
|
||||
keyboard.push([{
|
||||
text: `🔍 ${nome.substring(0, 35)}`,
|
||||
callback_data: `diag_servico_${idCliente}_${s.id_servico || s.id}_${location}`
|
||||
}]);
|
||||
});
|
||||
|
||||
await this.bot.sendMessage(chatId, message, {
|
||||
parse_mode: 'Markdown',
|
||||
reply_markup: { inline_keyboard: keyboard }
|
||||
});
|
||||
}
|
||||
|
||||
async handleDiagClienteCallback(callbackQuery, data) {
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
const parts = data.replace('diag_cliente_', '').split('_');
|
||||
const idCliente = parts[0];
|
||||
const location = parts.slice(1).join('_');
|
||||
|
||||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||||
await this._mostrarServicosParaDiagnostico(chatId, idCliente, location);
|
||||
}
|
||||
|
||||
async handleDiagServicoCallback(callbackQuery, data) {
|
||||
const chatId = callbackQuery.message.chat.id;
|
||||
const parts = data.replace('diag_servico_', '').split('_');
|
||||
const idCliente = parts[0];
|
||||
const idServico = parts[1];
|
||||
const location = parts.slice(2).join('_');
|
||||
|
||||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||||
await this.runDiagnosticoServico(chatId, idCliente, idServico, location, null);
|
||||
}
|
||||
|
||||
async runDiagnosticoServico(chatId, idCliente, idServico, location, servicoPreCarregado) {
|
||||
try {
|
||||
await this.bot.sendMessage(chatId, '⏳ Executando diagnóstico completo...');
|
||||
|
||||
// Buscar serviços caso não tenhamos o objeto do serviço
|
||||
let servico = servicoPreCarregado;
|
||||
if (!servico) {
|
||||
const servicosResult = await this.topsapp.obterServicosCliente(idCliente, location);
|
||||
if (!servicosResult.success) {
|
||||
await this.bot.sendMessage(chatId, `❌ Erro ao buscar serviços: ${servicosResult.error}`);
|
||||
return;
|
||||
}
|
||||
const idNum = parseInt(idServico, 10);
|
||||
servico = (servicosResult.servicos || []).find(s =>
|
||||
(s.id_servico || s.id) === idNum || String(s.id_servico || s.id) === String(idServico)
|
||||
);
|
||||
}
|
||||
|
||||
if (!servico) {
|
||||
await this.bot.sendMessage(chatId, `❌ Serviço #${idServico} não encontrado.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const pppoeLogin = servico.usuario || servico.pppoe_login || servico.login || null;
|
||||
const serial = servico.serial || servico.comodato_serial || servico.mac || null;
|
||||
const statusServico = this.topsapp.getStatusServicoDetalhado
|
||||
? this.topsapp.getStatusServicoDetalhado(servico.id_status)
|
||||
: (servico.status || 'N/A');
|
||||
const nomePlano = servico.descricao || servico.nome || 'N/A';
|
||||
const endereco = servico.instalacao_endereco || servico.end_rua || null;
|
||||
const cidade = servico.instalacao_cidade || null;
|
||||
|
||||
// Executar consultas em paralelo: Juniper + ONU
|
||||
const [juniperResult, onuResult] = await Promise.all([
|
||||
pppoeLogin
|
||||
? this.ssh.getJuniperSubscriberInfo('juniper', pppoeLogin).catch(e => ({ success: false, error: e.message }))
|
||||
: Promise.resolve({ success: false, skipped: true }),
|
||||
serial
|
||||
? this._diagnosticarONU(serial).catch(e => ({ success: false, error: e.message }))
|
||||
: Promise.resolve({ success: false, skipped: true })
|
||||
]);
|
||||
|
||||
// Montar relatório
|
||||
let msg = `🩺 *Diagnóstico do Cliente*\n`;
|
||||
msg += `━━━━━━━━━━━━━━━━━━━━━\n\n`;
|
||||
|
||||
// Bloco 1: TopSapp
|
||||
msg += `📋 *Serviço TopSapp*\n`;
|
||||
msg += ` 📦 Plano: ${nomePlano}\n`;
|
||||
msg += ` 🔌 Status: ${statusServico}\n`;
|
||||
if (pppoeLogin) msg += ` 👤 Login PPPoE: \`${pppoeLogin}\`\n`;
|
||||
if (endereco) msg += ` 📍 Endereço: ${endereco}${cidade ? `, ${cidade}` : ''}\n`;
|
||||
msg += '\n';
|
||||
|
||||
// Bloco 2: Concentrador Juniper
|
||||
msg += `🌐 *Concentrador Juniper*\n`;
|
||||
if (juniperResult.skipped) {
|
||||
msg += ` ⚫ Login PPPoE não informado no cadastro\n`;
|
||||
} else if (!juniperResult.success) {
|
||||
msg += ` ⚠️ Erro ao consultar: ${juniperResult.error || 'falha na consulta'}\n`;
|
||||
} else if (juniperResult.connected) {
|
||||
msg += ` 🟢 *Conectado*\n`;
|
||||
msg += ` 🌐 IP: \`${juniperResult.ip || 'N/A'}\`\n`;
|
||||
msg += ` 🔌 Interface: \`${juniperResult.interface || 'N/A'}\`\n`;
|
||||
} else {
|
||||
msg += ` 🔴 *Desconectado* (sem sessão PPPoE ativa)\n`;
|
||||
}
|
||||
msg += '\n';
|
||||
|
||||
// Bloco 3: ONU
|
||||
msg += `📡 *ONU / ONT*\n`;
|
||||
if (onuResult.skipped) {
|
||||
msg += ` ⚫ Serial não informado no cadastro\n`;
|
||||
} else if (!onuResult.success) {
|
||||
msg += ` ❌ ${onuResult.error || 'ONU não encontrada'}\n`;
|
||||
if (serial) msg += ` 📋 Serial buscado: \`${serial}\`\n`;
|
||||
} else {
|
||||
const rxLabel = onuResult.rxPower || 'N/A';
|
||||
const rxNum = parseFloat(rxLabel);
|
||||
const rxEmoji = isNaN(rxNum) ? '⚫' : rxNum >= -27 ? '🟢' : rxNum >= -30 ? '🟡' : '🔴';
|
||||
|
||||
msg += ` 📋 Serial: \`${serial}\`\n`;
|
||||
msg += ` 🏢 OLT: ${onuResult.oltName || onuResult.oltType || 'N/A'}\n`;
|
||||
if (onuResult.slot || onuResult.pon) {
|
||||
msg += ` 📍 Slot/PON: ${onuResult.slot || '?'}/${onuResult.pon || '?'}\n`;
|
||||
}
|
||||
msg += ` 🔌 Estado: ${onuResult.online ? '🟢 Online' : '🔴 Offline'}\n`;
|
||||
msg += ` ${rxEmoji} Rx Power: *${rxLabel}*`;
|
||||
if (onuResult.type === 'fiberhome') msg += ` _(compensado)_`;
|
||||
msg += '\n';
|
||||
|
||||
if (onuResult.portaEthernet) {
|
||||
const ethOk = /forward|up|1gbit|100mbit/i.test(onuResult.portaEthernet);
|
||||
msg += ` ${ethOk ? '🟢' : '🔴'} Porta Ethernet: ${onuResult.portaEthernet}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
await this.bot.sendMessage(chatId, msg, { parse_mode: 'Markdown' });
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro em runDiagnosticoServico:', error);
|
||||
await this.bot.sendMessage(chatId, `❌ Erro no diagnóstico: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Diagnóstico de ONU: detecta tipo (Datacom/FiberHome) e retorna dados estruturados
|
||||
*/
|
||||
async _diagnosticarONU(serial) {
|
||||
const serialUpper = serial.toUpperCase();
|
||||
|
||||
if (serialUpper.startsWith('DACM')) {
|
||||
return await this._diagnosticarONUDatacom(serial);
|
||||
} else {
|
||||
return await this._diagnosticarONUFiberhome(serial);
|
||||
}
|
||||
}
|
||||
|
||||
async _diagnosticarONUDatacom(serial) {
|
||||
const olts = this.ssh.listOLTs();
|
||||
if (olts.length === 0) {
|
||||
return { success: false, error: 'Nenhuma OLT Datacom configurada' };
|
||||
}
|
||||
|
||||
// Buscar ONU em todas as OLTs em paralelo
|
||||
const searches = olts.map(olt =>
|
||||
this.ssh.findOnuBySerial(olt.id, serial)
|
||||
.then(r => ({ ...r, oltId: olt.id, oltName: olt.name }))
|
||||
.catch(() => ({ success: false }))
|
||||
);
|
||||
const results = await Promise.allSettled(searches);
|
||||
|
||||
let found = null;
|
||||
for (const r of results) {
|
||||
if (r.status === 'fulfilled' && r.value.success) {
|
||||
found = r.value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
return { success: false, error: `ONU ${serial} não encontrada em nenhuma OLT Datacom` };
|
||||
}
|
||||
|
||||
const { oltId, oltName, onuInfo } = found;
|
||||
const { slot, onuId } = onuInfo;
|
||||
|
||||
// Buscar sinal e porta ethernet em paralelo
|
||||
const [signalResult, ethResult] = await Promise.all([
|
||||
this.ssh.checkOnuSignal(oltId, slot, onuId).catch(e => ({ success: false, error: e.message })),
|
||||
this.ssh.checkOnuEthernetDatacom(oltId, slot, onuId).catch(e => ({ success: false }))
|
||||
]);
|
||||
|
||||
// Parsear sinal
|
||||
const rawSignal = signalResult.output || '';
|
||||
const stateMatch = rawSignal.match(/Operational\s+state\s*:\s*(\S+)/i);
|
||||
const rxMatch = rawSignal.match(/Rx\s+Optical\s+Power\s*\[dBm\]\s*:\s*([-\d.]+)/i);
|
||||
|
||||
const operationalState = stateMatch ? stateMatch[1] : null;
|
||||
const rxPower = rxMatch ? `${rxMatch[1]} dBm` : null;
|
||||
const online = operationalState ? /up|active|online/i.test(operationalState) : false;
|
||||
|
||||
// Parsear ethernet
|
||||
let portaEthernet = null;
|
||||
if (ethResult.success) {
|
||||
const ethRaw = ethResult.rawOutput || '';
|
||||
const ethMatch = ethRaw.match(/\b(Forwarding|Down|Up|Blocking)\b[^\n]*([\d]+(?:Gbit|Mbit)[^\n]*|N\/A)?/i);
|
||||
if (ethMatch) {
|
||||
portaEthernet = ethMatch[0].trim().replace(/\s+/g, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
type: 'datacom',
|
||||
oltName,
|
||||
slot,
|
||||
pon: slot ? slot.split('/')[2] || slot : null,
|
||||
onuId,
|
||||
online,
|
||||
rxPower,
|
||||
operationalState,
|
||||
portaEthernet
|
||||
};
|
||||
}
|
||||
|
||||
async _diagnosticarONUFiberhome(serial) {
|
||||
const resultado = await this.fiberhome.obterStatusONU(serial);
|
||||
|
||||
if (!resultado.success) {
|
||||
return { success: false, error: resultado.error || 'ONU não encontrada na FiberHome' };
|
||||
}
|
||||
|
||||
const portaPrincipal = resultado.portasEthernet && resultado.portasEthernet.length > 0
|
||||
? resultado.portasEthernet[0]
|
||||
: null;
|
||||
|
||||
return {
|
||||
success: true,
|
||||
type: 'fiberhome',
|
||||
oltName: 'FiberHome',
|
||||
slot: resultado.slot,
|
||||
pon: resultado.pon,
|
||||
onuId: resultado.onuId,
|
||||
online: resultado.online,
|
||||
rxPower: resultado.rxPower,
|
||||
txPower: resultado.txPower,
|
||||
portaEthernet: portaPrincipal ? `${portaPrincipal.status}` : null
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Verificar sinal de ONU
|
||||
*/
|
||||
@@ -1539,6 +1893,12 @@ Digite /help para ver todos os comandos disponíveis!
|
||||
const serialNumber = data.replace('fiberhome_details_', '');
|
||||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||||
await this.handleStatusONU(chatId, serialNumber);
|
||||
} else if (data.startsWith('diag_cliente_')) {
|
||||
console.log(`🔍 Condição diag_cliente_ atendida`);
|
||||
await this.handleDiagClienteCallback(callbackQuery, data);
|
||||
} else if (data.startsWith('diag_servico_')) {
|
||||
console.log(`🔍 Condição diag_servico_ atendida`);
|
||||
await this.handleDiagServicoCallback(callbackQuery, data);
|
||||
} else if (data.startsWith('dados_cliente_')) {
|
||||
console.log(`🔍 Condição dados_cliente_ atendida`);
|
||||
await this.handleDadosClienteCallback(callbackQuery, data);
|
||||
|
||||
Reference in new issue
Block a user