feature/IO-2885-IntelliPay-App-Postback-Support

- Clean intellipay.js
This commit is contained in:
Dave Richer
2025-04-01 12:57:32 -04:00
parent 0ef2814de3
commit 09c1a8ae35

View File

@@ -8,6 +8,7 @@ const { sendTaskEmail } = require("../email/sendemail");
const generateEmailTemplate = require("../email/generateTemplate");
const { SecretsManagerClient, GetSecretValueCommand } = require("@aws-sdk/client-secrets-manager");
const { InstanceRegion, InstanceEndpoints } = require("../utils/instanceMgr");
const { isEmpty, isNumber } = require("lodash");
const domain = process.env.NODE_ENV ? "secure" : "test";
@@ -57,7 +58,6 @@ const getShopCredentials = async (bodyshop) => {
const decodeComment = (comment) => {
try {
return comment ? JSON.parse(Buffer.from(comment, "base64").toString()) : null;
// eslint-disable-next-line no-unused-vars
} catch (error) {
return null; // Handle malformed base64 string gracefully
}
@@ -85,17 +85,17 @@ const lightboxCredentials = async (req, res) => {
const shopCredentials = await getShopCredentials(req.body.bodyshop);
if (shopCredentials.error) {
if (shopCredentials?.error) {
logger.log("intellipay-credentials-error", "ERROR", req.user?.email, null, {
message: shopCredentials.error?.message,
...logMeta
});
res.json({
return res.json({
message: shopCredentials.error?.message,
type: "intellipay-credentials-error",
...logMeta
});
return;
}
try {
@@ -116,13 +116,14 @@ const lightboxCredentials = async (req, res) => {
...logMeta
});
res.send(response.data);
return res.send(response.data);
} catch (error) {
logger.log("intellipay-lightbox-error", "ERROR", req.user?.email, null, {
message: error?.message,
...logMeta
});
res.json({
return res.json({
message: error?.message,
type: "intellipay-lightbox-error",
...logMeta
@@ -154,18 +155,17 @@ const paymentRefund = async (req, res) => {
const shopCredentials = await getShopCredentials(req.body.bodyshop);
if (shopCredentials.error) {
if (shopCredentials?.error) {
logger.log("intellipay-refund-credentials-error", "ERROR", req.user?.email, null, {
credentialsError: shopCredentials.error,
...logResponseMeta
});
res.status(400).json({
return res.status(400).json({
credentialsError: shopCredentials.error,
type: "intellipay-refund-credentials-error",
...logResponseMeta
});
return;
}
try {
@@ -193,13 +193,14 @@ const paymentRefund = async (req, res) => {
...logResponseMeta
});
res.send(response.data);
return res.send(response.data);
} catch (error) {
logger.log("intellipay-refund-error", "ERROR", req.user?.email, null, {
message: error?.message,
...logResponseMeta
});
res.status(500).json({
return res.status(500).json({
message: error?.message,
type: "intellipay-refund-error",
...logResponseMeta
@@ -233,17 +234,17 @@ const generatePaymentUrl = async (req, res) => {
const shopCredentials = await getShopCredentials(req.body.bodyshop);
if (shopCredentials.error) {
if (shopCredentials?.error) {
logger.log("intellipay-generate-payment-url-credentials-error", "ERROR", req.user?.email, null, {
message: shopCredentials.error?.message,
...logResponseMeta
});
res.status(400).json({
return res.status(400).json({
message: shopCredentials.error?.message,
type: "intellipay-generate-payment-url-credentials-error",
...logResponseMeta
});
return;
}
try {
@@ -274,13 +275,14 @@ const generatePaymentUrl = async (req, res) => {
...logResponseMeta
});
res.send(response.data);
return res.send(response.data);
} catch (error) {
logger.log("intellipay-generate-payment-url-error", "ERROR", req.user?.email, null, {
message: error?.message,
...logResponseMeta
});
res.status(500).json({ message: error?.message, ...logResponseMeta });
return res.status(500).json({ message: error?.message, ...logResponseMeta });
}
};
@@ -304,24 +306,24 @@ const checkFee = async (req, res) => {
logger.log("intellipay-checkfee-request-received", "DEBUG", req.user?.email, null, logResponseMeta);
if (!req.body.amount || req.body.amount <= 0) {
if (!isNumber(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.",
...logResponseMeta
});
res.json({ fee: 0 });
return;
return res.json({ fee: 0 });
}
const shopCredentials = await getShopCredentials(req.body.bodyshop);
if (shopCredentials.error) {
if (shopCredentials?.error) {
logger.log("intellipay-checkfee-credentials-error", "ERROR", req.user?.email, null, {
message: shopCredentials.error?.message,
...logResponseMeta
});
res.status(400).json({ error: shopCredentials.error?.message, ...logResponseMeta });
return;
return res.status(400).json({ error: shopCredentials.error?.message, ...logResponseMeta });
}
try {
@@ -357,34 +359,40 @@ const checkFee = async (req, res) => {
message: response.data?.error,
...logResponseMeta
});
res.status(400).json({
return res.status(400).json({
error: response.data?.error,
type: "intellipay-checkfee-api-error",
...logResponseMeta
});
} else if (response.data < 0) {
}
if (response.data < 0) {
logger.log("intellipay-checkfee-negative-fee", "ERROR", req.user?.email, null, {
message: "Fee amount returned is negative.",
...logResponseMeta
});
res.json({
return 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,
...logResponseMeta
});
res.json({ fee: response.data, ...logResponseMeta });
}
logger.log("intellipay-checkfee-success", "DEBUG", req.user?.email, null, {
fee: response.data,
...logResponseMeta
});
return res.json({ fee: response.data, ...logResponseMeta });
} catch (error) {
logger.log("intellipay-checkfee-error", "ERROR", req.user?.email, null, {
message: error?.message,
...logResponseMeta
});
res.status(500).json({ error: error?.message, logResponseMeta });
return res.status(500).json({ error: error?.message, logResponseMeta });
}
};
@@ -406,19 +414,15 @@ const postBack = async (req, res) => {
logger.log("intellipay-postback-received", "DEBUG", "api", null, logResponseMeta);
try {
if ((!values.invoice || values.invoice === "") && !decodedComment) {
//invoice is specified through the pay link. Comment by IO.
if (isEmpty(values?.invoice) && !decodedComment) {
logger.log("intellipay-postback-ignored", "DEBUG", "api", null, {
message: "No invoice or comment provided",
...logResponseMeta
});
res.sendStatus(200);
return;
return res.sendStatus(200);
}
if (decodedComment) {
//Shifted the order to have this first to retain backwards compatibility for the old style of short link.
//This has been triggered by IO and may have multiple jobs.
const parsedComment = decodedComment;
logger.log("intellipay-postback-parsed-comment", "DEBUG", "api", null, {
@@ -426,18 +430,16 @@ const postBack = async (req, res) => {
...logResponseMeta
});
//Adding in the user email to the short pay email.
//Need to check this to ensure backwards compatibility for clients that don't update.
const partialPayments = Array.isArray(parsedComment) ? parsedComment : parsedComment.payments;
// Fetch jobs by job IDs
const jobs = await gqlClient.request(queries.GET_JOBS_BY_PKS, {
ids: partialPayments.map((p) => p.jobid)
});
const bodyshop = await gqlClient.request(queries.GET_BODYSHOP_BY_ID, {
id: jobs.jobs[0].shopid
});
const ipMapping = bodyshop.bodyshops_by_pk.intellipay_config?.payment_map;
logger.log("intellipay-postback-jobs-fetched", "DEBUG", "api", null, {
@@ -446,7 +448,6 @@ const postBack = async (req, res) => {
...logResponseMeta
});
// Insert new payments
const paymentResult = await gqlClient.request(queries.INSERT_NEW_PAYMENT, {
paymentInput: partialPayments.map((p) => ({
amount: p.amount,
@@ -476,7 +477,7 @@ const postBack = async (req, res) => {
...logResponseMeta
});
if (values.origin === "OneLink" && parsedComment.userEmail) {
if (values?.origin === "OneLink" && parsedComment?.userEmail) {
sendTaskEmail({
to: parsedComment.userEmail,
subject: `New Payment(s) Received - RO ${jobs.jobs.map((j) => j.ro_number).join(", ")}`,
@@ -500,8 +501,11 @@ const postBack = async (req, res) => {
});
});
}
res.sendStatus(200);
} else if (values.invoice) {
return res.sendStatus(200);
}
if (values?.invoice) {
const job = await gqlClient.request(queries.GET_JOB_BY_PK, {
id: values.invoice
});
@@ -551,14 +555,24 @@ const postBack = async (req, res) => {
responseResults,
...logResponseMeta
});
res.sendStatus(200);
return res.sendStatus(200);
}
// Default case: no valid conditions met
logger.log("intellipay-postback-invalid", "WARN", "api", null, {
message: "No valid invoice or comment provided",
...logResponseMeta
});
return res.status(400).send("Bad Request: No valid invoice or comment provided");
} catch (error) {
logger.log("intellipay-postback-error", "ERROR", "api", null, {
message: error?.message,
...logResponseMeta
});
res.status(400).json({ successful: false, error: error.message, ...logResponseMeta });
return res.status(400).json({ successful: false, error: error.message, ...logResponseMeta });
}
};