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
@@ -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;
|
||||
Reference in new issue
Block a user