diff --git a/src/bot/handler.js b/src/bot/handler.js index 39667f4..de9560f 100644 --- a/src/bot/handler.js +++ b/src/bot/handler.js @@ -1159,8 +1159,7 @@ Digite /help para ver todos os comandos disponíveis! case 'adicionar_onu_fiberhome_step3': // Recebeu confirmação de VLAN customizada - const vlanInput = text.trim(); - + const vlanInput = text.trim(); if (vlanInput && !isNaN(vlanInput)) { const vlan = parseInt(vlanInput); if (vlan >= 1 && vlan <= 4094) { @@ -1177,7 +1176,11 @@ Digite /help para ver todos os comandos disponíveis! this.userSessions.delete(userId); // Executar adição da ONU - await this.executarAdicaoOnuFiberhome(chatId, session); + await this.executarAdicaoOnuFiberhome(chatId, session, userId); + return; + + case 'topsapp_onu_aguardando_nome': + await this.topsappOnuBuscarCliente(chatId, userId, text.trim(), session.onuData); return; } } @@ -1211,7 +1214,7 @@ Digite /help para ver todos os comandos disponíveis! /** * Executar adição da ONU Fiberhome */ - async executarAdicaoOnuFiberhome(chatId, session) { + async executarAdicaoOnuFiberhome(chatId, session, userId = null) { try { const { serial, usuario, vlan, onuType } = session; @@ -1254,6 +1257,33 @@ Digite /help para ver todos os comandos disponíveis! `⚡ A ONU foi reiniciada e estará disponível em alguns instantes.`, { parse_mode: 'Markdown' } ); + + // Convidar para registrar no TopSapp + if (userId) { + this.userSessions.set(userId, { + action: 'topsapp_onu_pre_busca', + onuData: { + tipo: 'fiberhome', + location: 'guarai_colmeia', + oltHost: resultado.details.olt, + serial, + portaAlias: `${resultado.details.slot}-${resultado.details.ponPort}` + } + }); + await this.bot.sendMessage(chatId, + `📋 *Registrar no TopSapp?*\n\nDeseja vincular esta ONU a um cliente no sistema TopSapp?`, + { + parse_mode: 'Markdown', + reply_markup: { + inline_keyboard: [[ + { text: '✅ Sim, vincular', callback_data: 'topsapp_onu_sim' }, + { text: '❌ Não', callback_data: 'cancel_action' } + ]] + } + } + ); + } + } else { await this.bot.sendMessage(chatId, `❌ *Erro ao adicionar ONU Fiberhome*\n\n` + @@ -1439,6 +1469,9 @@ Digite /help para ver todos os comandos disponíveis! } else if (data.startsWith('remove_readd_')) { console.log(`🔍 Chamando handleRemoveAndReAddCallback`); await this.handleRemoveAndReAddCallback(callbackQuery, data); + } else if (data.startsWith('topsapp_onu_')) { + console.log(`🔍 Condição topsapp_onu_ atendida`); + await this.handleTopSappOnuCallback(callbackQuery, data); } else if (data.startsWith('add_onu_vlan_')) { console.log(`🔍 Chamando handleAddOnuVlanCallback`); await this.handleAddOnuVlanCallback(callbackQuery, data); @@ -3180,7 +3213,7 @@ Digite /help para ver todos os comandos disponíveis! this.userSessions.delete(userId); // Executar adição da ONU - await this.executarAdicaoOnuFiberhome(chatId, session); + await this.executarAdicaoOnuFiberhome(chatId, session, userId); } else if (data === 'fh_vlan_custom') { // Pedir VLAN customizada - manter sessão no step3 para receber input do usuário @@ -3201,6 +3234,7 @@ Digite /help para ver todos os comandos disponíveis! */ async handleConfirmAddCallback(callbackQuery, data) { const chatId = callbackQuery.message.chat.id; + const userId = callbackQuery.from.id; console.log(`🔍 handleConfirmAddCallback chamado com data: ${data}`); // Parse do formato: confirm_add_olt_dito_1-1-3_0_603_DACM915E0F76 @@ -3284,6 +3318,33 @@ Digite /help para ver todos os comandos disponíveis! parse_mode: 'Markdown' } ); + + // Convidar para registrar no TopSapp + const tsLocation = oltId.includes('pedro_afonso') ? 'pedro_afonso' : 'guarai_colmeia'; + const oltEquipment = this.ssh.equipamentos.get(oltId); + this.userSessions.set(userId, { + action: 'topsapp_onu_pre_busca', + onuData: { + tipo: 'datacom', + location: tsLocation, + oltHost: oltEquipment ? oltEquipment.host : '', + serial: serialNumber, + portaAlias: slot + } + }); + await this.bot.sendMessage(chatId, + `📋 *Registrar no TopSapp?*\n\nDeseja vincular esta ONU a um cliente no sistema TopSapp?`, + { + parse_mode: 'Markdown', + reply_markup: { + inline_keyboard: [[ + { text: '✅ Sim, vincular', callback_data: 'topsapp_onu_sim' }, + { text: '❌ Não', callback_data: 'cancel_action' } + ]] + } + } + ); + } else { await this.bot.editMessageText( `❌ **Erro na Adição**\n\n` + @@ -5855,6 +5916,320 @@ Digite /help para ver todos os comandos disponíveis! // Limpar sessão this.suporteSessions.delete(sessionId); } + + // ───────────────────────────────────────────────────────────────────────── + // TopSapp — Vinculação de ONU após adição + // ───────────────────────────────────────────────────────────────────────── + + /** + * Roteador de callbacks topsapp_onu_* + */ + async handleTopSappOnuCallback(callbackQuery, data) { + const chatId = callbackQuery.message.chat.id; + const userId = callbackQuery.from.id; + + await this.bot.answerCallbackQuery(callbackQuery.id); + + const session = this.userSessions.get(userId); + + if (data === 'topsapp_onu_sim') { + if (!session || !session.onuData) { + await this.bot.sendMessage(chatId, '❌ Sessão expirada. Tente novamente após adicionar a ONU.'); + return; + } + session.action = 'topsapp_onu_aguardando_nome'; + this.userSessions.set(userId, session); + await this.bot.sendMessage(chatId, + `🔍 *Buscar Cliente no TopSapp*\n\nDigite o nome ou CPF do cliente:`, + { parse_mode: 'Markdown' } + ); + return; + } + + if (data.startsWith('topsapp_onu_cli_')) { + const idCliente = data.replace('topsapp_onu_cli_', ''); + if (!session || !session.onuData) { + await this.bot.sendMessage(chatId, '❌ Sessão expirada. Tente novamente.'); + return; + } + await this.topsappOnuMostrarServicos(chatId, userId, idCliente, session.onuData); + return; + } + + if (data.startsWith('topsapp_onu_svc_')) { + // formato: topsapp_onu_svc__ + const parts = data.replace('topsapp_onu_svc_', '').split('_'); + const idServico = parts[0]; + const idCliente = parts[1]; + if (!session || !session.onuData) { + await this.bot.sendMessage(chatId, '❌ Sessão expirada. Tente novamente.'); + return; + } + await this.topsappOnuConfirmarVinculo(chatId, userId, idServico, idCliente, session.onuData); + return; + } + + if (data === 'topsapp_onu_ok') { + if (!session || !session.ftthPayload) { + await this.bot.sendMessage(chatId, '❌ Sessão expirada. Tente novamente.'); + return; + } + await this.topsappOnuExecutarVinculo(chatId, userId, session); + return; + } + + await this.bot.sendMessage(chatId, '❓ Ação desconhecida.'); + } + + /** + * Busca cliente no TopSapp e exibe lista para seleção + */ + async topsappOnuBuscarCliente(chatId, userId, query, onuData) { + try { + await this.bot.sendMessage(chatId, '🔍 Buscando cliente...'); + + const resultado = await this.topsapp.buscarCliente(query, onuData.location); + + if (!resultado.success) { + await this.bot.sendMessage(chatId, + `❌ *Erro na busca*\n\n${resultado.error}`, + { parse_mode: 'Markdown' } + ); + this.userSessions.delete(userId); + return; + } + + if (!resultado.clientes || resultado.clientes.length === 0) { + await this.bot.sendMessage(chatId, + `🔍 *Nenhum cliente encontrado*\n\nTermo: "${query}"\n\nDigite outro nome ou CPF:`, + { + parse_mode: 'Markdown', + reply_markup: { inline_keyboard: [[{ text: '❌ Cancelar', callback_data: 'cancel_action' }]] } + } + ); + // Mantém sessão ativa para nova tentativa + return; + } + + const keyboard = []; + let msg = `👥 *${resultado.clientes.length > 1 ? resultado.clientes.length + ' clientes encontrados' : 'Cliente encontrado'}*\n\nSelecione o cliente:\n\n`; + + resultado.clientes.slice(0, 8).forEach((cliente, i) => { + msg += `${i + 1}. *${cliente.nome}* (ID: ${cliente.id})\n`; + keyboard.push([{ text: `${i + 1}. ${cliente.nome}`, callback_data: `topsapp_onu_cli_${cliente.id}` }]); + }); + + keyboard.push([{ text: '❌ Cancelar', callback_data: 'cancel_action' }]); + + await this.bot.sendMessage(chatId, msg, { + parse_mode: 'Markdown', + reply_markup: { inline_keyboard: keyboard } + }); + + } catch (error) { + console.error('❌ Erro ao buscar cliente TopSapp:', error); + await this.bot.sendMessage(chatId, `❌ Erro ao buscar cliente: ${error.message}`); + this.userSessions.delete(userId); + } + } + + /** + * Lista serviços ativos do cliente para seleção + */ + async topsappOnuMostrarServicos(chatId, userId, idCliente, onuData) { + try { + await this.bot.sendMessage(chatId, '📋 Buscando serviços do cliente...'); + + const servicosResult = await this.topsapp.obterServicosCliente(idCliente, onuData.location); + + if (!servicosResult.success) { + await this.bot.sendMessage(chatId, `❌ Erro ao buscar serviços: ${servicosResult.error}`); + this.userSessions.delete(userId); + return; + } + + const servicos = servicosResult.servicos || []; + const servicosAtivos = servicos.filter(s => + s.id_status === 1 || (s.status || '').toLowerCase() === 'liberado' + ); + + if (servicosAtivos.length === 0) { + await this.bot.sendMessage(chatId, + `⚠️ *Nenhum serviço ativo encontrado* para o cliente ID ${idCliente}.\n\nCancele e verifique o cliente.`, + { + parse_mode: 'Markdown', + reply_markup: { inline_keyboard: [[{ text: '❌ Cancelar', callback_data: 'cancel_action' }]] } + } + ); + return; + } + + const keyboard = []; + let msg = `📋 *Serviços ativos do cliente*\n\nSelecione o serviço FTTH:\n\n`; + + servicosAtivos.slice(0, 8).forEach((servico, i) => { + const idSvc = servico.id_servico || servico.id; + const nome = servico.descricao || servico.nome || 'Serviço'; + const login = servico.usuario ? ` (${servico.usuario})` : ''; + msg += `${i + 1}. *${nome}*${login} — ID: ${idSvc}\n`; + keyboard.push([{ text: `${i + 1}. ${nome}${login}`, callback_data: `topsapp_onu_svc_${idSvc}_${idCliente}` }]); + }); + + keyboard.push([{ text: '❌ Cancelar', callback_data: 'cancel_action' }]); + + await this.bot.sendMessage(chatId, msg, { + parse_mode: 'Markdown', + reply_markup: { inline_keyboard: keyboard } + }); + + } catch (error) { + console.error('❌ Erro ao listar serviços TopSapp:', error); + await this.bot.sendMessage(chatId, `❌ Erro: ${error.message}`); + this.userSessions.delete(userId); + } + } + + /** + * Faz matching OLT/porta/perfil e mostra tela de confirmação + */ + async topsappOnuConfirmarVinculo(chatId, userId, idServico, idCliente, onuData) { + try { + await this.bot.sendMessage(chatId, '🔌 Buscando dados da OLT no TopSapp...'); + + const oltsResult = await this.topsapp.obterOlts(onuData.location); + + if (!oltsResult.success) { + await this.bot.sendMessage(chatId, `❌ Erro ao buscar OLTs: ${oltsResult.error}`); + this.userSessions.delete(userId); + return; + } + + const olts = oltsResult.data?.dados?.dados || oltsResult.data?.dados || []; + + // Encontrar OLT pelo SSID (IP de gerência) + let oltEncontrada = olts.find(o => o.ssid === onuData.oltHost); + if (!oltEncontrada && olts.length > 0) { + oltEncontrada = olts[0]; + console.log(`⚠️ OLT não encontrada por SSID "${onuData.oltHost}", usando a primeira: ${oltEncontrada.nome}`); + } + + if (!oltEncontrada) { + await this.bot.sendMessage(chatId, `❌ Nenhuma OLT encontrada no TopSapp para este servidor.`); + this.userSessions.delete(userId); + return; + } + + // Encontrar porta pelo alias + const portas = oltEncontrada.portas || []; + let portaEncontrada = portas.find(p => p.alias === onuData.portaAlias); + if (!portaEncontrada && portas.length > 0) { + portaEncontrada = portas[0]; + console.log(`⚠️ Porta não encontrada por alias "${onuData.portaAlias}", usando a primeira: ${portaEncontrada.alias}`); + } + + if (!portaEncontrada) { + await this.bot.sendMessage(chatId, `❌ Nenhuma porta encontrada na OLT "${oltEncontrada.nome}".`); + this.userSessions.delete(userId); + return; + } + + // Encontrar perfil por tipo de ONU + const perfis = oltEncontrada.perfis || []; + let perfilEncontrado; + if (onuData.tipo === 'datacom') { + perfilEncontrado = perfis.find(p => p.identificacao && p.identificacao.includes('DATACOM ONU_BRIDGE_')); + } else { + perfilEncontrado = perfis.find(p => p.identificacao === 'ONU-BRIDGE-AN5506-02-B'); + } + if (!perfilEncontrado && perfis.length > 0) { + perfilEncontrado = perfis[0]; + console.log(`⚠️ Perfil não encontrado por tipo, usando o primeiro: ${perfilEncontrado.identificacao}`); + } + + if (!perfilEncontrado) { + await this.bot.sendMessage(chatId, `❌ Nenhum perfil encontrado na OLT "${oltEncontrada.nome}".`); + this.userSessions.delete(userId); + return; + } + + const ftthData = { + serial: onuData.serial, + idAP: oltEncontrada.id, + idPorta: portaEncontrada.id, + idPerfil: perfilEncontrado.id + }; + + // Salvar payload de confirmação na sessão + const session = this.userSessions.get(userId); + session.action = 'topsapp_onu_confirmando'; + session.ftthPayload = { + idCliente, + idServico, + ftthData, + location: onuData.location + }; + this.userSessions.set(userId, session); + + await this.bot.sendMessage(chatId, + `🔌 *Confirmar Vinculação no TopSapp*\n\n` + + `📱 *Serial:* \`${onuData.serial}\`\n` + + `🏢 *OLT:* ${oltEncontrada.nome}\n` + + `📡 *Porta:* ${portaEncontrada.alias}\n` + + `⚙️ *Perfil:* ${perfilEncontrado.identificacao}\n` + + `🆔 *Serviço ID:* ${idServico}\n` + + `👤 *Cliente ID:* ${idCliente}\n\n` + + `Confirmar os dados acima?`, + { + parse_mode: 'Markdown', + reply_markup: { + inline_keyboard: [[ + { text: '✅ Confirmar', callback_data: 'topsapp_onu_ok' }, + { text: '❌ Cancelar', callback_data: 'cancel_action' } + ]] + } + } + ); + + } catch (error) { + console.error('❌ Erro ao confirmar vínculo TopSapp:', error); + await this.bot.sendMessage(chatId, `❌ Erro: ${error.message}`); + this.userSessions.delete(userId); + } + } + + /** + * Executa a atualização FTTH no TopSapp via AlterarServico + */ + async topsappOnuExecutarVinculo(chatId, userId, session) { + try { + const { idCliente, idServico, ftthData, location } = session.ftthPayload; + + await this.bot.sendMessage(chatId, '⏳ Salvando dados no TopSapp...'); + + const resultado = await this.topsapp.atualizarFTTH(idCliente, idServico, ftthData, location); + + if (resultado.success) { + await this.bot.sendMessage(chatId, + `✅ *ONU vinculada com sucesso no TopSapp!*\n\n` + + `📱 *Serial:* \`${ftthData.serial}\`\n` + + `🆔 *Serviço ID:* ${idServico}\n` + + `👤 *Cliente ID:* ${idCliente}`, + { parse_mode: 'Markdown' } + ); + } else { + await this.bot.sendMessage(chatId, + `❌ *Erro ao vincular no TopSapp*\n\n${resultado.error}`, + { parse_mode: 'Markdown' } + ); + } + + } catch (error) { + console.error('❌ Erro ao executar vínculo TopSapp:', error); + await this.bot.sendMessage(chatId, `❌ Erro: ${error.message}`); + } finally { + this.userSessions.delete(userId); + } + } } module.exports = BotHandler; diff --git a/src/topsapp/api.js b/src/topsapp/api.js index be81b2a..2c16784 100644 --- a/src/topsapp/api.js +++ b/src/topsapp/api.js @@ -823,6 +823,35 @@ class TopSappAPI { } } + /** + * Obter lista de OLTs cadastradas no TopSapp + */ + async obterOlts(location = '', credentials) { + const instance = this.getInstanceByLocation(location); + try { + const session = await this.getValidSession(instance, credentials); + return await this.makeRequest('ObterOlts', { idUsuario: session.idUsuario || 1 }, instance, credentials); + } catch (error) { + return { success: false, error: error.message }; + } + } + + /** + * Atualizar dados FTTH de um serviço (vincular ONU a cliente/serviço) + */ + async atualizarFTTH(idCliente, idServico, ftthData, location = '', credentials) { + const instance = this.getInstanceByLocation(location); + try { + return await this.makeRequest('AlterarServico', { + idCliente: parseInt(idCliente), + idServico: parseInt(idServico), + ...ftthData + }, instance, credentials); + } catch (error) { + return { success: false, error: error.message }; + } + } + /** * Listar todas as instâncias disponíveis */ diff --git a/src/topsapp/manager.js b/src/topsapp/manager.js index 0d22c64..d4c401d 100644 --- a/src/topsapp/manager.js +++ b/src/topsapp/manager.js @@ -1261,6 +1261,23 @@ class TopSappManager { }; } } + /** + * Obter lista de OLTs cadastradas no TopSapp + */ + async obterOlts(location = '') { + if (!this.isReady()) return { success: false, error: 'TopSapp não configurado' }; + const credentials = this.config.getCredentialsByLocation(location); + return await this.api.obterOlts(location, credentials); + } + + /** + * Atualizar dados FTTH de um serviço (vincular ONU a cliente/serviço) + */ + async atualizarFTTH(idCliente, idServico, ftthData, location = '') { + if (!this.isReady()) return { success: false, error: 'TopSapp não configurado' }; + const credentials = this.config.getCredentialsByLocation(location); + return await this.api.atualizarFTTH(idCliente, idServico, ftthData, location, credentials); + } } module.exports = TopSappManager;