Merge remote-tracking branch 'origin/feature/IO-3498-QBO-Auth-Token' into hotfix/2026-01-15

This commit is contained in:
Dave
2026-01-15 19:35:44 -05:00
3 changed files with 87 additions and 97 deletions

View File

@@ -136,9 +136,7 @@ async function QueryVendorRecord(oauthClient, qbo_realmId, req, bill) {
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From vendor where DisplayName = '${StandardizeName(bill.vendor.name)}'`
From vendor
where DisplayName = '${StandardizeName(bill.vendor.name)}'`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -150,21 +148,17 @@ async function QueryVendorRecord(oauthClient, qbo_realmId, req, bill) {
method: "POST", method: "POST",
name: "QueryVendorRecord", name: "QueryVendorRecord",
billid: bill.id, billid: bill.id,
status: result.response?.status, status: result.status,
bodyshopid: bill.job.shopid, bodyshopid: bill.job.shopid,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, result); setNewRefreshToken(req.user.email, result);
return ( return result.json?.QueryResponse?.Vendor[0];
result.json &&
result.json.QueryResponse &&
result.json.QueryResponse.Vendor &&
result.json.QueryResponse.Vendor[0]
);
} catch (error) { } catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, { logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, {
error: (error && error.authResponse && error.authResponse.body) || (error && error.message), method: "QueryVendorRecord",
method: "QueryVendorRecord" error: error.message,
stack: error.stack
}); });
throw error; throw error;
} }
@@ -188,16 +182,20 @@ async function InsertVendorRecord(oauthClient, qbo_realmId, req, bill) {
method: "POST", method: "POST",
name: "InsertVendorRecord", name: "InsertVendorRecord",
billid: bill.id, billid: bill.id,
status: result.response?.status, status: result.status,
bodyshopid: bill.job.shopid, bodyshopid: bill.job.shopid,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, result); setNewRefreshToken(req.user.email, result);
return result && result.json && result.json.Vendor; if (result.status >= 400) {
throw new Error(JSON.stringify(result.json.Fault));
}
if (result.status === 200) return result?.json;
} catch (error) { } catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, { logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, {
error: (error && error.authResponse && error.authResponse.body) || (error && error.message), method: "InsertVendorRecord",
method: "InsertVendorRecord" validationError: error.message,
stack: error.stack
}); });
throw error; throw error;
} }
@@ -274,7 +272,6 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor, bodyshop)
) )
}) })
.percentage(bill.federal_tax_rate) .percentage(bill.federal_tax_rate)
.toFormat(DineroQbFormat) .toFormat(DineroQbFormat)
}); });
} }
@@ -332,18 +329,21 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor, bodyshop)
method: "POST", method: "POST",
name: "InsertBill", name: "InsertBill",
billid: bill.id, billid: bill.id,
status: result.response?.status, status: result.status,
bodyshopid: bill.job.shopid, bodyshopid: bill.job.shopid,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, result); setNewRefreshToken(req.user.email, result);
return result && result.json && result.json.Bill; if (result.status >= 400) {
throw new Error(JSON.stringify(result.json.Fault));
}
if (result.status === 200) return result?.json;
} catch (error) { } catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, { logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, {
error: error, //(error && error.authResponse && error.authResponse.body) || (error && error.message), method: "InsertBill",
validationError: JSON.stringify(error?.response?.data), validationError: error.message,
accountmeta: JSON.stringify({ accounts, taxCodes, classes }), accountmeta: JSON.stringify({ accounts, taxCodes, classes }),
method: "InsertBill" stack: error.stack
}); });
throw error; throw error;
} }
@@ -403,9 +403,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid) {
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From Account where AccountType in ('Cost of Goods Sold', 'Other Current Liability')`
From Account
where AccountType in ('Cost of Goods Sold', 'Other Current Liability')`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -416,18 +414,13 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid) {
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "QueryAccountType", name: "QueryAccountType",
status: accounts.response?.status, status: accounts.status,
bodyshopid, bodyshopid,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, accounts); setNewRefreshToken(req.user.email, accounts);
const taxCodes = await oauthClient.makeApiCall({ const taxCodes = await oauthClient.makeApiCall({
url: urlBuilder( url: urlBuilder(qbo_realmId, "query", `select * From TaxCode`),
qbo_realmId,
"query",
`select *
From TaxCode`
),
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"
@@ -442,12 +435,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid) {
email: req.user.email email: req.user.email
}); });
const classes = await oauthClient.makeApiCall({ const classes = await oauthClient.makeApiCall({
url: urlBuilder( url: urlBuilder(qbo_realmId, "query", `select * From Class`),
qbo_realmId,
"query",
`select *
From Class`
),
method: "POST", method: "POST",
headers: { headers: {
"Content-Type": "application/json" "Content-Type": "application/json"

View File

@@ -174,7 +174,6 @@ exports.default = async (req, res) => {
res.status(200).json(ret); res.status(200).json(ret);
} catch (error) { } catch (error) {
//console.log(error);
logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, { logger.log("qbo-payment-create-error", "ERROR", req.user.email, null, {
error: error.message, error: error.message,
stack: error.stack stack: error.stack
@@ -253,16 +252,20 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef)
method: "POST", method: "POST",
name: "InsertPayment", name: "InsertPayment",
paymentid: payment.id, paymentid: payment.id,
status: result.response?.status, status: result.status,
bodyshopid: payment.job.shopid, bodyshopid: payment.job.shopid,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, result); setNewRefreshToken(req.user.email, result);
return result && result.Bill; if (result.status >= 400) {
throw new Error(JSON.stringify(result.json.Fault));
}
if (result.status === 200) return result?.json;
} catch (error) { } catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, payment.id, { logger.log("qbo-payables-error", "DEBUG", req.user.email, payment.id, {
error: error && error.message, method: "InsertPayment",
method: "InsertPayment" validationError: error.message,
stack: error.stack
}); });
throw error; throw error;
} }
@@ -273,9 +276,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From Invoice where DocNumber like '${ro_number}%'`
From Invoice
where DocNumber like '${ro_number}%'`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -286,8 +287,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "QueryInvoice", name: "QueryInvoice",
status: invoice.status,
status: invoice.response?.status,
bodyshopid, bodyshopid,
email: req.user.email email: req.user.email
}); });
@@ -295,8 +295,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From PaymentMethod`
From PaymentMethod`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -307,7 +306,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "QueryPaymentMethod", name: "QueryPaymentMethod",
status: paymentMethods.response?.status, status: paymentMethods.status,
bodyshopid, bodyshopid,
email: req.user.email email: req.user.email
}); });
@@ -351,8 +350,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From TaxCode`
From TaxCode`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -363,8 +361,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "QueryTaxCode", name: "QueryTaxCode",
status: taxCodes.status,
status: taxCodes.response?.status,
bodyshopid, bodyshopid,
email: req.user.email email: req.user.email
}); });
@@ -372,8 +369,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From Item`
From Item`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -384,7 +380,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number, isCreditM
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "QueryItems", name: "QueryItems",
status: items.response?.status, status: items.status,
bodyshopid, bodyshopid,
email: req.user.email email: req.user.email
}); });
@@ -494,18 +490,21 @@ async function InsertCreditMemo(oauthClient, qbo_realmId, req, payment, parentRe
method: "POST", method: "POST",
name: "InsertCreditMemo", name: "InsertCreditMemo",
paymentid: payment.id, paymentid: payment.id,
status: result.response?.status, status: result.status,
bodyshopid: req.user.bodyshopid, bodyshopid: req.user.bodyshopid,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, result); setNewRefreshToken(req.user.email, result);
return result && result.Bill; if (result.status >= 400) {
throw new Error(JSON.stringify(result.json.Fault));
}
if (result.status === 200) return result?.json;
} catch (error) { } catch (error) {
logger.log("qbo-payables-error", "DEBUG", req.user.email, payment.id, { logger.log("qbo-payables-error", "DEBUG", req.user.email, payment.id, {
error: error, method: "InsertCreditMemo",
validationError: JSON.stringify(error?.response?.data), validationError: error.message,
accountmeta: JSON.stringify({ items, taxCodes }), accountmeta: JSON.stringify({ items, taxCodes }),
method: "InsertCreditMemo" stack: error.stack
}); });
throw error; throw error;
} }

