diff --git a/src/bot/handler.js b/src/bot/handler.js index 08e3ad9..fc53054 100644 --- a/src/bot/handler.js +++ b/src/bot/handler.js @@ -9032,116 +9032,141 @@ Digite /help para ver todos os comandos disponíveis! return; } - const aviso = result.modoFallback - ? '\n⚠️ _IP não encontrado nos registros (sessão encerrada). Mostrando sessões ativas nesse horário._\n' - : ''; + if (result.modoFallback) { + await this.bot.sendMessage(chatId, + `⚠️ _IP não armazenado para sessões encerradas. Mostrando sessões ativas às ${horaStr}._`, + { parse_mode: 'Markdown' } + ); + } + const titulo = `Sessão em ${dataStr}${horaStr ? ' ' + horaStr : ''}`; - await this._exibirAcessosCgnat(chatId, session.privateIP, result.dados, titulo + aviso); + await this._exibirAcessosCgnat(chatId, session.privateIP, result.dados, titulo); } /** - * Consulta conexões ATIVAS agora para o IP privado CGNAT - * Usa ObterClientesServicos com conexao: "online" e filtra por IP + * Consulta conexões ATIVAS agora para o IP privado CGNAT, + * identifica o cliente e exibe seus dados cadastrais. */ async handleCgnatConsultarAtivas(chatId, privateIP) { await this.bot.sendMessage(chatId, - `🔍 Consultando conexões ativas para \`${privateIP}\`...`, + `🔍 Consultando conexão ativa para \`${privateIP}\`...`, { parse_mode: 'Markdown' } ); const result = await this.topsapp.buscarConexaoAtivaPorIp(privateIP); if (!result.success) { - await this.bot.sendMessage(chatId, - `❌ Erro ao consultar TopSapp: ${result.error}`, - { parse_mode: 'Markdown' } - ); + await this.bot.sendMessage(chatId, `❌ Erro ao consultar TopSapp: ${result.error}`, { parse_mode: 'Markdown' }); return; } if (result.total === 0) { const extra = result.totalGeral > 0 - ? `\n\n_(${result.totalGeral} conexões online, nenhuma com IP \`${privateIP}\`)_` - : `\n\n_(nenhuma conexão online no momento)_`; + ? `_(${result.totalGeral} sessões ativas, nenhuma com IP \`${privateIP}\`)_` + : `_(nenhuma sessão ativa no momento)_`; await this.bot.sendMessage(chatId, - `ℹ️ Nenhuma conexão ativa encontrada para o IP \`${privateIP}\`.${extra}`, + `ℹ️ Nenhuma conexão ativa encontrada para \`${privateIP}\`.\n${extra}`, { parse_mode: 'Markdown' } ); return; } - await this._exibirConexoesAtivasCgnat(chatId, privateIP, result.dados); + const sessao = result.dados[0]; + await this._exibirClienteCgnat(chatId, sessao, privateIP); } /** - * Exibe histórico de acessos CGNAT (ObterClientesServicosAcessos) + * Identifica o cliente a partir de um registro de sessão CGNAT e exibe seus dados. + */ + async _exibirClienteCgnat(chatId, sessao, privateIP) { + const { id_cliente, usuario, inicio, termino, nas_ip } = sessao; + + const inicioFmt = inicio ? inicio.replace(/-\d{2}$/, '').replace('T', ' ') : '—'; + const terminoFmt = termino ? termino.replace(/-\d{2}$/, '').replace('T', ' ') : 'ativo'; + + // Se não tem id_cliente válido, mostra só o que temos + if (!id_cliente || id_cliente < 0) { + await this.bot.sendMessage(chatId, + `🌐 *Sessão CGNAT — \`${privateIP}\`*\n\n` + + `👤 Login: \`${usuario || '—'}\`\n` + + `🕐 ${inicioFmt} → ${terminoFmt}\n` + + `⚠️ _Cliente não identificado (registro sem ID)_`, + { parse_mode: 'Markdown' } + ); + return; + } + + await this.bot.sendMessage(chatId, `🔍 Buscando dados do cliente (ID ${id_cliente})...`, { parse_mode: 'Markdown' }); + + const dadosResult = await this.topsapp.obterDadosCadastrais(id_cliente); + + if (!dadosResult.success || !dadosResult.cliente) { + // Fallback: mostra só os dados da sessão + await this.bot.sendMessage(chatId, + `🌐 *Sessão CGNAT — \`${privateIP}\`*\n\n` + + `👤 Login: \`${usuario || '—'}\`\n` + + `🕐 ${inicioFmt} → ${terminoFmt}\n` + + `❌ Erro ao buscar dados do cliente: ${dadosResult.error || 'desconhecido'}`, + { parse_mode: 'Markdown' } + ); + return; + } + + const c = dadosResult.cliente; + const servAtivo = (dadosResult.servicos || []).find(s => s.login === usuario) || (dadosResult.servicos || [])[0]; + + let msg = `🌐 *Cliente identificado via CGNAT*\n`; + msg += `📡 IP Privado: \`${privateIP}\`\n\n`; + + msg += `👤 *${c.nome || '—'}*\n`; + if (c.cpf_cnpj) msg += `🪪 CPF/CNPJ: \`${c.cpf_cnpj}\`\n`; + if (c.telefone || c.celular) msg += `📞 Tel: ${c.telefone || c.celular}\n`; + if (c.email) msg += `📧 ${c.email}\n`; + + msg += `\n🔌 *Serviço:*\n`; + msg += ` Login: \`${usuario}\`\n`; + msg += ` 🕐 Sessão: ${inicioFmt} → ${terminoFmt}\n`; + if (servAtivo) { + if (servAtivo.planoNome) msg += ` 📦 Plano: ${servAtivo.planoNome}\n`; + if (servAtivo.statusFormatado) msg += ` 🔄 Status: ${servAtivo.statusFormatado}\n`; + } + + await this.bot.sendMessage(chatId, msg, { parse_mode: 'Markdown' }); + + // Botões de ação + const keyboard = { + inline_keyboard: [[ + { text: '📋 Diagnóstico completo', callback_data: `diag_cliente_${id_cliente}_guarai_colmeia` }, + { text: '❌ Fechar', callback_data: 'cancel_action' } + ]] + }; + await this.bot.sendMessage(chatId, '💡 Deseja ver o diagnóstico completo do cliente?', { reply_markup: keyboard }); + } + + /** + * Exibe sessões CGNAT do histórico e busca dados do cliente se identificado */ async _exibirAcessosCgnat(chatId, privateIP, acessos, titulo) { - let msg = `🌐 *${titulo} — \`${privateIP}\`*\n\n`; + // Se há apenas uma sessão com id_cliente válido, vai direto para o cliente + const comCliente = acessos.filter(a => a.id_cliente && a.id_cliente > 0); + if (comCliente.length === 1) { + await this._exibirClienteCgnat(chatId, comCliente[0], privateIP); + return; + } - for (const a of acessos.slice(0, 10)) { - const inicio = a.inicio ? a.inicio.replace(/\.\d+.*$/, '').replace('T', ' ') : '—'; - const termino = a.termino ? a.termino.replace(/\.\d+.*$/, '').replace('T', ' ') : 'ativo'; - msg += `👤 *${a.usuario || '—'}*\n`; + // Múltiplas sessões — lista para o usuário escolher + let msg = `🌐 *${titulo}*\n\`${privateIP}\`\n\n`; + for (const a of acessos.slice(0, 8)) { + const inicio = a.inicio ? a.inicio.replace(/-\d{2}$/, '').replace('T', ' ') : '—'; + const termino = a.termino ? a.termino.replace(/-\d{2}$/, '').replace('T', ' ') : 'ativo'; + msg += `👤 *${a.usuario || '—'}* (ID cliente: ${a.id_cliente || '?'})\n`; msg += ` 🕐 ${inicio} → ${termino}\n`; - if (a.ip) msg += ` 🖥️ IP: \`${a.ip}\`\n`; - if (a.estacao) msg += ` 📡 Estação: ${a.estacao}\n`; + if (a.ip) msg += ` 🖥️ \`${a.ip}\`\n`; msg += '\n'; } - - if (acessos.length > 10) { - msg += `_... e mais ${acessos.length - 10} registro(s)._\n`; - } + if (acessos.length > 8) msg += `_... e mais ${acessos.length - 8} registro(s)._\n`; await this.bot.sendMessage(chatId, msg, { parse_mode: 'Markdown' }); - - const logins = [...new Set(acessos.slice(0, 10).map(a => a.usuario).filter(Boolean))]; - if (logins.length === 1) { - const keyboard = { - inline_keyboard: [[ - { text: `🔍 Ver dados de ${logins[0]}`, callback_data: `buscar_cgnat_user_${logins[0]}` }, - { text: '❌ Fechar', callback_data: 'cancel_action' } - ]] - }; - await this.bot.sendMessage(chatId, '💡 Deseja ver os dados cadastrais do cliente?', { - reply_markup: keyboard - }); - } - } - - /** - * Exibe conexões ativas CGNAT (ObterClientesServicos com conexao: online) - */ - async _exibirConexoesAtivasCgnat(chatId, privateIP, servicos) { - let msg = `🟢 *Conexões ativas — \`${privateIP}\`*\n\n`; - - for (const s of servicos.slice(0, 10)) { - msg += `👤 *${s.usuario || '—'}*\n`; - if (s.nome_cliente || s.cliente) msg += ` 🏷️ Cliente: ${s.nome_cliente || s.cliente}\n`; - msg += ` 🖥️ IP: \`${s.ip || '—'}\`\n`; - if (s.descricao) msg += ` 📦 Plano: ${s.descricao}\n`; - if (s.status) msg += ` 🔄 Status: ${s.status}\n`; - msg += '\n'; - } - - if (servicos.length > 10) { - msg += `_... e mais ${servicos.length - 10} registro(s)._\n`; - } - - await this.bot.sendMessage(chatId, msg, { parse_mode: 'Markdown' }); - - const logins = [...new Set(servicos.slice(0, 10).map(s => s.usuario).filter(Boolean))]; - if (logins.length === 1) { - const keyboard = { - inline_keyboard: [[ - { text: `🔍 Ver dados de ${logins[0]}`, callback_data: `buscar_cgnat_user_${logins[0]}` }, - { text: '❌ Fechar', callback_data: 'cancel_action' } - ]] - }; - await this.bot.sendMessage(chatId, '💡 Deseja ver os dados cadastrais do cliente?', { - reply_markup: keyboard - }); - } } /**