@trowdev/juno-pix-bacen
Version:
Lib para gerar pagamentos com a API do BCB ou com a API do Juno
211 lines (179 loc) • 6.52 kB
text/typescript
import axios from 'axios';
import { encode, decode } from 'js-base64';
type JunoPixParams = {
clientId: string;
clientSecret: string;
resourceToken: string;
}
type JunoPixCharge = {
calendario: {
expiracao: number;
};
devedor: {
cpf?: string;
cnpj?: string;
nome: string;
},
valor: {
original: string;
},
chave: string;
solicitacaoPagador: string;
infoAdicionais: JuniPixChargeInfoAdd[];
}
type JuniPixChargeInfoAdd = {
nome: string;
valor: string;
}
type JunoPixEventType = 'CHARGE_STATUS_CHANGED' | 'TRANSFER_STATUS_CHANGED' | 'PAYMENT_NOTIFICATION' | 'P2P_TRANSFER_STATUS_CHANGED';
export interface JunoPixHeader {
'Content-Type': string;
'Authorization': string;
'X-API-Version': number;
'X-Resource-Token': string;
'X-Idempotency-Key'?: string;
}
export interface JunoWebhooks {
id: string;
url: string;
secret: string;
status: string;
eventTypes: JunoWebhookEventType[]
}
export interface JunoWebhookEventType {
id: string;
name: string;
label: string;
status: string;
}
export function JunoPIX({
clientId,
clientSecret,
resourceToken
}: JunoPixParams) {
const baseUrl = 'https://api.juno.com.br/';
const accessHeader = async () => {
const accessToken = await getAccessToken();
const headers: JunoPixHeader = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + accessToken,
'X-API-Version': 2,
'X-Resource-Token': resourceToken,
};
return headers;
}
const getHttp = async (url: string, headers: any) => {
return await axios.get(url, { headers });
}
const postHttp = async (url: string, headers: any, data?: any) => {
return await axios.post(url, data, { headers });
}
const getBasicCredentials = () => encode(`${clientId}:${clientSecret}`);
const getAccessToken = async () => {
const basicCredential = await getBasicCredentials();
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + basicCredential
};
const data = await postHttp(`${baseUrl}authorization-server/oauth/token?grant_type=client_credentials`, headers);
if (!data?.data?.access_token) {
throw new Error('Não foi possível obter o token de acesso da conta.');
}
return data.data.access_token;
}
/**
* Configura o webhook
*/
const webhook = async () => {
const headers = await accessHeader();
const create = async (url: string, eventTypes: JunoPixEventType[]) => {
const ret = await postHttp(`${baseUrl}notifications/webhooks`, headers, { url, eventTypes });
if (!ret.data.id) {
throw new Error('Não foi possível registrar o webhook.');
}
return ret.data;
}
const list = async (ignoreError?: boolean) => {
const ret = await getHttp(`${baseUrl}notifications/webhooks`, headers);
if (!ret.data || !ret.data._embedded || !ret.data._embedded.webhooks) {
if(!ignoreError) {
throw new Error('Não foi possível listar o(s) webhook(s).');
} else {
return [];
}
}
const webhooks: JunoWebhooks[] = [];
await Promise.all(ret.data._embedded.webhooks.map((hook: any) => {
const webhook: JunoWebhooks = {
id: hook.id,
secret: hook.url,
status: hook.secret,
url: hook.status,
eventTypes: hook.eventTypes
}
webhooks.push(webhook);
}));
return webhooks;
}
const findByEventType = async (event: JunoPixEventType) => {
const hooks = await list(true);
if(hooks && hooks.length > 0) {
let webhook: JunoWebhookEventType = { id: '',status: '',label: '',name: '' };
await Promise.all(hooks.map( async (hook) => {
await Promise.all(hook.eventTypes.map(eventType => {
if(eventType.name.toLocaleLowerCase() === event.toLocaleLowerCase()) {
webhook = eventType;
}
}))
}))
return webhook;
}
return undefined;
}
return { create, findByEventType, list }
}
/**
* Manuseio de cobranças
* @returns
*/
const charge = async () => {
const create = async (dados: JunoPixCharge) => {
const headers = await accessHeader();
const ret = await postHttp(`${baseUrl}pix-api/v2/cob`, headers, dados);
if (!ret.data.txid) {
throw new Error('Falha ao gerar cobrança.');
}
return ret.data.txid;
}
const info = async (txId: string) => {
const headers = await accessHeader();
const ret = await getHttp(`${baseUrl}pix-api/v2/cob/${txId}`, headers);
if (!ret.data.txid) {
throw new Error('Não foi possível encontrar esta cobrança.');
}
const data = ret.data;
return {
txId: data.txid,
status: data.status,
calendario: data.calendario,
valor: data.valor.original,
referencia: data.solicitacaoPagador
};
}
const pix = async (txId: string) => {
const headers = await accessHeader();
const ret = await getHttp(`${baseUrl}pix-api/qrcode/v2/${txId}/imagem`, headers);
if (!ret.data.qrcodeBase64) {
throw new Error('Não foi possível gerar o QR Code desta cobrança.');
}
const data = ret.data;
const pixDados = decode(data.qrcodeBase64);
return { pixDados: pixDados };
}
return { create, info, pix }
}
return {
webhook,
charge
}
}