const GraphQLClient = require("graphql-request").GraphQLClient; const path = require("path"); const queries = require("../graphql-client/queries"); const Dinero = require("dinero.js"); const qs = require("query-string"); const axios = require("axios"); const moment = require("moment"); const logger = require("../utils/logger"); const InstanceManager = require("../utils/instanceMgr").default; require("dotenv").config({ path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`) }); const domain = process.env.NODE_ENV ? "secure" : "test"; const { SecretsManagerClient, GetSecretValueCommand } = require("@aws-sdk/client-secrets-manager"); const client = new SecretsManagerClient({ region: InstanceManager({ imex: "ca-central-1", rome: "us-east-2" }) }); const gqlClient = require("../graphql-client/graphql-client").client; const getShopCredentials = async (bodyshop) => { // Development only if (process.env.NODE_ENV === undefined) { return { merchantkey: process.env.INTELLIPAY_MERCHANTKEY, apikey: process.env.INTELLIPAY_APIKEY }; } // Production code if (bodyshop?.imexshopid) { try { const secret = await client.send( new GetSecretValueCommand({ SecretId: `intellipay-credentials-${bodyshop.imexshopid}`, VersionStage: "AWSCURRENT" // VersionStage defaults to AWSCURRENT if unspecified }) ); return JSON.parse(secret.SecretString); } catch (error) { return { error: error.message }; } } }; exports.lightbox_credentials = async (req, res) => { logger.log("intellipay-lightbox-credentials", "DEBUG", req.user?.email, null, null); const shopCredentials = await getShopCredentials(req.body.bodyshop); if (shopCredentials.error) { res.json(shopCredentials); return; } try { const options = { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, data: qs.stringify({ ...shopCredentials, operatingenv: "businessattended" }), url: `https://${domain}.cpteller.com/api/custapi.cfc?method=autoterminal${req.body.refresh ? "_refresh" : ""}` //autoterminal_refresh }; const response = await axios(options); res.send(response.data); } catch (error) { console.log(error); logger.log("intellipay-lightbox-credentials-error", "ERROR", req.user?.email, null, { error: JSON.stringify(error) }); res.json({ error }); } }; exports.payment_refund = async (req, res) => { logger.log("intellipay-refund", "DEBUG", req.user?.email, null, null); const shopCredentials = await getShopCredentials(req.body.bodyshop); try { const options = { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, data: qs.stringify({ method: "payment_refund", ...shopCredentials, paymentid: req.body.paymentid, amount: req.body.amount }), url: `https://${domain}.cpteller.com/api/26/webapi.cfc?method=payment_refund` }; const response = await axios(options); res.send(response.data); } catch (error) { console.log(error); logger.log("intellipay-refund-error", "ERROR", req.user?.email, null, { error: JSON.stringify(error) }); res.json({ error }); } }; exports.generate_payment_url = async (req, res) => { logger.log("intellipay-payment-url", "DEBUG", req.user?.email, null, null); const shopCredentials = await getShopCredentials(req.body.bodyshop); try { const options = { method: "POST", headers: { "content-type": "application/x-www-form-urlencoded" }, //TODO: Move these to environment variables/database. data: qs.stringify({ ...shopCredentials, //...req.body, amount: Dinero({ amount: Math.round(req.body.amount * 100) }).toFormat("0.00"), account: req.body.account, invoice: req.body.invoice, createshorturl: true //The postback URL is set at the CP teller global terminal settings page. }), url: `https://${domain}.cpteller.com/api/custapi.cfc?method=generate_lightbox_url` }; const response = await axios(options); res.send(response.data); } catch (error) { console.log(error); logger.log("intellipay-payment-url-error", "ERROR", req.user?.email, null, { error: JSON.stringify(error) }); res.json({ error }); } }; exports.postback = async (req, res) => { try { logger.log("intellipay-postback", "DEBUG", req.user?.email, null, req.body); const { body: values } = req; const comment = Buffer.from(values?.comment, "base64").toString(); if ((!values.invoice || values.invoice === "") && !comment) { //invoice is specified through the pay link. Comment by IO. logger.log("intellipay-postback-ignored", "DEBUG", req.user?.email, null, req.body); res.sendStatus(200); return; } if (values.invoice) { //This is a link email that's been sent out. const job = await gqlClient.request(queries.GET_JOB_BY_PK, { id: values.invoice }); const paymentResult = await gqlClient.request(queries.INSERT_NEW_PAYMENT, { paymentInput: { amount: values.total, transactionid: values.authcode, payer: "Customer", type: values.cardtype, jobid: values.invoice, date: moment(Date.now()) } }); const responseResults = await gqlClient.request(queries.INSERT_PAYMENT_RESPONSE, { paymentResponse: { amount: values.total, bodyshopid: job.jobs_by_pk.shopid, paymentid: paymentResult.id, jobid: values.invoice, declinereason: "Approved", ext_paymentid: values.paymentid, successful: true, response: values } }); logger.log("intellipay-postback-link-success", "DEBUG", req.user?.email, null, { iprequest: values, responseResults, paymentResult }); res.sendStatus(200); } else if (comment) { //This has been triggered by IO and may have multiple jobs. const partialPayments = JSON.parse(comment); const jobs = await gqlClient.request(queries.GET_JOBS_BY_PKS, { ids: partialPayments.map((p) => p.jobid) }); const paymentResult = await gqlClient.request(queries.INSERT_NEW_PAYMENT, { paymentInput: partialPayments.map((p) => ({ amount: p.amount, transactionid: values.authcode, payer: "Customer", type: values.cardtype, jobid: p.jobid, date: moment(Date.now()), payment_responses: { data: { amount: values.total, bodyshopid: jobs.jobs[0].shopid, jobid: p.jobid, declinereason: "Approved", ext_paymentid: values.paymentid, successful: true, response: values } } })) }); logger.log("intellipay-postback-app-success", "DEBUG", req.user?.email, null, { iprequest: values, paymentResult }); res.sendStatus(200); } } catch (error) { logger.log("intellipay-postback-error", "ERROR", req.user?.email, null, { error: JSON.stringify(error), body: req.body }); res.status(400).json({ succesful: false, error: error.message }); } };