sgp - pedro afonso
This commit is contained in:
1 parent
ddf426fd5f
commit
828b6e7209
6 files changed
+3432
-2665
No files matched your search
+72
-60
@@ -1,60 +1,72 @@
|
|||||||
# Variáveis de ambiente
|
# Variáveis de ambiente
|
||||||
TELEGRAM_BOT_TOKEN=seu_token_do_bot_aqui
|
TELEGRAM_BOT_TOKEN=seu_token_do_bot_aqui
|
||||||
|
|
||||||
# Configurações SSH (exemplo)
|
# Configurações SSH (exemplo)
|
||||||
DEFAULT_SSH_HOST=192.168.1.1
|
DEFAULT_SSH_HOST=192.168.1.1
|
||||||
DEFAULT_SSH_USER=admin
|
DEFAULT_SSH_USER=admin
|
||||||
DEFAULT_SSH_PASSWORD=password
|
DEFAULT_SSH_PASSWORD=password
|
||||||
|
|
||||||
# Configurações do bot
|
# Configurações do bot
|
||||||
BOT_DEBUG=true
|
BOT_DEBUG=true
|
||||||
|
|
||||||
# IDs do Telegram com acesso a TODAS as cidades/provedores (admin)
|
# IDs do Telegram com acesso a TODAS as cidades/provedores (admin)
|
||||||
ALLOWED_USERS=123456789,987654321
|
ALLOWED_USERS=123456789,987654321
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# Acesso por cidade/provedor (IDs do Telegram, separados por vírgula)
|
# Acesso por cidade/provedor (IDs do Telegram, separados por vírgula)
|
||||||
# Um usuário pode estar em mais de uma lista; se estiver em mais de
|
# Um usuário pode estar em mais de uma lista; se estiver em mais de
|
||||||
# uma cidade, o bot exibirá um menu para escolher qual atender.
|
# uma cidade, o bot exibirá um menu para escolher qual atender.
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
GUARAI_ALLOWED_USERS=
|
GUARAI_ALLOWED_USERS=
|
||||||
PEDRO_AFONSO_ALLOWED_USERS=
|
PEDRO_AFONSO_ALLOWED_USERS=
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# Concentrador Juniper - Guaraí
|
# Concentrador Juniper - Guaraí
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
JUNIPER_GUARAI_HOST=131.0.192.254
|
JUNIPER_GUARAI_HOST=131.0.192.254
|
||||||
JUNIPER_GUARAI_USER=rodrigo
|
JUNIPER_GUARAI_USER=rodrigo
|
||||||
JUNIPER_GUARAI_PASS=
|
JUNIPER_GUARAI_PASS=
|
||||||
|
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
# Concentrador Juniper - Pedro Afonso
|
# Concentrador Juniper - Pedro Afonso
|
||||||
# ==========================================================
|
# ==========================================================
|
||||||
JUNIPER_PEDRO_AFONSO_HOST=45.189.140.2
|
JUNIPER_PEDRO_AFONSO_HOST=45.189.140.2
|
||||||
JUNIPER_PEDRO_AFONSO_USER=rodrigo
|
JUNIPER_PEDRO_AFONSO_USER=rodrigo
|
||||||
JUNIPER_PEDRO_AFONSO_PASS=
|
JUNIPER_PEDRO_AFONSO_PASS=
|
||||||
|
|
||||||
# Configurações TopSapp - Instância Guarai/Colmeia
|
# Configurações TopSapp - Instância Guarai/Colmeia
|
||||||
TOPSAPP_GUARAI_USER=seu_usuario_guarai
|
TOPSAPP_GUARAI_USER=seu_usuario_guarai
|
||||||
TOPSAPP_GUARAI_PASS=sua_senha_guarai
|
TOPSAPP_GUARAI_PASS=sua_senha_guarai
|
||||||
|
|
||||||
# Configurações TopSapp - Instância Pedro Afonso
|
# Configurações SGP - Pedro Afonso (substitui o TopSapp nesta cidade)
|
||||||
TOPSAPP_PEDRO_AFONSO_USER=seu_usuario_pedro_afonso
|
# Autenticação: app + token (Sistema -> Ferramentas -> Painel Admin -> Tokens)
|
||||||
TOPSAPP_PEDRO_AFONSO_PASS=sua_senha_pedro_afonso
|
# ou, alternativamente, usuário + senha do SGP (Basic Auth)
|
||||||
|
SGP_PEDRO_AFONSO_URL=https://seu-sgp.exemplo.com.br
|
||||||
# ==========================================================
|
SGP_PEDRO_AFONSO_APP=nome_da_aplicacao
|
||||||
# Configurações GenieACS (TR-069 ACS)
|
SGP_PEDRO_AFONSO_TOKEN=token_da_aplicacao
|
||||||
# Porta padrão NBI: 7557
|
#SGP_PEDRO_AFONSO_USER=
|
||||||
# ==========================================================
|
#SGP_PEDRO_AFONSO_PASS=
|
||||||
|
# Opcional: id da OLT no SGP -> id_ap legado (2 = Pedro Afonso, 4 = Canavieiras).
|
||||||
# Instância Guarai - Clicknet
|
# Se omitido, é deduzido pelo nome da OLT no SGP.
|
||||||
GENIEACS_GUARAI_URL=http://g.clicknetto.com.br
|
#SGP_PEDRO_AFONSO_OLT_MAP=12:2,15:4
|
||||||
GENIEACS_GUARAI_NBI_PORT=7557
|
# Opcional: ids de status de contrato do SGP (padrão: 1 = Ativo, 4 = Suspenso)
|
||||||
GENIEACS_GUARAI_USER=api
|
#SGP_STATUS_ATIVO=1
|
||||||
GENIEACS_GUARAI_PASS=sua_senha_genieacs_guarai
|
#SGP_STATUS_BLOQUEADO=4
|
||||||
|
#SGP_INSECURE_TLS=false
|
||||||
# Exemplo de nova instância futura:
|
|
||||||
# GENIEACS_PEDRO_AFONSO_URL=http://genieacs.exemplo.com.br
|
# ==========================================================
|
||||||
# GENIEACS_PEDRO_AFONSO_NBI_PORT=7557
|
# Configurações GenieACS (TR-069 ACS)
|
||||||
# GENIEACS_PEDRO_AFONSO_USER=api
|
# Porta padrão NBI: 7557
|
||||||
# GENIEACS_PEDRO_AFONSO_PASS=sua_senha
|
# ==========================================================
|
||||||
|
|
||||||
|
# Instância Guarai - Clicknet
|
||||||
|
GENIEACS_GUARAI_URL=http://g.clicknetto.com.br
|
||||||
|
GENIEACS_GUARAI_NBI_PORT=7557
|
||||||
|
GENIEACS_GUARAI_USER=api
|
||||||
|
GENIEACS_GUARAI_PASS=sua_senha_genieacs_guarai
|
||||||
|
|
||||||
|
# Exemplo de nova instância futura:
|
||||||
|
# GENIEACS_PEDRO_AFONSO_URL=http://genieacs.exemplo.com.br
|
||||||
|
# GENIEACS_PEDRO_AFONSO_NBI_PORT=7557
|
||||||
|
# GENIEACS_PEDRO_AFONSO_USER=api
|
||||||
|
# GENIEACS_PEDRO_AFONSO_PASS=sua_senha
|
||||||
@@ -6899,6 +6899,10 @@ Digite /help para ver todos os comandos disponíveis!
|
|||||||
|
|
||||||
dadosSuporte.outrasInformacoes = `Criado via Bot Telegram\nData original: ${dados.dataHoraTexto}`;
|
dadosSuporte.outrasInformacoes = `Criado via Bot Telegram\nData original: ${dados.dataHoraTexto}`;
|
||||||
|
|
||||||
|
// Usados pelo SGP (técnico responsável e agendamento são definidos na abertura do chamado)
|
||||||
|
dadosSuporte.idTecnico = dados.tecnicoSelecionado?.id;
|
||||||
|
dadosSuporte.dataHoraAgendamento = dados.dataHora;
|
||||||
|
|
||||||
const resultado = await this.topsapp.adicionarSuporte(dadosSuporte, location);
|
const resultado = await this.topsapp.adicionarSuporte(dadosSuporte, location);
|
||||||
|
|
||||||
if (resultado.success) {
|
if (resultado.success) {
|
||||||
|
|||||||
+718
@@ -0,0 +1,718 @@
|
|||||||
|
const axios = require('axios');
|
||||||
|
const https = require('https');
|
||||||
|
const logger = require('../utils/logger');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cliente da API do SGP (https://documenter.getpostman.com/view/6682240/2sB34hHg2V).
|
||||||
|
*
|
||||||
|
* Expõe a mesma superfície que o TopSappAPI usa no TopSappManager e devolve os
|
||||||
|
* dados no mesmo formato ({ success, data: { dados: [...] }, instance }), de
|
||||||
|
* modo que o restante do bot não precise saber qual sistema está por trás.
|
||||||
|
*
|
||||||
|
* Convenções de mapeamento:
|
||||||
|
* - idCliente -> id do cliente no SGP
|
||||||
|
* - id_servico -> id do CONTRATO no SGP (bloqueio/liberação são feitos por contrato)
|
||||||
|
* - id da fatura -> id do título no SGP
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Status de contrato no SGP (documentação pública)
|
||||||
|
const SGP_STATUS_ATIVO = parseInt(process.env.SGP_STATUS_ATIVO || '1', 10);
|
||||||
|
const SGP_STATUS_BLOQUEADO = parseInt(process.env.SGP_STATUS_BLOQUEADO || '4', 10); // Suspenso
|
||||||
|
|
||||||
|
class SgpAPI {
|
||||||
|
constructor() {
|
||||||
|
this.instances = {
|
||||||
|
pedro_afonso: {
|
||||||
|
key: 'pedro_afonso',
|
||||||
|
name: 'Pedro Afonso (SGP)',
|
||||||
|
cities: ['pedro afonso', 'pedro_afonso']
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.httpsAgent = new https.Agent({
|
||||||
|
rejectUnauthorized: process.env.SGP_INSECURE_TLS !== 'true'
|
||||||
|
});
|
||||||
|
this.tituloCache = new Map(); // id título -> { at, titulo }
|
||||||
|
this.tecnicoCache = new Map(); // id técnico -> username
|
||||||
|
|
||||||
|
console.log('🔗 SgpAPI inicializado');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ infra
|
||||||
|
|
||||||
|
getInstanceByLocation() {
|
||||||
|
return this.instances.pedro_afonso;
|
||||||
|
}
|
||||||
|
|
||||||
|
getInstances() {
|
||||||
|
return Object.values(this.instances);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearExpiredSessions() {
|
||||||
|
const now = Date.now();
|
||||||
|
for (const [id, entry] of this.tituloCache.entries()) {
|
||||||
|
if (now - entry.at > 2 * 60 * 1000) this.tituloCache.delete(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_name(credentials) {
|
||||||
|
return this.getInstanceByLocation().name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requisição genérica ao SGP. Autentica com token+app (corpo/query) ou Basic Auth.
|
||||||
|
*/
|
||||||
|
async _request(credentials, method, path, params = {}) {
|
||||||
|
if (!credentials || !credentials.baseURL) {
|
||||||
|
throw new Error('SGP não configurado (URL ausente)');
|
||||||
|
}
|
||||||
|
|
||||||
|
const clean = {};
|
||||||
|
Object.keys(params).forEach(k => {
|
||||||
|
if (params[k] !== undefined && params[k] !== null && params[k] !== '') clean[k] = params[k];
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
method,
|
||||||
|
url: `${credentials.baseURL.replace(/\/$/, '')}${path}`,
|
||||||
|
httpsAgent: this.httpsAgent,
|
||||||
|
timeout: 30000
|
||||||
|
};
|
||||||
|
|
||||||
|
if (credentials.app && credentials.token) {
|
||||||
|
clean.app = credentials.app;
|
||||||
|
clean.token = credentials.token;
|
||||||
|
} else if (credentials.usuario && credentials.senha) {
|
||||||
|
config.auth = { username: credentials.usuario, password: credentials.senha };
|
||||||
|
} else {
|
||||||
|
throw new Error('SGP sem credenciais (app/token ou usuário/senha)');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method === 'GET') {
|
||||||
|
config.params = clean;
|
||||||
|
} else {
|
||||||
|
const body = new URLSearchParams();
|
||||||
|
Object.keys(clean).forEach(k => body.append(k, String(clean[k])));
|
||||||
|
config.data = body.toString();
|
||||||
|
config.headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios(config);
|
||||||
|
return response.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Envolve uma chamada no formato { success, data, instance } / { success:false, error }
|
||||||
|
*/
|
||||||
|
async _wrap(credentials, fn) {
|
||||||
|
try {
|
||||||
|
const data = await fn();
|
||||||
|
return { success: true, data, instance: this._name(credentials) };
|
||||||
|
} catch (error) {
|
||||||
|
const body = error.response?.data;
|
||||||
|
const msg = (body && (body.msg || body.mensagem || body.detail || body.message || body.erro))
|
||||||
|
|| error.message;
|
||||||
|
logger.warn('Erro na API SGP', { error: msg, status: error.response?.status });
|
||||||
|
console.error(`❌ Erro SGP: ${msg}`);
|
||||||
|
return { success: false, error: typeof msg === 'string' ? msg : JSON.stringify(msg), instance: this._name(credentials) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------- helpers
|
||||||
|
|
||||||
|
_formatarData(data) {
|
||||||
|
if (!data) return '';
|
||||||
|
const m = String(data).match(/^(\d{4})-(\d{2})-(\d{2})/);
|
||||||
|
return m ? `${m[3]}/${m[2]}/${m[1]}` : String(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
_statusId(texto) {
|
||||||
|
const t = String(texto || '').toLowerCase()
|
||||||
|
.normalize('NFD').replace(/[̀-ͯ]/g, '').trim();
|
||||||
|
if (/^ativo/.test(t)) return 1;
|
||||||
|
if (/suspens|bloquead/.test(t)) return 2;
|
||||||
|
if (/cancelad|inativ|desativ/.test(t)) return 3;
|
||||||
|
return 5; // aguardando / inviabilidade / outros
|
||||||
|
}
|
||||||
|
|
||||||
|
_textoStatus(idStatus) {
|
||||||
|
switch (idStatus) {
|
||||||
|
case 1: return 'liberado';
|
||||||
|
case 2: return 'bloqueado';
|
||||||
|
case 3: return 'desativado';
|
||||||
|
default: return 'desconhecido';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** id_ap legado (2 = Pedro Afonso, 4 = Canavieiras) a partir da OLT do SGP */
|
||||||
|
_idApLegado(onu) {
|
||||||
|
if (!onu) return '';
|
||||||
|
const mapa = {};
|
||||||
|
(process.env.SGP_PEDRO_AFONSO_OLT_MAP || '').split(',').forEach(par => {
|
||||||
|
const [sgpId, legado] = par.split(':').map(s => s && s.trim());
|
||||||
|
if (sgpId && legado) mapa[sgpId] = legado;
|
||||||
|
});
|
||||||
|
if (onu.olt_id !== undefined && mapa[String(onu.olt_id)]) return mapa[String(onu.olt_id)];
|
||||||
|
const nome = String(onu.olt_nome || '').toLowerCase();
|
||||||
|
if (/canavieiras/.test(nome)) return '4';
|
||||||
|
if (/pedro|afonso/.test(nome)) return '2';
|
||||||
|
return onu.olt_id !== undefined ? String(onu.olt_id) : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
_clienteId(c) {
|
||||||
|
return c.id ?? c.clienteId ?? c.cliente_id ?? c.idCliente ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_mapCliente(c) {
|
||||||
|
const contratos = c.contratos || [];
|
||||||
|
const ativo = contratos.some(ct => this._statusId(ct.status) === 1);
|
||||||
|
const contatos = c.contatos || c.telefones || [];
|
||||||
|
const primeiroContato = Array.isArray(contatos) && contatos.length
|
||||||
|
? (typeof contatos[0] === 'string' ? contatos[0] : (contatos[0].contato || contatos[0].numero || ''))
|
||||||
|
: '';
|
||||||
|
const end = c.endereco || {};
|
||||||
|
return {
|
||||||
|
id: this._clienteId(c),
|
||||||
|
nome: c.nome,
|
||||||
|
cpf: c.cpfcnpj || '',
|
||||||
|
cpfCnpj: c.cpfcnpj || '',
|
||||||
|
email: c.email || (Array.isArray(c.emails) ? c.emails[0] : '') || '',
|
||||||
|
telefone: c.telefone || c.celular || primeiroContato,
|
||||||
|
celular: c.celular || c.telefone || primeiroContato,
|
||||||
|
endereco: end.logradouro || '',
|
||||||
|
numero: end.numero || '',
|
||||||
|
bairro: end.bairro || '',
|
||||||
|
cidade: end.cidade || '',
|
||||||
|
uf: end.uf || '',
|
||||||
|
cep: end.cep || '',
|
||||||
|
complemento: end.complemento || '',
|
||||||
|
observacoes: c.observacao_cliente || '',
|
||||||
|
data_cadastro: c.dataCadastro || '',
|
||||||
|
status: ativo ? 1 : 0,
|
||||||
|
statusOriginal: contratos.map(ct => ct.status).join(', '),
|
||||||
|
id_status: ativo ? 1 : 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
_mapServicos(c) {
|
||||||
|
const idCliente = this._clienteId(c);
|
||||||
|
const end = c.endereco || {};
|
||||||
|
const out = [];
|
||||||
|
|
||||||
|
(c.contratos || []).forEach(ct => {
|
||||||
|
const idStatus = this._statusId(ct.status);
|
||||||
|
(ct.servicos && ct.servicos.length ? ct.servicos : [{}]).forEach(srv => {
|
||||||
|
const onu = srv.onu || {};
|
||||||
|
const conexao = onu.conexao || srv.conexao || {};
|
||||||
|
const e = srv.endereco || end;
|
||||||
|
out.push({
|
||||||
|
id: ct.contrato,
|
||||||
|
id_servico: ct.contrato,
|
||||||
|
servico_id: srv.id,
|
||||||
|
id_cliente: idCliente,
|
||||||
|
idCliente,
|
||||||
|
descricao: srv.plano?.descricao || srv.tipo || 'Serviço',
|
||||||
|
nome: srv.plano?.descricao || srv.tipo || 'Serviço',
|
||||||
|
plano_nome: srv.plano?.descricao || '',
|
||||||
|
tipo_servico: srv.tipo || '',
|
||||||
|
id_status: idStatus,
|
||||||
|
status: this._textoStatus(idStatus),
|
||||||
|
motivo_status: ct.motivo_status || '',
|
||||||
|
data_cadastro: ct.dataCadastro || '',
|
||||||
|
|
||||||
|
usuario: srv.login || onu.login || '',
|
||||||
|
login: srv.login || onu.login || '',
|
||||||
|
pppoe_login: srv.login || '',
|
||||||
|
senha: srv.senha || '',
|
||||||
|
ip: srv.ip || '',
|
||||||
|
mac: srv.mac || '',
|
||||||
|
|
||||||
|
// Dados do cliente (o TopSapp os devolvia embutidos no serviço)
|
||||||
|
instalacao_nome: c.nome,
|
||||||
|
cpf: c.cpfcnpj || '',
|
||||||
|
instalacao_endereco: e.logradouro || '',
|
||||||
|
instalacao_numero: e.numero || '',
|
||||||
|
instalacao_bairro: e.bairro || '',
|
||||||
|
instalacao_cidade: e.cidade || '',
|
||||||
|
instalacao_uf: e.uf || '',
|
||||||
|
instalacao_cep: e.cep || '',
|
||||||
|
instalacao_complemento: e.complemento || '',
|
||||||
|
latitude: e.latitude || '',
|
||||||
|
longitude: e.longitude || '',
|
||||||
|
|
||||||
|
// FTTH
|
||||||
|
tecnologia: 'FTTH',
|
||||||
|
base: onu.olt_nome || '',
|
||||||
|
id_ap: this._idApLegado(onu),
|
||||||
|
id_olt_sgp: onu.olt_id,
|
||||||
|
pon: onu.pon !== undefined ? `${onu.slot ?? ''}/${onu.pon}` : '',
|
||||||
|
perfil: '',
|
||||||
|
serial: onu.serial || '',
|
||||||
|
serviceport: '',
|
||||||
|
ultimo_rx_power: onu.rx || '',
|
||||||
|
ultimo_tx_power: onu.tx || '',
|
||||||
|
data_ultimo_sinal: '',
|
||||||
|
hora_ultimo_sinal: '',
|
||||||
|
conexao: conexao.status || '',
|
||||||
|
ultimo_acesso: conexao.data_conexao || '',
|
||||||
|
ultimo_ip: conexao.ip || '',
|
||||||
|
|
||||||
|
dhcp_username: '',
|
||||||
|
dhcp_agent_circuit_id: '',
|
||||||
|
dhcp_client_id: '',
|
||||||
|
dhcp_liberar: undefined
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
async _listarClientes(credentials, params) {
|
||||||
|
const todos = [];
|
||||||
|
let offset = 0;
|
||||||
|
for (let pagina = 0; pagina < 20; pagina++) {
|
||||||
|
const data = await this._request(credentials, 'POST', '/api/ura/clientes/', {
|
||||||
|
omitir_titulos: 1,
|
||||||
|
limit: 100,
|
||||||
|
offset,
|
||||||
|
...params
|
||||||
|
});
|
||||||
|
const lote = data.clientes || [];
|
||||||
|
todos.push(...lote);
|
||||||
|
const total = data.paginacao?.total ?? lote.length;
|
||||||
|
offset += lote.length;
|
||||||
|
if (lote.length === 0 || offset >= total) break;
|
||||||
|
}
|
||||||
|
return todos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------------------------------------------------------------- clientes
|
||||||
|
|
||||||
|
async buscarCliente(query, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation();
|
||||||
|
try {
|
||||||
|
const q = String(query || '').trim();
|
||||||
|
const params = {};
|
||||||
|
const digitos = q.replace(/\D/g, '');
|
||||||
|
|
||||||
|
if (/^\d+$/.test(q) && q.length !== 11 && q.length !== 14) {
|
||||||
|
params.cliente_id = parseInt(q, 10);
|
||||||
|
} else if (digitos.length === 11 || digitos.length === 14) {
|
||||||
|
params.cpfcnpj = digitos;
|
||||||
|
} else {
|
||||||
|
params.cliente_nome = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`🔍 [SGP] Buscando cliente:`, params);
|
||||||
|
const clientes = await this._listarClientes(credentials, params);
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
clientes: clientes.map(c => this._mapCliente(c)),
|
||||||
|
instance: instance.name
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ [SGP] Erro na busca de cliente:', error.message);
|
||||||
|
return { success: false, error: error.response?.data?.msg || error.message, instance: instance.name };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterServicosCliente(idCliente, location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const id = parseInt(idCliente, 10);
|
||||||
|
if (isNaN(id)) throw new Error(`ID do cliente inválido: ${idCliente}`);
|
||||||
|
const clientes = await this._listarClientes(credentials, { cliente_id: id });
|
||||||
|
const dados = [];
|
||||||
|
clientes.forEach(c => dados.push(...this._mapServicos({ ...c, id: this._clienteId(c) ?? id })));
|
||||||
|
return { dados };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterDadosCompletosCliente(idCliente, location = '', credentials) {
|
||||||
|
const instance = this.getInstanceByLocation();
|
||||||
|
try {
|
||||||
|
const id = parseInt(idCliente, 10);
|
||||||
|
const clientes = await this._listarClientes(credentials, { cliente_id: id });
|
||||||
|
if (!clientes.length) {
|
||||||
|
return { success: false, error: 'Cliente não encontrado', instance: instance.name };
|
||||||
|
}
|
||||||
|
const c = { ...clientes[0], id: this._clienteId(clientes[0]) ?? id };
|
||||||
|
const cliente = this._mapCliente(c);
|
||||||
|
const primeiro = this._mapServicos(c)[0] || {};
|
||||||
|
cliente.latitude = primeiro.latitude || '';
|
||||||
|
cliente.longitude = primeiro.longitude || '';
|
||||||
|
return { success: true, cliente, instance: instance.name, fonte: 'sgp' };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.response?.data?.msg || error.message, instance: instance.name };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterDadosCliente(idCliente, location = '', credentials) {
|
||||||
|
const r = await this.obterDadosCompletosCliente(idCliente, location, credentials);
|
||||||
|
if (!r.success) return r;
|
||||||
|
return { success: true, data: { clientes: [r.cliente] }, instance: r.instance };
|
||||||
|
}
|
||||||
|
|
||||||
|
interpretarStatusCliente(cliente) {
|
||||||
|
return cliente.status === 1 || cliente.id_status === 1 ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
interpretarStatusServico(servico) {
|
||||||
|
return servico.id_status || this._statusId(servico.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
obterTextoStatus(idStatus) {
|
||||||
|
return this._textoStatus(parseInt(idStatus, 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------- faturas
|
||||||
|
|
||||||
|
_mapTitulo(t, idCliente = null) {
|
||||||
|
const pago = t.status === 'pago' || !!t.dataPagamento;
|
||||||
|
return {
|
||||||
|
id: t.id,
|
||||||
|
valor: t.valorCorrigido ?? t.valor,
|
||||||
|
valor_original: t.valor,
|
||||||
|
vencimento: this._formatarData(t.dataVencimento),
|
||||||
|
pago: pago ? 'SIM' : 'NAO',
|
||||||
|
historico: t.demonstrativo || `Fatura ${t.numeroDocumento || t.id}`,
|
||||||
|
descricao: t.demonstrativo || 'Mensalidade',
|
||||||
|
periodo_inicio: '',
|
||||||
|
periodo_fim: '',
|
||||||
|
codigo_cliente: idCliente,
|
||||||
|
id_servico: t.clienteContrato,
|
||||||
|
numero_documento: t.numeroDocumento,
|
||||||
|
link: t.link,
|
||||||
|
linha_digitavel: t.linhaDigitavel || '',
|
||||||
|
codigo_barras: t.codigoBarras || '',
|
||||||
|
qrcode: t.codigoPix || ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterFaturas(idCliente, location = '', credentials, idServico = null) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const params = { status: 'abertos' };
|
||||||
|
if (idCliente) params.cliente_id = parseInt(idCliente, 10);
|
||||||
|
if (idServico) params.contrato = parseInt(idServico, 10);
|
||||||
|
|
||||||
|
const dados = [];
|
||||||
|
let offset = 0;
|
||||||
|
for (let pagina = 0; pagina < 20; pagina++) {
|
||||||
|
const data = await this._request(credentials, 'POST', '/api/ura/titulos/', {
|
||||||
|
...params, limit: 250, offset
|
||||||
|
});
|
||||||
|
const lote = data.titulos || [];
|
||||||
|
lote.forEach(t => {
|
||||||
|
this.tituloCache.set(String(t.id), { at: Date.now(), titulo: t });
|
||||||
|
dados.push(this._mapTitulo(t, idCliente));
|
||||||
|
});
|
||||||
|
const total = data.paginacao?.total ?? lote.length;
|
||||||
|
offset += lote.length;
|
||||||
|
if (lote.length === 0 || offset >= total) break;
|
||||||
|
}
|
||||||
|
return { dados };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async _obterTitulo(idFatura, credentials) {
|
||||||
|
const cached = this.tituloCache.get(String(idFatura));
|
||||||
|
if (cached && Date.now() - cached.at < 2 * 60 * 1000) return cached.titulo;
|
||||||
|
|
||||||
|
const data = await this._request(credentials, 'POST', '/api/ura/titulos/', {
|
||||||
|
titulo_id: parseInt(idFatura, 10)
|
||||||
|
});
|
||||||
|
const titulo = (data.titulos || [])[0];
|
||||||
|
if (!titulo) throw new Error('Fatura não encontrada');
|
||||||
|
this.tituloCache.set(String(idFatura), { at: Date.now(), titulo });
|
||||||
|
return titulo;
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterDadosFatura(idFatura, idCliente, location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const titulo = await this._obterTitulo(idFatura, credentials);
|
||||||
|
const f = this._mapTitulo(titulo, idCliente);
|
||||||
|
return { fatura: f };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Baixa o boleto em PDF e devolve em Base64 (mesmo contrato do TopSapp).
|
||||||
|
*/
|
||||||
|
async obterBoletoBase64(idFatura, location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const titulo = await this._obterTitulo(idFatura, credentials);
|
||||||
|
let link = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const seg = await this._request(credentials, 'POST', '/api/ura/fatura2via/', {
|
||||||
|
contrato: titulo.clienteContrato,
|
||||||
|
numero_documento: titulo.numeroDocumento,
|
||||||
|
link_pdf: 1,
|
||||||
|
nao_gerar_os: 1
|
||||||
|
});
|
||||||
|
link = (seg.links || []).find(l => String(l.fatura) === String(idFatura))?.link || seg.link;
|
||||||
|
} catch (error) {
|
||||||
|
logger.warn('SGP fatura2via falhou, usando link do título', { error: error.message });
|
||||||
|
}
|
||||||
|
link = link || titulo.link;
|
||||||
|
if (!link) throw new Error('Boleto sem link disponível');
|
||||||
|
|
||||||
|
const resp = await axios.get(link, {
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
httpsAgent: this.httpsAgent,
|
||||||
|
timeout: 30000
|
||||||
|
});
|
||||||
|
const tipo = String(resp.headers['content-type'] || '');
|
||||||
|
if (!/pdf/i.test(tipo)) throw new Error(`O link do boleto não retornou PDF (${tipo || 'desconhecido'}): ${link}`);
|
||||||
|
|
||||||
|
return { arquivo: Buffer.from(resp.data).toString('base64'), link };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
convertBase64ToPDF(base64String, filename = 'boleto.pdf') {
|
||||||
|
try {
|
||||||
|
const base64Data = base64String.replace(/^data:application\/pdf;base64,/, '');
|
||||||
|
return { success: true, buffer: Buffer.from(base64Data, 'base64'), filename, mimeType: 'application/pdf' };
|
||||||
|
} catch (error) {
|
||||||
|
return { success: false, error: error.message };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------ bloqueio/liberação
|
||||||
|
|
||||||
|
async _alterarStatusContrato(idContrato, status, credentials) {
|
||||||
|
return this._wrap(credentials, () => this._request(credentials, 'POST', '/api/ura/contrato/status/edit/', {
|
||||||
|
contrato: parseInt(idContrato, 10),
|
||||||
|
status
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
async alterarStatusServico(idServico, idCliente, status, location = '', credentials) {
|
||||||
|
// status no formato TopSapp: 1 = ativo, 2 = bloqueado
|
||||||
|
return this._alterarStatusContrato(idServico, status === 1 ? SGP_STATUS_ATIVO : SGP_STATUS_BLOQUEADO, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
async bloquearServico(idServico, idCliente, location = '', credentials) {
|
||||||
|
return this._alterarStatusContrato(idServico, SGP_STATUS_BLOQUEADO, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
async liberarServico(idServico, idCliente, location = '', credentials) {
|
||||||
|
return this._alterarStatusContrato(idServico, SGP_STATUS_ATIVO, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------- suporte
|
||||||
|
|
||||||
|
async obterTecnicos(location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const lista = await this._request(credentials, 'POST', '/api/ura/tecnicos/');
|
||||||
|
(lista || []).forEach(t => this.tecnicoCache.set(String(t.id), t.username));
|
||||||
|
return { dados: (lista || []).map(t => ({ id: t.id, nome: t.nome, username: t.username })) };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Equivalente aos "operadores" do TopSapp: o bot só usa id_tecnico e tecnico */
|
||||||
|
async obterOperadores(location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const lista = await this._request(credentials, 'POST', '/api/ura/tecnicos/');
|
||||||
|
(lista || []).forEach(t => this.tecnicoCache.set(String(t.id), t.username));
|
||||||
|
return { dados: (lista || []).map(t => ({ id: t.id, id_tecnico: t.id, tecnico: t.nome, username: t.username })) };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterFuncionarios(location = '', credentials) {
|
||||||
|
return this.obterTecnicos(location, credentials);
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterSuporteCategorias(location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const lista = await this._request(credentials, 'GET', '/api/os/ocorrencia/tipo/list/');
|
||||||
|
// "ocorrenciatipo" do chamado usa o código do tipo
|
||||||
|
return { dados: (lista || []).map(t => ({ id: t.codigo ?? t.id, descricao: t.descricao })) };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterSuporteTiposAtendimento(location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const lista = await this._request(credentials, 'GET', '/api/ura/ocorrencia/metodo/list/');
|
||||||
|
return { dados: (lista || []).map(m => ({ id: m.codigo, descricao: m.descricao })) };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abre chamado (ocorrência + O.S.). idServico = contrato.
|
||||||
|
*/
|
||||||
|
async adicionarSuporte(dadosSuporte, location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const params = {
|
||||||
|
contrato: parseInt(dadosSuporte.idServico, 10),
|
||||||
|
conteudo: dadosSuporte.descricao,
|
||||||
|
conteudolimpo: 1,
|
||||||
|
ocorrenciatipo: dadosSuporte.idCategoria,
|
||||||
|
observacao: dadosSuporte.outrasInformacoes,
|
||||||
|
contato_nome: dadosSuporte.contato,
|
||||||
|
contato_telefone: dadosSuporte.contatoTelefone
|
||||||
|
};
|
||||||
|
|
||||||
|
if (dadosSuporte.idTecnico) {
|
||||||
|
const username = this.tecnicoCache.get(String(dadosSuporte.idTecnico));
|
||||||
|
if (username) params.responsavel = username;
|
||||||
|
}
|
||||||
|
if (dadosSuporte.dataHoraAgendamento) {
|
||||||
|
const d = new Date(dadosSuporte.dataHoraAgendamento);
|
||||||
|
if (!isNaN(d.getTime())) {
|
||||||
|
const p = n => String(n).padStart(2, '0');
|
||||||
|
params.data_hora_agendamento = `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await this._request(credentials, 'POST', '/api/ura/chamado/', params);
|
||||||
|
if (data.status !== undefined && Number(data.status) !== 1) {
|
||||||
|
throw new Error(data.msg || 'Não foi possível abrir o chamado');
|
||||||
|
}
|
||||||
|
return { protocolo: data.protocolo, ...data };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* O técnico já é definido na abertura do chamado (campo "responsavel").
|
||||||
|
*/
|
||||||
|
async encaminharSuporte(idSuporte, idTecnico, descricao, location = '', credentials) {
|
||||||
|
return { success: true, data: { msg: 'Técnico definido na abertura do chamado' }, instance: this._name(credentials) };
|
||||||
|
}
|
||||||
|
|
||||||
|
async obterSuportesAbertos(idCliente, location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const lista = await this._request(credentials, 'POST', '/api/os/list/', {
|
||||||
|
cliente_id: parseInt(idCliente, 10)
|
||||||
|
});
|
||||||
|
const dados = (lista || [])
|
||||||
|
.filter(os => Number(os.os_status) !== 1 && !os.os_data_finalizacao)
|
||||||
|
.map(os => ({
|
||||||
|
id: os.os_id,
|
||||||
|
protocolo: os.os_protocolo,
|
||||||
|
defeito: os.os_conteudo || os.os_motivo_descricao || '',
|
||||||
|
endereco: os.endereco_logradouro || '',
|
||||||
|
numero: os.endereco_numero || '',
|
||||||
|
bairro: os.endereco_bairro || '',
|
||||||
|
cidade: os.endereco_cidade || '',
|
||||||
|
data: os.os_data_agendamento || os.os_data_cadastro || ''
|
||||||
|
}));
|
||||||
|
return { dados };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async finalizarSuporte(idSuporte, descricao, location = '', credentials) {
|
||||||
|
return this._wrap(credentials, () => {
|
||||||
|
const d = new Date();
|
||||||
|
const p = n => String(n).padStart(2, '0');
|
||||||
|
const agora = `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
||||||
|
return this._request(credentials, 'POST', `/api/os/update/id/${parseInt(idSuporte, 10)}/`, {
|
||||||
|
os_status: 1,
|
||||||
|
os_servicoprestado: descricao,
|
||||||
|
os_data_finalizacao: agora
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------- FTTH
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lista OLTs no formato que o fluxo de vínculo de ONU espera (nome/ssid/portas/perfis).
|
||||||
|
* O SGP não exige porta/perfil para vincular uma ONU já autorizada, então
|
||||||
|
* são devolvidos valores neutros apenas para o fluxo seguir.
|
||||||
|
*/
|
||||||
|
async obterOlts(location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const lista = await this._request(credentials, 'GET', '/api/fttx/olt/list/');
|
||||||
|
return {
|
||||||
|
dados: (lista || []).map(o => ({
|
||||||
|
id: o.id,
|
||||||
|
nome: o.name,
|
||||||
|
ssid: o.host || '',
|
||||||
|
portas: [{ id: 0, alias: 'SGP' }],
|
||||||
|
perfis: [{ id: 0, identificacao: 'SGP' }]
|
||||||
|
}))
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vincula uma ONU a um serviço: localiza a ONU pelo serial no SGP e associa ao login do contrato.
|
||||||
|
*/
|
||||||
|
async atualizarFTTH(idCliente, idServico, ftthData, location = '', credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const serial = String(ftthData.serial || '').toUpperCase();
|
||||||
|
if (!serial) throw new Error('Serial da ONU não informado');
|
||||||
|
|
||||||
|
const servicos = await this.obterServicosCliente(idCliente, location, credentials);
|
||||||
|
if (!servicos.success) throw new Error(servicos.error);
|
||||||
|
const srv = servicos.data.dados.find(s => String(s.id_servico) === String(idServico));
|
||||||
|
if (!srv) throw new Error(`Contrato #${idServico} não encontrado para o cliente`);
|
||||||
|
if (!srv.login) throw new Error('Contrato sem login de serviço para vincular a ONU');
|
||||||
|
|
||||||
|
const onus = await this._request(credentials, 'GET', '/api/fttx/onu/list/');
|
||||||
|
const onu = (onus || []).find(o => String(o.phy_addr || '').toUpperCase() === serial);
|
||||||
|
if (!onu) {
|
||||||
|
throw new Error(`ONU ${serial} não está cadastrada/autorizada no SGP. Autorize-a no SGP e tente novamente.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._request(credentials, 'POST', `/api/fttx/onu/${onu.id}/edit/`, {
|
||||||
|
onu_update: 'service',
|
||||||
|
service: srv.login
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------ RADIUS
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sessões PPPoE (equivalente a ObterClientesServicosAcessos).
|
||||||
|
* params: { status: 'on' } ou { dataInicial, dataFinal } (DD/MM/AAAA)
|
||||||
|
*/
|
||||||
|
async obterAcessos(params, instance, credentials) {
|
||||||
|
return this._wrap(credentials, async () => {
|
||||||
|
const query = { limit: 1000 };
|
||||||
|
if (params.status === 'on') query.online = 1;
|
||||||
|
|
||||||
|
const iso = d => {
|
||||||
|
const m = String(d || '').match(/^(\d{2})\/(\d{2})\/(\d{4})$/);
|
||||||
|
return m ? `${m[3]}-${m[2]}-${m[1]}` : null;
|
||||||
|
};
|
||||||
|
const ini = iso(params.dataInicial);
|
||||||
|
const fim = iso(params.dataFinal);
|
||||||
|
|
||||||
|
const sessoes = [];
|
||||||
|
let offset = 0;
|
||||||
|
for (let pagina = 0; pagina < 20; pagina++) {
|
||||||
|
const data = await this._request(credentials, 'POST', '/ws/radius/radacct/list/all/', { ...query, offset });
|
||||||
|
const lote = data.result || [];
|
||||||
|
lote.forEach(item => {
|
||||||
|
(item.radacct || []).forEach(r => {
|
||||||
|
const inicio = String(r.acctstarttime || '');
|
||||||
|
if (ini && fim && inicio) {
|
||||||
|
const dia = inicio.slice(0, 10);
|
||||||
|
const termDia = r.acctstoptime ? String(r.acctstoptime).slice(0, 10) : '9999-12-31';
|
||||||
|
if (dia > fim || termDia < ini) return;
|
||||||
|
}
|
||||||
|
sessoes.push({
|
||||||
|
id_cliente: -1,
|
||||||
|
usuario: r.username || item.pppoe_login,
|
||||||
|
ip: r.framedipaddress || item.ip || '',
|
||||||
|
inicio,
|
||||||
|
termino: r.acctstoptime || '',
|
||||||
|
nas_ip: r.nasipaddress || '',
|
||||||
|
nome: item.nome
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const total = data.paggination?.total ?? lote.length;
|
||||||
|
offset += lote.length;
|
||||||
|
if (lote.length === 0 || offset >= total) break;
|
||||||
|
}
|
||||||
|
return { dados: sessoes };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SgpAPI;
|
||||||
+1063
-1073
File diff suppressed because it is too large.
Load diff
+127
-100
@@ -1,100 +1,127 @@
|
|||||||
/**
|
/**
|
||||||
* Configurações do TopSapp
|
* Configurações do TopSapp
|
||||||
*/
|
*/
|
||||||
class TopSappConfig {
|
class TopSappConfig {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.credentials = {
|
this.credentials = {
|
||||||
guarai_colmeia: {
|
guarai_colmeia: {
|
||||||
usuario: process.env.TOPSAPP_GUARAI_USER || '',
|
usuario: process.env.TOPSAPP_GUARAI_USER || '',
|
||||||
senha: process.env.TOPSAPP_GUARAI_PASS || '',
|
senha: process.env.TOPSAPP_GUARAI_PASS || '',
|
||||||
identificador: process.env.TOPSAPP_GUARAI_ID || 'BotTelegram',
|
identificador: process.env.TOPSAPP_GUARAI_ID || 'BotTelegram',
|
||||||
idUsuario: process.env.TOPSAPP_GUARAI_USERID || '1'
|
idUsuario: process.env.TOPSAPP_GUARAI_USERID || '1'
|
||||||
},
|
},
|
||||||
pedro_afonso: {
|
};
|
||||||
usuario: process.env.TOPSAPP_PEDRO_AFONSO_USER || '',
|
|
||||||
senha: process.env.TOPSAPP_PEDRO_AFONSO_PASS || '',
|
// Pedro Afonso migrou do TopSapp para o SGP
|
||||||
identificador: process.env.TOPSAPP_PEDRO_AFONSO_ID || 'BotTelegram',
|
this.sgpCredentials = {
|
||||||
idUsuario: process.env.TOPSAPP_PEDRO_AFONSO_USERID || '1'
|
pedro_afonso: {
|
||||||
}
|
baseURL: process.env.SGP_PEDRO_AFONSO_URL || '',
|
||||||
};
|
app: process.env.SGP_PEDRO_AFONSO_APP || '',
|
||||||
|
token: process.env.SGP_PEDRO_AFONSO_TOKEN || '',
|
||||||
this.isConfigured = this.validateConfiguration();
|
usuario: process.env.SGP_PEDRO_AFONSO_USER || '',
|
||||||
}
|
senha: process.env.SGP_PEDRO_AFONSO_PASS || ''
|
||||||
|
}
|
||||||
/**
|
};
|
||||||
* Validar se as configurações estão completas
|
|
||||||
*/
|
this.isConfigured = this.validateConfiguration();
|
||||||
validateConfiguration() {
|
}
|
||||||
const required = ['usuario', 'senha'];
|
|
||||||
|
/**
|
||||||
for (const instance in this.credentials) {
|
* Validar se as configurações estão completas
|
||||||
const creds = this.credentials[instance];
|
*/
|
||||||
for (const field of required) {
|
validateConfiguration() {
|
||||||
if (!creds[field]) {
|
const required = ['usuario', 'senha'];
|
||||||
console.warn(`⚠️ TopSapp: Campo ${field} não configurado para ${instance}`);
|
|
||||||
return false;
|
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}`);
|
||||||
console.log('✅ TopSapp: Configurações validadas');
|
return false;
|
||||||
return true;
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/**
|
|
||||||
* Obter credenciais para uma instância
|
console.log('✅ TopSapp: Configurações validadas');
|
||||||
*/
|
return true;
|
||||||
getCredentials(instanceKey) {
|
}
|
||||||
return this.credentials[instanceKey] || null;
|
|
||||||
}
|
/**
|
||||||
|
* SGP configurado quando há URL e (app+token ou usuário+senha)
|
||||||
/**
|
*/
|
||||||
* Obter credenciais a partir do site ativo (cidade/provedor)
|
isSgpConfigured(key = 'pedro_afonso') {
|
||||||
*/
|
const c = this.sgpCredentials[key];
|
||||||
getCredentialsBySite(siteId) {
|
return !!(c && c.baseURL && ((c.app && c.token) || (c.usuario && c.senha)));
|
||||||
const sites = require('../config/sites');
|
}
|
||||||
const site = sites.getSite(siteId);
|
|
||||||
if (!site) return this.credentials.guarai_colmeia;
|
/**
|
||||||
return this.credentials[site.topsappKey] || null;
|
* Obter credenciais para uma instância
|
||||||
}
|
*/
|
||||||
|
getCredentials(instanceKey) {
|
||||||
/**
|
return this.credentials[instanceKey] || null;
|
||||||
* Obter credenciais por localização
|
}
|
||||||
*/
|
|
||||||
getCredentialsByLocation(location = '') {
|
/**
|
||||||
const loc = location.toLowerCase();
|
* Obter credenciais a partir do site ativo (cidade/provedor)
|
||||||
|
*/
|
||||||
if (loc.includes('pedro') || loc.includes('afonso')) {
|
getCredentialsBySite(siteId) {
|
||||||
return this.credentials.pedro_afonso;
|
const sites = require('../config/sites');
|
||||||
}
|
const site = sites.getSite(siteId);
|
||||||
|
if (!site) return this.credentials.guarai_colmeia;
|
||||||
return this.credentials.guarai_colmeia;
|
return this.credentials[site.topsappKey] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verificar se o TopSapp está configurado
|
* Obter credenciais por localização
|
||||||
*/
|
*/
|
||||||
isReady() {
|
getCredentialsByLocation(location = '') {
|
||||||
return this.isConfigured;
|
if (this.usesSgp(location)) {
|
||||||
}
|
return this.sgpCredentials.pedro_afonso;
|
||||||
|
}
|
||||||
/**
|
return this.credentials.guarai_colmeia;
|
||||||
* Obter status da configuração
|
}
|
||||||
*/
|
|
||||||
getStatus() {
|
/**
|
||||||
const status = {};
|
* Pedro Afonso é atendido pelo SGP; as demais localidades pelo TopSapp
|
||||||
|
*/
|
||||||
for (const instance in this.credentials) {
|
usesSgp(location = '') {
|
||||||
const creds = this.credentials[instance];
|
const loc = String(location || '').toLowerCase();
|
||||||
status[instance] = {
|
return loc.includes('pedro') || loc.includes('afonso');
|
||||||
configured: !!(creds.usuario && creds.senha),
|
}
|
||||||
usuario: creds.usuario ? '✅' : '❌',
|
|
||||||
senha: creds.senha ? '✅' : '❌'
|
/**
|
||||||
};
|
* Verificar se o TopSapp está configurado
|
||||||
}
|
*/
|
||||||
|
isReady(location) {
|
||||||
return status;
|
if (location === undefined) {
|
||||||
}
|
return this.isConfigured || this.isSgpConfigured();
|
||||||
}
|
}
|
||||||
|
return this.usesSgp(location) ? this.isSgpConfigured() : this.isConfigured;
|
||||||
module.exports = TopSappConfig;
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 ? '✅' : '❌'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
status.pedro_afonso_sgp = {
|
||||||
|
configured: this.isSgpConfigured(),
|
||||||
|
usuario: this.sgpCredentials.pedro_afonso.baseURL ? '✅' : '❌',
|
||||||
|
senha: (this.sgpCredentials.pedro_afonso.token || this.sgpCredentials.pedro_afonso.senha) ? '✅' : '❌'
|
||||||
|
};
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = TopSappConfig;
|
||||||
+1448
-1432
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user