thunderpix
Version:
Biblioteca javascript de padronização de gateways de pagamentos PIX
329 lines (291 loc) • 11.4 kB
text/typescript
import axios from 'axios';
import ProviderInterface from '../../interfaces/ProviderInterface';
import { randomUUID } from '../../utils/all/index';
// import * as fs from 'fs';
interface ProviderConstruct {
clientId: string;
clientSecret: string;
certificatePath: string;
isTest: boolean;
}
export default class EfiPayProvider implements ProviderInterface {
private baseUrl: string;
private clientId: string;
private clientSecret: string;
private certificatePath: string;
private accessToken: string | null;
public providerInfo = {
name: 'EfiPay',
description: 'Plataforma de pagamentos Pix via API.',
documentation: 'https://dev.efipay.com.br/docs/api-pix/',
isOnline: true,
vendor: {
name: 'EfiPay',
shotname: 'efipay',
url: 'https://www.efipay.com.br',
api: 'https://api.efipay.com.br',
versions: [
{
name: 'br.com.efipay.api-v1',
version: '1.0.0',
path: '/',
}
],
},
};
constructor(configs: ProviderConstruct) {
this.baseUrl = configs.isTest ? 'https://pix-h.api.efipay.com.br' : 'https://pix.api.efipay.com.br';
this.clientId = configs.clientId;
this.clientSecret = configs.clientSecret;
this.certificatePath = configs.certificatePath;
this.accessToken = null;
}
searchPixBilling(body?: object): Promise<Object> {
throw new Error('Method not implemented.');
}
// Autenticação OAuth2.0
async generateToken(): Promise<void> {
const auth = Buffer.from(`${this.clientId}:${this.clientSecret}`).toString('base64');
const response = await axios.post(
`${this.baseUrl}/oauth/token`,
{ grant_type: 'client_credentials' },
{
headers: {
Authorization: `Basic ${auth}`,
'Content-Type': 'application/json',
},
/**
* Futura correção para
* compatibilidade com backend e frontend
*/
// httpsAgent: new (require('https').Agent)({
// pfx: fs.readFileSync(this.certificatePath),
// passphrase: '', // Senha do certificado se houver
// }),
}
);
this.accessToken = response.data.access_token;
}
// Função auxiliar para configurar os headers com token de autorização
private getHeaders(): any {
if (!this.accessToken) {
throw new Error('Token de acesso não foi gerado.');
}
return {
Authorization: `Bearer ${this.accessToken}`,
'Content-Type': 'application/json',
};
}
// Geração de cobrança Pix (Pix Cob)
async gerarCobPix(
valueCents: number,
description: string,
customer: {
name: string,
document: string,
email: string,
phone: string
}
) {
const payload = {
calendario: {
expiracao: 3600
},
devedor: {
cpf: customer.document,
nome: customer.name
},
valor: {
original: (valueCents / 100).toFixed(2) // Valor em reais
},
chave: randomUUID(), // Chave Pix ou chave aleatória
infoAdicionais: [
{ nome: 'Descrição', valor: description }
]
};
const response = await axios.post(`${this.baseUrl}/v2/cob`, payload, {
headers: this.getHeaders(),
});
return response.data;
}
// Listar cobranças Pix
async listarCobrancas(
page: number = 1,
registrationStartDate?: string,
registrationEndDate?: string
) {
const params = {
inicio: registrationStartDate || new Date().toISOString(),
fim: registrationEndDate || new Date().toISOString(),
paginaAtual: page,
};
const response = await axios.get(`${this.baseUrl}/v2/cob`, {
headers: this.getHeaders(),
params,
});
return response.data;
}
// Consultar cobrança Pix por ID
async consultarCobrancaPorID(txid: string) {
const response = await axios.get(`${this.baseUrl}/v2/cob/${txid}`, {
headers: this.getHeaders(),
});
return response.data;
}
// Estornar uma cobrança Pix
async estornarCobranca(txid: string) {
const response = await axios.post(`${this.baseUrl}/v2/pix/${txid}/devolucao`, {
valor: '10.00', // Valor do estorno
}, {
headers: this.getHeaders(),
});
return response.data;
}
// Geração de cobrança com Pix (Cob)
async generatingPixBilling(body: PixGeneratingPixBillingInterface): Promise<Object> {
const valueCents = Math.round(body.valueCents);
await this.generateToken();
const data = await this.gerarCobPix(valueCents, body.description, {
name: body.name,
document: body.document,
email: body.email,
phone: body.phone,
});
return {
qrcode: data.pix.qrcode, // QR Code gerado em base64
pixkey: data.pix.txid, // Transaction ID do Pix
value: {
original: body.valueCents,
cents: valueCents,
fixed: (valueCents / 100).toFixed(2),
float: valueCents / 100,
},
expires: {
timestamp: body.expires,
dateTime: new Date(body.expires * 1000).toLocaleString('pt-BR'),
iso: new Date(body.expires * 1000).toISOString(),
},
code: data.txid, // Código de transação
};
}
// Listar cobranças Pix
async listingPixBilling(body: PixlistingPixBilling): Promise<listingPixBillingOutput> {
const data = await this.listarCobrancas(
body.page ?? 1,
body.registrationDateStart ?? new Date().toISOString(),
body.registrationDateEnd ?? new Date().toISOString()
);
const cobrancas = data.cobs.map((mp: any) => ({
referenceCode: mp.txid,
valueCents: mp.valor.original * 100,
content: mp.qrcode,
status: mp.status,
generatorName: mp.devedor.nome,
generatorDocument: mp.devedor.cpf,
registrationDate: mp.calendario.criacao,
paymentDate: mp.calendario.expiracao,
endToEnd: mp.endToEndId || 'N/A',
}));
return {
qrcodes: cobrancas,
meta: {
current_page: body.page || 1,
total_pages: Math.ceil(data.total / 20),
total_items_amount: data.total,
total_value_cents: cobrancas.reduce((acc: number, curr: any) => acc + curr.valueCents, 0),
},
};
}
// Função de saque (withdraw)
async generateProviderWidthdraw(body: PixGenerateProviderWidthdraw): Promise<generateProviderWidthdrawOutput> {
const payload = {
valor: (body.valueCents / 100).toFixed(2),
chave: body.pixKey,
descricao: `Saque para ${body.receiverName}`,
};
const response = await axios.post(`${this.baseUrl}/v2/pix`, payload, {
headers: this.getHeaders(),
});
const withdrawal = response.data;
return {
reference_code: withdrawal.txid,
idempotent_id: body.idempotentId,
value_cents: withdrawal.valor * 100,
pix_key_type: body.pixKeyType || 'CPF',
pix_key: body.pixKey ?? '',
receiver_name: body.receiverName,
receiver_document: body.receiverDocument,
status: withdrawal.status,
};
}
// Listar saques (withdrawals)
async listProviderWidthdraw(body: listProviderWidthdraw): Promise<listProviderWidthdrawOutput> {
const params = {
inicio: body.registrationDateStart || new Date().toISOString(),
fim: body.registrationDateEnd || new Date().toISOString(),
page: body.page,
};
const response = await axios.get(`${this.baseUrl}/v2/withdrawals`, {
headers: this.getHeaders(),
params,
});
const withdrawals = response.data.withdrawals.map((withdrawal: any) => ({
referenceCode: withdrawal.txid,
idempotentId: withdrawal.correlationId,
valueCents: Math.round(withdrawal.valor * 100),
pixKeyType: withdrawal.pixKeyType || 'CPF',
pixKey: withdrawal.pixKey,
receiverName: withdrawal.receiverName,
receiverDocument: withdrawal.receiverDocument,
status: withdrawal.status,
registrationDate: withdrawal.created_at,
paymentDate: withdrawal.paid_at || null,
cancellationDate: withdrawal.cancelled_at || null,
cancellationReason: withdrawal.cancellation_reason || null,
endToEnd: withdrawal.endToEndId || 'N/A',
}));
return {
payments: withdrawals,
meta: {
current_page: body.page || 1,
total_pages: response.data.paginacao.total_pages,
total_items_amount: response.data.paginacao.total_items,
total_value_cents: withdrawals.reduce((acc: number, curr: any) => acc + curr.valueCents, 0),
},
};
}
async getBalance(): Promise<BalanceOutput> {
// Garante que o token OAuth2 foi gerado
await this.generateToken();
// Faz a requisição para obter o saldo
const response = await axios.get(`${this.baseUrl}/v2/conta/saldo`, {
headers: this.getHeaders(),
});
const saldo = response.data;
return {
valueCents: Math.round(saldo.saldo * 100), // Converte o valor para centavos
valueFloat: saldo.saldo, // Valor em formato decimal
};
}
// Consultar saque por referência
async searchProviderWidthdraw(body: { correlationId: string }): Promise<Object> {
const response = await axios.get(`${this.baseUrl}/v2/withdrawals/${body.correlationId}`, {
headers: this.getHeaders(),
});
const withdrawal = response.data;
return {
referenceCode: withdrawal.txid,
idempotentId: withdrawal.correlationId,
valueCents: Math.round(withdrawal.valor * 100),
pixKeyType: withdrawal.pixKeyType || 'CPF',
pixKey: withdrawal.pixKey,
receiverName: withdrawal.receiverName,
receiverDocument: withdrawal.receiverDocument,
status: withdrawal.status,
registrationDate: withdrawal.created_at,
paymentDate: withdrawal.paid_at || null,
cancellationDate: withdrawal.cancelled_at || null,
endToEnd: withdrawal.endToEndId || 'N/A',
};
}
}