From edaeb5d77aacb3edad3c4c585ca8b672e4a8f9cf Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 4 Sep 2025 15:16:48 -0700 Subject: [PATCH 1/2] IO-3355 Job Cash Discounting Signed-off-by: Allan Carr --- ...totals.cash-discount-display.component.jsx | 46 +++++-------- server/intellipay/intellipay.js | 69 +++++-------------- 2 files changed, 37 insertions(+), 78 deletions(-) diff --git a/client/src/components/job-totals-table/jobs-totals.cash-discount-display.component.jsx b/client/src/components/job-totals-table/jobs-totals.cash-discount-display.component.jsx index e5a89e23c..409e2e5dc 100644 --- a/client/src/components/job-totals-table/jobs-totals.cash-discount-display.component.jsx +++ b/client/src/components/job-totals-table/jobs-totals.cash-discount-display.component.jsx @@ -20,35 +20,27 @@ export function JobTotalsCashDiscount({ bodyshop, amountDinero }) { const notification = useNotification(); const fetchData = useCallback(async () => { - if (amountDinero && bodyshop) { - setLoading(true); - let response; - try { - response = await axios.post("/intellipay/checkfee", { - bodyshop: { id: bodyshop.id, imexshopid: bodyshop.imexshopid, state: bodyshop.state }, - amount: Dinero(amountDinero).toFormat("0.00") - }); + if (!amountDinero || !bodyshop) return; - if (response?.data?.error) { - notification.open({ - type: "error", - message: - response.data?.error || - "Error encountered when contacting IntelliPay service to determine cash discounted price." - }); - } else { - setFee(response.data?.fee || 0); - } - } catch (error) { - notification.open({ - type: "error", - message: - error.response?.data?.error || - "Error encountered when contacting IntelliPay service to determine cash discounted price." - }); - } finally { - setLoading(false); + setLoading(true); + const errorMessage = "Error encountered when contacting IntelliPay service to determine cash discounted price."; + + try { + const { id, imexshopid, state } = bodyshop; + const { data } = await axios.post("/intellipay/checkfee", { + bodyshop: { id, imexshopid, state }, + amount: Dinero(amountDinero).toUnit() + }); + + if (data?.error) { + notification.open({ type: "error", message: data.error || errorMessage }); + } else { + setFee(data?.fee ?? 0); } + } catch (error) { + notification.open({ type: "error", message: error.response?.data?.error || errorMessage }); + } finally { + setLoading(false); } }, [amountDinero, bodyshop, notification]); diff --git a/server/intellipay/intellipay.js b/server/intellipay/intellipay.js index faa725faf..bc6c0763f 100644 --- a/server/intellipay/intellipay.js +++ b/server/intellipay/intellipay.js @@ -252,35 +252,27 @@ const generatePaymentUrl = async (req, res) => { * @returns {Promise} */ const checkFee = async (req, res) => { - 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 - }; + const { bodyshop = {}, amount } = req.body || {}; + const { id, imexshopid, shopname, state } = bodyshop; + const logResponseMeta = { bodyshop: { id, imexshopid, name: shopname, state }, amount }; logger.log("intellipay-checkfee-request-received", "DEBUG", req.user?.email, null, logResponseMeta); - if (!isNumber(req.body?.amount) || req.body?.amount <= 0) { + if (!isNumber(amount) || amount <= 0) { logger.log("intellipay-checkfee-skip", "DEBUG", req.user?.email, null, { message: "Amount is zero or undefined, skipping fee check.", ...logResponseMeta }); - return res.json({ fee: 0 }); } - const shopCredentials = await getShopCredentials(req.body.bodyshop); + const shopCredentials = await getShopCredentials(bodyshop); if (shopCredentials?.error) { logger.log("intellipay-checkfee-credentials-error", "ERROR", req.user?.email, null, { message: shopCredentials.error?.message, ...logResponseMeta }); - return res.status(400).json({ error: shopCredentials.error?.message, ...logResponseMeta }); } @@ -292,13 +284,10 @@ const checkFee = async (req, res) => { { method: "fee", ...shopCredentials, - amount: req.body.amount, - paymenttype: `CC`, + amount: String(amount), // Type cast to string as required by API + paymenttype: "CC", cardnum: "4111111111111111", // Required for compatibility with API - state: - req.body.bodyshop?.state && req.body.bodyshop.state.length === 2 - ? req.body.bodyshop.state.toUpperCase() - : "ZZ" + state: state?.toUpperCase() || "ZZ" }, { sort: false } // Ensure query string order is preserved ), @@ -310,46 +299,24 @@ const checkFee = async (req, res) => { ...logResponseMeta }); - const response = await axios(options); + const { data } = await axios(options); - if (response.data?.error) { - logger.log("intellipay-checkfee-api-error", "ERROR", req.user?.email, null, { - message: response.data?.error, - ...logResponseMeta - }); - - return res.status(400).json({ - error: response.data?.error, - type: "intellipay-checkfee-api-error", - ...logResponseMeta - }); + if (data?.error || data < 0) { + const errorType = data?.error ? "intellipay-checkfee-api-error" : "intellipay-checkfee-negative-fee"; + const errorMessage = data?.error + ? data?.error + : "Fee amount negative. Check API credentials & account configuration."; + logger.log(errorType, "ERROR", req.user?.email, null, { message: errorMessage, data, ...logResponseMeta }); + return res.status(400).json({ error: errorMessage, type: errorType, data, ...logResponseMeta }); } - if (response.data < 0) { - logger.log("intellipay-checkfee-negative-fee", "ERROR", req.user?.email, null, { - message: "Fee amount returned is negative.", - ...logResponseMeta - }); - - return res.json({ - error: "Fee amount negative. Check API credentials & account configuration.", - ...logResponseMeta, - type: "intellipay-checkfee-negative-fee" - }); - } - - logger.log("intellipay-checkfee-success", "DEBUG", req.user?.email, null, { - fee: response.data, - ...logResponseMeta - }); - - return res.json({ fee: response.data, ...logResponseMeta }); + logger.log("intellipay-checkfee-success", "DEBUG", req.user?.email, null, { fee: data, ...logResponseMeta }); + return res.json({ fee: data, ...logResponseMeta }); } catch (error) { logger.log("intellipay-checkfee-error", "ERROR", req.user?.email, null, { message: error?.message, ...logResponseMeta }); - return res.status(500).json({ error: error?.message, logResponseMeta }); } }; From d9f59fcad4047dba8d5945b06242fb95b124e371 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Thu, 4 Sep 2025 15:27:06 -0700 Subject: [PATCH 2/2] IO-3355 Correct translation Signed-off-by: Allan Carr --- client/src/components/vendors-form/vendors-form.component.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/components/vendors-form/vendors-form.component.jsx b/client/src/components/vendors-form/vendors-form.component.jsx index 20aa07d9c..7d2cd1468 100644 --- a/client/src/components/vendors-form/vendors-form.component.jsx +++ b/client/src/components/vendors-form/vendors-form.component.jsx @@ -173,7 +173,7 @@ export function VendorsFormComponent({ bodyshop, form, formLoading, handleDelete