diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 7cfb277dd..20dd617dd 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -37861,6 +37861,27 @@ + + inserting + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + diff --git a/client/src/components/card-payment-modal/card-payment-modal.component..jsx b/client/src/components/card-payment-modal/card-payment-modal.component..jsx index 15c4ffe3a..071e2a758 100644 --- a/client/src/components/card-payment-modal/card-payment-modal.component..jsx +++ b/client/src/components/card-payment-modal/card-payment-modal.component..jsx @@ -1,12 +1,15 @@ -import { useMutation, useQuery } from "@apollo/client"; +import { DeleteFilled } from "@ant-design/icons"; +import { useLazyQuery, useMutation } from "@apollo/client"; import { Button, Card, + Col, Form, Input, - InputNumber, Row, + Space, Spin, + Statistic, notification, } from "antd"; import axios from "axios"; @@ -17,7 +20,7 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { INSERT_PAYMENT_RESPONSE, - QUERY_RO_AND_OWNER_BY_JOB_PK, + QUERY_RO_AND_OWNER_BY_JOB_PKS, } from "../../graphql/payment_response.queries"; import { INSERT_NEW_PAYMENT } from "../../graphql/payments.queries"; import { insertAuditTrail } from "../../redux/application/application.actions"; @@ -25,9 +28,8 @@ import { toggleModalVisible } from "../../redux/modals/modals.actions"; import { selectCardPayment } from "../../redux/modals/modals.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; -import DataLabel from "../data-label/data-label.component"; +import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component"; import JobSearchSelectComponent from "../job-search-select/job-search-select.component"; -import LayoutFormRow from "../layout-form-row/layout-form-row.component"; const mapStateToProps = createStructuredSelector({ cardPaymentModal: selectCardPayment, @@ -49,18 +51,21 @@ const CardPaymentModalComponent = ({ const { context } = cardPaymentModal; const [form] = Form.useForm(); - const amount = Form.useWatch("amount", form); - const jobid = Form.useWatch("jobid", form); + const [loading, setLoading] = useState(false); const [insertPayment] = useMutation(INSERT_NEW_PAYMENT); const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE); const { t } = useTranslation(); - const { data, refetch } = useQuery(QUERY_RO_AND_OWNER_BY_JOB_PK, { - variables: { jobid: context?.jobid ?? "" }, - skip: !context?.jobid, - }); + const [, { data, refetch, queryLoading }] = useLazyQuery( + QUERY_RO_AND_OWNER_BY_JOB_PKS, + { + variables: { jobids: [context.jobid] }, + skip: true, + } + ); + console.log("🚀 ~ file: card-payment-modal.component..jsx:61 ~ data:", data); //Initialize the intellipay window. const SetIntellipayCallbackFunctions = () => { console.log("*** Set IntelliPay callback functions."); @@ -76,69 +81,68 @@ const CardPaymentModalComponent = ({ window.intellipay.runOnNonApproval(async function (response) { // Mutate unsuccessful payment + + const { payments } = form.getFieldsValue(); + await insertPaymentResponse({ variables: { - paymentResponse: { - amount: response.amount, + paymentResponse: payments.map((payment) => ({ + amount: payment.amount, bodyshopid: bodyshop.id, - jobid: jobid || context.jobid, + jobid: payment.jobid, declinereason: response.declinereason, ext_paymentid: response.paymentid.toString(), successful: false, response, - }, + })), }, }); - insertAuditTrail({ - jobid: jobid || context?.jobid, - operation: AuditTrailMapping.failedpayment(), - }); + + payments.forEach((payment) => + insertAuditTrail({ + jobid: payment.jobid, + operation: AuditTrailMapping.failedpayment(), + }) + ); }); }; const handleFinish = async (values) => { try { - const paymentResult = await insertPayment({ + await insertPayment({ variables: { - paymentInput: { - amount: values.amount, + paymentInput: values.payments.map((payment) => ({ + amount: payment.amount, transactionid: (values.paymentResponse.paymentid || "").toString(), payer: t("payments.labels.customer"), type: values.paymentResponse.cardbrand, - jobid: values.jobid, + jobid: payment.jobid, date: moment(Date.now()), - }, + payment_responses: { + data: [ + { + amount: payment.amount, + bodyshopid: bodyshop.id, + + jobid: payment.jobid, + declinereason: values.paymentResponse.declinereason, + ext_paymentid: values.paymentResponse.paymentid.toString(), + successful: true, + response: values.paymentResponse, + }, + ], + }, + })), }, refetchQueries: ["GET_JOB_BY_PK"], - update(cache, { data }) { - cache.modify({ - id: cache.identify({ id: values.jobid, __typename: "jobs" }), - fields: { - payments(cachedPayments) { - return [...data.insert_payments.returning, ...cachedPayments]; - }, - }, - }); - }, - }); - - 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, - }, - }, }); toggleModalVisible(); } catch (error) { console.error(error); + notification.open({ + type: "error", + message: t("payments.errors.inserting", { error: error.message }), + }); } finally { setLoading(false); } @@ -146,9 +150,16 @@ const CardPaymentModalComponent = ({ const handleIntelliPayCharge = async () => { setLoading(true); - try { - console.warn("*** Window.Intellipay", !!window.intellipay); + //Validate + try { + await form.validateFields(); + } catch (error) { + setLoading(false); + return; + } + + try { const response = await axios.post("/intellipay/lightbox_credentials", { bodyshop, refresh: !!window.intellipay, @@ -182,93 +193,175 @@ const CardPaymentModalComponent = ({ - - - { - refetch({ jobid: e }); - }} - /> - - + + {(fields, { add, remove, move }) => { + return ( + + {fields.map((field, index) => ( + + + + + + + + + + + + + + { + remove(field.name); + }} + /> + + + + ))} + + { + add(); + }} + style={{ width: "100%" }} + > + {t("general.actions.add")} + + + + ); + }} + - {/* Lighbox Input amount needs to be hidden */} - - - - {/* Lightbox payment response when it is completed */} - - + + prevValues.payments?.map((p) => p?.jobid).join() !== + curValues.payments?.map((p) => p?.jobid).join() + } + > + {() => { + console.log("Updating the owner info section."); + //If all of the job ids have been fileld in, then query and update the IP field. + const { payments } = form.getFieldsValue(); + if ( + payments?.length > 0 && + payments?.filter((p) => p?.jobid).length === payments?.length + ) { + console.log("**Calling refetch."); + refetch({ jobids: payments.map((p) => p.jobid) }); + } + console.log( + "Acc info", + data, + payments && data && data.jobs.length > 0 + ? data.jobs.map((j) => j.ro_number).join(", ") + : null + ); + return ( + <> + 0 + ? data.jobs.map((j) => j.ro_number).join(", ") + : null + } + hidden + /> + 0 + ? data.jobs.filter((j) => j.ownr_ea)[0]?.ownr_ea + : null + } + hidden + /> + > + ); + }} + + + prevValues.payments?.map((p) => p?.amount).join() !== + curValues.payments?.map((p) => p?.amount).join() + } + > + {() => { + const { payments } = form.getFieldsValue(); + const totalAmountToCharge = payments?.reduce((acc, val) => { + return acc + (val?.amount || 0); + }, 0); + + return ( + + + + 0)} + onClick={handleIntelliPayCharge} + > + {t("job_payments.buttons.proceedtopayment")} + + + ); + }} - - - - - - - - {t("job_payments.buttons.proceedtopayment")} - - {context?.balance && ( - - {context?.balance.toFormat()} - - )} - - + {/* Lightbox payment response when it is completed */} + + + diff --git a/client/src/components/card-payment-modal/card-payment-modal.container..jsx b/client/src/components/card-payment-modal/card-payment-modal.container..jsx index 547a0ab75..f33b7bc9e 100644 --- a/client/src/components/card-payment-modal/card-payment-modal.container..jsx +++ b/client/src/components/card-payment-modal/card-payment-modal.container..jsx @@ -43,7 +43,7 @@ function CardPaymentModalContainer({ {t("job_payments.buttons.goback")} , ]} - width="60%" + width="80%" destroyOnClose > diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index e2208d939..dcb6eff92 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -254,7 +254,7 @@ function Header({ onClick={() => { setCardPaymentContext({ actions: {}, - context: null, + context: {}, }); }} icon={} diff --git a/client/src/components/jobs-available-table/jobs-available-table.container.jsx b/client/src/components/jobs-available-table/jobs-available-table.container.jsx index 7765c1b91..ad85bf494 100644 --- a/client/src/components/jobs-available-table/jobs-available-table.container.jsx +++ b/client/src/components/jobs-available-table/jobs-available-table.container.jsx @@ -139,6 +139,7 @@ export function JobsAvailableContainer({ // owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"), // job_totals: newTotals, date_open: moment(), + status: bodyshop.md_ro_statuses.default_imported, notes: { data: { created_by: currentUser.email, diff --git a/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx b/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx index 795e60110..8bbda03e1 100644 --- a/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx +++ b/client/src/components/jobs-close-export-button/jobs-close-export-button.component.jsx @@ -192,7 +192,7 @@ export function JobsCloseExportButton({ }); } } - if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) { notification.open({ type: "success", key: "jobsuccessexport", diff --git a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx index 15fdb32b4..3204d7311 100644 --- a/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx +++ b/client/src/components/jobs-export-all-button/jobs-export-all-button.component.jsx @@ -190,7 +190,7 @@ export function JobsExportAllButton({ }); } } - if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) { notification.open({ type: "success", key: "jobsuccessexport", diff --git a/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx b/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx index 723fd0526..c448e4f4a 100644 --- a/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx +++ b/client/src/components/payable-export-all-button/payable-export-all-button.component.jsx @@ -192,7 +192,7 @@ export function PayableExportAll({ }); } } - if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) { notification.open({ type: "success", key: "billsuccessexport", diff --git a/client/src/components/payable-export-button/payable-export-button.component.jsx b/client/src/components/payable-export-button/payable-export-button.component.jsx index 1836acb18..c2970b8d8 100644 --- a/client/src/components/payable-export-button/payable-export-button.component.jsx +++ b/client/src/components/payable-export-button/payable-export-button.component.jsx @@ -185,7 +185,7 @@ export function PayableExportButton({ }); } } - if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) { notification.open({ type: "success", key: "billsuccessexport", diff --git a/client/src/components/payment-expanded-row/payment-expanded-row.component.jsx b/client/src/components/payment-expanded-row/payment-expanded-row.component.jsx index 6266457a7..a150eee78 100644 --- a/client/src/components/payment-expanded-row/payment-expanded-row.component.jsx +++ b/client/src/components/payment-expanded-row/payment-expanded-row.component.jsx @@ -1,15 +1,24 @@ -import React, { useState } from "react"; import { useMutation, useQuery } from "@apollo/client"; +import { + Button, + Descriptions, + InputNumber, + Modal, + Space, + notification, +} from "antd"; +import axios from "axios"; +import moment from "moment"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; import { GET_REFUNDABLE_AMOUNT_BY_JOBID, INSERT_PAYMENT_RESPONSE, QUERY_PAYMENT_RESPONSE_BY_PAYMENT_ID, } from "../../graphql/payment_response.queries"; -import { Button, Descriptions, InputNumber, Modal, notification } from "antd"; -import moment from "moment"; -import axios from "axios"; import { INSERT_NEW_PAYMENT } from "../../graphql/payments.queries"; -import { useTranslation } from "react-i18next"; +import CurrencyFormatter from "../../utils/CurrencyFormatter"; +import { DateTimeFormatter } from "../../utils/DateFormatter"; const { confirm } = Modal; @@ -137,10 +146,10 @@ const PaymentExpandedRowComponent = ({ record, bodyshop }) => { {payment_response?.response?.nameOnCard ?? ""} - {record.amount} + {record.amount} - {moment(record.created_at).format("YYYY-MM-DD HH:mm:ss")} + {{record.created_at}} {record.transactionid} @@ -151,17 +160,22 @@ const PaymentExpandedRowComponent = ({ record, bodyshop }) => { {record.type} + + {record.paymentnum} + {payment_response && ( - + + - showConfirm(payment_response)}> - {t("job_payments.buttons.refundpayment")} - + showConfirm(payment_response)}> + {t("job_payments.buttons.refundpayment")} + + )} diff --git a/client/src/components/payment-export-button/payment-export-button.component.jsx b/client/src/components/payment-export-button/payment-export-button.component.jsx index 91f9ccc88..931254b92 100644 --- a/client/src/components/payment-export-button/payment-export-button.component.jsx +++ b/client/src/components/payment-export-button/payment-export-button.component.jsx @@ -191,7 +191,7 @@ export function PaymentExportButton({ }); } } - if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) { notification.open({ type: "success", key: "paymentsuccessexport", diff --git a/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx b/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx index 721e906d5..0b2e6cd7b 100644 --- a/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx +++ b/client/src/components/payments-export-all-button/payments-export-all-button.component.jsx @@ -179,7 +179,7 @@ export function PaymentsExportAllButton({ }); } } - if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) { + if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) { notification.open({ type: "success", key: "paymentsuccessexport", diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index e59083a3a..31578b244 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -574,7 +574,6 @@ export const GET_JOB_BY_PK = gql` est_co_nm est_ct_fn est_ct_ln - est_ph1 est_ea selling_dealer @@ -756,6 +755,7 @@ export const GET_JOB_BY_PK = gql` jobid amount payer + paymentnum created_at transactionid memo diff --git a/client/src/graphql/payment_response.queries.js b/client/src/graphql/payment_response.queries.js index 8722e6cd8..a23d00dbb 100644 --- a/client/src/graphql/payment_response.queries.js +++ b/client/src/graphql/payment_response.queries.js @@ -28,16 +28,14 @@ export const QUERY_PAYMENT_RESPONSE_BY_PAYMENT_ID = gql` } `; -export const QUERY_RO_AND_OWNER_BY_JOB_PK = gql` - query QUERY_RO_AND_OWNER_BY_JOB_PK($jobid: uuid!) { - jobs_by_pk(id: $jobid) { +export const QUERY_RO_AND_OWNER_BY_JOB_PKS = gql` + query QUERY_RO_AND_OWNER_BY_JOB_PKS($jobids: [uuid!]!) { + jobs(where: { id: { _in: $jobids } }) { ro_number - owner { - ownr_fn - ownr_ln - ownr_ea - ownr_zip - } + ownr_fn + ownr_ln + ownr_ea + ownr_zip } } `; diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 51b29311b..963e41b15 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -1222,6 +1222,7 @@ "payer": "Payer", "payername": "Payer Name", "paymentid": "Payment Reference ID", + "paymentnum": "Payment Number", "paymenttype": "Payment Type", "refundamount": "Refund Amount", "transactionid": "Transaction ID" @@ -2245,7 +2246,8 @@ }, "errors": { "exporting": "Error exporting payment(s). {{error}}", - "exporting-partner": "Error exporting to partner. Please check the partner interaction log for more errors." + "exporting-partner": "Error exporting to partner. Please check the partner interaction log for more errors.", + "inserting": "Error inserting payment. {{error}}" }, "fields": { "amount": "Amount", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index f8b695e7a..62583504c 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -1222,6 +1222,7 @@ "payer": "", "payername": "", "paymentid": "", + "paymentnum": "", "paymenttype": "", "refundamount": "", "transactionid": "" @@ -2245,7 +2246,8 @@ }, "errors": { "exporting": "", - "exporting-partner": "" + "exporting-partner": "", + "inserting": "" }, "fields": { "amount": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 3a11ec5bc..d32815fd0 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -1222,6 +1222,7 @@ "payer": "", "payername": "", "paymentid": "", + "paymentnum": "", "paymenttype": "", "refundamount": "", "transactionid": "" @@ -2245,7 +2246,8 @@ }, "errors": { "exporting": "", - "exporting-partner": "" + "exporting-partner": "", + "inserting": "" }, "fields": { "amount": "", diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 1d05bd8fd..9b19c1777 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -3274,6 +3274,7 @@ - cat_no - category - cieca_pfl + - cieca_pfo - cieca_pft - cieca_stl - cieca_ttl @@ -3542,6 +3543,7 @@ - cat_no - category - cieca_pfl + - cieca_pfo - cieca_pft - cieca_stl - cieca_ttl @@ -3821,6 +3823,7 @@ - cat_no - category - cieca_pfl + - cieca_pfo - cieca_pft - cieca_stl - cieca_ttl diff --git a/hasura/migrations/1695757361064_alter_table_public_jobs_add_column_cieca_pfo/down.sql b/hasura/migrations/1695757361064_alter_table_public_jobs_add_column_cieca_pfo/down.sql new file mode 100644 index 000000000..31337afb8 --- /dev/null +++ b/hasura/migrations/1695757361064_alter_table_public_jobs_add_column_cieca_pfo/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."jobs" add column "cieca_pfo" jsonb +-- null default jsonb_build_object(); diff --git a/hasura/migrations/1695757361064_alter_table_public_jobs_add_column_cieca_pfo/up.sql b/hasura/migrations/1695757361064_alter_table_public_jobs_add_column_cieca_pfo/up.sql new file mode 100644 index 000000000..d21094fdd --- /dev/null +++ b/hasura/migrations/1695757361064_alter_table_public_jobs_add_column_cieca_pfo/up.sql @@ -0,0 +1,2 @@ +alter table "public"."jobs" add column "cieca_pfo" jsonb + null default jsonb_build_object();