This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-10-14 16:41:07 -03:00
1 parent 3168b3906c
commit ba8ef2994b
1 file changed
+48 -2
+48 -2
View File
@@ -453,7 +453,7 @@ class SgpAPI {
async obterFaturas(idCliente, location = '', credentials, idServico = null) { async obterFaturas(idCliente, location = '', credentials, idServico = null) {
return this._wrap(credentials, async () => { return this._wrap(credentials, async () => {
const params = { status: 'abertos' }; const params = { status: 'abertos', ordenar: 'data_vencimento', ordenar_ordem: 'asc' };
if (idCliente) params.cliente_id = parseInt(idCliente, 10); if (idCliente) params.cliente_id = parseInt(idCliente, 10);
if (idServico) params.contrato = parseInt(idServico, 10); if (idServico) params.contrato = parseInt(idServico, 10);
@@ -466,12 +466,15 @@ class SgpAPI {
const lote = data.titulos || []; const lote = data.titulos || [];
lote.forEach(t => { lote.forEach(t => {
this.tituloCache.set(String(t.id), { at: Date.now(), titulo: t }); this.tituloCache.set(String(t.id), { at: Date.now(), titulo: t });
dados.push(this._mapTitulo(t, idCliente)); dados.push({ ...this._mapTitulo(t, idCliente), _venc: t.dataVencimento || '' });
}); });
const total = data.paginacao?.total ?? lote.length; const total = data.paginacao?.total ?? lote.length;
offset += lote.length; offset += lote.length;
if (lote.length === 0 || offset >= total) break; if (lote.length === 0 || offset >= total) break;
} }
// Garante ordem crescente de vencimento (AAAA-MM-DD ordena como texto)
dados.sort((a, b) => String(a._venc).localeCompare(String(b._venc)));
dados.forEach(d => delete d._venc);
return { dados }; return { dados };
}); });
} }
@@ -493,10 +496,53 @@ class SgpAPI {
return this._wrap(credentials, async () => { return this._wrap(credentials, async () => {
const titulo = await this._obterTitulo(idFatura, credentials); const titulo = await this._obterTitulo(idFatura, credentials);
const f = this._mapTitulo(titulo, idCliente); const f = this._mapTitulo(titulo, idCliente);
// A listagem de títulos nem sempre traz o PIX; nesse caso gera/consulta pelo endpoint de PIX
if (!f.qrcode && titulo.clienteContrato) {
f.qrcode = await this._obterPix(titulo, credentials);
if (f.qrcode) titulo.codigoPix = f.qrcode; // fica no cache
}
return { fatura: f }; return { fatura: f };
}); });
} }
/**
* Gera (ou consulta) o PIX copia e cola do título.
*/
async _obterPix(titulo, credentials) {
try {
const data = await this._request(credentials, 'POST', `/api/ura/pagamento/pix/${titulo.id}`, {
contrato: titulo.clienteContrato
});
if (process.env.SGP_DEBUG === 'true') {
console.log('🧪 [SGP] Resposta do PIX:', JSON.stringify(data));
}
return this._extrairPix(data);
} catch (error) {
logger.warn('SGP: não foi possível gerar o PIX', { titulo: titulo.id, error: error.message });
return '';
}
}
/**
* Procura o código copia e cola (EMV, começa com "000201") na resposta, qualquer que seja o campo.
*/
_extrairPix(data, nivel = 0) {
if (!data || nivel > 4) return '';
if (typeof data === 'string') return /^0002\d{2}/.test(data.trim()) ? data.trim() : '';
if (typeof data !== 'object') return '';
const preferidos = ['codigoPix', 'codigo_pix', 'qrcode', 'pix_copia_cola', 'copia_cola', 'copiaecola', 'emv', 'brcode', 'payload', 'pix'];
for (const k of preferidos) {
const v = this._extrairPix(data[k], nivel + 1);
if (v) return v;
}
for (const k of Object.keys(data)) {
const v = this._extrairPix(data[k], nivel + 1);
if (v) return v;
}
return '';
}
/** /**
* Baixa o boleto em PDF e devolve em Base64 (mesmo contrato do TopSapp). * Baixa o boleto em PDF e devolve em Base64 (mesmo contrato do TopSapp).
*/ */