#!/usr/bin/env -S /usr/bin/node --no-deprecation require("dotenv").config({ quiet: true }); const decimal = require("decimal.js"); const randomUUID = require("crypto").randomUUID; const DEBUG = true; const AUTH_URL = "https://genial-arquitetura-authentication.homolog.api.genial.systems"; const COREBK_URL = "https://genial-arquitetura-corebank.homolog.api.genial.systems"; const BAAS_URL = "https://gerador-arquitetura-baas.homolog.api.genial.systems"; const OPS_URL = "https://genial-baas-operations.homolog.api.genial.systems"; async function main() { const args = process.argv.slice(2); if (args.length === 0) return help(); const cmd = args[0]; const rest = args.slice(1); try { switch (cmd) { case "token": { const [ok, tok] = await getToken(); if (!ok) return fail(tok); console.log(tok); break; } case "balance": { await Balance(rest[0]); break; } case "getkey": { if (rest.length < 1) return fail("Usage: getkey "); await getKey(rest[0]); break; } case "decode": { if (rest.length < 1) return fail("Usage: decodeQrcode "); await decodeQrcode(rest[0]); break; } case "payQr": { if (rest.length < 2) return fail("Usage: payQr "); console.log(rest[0], rest[1]); await PayQr(rest[0], rest[1]); break; } case "qrcodeStatic": { await qrcodeStatic(); break; } case "paykey": { if (rest.length < 2) return fail("Usage: payInit "); await PayInit(rest[0], rest[1]); break; } case "qrcodedynamic": { if (rest.length < 1) return fail("Usage: qrcode "); await QrCodeDynamic(rest[0]); break; } case "statusIn": { //not working on my machine if (rest.length < 1) return fail("Usage: statusIn "); await StatusIn(rest[0]); break; } case "statusOut": { //not working on my machine if (rest.length < 1) return fail("Usage: statusOut "); await StatusOut(rest[0]); break; } case "refund": { if (rest.length < 1) return fail("Usage: refund "); await Refund(rest[0], rest[1]); break; } default: help(); return; } } catch (e) { fail(e.message || e); help(); return; } } function help() { console.log(`Usage: genial-cli [args] Commands: token balance getkey statusOut statusIn qrcode payInit [value] [pixKey] pay payQr refund preview boletoPay [description] [uuid] boletoGet `); process.exit(1); } function fail(msg) { console.error("Error:", msg); process.exit(1); } /* =============== Auth =============== */ async function getToken() { const url = `${AUTH_URL}/v1/authentication`; const options = { method: "POST", headers: { basic: process.env.TOKEN_BASIC, "X-ORIGEM": process.env.TOKEN_XORIGEM, }, }; try { if (DEBUG) { console.log("\nDEBUG callApi:", options.method, url); } const res = await fetch(url, options); const text = await res.text(); if (DEBUG) { console.log("DEBUG getToken status:", res.status); console.log("DEBUG getToken body:", text); } if (res.status < 200 || res.status >= 300) return [false, { status: res.status, body: text }]; const json = JSON.parse(text); if (!json.token) return [false, "No token in response"]; return [true, json.token]; } catch (e) { return [false, e.message]; } } async function callApi(method, url, body) { const [ok, token] = await getToken(); if (!ok) return [false, token]; const headers = { Authorization: token, "X-ORIGEM": process.env.TOKEN_XORIGEM, }; const options = { method, headers }; if (method.toUpperCase() === "POST") { headers["Content-Type"] = "application/json"; options.body = body ? JSON.stringify(body) : ""; } if (DEBUG) { console.log("\nDEBUG callApi:", method, url); if (body) console.log("DEBUG body:", JSON.stringify(body)); } try { const res = await fetch(url, options); const text = await res.text(); if (DEBUG) { console.log("DEBUG status:", res.status); console.log("DEBUG raw:", text); } if (res.status < 200 || res.status >= 300) return [false, { status: res.status, body: text }]; try { return [true, JSON.parse(text)]; } catch { return [true, text]; } } catch (e) { return [false, e.message]; } } /** * @description * account 2 is me the user * account 1 is smartpay the receiver of the payment */ /* =============== 1) Balance =============== done*/ async function Balance(accountNumber) { //INFO: they share 2 acount to test, but idk if on prod only is gonna be one. ignore this, after i know the answer i will delete let account = process.env.ACCOUNT1; const url = `${COREBK_URL}/v1/core-banking/balance/1/${account}`; const [ok, out] = await callApi("GET", url); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 2) Dict Key =============== done*/ async function getKey(pixKey) { const url = `${BAAS_URL}/v2/pix/key-account-partner/1/${process.env.ACCOUNT1}/${pixKey}`; const [ok, out] = await callApi("GET", url); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== DECODE QRCODE =============== done*/ async function decodeQrcode(qrcode) { const url = `https://gerador-arquitetura-baas.homolog.api.genial.systems/v1/pix/qrcode-decode?qrcode=${encodeURIComponent( qrcode )}`; const [ok, out] = await callApi("GET", url); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 8) Pay by QR =============== done*/ async function PayQr(qrCodeCopyPaste, value) { const url = `${BAAS_URL}/v1/pix/copy-paste`; /** * debit is our account that is going to pay the qr code, need prod keys to do it correctly */ const body = { qrCodeCopyPaste, value: Number(value), debit: { name: process.env.ACCOUNT2_NAME, agency: 1, account: process.env.ACCOUNT2, accountType: "CACC", }, }; console.log(body); const [ok, out] = await callApi("POST", url, body); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 2) QR Code Static =============== done*/ async function qrcodeStatic() { const url = `${BAAS_URL}/v1/pix/qrcode-static/`; const body = { accountHolderName: process.env.ACCOUNT1_NAME, addressingKey: { key: process.env.ACCOUNT1_KEY, type: "EVP", }, account: process.env.ACCOUNT1, agency: 1, // additionalInformation: "Pagamento de teste genial-cli" /**@optional */, // value: 10.0, /**@optional */ }; const [ok, out] = await callApi("POST", url, body); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 3) Status OUT (PAC008) =============== NEED TO CHECK*/ async function StatusOut(e2e) { const url = `${OPS_URL}/v1/cashout/${encodeURIComponent(e2e)}`; const [ok, out] = await callApi("GET", url); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 4) Status IN (PAC002) =============== NEED TO CHECK*/ async function StatusIn(transactionId) { const url = `${OPS_URL}/v1/cashin/end-to-end-id/${encodeURIComponent( transactionId )}`; const [ok, out] = await callApi("GET", url); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 6) Init Pix by Key (PAC008 Start) =============== done */ /** * * @param pixKey * @param value * @returns confirmed idempotencyId [@description we need to create the idempotencyId on our side to confirm the payment later ] */ async function PayInit(pixKey, value) { const url = `${BAAS_URL}/v1/pix/send/initialization`; const body = { debit: { name: process.env.ACCOUNT1_NAME, agency: 1, account: process.env.ACCOUNT1, accountType: "CACC", }, credit: { key: pixKey, }, value: String(value), idempotencyId: randomUUID(), }; var [ok, out] = await callApi("POST", url, body); if (!ok) return fail(out); console.dir(out, { depth: null }); if (out?.data?.idempotencyId) { console.log("idempotencyId:", out.data.idempotencyId); } var [ok, reply] = await paykey(out.data.idempotencyId); if (!ok) return fail(reply); console.dir(reply, { depth: null }); } /* =============== 7) Pay by Idempotency (PAC008) =============== done */ /** * * @param idempotencyId * @param payinfo * @returns */ async function paykey(idempotencyId, payinfo) { const url = `${BAAS_URL}/v1/pix/send/confirmed`; const body = { idempotencyId: idempotencyId, ignorePaymentDuplication: false, // additionalInformation: payinfo, /**@optional */ }; const [ok, out] = await callApi("POST", url, body); if (!ok) return fail(out); if (DEBUG) console.log("Payment confirmed for idempotencyId:", idempotencyId); return [true, out]; } /* =============== 9) Refund (PAC004) =============== worked*/ async function Refund(eventId, value) { const url = `${BAAS_URL}/v1/pix/return`; const body = { value: value, returnReasonCode: "MD06", eventId: eventId, }; const [ok, out] = await callApi("POST", url, body); if (!ok) return fail(out); console.dir(out, { depth: null }); } async function QrCodeDynamic(value) { const url = `${BAAS_URL}/v2/qrcode/dynamic?agency=1&account=${process.env.ACCOUNT1}`; const body = { items: [ { addressingKey: { key: process.env.ACCOUNT1_KEY, type: "EVP", }, accountHolderName: process.env.ACCOUNT1_NAME, accountHolderCity: "SAO PAULO", dynamicQRCodeType: "IMMEDIATE", immediate: { expiration: 36000, paymentValue: { documentValue: value, showPaymentValueInQrCode: true, //"cashback": { //"cashbackType": "WITHDRAW", //"value": 0, //"allowValueChange": true, //"withdrawProviders": { //"agentModality": "string", //"serviceProvider": "string" //} //} }, payerInformation: { cpfCnpj: "37812511871", name: "gustavo lopes", validatePayerInformation: true, }, receiverInformation: { taxId: process.env.DOCUMENT_NUMBER, name: process.env.ACCOUNT1_NAME, tradeName: process.env.ACCOUNT1_NAME, }, }, payerRequestInformation: "TESTE SOLICITAÇÃO AO PAYER", //"additionalInformation": [ //{ //"name": "string", //"content": "string", //"showToPayer": true //} //], //"itemId": "string", //"receiverTxId": "CTXXXXXXXXXXXX999999995800" }, ], }; const [ok, out] = await callApi("POST", url, body); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 10) Preview Pagamento (BOLETO) =============== did not test*/ async function Preview(emv) { const url = `${BAAS_URL}/v1/payments/preview`; const body = { emv }; const [ok, out] = await callApi("POST", url, body); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 11) Boleto Pay =============== did not test*/ async function BoletoPay(taxId, line, description, uuid) { const url = `${BAAS_URL}/v1/payments/boleto`; const body = { taxId, description: description || "Pagamento de boleto", line, uuid: uuid || `BOL-${Date.now()}`, }; const [ok, out] = await callApi("POST", url, body); if (!ok) return fail(out); console.dir(out, { depth: null }); } /* =============== 12) Boleto Get by Id =============== did not test*/ async function BoletoGet(id) { const url = `${BAAS_URL}/v1/payments/boleto/${encodeURIComponent(id)}`; const [ok, out] = await callApi("GET", url); if (!ok) return fail(out); console.dir(out, { depth: null }); } main();