diff --git a/client/src/components/_test/card-payment-modal.component..jsx b/client/src/components/_test/card-payment-modal.component..jsx
new file mode 100644
index 000000000..5f0d9617b
--- /dev/null
+++ b/client/src/components/_test/card-payment-modal.component..jsx
@@ -0,0 +1,43 @@
+import { Modal } from "antd";
+import React from "react";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { toggleModalVisible } from "../../redux/modals/modals.actions";
+import { selectCardPayment } from "../../redux/modals/modals.selectors";
+import { selectBodyshop } from "../../redux/user/user.selectors";
+import IntellipayTestPage from "./intellipay-test";
+
+const mapStateToProps = createStructuredSelector({
+ cardPaymentModal: selectCardPayment,
+ bodyshop: selectBodyshop,
+});
+
+const mapDispatchToProps = (dispatch) => ({
+ toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment")),
+});
+
+function CardPaymentModalComponent({
+ cardPaymentModal,
+ toggleModalVisible,
+ bodyshop,
+}) {
+ const { context, visible } = cardPaymentModal;
+
+ return (
+ toggleModalVisible()}
+ onCancel={() => toggleModalVisible()}
+ cancelButtonProps={{ style: { display: "none" } }}
+ width="90%"
+ destroyOnClose
+ >
+
+
+ );
+}
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(CardPaymentModalComponent);
diff --git a/client/src/components/_test/intellipay-test.jsx b/client/src/components/_test/intellipay-test.jsx
new file mode 100644
index 000000000..eb06d7651
--- /dev/null
+++ b/client/src/components/_test/intellipay-test.jsx
@@ -0,0 +1,161 @@
+import React, { useEffect } from "react";
+import axios from "axios";
+import { useTranslation } from "react-i18next";
+import { Button, Card, Form, Input, InputNumber, Select } from "antd";
+import moment from "moment";
+import { useMutation } from "@apollo/client";
+import LayoutFormRow from "../layout-form-row/layout-form-row.component";
+import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
+import { INSERT_NEW_PAYMENT } from "../../graphql/payments.queries";
+import { INSERT_PAYMENT_RESPONSE } from "./payment_response.queries";
+
+const IntellpayTestPage = ({ bodyshop, context }) => {
+ const [form] = Form.useForm();
+ const amount = Form.useWatch("amount", form);
+ const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
+ const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE);
+ const { t } = useTranslation();
+
+ useEffect(() => {
+ axios.get("/intellipay/lightbox_credentials").then((response) => {
+ var rg = document.createRange();
+ let node = rg.createContextualFragment(response.data);
+
+ document.documentElement.appendChild(node);
+ window.intellipay.initialize();
+
+ console.log("Modal: Intellipay Initialized");
+
+ window.intellipay.runOnClose(() => {
+ // Apparently it automatically removes itself in the document when closed
+ // so we just need to reintialize it
+ window.intellipay.initialize();
+ });
+
+ window.intellipay.runOnApproval(async function (response) {
+ console.log("Modal - Payment Response: ", response);
+ // TODO store the response
+ form.setFieldValue("paymentResponse", response);
+ });
+ });
+ }, []);
+
+ const disabled = false;
+
+ const handleFinish = async (values) => {
+ console.log("Modal: Handle Finish Values", values);
+
+ const paymentResult = await insertPayment({
+ variables: {
+ paymentInput: {
+ amount: values.amount,
+ transactionid: values.paymentResponse.receiptelements.transid,
+ payer: values.payer,
+ type: values.paymentResponse.cardType,
+ jobid: values.jobid,
+ date: moment(Date.now()),
+ },
+ },
+ });
+
+ const paymentResponseResult = await insertPaymentResponse({
+ variables: {
+ paymentResponse: {
+ amount: values.amount,
+ bodyshopid: bodyshop.id,
+ paymentid: paymentResult.data.insert_payments.returning[0].id,
+ jobid: values.jobid,
+ declinereason: values.paymentResponse.declinereason,
+ ext_paymentid: values.paymentResponse.paymentid.toString(),
+ successful: true,
+ response: values.paymentResponse,
+ },
+ },
+ });
+
+ console.log("Modal - Insert Payment Result: ", paymentResult);
+ console.log(
+ "Modal - Insert Respose Payment Result: ",
+ paymentResponseResult
+ );
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default IntellpayTestPage;
diff --git a/client/src/components/_test/payment_response.json b/client/src/components/_test/payment_response.json
new file mode 100644
index 000000000..2087d3e32
--- /dev/null
+++ b/client/src/components/_test/payment_response.json
@@ -0,0 +1,63 @@
+{
+ "status": 24201299,
+ "custid": 19607899,
+ "paymentid": 24201299,
+ "response": "A",
+ "authcode": "498680",
+ "declinereason": "Approved",
+ "fee": 0,
+ "invoice": "",
+ "account": "john",
+ "amount": 1000,
+ "amountincludesfee": false,
+ "total": 1000,
+ "paymenttype": "C",
+ "methodhint": "VI ***1111",
+ "cardbrand": "Visa",
+ "cardnumdisplay": "***1111",
+ "receiptelements": {
+ "authcode": "498680",
+ "cust_srv_ph_num": "1-555-555-5555",
+ "rcpt_pg_ftr_txt": "Thank You\nPlease Come Again",
+ "rcpt_currency": "USD",
+ "responsecode": "A",
+ "rcpt_pay_mthd": "Visa",
+ "transid": "C00 915799",
+ "merch_disp_nm": "CP Devel Test",
+ "rcpt_input_mthd": "Keyed",
+ "rcpt_pg_hdr_txt": "Welcome!",
+ "rcpt_tran_time": "Thursday February 23 2023, 11:25:36 pm +08",
+ "rcpt_trans_type": "Normal Transaction (Sale)",
+ "message": "Approved",
+ "rcpt_dba_addr": "1234 Storefront Ave\nSome City, UT 84111",
+ "avsdata": "N",
+ "receiptrequirements": "S",
+ "rcpt_cardnum": "************1111",
+ "cv2result": "M",
+ "rfnd_policy_txt": "No Refunds\nStore Credit Only",
+ "labels": {
+ "tranref": "REF#",
+ "tid": "TID",
+ "validationcode": "ValCode",
+ "emvapplicationid": "AID",
+ "emvatc": "ATC",
+ "rcpt_pay_mthd": "Pay Method",
+ "transid": "TransID",
+ "rcpt_input_mthd": "IMode",
+ "emvtsi": "TSI",
+ "emvac": "AC",
+ "rcpt_trans_type": "TranType",
+ "emvapplicationname": "PApp",
+ "visarewards": "RewardsProg"
+ }
+ },
+ "receipttoken": "H4sIAAAAAAAAACXMTQuCMBgA4P/ynh3tw_3dBI/ipQ8NOtRN53QiblpBRfTfCzo/8LwhxGAdZCCwFYoJJFQjI2kvHdGu74lVkgmrWyWNhASW5jW7cB87yHjKKePGJODnxrrnMl7dDTKmEJlSOqV/_N30XPpyj2Eddq57_KKZ8FLzmh_G1VQnVfhjiXGK1XYTc/h8AVOkf4qUAAAA",
+ "call": "card_payment",
+ "nonce": "488b5568-b5c1-4f38-8b2f-3b050f3abb11P",
+ "hmac": "JyPAJ9Yx0SlYBTtqns1OxAFRt+xF3l2UiLPO5zTDRBE=",
+ "paymentreferenceid": "C19607899P24201299",
+ "cardnum": "...1111",
+ "email": "",
+ "nameOnCard": "John Allen",
+ "cardType": "visa"
+}
diff --git a/client/src/components/_test/payment_response.queries.js b/client/src/components/_test/payment_response.queries.js
new file mode 100644
index 000000000..4f266573a
--- /dev/null
+++ b/client/src/components/_test/payment_response.queries.js
@@ -0,0 +1,29 @@
+import { gql } from "@apollo/client";
+
+export const QUERY_ALL_PAYMENT_RESPONSE = gql`
+ query QUERY_ALL_PAYMENT_RESPONSE {
+ payment_response {
+ amount
+ bodyshopid
+ declinereason
+ ext_paymentid
+ id
+ jobid
+ paymentid
+ response
+ successful
+ }
+ }
+`;
+
+export const INSERT_PAYMENT_RESPONSE = gql`
+ mutation INSERT_PAYMENT_RESPONSE(
+ $paymentResponse: [payment_response_insert_input!]!
+ ) {
+ insert_payment_response(objects: $paymentResponse) {
+ returning {
+ id
+ }
+ }
+ }
+`;
diff --git a/client/src/components/_test/test.component.jsx b/client/src/components/_test/test.component.jsx
deleted file mode 100644
index b6b02b7c0..000000000
--- a/client/src/components/_test/test.component.jsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import React from "react";
-import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
-export default function Test() {
- return (
-
-
-
- );
-}
diff --git a/client/src/components/_test/test.page.jsx b/client/src/components/_test/test.page.jsx
new file mode 100644
index 000000000..b750e3873
--- /dev/null
+++ b/client/src/components/_test/test.page.jsx
@@ -0,0 +1,35 @@
+import { Button } from "antd";
+import React from "react";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { setModalContext } from "../../redux/modals/modals.actions";
+import CardPaymentModalComponent from "./card-payment-modal.component.";
+
+const mapStateToProps = createStructuredSelector({});
+
+const mapDispatchToProps = (dispatch) => ({
+ setCardPaymentContext: (context) =>
+ dispatch(setModalContext({ context: context, modal: "cardPayment" })),
+});
+
+function Test({ setCardPaymentContext }) {
+ return (
+
+
+
+ {/* */}
+
+ );
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Test);
diff --git a/client/src/components/payment-modal/payment-modal.container.jsx b/client/src/components/payment-modal/payment-modal.container.jsx
index 4b270bca5..9f31807e9 100644
--- a/client/src/components/payment-modal/payment-modal.container.jsx
+++ b/client/src/components/payment-modal/payment-modal.container.jsx
@@ -7,14 +7,14 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
INSERT_NEW_PAYMENT,
- UPDATE_PAYMENT
+ UPDATE_PAYMENT,
} from "../../graphql/payments.queries";
import { setEmailOptions } from "../../redux/email/email.actions";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectPayment } from "../../redux/modals/modals.selectors";
import {
selectBodyshop,
- selectCurrentUser
+ selectCurrentUser,
} from "../../redux/user/user.selectors";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx
index 7a71f2cd1..46949077f 100644
--- a/client/src/pages/manage/manage.page.component.jsx
+++ b/client/src/pages/manage/manage.page.component.jsx
@@ -16,7 +16,7 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com
import PartnerPingComponent from "../../components/partner-ping/partner-ping.component";
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
-import TestComponent from "../../components/_test/test.component";
+import TestComponent from "../../components/_test/test.page";
import { requestForToken } from "../../firebase/firebase.utils";
import {
selectBodyshop,
@@ -193,9 +193,8 @@ export function Manage({ match, conflict, bodyshop }) {
}
>
-
-
-
+
+
diff --git a/client/src/redux/modals/modals.reducer.js b/client/src/redux/modals/modals.reducer.js
index 72859b08f..3209ae53d 100644
--- a/client/src/redux/modals/modals.reducer.js
+++ b/client/src/redux/modals/modals.reducer.js
@@ -25,6 +25,7 @@ const INITIAL_STATE = {
contractFinder: { ...baseModal },
inventoryUpsert: { ...baseModal },
ca_bc_eftTableConvert: { ...baseModal },
+ cardPayment: { ...baseModal },
};
const modalsReducer = (state = INITIAL_STATE, action) => {
diff --git a/client/src/redux/modals/modals.selectors.js b/client/src/redux/modals/modals.selectors.js
index 82d4f706d..8a4cfee77 100644
--- a/client/src/redux/modals/modals.selectors.js
+++ b/client/src/redux/modals/modals.selectors.js
@@ -79,3 +79,8 @@ export const selectCaBcEtfTableConvert = createSelector(
[selectModals],
(modals) => modals.ca_bc_eftTableConvert
);
+
+export const selectCardPayment = createSelector(
+ [selectModals],
+ (modals) => modals.cardPayment
+);
diff --git a/server.js b/server.js
index 90d3da90f..12a90f3c8 100644
--- a/server.js
+++ b/server.js
@@ -225,6 +225,13 @@ app.post(
mixdataUpload.mixdataUpload
);
+var intellipay = require("./server/intellipay/intellipay");
+app.get(
+ "/intellipay/lightbox_credentials",
+ fb.validateFirebaseIdToken,
+ intellipay.lightbox_credentials
+);
+
var ioevent = require("./server/ioevent/ioevent");
app.post("/ioevent", ioevent.default);
app.post("/newlog", (req, res) => {
diff --git a/server/intellipay/intellipay.js b/server/intellipay/intellipay.js
new file mode 100644
index 000000000..87aec5e2c
--- /dev/null
+++ b/server/intellipay/intellipay.js
@@ -0,0 +1,36 @@
+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");
+require("dotenv").config({
+ path: path.resolve(
+ process.cwd(),
+ `.env.${process.env.NODE_ENV || "development"}`
+ ),
+});
+
+exports.lightbox_credentials = async (req, res) => {
+ console.log("In API Lightbox Credential route.");
+ try {
+ const options = {
+ method: "POST",
+ headers: { "content-type": "application/x-www-form-urlencoded" },
+ //TODO: Move these to environment variables/database.
+ data: qs.stringify({
+ merchantkey: "3B8068",
+ apikey: "Oepn2B.XqRgzAqHqvOOmYUxD2VW.vGSipi",
+ operatingenv: "businessattended", // add these for EMV Swipe
+ }),
+ url: "https://test.cpteller.com/api/custapi.cfc?method=autoterminal", //added .test
+ };
+
+ const response = await axios(options);
+
+ res.send(response.data);
+ } catch (error) {
+ console.log(error);
+ res.json({ error });
+ }
+};