Add TopSapp preliminary support

Signed-off-by: Rodrigo B. de Sousa Martins <rodrigo.sousa.577@gmail.com>
This commit is contained in:
rodrigo committed 2025-08-08 18:40:39 -03:00
1 parent d4c37a3f78
commit 723ad8c268
10 files changed
+11952 -2

No files matched your search

+333
View File
@@ -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;
+90
View File
@@ -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;
+9
View File
@@ -0,0 +1,9 @@
const TopSappAPI = require('./api');
const TopSappConfig = require('./config');
const TopSappManager = require('./manager');
module.exports = {
TopSappAPI,
TopSappConfig,
TopSappManager
};
+372
View File
@@ -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;