From 613c09594fa11a72170dcdd6c302b6f9b8ff7aed Mon Sep 17 00:00:00 2001 From: Leonardo Matos Date: Thu, 1 Aug 2024 17:17:39 -0300 Subject: [PATCH] fix(apps): Prefering keys from app data (when available) over env vars Update env vars always config keys are read from app data (seller config) --- .../mercadopago/src/mp-create-transaction.ts | 32 ++-- packages/apps/mercadopago/src/mp-webhook.ts | 162 +++++++++--------- .../pagarme/src/pagarme-create-transaction.ts | 19 +- packages/apps/pagarme/src/pagarme-webhook.ts | 15 +- .../src/paghiper-create-transaction.ts | 17 +- .../apps/pix/src/pix-create-transaction.ts | 33 ++-- packages/apps/pix/src/pix-list-payments.ts | 28 ++- 7 files changed, 148 insertions(+), 158 deletions(-) diff --git a/packages/apps/mercadopago/src/mp-create-transaction.ts b/packages/apps/mercadopago/src/mp-create-transaction.ts index f818f4647..c3eb7e96c 100644 --- a/packages/apps/mercadopago/src/mp-create-transaction.ts +++ b/packages/apps/mercadopago/src/mp-create-transaction.ts @@ -4,8 +4,7 @@ import type { CreateTransactionResponse, } from '@cloudcommerce/types'; import { getFirestore } from 'firebase-admin/firestore'; -import logger from 'firebase-functions/logger'; -import config from '@cloudcommerce/firebase/lib/config'; +import config, { logger } from '@cloudcommerce/firebase/lib/config'; import axios from 'axios'; const parsePaymentStatus = (status: string) => { @@ -60,7 +59,7 @@ export default async (appData: AppModuleBody) => { const { buyer } = params; const orderId = params.order_id; - logger.log('> MP Transaction #', storeId, orderId); + logger.info('> MP Transaction #', { storeId, orderId }); // https://www.mercadopago.com.br/developers/pt/reference/payments/_payments/post/ const payerPhone = { @@ -145,20 +144,19 @@ export default async (appData: AppModuleBody) => { ecom_order_id: orderId, }, }; - logger.log('>data: ', JSON.stringify(payment)); + logger.info('>data: ', payment); + const mpAccessToken = configApp.mp_access_token; + if (typeof mpAccessToken === 'string' && mpAccessToken) { + process.env.MERCADOPAGO_TOKEN = mpAccessToken; + } if (!process.env.MERCADOPAGO_TOKEN) { - const mpAccessToken = configApp.mp_access_token; - if (typeof mpAccessToken === 'string' && mpAccessToken) { - process.env.MERCADOPAGO_TOKEN = mpAccessToken; - } else { - logger.warn('Missing Mercadopago access token'); - return { - status: 409, - error: 'CREATE_TRANSACTION_ERR', - message: 'The MERCADOPAGO_TOKEN is not defined in the environment variables', - }; - } + logger.warn('Missing Mercadopago access token'); + return { + status: 409, + error: 'CREATE_TRANSACTION_ERR', + message: 'The MERCADOPAGO_TOKEN is not defined in the environment variables', + }; } try { @@ -179,7 +177,7 @@ export default async (appData: AppModuleBody) => { data: payment, }); if (data) { - logger.log('> MP Checkout #', storeId, orderId); + logger.info('> MP Checkout #', { storeId, orderId }); const statusPayment = parsePaymentStatus(data.status); let isSaveRetry = false; @@ -198,7 +196,7 @@ export default async (appData: AppModuleBody) => { merge: true, }) .then(() => { - logger.log('> Payment #', String(data.id)); + logger.info('> Payment #', { paymentId: String(data.id) }); resolve(true); }) .catch((err) => { diff --git a/packages/apps/mercadopago/src/mp-webhook.ts b/packages/apps/mercadopago/src/mp-webhook.ts index 531cc5ded..bc24b5238 100644 --- a/packages/apps/mercadopago/src/mp-webhook.ts +++ b/packages/apps/mercadopago/src/mp-webhook.ts @@ -23,107 +23,103 @@ export const mercadopago = { const app = (await api.get( `applications?app_id=${config.get().apps.mercadoPago.appId}&fields=hidden_data`, )).data.result; + const mpAccessToken = app[0]?.hidden_data?.mp_access_token; + if (typeof mpAccessToken === 'string' && mpAccessToken) { + process.env.MERCADOPAGO_TOKEN = mpAccessToken; + } if (!process.env.MERCADOPAGO_TOKEN) { - const mpAccessToken = app[0].hidden_data?.mp_access_token; - if (typeof mpAccessToken === 'string' && mpAccessToken) { - process.env.MERCADOPAGO_TOKEN = mpAccessToken; - } else { - logger.warn('Missing Mercadopago access token'); - } + logger.warn('Missing Mercadopago access token'); + res.sendStatus(406); + return; } - if (process.env.MERCADOPAGO_TOKEN) { - const notification = req.body; - if (notification.type !== 'payment' || !notification.data || !notification.data.id) { - res.status(404).send('SKIP'); - } - - logger.log('> MP Notification for Payment #', notification.data.id); + const notification = req.body; + if (notification.type !== 'payment' || !notification.data || !notification.data.id) { + res.status(404).send('SKIP'); + } + logger.log('> MP Notification for Payment #', notification.data.id); - const docRef = getFirestore().collection('mercadopagoPayments') - .doc(String(notification.data.id)); + const docRef = getFirestore().collection('mercadopagoPayments') + .doc(String(notification.data.id)); - docRef.get() - .then(async (doc) => { - if (doc.exists) { - const data = doc.data(); - const orderId = data?.order_id; - const order = (await api.get( - `orders/${orderId}`, - )).data; - logger.log('>order ', JSON.stringify(order), '<'); - if (order && order.transactions) { - const payment = (await axios.get( - `https://api.mercadopago.com/v1/payments/${notification.data.id}`, - { - headers: { - Authorization: `Bearer ${process.env.MERCADOPAGO_TOKEN}`, - 'Content-Type': 'application/json', - }, + docRef.get() + .then(async (doc) => { + if (doc.exists) { + const data = doc.data(); + const orderId = data?.order_id; + const order = (await api.get( + `orders/${orderId}`, + )).data; + logger.log('>order ', JSON.stringify(order), '<'); + if (order && order.transactions) { + const payment = (await axios.get( + `https://api.mercadopago.com/v1/payments/${notification.data.id}`, + { + headers: { + Authorization: `Bearer ${process.env.MERCADOPAGO_TOKEN}`, + 'Content-Type': 'application/json', }, - )).data; - logger.log('>payment ', JSON.stringify(payment), ' <'); - const methodPayment = payment.payment_method_id; + }, + )).data; + logger.log('>payment ', JSON.stringify(payment), ' <'); + const methodPayment = payment.payment_method_id; - const transaction = order.transactions.find(({ intermediator }) => { - return intermediator - && intermediator.transaction_code === notification.data.id; - }); - const status = parsePaymentStatus(payment.status); - if (transaction) { - const bodyPaymentHistory = { - transaction_id: transaction._id, - date_time: new Date().toISOString(), - status, - notification_code: String(notification.id), - flags: [ - 'mercadopago', - ], - } as any; // TODO: incompatible type=> amount and status + const transaction = order.transactions.find(({ intermediator }) => { + return intermediator + && intermediator.transaction_code === notification.data.id; + }); + const status = parsePaymentStatus(payment.status); + if (transaction) { + const bodyPaymentHistory = { + transaction_id: transaction._id, + date_time: new Date().toISOString(), + status, + notification_code: String(notification.id), + flags: [ + 'mercadopago', + ], + } as any; // TODO: incompatible type=> amount and status - if (status !== order.financial_status?.current) { - // avoid unnecessary API request - await api.post(`orders/${orderId}/payments_history`, bodyPaymentHistory); - const updatedAt = new Date().toISOString(); - docRef.set({ status, updatedAt }, { merge: true }).catch(logger.error); - } + if (status !== order.financial_status?.current) { + // avoid unnecessary API request + await api.post(`orders/${orderId}/payments_history`, bodyPaymentHistory); + const updatedAt = new Date().toISOString(); + docRef.set({ status, updatedAt }, { merge: true }).catch(logger.error); + } - if ((status === 'paid' && methodPayment === 'pix' && transaction)) { - let { notes } = transaction; - notes = notes?.replace('display:block', 'display:none'); // disable QR Code - notes = `${notes} # PIX Aprovado`; + if ((status === 'paid' && methodPayment === 'pix' && transaction)) { + let { notes } = transaction; + notes = notes?.replace('display:block', 'display:none'); // disable QR Code + notes = `${notes} # PIX Aprovado`; - // Update to disable QR Code - try { - await api.patch( - `orders/${order._id}/transactions/${transaction._id}`, - { notes }, - ); - } catch (e) { - logger.error(e); - } + // Update to disable QR Code + try { + await api.patch( + `orders/${order._id}/transactions/${transaction._id}`, + { notes }, + ); + } catch (e) { + logger.error(e); } - res.status(200).send('SUCCESS'); - } else { - logger.log('> Transaction not found #', notification.data.id); - res.sendStatus(404); } + res.status(200).send('SUCCESS'); } else { - logger.log('> Order Not Found #', orderId); + logger.log('> Transaction not found #', notification.data.id); res.sendStatus(404); } } else { - logger.log('> Payment not found in Firestore #', notification.data.id); + logger.log('> Order Not Found #', orderId); res.sendStatus(404); } - }) - .catch((err) => { - logger.error(err); - res.sendStatus(503); - }); - } else { - res.sendStatus(406); - } + } else { + logger.log('> Payment not found in Firestore #', notification.data.id); + res.sendStatus(404); + } + }) + .catch((err) => { + logger.error(err); + res.sendStatus(503); + }); } catch (e) { logger.error(e); res.sendStatus(500); diff --git a/packages/apps/pagarme/src/pagarme-create-transaction.ts b/packages/apps/pagarme/src/pagarme-create-transaction.ts index ea286df02..240e766b0 100644 --- a/packages/apps/pagarme/src/pagarme-create-transaction.ts +++ b/packages/apps/pagarme/src/pagarme-create-transaction.ts @@ -37,17 +37,16 @@ export default async (modBody: AppModuleBody<'create_transaction'>) => { } = params; logger.info(`Transaction #${orderId}`); + const pagarmeToken = appData.pagarme_api_key; + if (typeof pagarmeToken === 'string' && pagarmeToken) { + process.env.PAGARME_TOKEN = pagarmeToken; + } if (!process.env.PAGARME_TOKEN) { - const pagarmeToken = appData.pagarme_api_key; - if (typeof pagarmeToken === 'string' && pagarmeToken) { - process.env.PAGARME_TOKEN = pagarmeToken; - } else { - logger.warn('Missing Pagar.me API token'); - return { - error: 'NO_PAGARME_KEYS', - message: 'Chave de API não configurada (lojista deve configurar o aplicativo)', - }; - } + logger.warn('Missing Pagar.me API token'); + return { + error: 'NO_PAGARME_KEYS', + message: 'Chave de API não configurada (lojista deve configurar o aplicativo)', + }; } // https://apx-mods.e-com.plus/api/v1/create_transaction/response_schema.json?store_id=100 diff --git a/packages/apps/pagarme/src/pagarme-webhook.ts b/packages/apps/pagarme/src/pagarme-webhook.ts index e724477d6..d6d4b64a4 100644 --- a/packages/apps/pagarme/src/pagarme-webhook.ts +++ b/packages/apps/pagarme/src/pagarme-webhook.ts @@ -22,15 +22,14 @@ export const pagarme = { `applications?app_id=${config.get().apps.pagarMe.appId}&fields=hidden_data`, )).data.result; + const pagarmeToken = app[0]?.hidden_data?.pagarme_api_key; + if (typeof pagarmeToken === 'string' && pagarmeToken) { + process.env.PAGARME_TOKEN = pagarmeToken; + } if (!process.env.PAGARME_TOKEN) { - const pagarmeToken = app[0].hidden_data?.pagarme_api_key; - if (typeof pagarmeToken === 'string' && pagarmeToken) { - process.env.PAGARME_TOKEN = pagarmeToken; - } else { - logger.warn('Missing PagarMe API token'); - res.sendStatus(409); - return; - } + logger.warn('Missing PagarMe API token'); + res.sendStatus(409); + return; } // https://docs.pagar.me/docs/gerenciando-postbacks diff --git a/packages/apps/paghiper/src/paghiper-create-transaction.ts b/packages/apps/paghiper/src/paghiper-create-transaction.ts index 6fbbd1783..abcb2c069 100644 --- a/packages/apps/paghiper/src/paghiper-create-transaction.ts +++ b/packages/apps/paghiper/src/paghiper-create-transaction.ts @@ -133,15 +133,18 @@ export default async (appData: AppModuleBody) => { paghiperTransaction.notification_url += '/pix'; } + const pagHiperToken = configApp.paghiper_api_key; + if (typeof pagHiperToken === 'string' && pagHiperToken) { + process.env.PAGHIPER_TOKEN = pagHiperToken; + } if (!process.env.PAGHIPER_TOKEN) { - const pagHiperToken = configApp.paghiper_api_key; - if (typeof pagHiperToken === 'string' && pagHiperToken) { - process.env.PAGHIPER_TOKEN = pagHiperToken; - } else { - logger.warn('Missing PagHiper API token'); - } + logger.warn('Missing PagHiper API token'); + return { + error: 'NO_PAGHIPER_KEYS', + message: 'Chave de API não configurada (lojista deve configurar o aplicativo)', + }; } - // use configured PagHiper API key + paghiperTransaction.apiKey = process.env.PAGHIPER_TOKEN; // merge configured banking billet options const options = configApp.banking_billet_options; diff --git a/packages/apps/pix/src/pix-create-transaction.ts b/packages/apps/pix/src/pix-create-transaction.ts index 0a06663eb..e6ac49058 100644 --- a/packages/apps/pix/src/pix-create-transaction.ts +++ b/packages/apps/pix/src/pix-create-transaction.ts @@ -103,11 +103,14 @@ export default async (appData: AppModuleBody) => { // const clientId = pixApi.client_id; // const clientSecret = pixApi.client_secret; - let clientId: string; - let clientSecret: string; - let tokenData: string; - - if (process.env.PIX_CREDENTIALS) { + let clientId: string | undefined; + let clientSecret: string | undefined; + let tokenData: string | undefined; + if (pixApi.client_id && pixApi.client_secret && pixApi.authentication) { + clientId = pixApi.client_id; + clientSecret = pixApi.client_secret; + tokenData = pixApi.authentication; + } else if (process.env.PIX_CREDENTIALS) { try { const pixCredentials = JSON.parse(process.env.PIX_CREDENTIALS); clientId = pixCredentials.client_id; @@ -115,15 +118,13 @@ export default async (appData: AppModuleBody) => { tokenData = pixCredentials.authentication; } catch (e) { logger.error(e); - - clientId = pixApi.client_id; - clientSecret = pixApi.client_secret; - tokenData = pixApi.authentication; } - } else { - clientId = pixApi.client_id; - clientSecret = pixApi.client_secret; - tokenData = pixApi.authentication; + } + if ((!clientId || !clientSecret) && !tokenData) { + return { + error: 'NO_PIX_CREDENTIALS', + message: 'Client ID e/ou Secret não configurados (lojista deve configurar o aplicativo)', + }; } const pix = new Pix({ @@ -236,9 +237,9 @@ export default async (appData: AppModuleBody) => { }; transaction.payment_link = qrCodeUrl; transaction.notes = ``; - - await saveToDb(clientId, clientSecret, pixApi, pix.axios, configApp, baseUri); - + if (clientId && clientSecret) { + await saveToDb(clientId, clientSecret, pixApi, pix.axios, configApp, baseUri); + } return { status: 200, redirect_to_payment: false, diff --git a/packages/apps/pix/src/pix-list-payments.ts b/packages/apps/pix/src/pix-list-payments.ts index b1b16ebab..de30ea24b 100644 --- a/packages/apps/pix/src/pix-list-payments.ts +++ b/packages/apps/pix/src/pix-list-payments.ts @@ -35,36 +35,30 @@ export default (data: AppModuleBody) => { return responseError(409, 'NO_PIX_CERTIFICATE', 'Certificado .PEM ou .P12 não configurado'); } - let clientId: string; - let clientSecret: string; - let authorization: string; - - if (process.env.PIX_CREDENTIALS) { + let clientId: string | undefined; + let clientSecret: string | undefined; + let tokenData: string | undefined; + if (pixApi.client_id && pixApi.client_secret && pixApi.authentication) { + clientId = pixApi.client_id; + clientSecret = pixApi.client_secret; + tokenData = pixApi.authentication; + } else if (process.env.PIX_CREDENTIALS) { try { const pixCredentials = JSON.parse(process.env.PIX_CREDENTIALS); clientId = pixCredentials.client_id; clientSecret = pixCredentials.client_secret; - authorization = pixCredentials.authentication; + tokenData = pixCredentials.authentication; } catch (e) { logger.error(e); - - clientId = pixApi.client_id; - clientSecret = pixApi.client_secret; - authorization = pixApi.authentication; } - } else { - clientId = pixApi.client_id; - clientSecret = pixApi.client_secret; - authorization = pixApi.authentication; } - - if ((!clientId || !clientSecret) && !authorization) { + if ((!clientId || !clientSecret) && !tokenData) { return responseError(409, 'NO_PIX_CREDENTIALS', 'Client ID e/ou Secret não configurados'); } + const response: ListPaymentsResponse = { payment_gateways: [], }; - // setup payment gateway object const gateway: Gateway = { label: 'Pagar com Pix',