UNPKG

thunderpix

Version:

Biblioteca javascript de padronização de gateways de pagamentos PIX

319 lines (287 loc) 10.5 kB
import axios from 'axios'; import ProviderInterface from '../../interfaces/ProviderInterface'; import { randomUUID } from '../../utils/all/index'; import PixProvider from './PixProvider'; interface ProviderConstruct { apiKey: string; isTest: boolean | false; } export default class OpenPixProvider implements ProviderInterface { private baseUrl: string; private apiKey: string; public providerInfo = { name: 'OpenPix', description: 'Plataforma de pagamentos instantâneos com Pix.', documentation: 'https://developers.openpix.com.br', isOnline: true, vendor: { name: 'OpenPix', shotname: 'openpix', url: 'https://openpix.com.br', api: 'https://api.openpix.com.br', versions: [ { name: 'br.com.openpix.api-v1', version: '1.0.0', path: '/', }, ], }, }; constructor(configs: ProviderConstruct) { this.baseUrl = configs.isTest ? 'https://sandbox.openpix.com.br' : 'https://api.openpix.com.br'; this.apiKey = configs.apiKey; } // Função auxiliar para configurar os headers de autorização private getHeaders(): any { return { Authorization: `Bearer ${this.apiKey}`, 'Content-Type': 'application/json', }; } // Geração de cobrança via Pix com chave Copia-e-Cola async gerarQrCodePix( valueCents: number, description: string, customer: { name: string; document: string; email: string; phone: string; city: string; }, ) { const payload = { correlationID: randomUUID(), value: valueCents, // Valor em centavos comment: description, customer: { name: customer.name, email: customer.email, taxID: customer.document, phone: customer.phone, }, }; const response = await axios.post( `${this.baseUrl}/api/v1/charge`, payload, { headers: this.getHeaders(), }, ); return response.data; } // Listar cobranças Pix async listarCobrancas( page: number = 1, registrationStartDate?: string, registrationEndDate?: string, ) { const params = { page, startDate: registrationStartDate, endDate: registrationEndDate, }; const response = await axios.get(`${this.baseUrl}/api/v1/charge`, { headers: this.getHeaders(), params, }); return response.data; } // Consultar cobrança Pix por ID async consultarCobrancaPorID(correlationID: string) { const response = await axios.get( `${this.baseUrl}/api/v1/charge/${correlationID}`, { headers: this.getHeaders(), }, ); return response.data; } // Estornar uma cobrança Pix async estornarCobranca(correlationID: string) { const response = await axios.post( `${this.baseUrl}/api/v1/charge/${correlationID}/refund`, {}, { headers: this.getHeaders(), }, ); return response.data; } // Geração de cobrança Pix com retorno formatado async generatingPixBilling( body: PixGeneratingPixBillingInterface, ): Promise<Object> { const valueCents = Math.round(body.valueCents); const data = await this.gerarQrCodePix(valueCents, body.description, { name: body.name, document: body.document, email: body.email, phone: body.phone, city: body.city, }); return { qrcode: data.charge.qrCodeImage, // QR Code gerado em base64 pixkey: data.charge.brCode, // Chave Copia-e-Cola 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.charge.correlationID, // Código de transação }; } // Função para 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.charges.map((mp: any) => ({ referenceCode: mp.correlationID, valueCents: mp.value, content: mp.qrCodeImage, status: mp.status, generatorName: mp.customer.name, generatorDocument: mp.customer.taxID, payerName: mp.payer?.name || 'N/A', payerDocument: mp.payer?.taxID || 'N/A', registrationDate: mp.createdAt, paymentDate: mp.paidAt, endToEnd: mp.endToEndId || 'N/A', })); return { qrcodes: cobrancas, meta: { current_page: body.page || 1, total_pages: Math.ceil(data.charges.length / 20), total_items_amount: data.charges.length, total_value_cents: cobrancas.reduce( (acc: number, curr: any) => acc + curr.valueCents, 0, ), }, }; } async searchPixBilling( body: searchPixBilling, ): Promise<searchPixBillingOutput> { const data = await this.consultarCobrancaPorID(body.reference); return { referenceCode: data.charge.correlationID, valueCents: data.charge.value, status: data.charge.status, registrationDate: data.charge.createdAt, paymentDate: data.charge.paidAt, generatorName: data.charge.customer.name, generatorDocument: data.charge.customer.taxID, }; } // Cadastrar pagamento manual (não suportado diretamente pela OpenPix) async generateProviderWidthdraw( body: PixGenerateProviderWidthdraw, ): Promise<generateProviderWidthdrawOutput> { return { reference_code: randomUUID(), idempotent_id: body.idempotentId, value_cents: body.valueCents, pix_key_type: body.pixKeyType || 'CPF', pix_key: body.pixKey || '12345678901', receiver_name: body.receiverName, receiver_document: body.receiverDocument, status: 'APPROVED', }; } // Listar pagamentos (não diretamente suportado pela OpenPix) async listProviderWidthdraw( body: listProviderWidthdraw, ): Promise<listProviderWidthdrawOutput> { const response = await axios.get( `${this.baseUrl}/api/v1/subaccount/withdraw`, { headers: this.getHeaders(), params: { page: body.page, registrationStartDate: body.registrationDateStart, registrationEndDate: body.registrationDateEnd, paymentStartDate: body.paymentStartDate, paymentEndDate: body.paymentEndDate, }, }, ); const payments = response.data.withdrawals.map((withdrawal: any) => ({ referenceCode: withdrawal.correlationID, idempotentId: withdrawal.correlationID, valueCents: withdrawal.value, pixKeyType: 'CPF', // Exemplo pixKey: withdrawal.destinationAlias, receiverName: withdrawal.comment || 'Desconhecido', receiverDocument: 'Não disponível', // Depende do campo disponível status: withdrawal.status, registrationDate: withdrawal.createdAt, paymentDate: withdrawal.paymentDate, cancellationDate: withdrawal.cancellationDate || null, cancellationReason: withdrawal.cancellationReason || null, endToEnd: withdrawal.transactionID || 'N/A', })); return { payments, meta: { current_page: body.page || 1, total_pages: 1, // Calcular se necessário total_items_amount: payments.length, total_value_cents: payments.reduce( (acc: number, curr: any) => acc + curr.valueCents, 0, ), }, }; } // Função para consultar o saldo disponível via API OpenPix async getBalance(): Promise<BalanceOutput> { const response = await axios.get(`${this.baseUrl}/api/v1/balance`, { headers: this.getHeaders(), }); const balance = response.data; return { valueCents: balance.balance * 100, // Converte o valor para centavos valueFloat: balance.balance, // Valor em formato decimal }; } async searchProviderWidthdraw(body: { correlationID: string; }): Promise<Object> { const response = await axios.get( `${this.baseUrl}/api/v1/subaccount/withdraw/${body.correlationID}`, { headers: this.getHeaders(), }, ); const data = response.data.withdrawal; return { referenceCode: data.correlationID, idempotentId: data.correlationID, valueCents: data.value, pixKeyType: (new PixProvider({pixkey: data.destinationAlias})).determinePixType().type, pixKey: data.destinationAlias, receiverName: data.comment || 'Desconhecido', receiverDocument: 'Não disponível', // Depende do campo disponível status: data.status, registrationDate: data.createdAt, paymentDate: data.paymentDate, endToEnd: data.transactionID || 'N/A', }; } }