Add TopSapp preliminary support
Signed-off-by: Rodrigo B. de Sousa Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
1 parent
d4c37a3f78
commit
723ad8c268
10 files changed
+11952
-2
No files matched your search
@@ -9,3 +9,11 @@ DEFAULT_SSH_PASSWORD=password
|
|||||||
# Configurações do bot
|
# Configurações do bot
|
||||||
BOT_DEBUG=true
|
BOT_DEBUG=true
|
||||||
ALLOWED_USERS=123456789,987654321
|
ALLOWED_USERS=123456789,987654321
|
||||||
|
|
||||||
|
# Configurações TopSapp - Instância Guarai/Colmeia
|
||||||
|
TOPSAPP_GUARAI_USER=seu_usuario_guarai
|
||||||
|
TOPSAPP_GUARAI_PASS=sua_senha_guarai
|
||||||
|
|
||||||
|
# Configurações TopSapp - Instância Pedro Afonso
|
||||||
|
TOPSAPP_PEDRO_AFONSO_USER=seu_usuario_pedro_afonso
|
||||||
|
TOPSAPP_PEDRO_AFONSO_PASS=sua_senha_pedro_afonso
|
||||||
@@ -0,0 +1,202 @@
|
|||||||
|
# Integração TopSapp - Bot de Ajuda
|
||||||
|
|
||||||
|
## 📋 Visão Geral
|
||||||
|
|
||||||
|
Esta integração permite ao bot interagir com o sistema TopSapp para gerenciar clientes, faturas e serviços através de comandos naturais no Telegram.
|
||||||
|
|
||||||
|
## 🏢 Instâncias Configuradas
|
||||||
|
|
||||||
|
### Guarai/Colmeia
|
||||||
|
- **Host**: 131.0.192.6
|
||||||
|
- **Porta**: 443 (HTTPS)
|
||||||
|
- **Localização**: Guarai e Colmeia
|
||||||
|
|
||||||
|
### Pedro Afonso
|
||||||
|
- **Host**: 45.189.140.18
|
||||||
|
- **Porta**: 443 (HTTPS)
|
||||||
|
- **Localização**: Pedro Afonso
|
||||||
|
|
||||||
|
## ⚙️ Configuração
|
||||||
|
|
||||||
|
### 1. Variáveis de Ambiente
|
||||||
|
|
||||||
|
Adicione as seguintes variáveis no arquivo `.env`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# TopSapp - Instância Guarai/Colmeia
|
||||||
|
TOPSAPP_GUARAI_USER=seu_usuario_guarai
|
||||||
|
TOPSAPP_GUARAI_PASS=sua_senha_guarai
|
||||||
|
|
||||||
|
# TopSapp - Instância Pedro Afonso
|
||||||
|
TOPSAPP_PEDRO_AFONSO_USER=seu_usuario_pedro_afonso
|
||||||
|
TOPSAPP_PEDRO_AFONSO_PASS=sua_senha_pedro_afonso
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Dependências
|
||||||
|
|
||||||
|
As seguintes dependências são necessárias:
|
||||||
|
- `axios` - Para requisições HTTP
|
||||||
|
- `form-data` - Para upload de formulários
|
||||||
|
- `https` - Para certificados SSL personalizados
|
||||||
|
|
||||||
|
## 🔧 Comandos Disponíveis
|
||||||
|
|
||||||
|
### 📊 Status do Sistema
|
||||||
|
```
|
||||||
|
status topsapp
|
||||||
|
verificar topsapp
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔍 Buscar Clientes
|
||||||
|
```
|
||||||
|
buscar cliente João da Silva
|
||||||
|
buscar cliente 123.456.789-10
|
||||||
|
buscar cliente Guarai João (específica instância)
|
||||||
|
buscar cliente Pedro Afonso Maria
|
||||||
|
```
|
||||||
|
|
||||||
|
### 📄 Ver Faturas
|
||||||
|
```
|
||||||
|
ver faturas 123.456.789-10
|
||||||
|
ver faturas cliente123
|
||||||
|
ver faturas Guarai 123.456.789-10
|
||||||
|
```
|
||||||
|
|
||||||
|
### 💸 Gerar Boletos
|
||||||
|
```
|
||||||
|
gerar boleto 12345
|
||||||
|
gerar boleto fatura123
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔒 Bloquear Clientes
|
||||||
|
```
|
||||||
|
bloquear cliente 456
|
||||||
|
bloquear 789
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔓 Liberar Clientes
|
||||||
|
```
|
||||||
|
liberar cliente 456
|
||||||
|
liberar 789
|
||||||
|
```
|
||||||
|
|
||||||
|
## 🚀 Funcionalidades
|
||||||
|
|
||||||
|
### ✅ Autenticação Automática
|
||||||
|
- Login automático com credenciais configuradas
|
||||||
|
- Gerenciamento de sessões com expiração
|
||||||
|
- Renovação automática de tokens
|
||||||
|
|
||||||
|
### 🌐 Multi-instância
|
||||||
|
- Detecção automática da instância por localização
|
||||||
|
- Roteamento de requisições para servidor correto
|
||||||
|
- Suporte a múltiplas configurações
|
||||||
|
|
||||||
|
### 📋 Gestão de Clientes
|
||||||
|
- Busca por nome, CPF ou ID
|
||||||
|
- Visualização de dados completos
|
||||||
|
- Histórico de serviços e faturas
|
||||||
|
|
||||||
|
### 💰 Sistema de Faturamento
|
||||||
|
- Listagem de faturas pendentes e pagas
|
||||||
|
- Geração de boletos em PDF
|
||||||
|
- Linha digitável para pagamento
|
||||||
|
|
||||||
|
### 🔐 Controle de Serviços
|
||||||
|
- Bloqueio de serviços em massa
|
||||||
|
- Liberação de serviços bloqueados
|
||||||
|
- Confirmação antes de ações críticas
|
||||||
|
|
||||||
|
### 📊 Relatórios e Status
|
||||||
|
- Status de configuração do sistema
|
||||||
|
- Estatísticas de uso por instância
|
||||||
|
- Monitoramento de conectividade
|
||||||
|
|
||||||
|
## 🔧 Arquitetura
|
||||||
|
|
||||||
|
### Classes Principais
|
||||||
|
|
||||||
|
#### `TopSappAPI`
|
||||||
|
- Gerencia autenticação e sessões
|
||||||
|
- Executa requisições para a API
|
||||||
|
- Converte Base64 para PDF
|
||||||
|
|
||||||
|
#### `TopSappConfig`
|
||||||
|
- Carrega configurações do ambiente
|
||||||
|
- Valida credenciais disponíveis
|
||||||
|
- Fornece dados de instâncias
|
||||||
|
|
||||||
|
#### `TopSappManager`
|
||||||
|
- Interface principal para o bot
|
||||||
|
- Coordena operações complexas
|
||||||
|
- Trata erros e formatação
|
||||||
|
|
||||||
|
## 📝 Logs e Debug
|
||||||
|
|
||||||
|
O sistema gera logs detalhados:
|
||||||
|
- `🎯` - Inicialização de componentes
|
||||||
|
- `🔐` - Operações de autenticação
|
||||||
|
- `📡` - Requisições para API
|
||||||
|
- `✅` - Operações bem-sucedidas
|
||||||
|
- `❌` - Erros e falhas
|
||||||
|
|
||||||
|
## ⚠️ Considerações de Segurança
|
||||||
|
|
||||||
|
- Certificados SSL auto-assinados são aceitos
|
||||||
|
- Sessões expiram automaticamente em 30 minutos
|
||||||
|
- Credenciais são armazenadas em variáveis de ambiente
|
||||||
|
- Timeout de 10 segundos para requisições
|
||||||
|
|
||||||
|
## 🐛 Troubleshooting
|
||||||
|
|
||||||
|
### Erro de Autenticação
|
||||||
|
1. Verificar credenciais no `.env`
|
||||||
|
2. Testar login manual no TopSapp
|
||||||
|
3. Verificar conectividade com o servidor
|
||||||
|
|
||||||
|
### Timeout de Conexão
|
||||||
|
1. Verificar conectividade de rede
|
||||||
|
2. Confirmar se os serviços estão online
|
||||||
|
3. Ajustar timeout se necessário
|
||||||
|
|
||||||
|
### Erro de Certificado SSL
|
||||||
|
- O sistema já está configurado para aceitar certificados auto-assinados
|
||||||
|
- Verificar se o hostname está correto
|
||||||
|
|
||||||
|
## 📈 Métricas de Performance
|
||||||
|
|
||||||
|
- Sessões mantidas por até 30 minutos
|
||||||
|
- Timeout de requisições: 10 segundos
|
||||||
|
- Suporte a operações simultâneas
|
||||||
|
- Cache de configurações carregadas
|
||||||
|
|
||||||
|
## 🔄 Manutenção
|
||||||
|
|
||||||
|
### Limpeza de Sessões
|
||||||
|
- Sessões expiradas são limpas automaticamente
|
||||||
|
- Intervalo de limpeza: 10 minutos
|
||||||
|
|
||||||
|
### Renovação de Tokens
|
||||||
|
- Detecção automática de expiração
|
||||||
|
- Re-autenticação transparente
|
||||||
|
- Sem interrupção do serviço
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💡 Exemplos de Uso
|
||||||
|
|
||||||
|
### Fluxo Completo de Atendimento
|
||||||
|
1. `buscar cliente João da Silva`
|
||||||
|
2. `ver faturas 123.456.789-10`
|
||||||
|
3. `gerar boleto 12345`
|
||||||
|
4. `bloquear cliente 456` (se necessário)
|
||||||
|
|
||||||
|
### Verificação de Status
|
||||||
|
1. `status topsapp`
|
||||||
|
2. Verificar configurações
|
||||||
|
3. Testar conectividade
|
||||||
|
|
||||||
|
### Operações por Localização
|
||||||
|
- `buscar cliente Guarai João` → Busca apenas em Guarai/Colmeia
|
||||||
|
- `buscar cliente Pedro Afonso Maria` → Busca apenas em Pedro Afonso
|
||||||
|
- `buscar cliente João` → Busca em todas as instâncias
|
||||||
File diff suppressed because it is too large.
Load diff
+3
-1
@@ -28,7 +28,9 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"node-telegram-bot-api": "^0.64.0",
|
"node-telegram-bot-api": "^0.64.0",
|
||||||
"ssh2": "^1.15.0",
|
"ssh2": "^1.15.0",
|
||||||
"dotenv": "^16.3.1"
|
"dotenv": "^16.3.1",
|
||||||
|
"axios": "^1.6.0",
|
||||||
|
"form-data": "^4.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^3.0.1"
|
"nodemon": "^3.0.1"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const NLPProcessor = require('../nlp/processor');
|
const NLPProcessor = require('../nlp/processor');
|
||||||
const SSHManager = require('../ssh/manager');
|
const SSHManager = require('../ssh/manager');
|
||||||
|
const { TopSappManager } = require('../topsapp');
|
||||||
const config = require('../config/config');
|
const config = require('../config/config');
|
||||||
|
|
||||||
class BotHandler {
|
class BotHandler {
|
||||||
@@ -7,6 +8,7 @@ class BotHandler {
|
|||||||
this.bot = bot;
|
this.bot = bot;
|
||||||
this.nlp = new NLPProcessor();
|
this.nlp = new NLPProcessor();
|
||||||
this.ssh = new SSHManager();
|
this.ssh = new SSHManager();
|
||||||
|
this.topsapp = new TopSappManager();
|
||||||
this.userSessions = new Map(); // Armazena sessões de usuário
|
this.userSessions = new Map(); // Armazena sessões de usuário
|
||||||
|
|
||||||
console.log('🎯 BotHandler inicializado');
|
console.log('🎯 BotHandler inicializado');
|
||||||
@@ -150,6 +152,36 @@ class BotHandler {
|
|||||||
await this.handleAdicionarOnu(chatId, target);
|
await this.handleAdicionarOnu(chatId, target);
|
||||||
break;
|
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 'status_topsapp':
|
||||||
|
console.log(`🏢 Executando handleStatusTopSapp`);
|
||||||
|
await this.handleStatusTopSapp(chatId);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'conectar':
|
case 'conectar':
|
||||||
await this.handleConnect(chatId, target);
|
await this.handleConnect(chatId, target);
|
||||||
break;
|
break;
|
||||||
@@ -256,6 +288,16 @@ Digite /help para ver todos os comandos disponíveis!
|
|||||||
• Oferece opções de firmware específicas para cada modelo
|
• Oferece opções de firmware específicas para cada modelo
|
||||||
• Processo seguro com confirmação
|
• 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"
|
||||||
|
• "ver faturas 123.456.789-10"
|
||||||
|
• "gerar boleto fatura123"
|
||||||
|
• "bloquear cliente 456"
|
||||||
|
• "liberar cliente 456"
|
||||||
|
• "status topsapp"
|
||||||
|
|
||||||
📊 STATUS E MONITORAMENTO:
|
📊 STATUS E MONITORAMENTO:
|
||||||
/status <equipamento> - Verifica status
|
/status <equipamento> - Verifica status
|
||||||
• "verificar concentrador"
|
• "verificar concentrador"
|
||||||
@@ -270,12 +312,18 @@ Digite /help para ver todos os comandos disponíveis!
|
|||||||
• "Listar usuários conectados"
|
• "Listar usuários conectados"
|
||||||
• "Reiniciar juniper"
|
• "Reiniciar juniper"
|
||||||
• "Ping 131.0.192.254"
|
• "Ping 131.0.192.254"
|
||||||
|
• "Buscar cliente João da Silva"
|
||||||
|
• "Ver faturas do CPF 123.456.789-10"
|
||||||
|
|
||||||
✅ EXEMPLOS PRÁTICOS:
|
✅ EXEMPLOS PRÁTICOS:
|
||||||
• "desconectar cliente user123"
|
• "desconectar cliente user123"
|
||||||
• "ver sinal DACM91569513"
|
• "ver sinal DACM91569513"
|
||||||
• "adicionar onu DACM91569513"
|
• "adicionar onu DACM91569513"
|
||||||
• "remover 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"
|
• "listar clientes conectados"
|
||||||
• "verificar status concentrador"
|
• "verificar status concentrador"
|
||||||
|
|
||||||
@@ -818,6 +866,12 @@ Digite /help para ver todos os comandos disponíveis!
|
|||||||
console.error(`❌ Erro em handleConfirmAddCallback:`, confirmError);
|
console.error(`❌ Erro em handleConfirmAddCallback:`, confirmError);
|
||||||
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro na confirmação');
|
await this.bot.answerCallbackQuery(callbackQuery.id, 'Erro na confirmação');
|
||||||
}
|
}
|
||||||
|
} 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('confirm_')) {
|
} else if (data.startsWith('confirm_')) {
|
||||||
console.log(`🔍 Condição confirm_ atendida`);
|
console.log(`🔍 Condição confirm_ atendida`);
|
||||||
await this.handleConfirmCallback(callbackQuery, data);
|
await this.handleConfirmCallback(callbackQuery, data);
|
||||||
@@ -2040,6 +2094,550 @@ Digite /help para ver todos os comandos disponíveis!
|
|||||||
{ parse_mode: 'Markdown' }
|
{ 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = `🔍 **Clientes encontrados**\n\n`;
|
||||||
|
message += `📊 **Total**: ${resultado.total} cliente(s)\n`;
|
||||||
|
message += `🌐 **Instância**: ${resultado.instancia}\n\n`;
|
||||||
|
|
||||||
|
resultado.clientes.slice(0, 5).forEach((cliente, index) => {
|
||||||
|
message += `👤 **${index + 1}. ${cliente.nome}**\n`;
|
||||||
|
message += `🆔 ID: \`${cliente.id}\`\n`;
|
||||||
|
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`;
|
||||||
|
message += `🏙️ Cidade: ${cliente.cidade}\n`;
|
||||||
|
message += `📊 Status: ${cliente.status === 1 ? '✅ Ativo' : '❌ Inativo'}\n\n`;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (resultado.total > 5) {
|
||||||
|
message += `📋 *Mostrando apenas os primeiros 5 resultados de ${resultado.total}*\n\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
message += `💡 **Comandos úteis:**\n`;
|
||||||
|
message += `• "ver faturas ${resultado.clientes[0].cpf}"\n`;
|
||||||
|
message += `• "bloquear cliente ${resultado.clientes[0].id}"\n`;
|
||||||
|
message += `• "liberar cliente ${resultado.clientes[0].id}"`;
|
||||||
|
|
||||||
|
await this.bot.sendMessage(chatId, message, { parse_mode: 'Markdown' });
|
||||||
|
|
||||||
|
} 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' }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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, buscar o cliente primeiro
|
||||||
|
let idCliente = clienteId;
|
||||||
|
if (clienteId.includes('.') || clienteId.includes('-')) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 += `💸 **${index + 1}. Fatura #${boleto.id}**\n`;
|
||||||
|
message += `💰 Valor: R$ ${boleto.valor}\n`;
|
||||||
|
message += `📅 Vencimento: ${boleto.vencimento}\n`;
|
||||||
|
message += `📊 Status: ${this.getStatusFatura(boleto.status)}\n`;
|
||||||
|
message += `📝 Descrição: ${boleto.descricao || 'Não informada'}\n`;
|
||||||
|
|
||||||
|
if (boleto.linhaDigitavel) {
|
||||||
|
message += `🔢 Linha digitável: \`${boleto.linhaDigitavel}\`\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) {
|
||||||
|
if (!target) {
|
||||||
|
await this.bot.sendMessage(chatId,
|
||||||
|
`🔒 **Bloquear Cliente**\n\n` +
|
||||||
|
`💡 **Como usar:**\n` +
|
||||||
|
`• "bloquear cliente 456"\n` +
|
||||||
|
`• "bloquear 789"`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Solicitar confirmação
|
||||||
|
const keyboard = {
|
||||||
|
inline_keyboard: [
|
||||||
|
[
|
||||||
|
{ text: '✅ Confirmar Bloqueio', callback_data: `confirm_block_${target}` },
|
||||||
|
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||||||
|
]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.bot.sendMessage(chatId,
|
||||||
|
`🔒 **Confirmar Bloqueio**\n\n` +
|
||||||
|
`⚠️ Deseja bloquear o cliente ID: ${target}?\n\n` +
|
||||||
|
`📋 Esta ação bloqueará todos os serviços ativos do cliente.`,
|
||||||
|
{
|
||||||
|
parse_mode: 'Markdown',
|
||||||
|
reply_markup: 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 cliente 456"\n` +
|
||||||
|
`• "liberar 789"`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Solicitar confirmação
|
||||||
|
const keyboard = {
|
||||||
|
inline_keyboard: [
|
||||||
|
[
|
||||||
|
{ text: '✅ Confirmar Liberação', callback_data: `confirm_unblock_${target}` },
|
||||||
|
{ text: '❌ Cancelar', callback_data: 'cancel_action' }
|
||||||
|
]
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
await this.bot.sendMessage(chatId,
|
||||||
|
`🔓 **Confirmar Liberação**\n\n` +
|
||||||
|
`✅ Deseja liberar o cliente ID: ${target}?\n\n` +
|
||||||
|
`📋 Esta ação liberará todos os serviços bloqueados do cliente.`,
|
||||||
|
{
|
||||||
|
parse_mode: 'Markdown',
|
||||||
|
reply_markup: 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) {
|
||||||
|
switch (status) {
|
||||||
|
case 1: return '✅ Paga';
|
||||||
|
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;
|
||||||
|
const clienteId = data.replace('confirm_block_', '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (!resultado.success) {
|
||||||
|
await this.bot.editMessageText(
|
||||||
|
`❌ **Erro ao bloquear cliente**\n\n` +
|
||||||
|
`🆔 Cliente ID: ${clienteId}\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;
|
||||||
|
const clienteId = data.replace('confirm_unblock_', '');
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.bot.answerCallbackQuery(callbackQuery.id, 'Processando liberação...');
|
||||||
|
|
||||||
|
await this.bot.editMessageText(
|
||||||
|
`🔓 **Liberando cliente ID: ${clienteId}**\n\n⏳ Aguarde...`,
|
||||||
|
{
|
||||||
|
chat_id: chatId,
|
||||||
|
message_id: callbackQuery.message.message_id,
|
||||||
|
parse_mode: 'Markdown'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const resultado = await this.topsapp.liberarCliente(clienteId);
|
||||||
|
|
||||||
|
if (!resultado.success) {
|
||||||
|
await this.bot.editMessageText(
|
||||||
|
`❌ **Erro ao liberar cliente**\n\n` +
|
||||||
|
`🆔 Cliente ID: ${clienteId}\n` +
|
||||||
|
`⚠️ Erro: ${resultado.error}`,
|
||||||
|
{
|
||||||
|
chat_id: chatId,
|
||||||
|
message_id: callbackQuery.message.message_id,
|
||||||
|
parse_mode: 'Markdown'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = `🔓 **Cliente liberado com sucesso!**\n\n`;
|
||||||
|
message += `🆔 Cliente ID: ${clienteId}\n`;
|
||||||
|
message += `🌐 Instância: ${resultado.instancia}\n`;
|
||||||
|
message += `📊 Serviços liberados: ${resultado.total}\n\n`;
|
||||||
|
|
||||||
|
if (resultado.servicosLiberados && resultado.servicosLiberados.length > 0) {
|
||||||
|
message += `📋 **Detalhes das liberações:**\n`;
|
||||||
|
resultado.servicosLiberados.forEach((servico, index) => {
|
||||||
|
message += `${index + 1}. ${servico.descricao}: ${servico.resultado.success ? '✅ Liberado' : '❌ 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 liberar cliente:', error);
|
||||||
|
await this.bot.editMessageText(
|
||||||
|
`❌ **Erro interno ao liberar cliente**\n\n` +
|
||||||
|
`🆔 Cliente ID: ${clienteId}\n` +
|
||||||
|
`⚠️ ${error.message}`,
|
||||||
|
{
|
||||||
|
chat_id: chatId,
|
||||||
|
message_id: callbackQuery.message.message_id,
|
||||||
|
parse_mode: 'Markdown'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BotHandler;
|
module.exports = BotHandler;
|
||||||
+84
-1
@@ -17,11 +17,24 @@ class NLPProcessor {
|
|||||||
'ping': ['ping', 'testar', 'test', 'conectividade'],
|
'ping': ['ping', 'testar', 'test', 'conectividade'],
|
||||||
'admin': ['admin', 'administração', 'administracao', 'painel'],
|
'admin': ['admin', 'administração', 'administracao', 'painel'],
|
||||||
'usuarios_autorizados': ['usuarios autorizados', 'users autorizados', 'lista usuarios', 'listar usuarios autorizados'],
|
'usuarios_autorizados': ['usuarios autorizados', 'users autorizados', 'lista usuarios', 'listar usuarios autorizados'],
|
||||||
'meu_id': ['meu id', 'meu user id', 'my id', 'user id', 'minha id']
|
'meu_id': ['meu id', 'meu user id', 'my id', 'user id', 'minha id'],
|
||||||
|
'buscar_cliente': ['buscar cliente', 'procurar cliente', 'encontrar cliente', 'search cliente', 'cliente'],
|
||||||
|
'ver_faturas': ['ver faturas', 'ver fatura', 'faturas', 'fatura', 'boletos', 'boleto', 'contas'],
|
||||||
|
'gerar_boleto': ['gerar boleto', 'boleto', 'criar boleto', 'pdf boleto', 'imprimir boleto'],
|
||||||
|
'bloquear_cliente': ['bloquear cliente', 'bloquear', 'suspender cliente', 'cortar cliente'],
|
||||||
|
'liberar_cliente': ['liberar cliente', 'liberar', 'desbloquear cliente', 'reconectar cliente'],
|
||||||
|
'status_topsapp': ['status topsapp', 'verificar topsapp', 'topsapp status', 'topsapp']
|
||||||
};
|
};
|
||||||
|
|
||||||
// Padrões de comandos
|
// Padrões de comandos
|
||||||
this.commandPatterns = [
|
this.commandPatterns = [
|
||||||
|
// Padrões específicos para TopSapp
|
||||||
|
/^(buscar|procurar|encontrar)\s+(cliente|user)\s+(.+)$/i,
|
||||||
|
/^(ver|mostrar)\s+(faturas?|boletos?|contas?)\s+(.+)$/i,
|
||||||
|
/^(gerar|criar|imprimir)\s+(boleto|pdf)\s+(.+)$/i,
|
||||||
|
/^(bloquear|suspender|cortar)\s+(cliente|user)\s+(.+)$/i,
|
||||||
|
/^(liberar|desbloquear|reconectar)\s+(cliente|user)\s+(.+)$/i,
|
||||||
|
/^(status|verificar)\s+(topsapp)$/i,
|
||||||
// Padrões específicos para ver sinal
|
// Padrões específicos para ver sinal
|
||||||
/^(ver|verificar|check)\s+(sinal|signal)\s+([A-Z0-9]+)$/i,
|
/^(ver|verificar|check)\s+(sinal|signal)\s+([A-Z0-9]+)$/i,
|
||||||
/^(sinal|signal)\s+([A-Z0-9]+)$/i,
|
/^(sinal|signal)\s+([A-Z0-9]+)$/i,
|
||||||
@@ -120,6 +133,76 @@ class NLPProcessor {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Detectar comandos TopSapp - buscar cliente
|
||||||
|
if (/buscar|procurar|encontrar/i.test(action) && /cliente|user/i.test(fullMatch)) {
|
||||||
|
let query = match[3] || match[2]; // Nome/CPF do cliente
|
||||||
|
|
||||||
|
return {
|
||||||
|
action: 'buscar_cliente',
|
||||||
|
target: query ? query.trim() : null,
|
||||||
|
confidence: 0.95,
|
||||||
|
type: 'topsapp_search_pattern'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detectar comandos TopSapp - ver faturas
|
||||||
|
if (/ver|mostrar/i.test(action) && /faturas?|boletos?|contas?/i.test(fullMatch)) {
|
||||||
|
let query = match[3] || match[2]; // ID/CPF do cliente
|
||||||
|
|
||||||
|
return {
|
||||||
|
action: 'ver_faturas',
|
||||||
|
target: query ? query.trim() : null,
|
||||||
|
confidence: 0.95,
|
||||||
|
type: 'topsapp_faturas_pattern'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detectar comandos TopSapp - gerar boleto
|
||||||
|
if (/gerar|criar|imprimir/i.test(action) && /boleto|pdf/i.test(fullMatch)) {
|
||||||
|
let faturaId = match[3] || match[2]; // ID da fatura
|
||||||
|
|
||||||
|
return {
|
||||||
|
action: 'gerar_boleto',
|
||||||
|
target: faturaId ? faturaId.trim() : null,
|
||||||
|
confidence: 0.95,
|
||||||
|
type: 'topsapp_boleto_pattern'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detectar comandos TopSapp - bloquear cliente
|
||||||
|
if (/bloquear|suspender|cortar/i.test(action) && /cliente|user/i.test(fullMatch)) {
|
||||||
|
let clienteId = match[3] || match[2]; // ID do cliente
|
||||||
|
|
||||||
|
return {
|
||||||
|
action: 'bloquear_cliente',
|
||||||
|
target: clienteId ? clienteId.trim() : null,
|
||||||
|
confidence: 0.95,
|
||||||
|
type: 'topsapp_block_pattern'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detectar comandos TopSapp - liberar cliente
|
||||||
|
if (/liberar|desbloquear|reconectar/i.test(action) && /cliente|user/i.test(fullMatch)) {
|
||||||
|
let clienteId = match[3] || match[2]; // ID do cliente
|
||||||
|
|
||||||
|
return {
|
||||||
|
action: 'liberar_cliente',
|
||||||
|
target: clienteId ? clienteId.trim() : null,
|
||||||
|
confidence: 0.95,
|
||||||
|
type: 'topsapp_unblock_pattern'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detectar comandos TopSapp - status
|
||||||
|
if (/status|verificar/i.test(action) && /topsapp/i.test(fullMatch)) {
|
||||||
|
return {
|
||||||
|
action: 'status_topsapp',
|
||||||
|
target: null,
|
||||||
|
confidence: 0.95,
|
||||||
|
type: 'topsapp_status_pattern'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Padrão específico para "sinal SERIAL"
|
// Padrão específico para "sinal SERIAL"
|
||||||
if (/sinal|signal/i.test(action)) {
|
if (/sinal|signal/i.test(action)) {
|
||||||
let serialNumber = match[2]; // Segundo grupo capturado
|
let serialNumber = match[2]; // Segundo grupo capturado
|
||||||
|
|||||||
@@ -0,0 +1,333 @@
|
|||||||
|
const axios = require('axios');
|
||||||
|
const https = require('https');
|
||||||
|
|
||||||
|
class TopSappAPI {
|
||||||
|
constructor() {
|
||||||
|
this.instances = {
|
||||||
|
'guarai_colmeia': {
|
||||||
|
baseURL: 'https://131.0.192.6:9910',
|
||||||
|
name: 'Guarai e Colmeia',
|
||||||
|
cities: ['guarai', 'colmeia']
|
||||||
|
},
|
||||||
|
'pedro_afonso': {
|
||||||
|
baseURL: 'https://45.189.140.18:9910',
|
||||||
|
name: 'Pedro Afonso',
|
||||||
|
cities: ['pedro afonso', 'pedro_afonso']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.sessions = new Map(); // Armazenar sessões ativas
|
||||||
|
|
||||||
|
// Configurar axios para ignorar certificados SSL auto-assinados
|
||||||
|
this.axiosConfig = {
|
||||||
|
httpsAgent: new https.Agent({
|
||||||
|
rejectUnauthorized: false
|
||||||
|
}),
|
||||||
|
timeout: 30000,
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('🔗 TopSappAPI inicializado');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determina qual instância usar baseada na cidade/região
|
||||||
|
*/
|
||||||
|
getInstanceByLocation(location = '') {
|
||||||
|
const loc = location.toLowerCase();
|
||||||
|
|
||||||
|
// Pedro Afonso
|
||||||
|
if (loc.includes('pedro') || loc.includes('afonso')) {
|
||||||
|
return this.instances.pedro_afonso;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Guarai e Colmeia (padrão)
|
||||||
|
return this.instances.guarai_colmeia;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Realizar login na API
|
||||||
|
*/
|
||||||
|
async login(instance, credentials) {
|
||||||
|
try {
|
||||||
|
console.log(`🔐 Fazendo login na instância: ${instance.name}`);
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('usuario', credentials.usuario);
|
||||||
|
formData.append('senha', credentials.senha);
|
||||||
|
formData.append('identificador', credentials.identificador || 'BotTelegram');
|
||||||
|
formData.append('idUsuario', credentials.idUsuario || '1');
|
||||||
|
|
||||||
|
const response = await axios.post(
|
||||||
|
`${instance.baseURL}/Login`,
|
||||||
|
formData,
|
||||||
|
this.axiosConfig
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.data && response.data.status === 'success') {
|
||||||
|
const sessionId = response.data.sessao;
|
||||||
|
this.sessions.set(instance.baseURL, {
|
||||||
|
sessionId,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
instance
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`✅ Login realizado com sucesso na instância: ${instance.name}`);
|
||||||
|
return { success: true, sessionId, instance };
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data?.message || 'Login falhou');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Erro no login da instância ${instance.name}:`, error.message);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
instance
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verificar se a sessão está válida
|
||||||
|
*/
|
||||||
|
isSessionValid(instanceURL) {
|
||||||
|
const session = this.sessions.get(instanceURL);
|
||||||
|
if (!session) return false;
|
||||||
|
|
||||||
|
// Sessão expira em 30 minutos
|
||||||
|
const thirtyMinutes = 30 * 60 * 1000;
|
||||||
|
return (Date.now() - session.timestamp) < thirtyMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter sessão válida ou fazer novo login
|
||||||
|
*/
|
||||||
|
async getValidSession(instance, credentials) {
|
||||||
|
if (this.isSessionValid(instance.baseURL)) {
|
||||||
|
return this.sessions.get(instance.baseURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
const loginResult = await this.login(instance, credentials);
|
||||||
|
if (loginResult.success) {
|
||||||
|
return this.sessions.get(instance.baseURL);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Não foi possível autenticar na instância ${instance.name}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fazer requisição autenticada para a API
|
||||||
|
*/
|
||||||
|
async makeRequest(endpoint, data = {}, instance, credentials) {
|
||||||
|
try {
|
||||||
|
const session = await this.getValidSession(instance, credentials);
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('sessao', session.sessionId);
|
||||||
|
|
||||||
|
// Adicionar parâmetros extras
|
||||||
|
Object.keys(data).forEach(key => {
|
||||||
|
if (data[key] !== undefined && data[key] !== null) {
|
||||||
|
formData.append(key, data[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`📡 Fazendo requisição para: ${instance.baseURL}/${endpoint}`);
|
||||||
|
|
||||||
|
const response = await axios.post(
|
||||||
|
`${instance.baseURL}/${endpoint}`,
|
||||||
|
formData,
|
||||||
|
this.axiosConfig
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.data && response.data.status === 'success') {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
data: response.data,
|
||||||
|
instance: instance.name
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
throw new Error(response.data?.message || 'Requisição falhou');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`❌ Erro na requisição ${endpoint}:`, error.message);
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
instance: instance.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buscar cliente por nome, CPF ou ID
|
||||||
|
*/
|
||||||
|
async buscarCliente(query, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation(location);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Tentar buscar por diferentes critérios
|
||||||
|
const searchParams = {};
|
||||||
|
|
||||||
|
// Se é número, pode ser CPF ou ID
|
||||||
|
if (/^\d+$/.test(query)) {
|
||||||
|
if (query.length === 11) {
|
||||||
|
searchParams.cpf = query;
|
||||||
|
} else {
|
||||||
|
searchParams.idCliente = query;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Buscar por nome
|
||||||
|
searchParams.nome = query;
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await this.makeRequest('ObterClientes', searchParams, instance, credentials);
|
||||||
|
|
||||||
|
if (result.success) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
clientes: result.data.clientes || [],
|
||||||
|
instance: result.instance
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message,
|
||||||
|
instance: instance.name
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter dados detalhados do cliente
|
||||||
|
*/
|
||||||
|
async obterDadosCliente(idCliente, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation(location);
|
||||||
|
|
||||||
|
return await this.makeRequest('ObterClientes', { idCliente }, instance, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter serviços do cliente
|
||||||
|
*/
|
||||||
|
async obterServicosCliente(idCliente, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation(location);
|
||||||
|
|
||||||
|
return await this.makeRequest('ObterClientesServicos', { idCliente }, instance, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter faturas em aberto do cliente
|
||||||
|
*/
|
||||||
|
async obterFaturas(idCliente, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation(location);
|
||||||
|
|
||||||
|
return await this.makeRequest('ObterDocReceber', {
|
||||||
|
idCliente,
|
||||||
|
situacao: 1 // Faturas em aberto
|
||||||
|
}, instance, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter dados para pagamento da fatura (linha digitável)
|
||||||
|
*/
|
||||||
|
async obterDadosFatura(idFatura, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation(location);
|
||||||
|
|
||||||
|
return await this.makeRequest('ObterDocReceberDadosFatura', { idFatura }, instance, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter boleto em Base64
|
||||||
|
*/
|
||||||
|
async obterBoletoBase64(idFatura, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation(location);
|
||||||
|
|
||||||
|
return await this.makeRequest('ObterDocReceberBase64', { idFatura }, instance, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alterar status do serviço (bloquear/liberar)
|
||||||
|
*/
|
||||||
|
async alterarStatusServico(idServico, status, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation(location);
|
||||||
|
|
||||||
|
// Status: 1 = Ativo, 2 = Bloqueado, 3 = Desativado
|
||||||
|
return await this.makeRequest('AlterarServicoStatus', {
|
||||||
|
idServico,
|
||||||
|
status
|
||||||
|
}, instance, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bloquear serviço do cliente
|
||||||
|
*/
|
||||||
|
async bloquearServico(idServico, location = '', credentials) {
|
||||||
|
return await this.alterarStatusServico(idServico, 2, location, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liberar serviço do cliente
|
||||||
|
*/
|
||||||
|
async liberarServico(idServico, location = '', credentials) {
|
||||||
|
return await this.alterarStatusServico(idServico, 1, location, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listar todas as instâncias disponíveis
|
||||||
|
*/
|
||||||
|
getInstances() {
|
||||||
|
return Object.values(this.instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converter Base64 para PDF
|
||||||
|
*/
|
||||||
|
convertBase64ToPDF(base64String, filename = 'boleto.pdf') {
|
||||||
|
try {
|
||||||
|
// Remove header se presente (data:application/pdf;base64,)
|
||||||
|
const base64Data = base64String.replace(/^data:application\/pdf;base64,/, '');
|
||||||
|
|
||||||
|
// Converte para buffer
|
||||||
|
const buffer = Buffer.from(base64Data, 'base64');
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
buffer,
|
||||||
|
filename,
|
||||||
|
mimeType: 'application/pdf'
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Limpar sessões expiradas
|
||||||
|
*/
|
||||||
|
clearExpiredSessions() {
|
||||||
|
const thirtyMinutes = 30 * 60 * 1000;
|
||||||
|
const now = Date.now();
|
||||||
|
|
||||||
|
for (const [instanceURL, session] of this.sessions.entries()) {
|
||||||
|
if ((now - session.timestamp) >= thirtyMinutes) {
|
||||||
|
this.sessions.delete(instanceURL);
|
||||||
|
console.log(`🧹 Sessão expirada removida: ${session.instance.name}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TopSappAPI;
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/**
|
||||||
|
* Configurações do TopSapp
|
||||||
|
*/
|
||||||
|
class TopSappConfig {
|
||||||
|
constructor() {
|
||||||
|
this.credentials = {
|
||||||
|
guarai_colmeia: {
|
||||||
|
usuario: process.env.TOPSAPP_GUARAI_USER || '',
|
||||||
|
senha: process.env.TOPSAPP_GUARAI_PASS || '',
|
||||||
|
identificador: process.env.TOPSAPP_GUARAI_ID || 'BotTelegram',
|
||||||
|
idUsuario: process.env.TOPSAPP_GUARAI_USERID || '1'
|
||||||
|
},
|
||||||
|
pedro_afonso: {
|
||||||
|
usuario: process.env.TOPSAPP_PEDRO_USER || '',
|
||||||
|
senha: process.env.TOPSAPP_PEDRO_PASS || '',
|
||||||
|
identificador: process.env.TOPSAPP_PEDRO_ID || 'BotTelegram',
|
||||||
|
idUsuario: process.env.TOPSAPP_PEDRO_USERID || '1'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.isConfigured = this.validateConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validar se as configurações estão completas
|
||||||
|
*/
|
||||||
|
validateConfiguration() {
|
||||||
|
const required = ['usuario', 'senha'];
|
||||||
|
|
||||||
|
for (const instance in this.credentials) {
|
||||||
|
const creds = this.credentials[instance];
|
||||||
|
for (const field of required) {
|
||||||
|
if (!creds[field]) {
|
||||||
|
console.warn(`⚠️ TopSapp: Campo ${field} não configurado para ${instance}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('✅ TopSapp: Configurações validadas');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter credenciais para uma instância
|
||||||
|
*/
|
||||||
|
getCredentials(instanceKey) {
|
||||||
|
return this.credentials[instanceKey] || null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter credenciais por localização
|
||||||
|
*/
|
||||||
|
getCredentialsByLocation(location = '') {
|
||||||
|
const loc = location.toLowerCase();
|
||||||
|
|
||||||
|
if (loc.includes('pedro') || loc.includes('afonso')) {
|
||||||
|
return this.credentials.pedro_afonso;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.credentials.guarai_colmeia;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verificar se o TopSapp está configurado
|
||||||
|
*/
|
||||||
|
isReady() {
|
||||||
|
return this.isConfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter status da configuração
|
||||||
|
*/
|
||||||
|
getStatus() {
|
||||||
|
const status = {};
|
||||||
|
|
||||||
|
for (const instance in this.credentials) {
|
||||||
|
const creds = this.credentials[instance];
|
||||||
|
status[instance] = {
|
||||||
|
configured: !!(creds.usuario && creds.senha),
|
||||||
|
usuario: creds.usuario ? '✅' : '❌',
|
||||||
|
senha: creds.senha ? '✅' : '❌'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TopSappConfig;
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
const TopSappAPI = require('./api');
|
||||||
|
const TopSappConfig = require('./config');
|
||||||
|
const TopSappManager = require('./manager');
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
TopSappAPI,
|
||||||
|
TopSappConfig,
|
||||||
|
TopSappManager
|
||||||
|
};
|
||||||
@@ -0,0 +1,372 @@
|
|||||||
|
const TopSappAPI = require('./api');
|
||||||
|
const TopSappConfig = require('./config');
|
||||||
|
const fs = require('fs').promises;
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
class TopSappManager {
|
||||||
|
constructor() {
|
||||||
|
this.api = new TopSappAPI();
|
||||||
|
this.config = new TopSappConfig();
|
||||||
|
|
||||||
|
// Limpar sessões expiradas a cada 10 minutos
|
||||||
|
setInterval(() => {
|
||||||
|
this.api.clearExpiredSessions();
|
||||||
|
}, 10 * 60 * 1000);
|
||||||
|
|
||||||
|
console.log('🎯 TopSappManager inicializado');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verificar se o TopSapp está configurado e pronto
|
||||||
|
*/
|
||||||
|
isReady() {
|
||||||
|
return this.config.isReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter status de configuração
|
||||||
|
*/
|
||||||
|
getConfigStatus() {
|
||||||
|
return this.config.getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Buscar cliente por nome, CPF ou ID
|
||||||
|
*/
|
||||||
|
async buscarCliente(query, location = '') {
|
||||||
|
if (!this.isReady()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'TopSapp não está configurado. Verifique as credenciais no arquivo .env'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const credentials = this.config.getCredentialsByLocation(location);
|
||||||
|
const result = await this.api.buscarCliente(query, location, credentials);
|
||||||
|
|
||||||
|
if (result.success && result.clientes) {
|
||||||
|
// Formatar resultados para melhor apresentação
|
||||||
|
const clientesFormatados = result.clientes.map(cliente => ({
|
||||||
|
id: cliente.id,
|
||||||
|
nome: cliente.nome,
|
||||||
|
cpf: cliente.cpf,
|
||||||
|
email: cliente.email,
|
||||||
|
telefone: cliente.telefone,
|
||||||
|
endereco: `${cliente.endereco}, ${cliente.numero} - ${cliente.bairro}`,
|
||||||
|
cidade: cliente.cidade,
|
||||||
|
status: cliente.status,
|
||||||
|
instancia: result.instance
|
||||||
|
}));
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
clientes: clientesFormatados,
|
||||||
|
total: clientesFormatados.length,
|
||||||
|
instancia: result.instance
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter dados completos do cliente
|
||||||
|
*/
|
||||||
|
async obterDadosCompletos(idCliente, location = '') {
|
||||||
|
if (!this.isReady()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'TopSapp não está configurado'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const credentials = this.config.getCredentialsByLocation(location);
|
||||||
|
|
||||||
|
// Buscar dados do cliente, serviços e faturas em paralelo
|
||||||
|
const [dadosCliente, servicos, faturas] = await Promise.all([
|
||||||
|
this.api.obterDadosCliente(idCliente, location, credentials),
|
||||||
|
this.api.obterServicosCliente(idCliente, location, credentials),
|
||||||
|
this.api.obterFaturas(idCliente, location, credentials)
|
||||||
|
]);
|
||||||
|
|
||||||
|
const resultado = {
|
||||||
|
success: true,
|
||||||
|
cliente: null,
|
||||||
|
servicos: [],
|
||||||
|
faturas: [],
|
||||||
|
instancia: location
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dadosCliente.success && dadosCliente.data.clientes) {
|
||||||
|
resultado.cliente = dadosCliente.data.clientes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (servicos.success && servicos.data.servicos) {
|
||||||
|
resultado.servicos = servicos.data.servicos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (faturas.success && faturas.data.faturas) {
|
||||||
|
resultado.faturas = faturas.data.faturas;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultado;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter boletos do cliente
|
||||||
|
*/
|
||||||
|
async obterBoletos(idCliente, location = '') {
|
||||||
|
if (!this.isReady()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'TopSapp não está configurado'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const credentials = this.config.getCredentialsByLocation(location);
|
||||||
|
const faturas = await this.api.obterFaturas(idCliente, location, credentials);
|
||||||
|
|
||||||
|
if (!faturas.success) {
|
||||||
|
return faturas;
|
||||||
|
}
|
||||||
|
|
||||||
|
const boletos = [];
|
||||||
|
|
||||||
|
for (const fatura of faturas.data.faturas || []) {
|
||||||
|
// Obter dados da fatura (linha digitável)
|
||||||
|
const dadosFatura = await this.api.obterDadosFatura(fatura.id, location, credentials);
|
||||||
|
|
||||||
|
const boleto = {
|
||||||
|
id: fatura.id,
|
||||||
|
valor: fatura.valor,
|
||||||
|
vencimento: fatura.vencimento,
|
||||||
|
status: fatura.status,
|
||||||
|
descricao: fatura.descricao,
|
||||||
|
linhaDigitavel: null
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dadosFatura.success && dadosFatura.data.linhaDigitavel) {
|
||||||
|
boleto.linhaDigitavel = dadosFatura.data.linhaDigitavel;
|
||||||
|
}
|
||||||
|
|
||||||
|
boletos.push(boleto);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
boletos,
|
||||||
|
total: boletos.length,
|
||||||
|
instancia: faturas.instance
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gerar PDF do boleto
|
||||||
|
*/
|
||||||
|
async gerarBoletoPDF(idFatura, location = '') {
|
||||||
|
if (!this.isReady()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'TopSapp não está configurado'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const credentials = this.config.getCredentialsByLocation(location);
|
||||||
|
const boletoBase64 = await this.api.obterBoletoBase64(idFatura, location, credentials);
|
||||||
|
|
||||||
|
if (!boletoBase64.success) {
|
||||||
|
return boletoBase64;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converter Base64 para PDF
|
||||||
|
const pdfResult = this.api.convertBase64ToPDF(
|
||||||
|
boletoBase64.data.arquivo,
|
||||||
|
`boleto_${idFatura}.pdf`
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pdfResult.success) {
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
filename: pdfResult.filename,
|
||||||
|
buffer: pdfResult.buffer,
|
||||||
|
mimeType: pdfResult.mimeType,
|
||||||
|
instancia: boletoBase64.instance
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return pdfResult;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Salvar PDF do boleto em arquivo
|
||||||
|
*/
|
||||||
|
async salvarBoletoPDF(idFatura, location = '', outputDir = './boletos') {
|
||||||
|
try {
|
||||||
|
const resultado = await this.gerarBoletoPDF(idFatura, location);
|
||||||
|
|
||||||
|
if (!resultado.success) {
|
||||||
|
return resultado;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Criar diretório se não existir
|
||||||
|
await fs.mkdir(outputDir, { recursive: true });
|
||||||
|
|
||||||
|
const filepath = path.join(outputDir, resultado.filename);
|
||||||
|
await fs.writeFile(filepath, resultado.buffer);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
filepath,
|
||||||
|
filename: resultado.filename,
|
||||||
|
instancia: resultado.instancia
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bloquear cliente
|
||||||
|
*/
|
||||||
|
async bloquearCliente(idCliente, location = '') {
|
||||||
|
if (!this.isReady()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'TopSapp não está configurado'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const credentials = this.config.getCredentialsByLocation(location);
|
||||||
|
|
||||||
|
// Obter serviços do cliente
|
||||||
|
const servicos = await this.api.obterServicosCliente(idCliente, location, credentials);
|
||||||
|
|
||||||
|
if (!servicos.success) {
|
||||||
|
return servicos;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultados = [];
|
||||||
|
|
||||||
|
// Bloquear todos os serviços ativos
|
||||||
|
for (const servico of servicos.data.servicos || []) {
|
||||||
|
if (servico.status === 1) { // Apenas serviços ativos
|
||||||
|
const resultado = await this.api.bloquearServico(servico.id, location, credentials);
|
||||||
|
resultados.push({
|
||||||
|
servicoId: servico.id,
|
||||||
|
descricao: servico.descricao,
|
||||||
|
resultado
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
servicosBloqueados: resultados,
|
||||||
|
total: resultados.length,
|
||||||
|
instancia: servicos.instance
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Liberar cliente
|
||||||
|
*/
|
||||||
|
async liberarCliente(idCliente, location = '') {
|
||||||
|
if (!this.isReady()) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: 'TopSapp não está configurado'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const credentials = this.config.getCredentialsByLocation(location);
|
||||||
|
|
||||||
|
// Obter serviços do cliente
|
||||||
|
const servicos = await this.api.obterServicosCliente(idCliente, location, credentials);
|
||||||
|
|
||||||
|
if (!servicos.success) {
|
||||||
|
return servicos;
|
||||||
|
}
|
||||||
|
|
||||||
|
const resultados = [];
|
||||||
|
|
||||||
|
// Liberar todos os serviços bloqueados
|
||||||
|
for (const servico of servicos.data.servicos || []) {
|
||||||
|
if (servico.status === 2) { // Apenas serviços bloqueados
|
||||||
|
const resultado = await this.api.liberarServico(servico.id, location, credentials);
|
||||||
|
resultados.push({
|
||||||
|
servicoId: servico.id,
|
||||||
|
descricao: servico.descricao,
|
||||||
|
resultado
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
servicosLiberados: resultados,
|
||||||
|
total: resultados.length,
|
||||||
|
instancia: servicos.instance
|
||||||
|
};
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
return {
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obter instâncias disponíveis
|
||||||
|
*/
|
||||||
|
getInstances() {
|
||||||
|
return this.api.getInstances();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TopSappManager;
|
||||||
Reference in new issue
Block a user