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"); 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: "ca-central-1", }); 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) => { logger.log("intellipay-postback", "ERROR", req.user?.email, null, req.body); const { body: values } = req; if (!values.invoice) { res.sendStatus(200); return; } // TODO query job by account name const job = await gqlClient.request(queries.GET_JOB_BY_PK, { id: values.invoice, }); // TODO add mutation to database try { const paymentResult = await gqlClient.request(queries.INSERT_NEW_PAYMENT, { paymentInput: { amount: values.total, transactionid: `C00 ${values.authcode}`, payer: "Customer", type: values.cardtype, jobid: values.invoice, date: moment(Date.now()), }, }); 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, }, }); res.send({ message: "Postback Successful" }); } 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 }); } };