Merged in release/2021-08-20 (pull request #181)
release/2021-08-20 Approved-by: Patrick Fic
This commit is contained in:
@@ -6,6 +6,7 @@ const Dinero = require("dinero.js");
|
||||
var builder = require("xmlbuilder2");
|
||||
const QbXmlUtils = require("./qbxml-utils");
|
||||
const moment = require("moment");
|
||||
const logger = require("../../utils/logger");
|
||||
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
@@ -45,7 +46,13 @@ exports.default = async (req, res) => {
|
||||
|
||||
res.status(200).json(QbXmlToExecute);
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
logger.log(
|
||||
"qbxml-payable-error",
|
||||
"error",
|
||||
req.body.user,
|
||||
req.body.billsToQuery,
|
||||
error
|
||||
);
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
};
|
||||
@@ -89,7 +96,6 @@ const generateBill = (bill) => {
|
||||
.end({ pretty: true });
|
||||
|
||||
const billQbxml_Full = QbXmlUtils.addQbxmlHeader(billQbxml_partial);
|
||||
console.log("generateBill -> billQbxml_Full", billQbxml_Full);
|
||||
|
||||
return billQbxml_Full;
|
||||
};
|
||||
@@ -131,7 +137,6 @@ const findTaxCode = (billLine, taxcode) => {
|
||||
!!t.federal === !!federal
|
||||
);
|
||||
if (t.length === 1) {
|
||||
console.log(t);
|
||||
return t[0].code;
|
||||
} else if (t.length > 1) {
|
||||
return "Multiple Tax Codes Match";
|
||||
|
||||
@@ -7,6 +7,8 @@ var builder = require("xmlbuilder2");
|
||||
const moment = require("moment");
|
||||
const QbXmlUtils = require("./qbxml-utils");
|
||||
const QbxmlReceivables = require("./qbxml-receivables");
|
||||
const logger = require("../../utils/logger");
|
||||
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
process.cwd(),
|
||||
@@ -80,13 +82,18 @@ exports.default = async (req, res) => {
|
||||
|
||||
res.status(200).json(QbXmlToExecute);
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
logger.log(
|
||||
"qbxml-payments-error",
|
||||
"error",
|
||||
req.body.user,
|
||||
req.body.paymentsToQuery,
|
||||
error
|
||||
);
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
};
|
||||
|
||||
const generatePayment = (payment, isThreeTier, twoTierPref) => {
|
||||
console.log("generatePayment -> payment", payment);
|
||||
let paymentQbxmlObj;
|
||||
if (payment.amount > 0) {
|
||||
paymentQbxmlObj = {
|
||||
@@ -194,7 +201,6 @@ const generatePayment = (payment, isThreeTier, twoTierPref) => {
|
||||
.end({ pretty: true });
|
||||
|
||||
const paymentQbxmlFull = QbXmlUtils.addQbxmlHeader(paymentQbxmlPartial);
|
||||
console.log("generateBill -> paymentQbxmlFull", paymentQbxmlFull);
|
||||
|
||||
return paymentQbxmlFull;
|
||||
};
|
||||
|
||||
@@ -6,6 +6,8 @@ const Dinero = require("dinero.js");
|
||||
const moment = require("moment");
|
||||
var builder = require("xmlbuilder2");
|
||||
const QbXmlUtils = require("./qbxml-utils");
|
||||
const logger = require("../../utils/logger");
|
||||
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
process.cwd(),
|
||||
@@ -93,7 +95,13 @@ exports.default = async (req, res) => {
|
||||
|
||||
res.status(200).json(QbXmlToExecute);
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
logger.log(
|
||||
"qbxml-payments-error",
|
||||
"error",
|
||||
req.body.user,
|
||||
req.body.jobIds,
|
||||
error
|
||||
);
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
};
|
||||
@@ -220,7 +228,7 @@ const generateInvoiceQbxml = (
|
||||
}).multiply(jobline.part_qty || 1);
|
||||
|
||||
if (jobline.prt_dsmk_p && jobline.prt_dsmk_p !== 0) {
|
||||
console.log("Have a part discount", jobline);
|
||||
// console.log("Have a part discount", jobline);
|
||||
DineroAmount = DineroAmount.add(
|
||||
DineroAmount.percentage(jobline.prt_dsmk_p || 0)
|
||||
);
|
||||
@@ -230,6 +238,13 @@ const generateInvoiceQbxml = (
|
||||
);
|
||||
|
||||
if (!account) {
|
||||
logger.log(
|
||||
"qbxml-receivables-no-account",
|
||||
"warn",
|
||||
null,
|
||||
jobline.id,
|
||||
null
|
||||
);
|
||||
throw new Error(
|
||||
`A matching account does not exist for the part allocation. Center: ${jobline.profitcenter_part}`
|
||||
);
|
||||
@@ -309,7 +324,7 @@ const generateInvoiceQbxml = (
|
||||
},
|
||||
});
|
||||
} else {
|
||||
console.log("NO MAPA ACCOUNT FOUND!!");
|
||||
//console.log("NO MAPA ACCOUNT FOUND!!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
167
server/cdk/cdk-calculate-allocations.js
Normal file
167
server/cdk/cdk-calculate-allocations.js
Normal file
@@ -0,0 +1,167 @@
|
||||
const path = require("path");
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
process.cwd(),
|
||||
`.env.${process.env.NODE_ENV || "development"}`
|
||||
),
|
||||
});
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
|
||||
const queries = require("../graphql-client/queries");
|
||||
const CdkBase = require("../web-sockets/web-socket");
|
||||
|
||||
const Dinero = require("dinero.js");
|
||||
const _ = require("lodash");
|
||||
|
||||
exports.default = async function (socket, jobid) {
|
||||
try {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Received request to calculate allocations for ${jobid}`
|
||||
);
|
||||
const job = await QueryJobData(socket, jobid);
|
||||
const { bodyshop } = job;
|
||||
|
||||
const taxAllocations = {
|
||||
local: {
|
||||
center: bodyshop.md_responsibility_centers.taxes.local.name,
|
||||
sale: Dinero(job.job_totals.totals.local_tax),
|
||||
cost: Dinero(),
|
||||
profitCenter: bodyshop.md_responsibility_centers.taxes.local,
|
||||
costCenter: bodyshop.md_responsibility_centers.taxes.local,
|
||||
},
|
||||
state: {
|
||||
center: bodyshop.md_responsibility_centers.taxes.state.name,
|
||||
sale: Dinero(job.job_totals.totals.state_tax),
|
||||
cost: Dinero(),
|
||||
profitCenter: bodyshop.md_responsibility_centers.taxes.state,
|
||||
costCenter: bodyshop.md_responsibility_centers.taxes.state,
|
||||
},
|
||||
federal: {
|
||||
center: bodyshop.md_responsibility_centers.taxes.federal.name,
|
||||
sale: Dinero(job.job_totals.totals.federal_tax),
|
||||
cost: Dinero(),
|
||||
profitCenter: bodyshop.md_responsibility_centers.taxes.federal,
|
||||
costCenter: bodyshop.md_responsibility_centers.taxes.federal,
|
||||
},
|
||||
};
|
||||
|
||||
const profitCenterHash = job.joblines.reduce((acc, val) => {
|
||||
//Check the Parts Assignment
|
||||
if (val.profitcenter_part) {
|
||||
if (!acc[val.profitcenter_part]) acc[val.profitcenter_part] = Dinero();
|
||||
|
||||
acc[val.profitcenter_part] = acc[val.profitcenter_part].add(
|
||||
Dinero({
|
||||
amount: Math.round((val.act_price || 0) * 100),
|
||||
}).multiply(val.part_qty || 0)
|
||||
);
|
||||
}
|
||||
if (val.profitcenter_labor) {
|
||||
//Check the Labor Assignment.
|
||||
|
||||
if (!acc[val.profitcenter_labor])
|
||||
acc[val.profitcenter_labor] = Dinero();
|
||||
|
||||
acc[val.profitcenter_labor] = acc[val.profitcenter_labor].add(
|
||||
Dinero({
|
||||
amount: Math.round(
|
||||
job[`rate_${val.mod_lbr_ty.toLowerCase()}`] * 100
|
||||
),
|
||||
}).multiply(val.mod_lb_hrs)
|
||||
);
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const costCenterHash = job.bills.reduce((bill_acc, bill_val) => {
|
||||
bill_val.billlines.map((line_val) => {
|
||||
if (!bill_acc[line_val.cost_center])
|
||||
bill_acc[line_val.cost_center] = Dinero();
|
||||
const lineDinero = Dinero({
|
||||
amount: Math.round((line_val.actual_cost || 0) * 100),
|
||||
})
|
||||
.multiply(line_val.quantity)
|
||||
.multiply(bill_val.is_credit_memo ? -1 : 1);
|
||||
|
||||
bill_acc[line_val.cost_center] =
|
||||
bill_acc[line_val.cost_center].add(lineDinero);
|
||||
|
||||
//Add appropriate tax amounts.
|
||||
const {
|
||||
applicable_taxes: { local, state, federal },
|
||||
} = line_val;
|
||||
if (local) {
|
||||
taxAllocations.local.cost = taxAllocations.local.cost.add(
|
||||
lineDinero.percentage(bill_val.local_tax_rate || 0)
|
||||
);
|
||||
}
|
||||
if (state) {
|
||||
taxAllocations.state.cost = taxAllocations.state.cost.add(
|
||||
lineDinero.percentage(bill_val.state_tax_rate || 0)
|
||||
);
|
||||
}
|
||||
if (federal) {
|
||||
taxAllocations.federal.cost = taxAllocations.federal.cost.add(
|
||||
lineDinero.percentage(bill_val.federal_tax_rate || 0)
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
return bill_acc;
|
||||
}, {});
|
||||
|
||||
const jobAllocations = _.union(
|
||||
Object.keys(profitCenterHash),
|
||||
Object.keys(costCenterHash)
|
||||
).map((key) => {
|
||||
const profitCenter = bodyshop.md_responsibility_centers.profits.find(
|
||||
(c) => c.name === key
|
||||
);
|
||||
const costCenter = bodyshop.md_responsibility_centers.costs.find(
|
||||
(c) => c.name === key
|
||||
);
|
||||
|
||||
return {
|
||||
center: key,
|
||||
sale: profitCenterHash[key] ? profitCenterHash[key] : Dinero(),
|
||||
cost: costCenterHash[key] ? costCenterHash[key] : Dinero(),
|
||||
profitCenter,
|
||||
costCenter,
|
||||
};
|
||||
});
|
||||
|
||||
return [
|
||||
...jobAllocations,
|
||||
...Object.keys(taxAllocations)
|
||||
.filter(
|
||||
(key) =>
|
||||
taxAllocations[key].sale.getAmount() > 0 ||
|
||||
taxAllocations[key].cost.getAmount() > 0
|
||||
)
|
||||
.map((key) => taxAllocations[key]),
|
||||
];
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error encountered in CdkCalculateAllocations. ${error}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
async function QueryJobData(socket, jobid) {
|
||||
CdkBase.createLogEvent(socket, "DEBUG", `Querying job data for id ${jobid}`);
|
||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
|
||||
const result = await client
|
||||
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
||||
.request(queries.GET_CDK_ALLOCATIONS, { id: jobid });
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`Job data query result ${JSON.stringify(result, null, 2)}`
|
||||
);
|
||||
return result.jobs_by_pk;
|
||||
}
|
||||
78
server/cdk/cdk-get-makes.js
Normal file
78
server/cdk/cdk-get-makes.js
Normal file
@@ -0,0 +1,78 @@
|
||||
const path = require("path");
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
process.cwd(),
|
||||
`.env.${process.env.NODE_ENV || "development"}`
|
||||
),
|
||||
});
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
const soap = require("soap");
|
||||
const queries = require("../graphql-client/queries");
|
||||
const CdkBase = require("../web-sockets/web-socket");
|
||||
const CdkWsdl = require("./cdk-wsdl").default;
|
||||
const logger = require("../utils/logger");
|
||||
const Dinero = require("dinero.js");
|
||||
const _ = require("lodash");
|
||||
const { CDK_CREDENTIALS, CheckCdkResponseForError } = require("./cdk-wsdl");
|
||||
const { performance } = require("perf_hooks");
|
||||
|
||||
exports.default = async function (socket, cdk_dealerid) {
|
||||
try {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Getting makes and models list from CDK.`
|
||||
);
|
||||
return await GetCdkMakes(socket, cdk_dealerid);
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error encountered in CdkGetMakes. ${error}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
async function GetCdkMakes(socket, cdk_dealerid) {
|
||||
CdkBase.createLogEvent(socket, "TRACE", `{1} Begin GetCDkMakes WSDL Call`);
|
||||
|
||||
try {
|
||||
const soapClientVehicleInsert = await soap.createClientAsync(
|
||||
CdkWsdl.VehicleInsert
|
||||
);
|
||||
const start = performance.now();
|
||||
|
||||
const soapResponseVehicleSearch =
|
||||
await soapClientVehicleInsert.getMakeModelAsync(
|
||||
{
|
||||
arg0: CDK_CREDENTIALS,
|
||||
arg1: { id: cdk_dealerid },
|
||||
},
|
||||
|
||||
{}
|
||||
);
|
||||
CheckCdkResponseForError(socket, soapResponseVehicleSearch);
|
||||
const [
|
||||
result, //rawResponse, soapheader, rawRequest
|
||||
] = soapResponseVehicleSearch;
|
||||
const end = performance.now();
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`soapClientVehicleInsert.getMakeModelAsync Result Length ${
|
||||
result.return.length
|
||||
} and took ${end - start}ms`
|
||||
);
|
||||
|
||||
return result.return.map((element, index) => {
|
||||
return { id: index, ...element };
|
||||
});
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in GetCdkMakes - ${JSON.stringify(error, null, 2)}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
@@ -10,40 +10,167 @@ const soap = require("soap");
|
||||
const queries = require("../graphql-client/queries");
|
||||
const CdkBase = require("../web-sockets/web-socket");
|
||||
const CdkWsdl = require("./cdk-wsdl").default;
|
||||
|
||||
const IMEX_CDK_USER = process.env.IMEX_CDK_USER,
|
||||
IMEX_CDK_PASSWORD = process.env.IMEX_CDK_PASSWORD;
|
||||
const logger = require("../utils/logger");
|
||||
const { CDK_CREDENTIALS, CheckCdkResponseForError } = require("./cdk-wsdl");
|
||||
|
||||
exports.default = async function (socket, jobid) {
|
||||
socket.logEvents = [];
|
||||
socket.recordid = jobid;
|
||||
try {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Received Job export request for id ${jobid}`
|
||||
);
|
||||
|
||||
//The following values will be stored on the socket to allow callbacks.
|
||||
//let clVFV, clADPV, clADPC;
|
||||
const JobData = await QueryJobData(socket, jobid);
|
||||
console.log(JSON.stringify(JobData, null, 2));
|
||||
const DealerId = JobData.bodyshop.cdk_dealerid;
|
||||
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`Dealer ID detected: ${JSON.stringify(DealerId)}`
|
||||
);
|
||||
|
||||
// Begin Calculate VID from DMS {1}
|
||||
await DetermineDMSVid(socket, JobData);
|
||||
//{1} Begin Calculate DMS Vehicle Id
|
||||
socket.clVFV = await CalculateDmsVid(socket, JobData);
|
||||
if (socket.clVFV.newId === "Y") {
|
||||
//{1.2} This is a new Vehicle ID
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{1.2} clVFV DMSVid does *not* exist.`
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`{1.2} clVFV: ${JSON.stringify(socket.clVFV, null, 2)}`
|
||||
);
|
||||
//Check if DMSCustId is Empty - which it should always be?
|
||||
//{6.6} Should check to see if a customer exists so that we can marry it to the new vehicle.
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{6.6} Trying to find customer ID in DMS.`
|
||||
);
|
||||
|
||||
//Array
|
||||
const strIDS = await FindCustomerIdFromDms(socket, JobData);
|
||||
if (strIDS && strIDS.length > 0) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{8.2} ${strIDS.length} Customer ID(s) found.`
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`{8.2} strIDS: ${JSON.stringify(strIDS, null, 2)}`
|
||||
);
|
||||
if (strIDS.length > 1) {
|
||||
//We have multiple IDs
|
||||
//TODO: Do we need to let the person select it?
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"WARNING",
|
||||
`{F} Mutliple customer ids have been found (${strIDS.length})`
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Asking for user intervention to select customer.`
|
||||
);
|
||||
socket.emit("cdk-select-customer", strIDS);
|
||||
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{8.5} Customer ID(s) *not* found.`
|
||||
);
|
||||
|
||||
//Create a customer number, then use that to insert the customer record.
|
||||
const newCustomerNumber = await GenerateCustomerNumberFromDms(
|
||||
socket,
|
||||
JobData
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{10.1} New Customer number generated. newCustomerNumber: ${newCustomerNumber}`
|
||||
);
|
||||
|
||||
//Use the new customer number to insert the customer record.
|
||||
socket.clADPC = await CreateCustomerInDms(
|
||||
socket,
|
||||
JobData,
|
||||
newCustomerNumber
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{11.1} New Customer inserted.`
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`{11.1} clADPC: ${JSON.stringify(socket.clADPC, null, 2)}`
|
||||
);
|
||||
}
|
||||
} else {
|
||||
CdkBase.createLogEvent(socket, "DEBUG", `{1.1} clVFV DMSVid does exist.`);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`{1.1} clVFV: ${JSON.stringify(socket.clVFV, null, 2)}`
|
||||
);
|
||||
|
||||
//{2} Begin Find Vehicle in DMS
|
||||
socket.clADPV = await FindVehicleInDms(socket, JobData, socket.clVFV); //TODO: Verify that this should always return a result. If an ID was found previously, it should be correct?
|
||||
|
||||
//{2.2} Check if the vehicle was found in the DMS.
|
||||
if (socket.clADPV.AppErrorNo === "0") {
|
||||
//Vehicle was found.
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{1.4} Vehicle was found in the DMS.`
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`{1.4} clADPV: ${JSON.stringify(socket.clADPV, null, 2)}`
|
||||
);
|
||||
} else {
|
||||
//Vehicle was not found.
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{6.4} Vehicle does not exist in DMS. Will have to create one.`
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`{6.4} clVFV: ${JSON.stringify(socket.clVFV, null, 2)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error encountered in JobExport. ${error}`
|
||||
`Error encountered in CdkJobExport. ${error}`
|
||||
);
|
||||
} finally {
|
||||
//Ensure we always insert logEvents
|
||||
//GQL to insert logevents.
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Capturing log events to database.`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -61,27 +188,267 @@ async function QueryJobData(socket, jobid) {
|
||||
return result.jobs_by_pk;
|
||||
}
|
||||
|
||||
async function DetermineDMSVid(socket, JobData) {
|
||||
CdkBase.createLogEvent(socket, "TRACE", "{1} Begin Determine DMS VehicleID");
|
||||
async function CreateCustomerInDms(socket, JobData, newCustomerNumber) {
|
||||
CdkBase.createLogEvent(socket, "DEBUG", `{11} Begin Create Customer in DMS`);
|
||||
|
||||
try {
|
||||
//Create SOAP Request for <getVehIds/>
|
||||
const soapClient = await soap.createClientAsync(CdkWsdl.VehicleSearch);
|
||||
const result = await soapClient.searchIDsByVINAsync(
|
||||
{
|
||||
arg0: { password: IMEX_CDK_PASSWORD, username: IMEX_CDK_USER },
|
||||
arg1: { id: JobData.bodyshop.cdk_dealerid },
|
||||
arg2: { VIN: JobData.v_vin },
|
||||
},
|
||||
|
||||
{}
|
||||
const soapClientCustomerInsertUpdate = await soap.createClientAsync(
|
||||
CdkWsdl.CustomerInsertUpdate
|
||||
);
|
||||
console.log(result);
|
||||
const soapResponseCustomerInsertUpdate =
|
||||
await soapClientCustomerInsertUpdate.insertAsync(
|
||||
{
|
||||
arg0: CDK_CREDENTIALS,
|
||||
arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards.
|
||||
arg2: { userId: null },
|
||||
arg3: {
|
||||
//Copied the required fields from the other integration.
|
||||
//TODO: Verify whether we need to bring more information in.
|
||||
id: { value: newCustomerNumber },
|
||||
address: {
|
||||
city: JobData.ownr_city,
|
||||
country: null,
|
||||
postalcode: JobData.ownr_zip,
|
||||
stateOrProvince: JobData.ownr_st,
|
||||
},
|
||||
contactInfo: {
|
||||
mainTelephoneNumber: { main: true, value: JobData.ownr_ph1 },
|
||||
},
|
||||
demographics: null,
|
||||
name1: {
|
||||
companyname: null,
|
||||
firstName: JobData.ownr_fn,
|
||||
fullname: null,
|
||||
lastName: JobData.ownr_ln,
|
||||
middleName: null,
|
||||
nameType: "Person",
|
||||
suffix: null,
|
||||
title: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{}
|
||||
);
|
||||
CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate);
|
||||
const [
|
||||
result, //rawResponse, soapheader, rawRequest
|
||||
] = soapResponseCustomerInsertUpdate;
|
||||
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`soapClientCustomerInsertUpdate.insertAsync Result ${JSON.stringify(
|
||||
result,
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
const customer = result && result.return;
|
||||
return customer;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in DetermineDMSVid - ${JSON.stringify(error, null, 2)}`
|
||||
`Error in CreateCustomerInDms - ${JSON.stringify(error, null, 2)}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function GenerateCustomerNumberFromDms(socket, JobData) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{10} Begin Generate Customer Number from DMS`
|
||||
);
|
||||
|
||||
try {
|
||||
const soapClientCustomerInsertUpdate = await soap.createClientAsync(
|
||||
CdkWsdl.CustomerInsertUpdate
|
||||
);
|
||||
const soapResponseCustomerInsertUpdate =
|
||||
await soapClientCustomerInsertUpdate.getCustomerNumberAsync(
|
||||
{
|
||||
arg0: CDK_CREDENTIALS,
|
||||
arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards.
|
||||
arg2: { userId: null },
|
||||
},
|
||||
|
||||
{}
|
||||
);
|
||||
CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate);
|
||||
const [
|
||||
result, //rawResponse, soapheader, rawRequest
|
||||
] = soapResponseCustomerInsertUpdate;
|
||||
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`soapClientCustomerInsertUpdate.getCustomerNumberAsync Result ${JSON.stringify(
|
||||
result,
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
const customerNumber =
|
||||
result && result.return && result.return.customerNumber;
|
||||
return customerNumber;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in GenerateCustomerNumberFromDms - ${JSON.stringify(
|
||||
error,
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function FindCustomerIdFromDms(socket, JobData) {
|
||||
const ownerName = `${JobData.ownr_ln},${JobData.ownr_fn}`;
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{8} Begin Read Customer from DMS using OWNER NAME: ${ownerName}`
|
||||
);
|
||||
|
||||
try {
|
||||
const soapClientCustomerSearch = await soap.createClientAsync(
|
||||
CdkWsdl.CustomerSearch
|
||||
);
|
||||
const soapResponseCustomerSearch =
|
||||
await soapClientCustomerSearch.executeSearchAsync(
|
||||
{
|
||||
arg0: CDK_CREDENTIALS,
|
||||
arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards.
|
||||
arg2: {
|
||||
verb: "EXACT",
|
||||
key: ownerName,
|
||||
},
|
||||
},
|
||||
|
||||
{}
|
||||
);
|
||||
CheckCdkResponseForError(socket, soapResponseCustomerSearch);
|
||||
const [
|
||||
result, // rawResponse, soapheader, rawRequest
|
||||
] = soapResponseCustomerSearch;
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`soapClientCustomerSearch.executeSearchBulkAsync Result ${JSON.stringify(
|
||||
result,
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
const CustomersFromDms = result && result.return;
|
||||
return CustomersFromDms;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in FindCustomerIdFromDms - ${JSON.stringify(error, null, 2)}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function FindVehicleInDms(socket, JobData, clVFV) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`{2}/{6} Begin Find Vehicle In DMS using clVFV: ${clVFV}`
|
||||
);
|
||||
|
||||
try {
|
||||
const soapClientVehicleInsertUpdate = await soap.createClientAsync(
|
||||
CdkWsdl.VehicleInsertUpdate
|
||||
);
|
||||
const soapResponseVehicleInsertUpdate =
|
||||
await soapClientVehicleInsertUpdate.readBulkAsync(
|
||||
{
|
||||
arg0: CDK_CREDENTIALS,
|
||||
arg1: { id: JobData.bodyshop.cdk_dealerid },
|
||||
arg2: {
|
||||
fileType: "VEHICLES",
|
||||
vehiclesVehicleId: clVFV.vehiclesVehId,
|
||||
},
|
||||
},
|
||||
|
||||
{}
|
||||
);
|
||||
CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate);
|
||||
const [
|
||||
result, //rawResponse, soapheader, rawRequest
|
||||
] = soapResponseVehicleInsertUpdate;
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`soapClientVehicleInsertUpdate.readBulkAsync Result ${JSON.stringify(
|
||||
result,
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
const VehicleFromDMS = result && result.return && result.return[0];
|
||||
return VehicleFromDMS;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in FindVehicleInDms - ${JSON.stringify(error, null, 2)}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function CalculateDmsVid(socket, JobData) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`{1} Begin Calculate DMS Vehicle ID using VIN: ${JobData.v_vin}`
|
||||
);
|
||||
|
||||
try {
|
||||
const soapClientVehicleInsertUpdate = await soap.createClientAsync(
|
||||
CdkWsdl.VehicleInsertUpdate
|
||||
);
|
||||
const soapResponseVehicleInsertUpdate =
|
||||
await soapClientVehicleInsertUpdate.getVehIdsAsync(
|
||||
{
|
||||
arg0: CDK_CREDENTIALS,
|
||||
arg1: { id: JobData.bodyshop.cdk_dealerid },
|
||||
arg2: { VIN: JobData.v_vin },
|
||||
},
|
||||
|
||||
{}
|
||||
);
|
||||
CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate);
|
||||
const [
|
||||
result, //rawResponse, soapheader, rawRequest
|
||||
] = soapResponseVehicleInsertUpdate;
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`soapClientVehicleInsertUpdate.searchIDsByVINAsync Result ${JSON.stringify(
|
||||
result,
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
const DmsVehicle = result && result.return && result.return[0];
|
||||
return DmsVehicle;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in CalculateDmsVid - ${JSON.stringify(error, null, 2)}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,99 @@
|
||||
exports.default = {
|
||||
VehicleSearch:
|
||||
"https://uat-3pa.dmotorworks.com/pip-vehicle/services/VehicleSearch?wsdl",
|
||||
const path = require("path");
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
process.cwd(),
|
||||
`.env.${process.env.NODE_ENV || "development"}`
|
||||
),
|
||||
});
|
||||
const CdkBase = require("../web-sockets/web-socket");
|
||||
|
||||
const IMEX_CDK_USER = process.env.IMEX_CDK_USER,
|
||||
IMEX_CDK_PASSWORD = process.env.IMEX_CDK_PASSWORD;
|
||||
const CDK_CREDENTIALS = {
|
||||
password: IMEX_CDK_PASSWORD,
|
||||
username: IMEX_CDK_USER,
|
||||
};
|
||||
|
||||
exports.CDK_CREDENTIALS = CDK_CREDENTIALS;
|
||||
// const cdkDomain =
|
||||
// process.env.NODE_ENV === "production"
|
||||
// ? "https://3pa.dmotorworks.com"
|
||||
// : "https://uat-3pa.dmotorworks.com";
|
||||
|
||||
function CheckCdkResponseForError(socket, soapResponse) {
|
||||
if (!soapResponse[0]) {
|
||||
//The response was null, this might be ok, it might not.
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"WARNING",
|
||||
`Warning detected in CDK Response - it appears to be null. Stack: ${
|
||||
new Error().stack
|
||||
}`
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
const ResultToCheck = soapResponse[0].return;
|
||||
|
||||
if (Array.isArray(ResultToCheck)) {
|
||||
ResultToCheck.forEach((result) => checkIndividualResult(socket, result));
|
||||
} else {
|
||||
checkIndividualResult(socket, ResultToCheck);
|
||||
}
|
||||
}
|
||||
exports.CheckCdkResponseForError = CheckCdkResponseForError;
|
||||
|
||||
function checkIndividualResult(socket, ResultToCheck) {
|
||||
if (
|
||||
ResultToCheck.errorLevel === 0 ||
|
||||
ResultToCheck.errorLevel === "0" ||
|
||||
ResultToCheck.code === "success" ||
|
||||
(!ResultToCheck.code && !ResultToCheck.errorLevel)
|
||||
)
|
||||
//TODO: Verify that this is the best way to detect errors.
|
||||
return;
|
||||
else {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error detected in CDK Response - ${JSON.stringify(
|
||||
ResultToCheck,
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
);
|
||||
|
||||
throw new Error(
|
||||
`Error found while validating CDK response for ${JSON.stringify(
|
||||
ResultToCheck,
|
||||
null,
|
||||
2
|
||||
)}:`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
exports.checkIndividualResult = checkIndividualResult;
|
||||
|
||||
const cdkDomain = "https://uat-3pa.dmotorworks.com";
|
||||
exports.default = {
|
||||
// VehicleSearch: `${cdkDomain}/pip-vehicle/services/VehicleSearch?wsdl`,
|
||||
VehicleInsertUpdate: `${cdkDomain}/pip-vehicle/services/VehicleInsertUpdate?wsdl`,
|
||||
CustomerInsertUpdate: `${cdkDomain}/pip-customer/services/CustomerInsertUpdate?wsdl`,
|
||||
CustomerSearch: `${cdkDomain}/pip-customer/services/CustomerSearch?wsdl`,
|
||||
VehicleSearch: `${cdkDomain}/pip-vehicle/services/VehicleSearch?wsdl`,
|
||||
VehicleInsert: `${cdkDomain}/pip-vehicle/services/VehicleInsertUpdate?wsdl`,
|
||||
};
|
||||
|
||||
// The following login credentials will be used for all PIPs and all environments (User Acceptance Testing and Production).
|
||||
// Only the URLs will change from https://uat-3pa.dmoto... to https://3pa.dmoto... or https://api-dit.connect... to https://api.connect...
|
||||
// Accounting GL/Accounting GL WIP Update - https://uat-3pa.dmotorworks.com/pip-accounting-gl/services/AccountingGLInsertUpdate?wsdl
|
||||
// Customer Insert Update - https://uat-3pa.dmotorworks.com/pip-customer/services/CustomerInsertUpdate?wsdl
|
||||
// Help Database Location - https://uat-3pa.dmotorworks.com/pip-help-database-location/services/HelpDatabaseLocation?wsdl
|
||||
// Parts Inventory Insert Update - https://uat-3pa.dmotorworks.com/pip-parts-inventory/services/PartsInventoryInsertUpdate?wsdl
|
||||
// Purchase Order Insert - https://uat-3pa.dmotorworks.com/pip-purchase-order/services/PurchaseOrderInsert?wsdl
|
||||
// Repair Order MLS Insert Update - https://uat-3pa.dmotorworks.com/pip-repair-order-mls/services/RepairOrderMLSInsertUpdate?wsdl
|
||||
// Repair Order Parts Insert Update - https://uat-3pa.dmotorworks.com/pip-repair-order-parts/services/RepairOrderPartsInsertUpdate?wsdl
|
||||
// Service History Insert - https://uat-3pa.dmotorworks.com/pip-service-history-insert/services/ServiceHistoryInsert?wsdl
|
||||
// Service Repair Order Update - https://uat-3pa.dmotorworks.com/pip-service-repair-order/services/ServiceRepairOrderUpdate?wsdl
|
||||
// Service Vehicle Insert Update - https://uat-3pa.dmotorworks.com/pip-vehicle/services/VehicleInsertUpdate?wsdl
|
||||
|
||||
@@ -928,3 +928,105 @@ exports.GET_AUTOHOUSE_SHOPS = `query GET_AUTOHOUSE_SHOPS {
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
exports.GET_CDK_ALLOCATIONS = `
|
||||
query QUERY_JOB_CLOSE_DETAILS($id: uuid!) {
|
||||
jobs_by_pk(id: $id) {
|
||||
bodyshop{
|
||||
id
|
||||
md_responsibility_centers
|
||||
}
|
||||
ro_number
|
||||
invoice_allocation
|
||||
ins_co_id
|
||||
id
|
||||
ded_amt
|
||||
ded_status
|
||||
depreciation_taxes
|
||||
other_amount_payable
|
||||
towing_payable
|
||||
storage_payable
|
||||
adjustment_bottom_line
|
||||
federal_tax_rate
|
||||
state_tax_rate
|
||||
local_tax_rate
|
||||
tax_tow_rt
|
||||
tax_str_rt
|
||||
tax_paint_mat_rt
|
||||
tax_sub_rt
|
||||
tax_lbr_rt
|
||||
tax_levies_rt
|
||||
parts_tax_rates
|
||||
job_totals
|
||||
rate_la1
|
||||
rate_la2
|
||||
rate_la3
|
||||
rate_la4
|
||||
rate_laa
|
||||
rate_lab
|
||||
rate_lad
|
||||
rate_lae
|
||||
rate_laf
|
||||
rate_lag
|
||||
rate_lam
|
||||
rate_lar
|
||||
rate_las
|
||||
rate_lau
|
||||
rate_ma2s
|
||||
rate_ma2t
|
||||
rate_ma3s
|
||||
rate_mabl
|
||||
rate_macs
|
||||
rate_mahw
|
||||
rate_mapa
|
||||
rate_mash
|
||||
rate_matd
|
||||
status
|
||||
date_exported
|
||||
date_invoiced
|
||||
voided
|
||||
scheduled_completion
|
||||
actual_completion
|
||||
scheduled_delivery
|
||||
actual_delivery
|
||||
scheduled_in
|
||||
actual_in
|
||||
bills {
|
||||
id
|
||||
federal_tax_rate
|
||||
local_tax_rate
|
||||
state_tax_rate
|
||||
is_credit_memo
|
||||
billlines {
|
||||
actual_cost
|
||||
cost_center
|
||||
id
|
||||
quantity
|
||||
applicable_taxes
|
||||
}
|
||||
}
|
||||
joblines(where: { removed: { _eq: false } }) {
|
||||
id
|
||||
removed
|
||||
tax_part
|
||||
line_desc
|
||||
prt_dsmk_p
|
||||
prt_dsmk_m
|
||||
part_type
|
||||
oem_partno
|
||||
db_price
|
||||
act_price
|
||||
part_qty
|
||||
mod_lbr_ty
|
||||
db_hrs
|
||||
mod_lb_hrs
|
||||
lbr_op
|
||||
lbr_amt
|
||||
op_code_desc
|
||||
profitcenter_labor
|
||||
profitcenter_part
|
||||
prt_dsmk_p
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
25
server/utils/logger.js
Normal file
25
server/utils/logger.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const graylog2 = require("graylog2");
|
||||
|
||||
const logger = new graylog2.graylog({
|
||||
servers: [{ host: "logs.bodyshop.app", port: 12201 }],
|
||||
});
|
||||
|
||||
function log(message, type, user, record, object) {
|
||||
console.log(message, {
|
||||
type,
|
||||
env: process.env.NODE_ENV,
|
||||
user,
|
||||
record,
|
||||
...object,
|
||||
});
|
||||
logger.log(message, {
|
||||
type,
|
||||
env: process.env.NODE_ENV || "development",
|
||||
user,
|
||||
record,
|
||||
...object,
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { log };
|
||||
//const logger = require("./server/utils/logger");
|
||||
@@ -1,5 +1,4 @@
|
||||
const path = require("path");
|
||||
const _ = require("lodash");
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
process.cwd(),
|
||||
@@ -10,7 +9,11 @@ require("dotenv").config({
|
||||
const { io } = require("../../server");
|
||||
const { admin } = require("../firebase/firebase-handler");
|
||||
const CdkJobExport = require("../cdk/cdk-job-export").default;
|
||||
const CdkGetMakes = require("../cdk/cdk-get-makes").default;
|
||||
const CdkCalculateAllocations =
|
||||
require("../cdk/cdk-calculate-allocations").default;
|
||||
const { isArray } = require("lodash");
|
||||
const logger = require("../utils/logger");
|
||||
|
||||
io.use(function (socket, next) {
|
||||
try {
|
||||
@@ -30,6 +33,10 @@ io.use(function (socket, next) {
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Uncaught connection error:::", error);
|
||||
logger.log("websocket-connection-error", "error", null, null, {
|
||||
token: socket.handshake.auth.token,
|
||||
...error,
|
||||
});
|
||||
next(new Error(`Authentication error ${error}`));
|
||||
}
|
||||
});
|
||||
@@ -46,6 +53,40 @@ io.on("connection", (socket) => {
|
||||
socket.on("cdk-export-job", (jobid) => {
|
||||
CdkJobExport(socket, jobid);
|
||||
});
|
||||
socket.on("cdk-selected-customer", (selectedCustomerId) => {
|
||||
createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`User selected customer ID ${selectedCustomerId}`
|
||||
);
|
||||
socket.selectedCustomerId = selectedCustomerId;
|
||||
//CdkJobExport(socket, jobid);
|
||||
});
|
||||
|
||||
socket.on("cdk-get-makes", async (cdk_dealerid, callback) => {
|
||||
try {
|
||||
const makes = await CdkGetMakes(socket, cdk_dealerid);
|
||||
callback(makes);
|
||||
} catch (error) {
|
||||
createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in cdk-get-makes WS call. ${JSON.stringify(error, null, 2)}`
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on("cdk-calculate-allocations", async (jobid, callback) => {
|
||||
const allocations = await CdkCalculateAllocations(socket, jobid);
|
||||
createLogEvent(socket, "DEBUG", `Allocations calculated.`);
|
||||
createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`Allocations calculated. ${JSON.stringify(allocations, null, 2)}`
|
||||
);
|
||||
|
||||
callback(allocations);
|
||||
});
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
createLogEvent(socket, "DEBUG", `User disconnected.`);
|
||||
@@ -55,7 +96,7 @@ io.on("connection", (socket) => {
|
||||
function createLogEvent(socket, level, message) {
|
||||
if (LogLevelHierarchy(socket.log_level) >= LogLevelHierarchy(level)) {
|
||||
console.log(
|
||||
`[CDK LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${
|
||||
`[WS LOG EVENT] ${level} - ${new Date()} - ${socket.user.email} - ${
|
||||
socket.id
|
||||
} - ${message}`
|
||||
);
|
||||
@@ -65,6 +106,10 @@ function createLogEvent(socket, level, message) {
|
||||
message,
|
||||
});
|
||||
|
||||
logger.log("ws-log-event", level, socket.user.email, socket.recordid, {
|
||||
wsmessage: message,
|
||||
});
|
||||
|
||||
if (socket.logEvents && isArray(socket.logEvents)) {
|
||||
socket.logEvents.push({
|
||||
timestamp: new Date(),
|
||||
@@ -72,6 +117,9 @@ function createLogEvent(socket, level, message) {
|
||||
message,
|
||||
});
|
||||
}
|
||||
// if (level === "ERROR") {
|
||||
// throw new Error(message);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user