|
|
|
|
@@ -18,21 +18,52 @@ const client = new SecretsManagerClient({
|
|
|
|
|
|
|
|
|
|
const gqlClient = require("../graphql-client/graphql-client").client;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Generates a properly formatted Cpteller API URL
|
|
|
|
|
* @param {Object} options - URL configuration options
|
|
|
|
|
* @param {string} options.apiType - 'webapi' or 'custapi'
|
|
|
|
|
* @param {string} [options.version] - API version (e.g., '26' for webapi)
|
|
|
|
|
* @param {Object} [options.params] - URL query parameters
|
|
|
|
|
* @returns {string} - The formatted Cpteller URL
|
|
|
|
|
*/
|
|
|
|
|
const getCptellerUrl = (options) => {
|
|
|
|
|
const { apiType = "webapi", version, params = {} } = options;
|
|
|
|
|
|
|
|
|
|
// Base URL construction
|
|
|
|
|
let url = `https://${domain}.cpteller.com/api/`;
|
|
|
|
|
|
|
|
|
|
// Add version if specified for webapi
|
|
|
|
|
if (apiType === "webapi" && version) {
|
|
|
|
|
url += `${version}/`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add the API endpoint
|
|
|
|
|
url += `${apiType}.cfc`;
|
|
|
|
|
|
|
|
|
|
// Add query parameters if any exist
|
|
|
|
|
const queryParams = new URLSearchParams(params).toString();
|
|
|
|
|
if (queryParams) {
|
|
|
|
|
url += `?${queryParams}`;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return url;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @description Get shop credentials from AWS Secrets Manager
|
|
|
|
|
* @param bodyshop
|
|
|
|
|
* @returns {Promise<{error}|{merchantkey: *, apikey: *}|any>}
|
|
|
|
|
*/
|
|
|
|
|
const getShopCredentials = async (bodyshop) => {
|
|
|
|
|
// Development only
|
|
|
|
|
if (process.env.NODE_ENV === undefined) {
|
|
|
|
|
// In Dev/Testing we will use the environment variables
|
|
|
|
|
if (process.env?.NODE_ENV !== "production") {
|
|
|
|
|
return {
|
|
|
|
|
merchantkey: process.env.INTELLIPAY_MERCHANTKEY,
|
|
|
|
|
apikey: process.env.INTELLIPAY_APIKEY
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Production code
|
|
|
|
|
// In Production we will use the AWS Secrets Manager
|
|
|
|
|
if (bodyshop?.imexshopid) {
|
|
|
|
|
try {
|
|
|
|
|
const secret = await client.send(
|
|
|
|
|
@@ -106,7 +137,10 @@ const lightboxCredentials = async (req, res) => {
|
|
|
|
|
...shopCredentials,
|
|
|
|
|
operatingenv: "businessattended"
|
|
|
|
|
}),
|
|
|
|
|
url: `https://${domain}.cpteller.com/api/custapi.cfc?method=autoterminal${req.body.refresh ? "_refresh" : ""}` //autoterminal_refresh
|
|
|
|
|
url: getCptellerUrl({
|
|
|
|
|
apiType: "custapi",
|
|
|
|
|
params: { method: `autoterminal${req.body.refresh ? "_refresh" : ""}` }
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const response = await axios(options);
|
|
|
|
|
@@ -178,7 +212,11 @@ const paymentRefund = async (req, res) => {
|
|
|
|
|
paymentid: req.body.paymentid,
|
|
|
|
|
amount: req.body.amount
|
|
|
|
|
}),
|
|
|
|
|
url: `https://${domain}.cpteller.com/api/26/webapi.cfc?method=payment_refund`
|
|
|
|
|
url: getCptellerUrl({
|
|
|
|
|
apiType: "webapi",
|
|
|
|
|
version: "26",
|
|
|
|
|
params: { method: "payment_refund" }
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.log("intellipay-refund-options-prepared", "DEBUG", req.user?.email, null, {
|
|
|
|
|
@@ -259,7 +297,10 @@ const generatePaymentUrl = async (req, res) => {
|
|
|
|
|
invoice: req.body.invoice,
|
|
|
|
|
createshorturl: true
|
|
|
|
|
}),
|
|
|
|
|
url: `https://${domain}.cpteller.com/api/custapi.cfc?method=generate_lightbox_url`
|
|
|
|
|
url: getCptellerUrl({
|
|
|
|
|
apiType: "custapi",
|
|
|
|
|
params: { method: "generate_lightbox_url" }
|
|
|
|
|
})
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.log("intellipay-generate-payment-url-options-prepared", "DEBUG", req.user?.email, null, {
|
|
|
|
|
@@ -344,7 +385,7 @@ const checkFee = async (req, res) => {
|
|
|
|
|
},
|
|
|
|
|
{ sort: false } // Ensure query string order is preserved
|
|
|
|
|
),
|
|
|
|
|
url: `https://${domain}.cpteller.com/api/26/webapi.cfc`
|
|
|
|
|
url: getCptellerUrl({ apiType: "webapi", version: "26" })
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
logger.log("intellipay-checkfee-options-prepared", "DEBUG", req.user?.email, null, {
|
|
|
|
|
@@ -506,19 +547,49 @@ const postBack = async (req, res) => {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (values?.invoice) {
|
|
|
|
|
const job = await gqlClient.request(queries.GET_JOB_BY_PK, {
|
|
|
|
|
id: values.invoice
|
|
|
|
|
// Early Bail on Merchant ID
|
|
|
|
|
if (!values?.merchantid) {
|
|
|
|
|
logger.log("intellipay-postback-no-merchantid", "ERROR", "api", null, {
|
|
|
|
|
message: "Merchant ID is missing",
|
|
|
|
|
...logResponseMeta
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return res.status(400).send("Bad Request: Merchant ID is missing");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const result = await gqlClient.request(queries.GET_JOBID_BY_MERCHANTID_RONUMBER, {
|
|
|
|
|
merchantID: values.merchantid,
|
|
|
|
|
roNumber: values.invoice
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const bodyshop = await gqlClient.request(queries.GET_BODYSHOP_BY_ID, {
|
|
|
|
|
id: job.jobs_by_pk.shopid
|
|
|
|
|
});
|
|
|
|
|
// Early Bail on No Jobs Found
|
|
|
|
|
if (!result?.jobs?.length) {
|
|
|
|
|
logger.log("intellipay-postback-job-not-found", "ERROR", "api", null, {
|
|
|
|
|
message: "Job not found",
|
|
|
|
|
...logResponseMeta
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const ipMapping = bodyshop.bodyshops_by_pk.intellipay_config?.payment_map;
|
|
|
|
|
return res.status(400).send("Bad Request: Job not found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const job = result?.jobs?.[0];
|
|
|
|
|
|
|
|
|
|
const bodyshop = job?.bodyshop;
|
|
|
|
|
|
|
|
|
|
// Early Bail on no Bodyshop Found
|
|
|
|
|
if (!bodyshop) {
|
|
|
|
|
logger.log("intellipay-postback-bodyshop-not-found", "ERROR", "api", null, {
|
|
|
|
|
message: "Bodyshop not found",
|
|
|
|
|
...logResponseMeta
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return res.status(400).send("Bad Request: Bodyshop not found");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const ipMapping = bodyshop?.intellipay_config?.payment_map;
|
|
|
|
|
|
|
|
|
|
logger.log("intellipay-postback-invoice-job-fetched", "DEBUG", "api", null, {
|
|
|
|
|
job,
|
|
|
|
|
bodyshop,
|
|
|
|
|
...logResponseMeta
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
@@ -528,7 +599,7 @@ const postBack = async (req, res) => {
|
|
|
|
|
transactionid: values.authcode,
|
|
|
|
|
payer: "Customer",
|
|
|
|
|
type: ipMapping ? ipMapping[(values.cardtype || "").toLowerCase()] || values.cardtype : values.cardtype,
|
|
|
|
|
jobid: values.invoice,
|
|
|
|
|
jobid: job.id,
|
|
|
|
|
date: moment(Date.now())
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
@@ -541,9 +612,9 @@ const postBack = async (req, res) => {
|
|
|
|
|
const responseResults = await gqlClient.request(queries.INSERT_PAYMENT_RESPONSE, {
|
|
|
|
|
paymentResponse: {
|
|
|
|
|
amount: values.total,
|
|
|
|
|
bodyshopid: bodyshop.bodyshops_by_pk.id,
|
|
|
|
|
bodyshopid: bodyshop.id,
|
|
|
|
|
paymentid: paymentResult.id,
|
|
|
|
|
jobid: values.invoice,
|
|
|
|
|
jobid: job.id,
|
|
|
|
|
declinereason: "Approved",
|
|
|
|
|
ext_paymentid: values.paymentid,
|
|
|
|
|
successful: true,
|
|
|
|
|
@@ -576,13 +647,10 @@ const postBack = async (req, res) => {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const postBackCallBack = async (req, res) => {};
|
|
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
|
lightboxCredentials,
|
|
|
|
|
paymentRefund,
|
|
|
|
|
generatePaymentUrl,
|
|
|
|
|
checkFee,
|
|
|
|
|
postBack,
|
|
|
|
|
postBackCallBack
|
|
|
|
|
postBack
|
|
|
|
|
};
|
|
|
|
|
|