Improvements to intellipay script.

This commit is contained in:
Patrick Fic
2023-08-11 09:48:39 -07:00
parent cbe0c78553
commit c3fe763261
8 changed files with 3277 additions and 3115 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project version="1.2" be_version="2.7.1"> <babeledit_project be_version="2.7.1" version="1.2">
<!-- <!--
BabelEdit project file BabelEdit project file
@@ -1474,6 +1474,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>admin_jobuninvoice</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>admin_jobunvoid</name> <name>admin_jobunvoid</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -3571,6 +3592,27 @@
<folder_node> <folder_node>
<name>validation</name> <name>validation</name>
<children> <children>
<concept_node>
<name>closingperiod</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>inventoryquantity</name> <name>inventoryquantity</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -4205,6 +4247,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>closingperiod</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>country</name> <name>country</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -19213,6 +19276,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>openingip</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>title</name> <name>title</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -23689,6 +23773,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>date_void</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>ded_amt</name> <name>ded_amt</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -28469,6 +28574,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>closingperiod</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>contracts</name> <name>contracts</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -40685,6 +40811,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>parts_return_slip</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>sublet_order</name> <name>sublet_order</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -44536,6 +44683,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>work_in_progress_jobs</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>work_in_progress_labour</name> <name>work_in_progress_labour</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -1,7 +1,17 @@
import React, { useCallback, useEffect } from "react"; import React, { useCallback, useEffect, useState } from "react";
import axios from "axios"; import axios from "axios";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Button, Card, Form, Input, InputNumber, Row, Select } from "antd"; import {
Button,
Card,
Form,
Input,
InputNumber,
Row,
Select,
Spin,
notification,
} from "antd";
import moment from "moment"; import moment from "moment";
import { useMutation, useQuery } from "@apollo/client"; import { useMutation, useQuery } from "@apollo/client";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
@@ -16,6 +26,14 @@ import { insertAuditTrail } from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { createStructuredSelector } from "reselect";
import { selectCardPayment } from "../../redux/modals/modals.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
cardPaymentModal: selectCardPayment,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) => insertAuditTrail: ({ jobid, operation }) =>
@@ -25,24 +43,39 @@ const mapDispatchToProps = (dispatch) => ({
const CardPaymentModalComponent = ({ const CardPaymentModalComponent = ({
bodyshop, bodyshop,
context, cardPaymentModal,
toggleModalVisible, toggleModalVisible,
insertAuditTrail, insertAuditTrail,
}) => { }) => {
const { context } = cardPaymentModal;
const [form] = Form.useForm(); const [form] = Form.useForm();
const amount = Form.useWatch("amount", form); const amount = Form.useWatch("amount", form);
const payer = Form.useWatch("payer", form);
const jobid = Form.useWatch("jobid", form); const jobid = Form.useWatch("jobid", form);
const [loading, setLoading] = useState(false);
const [insertPayment] = useMutation(INSERT_NEW_PAYMENT); const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE); const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE);
const { t } = useTranslation(); const { t } = useTranslation();
const { data, refetch } = useQuery(QUERY_RO_AND_OWNER_BY_JOB_PK, { const { data, refetch } = useQuery(QUERY_RO_AND_OWNER_BY_JOB_PK, {
variables: { jobid: context?.jobid ?? "" }, variables: { jobid: context?.jobid ?? "" },
skip: !context?.jobid,
}); });
const nonApproval = useCallback( //Initialize the intellipay window.
async (response) => { const SetIntellipayCallbackFunctions = () => {
console.log("*** Set IntelliPay callback functions.");
window.intellipay.runOnClose(() => {
//window.intellipay.initialize();
});
window.intellipay.runOnApproval(async function (response) {
console.warn("*** Running On Approval Script ***");
form.setFieldValue("paymentResponse", response);
form.submit();
});
window.intellipay.runOnNonApproval(async function (response) {
// Mutate unsuccessful payment // Mutate unsuccessful payment
await insertPaymentResponse({ await insertPaymentResponse({
variables: { variables: {
@@ -57,83 +90,27 @@ const CardPaymentModalComponent = ({
}, },
}, },
}); });
// Insert failed payment to audit trail
insertAuditTrail({ insertAuditTrail({
jobid: jobid || context?.jobid, jobid: jobid || context?.jobid,
operation: AuditTrailMapping.failedpayment(), operation: AuditTrailMapping.failedpayment(),
}); });
},
[bodyshop, context, insertAuditTrail, insertPaymentResponse, jobid]
);
const initIntellipayFunctions = useCallback(() => {
if (window.intellipay !== undefined && typeof jobid !== "undefined") {
console.log("intellipay init functions");
window.intellipay.runOnClose(() => {
window.intellipay.initialize();
}); });
};
window.intellipay.runOnApproval(async function (response) {
form.setFieldValue("paymentResponse", response);
form.submit();
toggleModalVisible();
});
window.intellipay.runOnNonApproval(nonApproval);
}
}, [form, jobid, nonApproval, toggleModalVisible]);
const initJobId = useCallback(() => {
if (context?.jobid) {
form.setFieldValue("jobid", context.jobid);
}
form.setFieldValue("payer", t("payments.labels.customer"));
}, [context?.jobid, form, t]);
useEffect(() => {
initJobId();
axios
.post("/intellipay/lightbox_credentials", { bodyshop })
.then((response) => {
var rg = document.createRange();
let node = rg.createContextualFragment(response.data);
document.documentElement.appendChild(node);
window.intellipay.initialize();
initIntellipayFunctions();
});
function handleEvents(...props) {
const operation = props[0].data.operation;
if (operation === "updateform") {
props[0].stopImmediatePropagation();
}
}
window.addEventListener("message", handleEvents, false);
return () => window.removeEventListener("message", handleEvents, false);
}, [bodyshop, initJobId, initIntellipayFunctions]);
const handleFinish = async (values) => { const handleFinish = async (values) => {
try {
const paymentResult = await insertPayment({ const paymentResult = await insertPayment({
variables: { variables: {
paymentInput: { paymentInput: {
amount: values.amount, amount: values.amount,
transactionid: values.paymentResponse.receiptelements.transid, transactionid: values.paymentResponse.receiptelements.transid,
payer: values.payer, payer: t("payments.labels.customer"),
type: values.paymentResponse.cardType, type: values.paymentResponse.cardType,
jobid: values.jobid, jobid: values.jobid,
date: moment(Date.now()), date: moment(Date.now()),
}, },
}, },
refetchQueries: ["GET_JOB_BY_PK"],
update(cache, { data }) { update(cache, { data }) {
cache.modify({ cache.modify({
id: cache.identify({ id: values.jobid, __typename: "jobs" }), id: cache.identify({ id: values.jobid, __typename: "jobs" }),
@@ -160,11 +137,43 @@ const CardPaymentModalComponent = ({
}, },
}, },
}); });
toggleModalVisible();
} catch (error) {
} finally {
setLoading(false);
}
};
const handleIntelliPayCharge = async () => {
setLoading(true);
try {
const response = await axios.post("/intellipay/lightbox_credentials", {
bodyshop,
});
var rg = document.createRange();
let node = rg.createContextualFragment(response.data);
document.documentElement.appendChild(node);
SetIntellipayCallbackFunctions();
window.intellipay.isAutoOpen = true;
window.intellipay.initialize();
} catch (error) {
notification.open({
type: "error",
message: t("job_payments.notifications.error.openingip"),
});
setLoading(false);
}
}; };
return ( return (
<Card title="Card Payment"> <Card title="Card Payment">
<Form onFinish={handleFinish} form={form}> <Spin spinning={loading}>
<Form
onFinish={handleFinish}
form={form}
initialValues={{ jobid: context?.jobid }}
>
<LayoutFormRow grow> <LayoutFormRow grow>
<Form.Item <Form.Item
name="jobid" name="jobid"
@@ -215,26 +224,6 @@ const CardPaymentModalComponent = ({
</Form.Item> </Form.Item>
<LayoutFormRow grow> <LayoutFormRow grow>
<Form.Item
label={t("payments.fields.payer")}
name="payer"
rules={[
{
required: true,
// message: t("general.validation.required"),
},
]}
>
<Select>
<Select.Option value={t("payments.labels.customer")}>
{t("payments.labels.customer")}
</Select.Option>
<Select.Option value={t("payments.labels.insurance")}>
{t("payments.labels.insurance")}
</Select.Option>
</Select>
</Form.Item>
<Form.Item <Form.Item
label="Amount" label="Amount"
name="amount" name="amount"
@@ -251,9 +240,10 @@ const CardPaymentModalComponent = ({
<Row justify="space-around"> <Row justify="space-around">
<Button <Button
type="primary" type="primary"
data-ipayname="submit" // data-ipayname="submit"
className="ipayfield" className="ipayfield"
disabled={!amount || !payer || !jobid} disabled={!amount || !jobid}
onClick={handleIntelliPayCharge}
> >
{t("job_payments.buttons.proceedtopayment")} {t("job_payments.buttons.proceedtopayment")}
</Button> </Button>
@@ -270,8 +260,12 @@ const CardPaymentModalComponent = ({
</Row> </Row>
</LayoutFormRow> </LayoutFormRow>
</Form> </Form>
</Spin>
</Card> </Card>
); );
}; };
export default connect(null, mapDispatchToProps)(CardPaymentModalComponent); export default connect(
mapStateToProps,
mapDispatchToProps
)(CardPaymentModalComponent);

View File

@@ -22,7 +22,7 @@ function CardPaymentModalContainer({
toggleModalVisible, toggleModalVisible,
bodyshop, bodyshop,
}) { }) {
const { context, visible } = cardPaymentModal; const { visible } = cardPaymentModal;
const { t } = useTranslation(); const { t } = useTranslation();
const handleCancel = () => { const handleCancel = () => {
@@ -35,7 +35,7 @@ function CardPaymentModalContainer({
return ( return (
<Modal <Modal
visible={visible} open={visible}
onOk={handleOK} onOk={handleOK}
onCancel={handleCancel} onCancel={handleCancel}
footer={[ footer={[
@@ -46,7 +46,7 @@ function CardPaymentModalContainer({
width="60%" width="60%"
destroyOnClose destroyOnClose
> >
<CardPaymentModalComponent bodyshop={bodyshop} context={context} /> <CardPaymentModalComponent />
</Modal> </Modal>
); );
} }

View File

@@ -18,7 +18,7 @@ export default function DataLabel({
<div {...props} style={{ display: "flex" }}> <div {...props} style={{ display: "flex" }}>
<div <div
style={{ style={{
flex: 2, // flex: 2,
marginRight: ".2rem", marginRight: ".2rem",
}} }}
> >

View File

@@ -1198,6 +1198,7 @@
"notifications": { "notifications": {
"error": { "error": {
"description": "Please try again. Make sure the refund amount does not exceeds the payment amount.", "description": "Please try again. Make sure the refund amount does not exceeds the payment amount.",
"openingip": "Error connecting to IntelliPay service.",
"title": "Error placing refund" "title": "Error placing refund"
} }
}, },
@@ -1926,7 +1927,7 @@
"customers": "Customers", "customers": "Customers",
"dashboard": "Dashboard", "dashboard": "Dashboard",
"enterbills": "Enter Bills", "enterbills": "Enter Bills",
"entercardpayment": "Enter Card Payments", "entercardpayment": "New Card Charge",
"enterpayment": "Enter Payments", "enterpayment": "Enter Payments",
"entertimeticket": "Enter Time Tickets", "entertimeticket": "Enter Time Tickets",
"export": "Export", "export": "Export",
@@ -2411,7 +2412,7 @@
"jobs": { "jobs": {
"individual_job_note": "Job Note RO: {{ro_number}}", "individual_job_note": "Job Note RO: {{ro_number}}",
"parts_order": "Parts Order PO: {{ro_number}} - {{name}}", "parts_order": "Parts Order PO: {{ro_number}} - {{name}}",
"parts_return_slip":"Parts Return PO: {{ro_number}} - {{name}}", "parts_return_slip": "Parts Return PO: {{ro_number}} - {{name}}",
"sublet_order": "Sublet Order PO: {{ro_number}} - {{name}}" "sublet_order": "Sublet Order PO: {{ro_number}} - {{name}}"
} }
}, },

View File

@@ -1198,6 +1198,7 @@
"notifications": { "notifications": {
"error": { "error": {
"description": "", "description": "",
"openingip": "",
"title": "" "title": ""
} }
}, },

View File

@@ -1198,6 +1198,7 @@
"notifications": { "notifications": {
"error": { "error": {
"description": "", "description": "",
"openingip": "",
"title": "" "title": ""
} }
}, },

View File

@@ -59,11 +59,7 @@ exports.lightbox_credentials = async (req, res) => {
//TODO: Move these to environment variables/database. //TODO: Move these to environment variables/database.
data: qs.stringify({ data: qs.stringify({
...shopCredentials, ...shopCredentials,
operatingenv: operatingenv: "businessattended",
// process.env.NODE_ENV === undefined
// ? process.env.NODE_ENV
// :
"businessattended",
}), }),
url: `https://${domain}.cpteller.com/api/custapi.cfc?method=autoterminal`, url: `https://${domain}.cpteller.com/api/custapi.cfc?method=autoterminal`,
}; };
@@ -114,6 +110,7 @@ exports.generate_payment_url = async (req, res) => {
...shopCredentials, ...shopCredentials,
...req.body, ...req.body,
createshorturl: true, 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`, url: `https://${domain}.cpteller.com/api/custapi.cfc?method=generate_lightbox_url`,
}; };