4586 lines
186 KiB
JavaScript
4586 lines
186 KiB
JavaScript
const NLPProcessor = require('../nlp/processor');
|
||
const SSHManager = require('../ssh/manager');
|
||
const { TopSappManager } = require('../topsapp');
|
||
const FiberhomeManager = require('../fiberhome/manager');
|
||
const config = require('../config/config');
|
||
const logger = require('../utils/logger');
|
||
|
||
class BotHandler {
|
||
constructor(bot) {
|
||
this.bot = bot;
|
||
this.nlp = new NLPProcessor();
|
||
this.ssh = new SSHManager();
|
||
this.topsapp = new TopSappManager();
|
||
this.fiberhome = new FiberhomeManager();
|
||
this.userSessions = new Map(); // Armazena sessões de usuário
|
||
|
||
logger.info('BotHandler inicializado');
|
||
console.log('🎯 BotHandler inicializado');
|
||
}
|
||
|
||
/**
|
||
* Verifica se o usuário tem permissão
|
||
*/
|
||
isAuthorized(userId) {
|
||
if (config.bot.allowedUsers.length === 0) {
|
||
return true; // Se não há lista de usuários, permite todos
|
||
}
|
||
return config.bot.allowedUsers.includes(userId);
|
||
}
|
||
|
||
/**
|
||
* Processa mensagens recebidas
|
||
*/
|
||
async handleMessage(msg) {
|
||
const chatId = msg.chat.id;
|
||
const userId = msg.from.id;
|
||
const text = msg.text;
|
||
|
||
// Log da mensagem
|
||
if (config.bot.debug) {
|
||
console.log(`📨 Mensagem de ${msg.from.first_name} (${userId}): ${text}`);
|
||
}
|
||
|
||
// Verificar autorização
|
||
if (!this.isAuthorized(userId)) {
|
||
await this.bot.sendMessage(chatId,
|
||
`🚫 **Acesso Negado**\n\n` +
|
||
`❌ Você não tem permissão para usar este bot.\n` +
|
||
`🆔 Seu ID: \`${userId}\`\n\n` +
|
||
`📞 Entre em contato com o administrador para solicitar acesso.`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
console.log(`🚫 Acesso negado para usuário ${msg.from.first_name} (${userId})`);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Verificar se o usuário está em uma sessão esperando input
|
||
const userSession = this.userSessions.get(userId);
|
||
if (userSession) {
|
||
await this.handleUserSessionInput(chatId, text, userId, userSession);
|
||
return;
|
||
}
|
||
|
||
// Processar a mensagem com NLP
|
||
const intent = this.nlp.processMessage(text);
|
||
|
||
if (config.bot.debug) {
|
||
console.log('🧠 Intent detectado:', intent);
|
||
}
|
||
|
||
// Executar ação baseada na intenção
|
||
await this.executeAction(chatId, intent, msg.from);
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao processar mensagem:', error);
|
||
await this.bot.sendMessage(chatId, '❌ Ocorreu um erro ao processar sua mensagem. Tente novamente.');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Executa ação baseada na intenção detectada
|
||
*/
|
||
async executeAction(chatId, intent, user) {
|
||
const { action, target, confidence, type } = intent;
|
||
|
||
// Se a confiança é muito baixa, pedir esclarecimento
|
||
if (confidence < 0.3 && action) {
|
||
const suggestions = this.nlp.suggestCorrection(action);
|
||
let message = '🤔 Não entendi muito bem. ';
|
||
|
||
if (suggestions.length > 0) {
|
||
message += `Você quis dizer: ${suggestions.join(', ')}?`;
|
||
} else {
|
||
message += 'Digite /help para ver os comandos disponíveis.';
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message);
|
||
return;
|
||
}
|
||
|
||
// Executar ação específica
|
||
try {
|
||
switch (action) {
|
||
case 'start':
|
||
await this.handleStart(chatId, user);
|
||
break;
|
||
|
||
case 'help':
|
||
await this.handleHelp(chatId);
|
||
break;
|
||
|
||
case 'ssh':
|
||
await this.handleSSH(chatId, target);
|
||
break;
|
||
|
||
case 'status':
|
||
await this.handleStatus(chatId, target);
|
||
break;
|
||
|
||
case 'lista':
|
||
case 'equipamentos':
|
||
await this.handleListEquipments(chatId);
|
||
break;
|
||
|
||
case 'listar_usuarios':
|
||
await this.handleListUsers(chatId, target);
|
||
break;
|
||
|
||
case 'admin':
|
||
case 'administracao':
|
||
await this.handleAdmin(chatId);
|
||
break;
|
||
|
||
case 'logs':
|
||
await this.handleViewLogs(chatId);
|
||
break;
|
||
|
||
case 'limpar_logs':
|
||
await this.handleClearLogs(chatId);
|
||
break;
|
||
|
||
case 'usuarios_autorizados':
|
||
await this.handleListAuthorizedUsers(chatId);
|
||
break;
|
||
|
||
case 'meu_id':
|
||
case 'meu_user_id':
|
||
await this.handleMyId(chatId, userId);
|
||
break;
|
||
|
||
case 'ver_sinal':
|
||
console.log(`🔍 Executando handleVerSinal com target: ${target}`);
|
||
await this.handleVerSinal(chatId, target);
|
||
break;
|
||
|
||
case 'remover_onu':
|
||
console.log(`🗑️ Executando handleRemoverOnu com target: ${target}`);
|
||
await this.handleRemoverOnu(chatId, target);
|
||
break;
|
||
|
||
case 'adicionar_onu':
|
||
console.log(`➕ Executando handleAdicionarOnu com target: ${target}`);
|
||
await this.handleAdicionarOnu(chatId, target);
|
||
break;
|
||
|
||
case 'buscar_cliente':
|
||
console.log(`🔍 Executando handleBuscarCliente com target: ${target}`);
|
||
await this.handleBuscarCliente(chatId, target);
|
||
break;
|
||
|
||
case 'ver_faturas':
|
||
console.log(`📄 Executando handleVerFaturas com target: ${target}`);
|
||
await this.handleVerFaturas(chatId, target);
|
||
break;
|
||
|
||
case 'gerar_boleto':
|
||
console.log(`💸 Executando handleGerarBoleto com target: ${target}`);
|
||
await this.handleGerarBoleto(chatId, target);
|
||
break;
|
||
|
||
case 'bloquear_cliente':
|
||
console.log(`🔒 Executando handleBloquearCliente com target: ${target}`);
|
||
await this.handleBloquearCliente(chatId, target);
|
||
break;
|
||
|
||
case 'liberar_cliente':
|
||
console.log(`🔓 Executando handleLiberarCliente com target: ${target}`);
|
||
await this.handleLiberarCliente(chatId, target);
|
||
break;
|
||
|
||
case 'listar_servicos':
|
||
console.log(`📋 Executando handleListarServicos com target: ${target}`);
|
||
await this.handleListarServicos(chatId, target);
|
||
break;
|
||
|
||
case 'dados_cliente':
|
||
case 'dados_cadastrais':
|
||
console.log(`📋 Executando handleDadosClientePorBusca com target: ${target}`);
|
||
await this.handleDadosClientePorBusca(chatId, target);
|
||
break;
|
||
|
||
case 'status_topsapp':
|
||
console.log(`🏢 Executando handleStatusTopSapp`);
|
||
await this.handleStatusTopSapp(chatId);
|
||
break;
|
||
|
||
case 'status_onu':
|
||
console.log(`📡 Executando handleStatusONU com target: ${target}`);
|
||
await this.handleStatusONU(chatId, target);
|
||
break;
|
||
|
||
case 'fiberhome_status':
|
||
console.log(`🔌 Executando handleFiberhomeStatus`);
|
||
await this.handleFiberhomeStatus(chatId);
|
||
break;
|
||
|
||
case 'conectar':
|
||
await this.handleConnect(chatId, target);
|
||
break;
|
||
|
||
case 'desconectar':
|
||
await this.handleDisconnect(chatId, target);
|
||
break;
|
||
|
||
case 'desconectar_usuario':
|
||
await this.handleDisconnectUser(chatId, target);
|
||
break;
|
||
|
||
case 'reiniciar':
|
||
await this.handleRestart(chatId, target);
|
||
break;
|
||
|
||
case 'ping':
|
||
await this.handlePing(chatId, target);
|
||
break;
|
||
|
||
default:
|
||
if (!action) {
|
||
await this.handleUnknown(chatId, intent.originalText || '');
|
||
} else {
|
||
await this.bot.sendMessage(chatId, `❓ Ação '${action}' não implementada ainda.`);
|
||
}
|
||
}
|
||
} catch (actionError) {
|
||
console.error(`❌ Erro ao executar ação '${action}':`, actionError);
|
||
await this.bot.sendMessage(chatId, `❌ Erro ao executar ação: ${actionError.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Comando /start
|
||
*/
|
||
async handleStart(chatId, user) {
|
||
const welcomeMessage = `
|
||
🤖 *Bem-vindo ao Bot de Ajuda!*
|
||
|
||
Olá ${user.first_name}! Agora você não precisa mandar mensagem pro Rodrigo ou no grupo da ID pra ficar vendo coisas triviais:
|
||
|
||
🔐 *Conexões SSH* - Acesso remoto a equipamentos
|
||
🌐 *Status de rede* - Verificação de conectividade
|
||
⚙️ *Comandos remotos* - Execução de tarefas
|
||
|
||
*Exemplos do que você pode dizer:*
|
||
• "Conectar no router1"
|
||
• "Verificar status do switch1"
|
||
• "Reiniciar equipamento"
|
||
• "Lista de equipamentos"
|
||
|
||
Digite /help para ver todos os comandos disponíveis!
|
||
`;
|
||
|
||
await this.bot.sendMessage(chatId, welcomeMessage, { parse_mode: 'Markdown' });
|
||
}
|
||
|
||
/**
|
||
* Comando /help
|
||
*/
|
||
async handleHelp(chatId) {
|
||
const helpMessage = `📋 COMANDOS DISPONÍVEIS:
|
||
|
||
🔧 COMANDOS BÁSICOS:
|
||
/start - Inicia o bot
|
||
/help - Mostra esta ajuda
|
||
/equipamentos - Lista equipamentos
|
||
|
||
🔐 SSH E CONEXÕES:
|
||
/ssh <equipamento> - Conecta via SSH
|
||
• "ssh juniper"
|
||
• "acessar concentrador"
|
||
|
||
👥 JUNIPER - GERENCIAR USUÁRIOS:
|
||
• "desconectar cliente USUARIO"
|
||
• "kick usuário USUARIO"
|
||
• "remover cliente USUARIO"
|
||
• "listar usuários conectados"
|
||
|
||
📡 OLT - VERIFICAR SINAL DE ONU:
|
||
• "ver sinal DACM91569513"
|
||
• "verificar sinal ABCD12345678"
|
||
• "sinal SERIAL_NUMBER"
|
||
• Suporte para OLT Fiberhome + OLTs Datacom
|
||
• Interface unificada para todas as OLTs
|
||
|
||
➕ OLT - ADICIONAR ONU:
|
||
• "adicionar onu DACM91569513"
|
||
• "cadastrar ABCD12345678"
|
||
• "add onu SERIAL_NUMBER"
|
||
|
||
🗑️ OLT - REMOVER ONU:
|
||
• "remover onu DACM91569513"
|
||
• "deletar ABCD12345678"
|
||
• "remover SERIAL_NUMBER"
|
||
|
||
🔄 OLT - REINICIAR ONU:
|
||
• Após verificar o sinal, use o botão "🔌 Reiniciar ONU"
|
||
• Comando confirma antes de reiniciar
|
||
• Processo automático com confirmação
|
||
|
||
⬆️ OLT - ATUALIZAR FIRMWARE ONU:
|
||
• Após verificar o sinal, use o botão "⬆️ Atualizar ONU"
|
||
• Detecta automaticamente o modelo (DM986-100/DM986-414)
|
||
• Oferece opções de firmware específicas para cada modelo
|
||
• Processo seguro com confirmação
|
||
|
||
🏢 TOPSAPP - GESTÃO DE CLIENTES:
|
||
• "buscar cliente João da Silva"
|
||
• "buscar cliente 123.456.789-10"
|
||
• "buscar cliente Guarai João"
|
||
• "dados cliente João Silva" (dados cadastrais completos)
|
||
• "dados cadastrais 123.456.789-10"
|
||
• "ver faturas 123.456.789-10"
|
||
• "listar serviços 123.456.789-10"
|
||
• "gerar boleto fatura123"
|
||
• "bloquear 123.456.789-10"
|
||
• "liberar 123.456.789-10"
|
||
• "status topsapp"
|
||
|
||
📋 DADOS CADASTRAIS COMPLETOS:
|
||
• Informações pessoais do cliente
|
||
• CPF, telefone, endereço completo
|
||
• Status atual do cliente (ativo/inativo)
|
||
• Dados de todos os serviços contratados
|
||
• Login, senha, IP fixo (quando aplicável)
|
||
• Plano contratado, valor mensalidade
|
||
• Dia de vencimento, status do serviço
|
||
• Dados FTTH: OLT, PON, VLAN, Serial ONU
|
||
• Modelo da ONU e níveis de sinal RX/TX
|
||
|
||
🔍 BUSCA INTELIGENTE:
|
||
• Busca por nome (com ou sem acentos)
|
||
• Busca por CPF (formatado ou não)
|
||
• Busca por ID do cliente
|
||
• Múltiplos resultados com seleção
|
||
• Interface com botões para ações rápidas
|
||
|
||
🔧 SERVIÇOS INDIVIDUAIS:
|
||
• Use "listar serviços CLIENTE" para ver todos os serviços
|
||
• Clique nos botões para bloquear/liberar serviços específicos
|
||
• Controle granular por serviço do cliente
|
||
|
||
📊 STATUS E MONITORAMENTO:
|
||
/status <equipamento> - Verifica status
|
||
• "verificar concentrador"
|
||
• "status do juniper"
|
||
|
||
🗣️ LINGUAGEM NATURAL:
|
||
• "Conectar no concentrador"
|
||
• "Desconectar cliente joao123"
|
||
• "Ver sinal DACM91569513"
|
||
• "Adicionar onu DACM91569513"
|
||
• "Remover onu DACM91569513"
|
||
• "Listar usuários conectados"
|
||
• "Reiniciar juniper"
|
||
• "Ping 131.0.192.254"
|
||
• "Buscar cliente João da Silva"
|
||
• "Ver faturas do CPF 123.456.789-10"
|
||
|
||
✅ EXEMPLOS PRÁTICOS:
|
||
• "desconectar cliente user123"
|
||
• "ver sinal DACM91569513"
|
||
• "adicionar onu DACM91569513"
|
||
• "remover onu DACM91569513"
|
||
• "buscar cliente João Pedro Afonso"
|
||
• "ver faturas cliente 123.456.789-10"
|
||
• "gerar boleto fatura456"
|
||
• "bloquear cliente 789"
|
||
• "listar clientes conectados"
|
||
• "verificar status concentrador"
|
||
|
||
🏢 OLTs DISPONÍVEIS:
|
||
• OLT FIBERHOME (131.0.192.9) - Via TL1
|
||
• OLT DITO (192.168.190.7)
|
||
• OLT COLMEIA (192.168.190.8)
|
||
• OLT CANAA (192.168.190.9)
|
||
• OLT CANAA 2 (192.168.190.10)
|
||
• OLT PEDRO AFONSO 1 (192.168.100.2)
|
||
• OLT CANAVIEIRAS (192.168.100.4)
|
||
|
||
🛡️ COMANDOS ADMINISTRATIVOS:
|
||
• "admin" - Painel administrativo
|
||
• "usuarios autorizados" - Ver usuários com acesso
|
||
• "meu id" - Ver seu ID do Telegram
|
||
|
||
🔶 FIBERHOME - COMANDOS ESPECÍFICOS:
|
||
• "status onu FHTT12345678" - Status detalhado de ONU específica
|
||
• "verificar onu FHTT12345678" - Verificar ONU por serial
|
||
• "onu status DeviceName" - Status por nome do dispositivo
|
||
• "fiberhome status" - Status das conexões Fiberhome
|
||
• Use "ver sinal" para interface unificada
|
||
|
||
�🔒 SEGURANÇA:
|
||
🛡️ Bot restrito a usuários autorizados
|
||
🆔 Para solicitar acesso, forneça seu ID`;
|
||
|
||
await this.bot.sendMessage(chatId, helpMessage);
|
||
}
|
||
|
||
/**
|
||
* Listar equipamentos
|
||
*/
|
||
async handleListEquipments(chatId) {
|
||
const equipments = this.ssh.listEquipments();
|
||
|
||
if (equipments.length === 0) {
|
||
await this.bot.sendMessage(chatId, '📋 Nenhum equipamento configurado.');
|
||
return;
|
||
}
|
||
|
||
let message = '📋 *Equipamentos Disponíveis:*\n\n';
|
||
|
||
equipments.forEach((eq, index) => {
|
||
message += `${index + 1}. *${eq.name}*\n`;
|
||
message += ` 📍 ${eq.host}:${eq.port}\n`;
|
||
message += ` 🔑 ID: \`${eq.id}\`\n\n`;
|
||
});
|
||
|
||
message += '💡 *Como usar:* Digite "conectar <ID>" ou "ssh <ID>"';
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
}
|
||
|
||
/**
|
||
* Conexão SSH
|
||
*/
|
||
async handleSSH(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId, '❓ Especifique o equipamento. Exemplo: "ssh router1"');
|
||
return;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, `🔄 Conectando em ${target}...`);
|
||
|
||
try {
|
||
const result = await this.ssh.connect(target);
|
||
|
||
if (result.success) {
|
||
await this.bot.sendMessage(chatId, `✅ ${result.message}`);
|
||
|
||
// Oferecer opções de comandos
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '📊 Status', callback_data: `cmd_status_${result.connectionId}` },
|
||
{ text: '🔄 Reiniciar', callback_data: `cmd_reboot_${result.connectionId}` }
|
||
],
|
||
[
|
||
{ text: '📋 Comando personalizado', callback_data: `cmd_custom_${result.connectionId}` },
|
||
{ text: '❌ Desconectar', callback_data: `cmd_disconnect_${result.connectionId}` }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(chatId, '🎛️ O que você gostaria de fazer?', {
|
||
reply_markup: keyboard
|
||
});
|
||
} else {
|
||
await this.bot.sendMessage(chatId, `❌ Falha na conexão: ${result.message}`);
|
||
}
|
||
} catch (error) {
|
||
await this.bot.sendMessage(chatId, `❌ Erro: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Verificar status
|
||
*/
|
||
async handleStatus(chatId, target) {
|
||
if (!target) {
|
||
// Mostrar status geral
|
||
const connections = this.ssh.getActiveConnections();
|
||
|
||
if (connections.length === 0) {
|
||
await this.bot.sendMessage(chatId, '📊 Nenhuma conexão ativa no momento.');
|
||
return;
|
||
}
|
||
|
||
let message = '📊 *Conexões Ativas:*\n\n';
|
||
connections.forEach((conn, index) => {
|
||
message += `${index + 1}. ${conn.equipment} (${conn.host})\n`;
|
||
message += ` ⏰ Conectado: ${conn.connectedAt.toLocaleString()}\n\n`;
|
||
});
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
return;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, `🔍 Verificando status de ${target}...`);
|
||
|
||
try {
|
||
const result = await this.ssh.testConnection(target);
|
||
|
||
if (result.success) {
|
||
await this.bot.sendMessage(chatId, `✅ ${result.message}`);
|
||
} else {
|
||
await this.bot.sendMessage(chatId, `❌ ${result.message}`);
|
||
}
|
||
} catch (error) {
|
||
await this.bot.sendMessage(chatId, `❌ Erro ao verificar status: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Conectar a um equipamento
|
||
*/
|
||
async handleConnect(chatId, target) {
|
||
await this.handleSSH(chatId, target);
|
||
}
|
||
|
||
/**
|
||
* Desconectar
|
||
*/
|
||
async handleDisconnect(chatId, target) {
|
||
if (!target || target === 'todas' || target === 'all') {
|
||
// Desconectar todas
|
||
this.ssh.closeAllConnections();
|
||
await this.bot.sendMessage(chatId, '🔌 Todas as conexões foram encerradas.');
|
||
return;
|
||
}
|
||
|
||
// Implementar lógica para desconectar equipamento específico
|
||
await this.bot.sendMessage(chatId, `🔌 Desconectando ${target}...`);
|
||
}
|
||
|
||
/**
|
||
* Reiniciar equipamento
|
||
*/
|
||
async handleRestart(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId, '❓ Especifique qual equipamento reiniciar.');
|
||
return;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, `⚠️ Reiniciar ${target}? Esta ação pode causar indisponibilidade.`, {
|
||
reply_markup: {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✅ Confirmar', callback_data: `confirm_restart_${target}` },
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]
|
||
]
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Ping
|
||
*/
|
||
async handlePing(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId, '❓ Especifique o IP ou hostname para fazer ping.');
|
||
return;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, `🏓 Fazendo ping para ${target}...`);
|
||
|
||
// Implementar ping usando comandos do sistema
|
||
// Por enquanto, simular resposta
|
||
setTimeout(async () => {
|
||
await this.bot.sendMessage(chatId, `🏓 Ping para ${target}: 12ms - Conexão OK`);
|
||
}, 2000);
|
||
}
|
||
|
||
/**
|
||
* Desconectar usuário específico no concentrador Juniper
|
||
*/
|
||
async handleDisconnectUser(chatId, username) {
|
||
if (!username) {
|
||
await this.bot.sendMessage(chatId, '❓ Especifique o usuário a ser desconectado. Exemplo: "desconectar cliente joao123"');
|
||
return;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, `🔄 Desconectando usuário ${username} do concentrador...`);
|
||
|
||
try {
|
||
// Usar concentrador Juniper como padrão
|
||
const result = await this.ssh.disconnectJuniperUser('juniper', username);
|
||
|
||
if (result.success) {
|
||
await this.bot.sendMessage(chatId, `✅ ${result.message}`);
|
||
|
||
if (result.output && result.output.trim()) {
|
||
const outputMessage = `📋 *Saída do comando:*\n\`\`\`\n${result.output}\n\`\`\``;
|
||
await this.bot.sendMessage(chatId, outputMessage, { parse_mode: 'Markdown' });
|
||
}
|
||
} else {
|
||
await this.bot.sendMessage(chatId, `❌ ${result.message}`);
|
||
|
||
if (result.error && result.error.trim()) {
|
||
const errorMessage = `⚠️ *Detalhes do erro:*\n\`\`\`\n${result.error}\n\`\`\``;
|
||
await this.bot.sendMessage(chatId, errorMessage, { parse_mode: 'Markdown' });
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao desconectar usuário:', error);
|
||
await this.bot.sendMessage(chatId, `❌ Erro interno: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Listar usuários conectados no concentrador
|
||
*/
|
||
async handleListUsers(chatId, target = 'juniper') {
|
||
await this.bot.sendMessage(chatId, '🔍 Listando usuários conectados no concentrador...');
|
||
|
||
try {
|
||
const result = await this.ssh.listJuniperUsers(target);
|
||
|
||
if (result.success) {
|
||
let message = '📋 *Usuários Conectados:*\n\n';
|
||
|
||
if (result.output && result.output.trim()) {
|
||
// Processar saída para extrair informações úteis
|
||
const lines = result.output.split('\n');
|
||
let userCount = 0;
|
||
|
||
for (const line of lines) {
|
||
if (line.trim() && !line.includes('Total') && !line.includes('---')) {
|
||
userCount++;
|
||
message += `${userCount}. \`${line.trim()}\`\n`;
|
||
}
|
||
}
|
||
|
||
if (userCount === 0) {
|
||
message += '🟢 Nenhum usuário conectado no momento.\n';
|
||
} else {
|
||
message += `\n👥 Total: ${userCount} usuário(s) conectado(s)`;
|
||
}
|
||
} else {
|
||
message += '🟢 Nenhum usuário conectado no momento.';
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
|
||
// Oferecer opções para desconectar usuários se houver algum conectado
|
||
if (result.output && result.output.trim() && !result.output.includes('Total: 0')) {
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '🔄 Atualizar lista', callback_data: 'refresh_users' },
|
||
{ text: '❌ Desconectar usuário', callback_data: 'disconnect_user_prompt' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(chatId, '🎛️ O que você gostaria de fazer?', {
|
||
reply_markup: keyboard
|
||
});
|
||
}
|
||
|
||
} else {
|
||
await this.bot.sendMessage(chatId, `❌ ${result.message}`);
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao listar usuários:', error);
|
||
await this.bot.sendMessage(chatId, `❌ Erro interno: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Verificar sinal de ONU
|
||
*/
|
||
async handleVerSinal(chatId, serialNumber) {
|
||
console.log(`🎯 handleVerSinal chamado - chatId: ${chatId}, serialNumber: ${serialNumber}`);
|
||
|
||
if (!serialNumber) {
|
||
console.log('❌ Serial number não fornecido');
|
||
await this.bot.sendMessage(chatId, '❓ Especifique o serial number da ONU. Exemplo: "ver sinal DACM91569513"');
|
||
return;
|
||
}
|
||
|
||
// Obter lista de OLTs disponíveis
|
||
const olts = this.ssh.listOLTs();
|
||
console.log(`📋 OLTs Datacom encontradas: ${olts.length}`);
|
||
|
||
// Criar menu de seleção de OLT
|
||
const keyboard = {
|
||
inline_keyboard: []
|
||
};
|
||
|
||
// Adicionar OLT Fiberhome como primeira opção
|
||
keyboard.inline_keyboard.push([
|
||
{ text: '🔶 OLT FIBERHOME', callback_data: `check_signal_fiberhome_${serialNumber}` }
|
||
]);
|
||
|
||
// Adicionar separador visual
|
||
if (olts.length > 0) {
|
||
keyboard.inline_keyboard.push([
|
||
{ text: '➖ OLTs DATACOM ➖', callback_data: 'separator' }
|
||
]);
|
||
|
||
// Adicionar botões para cada OLT Datacom (2 por linha)
|
||
for (let i = 0; i < olts.length; i += 2) {
|
||
const row = [];
|
||
|
||
row.push({
|
||
text: olts[i].name,
|
||
callback_data: `check_signal_${olts[i].id}_${serialNumber}`
|
||
});
|
||
|
||
if (i + 1 < olts.length) {
|
||
row.push({
|
||
text: olts[i + 1].name,
|
||
callback_data: `check_signal_${olts[i + 1].id}_${serialNumber}`
|
||
});
|
||
}
|
||
|
||
keyboard.inline_keyboard.push(row);
|
||
}
|
||
}
|
||
|
||
// Adicionar botão de cancelar
|
||
keyboard.inline_keyboard.push([
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]);
|
||
|
||
console.log(`📤 Enviando mensagem com Fiberhome + ${olts.length} OLTs Datacom para seleção`);
|
||
await this.bot.sendMessage(chatId, `🔍 *Verificar sinal da ONU*\nSerial: \`${serialNumber}\`\n\nSelecione onde deseja pesquisar:`, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: keyboard
|
||
});
|
||
console.log(`✅ Mensagem de seleção de OLT enviada com sucesso`);
|
||
}
|
||
|
||
/**
|
||
* Executa verificação de sinal em uma OLT específica
|
||
*/
|
||
async handleCheckSignalOLT(chatId, oltId, serialNumber) {
|
||
const olt = this.ssh.equipamentos.get(oltId);
|
||
if (!olt) {
|
||
await this.bot.sendMessage(chatId, `❌ OLT ${oltId} não encontrada.`);
|
||
return;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, `🔍 Procurando ONU ${serialNumber} na ${olt.name}...`);
|
||
|
||
try {
|
||
const result = await this.ssh.checkOnuSignalBySerial(oltId, serialNumber);
|
||
|
||
if (result.success) {
|
||
let message = `📡 *Sinal da ONU ${serialNumber}*\n\n`;
|
||
message += `🏢 **OLT:** ${olt.name} (${olt.host})\n`;
|
||
message += `📍 **Localização:** Slot ${result.slot}, ONU ${result.onuId}\n\n`;
|
||
message += `📊 **Informações do Sinal:**\n`;
|
||
message += `\`\`\`\n${result.signalOutput}\n\`\`\``;
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
|
||
// Oferecer opções adicionais
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '🔄 Atualizar sinal', callback_data: `check_signal_${oltId}_${serialNumber}` },
|
||
{ text: '📋 Ver configuração', callback_data: `show_config_${oltId}_${result.slot}_${result.onuId}` }
|
||
],
|
||
[
|
||
{ text: '🔌 Reiniciar ONU', callback_data: `reset_onu_${oltId}_${result.slot}_${result.onuId}` },
|
||
{ text: '⬆️ Atualizar ONU', callback_data: `update_onu_${oltId}_${result.slot}_${result.onuId}` }
|
||
],
|
||
[
|
||
{ text: '🔍 Pesquisar em outra OLT', callback_data: `ver_sinal_${serialNumber}` }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(chatId, '🎛️ O que você gostaria de fazer?', {
|
||
reply_markup: keyboard
|
||
});
|
||
|
||
} else {
|
||
await this.bot.sendMessage(chatId, `❌ ${result.message}`);
|
||
|
||
// Oferecer pesquisar em outras OLTs
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '🔍 Pesquisar em outra OLT', callback_data: `ver_sinal_${serialNumber}` },
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(chatId, 'ONU não encontrada nesta OLT. Deseja pesquisar em outra?', {
|
||
reply_markup: keyboard
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao verificar sinal:', error);
|
||
await this.bot.sendMessage(chatId, `❌ Erro interno: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Comando para remover ONU
|
||
*/
|
||
async handleRemoverOnu(chatId, serialNumber) {
|
||
if (!serialNumber) {
|
||
await this.bot.sendMessage(chatId, '❌ Por favor, informe o serial da ONU que deseja remover.\n\nExemplo: `remover FHTT12345678`', { parse_mode: 'Markdown' });
|
||
return;
|
||
}
|
||
|
||
// Perguntar em qual OLT buscar
|
||
const oltOptions = this.ssh.listOLTs();
|
||
|
||
if (oltOptions.length === 0) {
|
||
await this.bot.sendMessage(chatId, '❌ Nenhuma OLT disponível configurada.');
|
||
return;
|
||
}
|
||
|
||
let keyboard = {
|
||
inline_keyboard: oltOptions.map(olt => [
|
||
{ text: `🏢 ${olt.name}`, callback_data: `remove_onu_${olt.id}_${serialNumber}` }
|
||
])
|
||
};
|
||
|
||
// Adicionar opção de cancelar
|
||
keyboard.inline_keyboard.push([
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]);
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`🗑️ **Remover ONU ${serialNumber}**\n\n` +
|
||
'🏢 Selecione a OLT onde a ONU está configurada:',
|
||
{
|
||
reply_markup: keyboard,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Comando para adicionar ONU
|
||
*/
|
||
async handleAdicionarOnu(chatId, serialNumber) {
|
||
if (!serialNumber) {
|
||
await this.bot.sendMessage(chatId, '❌ Por favor, informe o serial da ONU que deseja adicionar.\n\nExemplo: `adicionar onu FHTT12345678`', { parse_mode: 'Markdown' });
|
||
return;
|
||
}
|
||
|
||
// Perguntar em qual OLT adicionar
|
||
const oltOptions = this.ssh.listOLTs();
|
||
|
||
if (oltOptions.length === 0) {
|
||
await this.bot.sendMessage(chatId, '❌ Nenhuma OLT disponível configurada.');
|
||
return;
|
||
}
|
||
|
||
let keyboard = {
|
||
inline_keyboard: oltOptions.map(olt => [
|
||
{ text: `🏢 ${olt.name}`, callback_data: `add_onu_${olt.id}_${serialNumber}` }
|
||
])
|
||
};
|
||
|
||
// Adicionar opção de cancelar
|
||
keyboard.inline_keyboard.push([
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]);
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`➕ **Adicionar ONU ${serialNumber}**\n\n` +
|
||
'🏢 Selecione a OLT onde deseja adicionar a ONU:',
|
||
{
|
||
reply_markup: keyboard,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Comando não reconhecido
|
||
*/
|
||
async handleUnknown(chatId, text) {
|
||
const suggestions = this.nlp.suggestCorrection(text);
|
||
|
||
let message = '❓ Não entendi o comando. ';
|
||
|
||
if (suggestions.length > 0) {
|
||
message += `Talvez você quis dizer: ${suggestions.join(', ')}?\n\n`;
|
||
}
|
||
|
||
message += 'Digite /help para ver todos os comandos disponíveis.';
|
||
|
||
await this.bot.sendMessage(chatId, message);
|
||
}
|
||
|
||
/**
|
||
* Processa callbacks de botões inline
|
||
*/
|
||
async handleCallbackQuery(callbackQuery) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
const data = callbackQuery.data;
|
||
const userId = callbackQuery.from.id;
|
||
|
||
// Verificar autorização
|
||
if (!this.isAuthorized(userId)) {
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, '🚫 Acesso negado');
|
||
console.log(`🚫 Callback negado para usuário (${userId})`);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
console.log(`🔍 Callback recebido: ${data}`);
|
||
console.log(`🔍 Verifica confirm_remove_: ${data.startsWith('confirm_remove_')}`);
|
||
|
||
if (data.startsWith('cmd_')) {
|
||
console.log(`🔍 Condição cmd_ atendida`);
|
||
await this.handleCommandCallback(callbackQuery, data);
|
||
} else if (data.startsWith('confirm_remove_')) {
|
||
console.log(`🔍 Chamando handleConfirmRemoveCallback`);
|
||
try {
|
||
await this.handleConfirmRemoveCallback(callbackQuery, data);
|
||
} catch (confirmError) {
|
||
console.error(`❌ Erro em handleConfirmRemoveCallback:`, confirmError);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro na confirmação');
|
||
}
|
||
} else if (data.startsWith('confirm_add_')) {
|
||
console.log(`🔍 Chamando handleConfirmAddCallback`);
|
||
try {
|
||
await this.handleConfirmAddCallback(callbackQuery, data);
|
||
} catch (confirmError) {
|
||
console.error(`❌ Erro em handleConfirmAddCallback:`, confirmError);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro na confirmação');
|
||
}
|
||
} else if (data.startsWith('confirm_block_service_')) {
|
||
console.log(`🔍 Chamando handleConfirmBlockServiceCallback`);
|
||
await this.handleConfirmBlockServiceCallback(callbackQuery, data);
|
||
} else if (data.startsWith('confirm_unblock_service_')) {
|
||
console.log(`🔍 Chamando handleConfirmUnblockServiceCallback`);
|
||
await this.handleConfirmUnblockServiceCallback(callbackQuery, data);
|
||
} else if (data.startsWith('confirm_block_all_')) {
|
||
console.log(`🔍 Chamando handleConfirmBlockAllCallback`);
|
||
await this.handleConfirmBlockAllCallback(callbackQuery, data);
|
||
} else if (data.startsWith('confirm_unblock_all_')) {
|
||
console.log(`🔍 Chamando handleConfirmUnblockAllCallback`);
|
||
await this.handleConfirmUnblockAllCallback(callbackQuery, data);
|
||
} else if (data.startsWith('confirm_block_')) {
|
||
console.log(`🔍 Chamando handleConfirmBlockCallback`);
|
||
await this.handleConfirmBlockCallback(callbackQuery, data);
|
||
} else if (data.startsWith('confirm_unblock_')) {
|
||
console.log(`🔍 Chamando handleConfirmUnblockCallback`);
|
||
await this.handleConfirmUnblockCallback(callbackQuery, data);
|
||
} else if (data.startsWith('block_service_')) {
|
||
console.log(`🔍 Chamando handleBlockServiceSelection`);
|
||
await this.handleBlockServiceSelection(callbackQuery, data);
|
||
} else if (data.startsWith('unblock_service_')) {
|
||
console.log(`🔍 Chamando handleUnblockServiceCallback`);
|
||
await this.handleUnblockServiceCallback(callbackQuery, data);
|
||
} else if (data.startsWith('confirm_')) {
|
||
console.log(`🔍 Condição confirm_ atendida`);
|
||
await this.handleConfirmCallback(callbackQuery, data);
|
||
} else if (data.startsWith('check_signal_')) {
|
||
console.log(`🔍 Condição check_signal_ atendida`);
|
||
await this.handleCheckSignalCallback(callbackQuery, data);
|
||
} else if (data.startsWith('ver_sinal_')) {
|
||
console.log(`🔍 Condição ver_sinal_ atendida`);
|
||
const serialNumber = data.replace('ver_sinal_', '');
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.handleVerSinal(chatId, serialNumber);
|
||
} else if (data.startsWith('show_config_')) {
|
||
console.log(`🔍 Condição show_config_ atendida`);
|
||
await this.handleShowConfigCallback(callbackQuery, data);
|
||
} else if (data.startsWith('reset_onu_')) {
|
||
console.log(`🔍 Condição reset_onu_ atendida`);
|
||
await this.handleResetOnuCallback(callbackQuery, data);
|
||
} else if (data.startsWith('update_onu_')) {
|
||
console.log(`🔍 Condição update_onu_ atendida`);
|
||
await this.handleUpdateOnuCallback(callbackQuery, data);
|
||
} else if (data.startsWith('firmware_')) {
|
||
console.log(`🔍 Condição firmware_ atendida`);
|
||
await this.handleFirmwareCallback(callbackQuery, data);
|
||
} else if (data.startsWith('remove_onu_')) {
|
||
console.log(`🔍 Chamando handleRemoveOnuCallback`);
|
||
await this.handleRemoveOnuCallback(callbackQuery, data);
|
||
} else if (data.startsWith('add_onu_')) {
|
||
console.log(`🔍 Chamando handleAddOnuCallback`);
|
||
await this.handleAddOnuCallback(callbackQuery, data);
|
||
} else if (data.startsWith('fiberhome_details_')) {
|
||
console.log(`🔍 Condição fiberhome_details_ atendida`);
|
||
const serialNumber = data.replace('fiberhome_details_', '');
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.handleStatusONU(chatId, serialNumber);
|
||
} else if (data.startsWith('dados_cliente_')) {
|
||
console.log(`🔍 Condição dados_cliente_ atendida`);
|
||
await this.handleDadosClienteCallback(callbackQuery, data);
|
||
} else if (data.startsWith('faturas_cliente_')) {
|
||
console.log(`🔍 Condição faturas_cliente_ atendida`);
|
||
await this.handleFaturasClienteCallback(callbackQuery, data);
|
||
} else if (data.startsWith('servicos_cliente_')) {
|
||
console.log(`🔍 Condição servicos_cliente_ atendida`);
|
||
await this.handleServicosClienteCallback(callbackQuery, data);
|
||
} else if (data === 'separator') {
|
||
// Ignorar clique no separador visual
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
} else if (data === 'cancel_action') {
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Ação cancelada');
|
||
await this.bot.editMessageText('❌ Ação cancelada.', {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
});
|
||
} else if (data === 'refresh_users') {
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.handleListUsers(chatId);
|
||
} else if (data === 'disconnect_user_prompt') {
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.bot.editMessageText('👤 Digite o nome do usuário que deseja desconectar:', {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
});
|
||
|
||
// Armazenar estado para próxima mensagem
|
||
this.userSessions.set(callbackQuery.from.id, {
|
||
type: 'waiting_username_disconnect'
|
||
});
|
||
} else {
|
||
console.log(`❓ Callback não reconhecido: ${data}`);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Comando não reconhecido');
|
||
}
|
||
} catch (error) {
|
||
console.error('❌ Erro no callback:', error);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro interno');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Processa callbacks de comandos
|
||
*/
|
||
async handleCommandCallback(callbackQuery, data) {
|
||
const parts = data.split('_');
|
||
const action = parts[1];
|
||
const connectionId = parts.slice(2).join('_');
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
|
||
switch (action) {
|
||
case 'status':
|
||
await this.executeSSHCommand(callbackQuery, connectionId, 'uptime');
|
||
break;
|
||
case 'reboot':
|
||
await this.confirmRebootCallback(callbackQuery, connectionId);
|
||
break;
|
||
case 'disconnect':
|
||
await this.disconnectCallback(callbackQuery, connectionId);
|
||
break;
|
||
case 'custom':
|
||
await this.requestCustomCommand(callbackQuery, connectionId);
|
||
break;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Executa comando SSH e mostra resultado
|
||
*/
|
||
async executeSSHCommand(callbackQuery, connectionId, command) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
try {
|
||
const result = await this.ssh.executeCommand(connectionId, command);
|
||
|
||
let message = `💻 *Comando:* \`${command}\`\n\n`;
|
||
|
||
if (result.success) {
|
||
message += `✅ *Resultado:*\n\`\`\`\n${result.output}\`\`\``;
|
||
} else {
|
||
message += `❌ *Erro:*\n\`\`\`\n${result.error}\`\`\``;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
} catch (error) {
|
||
await this.bot.sendMessage(chatId, `❌ Erro ao executar comando: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Confirma reinicialização
|
||
*/
|
||
async confirmRebootCallback(callbackQuery, connectionId) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.editMessageText('⚠️ Tem certeza que deseja reiniciar o equipamento?', {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
reply_markup: {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✅ SIM, reiniciar', callback_data: `confirm_reboot_${connectionId}` },
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]
|
||
]
|
||
}
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Desconecta conexão SSH
|
||
*/
|
||
async disconnectCallback(callbackQuery, connectionId) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
const success = this.ssh.disconnect(connectionId);
|
||
|
||
if (success) {
|
||
await this.bot.editMessageText('🔌 Conexão encerrada com sucesso.', {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
});
|
||
} else {
|
||
await this.bot.editMessageText('❌ Conexão não encontrada ou já encerrada.', {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
});
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Solicita comando personalizado
|
||
*/
|
||
async requestCustomCommand(callbackQuery, connectionId) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
// Armazenar estado para próxima mensagem
|
||
this.userSessions.set(callbackQuery.from.id, {
|
||
type: 'waiting_custom_command',
|
||
connectionId: connectionId
|
||
});
|
||
|
||
await this.bot.editMessageText('💻 Digite o comando que deseja executar:', {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
});
|
||
}
|
||
|
||
/**
|
||
* Processa callbacks de confirmação
|
||
*/
|
||
async handleConfirmCallback(callbackQuery, data) {
|
||
const parts = data.split('_');
|
||
const action = parts[1];
|
||
|
||
if (action === 'restart' || action === 'reboot') {
|
||
const target = parts.slice(2).join('_');
|
||
await this.executeRestart(callbackQuery, target);
|
||
} else if (action === 'reset' && parts[2] === 'onu') {
|
||
// Formato: confirm_reset_onu_oltid_slot_onuid
|
||
await this.handleConfirmResetOnu(callbackQuery, data);
|
||
} else if (action === 'firmware') {
|
||
// Formato: confirm_firmware_filename_oltid_slot_onuid
|
||
await this.handleConfirmFirmware(callbackQuery, data);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Executa reinicialização confirmada
|
||
*/
|
||
async executeRestart(callbackQuery, target) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.editMessageText(`🔄 Reiniciando ${target}...`, {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
});
|
||
|
||
// Simular reinicialização (implementar comando real aqui)
|
||
setTimeout(async () => {
|
||
await this.bot.sendMessage(chatId, `✅ ${target} foi reiniciado com sucesso.`);
|
||
}, 3000);
|
||
}
|
||
|
||
/**
|
||
* Lida com input de usuário durante sessões específicas
|
||
*/
|
||
async handleUserSessionInput(chatId, text, userId, session) {
|
||
switch (session.type) {
|
||
case 'waiting_custom_command':
|
||
await this.executeCustomCommand(chatId, session.connectionId, text);
|
||
break;
|
||
|
||
case 'waiting_username_disconnect':
|
||
await this.handleDisconnectUser(chatId, text.trim());
|
||
break;
|
||
|
||
default:
|
||
await this.bot.sendMessage(chatId, '❓ Estado de sessão desconhecido. Tente novamente.');
|
||
}
|
||
|
||
// Limpar sessão
|
||
this.userSessions.delete(userId);
|
||
}
|
||
|
||
/**
|
||
* Executa comando personalizado em uma conexão SSH
|
||
*/
|
||
async executeCustomCommand(chatId, connectionId, command) {
|
||
await this.bot.sendMessage(chatId, `💻 Executando: \`${command}\``, { parse_mode: 'Markdown' });
|
||
|
||
try {
|
||
const result = await this.ssh.executeCommand(connectionId, command);
|
||
|
||
let message = `💻 *Comando:* \`${command}\`\n\n`;
|
||
|
||
if (result.success) {
|
||
message += `✅ *Resultado:*\n\`\`\`\n${result.output || 'Comando executado com sucesso'}\`\`\``;
|
||
} else {
|
||
message += `❌ *Erro:*\n\`\`\`\n${result.error || 'Erro desconhecido'}\`\`\``;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
} catch (error) {
|
||
await this.bot.sendMessage(chatId, `❌ Erro ao executar comando: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Processa callback de verificação de sinal
|
||
*/
|
||
async handleCheckSignalCallback(callbackQuery, data) {
|
||
const parts = data.split('_');
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
// Verificar se é Fiberhome (formato: check_signal_fiberhome_SERIAL)
|
||
if (parts.length === 4 && parts[2] === 'fiberhome') {
|
||
const serialNumber = parts[3];
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.handleCheckSignalFiberhome(chatId, serialNumber);
|
||
return;
|
||
}
|
||
|
||
// Formato padrão Datacom: check_signal_olt_dito_SERIAL ou check_signal_olt_pedro_afonso_SERIAL
|
||
let oltId, serialNumber;
|
||
|
||
if (parts.length === 6 && parts[2] === 'olt' && parts[3] === 'pedro' && parts[4] === 'afonso') {
|
||
// Caso: check_signal_olt_pedro_afonso_SERIAL
|
||
oltId = parts[2] + '_' + parts[3] + '_' + parts[4]; // "olt_pedro_afonso"
|
||
serialNumber = parts[5];
|
||
} else if (parts.length === 5) {
|
||
// Caso: check_signal_olt_dito_SERIAL
|
||
oltId = parts[2] + '_' + parts[3]; // "olt_dito"
|
||
serialNumber = parts[4];
|
||
} else if (parts.length === 4) {
|
||
// Caso: check_signal_oltid_SERIAL (se existir formato mais simples)
|
||
oltId = parts[2];
|
||
serialNumber = parts[3];
|
||
} else {
|
||
// Tentar reconstruir dinamicamente
|
||
oltId = parts.slice(2, -1).join('_'); // Tudo exceto o último (que é o serial)
|
||
serialNumber = parts[parts.length - 1]; // Último elemento
|
||
}
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.handleCheckSignalOLT(chatId, oltId, serialNumber);
|
||
}
|
||
|
||
/**
|
||
* Executa verificação de sinal na OLT Fiberhome
|
||
*/
|
||
async handleCheckSignalFiberhome(chatId, serialNumber) {
|
||
await this.bot.sendMessage(chatId, `🔍 Procurando ONU ${serialNumber} na OLT Fiberhome...`);
|
||
|
||
try {
|
||
// Usar a mesma lógica do handleStatusONU
|
||
let resultado;
|
||
if (serialNumber.length === 12 && /^[A-Z0-9]+$/.test(serialNumber)) {
|
||
// É um serial
|
||
resultado = await this.fiberhome.obterStatusONU(serialNumber);
|
||
} else {
|
||
// Pode ser device name
|
||
resultado = await this.fiberhome.obterStatusONUPorNome(serialNumber);
|
||
}
|
||
|
||
if (resultado.success) {
|
||
// Formatar resposta similar às OLTs Datacom
|
||
let message = `📡 *Sinal da ONU ${serialNumber}*\n\n`;
|
||
message += `🏢 **OLT:** Fiberhome UNM2000 (131.0.192.9)\n`;
|
||
message += `📍 **Localização:** Slot ${resultado.slot}, PON ${resultado.pon}, ONU ${resultado.onuId}\n`;
|
||
message += `🔌 **Status:** ${resultado.online ? '🟢 Online' : '🔴 Offline'}\n\n`;
|
||
|
||
message += `📊 **Informações do Sinal:**\n`;
|
||
message += `📡 **RX Power:** ${resultado.rxPower}\n`;
|
||
message += `📤 **TX Power:** ${resultado.txPower}\n`;
|
||
message += `📏 **Distância:** ${resultado.distance}\n\n`;
|
||
|
||
// Status das portas Ethernet (resumido)
|
||
if (resultado.portasEthernet.length > 0) {
|
||
const portasAtivas = resultado.portasEthernet.filter(p => p.status === 'active' || p.status === 'up').length;
|
||
message += `🔗 **Portas Ethernet:** ${portasAtivas}/${resultado.portasEthernet.length} ativas\n`;
|
||
}
|
||
|
||
// Serviços WAN
|
||
if (resultado.servicosWAN.length > 0) {
|
||
const servicosAtivos = resultado.servicosWAN.filter(s => s.status === 'active').length;
|
||
message += `🌐 **Serviços WAN:** ${servicosAtivos} ativo(s)\n`;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
|
||
// Oferecer opções adicionais (similar às OLTs Datacom)
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '🔄 Atualizar sinal', callback_data: `check_signal_fiberhome_${serialNumber}` },
|
||
{ text: '📋 Detalhes completos', callback_data: `fiberhome_details_${serialNumber}` }
|
||
],
|
||
[
|
||
{ text: '🔍 Pesquisar em OLT Datacom', callback_data: `ver_sinal_${serialNumber}` }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(chatId, '🎛️ O que você gostaria de fazer?', {
|
||
reply_markup: keyboard
|
||
});
|
||
|
||
} else {
|
||
await this.bot.sendMessage(chatId, `❌ ONU ${serialNumber} não encontrada na OLT Fiberhome.`);
|
||
|
||
// Oferecer pesquisar em OLTs Datacom
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '🔍 Pesquisar em OLT Datacom', callback_data: `ver_sinal_${serialNumber}` },
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(chatId, 'ONU não encontrada na Fiberhome. Deseja pesquisar nas OLTs Datacom?', {
|
||
reply_markup: keyboard
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao verificar sinal Fiberhome:', error);
|
||
await this.bot.sendMessage(chatId, `❌ Erro interno: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Processa callback de mostrar configuração
|
||
*/
|
||
async handleShowConfigCallback(callbackQuery, data) {
|
||
const parts = data.split('_');
|
||
// Formato: show_config_olt_dito_slot_onuid ou show_config_olt_pedro_afonso_slot_onuid
|
||
let oltId, slot, onuId;
|
||
|
||
if (parts.length === 7 && parts[2] === 'olt' && parts[3] === 'pedro' && parts[4] === 'afonso') {
|
||
// Caso: show_config_olt_pedro_afonso_slot_onuid
|
||
oltId = parts[2] + '_' + parts[3] + '_' + parts[4]; // "olt_pedro_afonso"
|
||
slot = parts[5];
|
||
onuId = parts[6];
|
||
} else if (parts.length === 6) {
|
||
// Caso: show_config_olt_dito_slot_onuid
|
||
oltId = parts[2] + '_' + parts[3]; // "olt_dito"
|
||
slot = parts[4];
|
||
onuId = parts[5];
|
||
} else if (parts.length === 5) {
|
||
// Caso: show_config_oltid_slot_onuid (se existir formato mais simples)
|
||
oltId = parts[2];
|
||
slot = parts[3];
|
||
onuId = parts[4];
|
||
} else {
|
||
// Tentar reconstruir dinamicamente
|
||
// Os dois últimos são sempre slot e onuId
|
||
onuId = parts[parts.length - 1];
|
||
slot = parts[parts.length - 2];
|
||
oltId = parts.slice(2, -2).join('_'); // Tudo entre o terceiro e os dois últimos
|
||
}
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.bot.sendMessage(chatId, `📋 Buscando configuração da ONU ${onuId} no slot ${slot}...`);
|
||
|
||
try {
|
||
const connection = await this.ssh.connect(oltId);
|
||
|
||
if (!connection.success) {
|
||
await this.bot.sendMessage(chatId, `❌ Erro na conexão: ${connection.message}`);
|
||
return;
|
||
}
|
||
|
||
const configCommand = `show running-config interface gpon ${slot} onu ${onuId}`;
|
||
const result = await this.ssh.executeCommand(connection.connectionId, configCommand);
|
||
|
||
this.ssh.disconnect(connection.connectionId);
|
||
|
||
if (result.success) {
|
||
let message = `📋 *Configuração da ONU*\n`;
|
||
message += `📍 Slot: ${slot}, ONU: ${onuId}\n\n`;
|
||
message += `\`\`\`\n${result.output}\n\`\`\``;
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
} else {
|
||
await this.bot.sendMessage(chatId, `❌ Erro ao obter configuração: ${result.error}`);
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao mostrar configuração:', error);
|
||
await this.bot.sendMessage(chatId, `❌ Erro interno: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Processa callback de reiniciar ONU
|
||
*/
|
||
async handleResetOnuCallback(callbackQuery, data) {
|
||
console.log(`🔌 handleResetOnuCallback chamado com data: ${data}`);
|
||
|
||
const parts = data.split('_');
|
||
console.log(`📝 Parts: ${JSON.stringify(parts)}`);
|
||
|
||
// Formato: reset_onu_olt_dito_slot_onuid ou reset_onu_olt_pedro_afonso_slot_onuid
|
||
let oltId, slot, onuId;
|
||
|
||
if (parts.length === 7 && parts[2] === 'olt' && parts[3] === 'pedro' && parts[4] === 'afonso') {
|
||
// Caso: reset_onu_olt_pedro_afonso_slot_onuid
|
||
oltId = parts[2] + '_' + parts[3] + '_' + parts[4]; // "olt_pedro_afonso"
|
||
slot = parts[5];
|
||
onuId = parts[6];
|
||
} else if (parts.length === 6) {
|
||
// Caso: reset_onu_olt_dito_slot_onuid
|
||
oltId = parts[2] + '_' + parts[3]; // "olt_dito"
|
||
slot = parts[4];
|
||
onuId = parts[5];
|
||
} else if (parts.length === 5) {
|
||
// Caso: reset_onu_oltid_slot_onuid (se existir formato mais simples)
|
||
oltId = parts[2];
|
||
slot = parts[3];
|
||
onuId = parts[4];
|
||
} else {
|
||
// Tentar reconstruir dinamicamente
|
||
// Os dois últimos são sempre slot e onuId
|
||
onuId = parts[parts.length - 1];
|
||
slot = parts[parts.length - 2];
|
||
oltId = parts.slice(2, -2).join('_'); // Tudo entre o terceiro e os dois últimos
|
||
}
|
||
|
||
console.log(`🎯 Parsed - OLT: ${oltId}, Slot: ${slot}, ONU: ${onuId}`);
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
// Primeiro mostrar confirmação
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.bot.editMessageText(
|
||
`⚠️ **Confirmação de Reinicialização**\n\n` +
|
||
`Tem certeza que deseja reiniciar a ONU?\n\n` +
|
||
`📍 **Slot:** ${slot}\n` +
|
||
`🔌 **ONU ID:** ${onuId}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`⚠️ Esta ação irá desconectar temporariamente o cliente.`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✅ SIM, Reiniciar', callback_data: `confirm_reset_onu_${oltId}_${slot}_${onuId}` },
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]
|
||
]
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Processa confirmação de reinicialização de ONU
|
||
*/
|
||
async handleConfirmResetOnu(callbackQuery, data) {
|
||
console.log(`🔄 handleConfirmResetOnu chamado com data: ${data}`);
|
||
|
||
const parts = data.replace('confirm_reset_onu_', '').split('_');
|
||
console.log(`📝 Parts após parsing: ${JSON.stringify(parts)}`);
|
||
|
||
// Formato após remoção do prefixo: olt_dito_slot_onuid
|
||
let oltId, slot, onuId;
|
||
|
||
if (parts.length === 4) {
|
||
// Caso: olt_dito_slot_onuid
|
||
oltId = parts[0] + '_' + parts[1]; // "olt_dito"
|
||
slot = parts[2];
|
||
onuId = parts[3];
|
||
} else if (parts.length === 3) {
|
||
// Caso: oltid_slot_onuid
|
||
oltId = parts[0];
|
||
slot = parts[1];
|
||
onuId = parts[2];
|
||
} else {
|
||
// Tentar reconstruir dinamicamente
|
||
onuId = parts[parts.length - 1];
|
||
slot = parts[parts.length - 2];
|
||
oltId = parts.slice(0, -2).join('_');
|
||
}
|
||
|
||
console.log(`🎯 Parsed - OLT: ${oltId}, Slot: ${slot}, ONU: ${onuId}`);
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.bot.editMessageText(
|
||
`🔄 **Reiniciando ONU...**\n\n` +
|
||
`📍 Slot: ${slot}\n` +
|
||
`🔌 ONU ID: ${onuId}\n` +
|
||
`🏢 OLT: ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`⏳ Aguarde, isso pode levar alguns segundos...`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
try {
|
||
const result = await this.ssh.resetOnuAlternative(oltId, slot, onuId);
|
||
|
||
if (result.success) {
|
||
await this.bot.editMessageText(
|
||
`✅ **ONU Reiniciada com Sucesso!**\n\n` +
|
||
`📍 Slot: ${slot}\n` +
|
||
`🔌 ONU ID: ${onuId}\n` +
|
||
`🏢 OLT: ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`🔄 A ONU deve voltar a funcionar em alguns instantes.\n` +
|
||
`📊 Recomenda-se verificar o sinal novamente em 1-2 minutos.`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
} else {
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro ao Reiniciar ONU**\n\n` +
|
||
`📍 Slot: ${slot}\n` +
|
||
`🔌 ONU ID: ${onuId}\n` +
|
||
`🏢 OLT: ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`❌ Erro: ${result.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao reiniciar ONU:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro Interno**\n\n` +
|
||
`Não foi possível reiniciar a ONU.\n` +
|
||
`Erro: ${error.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Processa callback de atualizar firmware da ONU
|
||
*/
|
||
async handleUpdateOnuCallback(callbackQuery, data) {
|
||
const parts = data.split('_');
|
||
// Formato: update_onu_olt_dito_slot_onuid ou update_onu_olt_pedro_afonso_slot_onuid
|
||
let oltId, slot, onuId;
|
||
|
||
if (parts.length === 7 && parts[2] === 'olt' && parts[3] === 'pedro' && parts[4] === 'afonso') {
|
||
// Caso: update_onu_olt_pedro_afonso_slot_onuid
|
||
oltId = parts[2] + '_' + parts[3] + '_' + parts[4]; // "olt_pedro_afonso"
|
||
slot = parts[5];
|
||
onuId = parts[6];
|
||
} else if (parts.length === 6) {
|
||
// Caso: update_onu_olt_dito_slot_onuid
|
||
oltId = parts[2] + '_' + parts[3]; // "olt_dito"
|
||
slot = parts[4];
|
||
onuId = parts[5];
|
||
} else if (parts.length === 5) {
|
||
// Caso: update_onu_oltid_slot_onuid (se existir formato mais simples)
|
||
oltId = parts[2];
|
||
slot = parts[3];
|
||
onuId = parts[4];
|
||
} else {
|
||
// Tentar reconstruir dinamicamente
|
||
// Os dois últimos são sempre slot e onuId
|
||
onuId = parts[parts.length - 1];
|
||
slot = parts[parts.length - 2];
|
||
oltId = parts.slice(2, -2).join('_'); // Tudo entre o terceiro e os dois últimos
|
||
}
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.bot.sendMessage(chatId, `🔍 Identificando modelo da ONU ${onuId} no slot ${slot}...`);
|
||
|
||
try {
|
||
// Obter detalhes da ONU para identificar o modelo
|
||
const details = await this.ssh.getOnuDetails(oltId, slot, onuId);
|
||
|
||
if (!details.success) {
|
||
await this.bot.sendMessage(chatId, `❌ Erro ao obter detalhes da ONU: ${details.message}`);
|
||
return;
|
||
}
|
||
|
||
const equipmentId = details.equipmentId;
|
||
console.log(`🔍 Equipment ID detectado: ${equipmentId}`);
|
||
|
||
// Determinar opções de firmware baseado no modelo
|
||
let firmwareOptions = [];
|
||
|
||
if (equipmentId.includes('DM986-100')) {
|
||
firmwareOptions = [
|
||
{ text: '📦 FW INTERMEDIÁRIA', callback_data: `firmware_DM986-100-inter.tar_${oltId}_${slot}_${onuId}` },
|
||
{ text: '📦 FW ATUAL (v56)', callback_data: `firmware_DM986-100-v56.tar_${oltId}_${slot}_${onuId}` },
|
||
{ text: '📦 FW ROUTER (R300)', callback_data: `firmware_DM986-100-R300.tar_${oltId}_${slot}_${onuId}` }
|
||
];
|
||
} else if (equipmentId.includes('DM986-414')) {
|
||
firmwareOptions = [
|
||
{ text: '📦 FW INTERMEDIÁRIA', callback_data: `firmware_DM986-414-inter.tar_${oltId}_${slot}_${onuId}` },
|
||
{ text: '📦 FW ATUAL (v70)', callback_data: `firmware_DM986-414-v70.tar_${oltId}_${slot}_${onuId}` }
|
||
];
|
||
} else {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Modelo não suportado**\n\n` +
|
||
`📍 Slot: ${slot}, ONU: ${onuId}\n` +
|
||
`🔍 Equipment ID: ${equipmentId}\n\n` +
|
||
`⚠️ Apenas DM986-100 e DM986-414 são suportados para atualização.`
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Criar teclado com opções de firmware
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
...firmwareOptions.map(option => [option]),
|
||
[{ text: '❌ Cancelar', callback_data: 'cancel_action' }]
|
||
]
|
||
};
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`⬆️ **Atualização de Firmware**\n\n` +
|
||
`📍 **Slot:** ${slot}\n` +
|
||
`🔌 **ONU ID:** ${onuId}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n` +
|
||
`🔍 **Modelo:** ${equipmentId}\n\n` +
|
||
`📦 Selecione a versão do firmware:`,
|
||
{
|
||
parse_mode: 'Markdown',
|
||
reply_markup: keyboard
|
||
}
|
||
);
|
||
|
||
} catch (error) {
|
||
console.error('Erro ao processar atualização de ONU:', error);
|
||
await this.bot.sendMessage(chatId, `❌ Erro interno: ${error.message}`);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Processa callback de seleção de firmware
|
||
*/
|
||
async handleFirmwareCallback(callbackQuery, data) {
|
||
// Formato: firmware_DM986-100-v56.tar_olt_dito_slot_onuid
|
||
const parts = data.replace('firmware_', '').split('_');
|
||
|
||
let firmwareFile, oltId, slot, onuId;
|
||
|
||
// O arquivo de firmware é sempre o primeiro elemento
|
||
firmwareFile = parts[0];
|
||
|
||
// Processar o resto baseado no número de partes
|
||
if (parts.length === 5) {
|
||
// Caso: DM986-100-v56.tar_olt_dito_slot_onuid
|
||
oltId = parts[1] + '_' + parts[2]; // "olt_dito"
|
||
slot = parts[3];
|
||
onuId = parts[4];
|
||
} else if (parts.length === 4) {
|
||
// Caso: DM986-100-v56.tar_oltid_slot_onuid
|
||
oltId = parts[1];
|
||
slot = parts[2];
|
||
onuId = parts[3];
|
||
} else {
|
||
// Tentar reconstruir dinamicamente
|
||
onuId = parts[parts.length - 1];
|
||
slot = parts[parts.length - 2];
|
||
oltId = parts.slice(1, -2).join('_');
|
||
}
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
// Mostrar confirmação
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.bot.editMessageText(
|
||
`⚠️ **Confirmação de Atualização de Firmware**\n\n` +
|
||
`📦 **Firmware:** ${firmwareFile}\n` +
|
||
`📍 **Slot:** ${slot}\n` +
|
||
`🔌 **ONU ID:** ${onuId}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`⚠️ **ATENÇÃO:**\n` +
|
||
`• A atualização pode demorar alguns minutos\n` +
|
||
`• A ONU ficará offline durante o processo\n` +
|
||
`• Não interrompa a operação\n\n` +
|
||
`Tem certeza que deseja continuar?`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✅ SIM, Atualizar', callback_data: `confirm_firmware_${firmwareFile}_${oltId}_${slot}_${onuId}` },
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]
|
||
]
|
||
}
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Processa confirmação de atualização de firmware
|
||
*/
|
||
async handleConfirmFirmware(callbackQuery, data) {
|
||
// Formato: confirm_firmware_DM986-100-v56.tar_olt_dito_slot_onuid
|
||
const parts = data.replace('confirm_firmware_', '').split('_');
|
||
|
||
let firmwareFile, oltId, slot, onuId;
|
||
|
||
firmwareFile = parts[0];
|
||
|
||
if (parts.length === 5) {
|
||
oltId = parts[1] + '_' + parts[2];
|
||
slot = parts[3];
|
||
onuId = parts[4];
|
||
} else if (parts.length === 4) {
|
||
oltId = parts[1];
|
||
slot = parts[2];
|
||
onuId = parts[3];
|
||
} else {
|
||
onuId = parts[parts.length - 1];
|
||
slot = parts[parts.length - 2];
|
||
oltId = parts.slice(1, -2).join('_');
|
||
}
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
await this.bot.editMessageText(
|
||
`⬆️ **Atualizando Firmware...**\n\n` +
|
||
`📦 Firmware: ${firmwareFile}\n` +
|
||
`📍 Slot: ${slot}\n` +
|
||
`🔌 ONU ID: ${onuId}\n` +
|
||
`🏢 OLT: ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`⏳ Enviando comando de atualização...`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
try {
|
||
const result = await this.ssh.updateOnuFirmware(oltId, slot, onuId, firmwareFile);
|
||
|
||
if (result.success) {
|
||
await this.bot.editMessageText(
|
||
`✅ **Comando de Atualização Enviado!**\n\n` +
|
||
`📦 **Firmware:** ${firmwareFile}\n` +
|
||
`📍 **Slot:** ${slot}\n` +
|
||
`🔌 **ONU ID:** ${onuId}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`✅ **Status:** Comando enviado com sucesso\n` +
|
||
`⏳ **Processamento:** A atualização está sendo processada pela OLT\n` +
|
||
`🕒 **Tempo estimado:** 5-15 minutos\n` +
|
||
`📡 **Importante:** Monitore o status da ONU\n\n` +
|
||
`💡 *A ONU ficará offline durante a atualização*`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
} else {
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro ao Enviar Comando**\n\n` +
|
||
`📦 **Firmware:** ${firmwareFile}\n` +
|
||
`📍 **Slot:** ${slot}\n` +
|
||
`🔌 **ONU ID:** ${onuId}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`❌ **Erro:** ${result.message}\n\n` +
|
||
`🔄 Tente novamente ou verifique a conexão`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao atualizar firmware:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro Interno**\n\n` +
|
||
`Não foi possível atualizar o firmware.\n` +
|
||
`Erro: ${error.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Handle callback para iniciar processo de remoção de ONU
|
||
*/
|
||
async handleRemoveOnuCallback(callbackQuery, data) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
const parts = data.split('_'); // remove_onu_olt_dito_[serialNumber] ou remove_onu_olt_pedro_afonso_[serialNumber]
|
||
|
||
let oltId, serialNumber;
|
||
|
||
if (parts.length >= 6 && parts[3] === 'pedro' && parts[4] === 'afonso') {
|
||
// Caso: remove_onu_olt_pedro_afonso_SERIAL
|
||
oltId = parts[2] + '_' + parts[3] + '_' + parts[4]; // "olt_pedro_afonso"
|
||
serialNumber = parts.slice(5).join('_'); // Serial pode ter underscores
|
||
} else if (parts.length >= 5) {
|
||
// Caso: remove_onu_olt_dito_SERIAL ou outras OLTs de duas palavras
|
||
oltId = parts[2] + '_' + parts[3]; // "olt_dito"
|
||
serialNumber = parts.slice(4).join('_'); // Serial pode ter underscores
|
||
} else {
|
||
// Fallback - caso não siga o padrão esperado
|
||
oltId = parts[2];
|
||
serialNumber = parts.slice(3).join('_');
|
||
}
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
|
||
await this.bot.editMessageText(
|
||
`🔍 **Buscando ONU ${serialNumber}**\n\n` +
|
||
`🏢 OLT: ${oltId.replace('olt_', '').replace(/_/g, '\\_').toUpperCase()}\n` +
|
||
`📱 Serial: ${serialNumber}\n\n` +
|
||
`⏳ Localizando ONU e service-port...`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
try {
|
||
const result = await this.ssh.removeOnuBySerial(oltId, serialNumber);
|
||
|
||
if (result.success && result.readyForRemoval) {
|
||
// ONU encontrada - mostrar informações e pedir confirmação
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✅ CONFIRMAR REMOÇÃO', callback_data: `confirm_remove_${oltId}_${result.slot.replace(/\//g, '-')}_${result.onuId}_${result.servicePort}_${serialNumber}` }
|
||
],
|
||
[
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.editMessageText(
|
||
`⚠️ **CONFIRMAÇÃO DE REMOÇÃO**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`📍 **Localização:** Slot ${result.slot}, ONU ${result.onuId}\n` +
|
||
`🔌 **Service-port:** ${result.servicePort}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').replace(/_/g, '\\_').toUpperCase()}\n\n` +
|
||
`⚠️ **ATENÇÃO:** Esta ação não pode ser desfeita!\n` +
|
||
`A ONU será completamente removida da OLT.\n\n` +
|
||
`🔴 **Confirme que deseja remover esta ONU:**`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown',
|
||
reply_markup: keyboard
|
||
}
|
||
);
|
||
} else {
|
||
await this.bot.editMessageText(
|
||
`❌ **ONU não encontrada**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').replace(/_/g, '\\_').toUpperCase()}\n\n` +
|
||
`❌ **Erro:** ${result.message}\n\n` +
|
||
`💡 Verifique se o serial está correto ou se a ONU existe nesta OLT`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao buscar ONU para remoção:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro interno**\n\n` +
|
||
`Não foi possível buscar a ONU.\n` +
|
||
`Erro: ${error.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Handle callback para confirmar remoção de ONU
|
||
*/
|
||
async handleConfirmRemoveCallback(callbackQuery, data) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
console.log(`🔍 handleConfirmRemoveCallback chamado com data: ${data}`);
|
||
|
||
const parts = data.split('_'); // confirm_remove_olt_dito_[slot]_[onuId]_[servicePort]_[serialNumber]
|
||
console.log(`🔍 Parts: ${JSON.stringify(parts)}`);
|
||
|
||
let oltId, slot, onuId, servicePort, serialNumber;
|
||
|
||
if (parts.length >= 9 && parts[3] === 'pedro' && parts[4] === 'afonso') {
|
||
// Caso: confirm_remove_olt_pedro_afonso_slot_onuId_servicePort_serialNumber
|
||
oltId = parts[2] + '_' + parts[3] + '_' + parts[4]; // "olt_pedro_afonso"
|
||
slot = parts[5].replace(/-/g, '/'); // Converter de volta: "1-1-3" -> "1/1/3"
|
||
onuId = parts[6];
|
||
servicePort = parts[7];
|
||
serialNumber = parts.slice(8).join('_'); // Serial pode ter underscores
|
||
} else if (parts.length >= 8) {
|
||
// Caso: confirm_remove_olt_dito_slot_onuId_servicePort_serialNumber
|
||
oltId = parts[2] + '_' + parts[3]; // "olt_dito"
|
||
slot = parts[4].replace(/-/g, '/'); // Converter de volta: "1-1-3" -> "1/1/3"
|
||
onuId = parts[5];
|
||
servicePort = parts[6];
|
||
serialNumber = parts.slice(7).join('_'); // Serial pode ter underscores
|
||
} else {
|
||
// Fallback - caso não siga o padrão esperado
|
||
oltId = parts[2];
|
||
slot = parts[3].replace(/-/g, '/'); // Converter de volta também no fallback
|
||
onuId = parts[4];
|
||
servicePort = parts[5];
|
||
serialNumber = parts.slice(6).join('_');
|
||
}
|
||
|
||
console.log(`🔍 Parsed - oltId: ${oltId}, slot: ${slot}, onuId: ${onuId}, servicePort: ${servicePort}, serialNumber: ${serialNumber}`);
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
|
||
await this.bot.editMessageText(
|
||
`🗑️ **Removendo ONU...**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`📍 **Localização:** Slot ${slot}, ONU ${onuId}\n` +
|
||
`🔌 **Service-port:** ${servicePort}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').replace(/_/g, '\\_').toUpperCase()}\n\n` +
|
||
`⏳ Executando comandos de remoção...`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
try {
|
||
const result = await this.ssh.removeOnu(oltId, slot, onuId, servicePort);
|
||
|
||
if (result.success) {
|
||
await this.bot.editMessageText(
|
||
`✅ **ONU Removida com Sucesso!**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`📍 **Localização:** Slot ${slot}, ONU ${onuId}\n` +
|
||
`🔌 **Service-port:** ${servicePort}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').replace(/_/g, '\\_').toUpperCase()}\n\n` +
|
||
`✅ **Status:** ONU removida completamente\n` +
|
||
`🗑️ **Ações realizadas:**\n` +
|
||
`• Removida interface ONU\n` +
|
||
`• Removido service-port\n` +
|
||
`• Configuração commitada\n\n` +
|
||
`💡 A ONU pode ser reconfigurada quando necessário`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
} else {
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro na Remoção**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`📍 **Localização:** Slot ${slot}, ONU ${onuId}\n` +
|
||
`🔌 **Service-port:** ${servicePort}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').replace(/_/g, '\\_').toUpperCase()}\n\n` +
|
||
`❌ **Erro:** ${result.message}\n\n` +
|
||
`🔄 Verifique o status da ONU ou tente novamente`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao remover ONU:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro Interno**\n\n` +
|
||
`Não foi possível remover a ONU.\n` +
|
||
`Erro: ${error.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Handle callback para iniciar processo de adição de ONU
|
||
*/
|
||
async handleAddOnuCallback(callbackQuery, data) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
const parts = data.split('_'); // add_onu_olt_dito_[serialNumber] ou add_onu_olt_pedro_afonso_[serialNumber]
|
||
|
||
let oltId, serialNumber;
|
||
|
||
if (parts.length >= 6 && parts[3] === 'pedro' && parts[4] === 'afonso') {
|
||
// Caso: add_onu_olt_pedro_afonso_SERIAL
|
||
oltId = parts[2] + '_' + parts[3] + '_' + parts[4]; // "olt_pedro_afonso"
|
||
serialNumber = parts.slice(5).join('_'); // Serial pode ter underscores
|
||
} else if (parts.length >= 5) {
|
||
// Caso: add_onu_olt_dito_SERIAL ou outras OLTs de duas palavras
|
||
oltId = parts[2] + '_' + parts[3]; // "olt_dito"
|
||
serialNumber = parts.slice(4).join('_'); // Serial pode ter underscores
|
||
} else {
|
||
// Fallback - caso não siga o padrão esperado
|
||
oltId = parts[2];
|
||
serialNumber = parts.slice(3).join('_');
|
||
}
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
|
||
await this.bot.editMessageText(
|
||
`🔍 **Analisando ONU ${serialNumber}**\n\n` +
|
||
`🏢 OLT: ${oltId.replace('olt_', '').replace(/_/g, '\\_').toUpperCase()}\n` +
|
||
`📱 Serial: ${serialNumber}\n\n` +
|
||
`⏳ Descobrindo slot e próximo ONU ID disponível...`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
try {
|
||
const result = await this.ssh.addOnuBySerial(oltId, serialNumber);
|
||
|
||
if (result.success && result.readyForAddition) {
|
||
// ONU analisada - mostrar informações e pedir confirmação
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✅ CONFIRMAR ADIÇÃO', callback_data: `confirm_add_${oltId}_${result.slot.replace(/\//g, '-')}_${result.onuId}_${result.vlanId}_${serialNumber}` }
|
||
],
|
||
[
|
||
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.editMessageText(
|
||
`✅ **CONFIRMAÇÃO DE ADIÇÃO**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`📍 **Slot descoberto:** ${result.slot}\n` +
|
||
`🔢 **ONU ID a usar:** ${result.onuId}\n` +
|
||
`🏷️ **VLAN ID:** ${result.vlanId}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`📋 **ONU IDs em uso no slot:** ${result.usedIds.join(', ')}\n\n` +
|
||
`⚡ **Configurações que serão aplicadas:**\n` +
|
||
`• Line-profile: DM986-100\n` +
|
||
`• Ethernet: porta 1\n` +
|
||
`• Native VLAN: ${result.vlanId}\n` +
|
||
`• Service-port: novo (auto)\n\n` +
|
||
`✅ **Confirme que deseja adicionar esta ONU:**`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown',
|
||
reply_markup: keyboard
|
||
}
|
||
);
|
||
} else {
|
||
let errorMessage = `❌ **Não foi possível adicionar a ONU**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n`;
|
||
|
||
if (result.message) {
|
||
errorMessage += `❌ **Erro:** ${result.message}\n\n`;
|
||
}
|
||
|
||
if (result.message && result.message.includes('discovered-onus')) {
|
||
errorMessage += `💡 **Dica:** Verifique se a ONU está ligada e descoberta pela OLT.\n` +
|
||
`Use o comando: \`show interface gpon discovered-onus\``;
|
||
} else if (result.message && result.message.includes('todos os ONU IDs')) {
|
||
errorMessage += `💡 **Dica:** O slot está lotado. Considere usar outro slot ou remover ONUs inutilizadas.`;
|
||
} else {
|
||
errorMessage += `💡 Verifique a conectividade com a OLT ou se a ONU está descoberta.`;
|
||
}
|
||
|
||
await this.bot.editMessageText(errorMessage, {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao analisar ONU para adição:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro interno**\n\n` +
|
||
`Não foi possível analisar a ONU.\n` +
|
||
`Erro: ${error.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Handle callback para confirmar adição de ONU
|
||
*/
|
||
async handleConfirmAddCallback(callbackQuery, data) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
console.log(`🔍 handleConfirmAddCallback chamado com data: ${data}`);
|
||
|
||
// Parse do formato: confirm_add_olt_dito_1-1-3_0_603_DACM915E0F76
|
||
const parts = data.split('_');
|
||
console.log(`🔍 Parts: ${JSON.stringify(parts)}`);
|
||
|
||
let oltId, slot, onuId, vlanId, serialNumber;
|
||
|
||
if (parts.length >= 8 && parts[2] === 'olt' && parts[3] === 'pedro' && parts[4] === 'afonso') {
|
||
// Caso: confirm_add_olt_pedro_afonso_1-1-3_0_603_DACM915E0F76
|
||
oltId = parts[2] + '_' + parts[3] + '_' + parts[4]; // "olt_pedro_afonso"
|
||
slot = parts[5].replace(/-/g, '/'); // Converter de volta: "1-1-3" -> "1/1/3"
|
||
onuId = parts[6];
|
||
vlanId = parts[7];
|
||
serialNumber = parts.slice(8).join('_'); // Serial pode ter underscores
|
||
} else if (parts.length >= 7) {
|
||
// Caso padrão: confirm_add_olt_dito_1-1-3_0_603_DACM915E0F76
|
||
oltId = parts[2] + '_' + parts[3]; // "olt_dito"
|
||
slot = parts[4].replace(/-/g, '/'); // Converter de volta: "1-1-3" -> "1/1/3"
|
||
onuId = parts[5];
|
||
vlanId = parts[6];
|
||
serialNumber = parts.slice(7).join('_'); // Serial pode ter underscores
|
||
} else if (parts.length >= 6) {
|
||
// Fallback para OLTs com nome simples
|
||
oltId = parts[2]; // "olt"
|
||
slot = parts[3].replace(/-/g, '/'); // Converter de volta
|
||
onuId = parts[4];
|
||
vlanId = parts[5];
|
||
serialNumber = parts.slice(6).join('_');
|
||
} else {
|
||
console.error(`❌ Formato de callback inválido: ${data}`);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, { text: 'Erro no formato do callback' });
|
||
return;
|
||
}
|
||
|
||
console.log(`🔍 Parsed - oltId: ${oltId}, slot: ${slot}, onuId: ${onuId}, vlanId: ${vlanId}, serialNumber: ${serialNumber}`);
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
|
||
await this.bot.editMessageText(
|
||
`➕ **Adicionando ONU...**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`📍 **Localização:** Slot ${slot}, ONU ${onuId}\n` +
|
||
`🏷️ **VLAN:** ${vlanId}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`⏳ Executando comandos de configuração...\n` +
|
||
`⚡ Este processo pode levar até 90 segundos`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
try {
|
||
const result = await this.ssh.addOnu(oltId, slot, onuId, serialNumber, parseInt(vlanId));
|
||
|
||
if (result.success) {
|
||
const servicePortInfo = result.servicePortId ?
|
||
`🔌 **Service-port:** ${result.servicePortId} (Auto-gerado)` :
|
||
`🔌 **Service-port:** Criado automaticamente`;
|
||
|
||
await this.bot.editMessageText(
|
||
`✅ **ONU Adicionada com Sucesso!**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`📍 **Localização:** Slot ${slot}, ONU ${onuId}\n` +
|
||
`🏷️ **VLAN:** ${vlanId}\n` +
|
||
`${servicePortInfo}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`✅ **Configurações aplicadas:**\n` +
|
||
`• Line-profile: DM986-100\n` +
|
||
`• Serial number: ${serialNumber}\n` +
|
||
`• Ethernet: porta 1\n` +
|
||
`• Native VLAN: ${vlanId}\n` +
|
||
`• Service-port: ${result.servicePortId || 'auto-gerado'} criado e configurado\n` +
|
||
`• Configuração commitada\n\n` +
|
||
`🎉 A ONU está pronta para uso!`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
} else {
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro na Adição**\n\n` +
|
||
`📱 **Serial:** ${serialNumber}\n` +
|
||
`📍 **Localização:** Slot ${slot}, ONU ${onuId}\n` +
|
||
`🏷️ **VLAN:** ${vlanId}\n` +
|
||
`🏢 **OLT:** ${oltId.replace('olt_', '').toUpperCase()}\n\n` +
|
||
`❌ **Erro:** ${result.message}\n\n` +
|
||
`🔄 Verifique a conectividade com a OLT ou tente novamente`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
} catch (error) {
|
||
console.error('Erro ao adicionar ONU:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro Interno**\n\n` +
|
||
`Não foi possível adicionar a ONU.\n` +
|
||
`Erro: ${error.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Painel administrativo
|
||
*/
|
||
async handleAdmin(chatId) {
|
||
const userId = chatId; // Para chats individuais, chatId = userId
|
||
|
||
// Verificar se é usuário autorizado
|
||
if (!this.isAuthorized(userId)) {
|
||
await this.bot.sendMessage(chatId, '🚫 Acesso negado ao painel administrativo.');
|
||
return;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`🛡️ **Painel Administrativo**\n\n` +
|
||
`👥 **Gestão de Usuários:**\n` +
|
||
`• \`usuarios autorizados\` - Ver lista de usuários\n` +
|
||
`• \`meu id\` - Ver seu ID do Telegram\n\n` +
|
||
`📊 **Sistema:**\n` +
|
||
`• \`status\` - Status do bot\n` +
|
||
`• \`equipamentos\` - Lista de equipamentos\n` +
|
||
`• \`logs\` - Ver logs recentes\n` +
|
||
`• \`limpar logs\` - Limpar logs do sistema\n\n` +
|
||
`🔧 **Comandos disponíveis:**\n` +
|
||
`• Ver sinal, adicionar ONU, remover ONU\n` +
|
||
`• Resetar ONU, atualizar firmware\n` +
|
||
`• Gerenciar usuários Juniper`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Listar usuários autorizados
|
||
*/
|
||
async handleListAuthorizedUsers(chatId) {
|
||
const userId = chatId;
|
||
|
||
if (!this.isAuthorized(userId)) {
|
||
await this.bot.sendMessage(chatId, '🚫 Acesso negado.');
|
||
return;
|
||
}
|
||
|
||
const authorizedUsers = config.bot.allowedUsers;
|
||
|
||
if (authorizedUsers.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`👥 **Usuários Autorizados**\n\n` +
|
||
`⚠️ Nenhuma restrição configurada\n` +
|
||
`🌐 Bot está aberto para todos os usuários\n\n` +
|
||
`💡 Configure ALLOWED_USERS no .env para restringir`
|
||
);
|
||
} else {
|
||
const userList = authorizedUsers.map((id, index) =>
|
||
`${index + 1}. ID: \`${id}\``
|
||
).join('\n');
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`👥 **Usuários Autorizados**\n\n` +
|
||
`📊 Total: ${authorizedUsers.length} usuário(s)\n\n` +
|
||
`${userList}\n\n` +
|
||
`🆔 Seu ID: \`${userId}\``,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Exibir ID do usuário
|
||
*/
|
||
async handleMyId(chatId, userId) {
|
||
await this.bot.sendMessage(chatId,
|
||
`🆔 **Sua Identificação**\n\n` +
|
||
`👤 User ID: \`${userId}\`\n` +
|
||
`💬 Chat ID: \`${chatId}\`\n\n` +
|
||
`📋 Use estes IDs para configurar permissões`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
|
||
/**
|
||
* Status do TopSapp
|
||
*/
|
||
async handleStatusTopSapp(chatId) {
|
||
try {
|
||
await this.bot.sendMessage(chatId, '🔄 Verificando status do TopSapp...');
|
||
|
||
const status = this.topsapp.getConfigStatus();
|
||
const instances = this.topsapp.getInstances();
|
||
|
||
let message = `🏢 **STATUS TOPSAPP**\n\n`;
|
||
|
||
if (status.ready) {
|
||
message += `✅ **Configuração**: OK\n`;
|
||
message += `📊 **Instâncias configuradas**: ${instances.length}\n\n`;
|
||
|
||
instances.forEach(instance => {
|
||
message += `🌐 **${instance.location}**\n`;
|
||
message += `└ ${instance.host}\n`;
|
||
message += `└ Status: ${status.instances.find(i => i.location === instance.location)?.configured ? '✅ Configurado' : '❌ Não configurado'}\n\n`;
|
||
});
|
||
|
||
message += `💡 Use os comandos:\n`;
|
||
message += `• "buscar cliente João"\n`;
|
||
message += `• "ver faturas 123.456.789-10"\n`;
|
||
message += `• "gerar boleto fatura123"\n`;
|
||
message += `• "bloquear cliente 456"`;
|
||
} else {
|
||
message += `❌ **Configuração**: Incompleta\n\n`;
|
||
message += `⚠️ **Problemas encontrados**:\n`;
|
||
|
||
status.instances.forEach(instance => {
|
||
if (!instance.configured) {
|
||
message += `• ${instance.location}: Credenciais não configuradas\n`;
|
||
}
|
||
});
|
||
|
||
message += `\n📝 **Configure no arquivo .env**:\n`;
|
||
message += `• TOPSAPP_GUARAI_USER\n`;
|
||
message += `• TOPSAPP_GUARAI_PASS\n`;
|
||
message += `• TOPSAPP_PEDRO_AFONSO_USER\n`;
|
||
message += `• TOPSAPP_PEDRO_AFONSO_PASS`;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao verificar status TopSapp:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao verificar status TopSapp**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Buscar cliente no TopSapp
|
||
*/
|
||
async handleBuscarCliente(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId,
|
||
`🔍 **Buscar Cliente**\n\n` +
|
||
`💡 **Como usar:**\n` +
|
||
`• "buscar cliente João da Silva"\n` +
|
||
`• "buscar cliente 123.456.789-10"\n` +
|
||
`• "buscar cliente Guarai João" (específica instância)\n` +
|
||
`• "buscar cliente Pedro Afonso Maria"`
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
|
||
|
||
// Detectar se especificou uma localização
|
||
let location = '';
|
||
let query = target;
|
||
|
||
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
|
||
location = 'Guarai/Colmeia';
|
||
query = target.replace(/(guarai|colmeia)/gi, '').trim();
|
||
} else if (target.toLowerCase().includes('pedro afonso')) {
|
||
location = 'Pedro Afonso';
|
||
query = target.replace(/pedro afonso/gi, '').trim();
|
||
}
|
||
|
||
const resultado = await this.topsapp.buscarCliente(query, location);
|
||
|
||
if (!resultado.success) {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro na busca**\n\n` +
|
||
`⚠️ ${resultado.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (!resultado.clientes || resultado.clientes.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`🔍 **Nenhum cliente encontrado**\n\n` +
|
||
`📝 Termo buscado: "${query}"\n` +
|
||
`🌐 Instância: ${resultado.instancia || 'Todas'}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Se encontrou mais de um cliente, mostrar lista para seleção
|
||
if (resultado.clientes.length > 1) {
|
||
let message = `🔍 **${resultado.clientes.length} clientes encontrados**\n\n`;
|
||
message += `🌐 **Instância**: ${resultado.instancia}\n\n`;
|
||
|
||
const keyboard = [];
|
||
|
||
resultado.clientes.slice(0, 10).forEach((cliente, index) => {
|
||
message += `👤 **${index + 1}. ${cliente.nome}**\n`;
|
||
message += `🆔 ID: \`${cliente.id}\`\n`;
|
||
if (cliente.cpf) {
|
||
message += `📄 CPF: \`${cliente.cpf}\`\n`;
|
||
}
|
||
message += `📞 ${cliente.telefone || 'Telefone não informado'}\n`;
|
||
message += `📊 Status: ${cliente.status === 1 ? '✅ Ativo' : '❌ Inativo'}\n\n`;
|
||
|
||
// Adicionar botões para ações
|
||
keyboard.push([
|
||
{ text: `📋 Dados ${index + 1}`, callback_data: `dados_cliente_${cliente.id}_${location}` },
|
||
{ text: `📄 Faturas ${index + 1}`, callback_data: `faturas_cliente_${cliente.id}_${location}` }
|
||
]);
|
||
});
|
||
|
||
if (resultado.clientes.length > 10) {
|
||
message += `📋 *Mostrando apenas os primeiros 10 resultados de ${resultado.clientes.length}*\n\n`;
|
||
}
|
||
|
||
message += `💡 **Selecione uma opção abaixo:**`;
|
||
|
||
await this.bot.sendMessage(chatId, message, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
return;
|
||
}
|
||
|
||
// Se encontrou apenas um cliente, mostrar dados detalhados
|
||
// Se encontrou apenas um cliente, mostrar dados detalhados
|
||
const cliente = resultado.clientes[0];
|
||
let message = `� **Cliente Encontrado**\n\n`;
|
||
message += `🆔 **ID**: \`${cliente.id}\`\n`;
|
||
message += `� **Nome**: ${cliente.nome}\n`;
|
||
|
||
if (cliente.cpf) {
|
||
message += `📄 **CPF**: \`${cliente.cpf}\`\n`;
|
||
}
|
||
|
||
message += `📧 **Email**: ${cliente.email || 'Não informado'}\n`;
|
||
message += `📞 **Telefone**: ${cliente.telefone || 'Não informado'}\n`;
|
||
message += `📍 **Endereço**: ${cliente.endereco || 'Não informado'}\n`;
|
||
message += `🏙️ **Cidade**: ${cliente.cidade || 'Não informado'}\n`;
|
||
message += `📊 **Status**: ${cliente.status === 1 ? '✅ Ativo' : '❌ Inativo'}\n`;
|
||
message += `🌐 **Instância**: ${resultado.instancia}\n\n`;
|
||
|
||
// Botões de ação
|
||
const keyboard = [
|
||
[
|
||
{ text: '📋 Dados Cadastrais', callback_data: `dados_cliente_${cliente.id}_${location}` },
|
||
{ text: '📄 Ver Faturas', callback_data: `faturas_cliente_${cliente.id}_${location}` }
|
||
],
|
||
[
|
||
{ text: '🔒 Bloquear', callback_data: `confirm_block_${cliente.id}_${location}` },
|
||
{ text: '🔓 Liberar', callback_data: `confirm_unblock_${cliente.id}_${location}` }
|
||
]
|
||
];
|
||
|
||
await this.bot.sendMessage(chatId, message, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao buscar cliente:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar cliente**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Mostrar dados cadastrais completos do cliente
|
||
*/
|
||
async handleDadosCliente(chatId, idCliente, location = '') {
|
||
try {
|
||
await this.bot.sendMessage(chatId, '📋 Carregando dados cadastrais...');
|
||
|
||
const resultado = await this.topsapp.obterDadosCadastrais(idCliente, location);
|
||
|
||
if (!resultado.success) {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar dados**\n\n` +
|
||
`⚠️ ${resultado.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
const cliente = resultado.cliente;
|
||
const servicos = resultado.servicos || [];
|
||
|
||
let message = `📋 **Dados Cadastrais Completos**\n\n`;
|
||
|
||
// Dados do cliente
|
||
message += `👤 **CLIENTE**\n`;
|
||
message += `🆔 ID: \`${cliente.id}\`\n`;
|
||
message += `👤 Nome: ${cliente.nome}\n`;
|
||
|
||
if (cliente.cpf) {
|
||
message += `📄 CPF: \`${cliente.cpf}\`\n`;
|
||
}
|
||
|
||
if (cliente.rg) {
|
||
message += `📄 RG: \`${cliente.rg}\`\n`;
|
||
}
|
||
|
||
message += `📧 Email: ${cliente.email || 'Não informado'}\n`;
|
||
message += `📞 Telefone: ${cliente.telefone || 'Não informado'}\n`;
|
||
message += `📱 Celular: ${cliente.celular || 'Não informado'}\n`;
|
||
|
||
// Endereço
|
||
if (cliente.endereco) {
|
||
message += `📍 Endereço: ${cliente.endereco}`;
|
||
if (cliente.numero) {
|
||
message += `, ${cliente.numero}`;
|
||
}
|
||
message += `\n`;
|
||
}
|
||
|
||
if (cliente.complemento) {
|
||
message += `📝 Complemento: ${cliente.complemento}\n`;
|
||
}
|
||
|
||
message += `🏘️ Bairro: ${cliente.bairro || 'Não informado'}\n`;
|
||
message += `🏙️ Cidade: ${cliente.cidade || 'Não informado'}`;
|
||
|
||
if (cliente.uf) {
|
||
message += ` - ${cliente.uf}`;
|
||
}
|
||
message += `\n`;
|
||
|
||
message += `📮 CEP: ${cliente.cep || 'Não informado'}\n`;
|
||
message += `📊 Status Geral: ${cliente.status === 1 ? '✅ Ativo' : '❌ Inativo'}\n`;
|
||
|
||
if (cliente.data_cadastro) {
|
||
message += `📅 Cadastro: ${this.formatarData(cliente.data_cadastro)}\n`;
|
||
}
|
||
|
||
if (cliente.observacoes) {
|
||
message += `📝 Observações: ${cliente.observacoes}\n`;
|
||
}
|
||
|
||
message += `\n🌐 **Instância**: ${resultado.instancia}\n\n`;
|
||
|
||
// Dados dos serviços
|
||
if (servicos.length > 0) {
|
||
message += `⚙️ **SERVIÇOS CONTRATADOS**\n\n`;
|
||
|
||
servicos.forEach((servico, index) => {
|
||
message += `📦 **Serviço ${index + 1}**\n`;
|
||
message += `🏷️ Plano: ${servico.planoNome}\n`;
|
||
message += `📊 Status: ${servico.statusFormatado}\n`;
|
||
|
||
if (servico.login) {
|
||
message += `👤 Login: \`${servico.login}\`\n`;
|
||
}
|
||
|
||
if (servico.senha) {
|
||
message += `🔑 Senha: \`${servico.senha}\`\n`;
|
||
}
|
||
|
||
if (servico.ip) {
|
||
message += `🌐 IP: \`${servico.ip}\`\n`;
|
||
}
|
||
|
||
if (servico.vencimento) {
|
||
message += `📅 Vencimento: Dia ${servico.vencimento}\n`;
|
||
}
|
||
|
||
if (servico.valor) {
|
||
message += `💰 Valor: R$ ${parseFloat(servico.valor).toFixed(2)}\n`;
|
||
}
|
||
|
||
message += `� Tecnologia: ${servico.tecnologia}\n`;
|
||
|
||
if (servico.velocidade_down) {
|
||
message += `⬇️ Download: ${servico.velocidade_down} Mbps\n`;
|
||
}
|
||
|
||
if (servico.velocidade_up) {
|
||
message += `⬆️ Upload: ${servico.velocidade_up} Mbps\n`;
|
||
}
|
||
|
||
// Dados FTTH - usando campos reais da API
|
||
if (servico.tecnologia === 'FTTH' || servico.pon || servico.serial) {
|
||
message += `\n📡 **Dados FTTH:**\n`;
|
||
|
||
if (servico.base || servico.id_ap) {
|
||
message += `🔌 Base/AP: ${servico.base || `AP ${servico.id_ap}`}\n`;
|
||
}
|
||
|
||
if (servico.pon) {
|
||
message += `🔗 PON: ${servico.pon}\n`;
|
||
}
|
||
|
||
if (servico.perfil) {
|
||
message += `⚙️ Perfil: ${servico.perfil}\n`;
|
||
}
|
||
|
||
if (servico.serial) {
|
||
message += `📟 Serial ONU: \`${servico.serial}\`\n`;
|
||
}
|
||
|
||
if (servico.serviceport) {
|
||
message += `🔌 Service Port: ${servico.serviceport}\n`;
|
||
}
|
||
|
||
if (servico.ultimo_rx_power) {
|
||
message += `� Último RX: ${servico.ultimo_rx_power} dBm\n`;
|
||
}
|
||
|
||
if (servico.ultimo_tx_power) {
|
||
message += `📡 Último TX: ${servico.ultimo_tx_power} dBm\n`;
|
||
}
|
||
|
||
if (servico.data_ultimo_sinal) {
|
||
message += `📅 Último sinal: ${this.formatarData(servico.data_ultimo_sinal)} ${servico.hora_ultimo_sinal || ''}\n`;
|
||
}
|
||
|
||
if (servico.conexao) {
|
||
const statusConexao = servico.conexao === 'online' ? '🟢 Online' : '🔴 Offline';
|
||
message += `🔌 Conexão: ${statusConexao}\n`;
|
||
}
|
||
|
||
if (servico.ultimo_acesso) {
|
||
message += `� Último acesso: ${servico.ultimo_acesso}\n`;
|
||
}
|
||
|
||
if (servico.ultimo_ip) {
|
||
message += `🌐 Último IP: \`${servico.ultimo_ip}\`\n`;
|
||
}
|
||
}
|
||
|
||
// Dados de instalação
|
||
if (servico.instalacao_endereco) {
|
||
message += `\n📍 **Endereço de Instalação:**\n`;
|
||
message += `🏠 ${servico.instalacao_endereco}, ${servico.instalacao_numero || 'S/N'}\n`;
|
||
|
||
if (servico.instalacao_complemento) {
|
||
message += `� Complemento: ${servico.instalacao_complemento}\n`;
|
||
}
|
||
|
||
message += `🏘️ ${servico.instalacao_bairro}, ${servico.instalacao_cidade}/${servico.instalacao_uf}\n`;
|
||
|
||
if (servico.instalacao_cep) {
|
||
message += `📮 CEP: ${servico.instalacao_cep}\n`;
|
||
}
|
||
|
||
if (servico.latitude && servico.longitude) {
|
||
message += `🗺️ Coordenadas: ${servico.latitude}, ${servico.longitude}\n`;
|
||
}
|
||
}
|
||
|
||
message += `\n`;
|
||
});
|
||
} else {
|
||
message += `⚙️ **SERVIÇOS**: Nenhum serviço encontrado\n\n`;
|
||
}
|
||
|
||
// Botões de ação
|
||
const keyboard = [
|
||
[
|
||
{ text: '📄 Ver Faturas', callback_data: `faturas_cliente_${idCliente}_${location}` },
|
||
{ text: '⚙️ Listar Serviços', callback_data: `servicos_cliente_${idCliente}_${location}` }
|
||
],
|
||
[
|
||
{ text: '🔒 Bloquear Cliente', callback_data: `confirm_block_${idCliente}_${location}` },
|
||
{ text: '🔓 Liberar Cliente', callback_data: `confirm_unblock_${idCliente}_${location}` }
|
||
]
|
||
];
|
||
|
||
await this.bot.sendMessage(chatId, message, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao buscar dados do cliente:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar dados do cliente**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Ver faturas do cliente
|
||
*/
|
||
async handleVerFaturas(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📄 **Ver Faturas**\n\n` +
|
||
`💡 **Como usar:**\n` +
|
||
`• "ver faturas 123.456.789-10"\n` +
|
||
`• "ver faturas cliente123"\n` +
|
||
`• "ver faturas Guarai 123.456.789-10"`
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await this.bot.sendMessage(chatId, '📄 Buscando faturas...');
|
||
|
||
// Detectar se especificou uma localização
|
||
let location = '';
|
||
let clienteId = target;
|
||
|
||
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
|
||
location = 'Guarai/Colmeia';
|
||
clienteId = target.replace(/(guarai|colmeia)/gi, '').trim();
|
||
} else if (target.toLowerCase().includes('pedro afonso')) {
|
||
location = 'Pedro Afonso';
|
||
clienteId = target.replace(/pedro afonso/gi, '').trim();
|
||
}
|
||
|
||
// Se é CPF ou nome, buscar o cliente primeiro
|
||
let idCliente = null;
|
||
|
||
// Verificar se é número puro (CPF sem formatação)
|
||
if (/^\d{11}$/.test(clienteId)) {
|
||
// É CPF sem formatação
|
||
const busca = await this.topsapp.buscarCliente(clienteId, location);
|
||
if (busca.success && busca.clientes && busca.clientes.length > 0) {
|
||
idCliente = busca.clientes[0].id;
|
||
location = busca.instancia;
|
||
} else {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Cliente não encontrado**\n\n` +
|
||
`📝 CPF: "${clienteId}"`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
} else if (clienteId.includes('.') || clienteId.includes('-') || isNaN(clienteId)) {
|
||
// É CPF formatado ou nome
|
||
const busca = await this.topsapp.buscarCliente(clienteId, location);
|
||
if (busca.success && busca.clientes && busca.clientes.length > 0) {
|
||
idCliente = busca.clientes[0].id;
|
||
location = busca.instancia;
|
||
} else {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Cliente não encontrado**\n\n` +
|
||
`📝 CPF/Nome: "${clienteId}"`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
} else {
|
||
// É ID numérico
|
||
idCliente = clienteId;
|
||
}
|
||
|
||
const resultado = await this.topsapp.obterBoletos(idCliente, location);
|
||
|
||
if (!resultado.success) {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar faturas**\n\n` +
|
||
`⚠️ ${resultado.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (!resultado.boletos || resultado.boletos.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📄 **Nenhuma fatura encontrada**\n\n` +
|
||
`👤 Cliente ID: ${idCliente}\n` +
|
||
`🌐 Instância: ${resultado.instancia || location}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
let message = `📄 **Faturas do Cliente**\n\n`;
|
||
message += `📊 **Total**: ${resultado.total} fatura(s)\n`;
|
||
message += `🌐 **Instância**: ${resultado.instancia}\n\n`;
|
||
|
||
resultado.boletos.slice(0, 10).forEach((boleto, index) => {
|
||
message += `━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n`;
|
||
message += `💸 **${index + 1}. Fatura #${boleto.id}**\n`;
|
||
message += `💰 **Valor:** R$ ${boleto.valor}\n`;
|
||
message += `📅 **Vencimento:** ${this.formatarData(boleto.vencimento)}\n`;
|
||
message += `📊 **Status:** ${this.getStatusFatura(boleto.status)}\n`;
|
||
if (boleto.descricao) {
|
||
message += `📝 **Descrição:** ${boleto.descricao}\n`;
|
||
}
|
||
if (boleto.periodo) {
|
||
message += `📆 **Período:** ${boleto.periodo}\n`;
|
||
}
|
||
|
||
if (boleto.linhaDigitavel) {
|
||
message += `\n🔢 **Linha Digitável:**\n\`${boleto.linhaDigitavel}\`\n`;
|
||
}
|
||
|
||
if (boleto.pixCopiaCola) {
|
||
message += `\n💳 **PIX Copia e Cola:**\n\`${boleto.pixCopiaCola}\`\n`;
|
||
}
|
||
|
||
message += '\n';
|
||
});
|
||
|
||
if (resultado.total > 10) {
|
||
message += `📋 *Mostrando apenas as primeiras 10 faturas de ${resultado.total}*\n\n`;
|
||
}
|
||
|
||
if (resultado.boletos.length > 0) {
|
||
message += `💡 **Gerar boleto:**\n`;
|
||
message += `• "gerar boleto ${resultado.boletos[0].id}"`;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao buscar faturas:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar faturas**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Gerar boleto PDF
|
||
*/
|
||
async handleGerarBoleto(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId,
|
||
`💸 **Gerar Boleto**\n\n` +
|
||
`💡 **Como usar:**\n` +
|
||
`• "gerar boleto 12345"\n` +
|
||
`• "gerar boleto fatura123"`
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await this.bot.sendMessage(chatId, '💸 Gerando boleto PDF...');
|
||
|
||
const resultado = await this.topsapp.gerarBoletoPDF(target);
|
||
|
||
if (!resultado.success) {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao gerar boleto**\n\n` +
|
||
`⚠️ ${resultado.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Enviar o PDF
|
||
await this.bot.sendDocument(chatId, resultado.buffer, {
|
||
filename: resultado.filename,
|
||
caption: `💸 **Boleto Gerado**\n\n` +
|
||
`📄 Arquivo: ${resultado.filename}\n` +
|
||
`🌐 Instância: ${resultado.instancia}`,
|
||
parse_mode: 'Markdown'
|
||
});
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`✅ **Boleto enviado com sucesso!**\n\n` +
|
||
`📄 Arquivo: ${resultado.filename}\n` +
|
||
`🌐 Instância: ${resultado.instancia}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao gerar boleto:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao gerar boleto**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Bloquear cliente
|
||
*/
|
||
async handleBloquearCliente(chatId, target) {
|
||
console.log(`🔍 handleBloquearCliente iniciado com target:`, target, `(tipo: ${typeof target})`);
|
||
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId,
|
||
`🔒 **Bloquear Cliente**\n\n` +
|
||
`💡 **Como usar:**\n` +
|
||
`• "bloquear 123.456.789-10"\n` +
|
||
`• "bloquear cliente João"\n` +
|
||
`• "bloquear Guarai 123.456.789-10"`
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
|
||
|
||
// Detectar se especificou uma localização
|
||
let location = '';
|
||
let clienteQuery = target;
|
||
|
||
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
|
||
location = 'Guarai/Colmeia';
|
||
clienteQuery = target.replace(/(guarai|colmeia)/gi, '').trim();
|
||
} else if (target.toLowerCase().includes('pedro afonso')) {
|
||
location = 'Pedro Afonso';
|
||
clienteQuery = target.replace(/pedro afonso/gi, '').trim();
|
||
}
|
||
|
||
// Buscar cliente primeiro
|
||
let idCliente = null;
|
||
let nomeCliente = '';
|
||
|
||
if (/^\d{11}$/.test(clienteQuery) || clienteQuery.includes('.') || clienteQuery.includes('-') || isNaN(clienteQuery)) {
|
||
// É CPF ou nome
|
||
const busca = await this.topsapp.buscarCliente(clienteQuery, location);
|
||
if (busca.success && busca.clientes && busca.clientes.length > 0) {
|
||
idCliente = busca.clientes[0].id;
|
||
nomeCliente = busca.clientes[0].nome;
|
||
location = busca.instancia;
|
||
} else {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Cliente não encontrado**\n\n` +
|
||
`📝 CPF/Nome: "${clienteQuery}"`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
} else {
|
||
// É ID numérico
|
||
idCliente = clienteQuery;
|
||
}
|
||
|
||
// Buscar serviços do cliente para mostrar opções
|
||
const servicosResult = await this.topsapp.obterServicosCliente(idCliente, location);
|
||
|
||
if (!servicosResult.success) {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar serviços**\n\n` +
|
||
`⚠️ ${servicosResult.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (!servicosResult.servicos || servicosResult.servicos.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📋 **Nenhum serviço encontrado**\n\n` +
|
||
`👤 Cliente: ${nomeCliente}\n` +
|
||
`🆔 ID: ${idCliente}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Verificar se há serviços liberados
|
||
const servicosLiberados = servicosResult.servicos.filter(s =>
|
||
s.status === 'liberado' || s.statusNumerico === 1
|
||
);
|
||
|
||
if (servicosLiberados.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`🔒 **Nenhum serviço liberado**\n\n` +
|
||
`👤 Cliente: ${nomeCliente}\n` +
|
||
`🆔 ID: ${idCliente}\n` +
|
||
`📊 Todos os ${servicosResult.servicos.length} serviços já estão bloqueados.`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Criar menu de seleção de serviços
|
||
let message = `🔒 **Selecionar Serviços para Bloquear**\n\n`;
|
||
message += `👤 **Cliente**: ${nomeCliente}\n`;
|
||
message += `🆔 **ID**: ${idCliente}\n`;
|
||
message += `🌐 **Instância**: ${location}\n\n`;
|
||
message += `✅ **Serviços liberados** (${servicosLiberados.length}):\n\n`;
|
||
|
||
const keyboard = [];
|
||
|
||
servicosLiberados.forEach((servico, index) => {
|
||
message += `${index + 1}. **${servico.nome}**\n`;
|
||
message += ` 💰 Valor: R$ ${servico.valorMensal}\n`;
|
||
message += ` 🆔 ID: ${servico.id}\n\n`;
|
||
|
||
// Botão para bloquear este serviço específico
|
||
keyboard.push([{
|
||
text: `🔒 Bloquear ${servico.nome}`,
|
||
callback_data: `confirm_block_service_${servico.id}_${idCliente}_${location.replace(/\s+/g, '_')}`
|
||
}]);
|
||
});
|
||
|
||
// Botão para bloquear todos
|
||
if (servicosLiberados.length > 1) {
|
||
keyboard.push([{
|
||
text: `🔒 Bloquear TODOS os serviços (${servicosLiberados.length})`,
|
||
callback_data: `confirm_block_all_${idCliente}_${location.replace(/\s+/g, '_')}`
|
||
}]);
|
||
}
|
||
|
||
// Botão cancelar
|
||
keyboard.push([{
|
||
text: '❌ Cancelar',
|
||
callback_data: 'cancel_action'
|
||
}]);
|
||
|
||
await this.bot.sendMessage(chatId, message, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao preparar bloqueio:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao preparar bloqueio**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Liberar cliente
|
||
*/
|
||
async handleLiberarCliente(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId,
|
||
`🔓 **Liberar Cliente**\n\n` +
|
||
`💡 **Como usar:**\n` +
|
||
`• "liberar 123.456.789-10"\n` +
|
||
`• "liberar cliente João"\n` +
|
||
`• "liberar Guarai 123.456.789-10"`
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await this.bot.sendMessage(chatId, '🔍 Buscando cliente...');
|
||
|
||
// Detectar se especificou uma localização
|
||
let location = '';
|
||
let clienteQuery = target;
|
||
|
||
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
|
||
location = 'Guarai/Colmeia';
|
||
clienteQuery = target.replace(/(guarai|colmeia)/gi, '').trim();
|
||
} else if (target.toLowerCase().includes('pedro afonso')) {
|
||
location = 'Pedro Afonso';
|
||
clienteQuery = target.replace(/pedro afonso/gi, '').trim();
|
||
}
|
||
|
||
// Buscar cliente primeiro
|
||
let idCliente = null;
|
||
let nomeCliente = '';
|
||
|
||
if (/^\d{11}$/.test(clienteQuery) || clienteQuery.includes('.') || clienteQuery.includes('-') || isNaN(clienteQuery)) {
|
||
// É CPF ou nome
|
||
const busca = await this.topsapp.buscarCliente(clienteQuery, location);
|
||
if (busca.success && busca.clientes && busca.clientes.length > 0) {
|
||
idCliente = busca.clientes[0].id;
|
||
nomeCliente = busca.clientes[0].nome;
|
||
location = busca.instancia;
|
||
} else {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Cliente não encontrado**\n\n` +
|
||
`📝 CPF/Nome: "${clienteQuery}"`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
} else {
|
||
// É ID numérico
|
||
idCliente = clienteQuery;
|
||
}
|
||
|
||
// Buscar serviços do cliente para mostrar opções
|
||
const servicosResult = await this.topsapp.obterServicosCliente(idCliente, location);
|
||
|
||
if (!servicosResult.success) {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar serviços**\n\n` +
|
||
`⚠️ ${servicosResult.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (!servicosResult.servicos || servicosResult.servicos.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📋 **Nenhum serviço encontrado**\n\n` +
|
||
`👤 Cliente: ${nomeCliente}\n` +
|
||
`🆔 ID: ${idCliente}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Verificar se há serviços bloqueados
|
||
const servicosBloqueados = servicosResult.servicos.filter(s =>
|
||
s.status === 'bloqueado' || s.statusNumerico === 2
|
||
);
|
||
|
||
if (servicosBloqueados.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`✅ **Nenhum serviço bloqueado**\n\n` +
|
||
`👤 Cliente: ${nomeCliente}\n` +
|
||
`🆔 ID: ${idCliente}\n` +
|
||
`📊 Todos os ${servicosResult.servicos.length} serviços estão liberados.`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Criar menu de seleção de serviços
|
||
let message = `🔓 **Selecionar Serviços para Liberar**\n\n`;
|
||
message += `👤 **Cliente**: ${nomeCliente}\n`;
|
||
message += `🆔 **ID**: ${idCliente}\n`;
|
||
message += `🌐 **Instância**: ${location}\n\n`;
|
||
message += `🔒 **Serviços bloqueados** (${servicosBloqueados.length}):\n\n`;
|
||
|
||
const keyboard = [];
|
||
|
||
servicosBloqueados.forEach((servico, index) => {
|
||
message += `${index + 1}. **${servico.nome}**\n`;
|
||
message += ` 💰 Valor: R$ ${servico.valorMensal}\n`;
|
||
message += ` 🆔 ID: ${servico.id}\n\n`;
|
||
|
||
// Botão para liberar este serviço específico
|
||
keyboard.push([{
|
||
text: `🔓 Liberar ${servico.nome}`,
|
||
callback_data: `confirm_unblock_service_${servico.id}_${idCliente}_${location.replace(/\s+/g, '_')}`
|
||
}]);
|
||
});
|
||
|
||
// Botão para liberar todos
|
||
if (servicosBloqueados.length > 1) {
|
||
keyboard.push([{
|
||
text: `🔓 Liberar TODOS os serviços (${servicosBloqueados.length})`,
|
||
callback_data: `confirm_unblock_all_${idCliente}_${location.replace(/\s+/g, '_')}`
|
||
}]);
|
||
}
|
||
|
||
// Botão cancelar
|
||
keyboard.push([{
|
||
text: '❌ Cancelar',
|
||
callback_data: 'cancel_action'
|
||
}]);
|
||
|
||
await this.bot.sendMessage(chatId, message, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao preparar liberação:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao preparar liberação**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Utilitário para obter status da fatura
|
||
*/
|
||
getStatusFatura(status) {
|
||
// Se já é uma string formatada, retornar diretamente
|
||
if (typeof status === 'string') {
|
||
switch (status.toLowerCase()) {
|
||
case 'pago': return '✅ Pago';
|
||
case 'pendente': return '⏳ Pendente';
|
||
case 'em aberto': return '⏳ Pendente';
|
||
case 'vencida': return '❌ Vencida';
|
||
case 'processando': return '🔄 Em processamento';
|
||
default: return `📊 ${status}`;
|
||
}
|
||
}
|
||
|
||
// Números (legado)
|
||
switch (status) {
|
||
case 1: return '✅ Pago';
|
||
case 2: return '⏳ Pendente';
|
||
case 3: return '❌ Vencida';
|
||
case 4: return '🔄 Em processamento';
|
||
default: return '❓ Status desconhecido';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Callback para confirmar bloqueio de cliente
|
||
*/
|
||
async handleConfirmBlockCallback(callbackQuery, data) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
try {
|
||
// Extrair dados: confirm_block_ID_LOCATION
|
||
const parts = data.replace('confirm_block_', '').split('_');
|
||
const clienteId = parts[0];
|
||
const location = parts[1] ? parts[1].replace(/_/g, ' ') : '';
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Processando bloqueio...');
|
||
|
||
await this.bot.editMessageText(
|
||
`🔒 **Bloqueando cliente ID: ${clienteId}**\n\n⏳ Aguarde...`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
const resultado = await this.topsapp.bloquearCliente(clienteId, location);
|
||
|
||
if (!resultado.success) {
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro ao bloquear cliente**\n\n` +
|
||
`🆔 Cliente ID: ${clienteId}\n` +
|
||
`🌐 Instância: ${location}\n` +
|
||
`⚠️ Erro: ${resultado.error}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
return;
|
||
}
|
||
|
||
let message = `🔒 **Cliente bloqueado com sucesso!**\n\n`;
|
||
message += `🆔 Cliente ID: ${clienteId}\n`;
|
||
message += `🌐 Instância: ${resultado.instancia}\n`;
|
||
message += `📊 Serviços bloqueados: ${resultado.total}\n\n`;
|
||
|
||
if (resultado.servicosBloqueados && resultado.servicosBloqueados.length > 0) {
|
||
message += `📋 **Detalhes dos bloqueios:**\n`;
|
||
resultado.servicosBloqueados.forEach((servico, index) => {
|
||
message += `${index + 1}. ${servico.descricao}: ${servico.resultado.success ? '✅ Bloqueado' : '❌ Erro'}\n`;
|
||
});
|
||
}
|
||
|
||
await this.bot.editMessageText(message, {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao bloquear cliente:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro interno ao bloquear cliente**\n\n` +
|
||
`🆔 Cliente ID: ${clienteId}\n` +
|
||
`⚠️ ${error.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Callback para confirmar liberação de cliente
|
||
*/
|
||
async handleConfirmUnblockCallback(callbackQuery, data) {
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
try {
|
||
// Extrair dados: confirm_unblock_ID_LOCATION
|
||
const parts = data.replace('confirm_unblock_', '').split('_');
|
||
const clienteId = parts[0];
|
||
const location = parts[1] ? parts[1].replace(/_/g, ' ') : '';
|
||
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Carregando opções...');
|
||
|
||
// Usar a mesma lógica do comando NLP para mostrar opções de serviços
|
||
// Em vez de liberar tudo diretamente, mostrar menu de seleção
|
||
const servicosResult = await this.topsapp.obterServicosCliente(clienteId, location);
|
||
|
||
if (!servicosResult.success) {
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro ao buscar serviços**\n\n` +
|
||
`⚠️ ${servicosResult.error}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (!servicosResult.servicos || servicosResult.servicos.length === 0) {
|
||
await this.bot.editMessageText(
|
||
`📋 **Nenhum serviço encontrado**\n\n` +
|
||
`🆔 Cliente ID: ${clienteId}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Verificar se há serviços bloqueados
|
||
const servicosBloqueados = servicosResult.servicos.filter(s =>
|
||
s.status === 'bloqueado' || s.statusNumerico === 2
|
||
);
|
||
|
||
if (servicosBloqueados.length === 0) {
|
||
await this.bot.editMessageText(
|
||
`✅ **Nenhum serviço bloqueado**\n\n` +
|
||
`🆔 Cliente ID: ${clienteId}\n` +
|
||
`📊 Todos os ${servicosResult.servicos.length} serviços estão liberados.`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Criar menu de seleção de serviços
|
||
let message = `🔓 **Selecionar Serviços para Liberar**\n\n`;
|
||
message += `🆔 **Cliente ID**: ${clienteId}\n`;
|
||
message += `🌐 **Instância**: ${location}\n\n`;
|
||
message += `� **Serviços bloqueados** (${servicosBloqueados.length}):\n\n`;
|
||
|
||
const keyboard = [];
|
||
|
||
servicosBloqueados.forEach((servico, index) => {
|
||
message += `${index + 1}. **${servico.nome}**\n`;
|
||
message += ` 💰 Valor: R$ ${servico.valorMensal}\n`;
|
||
message += ` 🆔 ID: ${servico.id}\n\n`;
|
||
|
||
// Botão para liberar este serviço específico
|
||
keyboard.push([{
|
||
text: `🔓 Liberar ${servico.nome}`,
|
||
callback_data: `confirm_unblock_service_${servico.id}_${clienteId}_${location.replace(/\s+/g, '_')}`
|
||
}]);
|
||
});
|
||
|
||
// Botão para liberar todos
|
||
if (servicosBloqueados.length > 1) {
|
||
keyboard.push([{
|
||
text: `🔓 Liberar TODOS os serviços (${servicosBloqueados.length})`,
|
||
callback_data: `confirm_unblock_all_${clienteId}_${location.replace(/\s+/g, '_')}`
|
||
}]);
|
||
}
|
||
|
||
// Botão cancelar
|
||
keyboard.push([{
|
||
text: '❌ Cancelar',
|
||
callback_data: 'cancel_action'
|
||
}]);
|
||
|
||
await this.bot.editMessageText(message, {
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao preparar liberação:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro ao preparar liberação**\n\n` +
|
||
`🆔 Cliente ID: ${clienteId}\n` +
|
||
`⚠️ ${error.message}`,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Comando para listar serviços do cliente
|
||
*/
|
||
async handleListarServicos(chatId, target) {
|
||
logger.botCommand(chatId, 'listar_servicos', { target });
|
||
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📋 **Listar Serviços**\n\n` +
|
||
`💡 **Como usar:**\n` +
|
||
`• "listar serviços 123.456.789-10"\n` +
|
||
`• "ver serviços cliente123"\n` +
|
||
`• "mostrar serviços Guarai 123.456.789-10"`
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await this.bot.sendMessage(chatId, '📋 Buscando serviços...');
|
||
|
||
// Detectar se especificou uma localização
|
||
let location = '';
|
||
let clienteQuery = target;
|
||
|
||
logger.debug('Processando busca de serviços', {
|
||
originalTarget: target,
|
||
chatId
|
||
});
|
||
|
||
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
|
||
location = 'Guarai/Colmeia';
|
||
clienteQuery = target.replace(/(guarai|colmeia)/gi, '').trim();
|
||
} else if (target.toLowerCase().includes('pedro afonso')) {
|
||
location = 'Pedro Afonso';
|
||
clienteQuery = target.replace(/pedro afonso/gi, '').trim();
|
||
}
|
||
|
||
logger.debug('Detectada localização e query', {
|
||
location,
|
||
clienteQuery,
|
||
isNumeric: !isNaN(clienteQuery),
|
||
isCPF: /^\d{11}$/.test(clienteQuery)
|
||
});
|
||
|
||
// Buscar cliente primeiro
|
||
let idCliente = null;
|
||
let nomeCliente = '';
|
||
|
||
if (/^\d{11}$/.test(clienteQuery) || clienteQuery.includes('.') || clienteQuery.includes('-') || isNaN(clienteQuery)) {
|
||
// É CPF ou nome
|
||
logger.debug('Buscando por CPF/Nome', { clienteQuery });
|
||
const busca = await this.topsapp.buscarCliente(clienteQuery, location);
|
||
logger.debug('Resultado da busca de cliente', busca);
|
||
|
||
if (busca.success && busca.clientes && busca.clientes.length > 0) {
|
||
idCliente = busca.clientes[0].id;
|
||
nomeCliente = busca.clientes[0].nome;
|
||
location = busca.instancia;
|
||
logger.debug('Cliente encontrado', { idCliente, nomeCliente, location });
|
||
} else {
|
||
logger.warn('Cliente não encontrado', { clienteQuery, location });
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Cliente não encontrado**\n\n` +
|
||
`📝 CPF/Nome: "${clienteQuery}"`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
} else {
|
||
// É ID numérico
|
||
idCliente = clienteQuery;
|
||
logger.debug('Usando ID direto', { idCliente: clienteQuery });
|
||
}
|
||
|
||
logger.debug('Chamando obterServicosCliente', {
|
||
idCliente,
|
||
location,
|
||
tipoIdCliente: typeof idCliente
|
||
});
|
||
|
||
const resultado = await this.topsapp.obterServicosCliente(idCliente, location);
|
||
logger.topsappOperation('obterServicosCliente', idCliente, resultado);
|
||
|
||
if (!resultado.success) {
|
||
logger.error('Erro ao buscar serviços', resultado.error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar serviços**\n\n` +
|
||
`⚠️ ${resultado.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
return;
|
||
}
|
||
|
||
// Debug: verificar se houve problema na filtragem
|
||
if (resultado.debug && resultado.debug.totalRetornadoAPI > 100) {
|
||
await this.bot.sendMessage(chatId,
|
||
`⚠️ **DEBUG: Possível problema na API**\n\n` +
|
||
`🔍 Total retornado pela API: ${resultado.debug.totalRetornadoAPI}\n` +
|
||
`🎯 Total filtrado para cliente ${resultado.debug.clienteId}: ${resultado.debug.totalFiltrado}\n` +
|
||
`🌐 Instância: ${resultado.instancia}\n\n` +
|
||
`💡 Se este número ainda está alto, há problema na API do TopSapp.`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
|
||
if (!resultado.servicos || resultado.servicos.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📋 **Nenhum serviço encontrado**\n\n` +
|
||
`👤 Cliente ID: ${idCliente}\n` +
|
||
`🌐 Instância: ${resultado.instancia}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Criar mensagem com lista de serviços
|
||
let message = `📋 **Serviços do Cliente**\n\n`;
|
||
if (nomeCliente) {
|
||
message += `👤 **Cliente**: ${nomeCliente}\n`;
|
||
}
|
||
message += `🆔 **ID**: ${idCliente}\n`;
|
||
message += `📊 **Total**: ${resultado.total} serviço(s)\n`;
|
||
message += `🌐 **Instância**: ${resultado.instancia}\n\n`;
|
||
|
||
// Criar botões inline para cada serviço
|
||
const keyboard = [];
|
||
|
||
resultado.servicos.forEach((servico, index) => {
|
||
message += `🔧 **${index + 1}. ${servico.nome}**\n`;
|
||
message += `🆔 ID: ${servico.id}\n`;
|
||
message += `📊 Status: ${this.getStatusServico(servico.status)}\n`;
|
||
message += `💰 Valor: R$ ${servico.valorMensal}\n`;
|
||
|
||
if (servico.dataAtivacao) {
|
||
message += `📅 Ativado em: ${servico.dataAtivacao}\n`;
|
||
}
|
||
|
||
message += '\n';
|
||
|
||
// Adicionar botões de ação baseados no status
|
||
const row = [];
|
||
if (servico.status === 'liberado') {
|
||
row.push({
|
||
text: `🔒 Bloquear ${servico.nome}`,
|
||
callback_data: `block_service_${servico.id}_${idCliente}_${location.replace(/\s+/g, '_')}`
|
||
});
|
||
} else {
|
||
row.push({
|
||
text: `🔓 Liberar ${servico.nome}`,
|
||
callback_data: `unblock_service_${servico.id}_${idCliente}_${location.replace(/\s+/g, '_')}`
|
||
});
|
||
}
|
||
keyboard.push(row);
|
||
});
|
||
|
||
await this.bot.sendMessage(chatId, message, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao listar serviços:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro interno ao listar serviços**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Utilitário para obter status do serviço
|
||
*/
|
||
getStatusServico(status) {
|
||
if (typeof status === 'string') {
|
||
switch (status.toLowerCase()) {
|
||
case 'liberado': return '✅ Liberado';
|
||
case 'bloqueado': return '🔒 Bloqueado';
|
||
case 'desativado': return '❌ Desativado';
|
||
default: return `📊 ${status}`;
|
||
}
|
||
}
|
||
|
||
switch (status) {
|
||
case 1: return '✅ Liberado';
|
||
case 2: return '🔒 Bloqueado';
|
||
case 3: return '❌ Desativado';
|
||
default: return '❓ Status desconhecido';
|
||
}
|
||
}
|
||
|
||
async handleConfirmBlockServiceCallback(callbackQuery, data) {
|
||
try {
|
||
// Extrair dados: confirm_block_service_SERVICEID_CLIENTEID_LOCATION
|
||
const parts = data.replace('confirm_block_service_', '').split('_');
|
||
const serviceId = parts[0];
|
||
const idCliente = parts[1];
|
||
const location = parts.slice(2).join('_').replace(/_/g, ' ');
|
||
|
||
logger.debug('handleConfirmBlockServiceCallback', {
|
||
serviceId,
|
||
idCliente,
|
||
location,
|
||
originalData: data
|
||
});
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.editMessageText(
|
||
'⏳ Bloqueando serviço...',
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
}
|
||
);
|
||
|
||
const resultado = await this.topsapp.alterarStatusServico(serviceId, 'bloquear', location);
|
||
|
||
let texto;
|
||
if (resultado.success) {
|
||
texto = '✅ Serviço bloqueado com sucesso!';
|
||
} else {
|
||
texto = `❌ Erro ao bloquear serviço: ${resultado.error}`;
|
||
}
|
||
|
||
await this.bot.editMessageText(
|
||
texto,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
}
|
||
);
|
||
|
||
} catch (error) {
|
||
logger.botError(callbackQuery.message.chat.id, error, 'handleConfirmBlockServiceCallback');
|
||
console.error('Erro no handleConfirmBlockServiceCallback:', error);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro interno do servidor');
|
||
}
|
||
}
|
||
|
||
async handleConfirmUnblockServiceCallback(callbackQuery, data) {
|
||
try {
|
||
// Extrair dados: confirm_unblock_service_SERVICEID_CLIENTEID_LOCATION
|
||
const parts = data.replace('confirm_unblock_service_', '').split('_');
|
||
const serviceId = parts[0];
|
||
const idCliente = parts[1];
|
||
const location = parts.slice(2).join('_').replace(/_/g, ' ');
|
||
|
||
logger.debug('handleConfirmUnblockServiceCallback', {
|
||
serviceId,
|
||
idCliente,
|
||
location,
|
||
originalData: data
|
||
});
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.editMessageText(
|
||
'⏳ Liberando serviço...',
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
}
|
||
);
|
||
|
||
const resultado = await this.topsapp.alterarStatusServico(serviceId, 'liberar', location);
|
||
|
||
let texto;
|
||
if (resultado.success) {
|
||
texto = '✅ Serviço liberado com sucesso!';
|
||
} else {
|
||
texto = `❌ Erro ao liberar serviço: ${resultado.error}`;
|
||
}
|
||
|
||
await this.bot.editMessageText(
|
||
texto,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
}
|
||
);
|
||
|
||
} catch (error) {
|
||
console.error('Erro no handleConfirmUnblockServiceCallback:', error);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro interno do servidor');
|
||
}
|
||
}
|
||
|
||
async handleConfirmBlockAllCallback(callbackQuery, data) {
|
||
try {
|
||
const clienteId = data.replace('confirm_block_all_', '');
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.editMessageText(
|
||
'⏳ Bloqueando todos os serviços...',
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
}
|
||
);
|
||
|
||
const resultado = await this.topsapp.bloquearCliente(clienteId);
|
||
|
||
let texto;
|
||
if (resultado.sucesso) {
|
||
texto = '✅ Todos os serviços foram bloqueados com sucesso!';
|
||
} else {
|
||
texto = `❌ Erro ao bloquear serviços: ${resultado.erro}`;
|
||
}
|
||
|
||
await this.bot.editMessageText(
|
||
texto,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
}
|
||
);
|
||
|
||
} catch (error) {
|
||
console.error('Erro no handleConfirmBlockAllCallback:', error);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro interno do servidor');
|
||
}
|
||
}
|
||
|
||
async handleConfirmUnblockAllCallback(callbackQuery, data) {
|
||
try {
|
||
const clienteId = data.replace('confirm_unblock_all_', '');
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
await this.bot.editMessageText(
|
||
'⏳ Liberando todos os serviços...',
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
}
|
||
);
|
||
|
||
const resultado = await this.topsapp.liberarCliente(clienteId);
|
||
|
||
let texto;
|
||
if (resultado.sucesso) {
|
||
texto = '✅ Todos os serviços foram liberados com sucesso!';
|
||
} else {
|
||
texto = `❌ Erro ao liberar serviços: ${resultado.erro}`;
|
||
}
|
||
|
||
await this.bot.editMessageText(
|
||
texto,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id
|
||
}
|
||
);
|
||
|
||
} catch (error) {
|
||
console.error('Erro no handleConfirmUnblockAllCallback:', error);
|
||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro interno do servidor');
|
||
}
|
||
}
|
||
|
||
async handleBlockServiceSelection(callbackQuery, data) {
|
||
try {
|
||
// Extrair dados: block_service_ID_CLIENTE_LOCATION
|
||
const parts = data.replace('block_service_', '').split('_');
|
||
const serviceId = parts[0];
|
||
const clienteId = parts[1];
|
||
const location = parts.slice(2).join('_').replace(/_/g, ' ');
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
// Criar mensagem de confirmação
|
||
const texto = `🔸 **Confirmar Bloqueio de Serviço**\n\n` +
|
||
`🆔 **ID do Serviço:** ${serviceId}\n` +
|
||
`👤 **Cliente:** ${clienteId}\n` +
|
||
`📍 **Localização:** ${location}\n\n` +
|
||
`⚠️ Tem certeza que deseja bloquear este serviço?`;
|
||
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✅ Sim, bloquear', callback_data: `confirm_block_service_${serviceId}_${clienteId}_${location.replace(/\s+/g, '_')}` },
|
||
{ text: '❌ Cancelar', callback_data: 'cancel' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.editMessageText(
|
||
texto,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
reply_markup: keyboard,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao selecionar serviço para bloqueio:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro interno ao selecionar serviço**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{
|
||
chat_id: callbackQuery.message.chat.id,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
async handleUnblockServiceSelection(callbackQuery, data) {
|
||
try {
|
||
// Extrair dados: unblock_service_ID_CLIENTE_LOCATION
|
||
const parts = data.replace('unblock_service_', '').split('_');
|
||
const serviceId = parts[0];
|
||
const clienteId = parts[1];
|
||
const location = parts.slice(2).join('_').replace(/_/g, ' ');
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
|
||
// Criar mensagem de confirmação
|
||
const texto = `🔸 **Confirmar Liberação de Serviço**\n\n` +
|
||
`🆔 **ID do Serviço:** ${serviceId}\n` +
|
||
`👤 **Cliente:** ${clienteId}\n` +
|
||
`📍 **Localização:** ${location}\n\n` +
|
||
`✅ Tem certeza que deseja liberar este serviço?`;
|
||
|
||
const keyboard = {
|
||
inline_keyboard: [
|
||
[
|
||
{ text: '✅ Sim, liberar', callback_data: `confirm_unblock_service_${serviceId}_${clienteId}_${location.replace(/\s+/g, '_')}` },
|
||
{ text: '❌ Cancelar', callback_data: 'cancel' }
|
||
]
|
||
]
|
||
};
|
||
|
||
await this.bot.editMessageText(
|
||
texto,
|
||
{
|
||
chat_id: chatId,
|
||
message_id: callbackQuery.message.message_id,
|
||
reply_markup: keyboard,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao selecionar serviço para liberação:', error);
|
||
await this.bot.editMessageText(
|
||
`❌ **Erro interno ao selecionar serviço**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{
|
||
chat_id: callbackQuery.message.chat.id,
|
||
message_id: callbackQuery.message.message_id,
|
||
parse_mode: 'Markdown'
|
||
}
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Visualizar logs recentes
|
||
*/
|
||
async handleViewLogs(chatId) {
|
||
const userId = chatId;
|
||
|
||
if (!this.isAuthorized(userId)) {
|
||
await this.bot.sendMessage(chatId, '🚫 Acesso negado.');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const recentLogs = logger.getRecentLogs(50);
|
||
|
||
if (recentLogs.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📋 **Logs do Sistema**\n\n` +
|
||
`ℹ️ Nenhum log encontrado ou modo debug desabilitado.`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Dividir logs em mensagens menores (Telegram tem limite de caracteres)
|
||
const maxLength = 4000;
|
||
let currentMessage = `📋 **Logs Recentes (${recentLogs.length} linhas)**\n\n\`\`\`\n`;
|
||
|
||
for (const line of recentLogs) {
|
||
const newLine = line + '\n';
|
||
|
||
if ((currentMessage + newLine + '```').length > maxLength) {
|
||
// Enviar mensagem atual e começar nova
|
||
currentMessage += '```';
|
||
await this.bot.sendMessage(chatId, currentMessage, { parse_mode: 'Markdown' });
|
||
currentMessage = '```\n' + newLine;
|
||
} else {
|
||
currentMessage += newLine;
|
||
}
|
||
}
|
||
|
||
// Enviar último bloco
|
||
if (currentMessage.length > 10) {
|
||
currentMessage += '```';
|
||
await this.bot.sendMessage(chatId, currentMessage, { parse_mode: 'Markdown' });
|
||
}
|
||
|
||
} catch (error) {
|
||
logger.botError(userId, error, 'handleViewLogs');
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao visualizar logs**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Limpar logs do sistema
|
||
*/
|
||
async handleClearLogs(chatId) {
|
||
const userId = chatId;
|
||
|
||
if (!this.isAuthorized(userId)) {
|
||
await this.bot.sendMessage(chatId, '🚫 Acesso negado.');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
logger.clearLogs();
|
||
logger.info('Logs limpos pelo usuário administrativo', { userId });
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`🧹 **Logs Limpos**\n\n` +
|
||
`✅ Todos os logs foram removidos com sucesso.`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
|
||
} catch (error) {
|
||
logger.botError(userId, error, 'handleClearLogs');
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao limpar logs**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Callback para mostrar dados cadastrais do cliente
|
||
*/
|
||
async handleDadosClienteCallback(callbackQuery, data) {
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
|
||
const parts = data.split('_');
|
||
const idCliente = parts[2];
|
||
const location = parts[3] || '';
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
await this.handleDadosCliente(chatId, idCliente, location);
|
||
}
|
||
|
||
/**
|
||
* Callback para mostrar faturas do cliente
|
||
*/
|
||
async handleFaturasClienteCallback(callbackQuery, data) {
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
|
||
const parts = data.split('_');
|
||
const idCliente = parts[2];
|
||
const location = parts[3] || '';
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
await this.handleVerFaturasById(chatId, idCliente, location);
|
||
}
|
||
|
||
/**
|
||
* Callback para mostrar serviços do cliente
|
||
*/
|
||
async handleServicosClienteCallback(callbackQuery, data) {
|
||
await this.bot.answerCallbackQuery(callbackQuery.id);
|
||
|
||
const parts = data.split('_');
|
||
const idCliente = parts[2];
|
||
const location = parts[3] || '';
|
||
|
||
const chatId = callbackQuery.message.chat.id;
|
||
await this.handleListarServicos(chatId, idCliente);
|
||
}
|
||
|
||
/**
|
||
* Ver faturas do cliente por ID com organização por serviço
|
||
*/
|
||
async handleVerFaturasById(chatId, idCliente, location = '') {
|
||
try {
|
||
await this.bot.sendMessage(chatId, '📄 Buscando faturas detalhadas...');
|
||
|
||
const resultado = await this.topsapp.obterFaturasDetalhadas(idCliente, location);
|
||
|
||
if (!resultado.success) {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar faturas**\n\n` +
|
||
`⚠️ ${resultado.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (!resultado.faturasPorServico || resultado.faturasPorServico.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📄 **Nenhuma fatura encontrada**\n\n` +
|
||
`👤 Cliente ID: ${idCliente}\n` +
|
||
`🌐 Instância: ${resultado.instancia || location}\n\n` +
|
||
`✅ O cliente está em dia com os pagamentos!`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Cabeçalho principal
|
||
let headerMessage = `📄 **FATURAS EM ABERTO POR SERVIÇO**\n\n`;
|
||
headerMessage += `👤 **Cliente ID**: ${idCliente}\n`;
|
||
headerMessage += `📊 **Total de serviços**: ${resultado.totalServicos}\n`;
|
||
headerMessage += `💳 **Total de faturas**: ${resultado.totalFaturas}\n`;
|
||
headerMessage += `🌐 **Instância**: ${resultado.instancia || location}\n\n`;
|
||
|
||
// Enviar cabeçalho
|
||
await this.bot.sendMessage(chatId, headerMessage, { parse_mode: 'Markdown' });
|
||
|
||
// Processar cada serviço separadamente
|
||
for (let i = 0; i < resultado.faturasPorServico.length; i++) {
|
||
const servicoData = resultado.faturasPorServico[i];
|
||
const servico = servicoData.servico;
|
||
const faturas = servicoData.faturas;
|
||
|
||
// Informações do serviço
|
||
let servicoMessage = `🔧 **SERVIÇO ${i + 1}: ${servico.nome}**\n`;
|
||
servicoMessage += `🏷️ Base: ${servico.base}\n`;
|
||
servicoMessage += `⚙️ Tecnologia: ${servico.tecnologia}\n`;
|
||
|
||
if (servico.valor_mensal && servico.valor_mensal > 0) {
|
||
servicoMessage += `💰 Valor mensal: R$ ${parseFloat(servico.valor_mensal).toFixed(2)}\n`;
|
||
}
|
||
|
||
if (servico.vencimento_dia !== 'Variável' && servico.vencimento_dia !== 'Não definido') {
|
||
servicoMessage += `📅 Vencimento: Todo dia ${servico.vencimento_dia}\n`;
|
||
}
|
||
|
||
servicoMessage += `📊 Status do serviço: ${servico.status}\n\n`;
|
||
|
||
// Enviar informações do serviço
|
||
await this.bot.sendMessage(chatId, servicoMessage, { parse_mode: 'Markdown' });
|
||
|
||
// Dividir faturas em grupos menores para evitar overflow
|
||
const faturasPorMensagem = 3; // Máximo 3 faturas por mensagem
|
||
for (let j = 0; j < faturas.length; j += faturasPorMensagem) {
|
||
const faturasGrupo = faturas.slice(j, j + faturasPorMensagem);
|
||
let faturaMessage = '';
|
||
|
||
faturasGrupo.forEach((fatura, index) => {
|
||
const valor = parseFloat(fatura.valor || 0);
|
||
const faturaIndex = j + index + 1;
|
||
|
||
// Destacar a data de vencimento
|
||
const dataVencimento = this.formatarData(fatura.vencimento);
|
||
const isVencida = new Date(fatura.vencimento) < new Date();
|
||
const statusVencimento = isVencida ? '🔴 VENCIDA' : '🟡 EM ABERTO';
|
||
|
||
faturaMessage += `📄 **Fatura ${faturaIndex}**\n`;
|
||
faturaMessage += `🆔 ID: \`${fatura.id}\`\n`;
|
||
faturaMessage += `💰 **Valor: R$ ${valor.toFixed(2)}**\n`;
|
||
faturaMessage += `⏰ **VENCIMENTO: ${dataVencimento} ${statusVencimento}**\n`;
|
||
|
||
if (fatura.periodo) {
|
||
faturaMessage += `📅 Período: ${fatura.periodo}\n`;
|
||
}
|
||
|
||
if (fatura.descricao) {
|
||
faturaMessage += `📝 Descrição: ${fatura.descricao}\n`;
|
||
}
|
||
|
||
faturaMessage += `📊 Status: ${this.getStatusFatura(fatura.status)}\n`;
|
||
|
||
// Linha digitável
|
||
if (fatura.linhaDigitavel) {
|
||
faturaMessage += `\n📋 **Linha Digitável:**\n\`${fatura.linhaDigitavel}\`\n`;
|
||
}
|
||
|
||
// PIX Copia e Cola
|
||
if (fatura.pixCopiaCola) {
|
||
faturaMessage += `\n💲 **PIX Copia e Cola:**\n\`${fatura.pixCopiaCola}\`\n`;
|
||
}
|
||
|
||
faturaMessage += `\n`;
|
||
});
|
||
|
||
// Enviar grupo de faturas
|
||
await this.bot.sendMessage(chatId, faturaMessage, { parse_mode: 'Markdown' });
|
||
}
|
||
}
|
||
|
||
// Enviar botões de ação na mensagem final
|
||
const keyboard = [
|
||
[
|
||
{ text: '📋 Dados Cadastrais', callback_data: `dados_cliente_${idCliente}_${location}` },
|
||
{ text: '⚙️ Ver Serviços', callback_data: `servicos_cliente_${idCliente}_${location}` }
|
||
]
|
||
];
|
||
|
||
if (resultado.faturasPorServico.length > 0 && resultado.faturasPorServico[0].faturas.length > 0) {
|
||
const primeiraFatura = resultado.faturasPorServico[0].faturas[0];
|
||
keyboard.push([
|
||
{ text: '📄 Gerar Boleto PDF', callback_data: `boleto_pdf_${primeiraFatura.id}_${location}` }
|
||
]);
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, '🔧 **Ações disponíveis:**', {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao buscar faturas detalhadas:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar faturas**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
for (let i = 0; i < resultado.faturasPorServico.length; i++) {
|
||
const servicoData = resultado.faturasPorServico[i];
|
||
const servico = servicoData.servico;
|
||
const faturas = servicoData.faturas;
|
||
|
||
message += `🔧 **SERVIÇO ${i + 1}: ${servico.nome}**\n`;
|
||
message += `🏷️ Base: ${servico.base}\n`;
|
||
message += `⚙️ Tecnologia: ${servico.tecnologia}\n`;
|
||
|
||
if (servico.valor_mensal && servico.valor_mensal > 0) {
|
||
message += `💰 Valor mensal: R$ ${parseFloat(servico.valor_mensal).toFixed(2)}\n`;
|
||
}
|
||
|
||
if (servico.vencimento_dia !== 'Variável' && servico.vencimento_dia !== 'Não definido') {
|
||
message += `📅 Vencimento: Todo dia ${servico.vencimento_dia}\n`;
|
||
}
|
||
|
||
message += `📊 Status do serviço: ${servico.status}\n\n`;
|
||
|
||
let valorTotalServico = 0;
|
||
|
||
// Processar faturas do serviço
|
||
faturas.forEach((fatura, index) => {
|
||
const valor = parseFloat(fatura.valor || 0);
|
||
valorTotalServico += valor;
|
||
valorTotalGeral += valor;
|
||
|
||
// Destacar a data de vencimento
|
||
const dataVencimento = this.formatarData(fatura.vencimento);
|
||
const isVencida = new Date(fatura.vencimento) < new Date();
|
||
const statusVencimento = isVencida ? '🔴 VENCIDA' : '🟡 EM ABERTO';
|
||
|
||
message += `� **Fatura ${index + 1}**\n`;
|
||
message += `🆔 ID: \`${fatura.id}\`\n`;
|
||
message += `💰 **Valor: R$ ${valor.toFixed(2)}**\n`;
|
||
message += `⏰ **VENCIMENTO: ${dataVencimento} ${statusVencimento}**\n`;
|
||
|
||
if (fatura.periodo) {
|
||
message += `📅 Período: ${fatura.periodo}\n`;
|
||
}
|
||
|
||
if (fatura.descricao) {
|
||
message += `📝 Descrição: ${fatura.descricao}\n`;
|
||
}
|
||
|
||
message += `📊 Status: ${this.getStatusFatura(fatura.status)}\n`;
|
||
|
||
// Linha digitável
|
||
if (fatura.linhaDigitavel) {
|
||
message += `\n📋 **Linha Digitável:**\n\`${fatura.linhaDigitavel}\`\n`;
|
||
}
|
||
|
||
// PIX Copia e Cola
|
||
if (fatura.pixCopiaCola) {
|
||
message += `\n💲 **PIX Copia e Cola:**\n\`${fatura.pixCopiaCola}\`\n`;
|
||
}
|
||
|
||
message += `\n`;
|
||
});
|
||
|
||
message += `💰 **Subtotal do serviço: R$ ${valorTotalServico.toFixed(2)}**\n`;
|
||
message += `${'-'.repeat(30)}\n\n`;
|
||
}
|
||
|
||
message += `💰 **TOTAL GERAL EM ABERTO: R$ ${valorTotalGeral.toFixed(2)}**\n\n`;
|
||
|
||
// Botões de ação
|
||
const keyboard = [
|
||
[
|
||
{ text: '📋 Dados Cadastrais', callback_data: `dados_cliente_${idCliente}_${location}` },
|
||
{ text: '⚙️ Ver Serviços', callback_data: `servicos_cliente_${idCliente}_${location}` }
|
||
]
|
||
];
|
||
|
||
// Adicionar botão para gerar PDF da primeira fatura
|
||
if (resultado.faturasPorServico.length > 0 && resultado.faturasPorServico[0].faturas.length > 0) {
|
||
const primeiraFatura = resultado.faturasPorServico[0].faturas[0];
|
||
keyboard.push([
|
||
{ text: '📄 Gerar Boleto PDF', callback_data: `boleto_pdf_${primeiraFatura.id}_${location}` }
|
||
]);
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao buscar faturas detalhadas:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar faturas**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Buscar e mostrar dados cadastrais do cliente
|
||
*/
|
||
async handleDadosClientePorBusca(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📋 **Dados Cadastrais**\n\n` +
|
||
`💡 **Como usar:**\n` +
|
||
`• "dados cliente João da Silva"\n` +
|
||
`• "dados cadastrais 123.456.789-10"\n` +
|
||
`• "dados cliente 12345" (ID do cliente)\n` +
|
||
`• "dados cliente Guarai João" (específica instância)`
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
// Primeiro, buscar o cliente
|
||
let location = '';
|
||
let query = target;
|
||
|
||
if (target.toLowerCase().includes('guarai') || target.toLowerCase().includes('colmeia')) {
|
||
location = 'Guarai/Colmeia';
|
||
query = target.replace(/(guarai|colmeia)/gi, '').trim();
|
||
} else if (target.toLowerCase().includes('pedro afonso')) {
|
||
location = 'Pedro Afonso';
|
||
query = target.replace(/pedro afonso/gi, '').trim();
|
||
}
|
||
|
||
const busca = await this.topsapp.buscarCliente(query, location);
|
||
|
||
if (!busca.success) {
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro na busca**\n\n` +
|
||
`⚠️ ${busca.error}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
if (!busca.clientes || busca.clientes.length === 0) {
|
||
await this.bot.sendMessage(chatId,
|
||
`🔍 **Nenhum cliente encontrado**\n\n` +
|
||
`📝 Termo buscado: "${query}"\n` +
|
||
`🌐 Instância: ${busca.instancia || 'Todas'}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Se encontrou mais de um, mostrar lista
|
||
if (busca.clientes.length > 1) {
|
||
let message = `📋 **${busca.clientes.length} clientes encontrados**\n\n`;
|
||
message += `🌐 **Instância**: ${busca.instancia}\n\n`;
|
||
message += `💡 **Selecione um cliente para ver os dados cadastrais:**\n\n`;
|
||
|
||
const keyboard = [];
|
||
|
||
busca.clientes.slice(0, 10).forEach((cliente, index) => {
|
||
message += `👤 **${index + 1}. ${cliente.nome}**\n`;
|
||
message += `🆔 ID: \`${cliente.id}\`\n`;
|
||
if (cliente.cpf) {
|
||
message += `📄 CPF: \`${cliente.cpf}\`\n`;
|
||
}
|
||
message += `📊 Status: ${cliente.status === 1 ? '✅ Ativo' : '❌ Inativo'}\n\n`;
|
||
|
||
keyboard.push([
|
||
{ text: `📋 Ver Dados ${index + 1}`, callback_data: `dados_cliente_${cliente.id}_${location}` }
|
||
]);
|
||
});
|
||
|
||
await this.bot.sendMessage(chatId, message, {
|
||
parse_mode: 'Markdown',
|
||
reply_markup: {
|
||
inline_keyboard: keyboard
|
||
}
|
||
});
|
||
return;
|
||
}
|
||
|
||
// Se encontrou apenas um, mostrar dados diretamente
|
||
const cliente = busca.clientes[0];
|
||
await this.handleDadosCliente(chatId, cliente.id, location || busca.instancia);
|
||
|
||
} catch (error) {
|
||
console.error('❌ Erro ao buscar dados do cliente:', error);
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao buscar dados do cliente**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Formatardata para DD/MM/YYYY
|
||
*/
|
||
formatarData(data) {
|
||
if (!data) return 'Data não informada';
|
||
|
||
// Se já está no formato DD/MM/YYYY, retornar como está
|
||
if (data.match(/^\d{2}\/\d{2}\/\d{4}$/)) {
|
||
return data;
|
||
}
|
||
|
||
// Se está no formato YYYY-MM-DD, converter
|
||
if (data.match(/^\d{4}-\d{2}-\d{2}$/)) {
|
||
const [ano, mes, dia] = data.split('-');
|
||
return `${dia}/${mes}/${ano}`;
|
||
}
|
||
|
||
// Tentar converter outros formatos
|
||
try {
|
||
const dataObj = new Date(data);
|
||
if (!isNaN(dataObj.getTime())) {
|
||
const dia = String(dataObj.getDate()).padStart(2, '0');
|
||
const mes = String(dataObj.getMonth() + 1).padStart(2, '0');
|
||
const ano = dataObj.getFullYear();
|
||
return `${dia}/${mes}/${ano}`;
|
||
}
|
||
} catch (error) {
|
||
console.warn('Erro ao formatar data:', data, error);
|
||
}
|
||
|
||
// Se não conseguiu formatar, retornar original
|
||
return data;
|
||
}
|
||
|
||
/**
|
||
* Verificar status de ONU Fiberhome
|
||
*/
|
||
async handleStatusONU(chatId, target) {
|
||
if (!target) {
|
||
await this.bot.sendMessage(chatId,
|
||
`📡 **Status ONU Fiberhome**\n\n` +
|
||
`💡 **Como usar:**\n` +
|
||
`• "status onu FHTT12345678"\n` +
|
||
`• "verificar onu FHTT12345678"\n` +
|
||
`• "onu status FHTT12345678"\n\n` +
|
||
`📝 **Nota:** Informe o serial da ONU (12 caracteres)`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
try {
|
||
await this.bot.sendMessage(chatId, '📡 Conectando à OLT Fiberhome...');
|
||
|
||
logger.botCommand(chatId, 'status_onu', { target });
|
||
|
||
// Verificar se é serial ou device name
|
||
let resultado;
|
||
if (target.length === 12 && /^[A-Z0-9]+$/.test(target)) {
|
||
// É um serial
|
||
resultado = await this.fiberhome.obterStatusONU(target);
|
||
} else {
|
||
// Pode ser device name
|
||
resultado = await this.fiberhome.obterStatusONUPorNome(target);
|
||
}
|
||
|
||
if (!resultado.success) {
|
||
// Escapar caracteres especiais para evitar problemas no Telegram
|
||
const errorMsg = resultado.error ? resultado.error.replace(/[_*\[\]()~`>#+=|{}.!-]/g, '\\$&') : 'Erro desconhecido';
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao obter status da ONU**\n\n` +
|
||
`🔍 **Busca:** \`${target}\`\n` +
|
||
`⚠️ **Erro:** ${errorMsg}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
return;
|
||
}
|
||
|
||
// Formatar informações da ONU
|
||
let message = `📡 **Status ONU Fiberhome**\n\n`;
|
||
message += `🆔 **Serial:** ${resultado.serial}\n`;
|
||
message += `📋 **Device Name:** ${resultado.deviceName}\n`;
|
||
message += `📍 **Posição:** Slot ${resultado.slot}, PON ${resultado.pon}, ONU ${resultado.onuId}\n`;
|
||
message += `🔌 **Status:** ${resultado.online ? '🟢 Online' : '🔴 Offline'}\n\n`;
|
||
|
||
// Informações de sinal
|
||
message += `📶 **Informações de Sinal:**\n`;
|
||
message += `📡 **RX Power:** ${resultado.rxPower}\n`;
|
||
message += `📤 **TX Power:** ${resultado.txPower}\n`;
|
||
message += `📏 **Distância:** ${resultado.distance}\n\n`;
|
||
|
||
// Status das portas Ethernet
|
||
if (resultado.portasEthernet.length > 0) {
|
||
message += `🔗 **Portas Ethernet:**\n`;
|
||
resultado.portasEthernet.forEach(porta => {
|
||
const statusIcon = porta.status === 'up' ? '🟢' : '🔴';
|
||
message += ` ${statusIcon} **Porta ${porta.porta}:** ${porta.status}\n`;
|
||
});
|
||
message += '\n';
|
||
}
|
||
|
||
// Serviços WAN
|
||
if (resultado.servicosWAN.length > 0) {
|
||
message += `🌐 **Serviços WAN:**\n`;
|
||
resultado.servicosWAN.forEach(servico => {
|
||
const statusIcon = servico.status === 'active' ? '🟢' : '🔴';
|
||
message += ` ${statusIcon} **Serviço ${servico.id}:** ${servico.status}\n`;
|
||
if (servico.ip !== 'N/A') {
|
||
message += ` 📍 **IP:** ${servico.ip}\n`;
|
||
}
|
||
});
|
||
} else {
|
||
message += `🌐 **Serviços WAN:** Nenhum configurado\n`;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
|
||
} catch (error) {
|
||
logger.botError(chatId, error, 'handleStatusONU');
|
||
|
||
// Escapar caracteres especiais para evitar problemas no Telegram
|
||
const errorMsg = error.message ? error.message.replace(/[_*\[\]()~`>#+=|{}.!-]/g, '\\$&') : 'Erro desconhecido';
|
||
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao verificar status da ONU**\n\n` +
|
||
`⚠️ ${errorMsg}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Verificar status das conexões Fiberhome
|
||
*/
|
||
async handleFiberhomeStatus(chatId) {
|
||
try {
|
||
await this.bot.sendMessage(chatId, '🔌 Diagnosticando conexões Fiberhome...');
|
||
|
||
logger.botCommand(chatId, 'fiberhome_status');
|
||
|
||
// Fazer diagnóstico completo
|
||
const diagnostico = await this.fiberhome.diagnosticarConectividade();
|
||
|
||
let message = `🔌 **Diagnóstico Fiberhome**\n\n`;
|
||
|
||
// Status OLT
|
||
message += `📡 **OLT (${diagnostico.olt.host}:${diagnostico.olt.port}):**\n`;
|
||
message += ` 🌐 **Conectividade:** ${diagnostico.olt.conectividade ? '🟢 OK' : '🔴 Falhou'}\n`;
|
||
message += ` � **Telnet:** ${diagnostico.olt.telnet ? '🟢 Conectado' : '🔴 Falhou'}\n`;
|
||
if (diagnostico.olt.erro) {
|
||
message += ` ⚠️ **Erro:** ${diagnostico.olt.erro}\n`;
|
||
}
|
||
message += '\n';
|
||
|
||
// Status UNM2000
|
||
message += `�️ **UNM2000 (${diagnostico.unm2000.host}:${diagnostico.unm2000.port}):**\n`;
|
||
message += ` 🌐 **Conectividade:** ${diagnostico.unm2000.conectividade ? '🟢 OK' : '🔴 Falhou'}\n`;
|
||
message += ` � **TL1:** ${diagnostico.unm2000.tl1 ? '🟢 Conectado' : '🔴 Falhou'}\n`;
|
||
if (diagnostico.unm2000.erro) {
|
||
message += ` ⚠️ **Erro:** ${diagnostico.unm2000.erro}\n`;
|
||
}
|
||
message += '\n';
|
||
|
||
// Configurações
|
||
message += `⚙️ **Configurações:**\n`;
|
||
message += ` 📡 **OLT:** GEPON/GEPON\n`;
|
||
message += ` 🖥️ **UNM2000:** 1/1\n\n`;
|
||
|
||
// Comandos disponíveis
|
||
message += `💡 **Comandos disponíveis:**\n`;
|
||
message += `• \`status onu FHTT12345678\` - Status de ONU específica\n`;
|
||
message += `• \`verificar onu FHTT12345678\` - Verificar ONU\n`;
|
||
message += `• \`onu status DeviceName\` - Status por nome do dispositivo\n\n`;
|
||
|
||
// Status geral
|
||
const oltOk = diagnostico.olt.conectividade && diagnostico.olt.telnet;
|
||
const unm2000Ok = diagnostico.unm2000.conectividade && diagnostico.unm2000.tl1;
|
||
|
||
if (oltOk && unm2000Ok) {
|
||
message += `✅ **Status:** Sistema funcionando normalmente`;
|
||
} else if (oltOk || unm2000Ok) {
|
||
message += `⚠️ **Status:** Funcionamento parcial`;
|
||
} else {
|
||
message += `❌ **Status:** Sistema indisponível`;
|
||
}
|
||
|
||
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||
|
||
} catch (error) {
|
||
logger.botError(chatId, error, 'handleFiberhomeStatus');
|
||
await this.bot.sendMessage(chatId,
|
||
`❌ **Erro ao diagnosticar Fiberhome**\n\n` +
|
||
`⚠️ ${error.message}`,
|
||
{ parse_mode: 'Markdown' }
|
||
);
|
||
}
|
||
}
|
||
}
|
||
|
||
module.exports = BotHandler;
|