Files
mercado.clube67.com/backend/services/asaasService.js
T

139 lines
4.2 KiB
JavaScript

'use strict'
// Fetch nativo do Node.js (Node 18+)
class AsaasService {
static getApiUrl() {
return process.env.ASAAS_ENV === 'production'
? 'https://api.asaas.com/v3'
: 'https://sandbox.asaas.com/api/v3'
}
static getApiKey() {
return process.env.ASAAS_API_KEY;
}
/**
* Busca ou cria um cliente no Asaas
*/
static async getOrCreateCustomer(nome, cpf, telefone, email) {
const key = this.getApiKey();
if (!key) throw new Error('API Key do Asaas não configurada');
if (key === 'sandbox_local') {
return 'cus_mock_' + Math.floor(Math.random() * 1000000);
}
const cleanCpf = cpf.replace(/\D/g, '')
// Tentar encontrar cliente existente pelo CPF
const searchRes = await fetch(`${this.getApiUrl()}/customers?cpfCnpj=${cleanCpf}`, {
headers: { 'access_token': key }
})
if (!searchRes.ok) {
console.warn('[AsaasService] busca de cliente retornou', searchRes.status)
} else {
const searchData = await searchRes.json()
if (searchData?.data?.length > 0) return searchData.data[0].id
}
// Criar novo cliente
const createRes = await fetch(`${this.getApiUrl()}/customers`, {
method: 'POST',
headers: {
'access_token': key,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: nome,
cpfCnpj: cleanCpf,
email: email || `${cleanCpf}@alemaoconveniencias.com.br`,
mobilePhone: telefone || null
})
})
const createData = await createRes.json()
if (!createRes.ok) {
console.error('Erro Asaas (Criar Cliente):', createData)
throw new Error(createData.errors ? createData.errors[0].description : 'Erro ao criar cliente no Asaas')
}
return createData.id
}
/**
* Cria uma cobrança via PIX
*/
static async createPixCharge(customerId, amount, description) {
const key = this.getApiKey();
if (!key) throw new Error('API Key do Asaas não configurada');
if (key === 'sandbox_local') {
return {
orderId: 'pay_mock_' + Math.floor(Math.random() * 1000000),
qrCodeUrl: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=', // transparent pixel fallback
pixCopyPaste: '00020101021126360014br.gov.bcb.pix0114sandbox_local_mock_12345652040000530398654041.005802BR5906Mocked6006Mocked62070503***6304ABCD'
}
}
// Data de vencimento hoje
const dueDate = new Date()
dueDate.setHours(23, 59, 59, 999)
const chargeRes = await fetch(`${this.getApiUrl()}/payments`, {
method: 'POST',
headers: {
'access_token': key,
'Content-Type': 'application/json'
},
body: JSON.stringify({
customer: customerId,
billingType: 'PIX',
value: amount,
dueDate: dueDate.toISOString().split('T')[0],
description: description
})
})
const chargeData = await chargeRes.json()
if (!chargeRes.ok) {
console.error('Erro Asaas (Criar Cobrança):', chargeData)
throw new Error(chargeData.errors ? chargeData.errors[0].description : 'Erro ao criar cobrança no Asaas')
}
// Gerar QR Code para a cobrança criada
const qrCodeRes = await fetch(`${this.getApiUrl()}/payments/${chargeData.id}/pixQrCode`, {
headers: { 'access_token': key }
})
let qrCodeData = null
if (qrCodeRes.ok) {
qrCodeData = await qrCodeRes.json()
}
return {
orderId: chargeData.id,
qrCodeUrl: qrCodeData ? qrCodeData.encodedImage : chargeData.invoiceUrl, // encodedImage é base64 ou usar invoiceUrl
pixCopyPaste: qrCodeData ? qrCodeData.payload : null
}
}
/**
* Busca os detalhes de uma cobrança existente
*/
static async getCharge(paymentId) {
const key = this.getApiKey();
if (key === 'sandbox_local') {
const orderStatus = process.env.MOCK_ORDER_PAID === 'true' ? 'RECEIVED' : 'PENDING';
return { status: orderStatus, id: paymentId };
}
const chargeRes = await fetch(`${this.getApiUrl()}/payments/${paymentId}`, {
headers: { 'access_token': key }
})
return await chargeRes.json()
}
}
module.exports = AsaasService