IO-256 Further work on QBO Receivables.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { Button, Space } from "antd";
|
import { Button, Space } from "antd";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import QboImg from "./qbo_signin.png";
|
//import QboImg from "./qbo_signin.png";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import { useCookies } from "react-cookie";
|
import { useCookies } from "react-cookie";
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -22,7 +22,6 @@ exports.default = async (req, res) => {
|
|||||||
scope: [OAuthClient.scopes.Accounting, OAuthClient.scopes.OpenId],
|
scope: [OAuthClient.scopes.Accounting, OAuthClient.scopes.OpenId],
|
||||||
state: req.user.email,
|
state: req.user.email,
|
||||||
}); // can be an array of multiple scopes ex : {scope:[OAuthClient.scopes.Accounting,OAuthClient.scopes.OpenId]}
|
}); // can be an array of multiple scopes ex : {scope:[OAuthClient.scopes.Accounting,OAuthClient.scopes.OpenId]}
|
||||||
// Redirect the authUri
|
|
||||||
|
|
||||||
res.send(authUri);
|
res.send(authUri);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -6,7 +6,9 @@ require("dotenv").config({
|
|||||||
`.env.${process.env.NODE_ENV || "development"}`
|
`.env.${process.env.NODE_ENV || "development"}`
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
const client = require("../../graphql-client/graphql-client").client;
|
const logger = require("../../utils/logger");
|
||||||
|
|
||||||
|
const apiGqlClient = require("../../graphql-client/graphql-client").client;
|
||||||
const queries = require("../../graphql-client/queries");
|
const queries = require("../../graphql-client/queries");
|
||||||
const {
|
const {
|
||||||
refresh: refreshOauthToken,
|
refresh: refreshOauthToken,
|
||||||
@@ -14,6 +16,8 @@ const {
|
|||||||
} = require("./qbo-callback");
|
} = require("./qbo-callback");
|
||||||
const OAuthClient = require("intuit-oauth");
|
const OAuthClient = require("intuit-oauth");
|
||||||
var QuickBooks = require("node-quickbooks");
|
var QuickBooks = require("node-quickbooks");
|
||||||
|
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||||
|
const { generateOwnerTier } = require("../qbxml/qbxml-utils");
|
||||||
|
|
||||||
const oauthClient = new OAuthClient({
|
const oauthClient = new OAuthClient({
|
||||||
clientId: process.env.QBO_CLIENT_ID,
|
clientId: process.env.QBO_CLIENT_ID,
|
||||||
@@ -25,83 +29,284 @@ const oauthClient = new OAuthClient({
|
|||||||
|
|
||||||
exports.default = async (req, res) => {
|
exports.default = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const response = await client.request(queries.GET_QBO_AUTH, {
|
//Fetch the API Access Tokens & Set them for the session.
|
||||||
|
const response = await apiGqlClient.request(queries.GET_QBO_AUTH, {
|
||||||
email: req.user.email,
|
email: req.user.email,
|
||||||
});
|
});
|
||||||
response.associations[0].qbo_auth;
|
response.associations[0].qbo_auth;
|
||||||
|
|
||||||
oauthClient.setToken(response.associations[0].qbo_auth);
|
oauthClient.setToken(response.associations[0].qbo_auth);
|
||||||
|
|
||||||
if (!oauthClient.token.isAccessTokenValid()) {
|
if (!oauthClient.token.isAccessTokenValid()) {
|
||||||
await refreshOauthToken(oauthClient, req);
|
await refreshOauthToken(oauthClient, req);
|
||||||
if (!oauthClient.token.isAccessTokenValid()) {
|
if (!oauthClient.token.isAccessTokenValid()) {
|
||||||
res.sendStatus(401);
|
res.sendStatus(401);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const BearerToken = req.headers.authorization;
|
||||||
const customerCreate = {
|
const { jobIds } = req.body;
|
||||||
FullyQualifiedName: "A Test Customer",
|
//Query Job Info
|
||||||
DisplayName: "A test Customer",
|
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||||
};
|
|
||||||
|
|
||||||
// const ret = await oauthClient.makeApiCall({
|
|
||||||
// url: urlBuilder(req.cookies.qbo_realmId, "customer"),
|
|
||||||
// method: "POST",
|
|
||||||
// headers: {
|
|
||||||
// "Content-Type": "application/json",
|
|
||||||
// },
|
|
||||||
// body: JSON.stringify(customerCreate),
|
|
||||||
// });
|
|
||||||
|
|
||||||
// const invoice = {
|
|
||||||
// Line: [
|
|
||||||
// {
|
|
||||||
// DetailType: "SalesItemLineDetail",
|
|
||||||
// Amount: 100,
|
|
||||||
// SalesItemLineDetail: {
|
|
||||||
// ItemRef: {
|
|
||||||
// name: "Services",
|
|
||||||
// value: "1",
|
|
||||||
// },
|
|
||||||
// TaxCodeRef: {
|
|
||||||
// value: "2",
|
|
||||||
// },
|
|
||||||
// Qty: 1,
|
|
||||||
// UnitPrice: 100,
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// CustomerRef: {
|
|
||||||
// name: "A test Customer",
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
|
|
||||||
// const ret2 = await oauthClient.makeApiCall({
|
|
||||||
// url: urlBuilder(req.cookies.qbo_realmId, "invoice"),
|
|
||||||
// method: "POST",
|
|
||||||
// headers: {
|
|
||||||
// "Content-Type": "application/json",
|
|
||||||
// },
|
|
||||||
// body: JSON.stringify(invoice),
|
|
||||||
// });
|
|
||||||
|
|
||||||
const ret2 = await oauthClient.makeApiCall({
|
|
||||||
url: urlBuilder(
|
|
||||||
req.cookies.qbo_realmId,
|
|
||||||
"query",
|
|
||||||
`select * From TaxCode where Active = true`
|
|
||||||
),
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
Authorization: BearerToken,
|
||||||
},
|
},
|
||||||
// body: JSON.stringify(invoice),
|
|
||||||
});
|
});
|
||||||
setNewRefreshToken(req.user.email, ret2);
|
const result = await client
|
||||||
console.log(ret2);
|
.setHeaders({ Authorization: BearerToken })
|
||||||
res.send(ret2);
|
.request(queries.QUERY_JOBS_FOR_RECEIVABLES_EXPORT, {
|
||||||
|
ids: ["966dc7f9-2acd-44dc-9df5-d07c5578070a"],
|
||||||
|
//jobIds
|
||||||
|
});
|
||||||
|
const { jobs, bodyshops } = result;
|
||||||
|
|
||||||
|
const job = jobs[0];
|
||||||
|
const bodyshop = bodyshops[0];
|
||||||
|
const isThreeTier = bodyshop.accountingconfig.tiers === 3;
|
||||||
|
const twoTierPref = bodyshop.accountingconfig.twotierpref;
|
||||||
|
|
||||||
|
//Replace this with a for-each loop to check every single Job that's included in the list.
|
||||||
|
|
||||||
|
let insCoCustomerTier, ownerCustomerTier;
|
||||||
|
if (isThreeTier || twoTierPref === "source") {
|
||||||
|
//Insert the insurance company tier.
|
||||||
|
//Query for top level customer, the insurance company name.
|
||||||
|
insCoCustomerTier = await QueryInsuranceCo(oauthClient, req, job);
|
||||||
|
if (!insCoCustomerTier) {
|
||||||
|
//Creating the Insurance Customer.
|
||||||
|
insCoCustomerTier = await InsertInsuranceCo(
|
||||||
|
oauthClient,
|
||||||
|
req,
|
||||||
|
job,
|
||||||
|
bodyshop
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isThreeTier || twoTierPref === "name") {
|
||||||
|
//Insert the name/owner and account for whether the source should be the ins co in 3 tier..
|
||||||
|
ownerCustomerTier = await QueryOwner(oauthClient, req, job);
|
||||||
|
//Query for the owner itself.
|
||||||
|
if (!ownerCustomerTier) {
|
||||||
|
ownerCustomerTier = await InsertOwner(
|
||||||
|
oauthClient,
|
||||||
|
req,
|
||||||
|
job,
|
||||||
|
isThreeTier,
|
||||||
|
insCoCustomerTier
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Query for the Job or Create it.
|
||||||
|
const jobrecord = await InsertJob(
|
||||||
|
oauthClient,
|
||||||
|
req,
|
||||||
|
job,
|
||||||
|
isThreeTier,
|
||||||
|
ownerCustomerTier
|
||||||
|
);
|
||||||
|
//Is there a job associated to the owner? If so, get the ID and move on.
|
||||||
|
|
||||||
|
//Otherwise create it.
|
||||||
|
|
||||||
|
res.sendStatus(200);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
res.status(400).json(error);
|
res.status(400).json(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
async function QueryInsuranceCo(oauthClient, req, job) {
|
||||||
|
const result = await oauthClient.makeApiCall({
|
||||||
|
url: urlBuilder(
|
||||||
|
req.cookies.qbo_realmId,
|
||||||
|
"query",
|
||||||
|
`select * From Customer where DisplayName = '${job.ins_co_nm}'`
|
||||||
|
),
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setNewRefreshToken(req.user.email, result);
|
||||||
|
return (
|
||||||
|
result.json &&
|
||||||
|
result.json.QueryResponse &&
|
||||||
|
result.json.QueryResponse.Customer &&
|
||||||
|
result.json.QueryResponse.Customer[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
async function InsertInsuranceCo(oauthClient, req, job, bodyshop) {
|
||||||
|
const insCo = bodyshop.md_ins_cos.find((i) => i.name === job.ins_co_nm);
|
||||||
|
|
||||||
|
const Customer = {
|
||||||
|
DisplayName: job.ins_co_nm,
|
||||||
|
BillAddr: {
|
||||||
|
City: job.ownr_city,
|
||||||
|
Line1: insCo.street1,
|
||||||
|
Line2: insCo.street2,
|
||||||
|
PostalCode: insCo.zip,
|
||||||
|
CountrySubDivisionCode: insCo.state,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const result = await oauthClient.makeApiCall({
|
||||||
|
url: urlBuilder(req.cookies.qbo_realmId, "customer"),
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(Customer),
|
||||||
|
});
|
||||||
|
setNewRefreshToken(req.user.email, result);
|
||||||
|
return result && result.Customer;
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
|
||||||
|
error,
|
||||||
|
method: "InsertInsuranceCo",
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function QueryOwner(oauthClient, req, job) {
|
||||||
|
const ownerName = generateOwnerTier(job, true, null);
|
||||||
|
const result = await oauthClient.makeApiCall({
|
||||||
|
url: urlBuilder(
|
||||||
|
req.cookies.qbo_realmId,
|
||||||
|
"query",
|
||||||
|
`select * From Customer where DisplayName = '${ownerName}'`
|
||||||
|
),
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
setNewRefreshToken(req.user.email, result);
|
||||||
|
return (
|
||||||
|
result.json &&
|
||||||
|
result.json.QueryResponse &&
|
||||||
|
result.json.QueryResponse.Customer &&
|
||||||
|
result.json.QueryResponse.Customer[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function InsertOwner(oauthClient, req, job, isThreeTier, parentTierRef) {
|
||||||
|
const ownerName = generateOwnerTier(job, true, null);
|
||||||
|
const Customer = {
|
||||||
|
DisplayName: ownerName,
|
||||||
|
BillAddr: {
|
||||||
|
City: job.ownr_city,
|
||||||
|
Line1: job.ownr_addr1,
|
||||||
|
Line2: job.ownr_addr2,
|
||||||
|
PostalCode: job.ownr_zip,
|
||||||
|
CountrySubDivisionCode: job.ownr_st,
|
||||||
|
},
|
||||||
|
...(isThreeTier
|
||||||
|
? {
|
||||||
|
Job: true,
|
||||||
|
ParentRef: {
|
||||||
|
value: parentTierRef.Id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const result = await oauthClient.makeApiCall({
|
||||||
|
url: urlBuilder(req.cookies.qbo_realmId, "customer"),
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(Customer),
|
||||||
|
});
|
||||||
|
setNewRefreshToken(req.user.email, result);
|
||||||
|
return result && result.Customer;
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
|
||||||
|
error,
|
||||||
|
method: "InsertOwner",
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async function InsertJob(oauthClient, req, job, isThreeTier, parentTierRef) {
|
||||||
|
const Customer = {
|
||||||
|
DisplayName: job.ro_number,
|
||||||
|
BillAddr: {
|
||||||
|
City: job.ownr_city,
|
||||||
|
Line1: job.ownr_addr1,
|
||||||
|
Line2: job.ownr_addr2,
|
||||||
|
PostalCode: job.ownr_zip,
|
||||||
|
CountrySubDivisionCode: job.ownr_st,
|
||||||
|
},
|
||||||
|
...(isThreeTier
|
||||||
|
? {
|
||||||
|
Job: true,
|
||||||
|
ParentRef: {
|
||||||
|
value: parentTierRef.Id,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
const result = await oauthClient.makeApiCall({
|
||||||
|
url: urlBuilder(req.cookies.qbo_realmId, "customer"),
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
body: JSON.stringify(Customer),
|
||||||
|
});
|
||||||
|
setNewRefreshToken(req.user.email, result);
|
||||||
|
return result && result.Customer;
|
||||||
|
} catch (error) {
|
||||||
|
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
|
||||||
|
error,
|
||||||
|
method: "InsertOwner",
|
||||||
|
});
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// const customerCreate = {
|
||||||
|
// FullyQualifiedName: "A Test Customer",
|
||||||
|
// DisplayName: "A test Customer",
|
||||||
|
// };
|
||||||
|
// const ret = await oauthClient.makeApiCall({
|
||||||
|
// url: urlBuilder(req.cookies.qbo_realmId, "customer"),
|
||||||
|
// method: "POST",
|
||||||
|
// headers: {
|
||||||
|
// "Content-Type": "application/json",
|
||||||
|
// },
|
||||||
|
// body: JSON.stringify(customerCreate),
|
||||||
|
// });
|
||||||
|
|
||||||
|
// const invoice = {
|
||||||
|
// Line: [
|
||||||
|
// {
|
||||||
|
// DetailType: "SalesItemLineDetail",
|
||||||
|
// Amount: 100,
|
||||||
|
// SalesItemLineDetail: {
|
||||||
|
// ItemRef: {
|
||||||
|
// name: "Services",
|
||||||
|
// value: "1",
|
||||||
|
// },
|
||||||
|
// TaxCodeRef: {
|
||||||
|
// value: "2",
|
||||||
|
// },
|
||||||
|
// Qty: 1,
|
||||||
|
// UnitPrice: 100,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// CustomerRef: {
|
||||||
|
// name: "A test Customer",
|
||||||
|
// },
|
||||||
|
// };
|
||||||
|
|
||||||
|
// const ret2 = await oauthClient.makeApiCall({
|
||||||
|
// url: urlBuilder(req.cookies.qbo_realmId, "invoice"),
|
||||||
|
// method: "POST",
|
||||||
|
// headers: {
|
||||||
|
// "Content-Type": "application/json",
|
||||||
|
// },
|
||||||
|
// body: JSON.stringify(invoice),
|
||||||
|
// });
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const OAuthClient = require("intuit-oauth");
|
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
require("dotenv").config({
|
require("dotenv").config({
|
||||||
path: path.resolve(
|
path: path.resolve(
|
||||||
|
|||||||
@@ -114,6 +114,7 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
|||||||
id
|
id
|
||||||
md_responsibility_centers
|
md_responsibility_centers
|
||||||
accountingconfig
|
accountingconfig
|
||||||
|
md_ins_cos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
Reference in New Issue
Block a user