From 8cee795d700b2cfdd11becb0b3b121c81b720883 Mon Sep 17 00:00:00 2001 From: Dave Richer Date: Thu, 12 Dec 2024 13:12:47 -0800 Subject: [PATCH] feature/IO-3056-Enhanced-Lightbox-Logging --- .../card-payment-modal.component..jsx | 4 +- server/intellipay/intellipay.js | 280 ++++++++++++------ 2 files changed, 188 insertions(+), 96 deletions(-) diff --git a/client/src/components/card-payment-modal/card-payment-modal.component..jsx b/client/src/components/card-payment-modal/card-payment-modal.component..jsx index 67fa15e4d..eef9f3ddb 100644 --- a/client/src/components/card-payment-modal/card-payment-modal.component..jsx +++ b/client/src/components/card-payment-modal/card-payment-modal.component..jsx @@ -119,13 +119,15 @@ const CardPaymentModalComponent = ({ } const iPayData = collectIPayFields(); + const { payments } = form.getFieldsValue(); try { const response = await axios.post("/intellipay/lightbox_credentials", { bodyshop, refresh: !!window.intellipay, paymentSplitMeta: form.getFieldsValue(), - iPayData: iPayData + iPayData: iPayData, + comment: btoa(JSON.stringify({ payments, userEmail: currentUser.email })) }); if (window.intellipay) { diff --git a/server/intellipay/intellipay.js b/server/intellipay/intellipay.js index a1fe11a6d..aa3ddb464 100644 --- a/server/intellipay/intellipay.js +++ b/server/intellipay/intellipay.js @@ -1,4 +1,7 @@ const path = require("path"); +require("dotenv").config({ + path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) +}); const queries = require("../graphql-client/queries"); const Dinero = require("dinero.js"); const qs = require("query-string"); @@ -8,9 +11,6 @@ const logger = require("../utils/logger"); const { sendTaskEmail } = require("../email/sendemail"); const generateEmailTemplate = require("../email/generateTemplate"); const { getEndpoints } = require("../email/tasksEmails"); -require("dotenv").config({ - path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) -}); const domain = process.env.NODE_ENV ? "secure" : "test"; @@ -50,17 +50,40 @@ const getShopCredentials = async (bodyshop) => { } }; +const decodeComment = (comment) => { + try { + return comment ? JSON.parse(Buffer.from(comment, "base64").toString()) : null; + } catch (error) { + return null; // Handle malformed base64 string gracefully + } +}; + exports.lightbox_credentials = async (req, res) => { - logger.log("intellipay-lightbox-credentials", "DEBUG", req.user?.email, null, { - iPayData: req.body.iPayData, - bodyshop: req.body.bodyshop - }); + const decodedComment = decodeComment(req.body?.comment); + const logMeta = { + iPayData: req.body?.iPayData, + decodedComment, + bodyshop: { + id: req.body?.bodyshop?.id, + imexshopid: req.body?.bodyshop?.imexshopid, + name: req.body?.bodyshop?.shopname + } + }; + + logger.log("intellipay-lightbox-credentials", "DEBUG", req.user?.email, null, logMeta); const shopCredentials = await getShopCredentials(req.body.bodyshop); if (shopCredentials.error) { - logger.log("intellipay-credentials-error", "ERROR", req.user?.email, null, { message: shopCredentials.error }); - res.json(shopCredentials); + logger.log("intellipay-credentials-error", "ERROR", req.user?.email, null, { + message: shopCredentials.error?.message, + ...logMeta + }); + res.json({ + message: shopCredentials.error?.message, + type: "intellipay-credentials-error", + ...logMeta + }); return; } @@ -78,31 +101,53 @@ exports.lightbox_credentials = async (req, res) => { const response = await axios(options); logger.log("intellipay-lightbox-success", "DEBUG", req.user?.email, null, { - responseData: response.data, - requestOptions: options + requestOptions: options, + ...logMeta }); res.send(response.data); } catch (error) { - logger.log("intellipay-lightbox-error", "ERROR", req.user?.email, null, { message: error.message }); - res.json({ message: error.message }); + logger.log("intellipay-lightbox-error", "ERROR", req.user?.email, null, { + message: error?.message, + ...logMeta + }); + res.json({ + message: error?.message, + type: "intellipay-lightbox-error", + ...logMeta + }); } }; exports.payment_refund = async (req, res) => { - logger.log("intellipay-refund-request-received", "DEBUG", req.user?.email, null, { - bodyshop: req.body.bodyshop, - paymentid: req.body.paymentid, - amount: req.body.amount - }); + const decodedComment = decodeComment(req.body.iPayData?.comment); + const logResponseMeta = { + iPayData: req.body?.iPayData, + bodyshop: { + id: req.body.bodyshop?.id, + imexshopid: req.body.bodyshop?.imexshopid, + name: req.body.bodyshop?.shopname + }, + paymentid: req.body?.paymentid, + amount: req.body?.amount, + decodedComment + }; + + logger.log("intellipay-refund-request-received", "DEBUG", req.user?.email, null, logResponseMeta); const shopCredentials = await getShopCredentials(req.body.bodyshop); if (shopCredentials.error) { logger.log("intellipay-refund-credentials-error", "ERROR", req.user?.email, null, { - credentialsError: shopCredentials.error + credentialsError: shopCredentials.error, + ...logResponseMeta + }); + + res.status(400).json({ + credentialsError: shopCredentials.error, + type: "intellipay-refund-credentials-error", + ...logResponseMeta }); - res.status(400).json({ error: shopCredentials.error }); return; } @@ -120,45 +165,61 @@ exports.payment_refund = async (req, res) => { }; logger.log("intellipay-refund-options-prepared", "DEBUG", req.user?.email, null, { - options + requestOptions: options, + ...logResponseMeta }); const response = await axios(options); logger.log("intellipay-refund-success", "DEBUG", req.user?.email, null, { - responseData: response.data + requestOptions: options, + ...logResponseMeta }); res.send(response.data); } catch (error) { logger.log("intellipay-refund-error", "ERROR", req.user?.email, null, { - error: error.message, - stack: error.stack, - requestOptions: { - paymentid: req.body.paymentid, - amount: req.body.amount - } + message: error?.message, + ...logResponseMeta + }); + res.status(500).json({ + message: error?.message, + type: "intellipay-refund-error", + ...logResponseMeta }); - res.status(500).json({ error: error.message }); } }; exports.generate_payment_url = async (req, res) => { - logger.log("intellipay-generate-payment-url-received", "DEBUG", req.user?.email, null, { - bodyshop: req.body.bodyshop, - amount: req.body.amount, - account: req.body.account, - comment: req.body.comment, - invoice: req.body.invoice - }); + const decodedComment = decodeComment(req.body.comment); + const logResponseMeta = { + iPayData: req.body?.iPayData, + bodyshop: { + id: req.body.bodyshop?.id, + imexshopid: req.body.bodyshop?.imexshopid, + name: req.body.bodyshop?.shopname + }, + amount: req.body?.amount, + account: req.body?.account, + comment: req.body?.comment, + invoice: req.body?.invoice, + decodedComment + }; + + logger.log("intellipay-generate-payment-url-received", "DEBUG", req.user?.email, null, logResponseMeta); const shopCredentials = await getShopCredentials(req.body.bodyshop); if (shopCredentials.error) { logger.log("intellipay-generate-payment-url-credentials-error", "ERROR", req.user?.email, null, { - credentialsError: shopCredentials.error + message: shopCredentials.error?.message, + ...logResponseMeta + }); + res.status(400).json({ + message: shopCredentials.error?.message, + type: "intellipay-generate-payment-url-credentials-error", + ...logResponseMeta }); - res.status(400).json({ error: shopCredentials.error }); return; } @@ -178,41 +239,46 @@ exports.generate_payment_url = async (req, res) => { }; logger.log("intellipay-generate-payment-url-options-prepared", "DEBUG", req.user?.email, null, { - options + requestOptions: options, + ...logResponseMeta }); const response = await axios(options); logger.log("intellipay-generate-payment-url-success", "DEBUG", req.user?.email, null, { - responseData: response.data + requestOptions: options, + shortUrl: response.data?.shorturl, + ...logResponseMeta }); res.send(response.data); } catch (error) { logger.log("intellipay-generate-payment-url-error", "ERROR", req.user?.email, null, { - error: error.message, - stack: error.stack, - requestOptions: { - amount: req.body.amount, - account: req.body.account, - comment: req.body.comment, - invoice: req.body.invoice - } + message: error?.message, + ...logResponseMeta }); - res.status(500).json({ error: error.message }); + res.status(500).json({ message: error?.message, ...logResponseMeta }); } }; //Reference: https://intellipay.com/dist/webapi26.html#operation/fee exports.checkfee = async (req, res) => { - logger.log("intellipay-checkfee-request-received", "DEBUG", req.user?.email, null, { - bodyshop: req.body.bodyshop, - amount: req.body.amount - }); + const logResponseMeta = { + bodyshop: { + id: req.body?.bodyshop?.id, + imexshopid: req.body?.bodyshop?.imexshopid, + name: req.body?.bodyshop?.shopname, + state: req.body?.bodyshop?.state + }, + amount: req.body?.amount + }; + + logger.log("intellipay-checkfee-request-received", "DEBUG", req.user?.email, null, logResponseMeta); if (!req.body.amount || req.body.amount <= 0) { logger.log("intellipay-checkfee-skip", "DEBUG", req.user?.email, null, { - message: "Amount is zero or undefined, skipping fee check." + message: "Amount is zero or undefined, skipping fee check.", + ...logResponseMeta }); res.json({ fee: 0 }); return; @@ -222,9 +288,10 @@ exports.checkfee = async (req, res) => { if (shopCredentials.error) { logger.log("intellipay-checkfee-credentials-error", "ERROR", req.user?.email, null, { - credentialsError: shopCredentials.error + message: shopCredentials.error?.message, + ...logResponseMeta }); - res.status(400).json({ error: shopCredentials.error }); + res.status(400).json({ error: shopCredentials.error?.message, ...logResponseMeta }); return; } @@ -250,56 +317,70 @@ exports.checkfee = async (req, res) => { }; logger.log("intellipay-checkfee-options-prepared", "DEBUG", req.user?.email, null, { - options + requestOptions: options, + ...logResponseMeta }); const response = await axios(options); if (response.data?.error) { logger.log("intellipay-checkfee-api-error", "ERROR", req.user?.email, null, { - apiError: response.data.error + message: response.data?.error, + ...logResponseMeta + }); + res.status(400).json({ + error: response.data?.error, + type: "intellipay-checkfee-api-error", + ...logResponseMeta }); - res.status(400).json({ error: response.data.error }); } else if (response.data < 0) { - logger.log("intellipay-checkfee-negative-fee", "ERROR", req.user?.email, "Fee amount returned is negative."); - res.json({ error: "Fee amount negative. Check API credentials & account configuration." }); + logger.log("intellipay-checkfee-negative-fee", "ERROR", req.user?.email, null, { + message: "Fee amount returned is negative.", + ...logResponseMeta + }); + res.json({ + error: "Fee amount negative. Check API credentials & account configuration.", + ...logResponseMeta, + type: "intellipay-checkfee-negative-fee" + }); } else { logger.log("intellipay-checkfee-success", "DEBUG", req.user?.email, null, { - fee: response.data + fee: response.data, + ...logResponseMeta }); - res.json({ fee: response.data }); + res.json({ fee: response.data, ...logResponseMeta }); } } catch (error) { logger.log("intellipay-checkfee-error", "ERROR", req.user?.email, null, { - error: error.message, - stack: error.stack, - amount: req.body.amount + message: error?.message, + ...logResponseMeta }); - res.status(500).json({ error: error.message }); + res.status(500).json({ error: error?.message, logResponseMeta }); } }; exports.postback = async (req, res) => { + const { body: values } = req; + const decodedComment = decodeComment(values?.comment); + const logResponseMeta = { + bodyshop: { + id: req.body?.bodyshop?.id, + imexshopid: req.body?.bodyshop?.imexshopid, + name: req.body?.bodyshop?.shopname, + state: req.body?.bodyshop?.state + }, + iprequest: values, + decodedComment + }; + + logger.log("intellipay-postback-received", "DEBUG", req.user?.email, null, logResponseMeta); + try { - const { body: values } = req; - - logger.log("intellipay-postback-received", "DEBUG", req.user?.email, null, { - iprequest: values, - base64Comment: values?.comment || null - }); - - // Decode the base64 comment, if it exists - const decodedComment = values?.comment ? Buffer.from(values.comment, "base64").toString() : null; - - logger.log("intellipay-postback-decoded-comment", "DEBUG", req.user?.email, null, { - decodedComment - }); - if ((!values.invoice || values.invoice === "") && !decodedComment) { //invoice is specified through the pay link. Comment by IO. logger.log("intellipay-postback-ignored", "DEBUG", req.user?.email, null, { - reason: "No invoice or comment provided", - iprequest: values + message: "No invoice or comment provided", + ...logResponseMeta }); res.sendStatus(200); return; @@ -311,7 +392,8 @@ exports.postback = async (req, res) => { const parsedComment = JSON.parse(decodedComment); logger.log("intellipay-postback-parsed-comment", "DEBUG", req.user?.email, null, { - parsedComment + parsedComment, + ...logResponseMeta }); //Adding in the user email to the short pay email. @@ -325,7 +407,9 @@ exports.postback = async (req, res) => { }); logger.log("intellipay-postback-jobs-fetched", "DEBUG", req.user?.email, null, { - jobs + jobs, + parsedComment, + ...logResponseMeta }); // Insert new payments @@ -352,7 +436,10 @@ exports.postback = async (req, res) => { }); logger.log("intellipay-postback-payment-success", "DEBUG", req.user?.email, null, { - paymentResult + paymentResult, + jobs, + parsedComment, + ...logResponseMeta }); if (values.origin === "OneLink" && parsedComment.userEmail) { @@ -375,9 +462,10 @@ exports.postback = async (req, res) => { }); } catch (error) { logger.log("intellipay-postback-email-error", "ERROR", req.user?.email, null, { - error: error.message, + message: error.message, jobs, - paymentResult + paymentResult, + ...logResponseMeta }); } } @@ -388,7 +476,8 @@ exports.postback = async (req, res) => { }); logger.log("intellipay-postback-invoice-job-fetched", "DEBUG", req.user?.email, null, { - job + job, + ...logResponseMeta }); const paymentResult = await gqlClient.request(queries.INSERT_NEW_PAYMENT, { @@ -403,7 +492,8 @@ exports.postback = async (req, res) => { }); logger.log("intellipay-postback-invoice-payment-success", "DEBUG", req.user?.email, null, { - paymentResult + paymentResult, + ...logResponseMeta }); const responseResults = await gqlClient.request(queries.INSERT_PAYMENT_RESPONSE, { @@ -420,16 +510,16 @@ exports.postback = async (req, res) => { }); logger.log("intellipay-postback-invoice-response-success", "DEBUG", req.user?.email, null, { - responseResults + responseResults, + ...logResponseMeta }); res.sendStatus(200); } } catch (error) { logger.log("intellipay-postback-error", "ERROR", req.user?.email, null, { - error: error.message, - stack: error.stack, - iprequest: req.body + message: error?.message, + ...logResponseMeta }); - res.status(400).json({ successful: false, error: error.message }); + res.status(400).json({ successful: false, error: error.message, ...logResponseMeta }); } };