diff --git a/server/accounting/qbo/qbo-payables.js b/server/accounting/qbo/qbo-payables.js index e9391c21d..64a1db7eb 100644 --- a/server/accounting/qbo/qbo-payables.js +++ b/server/accounting/qbo/qbo-payables.js @@ -87,17 +87,17 @@ exports.default = async (req, res) => { } catch (error) { logger.log("qbo-paybles-create-error", "ERROR", req.user.email, null, { error: - (error?.authResponse && error.authResponse.body) || - error.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") || + error?.authResponse?.body || + error?.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") || error?.message }); ret.push({ billid: bill.id, success: false, errorMessage: - (error && error.authResponse && error.authResponse.body) || - error.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") || - (error && error.message) + error?.authResponse?.body || + error?.response?.data?.Fault?.Error.map((e) => e.Detail).join(", ") || + error?.message }); //Add the export log error. @@ -108,9 +108,7 @@ exports.default = async (req, res) => { bodyshopid: bodyshop.id, billid: bill.id, successful: false, - message: JSON.stringify([ - (error && error.authResponse && error.authResponse.body) || (error && error.message) - ]), + message: JSON.stringify([error?.authResponse?.body || error?.message]), useremail: req.user.email } ] @@ -153,7 +151,7 @@ async function QueryVendorRecord(oauthClient, qbo_realmId, req, bill) { email: req.user.email }); setNewRefreshToken(req.user.email, result); - return result.json?.QueryResponse?.Vendor[0]; + return result.json?.QueryResponse?.Vendor?.[0]; } catch (error) { logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, { method: "QueryVendorRecord", @@ -190,7 +188,7 @@ async function InsertVendorRecord(oauthClient, qbo_realmId, req, bill) { if (result.status >= 400) { throw new Error(JSON.stringify(result.json.Fault)); } - if (result.status === 200) return result?.json; + if (result.status === 200) return result?.json.Vendor; } catch (error) { logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, { method: "InsertVendorRecord", @@ -248,12 +246,7 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor, bodyshop) } //QB USA with GST //This was required for the No. 1 Collision Group. - if ( - bodyshop.accountingconfig && - bodyshop.accountingconfig.qbo && - bodyshop.accountingconfig.qbo_usa && - bodyshop.region_config.includes("CA_") - ) { + if (bodyshop.accountingconfig?.qbo && bodyshop.accountingconfig?.qbo_usa && bodyshop.region_config.includes("CA_")) { lines.push({ DetailType: "AccountBasedExpenseLineDetail", @@ -276,7 +269,8 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor, bodyshop) }); } - const billQbo = { + let billQbo, VendorCredit; + const billObject = { VendorRef: { value: vendor.Id }, @@ -298,22 +292,30 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor, bodyshop) DocNumber: bill.invoice_number, //...(bill.job.class ? { ClassRef: { Id: classes[bill.job.class] } } : {}), ...(!( - bodyshop.accountingconfig && - bodyshop.accountingconfig.qbo && - bodyshop.accountingconfig.qbo_usa && + bodyshop.accountingconfig?.qbo && + bodyshop.accountingconfig?.qbo_usa && bodyshop.region_config.includes("CA_") ) ? { GlobalTaxCalculation: "TaxExcluded" } : {}), - ...(bodyshop.accountingconfig.qbo_departmentid && - bodyshop.accountingconfig.qbo_departmentid.trim() !== "" && { - DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid } - }), + ...(bodyshop.accountingconfig.qbo_departmentid?.trim() !== "" && { + DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid } + }), PrivateNote: `RO ${bill.job.ro_number || ""}`, Line: lines }; + + if (bill.is_credit_memo) { + VendorCredit = billObject; + } else { + billQbo = billObject; + } + + const logKey = bill.is_credit_memo ? "VendorCredit" : "billQbo"; + const logValue = bill.is_credit_memo ? VendorCredit : billQbo; + logger.log("qbo-payable-objectlog", "DEBUG", req.user.email, bill.id, { - billQbo + [logKey]: logValue }); try { const result = await oauthClient.makeApiCall({ @@ -322,7 +324,7 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor, bodyshop) headers: { "Content-Type": "application/json" }, - body: JSON.stringify(billQbo) + body: JSON.stringify(bill.is_credit_memo ? VendorCredit : billQbo) }); logger.LogIntegrationCall({ platform: "QBO", @@ -450,30 +452,19 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid) { email: req.user.email }); const taxCodeMapping = {}; - - taxCodes.json && - taxCodes.json.QueryResponse && - taxCodes.json.QueryResponse.TaxCode && - taxCodes.json.QueryResponse.TaxCode.forEach((t) => { - taxCodeMapping[t.Name] = t.Id; - }); + taxCodes.json?.QueryResponse?.TaxCode?.forEach((t) => { + taxCodeMapping[t.Name] = t.Id; + }); const accountMapping = {}; - - accounts.json && - accounts.json.QueryResponse && - accounts.json.QueryResponse.Account && - accounts.json.QueryResponse.Account.forEach((t) => { - accountMapping[t.FullyQualifiedName] = t.Id; - }); + accounts.json?.QueryResponse?.Account?.forEach((t) => { + accountMapping[t.FullyQualifiedName] = t.Id; + }); const classMapping = {}; - classes.json && - classes.json.QueryResponse && - classes.json.QueryResponse.Class && - classes.json.QueryResponse.Class.forEach((t) => { - classMapping[t.Name] = t.Id; - }); + classes.json?.QueryResponse?.Class?.forEach((t) => { + classMapping[t.Name] = t.Id; + }); return { accounts: accountMapping, diff --git a/server/accounting/qbo/qbo-payments.js b/server/accounting/qbo/qbo-payments.js index be9a28ab1..f4c5d6c52 100644 --- a/server/accounting/qbo/qbo-payments.js +++ b/server/accounting/qbo/qbo-payments.js @@ -145,7 +145,7 @@ exports.default = async (req, res) => { ret.push({ paymentid: payment.id, success: true }); } catch (error) { logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, { - error: (error && error.authResponse && error.authResponse.body) || (error && error.message) + error: error?.authResponse?.body || error?.message }); //Add the export log error. if (elgen) { @@ -155,9 +155,7 @@ exports.default = async (req, res) => { bodyshopid: bodyshop.id, paymentid: payment.id, successful: false, - message: JSON.stringify([ - (error && error.authResponse && error.authResponse.body) || (error && error.message) - ]), + message: JSON.stringify([error?.authResponse?.body || error?.message]), useremail: req.user.email } ] @@ -167,7 +165,7 @@ exports.default = async (req, res) => { ret.push({ paymentid: payment.id, success: false, - errorMessage: (error && error.authResponse && error.authResponse.body) || (error && error.message) + errorMessage: error?.authResponse?.body || error?.message }); } } @@ -201,9 +199,7 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef) CustomerRef: { value: parentRef.Id }, - TxnDate: moment(payment.date) //.tz(bodyshop.timezone) - .format("YYYY-MM-DD"), - //DueDate: bill.due_date && moment(bill.due_date).format("YYYY-MM-DD"), + TxnDate: moment(payment.date).format("YYYY-MM-DD"), DocNumber: payment.paymentnum, TotalAmt: Dinero({ amount: Math.round(payment.amount * 100) @@ -211,19 +207,13 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef) PaymentMethodRef: { value: paymentMethods[payment.type] }, - PrivateNote: payment.memo - ? payment.memo.length > 4000 - ? payment.memo.substring(0, 4000).trim() - : payment.memo.trim() - : "", + PrivateNote: payment.memo?.substring(0, 4000)?.trim() ?? "", PaymentRefNum: payment.transactionid, - ...(invoices && invoices.length === 1 && invoices[0] + ...(invoices?.length === 1 && invoices[0] ? { Line: [ { - Amount: Dinero({ - amount: Math.round(payment.amount * 100) - }).toFormat(DineroQbFormat), + Amount: Dinero({ amount: Math.round(payment.amount * 100) }).toFormat(DineroQbFormat), LinkedTxn: [ { TxnId: invoices[0].Id, @@ -260,7 +250,7 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef) if (result.status >= 400) { throw new Error(JSON.stringify(result.json.Fault)); } - if (result.status === 200) return result?.json; + if (result.status === 200) return result?.json.Customer; } catch (error) { logger.log("qbo-payables-error", "DEBUG", req.user.email, payment.id, { method: "InsertPayment", @@ -273,11 +263,7 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef) async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditMemo, parentTierRef, bodyshopid) { const invoice = await oauthClient.makeApiCall({ - url: urlBuilder( - qbo_realmId, - "query", - `select * From Invoice where DocNumber like '${ro_number}%'` - ), + url: urlBuilder(qbo_realmId, "query", `select * From Invoice where DocNumber like '${ro_number}%'`), method: "POST", headers: { "Content-Type": "application/json" @@ -292,11 +278,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM email: req.user.email }); const paymentMethods = await oauthClient.makeApiCall({ - url: urlBuilder( - qbo_realmId, - "query", - `select * From PaymentMethod` - ), + url: urlBuilder(qbo_realmId, "query", `select * From PaymentMethod`), method: "POST", headers: { "Content-Type": "application/json" @@ -322,12 +304,9 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM const paymentMethodMapping = {}; - paymentMethods.json && - paymentMethods.json.QueryResponse && - paymentMethods.json.QueryResponse.PaymentMethod && - paymentMethods.json.QueryResponse.PaymentMethod.forEach((t) => { - paymentMethodMapping[t.Name] = t.Id; - }); + paymentMethods.json?.QueryResponse?.PaymentMethod?.forEach((t) => { + paymentMethodMapping[t.Name] = t.Id; + }); // const accountMapping = {}; @@ -347,11 +326,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM if (isCreditMemo) { const taxCodes = await oauthClient.makeApiCall({ - url: urlBuilder( - qbo_realmId, - "query", - `select * From TaxCode` - ), + url: urlBuilder(qbo_realmId, "query", `select * From TaxCode`), method: "POST", headers: { "Content-Type": "application/json" @@ -366,11 +341,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM email: req.user.email }); const items = await oauthClient.makeApiCall({ - url: urlBuilder( - qbo_realmId, - "query", - `select * From Item` - ), + url: urlBuilder(qbo_realmId, "query", `select * From Item`), method: "POST", headers: { "Content-Type": "application/json" @@ -388,20 +359,15 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM const itemMapping = {}; - items.json && - items.json.QueryResponse && - items.json.QueryResponse.Item && - items.json.QueryResponse.Item.forEach((t) => { - itemMapping[t.Name] = t.Id; - }); + items.json?.QueryResponse?.Item?.forEach((t) => { + itemMapping[t.Name] = t.Id; + }); const taxCodeMapping = {}; - taxCodes.json && - taxCodes.json.QueryResponse && - taxCodes.json.QueryResponse.TaxCode && - taxCodes.json.QueryResponse.TaxCode.forEach((t) => { - taxCodeMapping[t.Name] = t.Id; - }); + taxCodes.json?.QueryResponse?.TaxCode?.forEach((t) => { + taxCodeMapping[t.Name] = t.Id; + }); + ret = { ...ret, items: itemMapping, @@ -413,12 +379,10 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM ...ret, paymentMethods: paymentMethodMapping, invoices: - invoice.json && - invoice.json.QueryResponse && - invoice.json.QueryResponse.Invoice && + invoice.json?.QueryResponse?.Invoice && (parentTierRef - ? [invoice.json.QueryResponse.Invoice.find((x) => x.CustomerRef.value === parentTierRef.Id)] - : [invoice.json.QueryResponse.Invoice[0]]) + ? [invoice.json?.QueryResponse?.Invoice.find((x) => x.CustomerRef?.value === parentTierRef?.Id)] + : [invoice.json?.QueryResponse?.Invoice?.[0]]) }; } @@ -433,7 +397,7 @@ async function InsertCreditMemo(oauthClient, qbo_realmId, req, payment, parentRe payment.job.shopid ); - if (invoices && invoices.length !== 1) { + if (invoices?.length !== 1) { throw new Error(`More than 1 invoice with DocNumber ${payment.ro_number} found.`); } @@ -441,11 +405,9 @@ async function InsertCreditMemo(oauthClient, qbo_realmId, req, payment, parentRe CustomerRef: { value: parentRef.Id }, - TxnDate: moment(payment.date) - //.tz(bodyshop.timezone) - .format("YYYY-MM-DD"), + TxnDate: moment(payment.date).format("YYYY-MM-DD"), DocNumber: payment.paymentnum, - ...(invoices && invoices[0] ? { InvoiceRef: { value: invoices[0].Id } } : {}), + ...(invoices?.[0] ? { InvoiceRef: { value: invoices[0].Id } } : {}), PaymentRefNum: payment.transactionid, Line: [ { diff --git a/server/accounting/qbo/qbo-receivables.js b/server/accounting/qbo/qbo-receivables.js index 10c662c74..bc97961cc 100644 --- a/server/accounting/qbo/qbo-receivables.js +++ b/server/accounting/qbo/qbo-receivables.js @@ -103,7 +103,7 @@ exports.default = async (req, res) => { if (!req.body.custDataOnly) { await InsertInvoice(oauthClient, qbo_realmId, req, job, bodyshop, jobTier); - if (job.qb_multiple_payers && job.qb_multiple_payers.length > 0) { + if (job.qb_multiple_payers?.length > 0) { for (const [index, payer] of job.qb_multiple_payers.entries()) { //do the thing. @@ -150,23 +150,21 @@ exports.default = async (req, res) => { // //No error. Mark the job exported & insert export log. if (elgen) { - await client - .setHeaders({ Authorization: BearerToken }) - .request(queries.QBO_MARK_JOB_EXPORTED, { - jobId: job.id, - job: { - status: bodyshop.md_ro_statuses.default_exported || "Exported*", - date_exported: moment().tz(bodyshop.timezone) - }, - logs: [ - { - bodyshopid: bodyshop.id, - jobid: job.id, - successful: true, - useremail: req.user.email - } - ] - }); + await client.setHeaders({ Authorization: BearerToken }).request(queries.QBO_MARK_JOB_EXPORTED, { + jobId: job.id, + job: { + status: bodyshop.md_ro_statuses.default_exported || "Exported*", + date_exported: moment().tz(bodyshop.timezone) + }, + logs: [ + { + bodyshopid: bodyshop.id, + jobid: job.id, + successful: true, + useremail: req.user.email + } + ] + }); } } ret.push({ jobid: job.id, success: true }); @@ -193,9 +191,7 @@ exports.default = async (req, res) => { bodyshopid: bodyshop.id, jobid: job.id, successful: false, - message: JSON.stringify([ - (error && error.authResponse && error.authResponse.body) || (error && error.message) - ]), + message: JSON.stringify([error?.authResponse?.body || error?.message]), useremail: req.user.email } ] @@ -232,18 +228,13 @@ async function QueryInsuranceCo(oauthClient, qbo_realmId, req, job) { platform: "QBO", method: "POST", name: "QueryCustomer", - status: result.response?.status, + status: result.status, bodyshopid: job.shopid, jobid: job.id, email: req.user.email }); setNewRefreshToken(req.user.email, result); - return ( - result.json && - result.json.QueryResponse && - result.json.QueryResponse.Customer && - result.json.QueryResponse.Customer[0] - ); + return result.json?.QueryResponse?.Customer?.[0]; } catch (error) { logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, { error, @@ -287,13 +278,13 @@ async function InsertInsuranceCo(oauthClient, qbo_realmId, req, job, bodyshop) { platform: "QBO", method: "POST", name: "InsertCustomer", - status: result.response.status, + status: result.status, bodyshopid: job.shopid, jobid: job.id, email: req.user.email }); setNewRefreshToken(req.user.email, result); - return result && result.json.Customer; + return result.json?.Customer; } catch (error) { logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, { error, @@ -322,18 +313,13 @@ async function QueryOwner(oauthClient, qbo_realmId, req, job, parentTierRef) { platform: "QBO", method: "POST", name: "QueryCustomer", - status: result.response?.status, + status: result.status, bodyshopid: job.shopid, jobid: job.id, email: req.user.email }); setNewRefreshToken(req.user.email, result); - return ( - result.json && - result.json.QueryResponse && - result.json.QueryResponse.Customer && - result.json.QueryResponse.Customer.find((x) => x.ParentRef?.value === parentTierRef?.Id) - ); + return result.json?.QueryResponse?.Customer?.find((x) => x.ParentRef?.value === parentTierRef?.Id); } exports.QueryOwner = QueryOwner; @@ -373,13 +359,13 @@ async function InsertOwner(oauthClient, qbo_realmId, req, job, isThreeTier, pare platform: "QBO", method: "POST", name: "InsertCustomer", - status: result.response?.status, + status: result.status, bodyshopid: job.shopid, jobid: job.id, email: req.user.email }); setNewRefreshToken(req.user.email, result); - return result && result.json.Customer; + return result.json?.Customer; } catch (error) { logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, { error, @@ -407,20 +393,14 @@ async function QueryJob(oauthClient, qbo_realmId, req, job, parentTierRef) { platform: "QBO", method: "POST", name: "QueryCustomer", - status: result.response?.status, + status: result.status, bodyshopid: job.shopid, jobid: job.id, email: req.user.email }); setNewRefreshToken(req.user.email, result); - return ( - result.json && - result.json.QueryResponse && - result.json.QueryResponse.Customer && - (parentTierRef - ? result.json.QueryResponse.Customer.find((x) => x.ParentRef.value === parentTierRef.Id) - : result.json.QueryResponse.Customer[0]) - ); + const customers = result.json?.QueryResponse?.Customer; + return customers && (parentTierRef ? customers.find((x) => x.ParentRef.value === parentTierRef.Id) : customers[0]); } exports.QueryJob = QueryJob; @@ -464,7 +444,7 @@ async function InsertJob(oauthClient, qbo_realmId, req, job, parentTierRef) { if (result.status >= 400) { throw new Error(JSON.stringify(result.json.Fault)); } - if (result.status === 200) return result?.json; + if (result.status === 200) return result?.json.Customer; } catch (error) { logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, { method: "InsertOwner", @@ -479,13 +459,7 @@ exports.InsertJob = InsertJob; async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid, jobid) { const items = await oauthClient.makeApiCall({ - url: urlBuilder( - qbo_realmId, - "query", - `select * - From Item - where active = true maxresults 1000` - ), + url: urlBuilder(qbo_realmId, "query", `select * From Item where active = true maxresults 1000`), method: "POST", headers: { "Content-Type": "application/json" @@ -502,13 +476,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid, jobid) { }); setNewRefreshToken(req.user.email, items); const taxCodes = await oauthClient.makeApiCall({ - url: urlBuilder( - qbo_realmId, - "query", - `select * - From TaxCode - where active = true` - ), + url: urlBuilder(qbo_realmId, "query", `select * From TaxCode where active = true`), method: "POST", headers: { "Content-Type": "application/json" @@ -524,12 +492,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid, jobid) { email: req.user.email }); const classes = await oauthClient.makeApiCall({ - url: urlBuilder( - qbo_realmId, - "query", - `select * - From Class` - ), + url: urlBuilder(qbo_realmId, "query", `select * From Class`), method: "POST", headers: { "Content-Type": "application/json" @@ -544,31 +507,21 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid, jobid) { jobid: jobid, email: req.user.email }); - const taxCodeMapping = {}; - taxCodes.json && - taxCodes.json.QueryResponse && - taxCodes.json.QueryResponse.TaxCode && - taxCodes.json.QueryResponse.TaxCode.forEach((t) => { - taxCodeMapping[t.Name] = t.Id; - }); + const taxCodeMapping = {}; + taxCodes.json?.QueryResponse?.TaxCode?.forEach((t) => { + taxCodeMapping[t.Name] = t.Id; + }); const itemMapping = {}; - - items.json && - items.json.QueryResponse && - items.json.QueryResponse.Item && - items.json.QueryResponse.Item.forEach((t) => { - itemMapping[t.Name] = t.Id; - }); + items.json?.QueryResponse?.Item?.forEach((t) => { + itemMapping[t.Name] = t.Id; + }); const classMapping = {}; - classes.json && - classes.json.QueryResponse && - classes.json.QueryResponse.Class && - classes.json.QueryResponse.Class.forEach((t) => { - classMapping[t.Name] = t.Id; - }); + classes.json?.QueryResponse?.Class?.forEach((t) => { + classMapping[t.Name] = t.Id; + }); return { items: itemMapping, @@ -601,12 +554,11 @@ async function InsertInvoice(oauthClient, qbo_realmId, req, job, bodyshop, paren } ${job.v_vin || ""} ${job.plate_no || ""} `.trim() }, CustomerRef: { - value: parentTierRef.Id + value: parentTierRef?.Id }, - ...(bodyshop.accountingconfig.qbo_departmentid && - bodyshop.accountingconfig.qbo_departmentid.trim() !== "" && { - DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid } - }), + ...(bodyshop.accountingconfig.qbo_departmentid?.trim() !== "" && { + DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid } + }), CustomField: [ ...(bodyshop.accountingconfig.ReceivableCustomField1 ? [ @@ -636,9 +588,8 @@ async function InsertInvoice(oauthClient, qbo_realmId, req, job, bodyshop, paren ] : []) ], - ...(bodyshop.accountingconfig && - bodyshop.accountingconfig.qbo && - bodyshop.accountingconfig.qbo_usa && { + ...(bodyshop.accountingconfig?.qbo && + bodyshop.accountingconfig?.qbo_usa && { TxnTaxDetail: { TxnTaxCodeRef: { value: taxCodes[bodyshop.md_responsibility_centers.taxes.state.accountitem] @@ -732,10 +683,9 @@ async function InsertInvoiceMultiPayerInvoice( CustomerRef: { value: parentTierRef.Id }, - ...(bodyshop.accountingconfig.qbo_departmentid && - bodyshop.accountingconfig.qbo_departmentid.trim() !== "" && { - DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid } - }), + ...(bodyshop.accountingconfig.qbo_departmentid?.trim() !== "" && { + DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid } + }), CustomField: [ ...(bodyshop.accountingconfig.ReceivableCustomField1 ? [ @@ -765,9 +715,8 @@ async function InsertInvoiceMultiPayerInvoice( ] : []) ], - ...(bodyshop.accountingconfig && - bodyshop.accountingconfig.qbo && - bodyshop.accountingconfig.qbo_usa && + ...(bodyshop.accountingconfig?.qbo && + bodyshop.accountingconfig?.qbo_usa && bodyshop.region_config.includes("CA_") && { TxnTaxDetail: { TxnTaxCodeRef: {