From d4bd3646902b1439f9056362a16934c3957e22be Mon Sep 17 00:00:00 2001 From: Rodrigo Bertoldo de Sousa Martins Date: Fri, 12 Dec 2025 14:07:26 -0300 Subject: [PATCH] TopSapp: fix API show blocked services from client Signed-off-by: Rodrigo Bertoldo de Sousa Martins --- src/bot/handler.js | 243 +++++++++++++++++++++++++++++++++-------- src/topsapp/manager.js | 47 ++++++++ 2 files changed, 245 insertions(+), 45 deletions(-) diff --git a/src/bot/handler.js b/src/bot/handler.js index cd05022..46072b2 100644 --- a/src/bot/handler.js +++ b/src/bot/handler.js @@ -1146,6 +1146,12 @@ Digite /help para ver todos os comandos disponíveis! } else if (data.startsWith('suporte_servico_')) { console.log(`🔍 Condição suporte_servico_ atendida`); await this.handleSuporteServicoCallback(callbackQuery, data); + } else if (data.startsWith('linha_')) { + console.log(`🔍 Condição linha_ atendida`); + await this.handleLinhaDigitavelCallback(callbackQuery, data); + } else if (data.startsWith('pix_')) { + console.log(`🔍 Condição pix_ atendida`); + await this.handlePixCallback(callbackQuery, data); } else { console.log(`❓ Callback não reconhecido: ${data}`); await this.bot.answerCallbackQuery(callbackQuery.id, 'Comando não reconhecido'); @@ -3086,7 +3092,7 @@ Digite /help para ver todos os comandos disponíveis! await this.bot.sendMessage(chatId, '📄 Buscando faturas...'); - const resultado = await this.topsapp.obterFaturas(idCliente, location); + const resultado = await this.topsapp.obterFaturasDetalhadas(idCliente, location); if (!resultado.success) { await this.bot.sendMessage(chatId, @@ -3097,64 +3103,99 @@ Digite /help para ver todos os comandos disponíveis! return; } - // Corrigir acesso aos dados: resultado.data é um objeto { resultado: true, dados: [...] } - const faturas = resultado.data?.dados || resultado.data?.faturas || resultado.faturas || []; + const faturasPorServico = resultado.faturasPorServico || []; - // Verificar se é realmente um array - if (!Array.isArray(faturas)) { - console.error('❌ Faturas não é um array:', typeof faturas, faturas); + if (faturasPorServico.length === 0) { await this.bot.sendMessage(chatId, - `❌ **Erro ao processar faturas**\n\n` + - `⚠️ Formato de resposta inválido`, + `📄 **Nenhuma fatura encontrada**\n\n` + + `✅ O cliente não possui faturas cadastradas.`, { parse_mode: 'Markdown' } ); return; } - if (faturas.length === 0) { - await this.bot.sendMessage(chatId, - `📄 **Nenhuma fatura em aberto**\n\n` + - `✅ O cliente não possui faturas pendentes.`, - { parse_mode: 'Markdown' } - ); - return; - } + // Contar total de faturas + let totalFaturas = 0; + faturasPorServico.forEach(s => { + totalFaturas += s.faturas.length; + }); let message = `📄 **FATURAS DO CLIENTE**\n\n`; message += `🆔 **ID Cliente**: ${idCliente}\n`; - message += `📊 **Total de faturas**: ${faturas.length}\n\n`; + message += `📊 **Total de faturas**: ${totalFaturas}\n\n`; - faturas.forEach((fatura, index) => { - // Verificar se está paga - const isPago = fatura.pago && fatura.pago.toUpperCase() === 'SIM'; - const statusEmoji = isPago ? '✅' : '🔴'; - const statusTexto = isPago ? 'PAGO' : 'EM ABERTO'; - - message += `${index + 1}. ${statusEmoji} **Fatura #${fatura.id || fatura.numero_fatura}**\n`; - - if (fatura.valor) { - const valor = parseFloat(fatura.valor); - message += ` 💰 Valor: R$ ${valor.toFixed(2)}\n`; + faturasPorServico.forEach((servicoInfo, sIndex) => { + if (servicoInfo.faturas.length > 0) { + message += `📋 **Serviço**: ${servicoInfo.servico.descricao || 'Serviço'}\n`; + message += `🆔 **ID**: ${servicoInfo.servico.id}\n\n`; + + servicoInfo.faturas.forEach((fatura, fIndex) => { + const isPago = fatura.status === 'Pago'; + const statusEmoji = isPago ? '✅' : '🔴'; + + message += `${fIndex + 1}. ${statusEmoji} **Fatura #${fatura.id}**\n`; + + if (fatura.valor) { + const valor = parseFloat(fatura.valor); + message += ` 💰 Valor: R$ ${valor.toFixed(2)}\n`; + } + + if (fatura.vencimento) { + message += ` 📅 Vencimento: ${fatura.vencimento}\n`; + } + + message += ` 📊 Status: ${fatura.status}\n`; + + if (fatura.descricao) { + message += ` 📝 Descrição: ${fatura.descricao}\n`; + } + + if (fatura.periodo) { + message += ` 📆 Período: ${fatura.periodo}\n`; + } + + message += `\n`; + }); + + message += `\n`; } - - if (fatura.vencimento) { - message += ` 📅 Vencimento: ${fatura.vencimento}\n`; - } - - message += ` 📊 Status: ${statusTexto}\n`; - - if (fatura.historico) { - message += ` 📝 Descrição: ${fatura.historico}\n`; - } - - if (isPago && fatura.datapagto) { - message += ` 💳 Pago em: ${fatura.datapagto}\n`; - } - - message += `\n`; }); - await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' }); + // Criar botões para cada fatura com linha digitável/PIX + const keyboard = []; + + faturasPorServico.forEach((servicoInfo) => { + servicoInfo.faturas.forEach((fatura) => { + if (fatura.status !== 'Pago') { + const row = []; + + if (fatura.linhaDigitavel) { + row.push({ + text: `📋 Linha Digitável #${fatura.id}`, + callback_data: `linha_${fatura.id}_${location}` + }); + } + + if (fatura.pixCopiaCola) { + row.push({ + text: `💳 PIX #${fatura.id}`, + callback_data: `pix_${fatura.id}_${location}` + }); + } + + if (row.length > 0) { + keyboard.push(row); + } + } + }); + }); + + await this.bot.sendMessage(chatId, message, { + parse_mode: 'Markdown', + reply_markup: keyboard.length > 0 ? { + inline_keyboard: keyboard + } : undefined + }); } catch (error) { console.error('❌ Erro ao buscar faturas:', error); @@ -3488,6 +3529,118 @@ Digite /help para ver todos os comandos disponíveis! await this.handleListarServicos(chatId, idCliente); } + /** + * Callback para exibir linha digitável + */ + async handleLinhaDigitavelCallback(callbackQuery, data) { + const chatId = callbackQuery.message.chat.id; + const parts = data.replace('linha_', '').split('_'); + const idFatura = parts[0]; + const location = parts.slice(1).join('_'); + + try { + await this.bot.answerCallbackQuery(callbackQuery.id); + await this.bot.sendMessage(chatId, '⏳ Buscando linha digitável...'); + + // Buscar dados da fatura + const resultado = await this.topsapp.obterDadosFatura(idFatura, location); + + if (!resultado.success) { + await this.bot.sendMessage(chatId, + `❌ **Erro ao buscar linha digitável**\n\n` + + `⚠️ ${resultado.error}`, + { parse_mode: 'Markdown' } + ); + return; + } + + const dadosFatura = resultado.data?.fatura || resultado.data?.dados || resultado.data; + + if (!dadosFatura || !dadosFatura.linha_digitavel) { + await this.bot.sendMessage(chatId, + `⚠️ **Linha digitável não disponível**\n\n` + + `A fatura #${idFatura} não possui linha digitável.`, + { parse_mode: 'Markdown' } + ); + return; + } + + let message = `📋 **LINHA DIGITÁVEL**\n\n`; + message += `🆔 **Fatura**: #${idFatura}\n`; + message += `💰 **Valor**: R$ ${parseFloat(dadosFatura.valor || dadosFatura.valor_atualizado || 0).toFixed(2)}\n`; + message += `📅 **Vencimento**: ${dadosFatura.vencimento || dadosFatura.vencimento_atualizado || 'N/A'}\n\n`; + message += `📋 **Linha Digitável**:\n\`${dadosFatura.linha_digitavel}\`\n\n`; + message += `💡 _Copie a linha digitável acima para pagar pelo app do banco_`; + + await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' }); + + } catch (error) { + console.error('❌ Erro ao buscar linha digitável:', error); + await this.bot.sendMessage(chatId, + `❌ **Erro ao buscar linha digitável**\n\n` + + `⚠️ ${error.message}`, + { parse_mode: 'Markdown' } + ); + } + } + + /** + * Callback para exibir PIX copia e cola + */ + async handlePixCallback(callbackQuery, data) { + const chatId = callbackQuery.message.chat.id; + const parts = data.replace('pix_', '').split('_'); + const idFatura = parts[0]; + const location = parts.slice(1).join('_'); + + try { + await this.bot.answerCallbackQuery(callbackQuery.id); + await this.bot.sendMessage(chatId, '⏳ Buscando código PIX...'); + + // Buscar dados da fatura + const resultado = await this.topsapp.obterDadosFatura(idFatura, location); + + if (!resultado.success) { + await this.bot.sendMessage(chatId, + `❌ **Erro ao buscar código PIX**\n\n` + + `⚠️ ${resultado.error}`, + { parse_mode: 'Markdown' } + ); + return; + } + + const dadosFatura = resultado.data?.fatura || resultado.data?.dados || resultado.data; + + const pixCode = dadosFatura?.qrcode || dadosFatura?.pix_copia_cola || dadosFatura?.codigo_pix; + + if (!dadosFatura || !pixCode) { + await this.bot.sendMessage(chatId, + `⚠️ **PIX não disponível**\n\n` + + `A fatura #${idFatura} não possui código PIX.`, + { parse_mode: 'Markdown' } + ); + return; + } + + let message = `💳 **PIX COPIA E COLA**\n\n`; + message += `🆔 **Fatura**: #${idFatura}\n`; + message += `💰 **Valor**: R$ ${parseFloat(dadosFatura.valor || dadosFatura.valor_atualizado || 0).toFixed(2)}\n`; + message += `📅 **Vencimento**: ${dadosFatura.vencimento || dadosFatura.vencimento_atualizado || 'N/A'}\n\n`; + message += `💳 **PIX Copia e Cola**:\n\`${pixCode}\`\n\n`; + message += `💡 _Copie o código acima e cole no app do banco na opção PIX Copia e Cola_`; + + await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' }); + + } catch (error) { + console.error('❌ Erro ao buscar código PIX:', error); + await this.bot.sendMessage(chatId, + `❌ **Erro ao buscar código PIX**\n\n` + + `⚠️ ${error.message}`, + { parse_mode: 'Markdown' } + ); + } + } + /** * Escapar caracteres problemáticos para Markdown do Telegram */ diff --git a/src/topsapp/manager.js b/src/topsapp/manager.js index 3fb8570..0d22c64 100644 --- a/src/topsapp/manager.js +++ b/src/topsapp/manager.js @@ -1214,6 +1214,53 @@ class TopSappManager { }; } } + + /** + * Obter dados completos de uma fatura (linha digitável, PIX, etc) + */ + async obterDadosFatura(idFatura, location = '') { + if (!this.isReady()) { + return { + success: false, + error: 'TopSapp não está configurado' + }; + } + + try { + const credentials = this.config.getCredentialsByLocation(location); + + // Primeiro obter a lista de faturas para pegar o idCliente + const faturas = await this.api.obterFaturas(null, location, credentials); + + if (!faturas.success || !faturas.data || !faturas.data.dados) { + return { + success: false, + error: 'Erro ao buscar faturas' + }; + } + + // Encontrar a fatura específica + const fatura = faturas.data.dados.find(f => f.id == idFatura); + + if (!fatura) { + return { + success: false, + error: 'Fatura não encontrada' + }; + } + + const idCliente = fatura.codigo_cliente || fatura.id_cliente; + + // Obter dados completos da fatura + return await this.api.obterDadosFatura(idFatura, idCliente, location, credentials); + + } catch (error) { + return { + success: false, + error: error.message + }; + } + } } module.exports = TopSappManager;