From acd3f545b3f500c2caca29824476050a00411df0 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Mon, 26 Sep 2022 11:33:58 -0700 Subject: [PATCH 01/11] IO-2054 RO Splitting for QBO --- bodyshop_translations.babel | 42 +++++++++ .../pages/jobs-close/jobs-close.component.jsx | 87 +++++++++++++++++-- client/src/translations/en_us/common.json | 2 + client/src/translations/es/common.json | 2 + client/src/translations/fr/common.json | 2 + server/accounting/qbo/qbo-receivables.js | 23 ++++- 6 files changed, 149 insertions(+), 9 deletions(-) diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 8d18dce03..c905978c4 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -26084,6 +26084,27 @@ + + additionalpayeroverallocation + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + additionaltotal false @@ -28062,6 +28083,27 @@ + + multipayers + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + net_repairs false diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx index b8f73c144..3df8aafc6 100644 --- a/client/src/pages/jobs-close/jobs-close.component.jsx +++ b/client/src/pages/jobs-close/jobs-close.component.jsx @@ -12,7 +12,9 @@ import { Popconfirm, Select, Space, + Statistic, Switch, + Typography, } from "antd"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; @@ -33,7 +35,7 @@ import { generateJobLinesUpdatesForInvoicing } from "../../graphql/jobs-lines.qu import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { selectJobReadOnly } from "../../redux/application/application.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors"; - +import Dinero from "dinero.js"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, jobRO: selectJobReadOnly, @@ -325,9 +327,41 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) { )} + {t("jobs.labels.multipayers")} {Qb_Multi_Ar.treatment === "on" && ( - <> - + + ({ + validator(_, value) { + let totalAllocated = Dinero(); + + const payers = form.getFieldValue("qb_multiple_payers"); + payers && + payers.forEach((payer) => { + totalAllocated = totalAllocated.add( + Dinero({ + amount: Math.round((payer?.amount || 0) * 100), + }) + ); + }); + const discrep = job.job_totals + ? Dinero(job.job_totals.totals.total_repairs).subtract( + totalAllocated + ) + : Dinero(); + return discrep.getAmount() > 0 + ? Promise.resolve() + : Promise.reject( + new Error( + t("jobs.labels.additionalpayeroverallocation") + ) + ); + }, + }), + ]} + > {(fields, { add, remove }) => { return (
@@ -382,7 +416,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
}> - - - - + {Qb_Multi_Ar.treatment === "on" && ( + Multiple Payers Item}> + + + + + )} {t("bodyshop.labels.responsibilitycenters.sales_tax_codes")} From c154e7be2ef8b707a9bc2450652d8e3c5df5eebc Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Sep 2022 08:41:45 -0700 Subject: [PATCH 03/11] IO-223 ARMS bug fixes. --- server/data/arms.js | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/server/data/arms.js b/server/data/arms.js index 7e3cd9643..959c13382 100644 --- a/server/data/arms.js +++ b/server/data/arms.js @@ -205,8 +205,8 @@ exports.default = async (req, res) => { Party: { PersonInfo: { PersonName: { - FirstName: job.ownr_fn, - LastName: job.ownr_ln, + FirstName: job.ownr_co_nm ? "" : job.ownr_fn, + LastName: job.ownr_co_nm ? job.ownr_co_nm : job.ownr_ln, }, // Communications: [ // { @@ -336,7 +336,7 @@ exports.default = async (req, res) => { LossDateTime: job.loss_date && moment(job.loss_date) - .tz(bodyshop.timezone) + //.tz(bodyshop.timezone) .format(momentFormat), LossDescCode: "Collision", PrimaryPOI: { @@ -515,8 +515,11 @@ exports.default = async (req, res) => { { TotalType: "LAB", TotalTypeDesc: "Body Labor", - TotalHours: job.job_totals.rates.lab.hours, - TotalAmt: Dinero(job.job_totals.rates.lab.total).toFormat("0.00"), + TotalHours: + job.job_totals.rates.lab.hours + job.job_totals.rates.la1.hours, + TotalAmt: Dinero(job.job_totals.rates.lab.total) + .add(Dinero(job.job_totals.rates.la1.total)) + .toFormat("0.00"), }, { TotalType: "LAF", @@ -635,9 +638,9 @@ exports.default = async (req, res) => { { TotalType: "OTAC", TotalTypeDesc: "Additional Charges", - TotalAmt: Dinero( - job.job_totals.additional.additionalCosts - ).toFormat("0.00"), + TotalAmt: Dinero(job.job_totals.additional.additionalCosts) + .add(Dinero(job.job_totals.additional.pvrt)) + .toFormat("0.00"), }, ], SummaryTotalsInfo: [ From 918bc402f69e8c2021196db8378f560b564ef946 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Sep 2022 15:07:15 -0700 Subject: [PATCH 04/11] IO-2054 Add Payments Export --- .../payment-form/payment-form.component.jsx | 24 +++++++-- server/accounting/qbo/qbo-payments.js | 49 +++++++++++++++---- 2 files changed, 60 insertions(+), 13 deletions(-) diff --git a/client/src/components/payment-form/payment-form.component.jsx b/client/src/components/payment-form/payment-form.component.jsx index 57a3ce4a7..9458aece3 100644 --- a/client/src/components/payment-form/payment-form.component.jsx +++ b/client/src/components/payment-form/payment-form.component.jsx @@ -1,3 +1,4 @@ +import { useTreatments } from "@splitsoftware/splitio-react"; import { CardElement } from "@stripe/react-stripe-js"; import { Checkbox, Form, Input, Radio, Select } from "antd"; import React from "react"; @@ -23,6 +24,11 @@ export function PaymentFormComponent({ disabled, }) { const [stripeState, setStripeState] = stripeStateArr; + const { Qb_Multi_Ar } = useTreatments( + ["Qb_Multi_Ar"], + {}, + bodyshop && bodyshop.imexshopid + ); const { t } = useTranslation(); const handleStripeChange = (e) => { @@ -106,9 +112,21 @@ export function PaymentFormComponent({ {t("payments.labels.customer")} - - {t("payments.labels.insurance")} - + {Qb_Multi_Ar.treatment === "on" ? ( + <> + + {bodyshop.md_ins_cos.map((i, idx) => ( + + {i.name} + + ))} + + + ) : ( + + {t("payments.labels.insurance")} + + )} diff --git a/server/accounting/qbo/qbo-payments.js b/server/accounting/qbo/qbo-payments.js index c903c0a43..c4f58079f 100644 --- a/server/accounting/qbo/qbo-payments.js +++ b/server/accounting/qbo/qbo-payments.js @@ -73,11 +73,19 @@ exports.default = async (req, res) => { for (const payment of payments) { try { - const isThreeTier = bodyshop.accountingconfig.tiers === 3; - const twoTierPref = bodyshop.accountingconfig.twotierpref; + let isThreeTier = bodyshop.accountingconfig.tiers === 3; + let twoTierPref = bodyshop.accountingconfig.twotierpref; //Replace this with a for-each loop to check every single Job that's included in the list. + //QB Multi AR - If it is in this scenario, overwrite whatever defaults are set since multi AR + //will always go Source => RO + if (payment.payer !== "Customer") { + payment.job.ins_co_nm = payment.payer; + twoTierPref = "source"; + isThreeTier = false; + } + let insCoCustomerTier, ownerCustomerTier, jobTier; if (isThreeTier || (!isThreeTier && twoTierPref === "source")) { //Insert the insurance company tier. @@ -106,7 +114,9 @@ exports.default = async (req, res) => { oauthClient, qbo_realmId, req, - payment.job + payment.job, + isThreeTier, + insCoCustomerTier ); //Query for the owner itself. if (!ownerCustomerTier) { @@ -122,7 +132,17 @@ exports.default = async (req, res) => { } //Query for the Job or Create it. - jobTier = await QueryJob(oauthClient, qbo_realmId, req, payment.job); + jobTier = await QueryJob( + oauthClient, + qbo_realmId, + req, + payment.job, + isThreeTier + ? ownerCustomerTier + : twoTierPref === "source" + ? insCoCustomerTier + : ownerCustomerTier + ); // Need to validate that the job tier is associated to the right individual? @@ -237,7 +257,8 @@ async function InsertPayment( qbo_realmId, req, payment.job.ro_number, - false + false, + parentRef ); if (invoices && invoices.length !== 1) { @@ -260,7 +281,7 @@ async function InsertPayment( PaymentMethodRef: { value: paymentMethods[payment.type], }, - ...(invoices && invoices.length === 1 + ...(invoices && invoices.length === 1 && invoices[0] ? { Line: [ { @@ -305,13 +326,14 @@ async function QueryMetaData( qbo_realmId, req, ro_number, - isCreditMemo + isCreditMemo, + parentTierRef ) { const invoice = await oauthClient.makeApiCall({ url: urlBuilder( qbo_realmId, "query", - `select * From Invoice where DocNumber = '${ro_number}'` + `select * From Invoice where DocNumber like '${ro_number}%'` ), method: "POST", headers: { @@ -407,7 +429,13 @@ async function QueryMetaData( invoices: invoice.json && invoice.json.QueryResponse && - invoice.json.QueryResponse.Invoice, + (parentTierRef + ? [ + invoice.json.QueryResponse.Invoice.find( + (x) => x.CustomerRef.value === parentTierRef.Id + ), + ] + : [invoice.json.QueryResponse.Invoice[0]]), }; } async function InsertCreditMemo( @@ -423,7 +451,8 @@ async function InsertCreditMemo( qbo_realmId, req, payment.job.ro_number, - true + true, + parentRef ); if (invoices && invoices.length !== 1) { From e8fc29ea61861c458ea84f40eb5fc426dd04d8ae Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Sep 2022 15:07:26 -0700 Subject: [PATCH 05/11] Autohouse Updates. --- client/src/pages/jobs-create/jobs-create.container.jsx | 1 + server/data/autohouse.js | 6 +++++- server/graphql-client/queries.js | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/client/src/pages/jobs-create/jobs-create.container.jsx b/client/src/pages/jobs-create/jobs-create.container.jsx index b7ffad7b2..15af524ed 100644 --- a/client/src/pages/jobs-create/jobs-create.container.jsx +++ b/client/src/pages/jobs-create/jobs-create.container.jsx @@ -89,6 +89,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { let job = Object.assign( {}, values, + { date_open: new Date() }, { vehicle: state.vehicle.selectedid || state.vehicle.none diff --git a/server/data/autohouse.js b/server/data/autohouse.js index 265187796..679a455b9 100644 --- a/server/data/autohouse.js +++ b/server/data/autohouse.js @@ -57,7 +57,7 @@ exports.default = async (req, res) => { bodyshopid: bodyshop.id, start: start ? moment(start).startOf("day") - : moment().subtract(3, "days").startOf("day"), + : moment().subtract(5, "days").startOf("day"), ...(end && { end: moment(end).startOf("day") }), } ); @@ -316,6 +316,10 @@ const CreateRepairOrderTag = (job, errorCallback) => { moment(job.date_open) .tz(job.bodyshop.timezone) .format(AhDateFormat)) || + (job.created_at && + moment(job.created_at) + .tz(job.bodyshop.timezone) + .format(AhDateFormat)) || "", ScheduledArrivalDate: (job.scheduled_in && diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index 1f984cde5..fdae6eb5e 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -623,6 +623,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshop } jobs(where: {_and: [{converted: {_eq: true}}, {updated_at: {_gt: $start}}, {updated_at: {_lte: $end}}, {shopid: {_eq: $bodyshopid}}]}) { id + created_at ro_number status est_ct_fn From 45fca7206b424618da907efe8e09bf23341d9fad Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 27 Sep 2022 17:07:42 -0700 Subject: [PATCH 06/11] IO-2054 Bug fix for payments. --- server/accounting/qbo/qbo-payments.js | 1 + 1 file changed, 1 insertion(+) diff --git a/server/accounting/qbo/qbo-payments.js b/server/accounting/qbo/qbo-payments.js index c4f58079f..3f729d80d 100644 --- a/server/accounting/qbo/qbo-payments.js +++ b/server/accounting/qbo/qbo-payments.js @@ -429,6 +429,7 @@ async function QueryMetaData( invoices: invoice.json && invoice.json.QueryResponse && + invoice.json.QueryResponse.Invoice && (parentTierRef ? [ invoice.json.QueryResponse.Invoice.find( From 045a3660a3e58dfa961d1246311b3f5faae56169 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Wed, 28 Sep 2022 11:30:11 -0700 Subject: [PATCH 07/11] IO-2054 Updated labels for multi AR. --- bodyshop_translations.babel | 42 +++++++++++++++++++ .../pages/jobs-close/jobs-close.component.jsx | 12 +++++- client/src/translations/en_us/common.json | 2 + client/src/translations/es/common.json | 2 + client/src/translations/fr/common.json | 2 + 5 files changed, 58 insertions(+), 2 deletions(-) diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index c905978c4..61ce03247 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -28335,6 +28335,27 @@
+ + pimraryamountpayable + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + plitooltips @@ -35325,6 +35346,27 @@ + + external + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + findermodal false diff --git a/client/src/pages/jobs-close/jobs-close.component.jsx b/client/src/pages/jobs-close/jobs-close.component.jsx index 3df8aafc6..4f014a240 100644 --- a/client/src/pages/jobs-close/jobs-close.component.jsx +++ b/client/src/pages/jobs-close/jobs-close.component.jsx @@ -416,7 +416,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) { - ))} - - - - - ); - }} - - - {() => { - //Perform Calculation to determine discrepancy. - let totalAllocated = Dinero(); + + ); + }} + + + + + {() => { + //Perform Calculation to determine discrepancy. + let totalAllocated = Dinero(); - const payers = form.getFieldValue("qb_multiple_payers"); - payers && - payers.forEach((payer) => { - totalAllocated = totalAllocated.add( - Dinero({ amount: Math.round((payer?.amount || 0) * 100) }) - ); - }); - const discrep = job.job_totals - ? Dinero(job.job_totals.totals.total_repairs).subtract( - totalAllocated - ) - : Dinero(); - return ( - - - - - - - - = - 0 ? "green" : "red", - }} - value={discrep.toFormat()} - /> - - ); - }} - - + const payers = form.getFieldValue("qb_multiple_payers"); + payers && + payers.forEach((payer) => { + totalAllocated = totalAllocated.add( + Dinero({ + amount: Math.round((payer?.amount || 0) * 100), + }) + ); + }); + const discrep = job.job_totals + ? Dinero(job.job_totals.totals.total_repairs).subtract( + totalAllocated + ) + : Dinero(); + return ( + + + + + - + + = + 0 ? "green" : "red", + }} + value={discrep.toFormat()} + /> + + ); + }} + + + )} From d699e49369e788dbd701c79b4246b365ac38b99e Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Wed, 28 Sep 2022 12:44:09 -0700 Subject: [PATCH 11/11] IO-223 Use NA for owner company name. --- server/data/arms.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/data/arms.js b/server/data/arms.js index 959c13382..a95887f05 100644 --- a/server/data/arms.js +++ b/server/data/arms.js @@ -205,7 +205,7 @@ exports.default = async (req, res) => { Party: { PersonInfo: { PersonName: { - FirstName: job.ownr_co_nm ? "" : job.ownr_fn, + FirstName: job.ownr_co_nm ? "N/A" : job.ownr_fn, LastName: job.ownr_co_nm ? job.ownr_co_nm : job.ownr_ln, }, // Communications: [