IO-256 Export receivables for QBO
@@ -8229,6 +8229,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>qbo</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>rbac</name>
|
<name>rbac</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
24
client/src/assets/C2QB_composite_English.svg
Normal file
|
After Width: | Height: | Size: 51 KiB |
24
client/src/assets/C2QB_transparent_English.svg
Normal file
|
After Width: | Height: | Size: 51 KiB |
4
client/src/assets/qbo/C2QB_green_btn_med_default.svg
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
5
client/src/assets/qbo/C2QB_green_btn_med_hover.svg
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
4
client/src/assets/qbo/C2QB_green_btn_short_default.svg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
5
client/src/assets/qbo/C2QB_green_btn_short_hover.svg
Normal file
|
After Width: | Height: | Size: 6.5 KiB |
4
client/src/assets/qbo/C2QB_green_btn_tall_default.svg
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
5
client/src/assets/qbo/C2QB_green_btn_tall_hover.svg
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
5
client/src/assets/qbo/C2QB_transparent_btn_med_hover.svg
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
@@ -11,6 +11,7 @@ import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-butto
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
@@ -206,6 +207,9 @@ export function AccountingReceivablesTableComponent({
|
|||||||
completedCallback={setSelectedJobs}
|
completedCallback={setSelectedJobs}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && (
|
||||||
|
<QboAuthorizeComponent />
|
||||||
|
)}
|
||||||
<Input.Search
|
<Input.Search
|
||||||
value={state.search}
|
value={state.search}
|
||||||
onChange={handleSearch}
|
onChange={handleSearch}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export function JobsCloseExportButton({
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const handleQbxml = async () => {
|
const handleQbxml = async () => {
|
||||||
|
//Check if it's a CDK setup.
|
||||||
if (bodyshop.cdk_dealerid) {
|
if (bodyshop.cdk_dealerid) {
|
||||||
history.push(`/manage/dms?jobId=${jobId}`);
|
history.push(`/manage/dms?jobId=${jobId}`);
|
||||||
return;
|
return;
|
||||||
@@ -41,48 +42,58 @@ export function JobsCloseExportButton({
|
|||||||
logImEXEvent("jobs_close_export");
|
logImEXEvent("jobs_close_export");
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
let QbXmlResponse;
|
//Check if it's a QBO Setup.
|
||||||
try {
|
|
||||||
QbXmlResponse = await axios.post(
|
|
||||||
"/accounting/qbxml/receivables",
|
|
||||||
{ jobIds: [jobId] },
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
console.log("handle -> XML", QbXmlResponse);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error getting QBXML from Server.", error);
|
|
||||||
notification["error"]({
|
|
||||||
message: t("jobs.errors.exporting", {
|
|
||||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
setLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let PartnerResponse;
|
let PartnerResponse;
|
||||||
try {
|
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||||
PartnerResponse = await axios.post(
|
PartnerResponse = await axios.post(`/qbo/receivables`, {
|
||||||
"http://localhost:1337/qb/",
|
withCredentials: true,
|
||||||
// "http://609feaeae986.ngrok.io/qb/",
|
jobIds: [jobId],
|
||||||
QbXmlResponse.data,
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error connecting to quickbooks or partner.", error);
|
|
||||||
notification["error"]({
|
|
||||||
message: t("jobs.errors.exporting-partner"),
|
|
||||||
});
|
});
|
||||||
setLoading(false);
|
} else {
|
||||||
return;
|
//Default is QBD
|
||||||
|
|
||||||
|
let QbXmlResponse;
|
||||||
|
try {
|
||||||
|
QbXmlResponse = await axios.post(
|
||||||
|
"/accounting/qbxml/receivables",
|
||||||
|
{ jobIds: [jobId] },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log("handle -> XML", QbXmlResponse);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error getting QBXML from Server.", error);
|
||||||
|
notification["error"]({
|
||||||
|
message: t("jobs.errors.exporting", {
|
||||||
|
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PartnerResponse = await axios.post(
|
||||||
|
"http://localhost:1337/qb/",
|
||||||
|
// "http://609feaeae986.ngrok.io/qb/",
|
||||||
|
QbXmlResponse.data,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error connecting to quickbooks or partner.", error);
|
||||||
|
notification["error"]({
|
||||||
|
message: t("jobs.errors.exporting-partner"),
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("PartnerResponse", PartnerResponse);
|
console.log("PartnerResponse", PartnerResponse);
|
||||||
|
|||||||
@@ -34,53 +34,61 @@ export function JobsExportAllButton({
|
|||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const handleQbxml = async () => {
|
const handleQbxml = async () => {
|
||||||
logImEXEvent("jobs_export_all");
|
logImEXEvent("jobs_export_all");
|
||||||
|
|
||||||
setLoading(true);
|
|
||||||
let QbXmlResponse;
|
|
||||||
try {
|
|
||||||
QbXmlResponse = await axios.post(
|
|
||||||
"/accounting/qbxml/receivables",
|
|
||||||
{ jobIds: jobIds },
|
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error getting QBXML from Server.", error);
|
|
||||||
notification["error"]({
|
|
||||||
message: t("jobs.errors.exporting", {
|
|
||||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
setLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let PartnerResponse;
|
let PartnerResponse;
|
||||||
try {
|
setLoading(true);
|
||||||
PartnerResponse = await axios.post(
|
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||||
"http://localhost:1337/qb/",
|
PartnerResponse = await axios.post(`/qbo/receivables`, {
|
||||||
// "http://609feaeae986.ngrok.io/qb/",
|
withCredentials: true,
|
||||||
QbXmlResponse.data,
|
jobIds: jobIds,
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
console.log("Error connecting to quickbooks or partner.", error);
|
|
||||||
notification["error"]({
|
|
||||||
message: t("jobs.errors.exporting-partner"),
|
|
||||||
});
|
});
|
||||||
setLoading(false);
|
} else {
|
||||||
return;
|
let QbXmlResponse;
|
||||||
}
|
try {
|
||||||
|
QbXmlResponse = await axios.post(
|
||||||
|
"/accounting/qbxml/receivables",
|
||||||
|
{ jobIds: jobIds },
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error getting QBXML from Server.", error);
|
||||||
|
notification["error"]({
|
||||||
|
message: t("jobs.errors.exporting", {
|
||||||
|
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
PartnerResponse = await axios.post(
|
||||||
|
"http://localhost:1337/qb/",
|
||||||
|
// "http://609feaeae986.ngrok.io/qb/",
|
||||||
|
QbXmlResponse.data,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Error connecting to quickbooks or partner.", error);
|
||||||
|
notification["error"]({
|
||||||
|
message: t("jobs.errors.exporting-partner"),
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
console.log("PartnerResponse", PartnerResponse);
|
console.log("PartnerResponse", PartnerResponse);
|
||||||
const groupedData = _.groupBy(PartnerResponse.data, "id");
|
const groupedData = _.groupBy(
|
||||||
|
PartnerResponse.data,
|
||||||
|
bodyshop.accountingconfig.qbo ? "jobid" : "id"
|
||||||
|
);
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
Object.keys(groupedData).map(async (key) => {
|
Object.keys(groupedData).map(async (key) => {
|
||||||
@@ -157,6 +165,7 @@ export function JobsExportAllButton({
|
|||||||
|
|
||||||
if (!!completedCallback) completedCallback([]);
|
if (!!completedCallback) completedCallback([]);
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import { Button, Space } from "antd";
|
import { Space, Tag } from "antd";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import React, { useEffect } from "react";
|
|
||||||
//import QboImg from "./qbo_signin.png";
|
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import { useLocation } from "react-router-dom";
|
import React, { useEffect } from "react";
|
||||||
import { useCookies } from "react-cookie";
|
import { useCookies } from "react-cookie";
|
||||||
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
|
import QboSignIn from "../../assets/qbo/C2QB_green_btn_med_default.svg";
|
||||||
|
import "./qbo-authorize.scss";
|
||||||
|
|
||||||
export default function QboAuthorizeComponent() {
|
export default function QboAuthorizeComponent() {
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
|
const history = useHistory();
|
||||||
const [, setCookie] = useCookies(["access_token", "refresh_token"]);
|
const [cookies, setCookie] = useCookies(["access_token", "refresh_token"]);
|
||||||
|
|
||||||
const handleQbSignIn = async () => {
|
const handleQbSignIn = async () => {
|
||||||
const result = await Axios.post("/qbo/authorize");
|
const result = await Axios.post("/qbo/authorize");
|
||||||
console.log("pushing to history", result.data);
|
|
||||||
window.location.href = result.data;
|
window.location.href = result.data;
|
||||||
};
|
};
|
||||||
const qs = queryString.parse(location.search);
|
const qs = queryString.parse(location.search);
|
||||||
@@ -35,42 +35,24 @@ export default function QboAuthorizeComponent() {
|
|||||||
path: "/",
|
path: "/",
|
||||||
expires,
|
expires,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
history.push({ pathname: `/manage/accounting/receivables` });
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [qs, location, setCookie]);
|
}, [qs, location, setCookie]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<Space>
|
||||||
<Space wrap>
|
<img
|
||||||
<Button onClick={handleQbSignIn}>
|
onClick={handleQbSignIn}
|
||||||
{/* <img
|
alt="Sign In to QuickBooks Online"
|
||||||
src={QboImg}
|
src={QboSignIn}
|
||||||
alt="Sign in with Intuit"
|
style={{ cursor: "pointer" }}
|
||||||
onClick={handleQbSignIn}
|
/>
|
||||||
/> */}
|
{!cookies.qbo_realmId && (
|
||||||
auth
|
<Tag color="red">No QuickBooks company has been connected.</Tag>
|
||||||
</Button>
|
)}
|
||||||
<Button
|
|
||||||
onClick={async () => {
|
|
||||||
const response = await Axios.get(`/qbo/refresh`, {
|
|
||||||
withCredentials: true,
|
|
||||||
});
|
|
||||||
console.log(response);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Refresh Token
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
onClick={async () => {
|
|
||||||
const response = await Axios.post(`/qbo/receivables`, {
|
|
||||||
withCredentials: true,
|
|
||||||
});
|
|
||||||
console.log(response);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
REC
|
|
||||||
</Button>
|
|
||||||
</Space>
|
|
||||||
{error && JSON.parse(decodeURIComponent(error)).error_description}
|
{error && JSON.parse(decodeURIComponent(error)).error_description}
|
||||||
</div>
|
</Space>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
8
client/src/components/qbo-authorize/qbo-authorize.scss
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
.qbo-sign-in {
|
||||||
|
background-image: url("../../assets/qbo/C2QB_green_btn_med_default.svg");
|
||||||
|
width: 274px;
|
||||||
|
height: 48px;
|
||||||
|
&:hover {
|
||||||
|
background-image: url("../../assets/qbo/C2QB_green_btn_med_hover.svg");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -121,6 +121,13 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("bodyshop.labels.accountingsetup")}>
|
<LayoutFormRow header={t("bodyshop.labels.accountingsetup")}>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.labels.qbo")}
|
||||||
|
valuePropName="checked"
|
||||||
|
name={["accountingconfig", "qbo"]}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.labels.accountingtiers")}
|
label={t("bodyshop.labels.accountingtiers")}
|
||||||
rules={[
|
rules={[
|
||||||
|
|||||||
@@ -509,6 +509,7 @@
|
|||||||
"orderstatuses": "Order Statuses",
|
"orderstatuses": "Order Statuses",
|
||||||
"partslocations": "Parts Locations",
|
"partslocations": "Parts Locations",
|
||||||
"printlater": "Print Later",
|
"printlater": "Print Later",
|
||||||
|
"qbo": "Use QuickBooks Online?",
|
||||||
"rbac": "Role Based Access Control",
|
"rbac": "Role Based Access Control",
|
||||||
"responsibilitycenters": {
|
"responsibilitycenters": {
|
||||||
"costs": "Cost Centers",
|
"costs": "Cost Centers",
|
||||||
|
|||||||
@@ -509,6 +509,7 @@
|
|||||||
"orderstatuses": "",
|
"orderstatuses": "",
|
||||||
"partslocations": "",
|
"partslocations": "",
|
||||||
"printlater": "",
|
"printlater": "",
|
||||||
|
"qbo": "",
|
||||||
"rbac": "",
|
"rbac": "",
|
||||||
"responsibilitycenters": {
|
"responsibilitycenters": {
|
||||||
"costs": "",
|
"costs": "",
|
||||||
|
|||||||
@@ -509,6 +509,7 @@
|
|||||||
"orderstatuses": "",
|
"orderstatuses": "",
|
||||||
"partslocations": "",
|
"partslocations": "",
|
||||||
"printlater": "",
|
"printlater": "",
|
||||||
|
"qbo": "",
|
||||||
"rbac": "",
|
"rbac": "",
|
||||||
"responsibilitycenters": {
|
"responsibilitycenters": {
|
||||||
"costs": "",
|
"costs": "",
|
||||||
|
|||||||
@@ -7,9 +7,6 @@ require("dotenv").config({
|
|||||||
});
|
});
|
||||||
const logger = require("../../utils/logger");
|
const logger = require("../../utils/logger");
|
||||||
const OAuthClient = require("intuit-oauth");
|
const OAuthClient = require("intuit-oauth");
|
||||||
var QuickBooks = require("node-quickbooks");
|
|
||||||
const Promise = require("bluebird");
|
|
||||||
const QuickBooksPromise = Promise.promisifyAll(QuickBooks.prototype);
|
|
||||||
const client = require("../../graphql-client/graphql-client").client;
|
const client = require("../../graphql-client/graphql-client").client;
|
||||||
const queries = require("../../graphql-client/queries");
|
const queries = require("../../graphql-client/queries");
|
||||||
const queryString = require("query-string");
|
const queryString = require("query-string");
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ require("dotenv").config({
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
const logger = require("../../utils/logger");
|
const logger = require("../../utils/logger");
|
||||||
const Dinero = require("dinero.js");
|
|
||||||
const DineroQbFormat = require("../accounting-constants").DineroQbFormat;
|
|
||||||
const apiGqlClient = require("../../graphql-client/graphql-client").client;
|
const apiGqlClient = require("../../graphql-client/graphql-client").client;
|
||||||
const queries = require("../../graphql-client/queries");
|
const queries = require("../../graphql-client/queries");
|
||||||
const {
|
const {
|
||||||
@@ -48,71 +46,87 @@ exports.default = async (req, res) => {
|
|||||||
Authorization: BearerToken,
|
Authorization: BearerToken,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
logger.log("qbo-payable-create", "DEBUG", req.user.email, jobIds);
|
logger.log("qbo-receivable-create", "DEBUG", req.user.email, jobIds);
|
||||||
const result = await client
|
const result = await client
|
||||||
.setHeaders({ Authorization: BearerToken })
|
.setHeaders({ Authorization: BearerToken })
|
||||||
.request(queries.QUERY_JOBS_FOR_RECEIVABLES_EXPORT, {
|
.request(queries.QUERY_JOBS_FOR_RECEIVABLES_EXPORT, {
|
||||||
ids: ["966dc7f9-2acd-44dc-9df5-d07c5578070a"],
|
ids: jobIds,
|
||||||
//jobIds
|
|
||||||
});
|
});
|
||||||
const { jobs, bodyshops } = result;
|
const { jobs, bodyshops } = result;
|
||||||
|
|
||||||
const job = jobs[0];
|
|
||||||
const bodyshop = bodyshops[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.
|
const ret = [];
|
||||||
|
for (const job of jobs) {
|
||||||
|
//const job = jobs[0];
|
||||||
|
try {
|
||||||
|
const isThreeTier = bodyshop.accountingconfig.tiers === 3;
|
||||||
|
const twoTierPref = bodyshop.accountingconfig.twotierpref;
|
||||||
|
|
||||||
let insCoCustomerTier, ownerCustomerTier, jobTier;
|
//Replace this with a for-each loop to check every single Job that's included in the list.
|
||||||
if (isThreeTier || twoTierPref === "source") {
|
|
||||||
//Insert the insurance company tier.
|
let insCoCustomerTier, ownerCustomerTier, jobTier;
|
||||||
//Query for top level customer, the insurance company name.
|
if (isThreeTier || twoTierPref === "source") {
|
||||||
insCoCustomerTier = await QueryInsuranceCo(oauthClient, req, job);
|
//Insert the insurance company tier.
|
||||||
if (!insCoCustomerTier) {
|
//Query for top level customer, the insurance company name.
|
||||||
//Creating the Insurance Customer.
|
insCoCustomerTier = await QueryInsuranceCo(oauthClient, req, job);
|
||||||
insCoCustomerTier = await InsertInsuranceCo(
|
if (!insCoCustomerTier) {
|
||||||
oauthClient,
|
//Creating the Insurance Customer.
|
||||||
req,
|
insCoCustomerTier = await InsertInsuranceCo(
|
||||||
job,
|
oauthClient,
|
||||||
bodyshop
|
req,
|
||||||
);
|
job,
|
||||||
|
bodyshop
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(insCoCustomerTier);
|
||||||
|
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
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log(ownerCustomerTier);
|
||||||
|
//Query for the Job or Create it.
|
||||||
|
jobTier = await QueryJob(oauthClient, req, job);
|
||||||
|
|
||||||
|
// Need to validate that the job tier is associated to the right individual?
|
||||||
|
|
||||||
|
if (!jobTier) {
|
||||||
|
jobTier = await InsertJob(
|
||||||
|
oauthClient,
|
||||||
|
req,
|
||||||
|
job,
|
||||||
|
isThreeTier,
|
||||||
|
ownerCustomerTier
|
||||||
|
);
|
||||||
|
}
|
||||||
|
console.log(jobTier);
|
||||||
|
await InsertInvoice(oauthClient, req, job, bodyshop, jobTier);
|
||||||
|
ret.push({ jobid: job.id, success: true });
|
||||||
|
} catch (error) {
|
||||||
|
ret.push({
|
||||||
|
jobid: job.id,
|
||||||
|
success: false,
|
||||||
|
errorMessage: error.message,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isThreeTier || twoTierPref === "name") {
|
res.status(200).json(ret);
|
||||||
//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.
|
|
||||||
jobTier = await QueryJob(oauthClient, req, job);
|
|
||||||
|
|
||||||
// Need to validate that the job tier is associated to the right individual?
|
|
||||||
|
|
||||||
if (!jobTier) {
|
|
||||||
jobTier = await InsertJob(
|
|
||||||
oauthClient,
|
|
||||||
req,
|
|
||||||
job,
|
|
||||||
isThreeTier,
|
|
||||||
ownerCustomerTier
|
|
||||||
);
|
|
||||||
}
|
|
||||||
await InsertInvoice(oauthClient, req, job, bodyshop, jobTier);
|
|
||||||
res.sendStatus(200);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
logger.log("qbo-payable-create-error", "ERROR", req.user.email, { error });
|
logger.log("qbo-receivable-create-error", "ERROR", req.user.email, {
|
||||||
|
error,
|
||||||
|
});
|
||||||
res.status(400).json(error);
|
res.status(400).json(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -168,7 +182,7 @@ async function InsertInsuranceCo(oauthClient, req, job, bodyshop) {
|
|||||||
body: JSON.stringify(Customer),
|
body: JSON.stringify(Customer),
|
||||||
});
|
});
|
||||||
setNewRefreshToken(req.user.email, result);
|
setNewRefreshToken(req.user.email, result);
|
||||||
return result && result.Customer;
|
return result && result.json.Customer;
|
||||||
} 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,
|
error,
|
||||||
@@ -230,7 +244,7 @@ async function InsertOwner(oauthClient, req, job, isThreeTier, parentTierRef) {
|
|||||||
body: JSON.stringify(Customer),
|
body: JSON.stringify(Customer),
|
||||||
});
|
});
|
||||||
setNewRefreshToken(req.user.email, result);
|
setNewRefreshToken(req.user.email, result);
|
||||||
return result && result.Customer;
|
return result && result.json.Customer;
|
||||||
} 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,
|
error,
|
||||||
@@ -290,7 +304,7 @@ async function InsertJob(oauthClient, req, job, isThreeTier, parentTierRef) {
|
|||||||
body: JSON.stringify(Customer),
|
body: JSON.stringify(Customer),
|
||||||
});
|
});
|
||||||
setNewRefreshToken(req.user.email, result);
|
setNewRefreshToken(req.user.email, result);
|
||||||
return result && result.Customer;
|
return result && result.json.Customer;
|
||||||
} 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,
|
error,
|
||||||
@@ -319,14 +333,6 @@ async function QueryMetaData(oauthClient, req) {
|
|||||||
|
|
||||||
const taxCodeMapping = {};
|
const taxCodeMapping = {};
|
||||||
|
|
||||||
const accounts = await oauthClient.makeApiCall({
|
|
||||||
url: urlBuilder(req.cookies.qbo_realmId, "query", `select * From Account`),
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
taxCodes.json &&
|
taxCodes.json &&
|
||||||
taxCodes.json.QueryResponse &&
|
taxCodes.json.QueryResponse &&
|
||||||
taxCodes.json.QueryResponse.TaxCode.forEach((t) => {
|
taxCodes.json.QueryResponse.TaxCode.forEach((t) => {
|
||||||
|
|||||||