IO-233 ARMS event based updates.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -113,3 +113,6 @@ firebase/.env
|
||||
!.elasticbeanstalk/*.cfg.yml
|
||||
!.elasticbeanstalk/*.global.yml
|
||||
logs/oAuthClient-log.log
|
||||
|
||||
|
||||
.node-persist/**
|
||||
@@ -1,3 +1,3 @@
|
||||
Must set the environment variables using:
|
||||
|
||||
firebase functions:config:set auth.graphql_endpoint="https://db.development.bodyshop.app/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopApp!"
|
||||
firebase functions:config:set auth.graphql_endpoint="https://db.dev.bodyshop.app/v1/graphql" auth.hasura_secret_admin_key="Dev-BodyShopApp!"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
version: 2
|
||||
endpoint: https://db.development.bodyshop.app
|
||||
endpoint: https://db.dev.bodyshop.app
|
||||
admin_secret: Dev-BodyShopApp!
|
||||
metadata_directory: metadata
|
||||
actions:
|
||||
|
||||
@@ -1,30 +1,30 @@
|
||||
- function:
|
||||
schema: public
|
||||
name: search_bills
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_cccontracts
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_dms_vehicles
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_exportlog
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_inventory
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_jobs
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_owners
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_payments
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_phonebook
|
||||
- function:
|
||||
schema: public
|
||||
- function:
|
||||
name: search_vehicles
|
||||
schema: public
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -41,6 +41,7 @@
|
||||
"moment-timezone": "^0.5.34",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-mailjet": "^5.1.0",
|
||||
"node-persist": "^3.1.0",
|
||||
"node-quickbooks": "^2.0.39",
|
||||
"nodemailer": "^6.7.7",
|
||||
"phone": "^3.1.23",
|
||||
|
||||
@@ -210,7 +210,7 @@ app.post("/qbo/payments", fb.validateFirebaseIdToken, qbo.payments);
|
||||
|
||||
var data = require("./server/data/data");
|
||||
app.post("/data/ah", data.autohouse);
|
||||
app.post("/data/arms", data.arms);
|
||||
app.post("/record-handler/arms", data.arms);
|
||||
|
||||
var taskHandler = require("./server/tasks/tasks");
|
||||
app.post("/taskHandler", taskHandler.taskHandler);
|
||||
@@ -238,6 +238,7 @@ app.get("/", async function (req, res) {
|
||||
res.status(200).send("Access Forbidden.");
|
||||
});
|
||||
|
||||
|
||||
server.listen(port, (error) => {
|
||||
if (error) throw error;
|
||||
logger.log(
|
||||
|
||||
@@ -3,7 +3,7 @@ const queries = require("../graphql-client/queries");
|
||||
const Dinero = require("dinero.js");
|
||||
const moment = require("moment-timezone");
|
||||
const fs = require("fs");
|
||||
|
||||
const storage = require("node-persist");
|
||||
const _ = require("lodash");
|
||||
const logger = require("../utils/logger");
|
||||
require("dotenv").config({
|
||||
@@ -13,6 +13,7 @@ require("dotenv").config({
|
||||
),
|
||||
});
|
||||
const soap = require("soap");
|
||||
const { sendServerEmail } = require("../email/sendemail");
|
||||
|
||||
const entegralEndpoint =
|
||||
process.env.NODE_ENV === "production"
|
||||
@@ -24,27 +25,63 @@ const uuid = require("uuid").v4;
|
||||
|
||||
const momentFormat = "yyyy-MM-DDTHH:mm:ss.SSS";
|
||||
|
||||
function pollFunc(fn, timeout, interval) {
|
||||
var startTime = new Date().getTime();
|
||||
(interval = interval || 1000), (canPoll = true);
|
||||
|
||||
(function p() {
|
||||
canPoll =
|
||||
timeout === 0 ? true : new Date().getTime() - startTime <= timeout;
|
||||
if (fn() && canPoll) {
|
||||
// ensures the function exucutes
|
||||
setTimeout(p, interval);
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
||||
pollFunc(getEntegralShopData, 0, 5 * 60 * 1000); //Set the metadata to refresh every 5 minutes.
|
||||
|
||||
async function getEntegralShopData() {
|
||||
const { bodyshops } = await client.request(queries.GET_ENTEGRAL_SHOPS);
|
||||
await storage.init({ logging: true });
|
||||
logger.log("set-entegral-shops-local-storage", "DEBUG", "API", null, null);
|
||||
await storage.setItem("entegralShops", bodyshops);
|
||||
return true; //Continue execution.
|
||||
}
|
||||
|
||||
exports.default = async (req, res) => {
|
||||
//Query for the List of Bodyshop Clients.
|
||||
logger.log("arms-start", "DEBUG", "api", null, null);
|
||||
const { bodyshops } = await client.request(queries.GET_ENTEGRAL_SHOPS);
|
||||
const job = req.body.event.data.new;
|
||||
logger.log("arms-job-update", "DEBUG", "api", job.id, null);
|
||||
|
||||
const allErrors = [];
|
||||
try {
|
||||
for (const bodyshop of bodyshops) {
|
||||
logger.log("arms-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||
shopname: bodyshop.shopname,
|
||||
});
|
||||
const erroredJobs = [];
|
||||
try {
|
||||
const { jobs } = await client.request(queries.ENTEGRAL_EXPORT, {
|
||||
bodyshopid: bodyshop.id,
|
||||
});
|
||||
const jobsToPush = [];
|
||||
let allEntegralShops = await storage.getItem("entegralShops");
|
||||
|
||||
jobs.forEach((job) => {
|
||||
if (!allEntegralShops) {
|
||||
await getEntegralShopData();
|
||||
allEntegralShops = await storage.getItem("entegralShops");
|
||||
}
|
||||
|
||||
//Is this job part of an entegral shop?
|
||||
const bodyshop = allEntegralShops.find((b) => b.id === job.shopid);
|
||||
if (!bodyshop) {
|
||||
//This job is not for entegral based shops.
|
||||
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV === "PRODUCTION") {
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
}
|
||||
//TODO: Check if an update should even be sent.
|
||||
if (false) {
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const transId = uuid(); // Can this actually be the job id?
|
||||
|
||||
let obj = {
|
||||
RqUID: transId,
|
||||
DocumentInfo: {
|
||||
@@ -71,9 +108,7 @@ exports.default = async (req, res) => {
|
||||
).format(momentFormat),
|
||||
ArrivalDateTime:
|
||||
job.actual_in &&
|
||||
moment(job.actual_in)
|
||||
.tz(bodyshop.timezone)
|
||||
.format(momentFormat),
|
||||
moment(job.actual_in).tz(bodyshop.timezone).format(momentFormat),
|
||||
ArrivalOdometerReading: job.kmin,
|
||||
TargetCompletionDateTime:
|
||||
job.scheduled_completion &&
|
||||
@@ -105,7 +140,7 @@ exports.default = async (req, res) => {
|
||||
CompanyName: job.ins_co_nm,
|
||||
IDInfo: {
|
||||
IDQualifierCode: "US",
|
||||
IDNum: 44, // ** Not sure where to get this entegral ID from?
|
||||
//IDNum: 44, // ** Not sure where to get this entegral ID from?
|
||||
},
|
||||
// Communications: [
|
||||
// {
|
||||
@@ -481,33 +516,25 @@ 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"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.rates.lab.total).toFormat("0.00"),
|
||||
},
|
||||
{
|
||||
TotalType: "LAF",
|
||||
TotalTypeDesc: "Frame Labor",
|
||||
TotalHours: job.job_totals.rates.laf.hours,
|
||||
TotalAmt: Dinero(job.job_totals.rates.laf.total).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.rates.laf.total).toFormat("0.00"),
|
||||
},
|
||||
{
|
||||
TotalType: "LAM",
|
||||
TotalTypeDesc: "Mechanical Labor",
|
||||
TotalHours: job.job_totals.rates.lam.hours,
|
||||
TotalAmt: Dinero(job.job_totals.rates.lam.total).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.rates.lam.total).toFormat("0.00"),
|
||||
},
|
||||
{
|
||||
TotalType: "LAR",
|
||||
TotalTypeDesc: "Refinish Labor",
|
||||
TotalHours: job.job_totals.rates.lar.hours,
|
||||
TotalAmt: Dinero(job.job_totals.rates.lar.total).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.rates.lar.total).toFormat("0.00"),
|
||||
},
|
||||
],
|
||||
PartsTotalsInfo: [
|
||||
@@ -579,16 +606,12 @@ exports.default = async (req, res) => {
|
||||
{
|
||||
TotalType: "MAPA",
|
||||
TotalTypeDesc: "Paint Materials",
|
||||
TotalAmt: Dinero(job.job_totals.rates.mapa.total).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.rates.mapa.total).toFormat("0.00"),
|
||||
},
|
||||
{
|
||||
TotalType: "MASH",
|
||||
TotalTypeDesc: "Shop Materials",
|
||||
TotalAmt: Dinero(job.job_totals.rates.mash.total).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.rates.mash.total).toFormat("0.00"),
|
||||
},
|
||||
// {
|
||||
// TotalType: "MAHW",
|
||||
@@ -607,9 +630,7 @@ exports.default = async (req, res) => {
|
||||
{
|
||||
TotalType: "OTTW",
|
||||
TotalTypeDesc: "Towing",
|
||||
TotalAmt: Dinero(job.job_totals.additional.towing).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.additional.towing).toFormat("0.00"),
|
||||
},
|
||||
{
|
||||
TotalType: "OTAC",
|
||||
@@ -624,17 +645,15 @@ exports.default = async (req, res) => {
|
||||
TotalType: "TOT",
|
||||
TotalSubType: "TT",
|
||||
TotalTypeDesc: "Gross Total",
|
||||
TotalAmt: Dinero(
|
||||
job.job_totals.totals.total_repairs
|
||||
).toFormat("0.00"),
|
||||
TotalAmt: Dinero(job.job_totals.totals.total_repairs).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
},
|
||||
{
|
||||
TotalType: "TOT",
|
||||
TotalSubType: "T2",
|
||||
TotalTypeDesc: "Net Total",
|
||||
TotalAmt: Dinero(job.job_totals.totals.subtotal).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.totals.subtotal).toFormat("0.00"),
|
||||
},
|
||||
{
|
||||
TotalType: "TOT",
|
||||
@@ -648,9 +667,7 @@ exports.default = async (req, res) => {
|
||||
TotalType: "TOT",
|
||||
TotalSubType: "F7",
|
||||
TotalTypeDesc: "Sales Tax",
|
||||
TotalAmt: Dinero(job.job_totals.totals.state_tax).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
TotalAmt: Dinero(job.job_totals.totals.state_tax).toFormat("0.00"),
|
||||
},
|
||||
{
|
||||
TotalType: "TOT",
|
||||
@@ -664,9 +681,9 @@ exports.default = async (req, res) => {
|
||||
TotalType: "TOT",
|
||||
TotalSubType: "D8",
|
||||
TotalTypeDesc: "Bottom Line Discount",
|
||||
TotalAmt: Dinero(
|
||||
job.job_totals.additional.adjustments
|
||||
).toFormat("0.00"),
|
||||
TotalAmt: Dinero(job.job_totals.additional.adjustments).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
},
|
||||
{
|
||||
TotalType: "TOT",
|
||||
@@ -708,9 +725,9 @@ exports.default = async (req, res) => {
|
||||
TotalType: "TOT",
|
||||
TotalSubType: "CUST",
|
||||
TotalTypeDesc: "Customer Pay",
|
||||
TotalAmt: Dinero(
|
||||
job.job_totals.totals.custPayable.total
|
||||
).toFormat("0.00"),
|
||||
TotalAmt: Dinero(job.job_totals.totals.custPayable.total).toFormat(
|
||||
"0.00"
|
||||
),
|
||||
},
|
||||
],
|
||||
// RepairTotalsType: 1,
|
||||
@@ -805,8 +822,73 @@ exports.default = async (req, res) => {
|
||||
};
|
||||
|
||||
deleteNullKeys(obj);
|
||||
jobsToPush.push(obj);
|
||||
|
||||
try {
|
||||
const entegralSoapClient = await soap.createClientAsync(
|
||||
entegralEndpoint,
|
||||
{
|
||||
ignoredNamespaces: true,
|
||||
wsdl_options: {
|
||||
// useEmptyTag: true,
|
||||
},
|
||||
wsdl_headers: {
|
||||
Authorization: `Basic ${new Buffer.from(
|
||||
`${process.env.ENTEGRAL_USER}:${process.env.ENTEGRAL_PASSWORD}`
|
||||
).toString("base64")}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
entegralSoapClient.setSecurity(
|
||||
new soap.BasicAuthSecurity(
|
||||
process.env.ENTEGRAL_USER,
|
||||
process.env.ENTEGRAL_PASSWORD
|
||||
)
|
||||
);
|
||||
|
||||
const entegralResponse =
|
||||
await entegralSoapClient.RepairOrderFolderAddRqAsync(
|
||||
obj,
|
||||
function (err, result, rawResponse, soapHeader, rawRequest) {
|
||||
fs.writeFileSync(`./logs/arms-request.xml`, rawRequest);
|
||||
fs.writeFileSync(`./logs/arms-response.xml`, rawResponse);
|
||||
|
||||
if (err) {
|
||||
sendServerEmail({
|
||||
subject: `ARMS Update Failed: ${bodyshop.shopname} - ${job.ro_number}`,
|
||||
text: `Error: ${JSON.stringify(error)}`,
|
||||
});
|
||||
}
|
||||
|
||||
res.status(200).json(err || result);
|
||||
}
|
||||
);
|
||||
|
||||
const [result, rawResponse, , rawRequest] = entegralResponse;
|
||||
} catch (error) {
|
||||
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
||||
console.log(error);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log("arms-failed-job", "ERROR", "api", job.shopid, {
|
||||
job: JSON.stringify({ id: job.id, ro_number: job.ro_number }),
|
||||
});
|
||||
}
|
||||
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
const allErrors = [];
|
||||
try {
|
||||
for (const bodyshop of bodyshops) {
|
||||
logger.log("arms-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||
shopname: bodyshop.shopname,
|
||||
});
|
||||
const erroredJobs = [];
|
||||
try {
|
||||
const { jobs } = await client.request(queries.ENTEGRAL_EXPORT, {
|
||||
bodyshopid: bodyshop.id,
|
||||
});
|
||||
const jobsToPush = [];
|
||||
|
||||
if (erroredJobs.length > 0) {
|
||||
logger.log("arms-failed-jobs", "ERROR", "api", bodyshop.id, {
|
||||
@@ -887,6 +969,7 @@ exports.default = async (req, res) => {
|
||||
};
|
||||
|
||||
function GetSupplementNumber(joblines) {
|
||||
if (!joblines) return 0;
|
||||
const max = _.max(
|
||||
joblines.map((jl) => parseInt((jl.line_ind || "0").replace(/[^\d.-]/g, "")))
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ const logger = new graylog2.graylog({
|
||||
});
|
||||
|
||||
function log(message, type, user, record, object) {
|
||||
if (type !== "ioevent" && type !== "DEBUG")
|
||||
if (type !== "ioevent")
|
||||
console.log(message, {
|
||||
type,
|
||||
env: process.env.NODE_ENV || "development",
|
||||
|
||||
@@ -2715,6 +2715,11 @@ node-mailjet@^5.1.0:
|
||||
json-bigint "^1.0.0"
|
||||
url-join "^4.0.0"
|
||||
|
||||
node-persist@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-persist/-/node-persist-3.1.0.tgz#9d4b03950bba70d37d13d3d3551840e25fd17e09"
|
||||
integrity sha512-/j+fd/u71wNgKf3V2bx4tnDm+3GvLnlCuvf2MXbJ3wern+67IAb6zN9Leu1tCWPlPNZ+v1hLSibVukkPK2HqJw==
|
||||
|
||||
node-quickbooks@^2.0.39:
|
||||
version "2.0.39"
|
||||
resolved "https://registry.yarnpkg.com/node-quickbooks/-/node-quickbooks-2.0.39.tgz#a2534d24063e8a0cea5bb80c66b0727c1c942081"
|
||||
|
||||
Reference in New Issue
Block a user