From 6717f5d7f2199a46eee5f2e4dc90b6d1dc381844 Mon Sep 17 00:00:00 2001 From: Rodrigo Bertoldo de Sousa Martins Date: Thu, 2 Apr 2026 23:36:53 -0300 Subject: [PATCH] genieacs: sync with topsapp parameters Signed-off-by: Rodrigo Bertoldo de Sousa Martins --- src/bot/handler.js | 212 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 203 insertions(+), 9 deletions(-) diff --git a/src/bot/handler.js b/src/bot/handler.js index 8a932d2..2e1884b 100644 --- a/src/bot/handler.js +++ b/src/bot/handler.js @@ -2033,6 +2033,36 @@ Digite /help para ver todos os comandos disponíveis! } else if (data.startsWith('router_cfg_')) { console.log(`🔍 Condição router_cfg_ atendida`); await this.handleRouterCfgCallback(callbackQuery, data); + } else if (data.startsWith('cfg_roteador_cli_')) { + console.log(`🔍 Condição cfg_roteador_cli_ atendida`); + await this.bot.answerCallbackQuery(callbackQuery.id); + const parts = data.replace('cfg_roteador_cli_', '').split('_'); + const idCliente = parts[0]; + const location = parts.slice(1).join('_'); + await this._configurarRoteadorSelecionarServico(chatId, userId, idCliente, location); + } else if (data.startsWith('cfg_roteador_srv_')) { + console.log(`🔍 Condição cfg_roteador_srv_ atendida`); + await this.bot.answerCallbackQuery(callbackQuery.id); + // formato: cfg_roteador_srv___ + const rest = data.replace('cfg_roteador_srv_', ''); + const parts = rest.split('_'); + const idCliente = parts[0]; + const idServico = parts[1]; + const location = parts.slice(2).join('_'); + // Recarregar o serviço para ter o objeto completo com pppoeLogin + const servicosResult = await this.topsapp.obterServicosCliente(idCliente, location); + if (!servicosResult.success) { + await this.bot.sendMessage(chatId, `❌ Erro ao buscar serviço: ${servicosResult.error}`); + } else { + const servico = (servicosResult.servicos || []).find(s => + String(s.id_servico || s.id) === String(idServico) + ); + if (!servico) { + await this.bot.sendMessage(chatId, `❌ Serviço #${idServico} não encontrado.`); + } else { + await this._configurarRoteadorPorServico(chatId, userId, servico, location); + } + } } else if (data.startsWith('diag_cliente_')) { console.log(`🔍 Condição diag_cliente_ atendida`); await this.handleDiagClienteCallback(callbackQuery, data); @@ -7520,36 +7550,201 @@ Digite /help para ver todos os comandos disponíveis! } /** - * Comando "configurar roteador ". - * Busca o dispositivo e exibe o menu de configurações com inline keyboard. + * Comando "configurar roteador ". + * + * Fluxo: + * 1. Se o termo parece serial/tag GenieACS (alphanumérico sem espaços) → busca direto no GenieACS. + * 2. Caso contrário, busca no TopSapp por nome/CPF: + * a. Seleciona o cliente (se houver múltiplos) + * b. Seleciona o serviço com login PPPoE + * c. Usa o login PPPoE como TAG para buscar no GenieACS + * d. Se não encontrar TAG no GenieACS → informa que não é possível configurar */ async handleConfigurarRoteador(chatId, userId, termo) { if (!termo) { await this.bot.sendMessage(chatId, '⚙️ *Configurar Roteador*\n\n' + - 'Informe o serial ou a TAG (login TopSapp) do dispositivo.\n' + + 'Informe o serial, TAG, nome do cliente ou CPF.\n' + 'Exemplos:\n' + '• `configurar roteador ABCD12345678`\n' + - '• `configurar roteador joao.silva`', + '• `configurar roteador joao.silva`\n' + + '• `configurar roteador João da Silva`\n' + + '• `configurar roteador 123.456.789-10`', { parse_mode: 'Markdown' } ); return; } - await this.bot.sendMessage(chatId, `🔍 Buscando dispositivo \`${termo}\` no GenieACS...`, { parse_mode: 'Markdown' }); + // CPF sem formatação: 11 dígitos numéricos → formata e encaminha para TopSapp + if (/^\d{11}$/.test(termo)) { + const cpfFormatado = `${termo.slice(0,3)}.${termo.slice(3,6)}.${termo.slice(6,9)}-${termo.slice(9,11)}`; + return this._configurarRoteadorBuscarTopSapp(chatId, userId, cpfFormatado); + } + // Heurística: serial/tag GenieACS não tem espaço e não é CPF formatado + const pareceGenieACS = !/\s/.test(termo) && !/^\d{3}\.\d{3}\.\d{3}-\d{2}$/.test(termo); + + if (pareceGenieACS) { + // Caminho direto: buscar no GenieACS por serial ou TAG + await this._configurarRoteadorPorGenieACS(chatId, userId, termo); + } else { + // Caminho via TopSapp: buscar cliente por nome/CPF + await this._configurarRoteadorBuscarTopSapp(chatId, userId, termo); + } + } + + /** + * Busca o dispositivo diretamente no GenieACS e abre o menu de configuração. + */ + async _configurarRoteadorPorGenieACS(chatId, userId, termo) { + await this.bot.sendMessage(chatId, `🔍 Buscando dispositivo \`${termo}\` no GenieACS...`, { parse_mode: 'Markdown' }); try { const resultado = await this.genieacs.buscarRoteador(termo); + if (!resultado.success) { + await this.bot.sendMessage(chatId, + `❌ *Dispositivo não encontrado no GenieACS*\n\n` + + `🔍 Busca: \`${termo}\`\n` + + `⚠️ ${resultado.error || 'Nenhum resultado'}\n\n` + + `_Tente buscar pelo nome ou CPF do cliente._`, + { parse_mode: 'Markdown' } + ); + return; + } + this.userSessions.set(userId, { + action: 'router_cfg', + deviceId: resultado.device.deviceId, + device: resultado.device, + instance: resultado.instance || '', + timestamp: Date.now() + }); + await this._enviarMenuConfigurarRoteador(chatId, resultado.device, resultado.instance || ''); + } catch (error) { + logger.error('Erro em _configurarRoteadorPorGenieACS:', error); + await this.bot.sendMessage(chatId, `❌ Erro ao consultar o GenieACS: ${error.message}`); + } + } + + /** + * Busca o cliente no TopSapp por nome/CPF e apresenta seleção. + */ + async _configurarRoteadorBuscarTopSapp(chatId, userId, query) { + await this.bot.sendMessage(chatId, `🔍 Buscando cliente "${query}" no TopSapp...`); + try { + const resultado = await this.topsapp.buscarCliente(query); + if (!resultado.success) { + await this.bot.sendMessage(chatId, `❌ Erro na busca: ${resultado.error}`); + return; + } + if (!resultado.clientes || resultado.clientes.length === 0) { + await this.bot.sendMessage(chatId, `🔍 Nenhum cliente encontrado para: "${query}"`); + return; + } + + const instancia = resultado.instancia || ''; + + if (resultado.clientes.length === 1) { + await this._configurarRoteadorSelecionarServico(chatId, userId, resultado.clientes[0].id, instancia); + return; + } + + // Múltiplos clientes → seleção + let msg = `🔍 *${resultado.clientes.length} clientes encontrados:*\n\n`; + const keyboard = []; + resultado.clientes.slice(0, 8).forEach((c, i) => { + msg += `*${i + 1}.* ${c.nome}`; + if (c.cpf) msg += ` — \`${c.cpf}\``; + msg += '\n'; + keyboard.push([{ + text: `⚙️ ${c.nome.substring(0, 35)}`, + callback_data: `cfg_roteador_cli_${c.id}_${instancia}` + }]); + }); + + await this.bot.sendMessage(chatId, msg, { + parse_mode: 'Markdown', + reply_markup: { inline_keyboard: keyboard } + }); + } catch (error) { + logger.error('Erro em _configurarRoteadorBuscarTopSapp:', error); + await this.bot.sendMessage(chatId, `❌ Erro: ${error.message}`); + } + } + + /** + * Busca os serviços do cliente e apresenta seleção (ou vai direto se só há 1). + */ + async _configurarRoteadorSelecionarServico(chatId, userId, idCliente, location) { + const servicosResult = await this.topsapp.obterServicosCliente(idCliente, location); + if (!servicosResult.success) { + await this.bot.sendMessage(chatId, `❌ Erro ao buscar serviços: ${servicosResult.error}`); + return; + } + + const servicos = (servicosResult.servicos || []).filter(s => { + const st = s.id_status || s.statusNumerico; + return st === 1 || st === '1' || + String(s.status).toLowerCase() === 'liberado' || + String(s.status).toLowerCase() === 'ativo'; + }); + + if (servicos.length === 0) { + await this.bot.sendMessage(chatId, `⚠️ Cliente sem serviços ativos.`); + return; + } + + if (servicos.length === 1) { + await this._configurarRoteadorPorServico(chatId, userId, servicos[0], location); + return; + } + + let msg = `⚙️ *Selecione o serviço:*\n\n`; + const keyboard = []; + servicos.forEach((s, i) => { + const nome = s.descricao || s.nome || `Serviço ${i + 1}`; + const login = s.usuario || s.pppoe_login || s.login || ''; + msg += `*${i + 1}.* ${nome}${login ? ` — \`${login}\`` : ''}\n`; + keyboard.push([{ + text: `⚙️ ${nome.substring(0, 35)}`, + callback_data: `cfg_roteador_srv_${idCliente}_${s.id_servico || s.id}_${location}` + }]); + }); + + await this.bot.sendMessage(chatId, msg, { + parse_mode: 'Markdown', + reply_markup: { inline_keyboard: keyboard } + }); + } + + /** + * A partir de um serviço TopSapp, extrai o login PPPoE, busca a TAG no GenieACS e abre o menu. + */ + async _configurarRoteadorPorServico(chatId, userId, servico, location) { + const pppoeLogin = servico.usuario || servico.pppoe_login || servico.login || null; + + if (!pppoeLogin) { + await this.bot.sendMessage(chatId, + `⚠️ O serviço selecionado não possui login PPPoE cadastrado.\n` + + `Não é possível localizar o roteador no GenieACS sem esse dado.` + ); + return; + } + + await this.bot.sendMessage(chatId, `🔍 Localizando roteador pela TAG \`${pppoeLogin}\` no GenieACS...`, { parse_mode: 'Markdown' }); + + try { + const resultado = await this.genieacs.buscarRoteador(pppoeLogin, location); if (!resultado.success) { await this.bot.sendMessage(chatId, - `❌ *Dispositivo não encontrado*\n\n🔍 Busca: \`${termo}\`\n⚠️ ${resultado.error || 'Nenhum resultado'}`, + `⚠️ *Roteador não encontrado no GenieACS*\n\n` + + `🏷️ TAG pesquisada: \`${pppoeLogin}\`\n\n` + + `Não é possível realizar alterações no roteador deste cliente pelo bot.\n` + + `_O dispositivo pode não estar cadastrado no GenieACS ou a TAG ainda não foi sincronizada._`, { parse_mode: 'Markdown' } ); return; } - // Salva contexto na sessão para os callbacks seguintes this.userSessions.set(userId, { action: 'router_cfg', deviceId: resultado.device.deviceId, @@ -7559,9 +7754,8 @@ Digite /help para ver todos os comandos disponíveis! }); await this._enviarMenuConfigurarRoteador(chatId, resultado.device, resultado.instance || ''); - } catch (error) { - logger.error('Erro em handleConfigurarRoteador:', error); + logger.error('Erro em _configurarRoteadorPorServico:', error); await this.bot.sendMessage(chatId, `❌ Erro ao consultar o GenieACS: ${error.message}`); } }