View File

@@ -71,7 +71,7 @@ exports.default = async (req, res) => {
if (isThreeTier || (!isThreeTier && twoTierPref === "name")) { if (isThreeTier || (!isThreeTier && twoTierPref === "name")) {
//Insert the name/owner and account for whether the source should be the ins co in 3 tier.. //Insert the name/owner and account for whether the source should be the ins co in 3 tier..
ownerCustomerTier = await QueryOwner(oauthClient, qbo_realmId, req, job, isThreeTier, insCoCustomerTier); ownerCustomerTier = await QueryOwner(oauthClient, qbo_realmId, req, job, insCoCustomerTier);
//Query for the owner itself. //Query for the owner itself.
if (!ownerCustomerTier) { if (!ownerCustomerTier) {
ownerCustomerTier = await InsertOwner(oauthClient, qbo_realmId, req, job, isThreeTier, insCoCustomerTier); ownerCustomerTier = await InsertOwner(oauthClient, qbo_realmId, req, job, isThreeTier, insCoCustomerTier);
@@ -108,7 +108,7 @@ exports.default = async (req, res) => {
//do the thing. //do the thing.
//Create the source level. //Create the source level.
let insCoCustomerTier, ownerCustomerTier, jobTier; let insCoCustomerTier, jobTier;
//Insert the insurance company tier. //Insert the insurance company tier.
//Query for top level customer, the insurance company name. //Query for top level customer, the insurance company name.
@@ -150,7 +150,7 @@ exports.default = async (req, res) => {
// //No error. Mark the job exported & insert export log. // //No error. Mark the job exported & insert export log.
if (elgen) { if (elgen) {
const result = await client await client
.setHeaders({ Authorization: BearerToken }) .setHeaders({ Authorization: BearerToken })
.request(queries.QBO_MARK_JOB_EXPORTED, { .request(queries.QBO_MARK_JOB_EXPORTED, {
jobId: job.id, jobId: job.id,
@@ -187,7 +187,7 @@ exports.default = async (req, res) => {
}); });
//Add the export log error. //Add the export log error.
if (elgen) { if (elgen) {
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_EXPORT_LOG, { await client.setHeaders({ Authorization: BearerToken }).request(queries.INSERT_EXPORT_LOG, {
logs: [ logs: [
{ {
bodyshopid: bodyshop.id, bodyshopid: bodyshop.id,
@@ -221,10 +221,7 @@ async function QueryInsuranceCo(oauthClient, qbo_realmId, req, job) {
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From Customer where DisplayName = '${StandardizeName(job.ins_co_nm.trim())}' and Active = true`
From Customer
where DisplayName = '${StandardizeName(job.ins_co_nm.trim())}'
and Active = true`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -308,16 +305,13 @@ async function InsertInsuranceCo(oauthClient, qbo_realmId, req, job, bodyshop) {
exports.InsertInsuranceCo = InsertInsuranceCo; exports.InsertInsuranceCo = InsertInsuranceCo;
async function QueryOwner(oauthClient, qbo_realmId, req, job, isThreeTier, parentTierRef) { async function QueryOwner(oauthClient, qbo_realmId, req, job, parentTierRef) {
const ownerName = generateOwnerTier(job, true, null); const ownerName = generateOwnerTier(job, true, null);
const result = await oauthClient.makeApiCall({ const result = await oauthClient.makeApiCall({
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From Customer where DisplayName = '${StandardizeName(ownerName)}' and Active = true`
From Customer
where DisplayName = '${StandardizeName(ownerName)}'
and Active = true`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -402,10 +396,7 @@ async function QueryJob(oauthClient, qbo_realmId, req, job, parentTierRef) {
url: urlBuilder( url: urlBuilder(
qbo_realmId, qbo_realmId,
"query", "query",
`select * `select * From Customer where DisplayName = '${job.ro_number}' and Active = true`
From Customer
where DisplayName = '${job.ro_number}'
and Active = true`
), ),
method: "POST", method: "POST",
headers: { headers: {
@@ -464,17 +455,21 @@ async function InsertJob(oauthClient, qbo_realmId, req, job, parentTierRef) {
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "InsertCustomer", name: "InsertCustomer",
status: result.response?.status, status: result.status,
bodyshopid: job.shopid, bodyshopid: job.shopid,
jobid: job.id, jobid: job.id,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, result); setNewRefreshToken(req.user.email, result);
return result && result.json.Customer; if (result.status >= 400) {
throw new Error(JSON.stringify(result.json.Fault));
}
if (result.status === 200) return result?.json;
} catch (error) { } catch (error) {
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, { logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
error, method: "InsertOwner",
method: "InsertOwner" validationError: error.message,
stack: error.stack
}); });
throw error; throw error;
} }
@@ -500,7 +495,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid, jobid) {
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "QueryItems", name: "QueryItems",
status: items.response?.status, status: items.status,
bodyshopid, bodyshopid,
jobid: jobid, jobid: jobid,
email: req.user.email email: req.user.email
@@ -523,7 +518,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid, jobid) {
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "QueryTaxCodes", name: "QueryTaxCodes",
status: taxCodes.response?.status, status: taxCodes.status,
bodyshopid, bodyshopid,
jobid: jobid, jobid: jobid,
email: req.user.email email: req.user.email
@@ -544,7 +539,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, bodyshopid, jobid) {
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "QueryClasses", name: "QueryClasses",
status: classes.response?.status, status: classes.status,
bodyshopid, bodyshopid,
jobid: jobid, jobid: jobid,
email: req.user.email email: req.user.email
@@ -679,19 +674,22 @@ async function InsertInvoice(oauthClient, qbo_realmId, req, job, bodyshop, paren
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "InsertInvoice", name: "InsertInvoice",
status: result.response?.status, status: result.status,
bodyshopid: job.shopid, bodyshopid: job.shopid,
jobid: job.id, jobid: job.id,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, result); setNewRefreshToken(req.user.email, result);
return result && result.json && result.json.Invoice; if (result.status >= 400) {
throw new Error(JSON.stringify(result.json.Fault));
}
if (result.status === 200) return result?.json;
} catch (error) { } catch (error) {
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, { logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
error,
method: "InsertInvoice", method: "InsertInvoice",
validationError: JSON.stringify(error?.response?.data), validationError: error.message,
accountmeta: JSON.stringify({ items, taxCodes, classes }) accountmeta: JSON.stringify({ items, taxCodes, classes }),
stack: error.stack
}); });
throw error; throw error;
} }
@@ -805,18 +803,23 @@ async function InsertInvoiceMultiPayerInvoice(
logger.LogIntegrationCall({ logger.LogIntegrationCall({
platform: "QBO", platform: "QBO",
method: "POST", method: "POST",
name: "InsertInvoice", name: "InsertInvoiceMultiPayerInvoice",
status: result.response?.status, status: result.status,
bodyshopid: job.shopid, bodyshopid: job.shopid,
jobid: job.id, jobid: job.id,
email: req.user.email email: req.user.email
}); });
setNewRefreshToken(req.user.email, result); setNewRefreshToken(req.user.email, result);
return result && result.json && result.json.Invoice; if (result.status >= 400) {
throw new Error(JSON.stringify(result.json.Fault));
}
if (result.status === 200) return result?.json;
} catch (error) { } catch (error) {
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, { logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
error, method: "InsertInvoiceMultiPayerInvoice",
method: "InsertOwner" validationError: error.message,
accountmeta: JSON.stringify({ items, taxCodes, classes }),
stack: error.stack
}); });
throw error; throw error;
} }