From 105ecd4221e0dc2acb22b4cf7c776cc2a6bdae33 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Wed, 30 Jun 2021 13:41:00 -0700 Subject: [PATCH 1/4] IO-233 CDK --- client/src/pages/dms/dms.container.jsx | 2 +- server/cdk/cdk-job-export.js | 285 +++++++++++++++++++++++-- server/cdk/cdk-wsdl.js | 33 ++- 3 files changed, 298 insertions(+), 22 deletions(-) diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx index 342035ec5..3af437f24 100644 --- a/client/src/pages/dms/dms.container.jsx +++ b/client/src/pages/dms/dms.container.jsx @@ -105,7 +105,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { {log.level} {moment(log.timestamp).format("MM/DD/YYYY HH:MM:ss")} - {log.message} + {log.message} ))} diff --git a/server/cdk/cdk-job-export.js b/server/cdk/cdk-job-export.js index f4e7ee993..56362086e 100644 --- a/server/cdk/cdk-job-export.js +++ b/server/cdk/cdk-job-export.js @@ -13,6 +13,10 @@ const CdkWsdl = require("./cdk-wsdl").default; 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.default = async function (socket, jobid) { socket.logEvents = []; @@ -22,24 +26,94 @@ exports.default = async function (socket, jobid) { "DEBUG", `Received Job export request for id ${jobid}` ); - + socket["cdk-job-export"] = {}; + 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 + clVFV = await CalculateDmsVid(socket, JobData); + if (clVFV.newId === "Y") { + //{1.2} This is a new Vehicle ID + CdkBase.createLogEvent( + socket, + "DEBUG", + `{1.2} clVFV DMSVid does *not* exist. clVFV: ${JSON.stringify( + 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.length > 0) { + CdkBase.createLogEvent(socket, "DEBUG", `{8.2} Customer ID(s) found.`); + } else { + CdkBase.createLogEvent( + socket, + "DEBUG", + `{8.5} Customer ID(s) *not* found.` + ); + } + } else { + CdkBase.createLogEvent( + socket, + "DEBUG", + `{1.2} clVFV DMSVid does exist. clVFV: ${JSON.stringify( + clVFV, + null, + 2 + )}` + ); + + //{2} Begin Find Vehicle in DMS + clADPV = await FindVehicleInDms(socket, JobData, 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 (clADPV.AppErrorNo === "0") { + //Vehicle was found. + CdkBase.createLogEvent( + socket, + "DEBUG", + `{1.4} Vehicle was found in the DMS. clADPV: ${JSON.stringify( + 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. clVFV: ${JSON.stringify( + 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 @@ -61,27 +135,200 @@ 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 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 { - //Create SOAP Request for - 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 soapClientCustomerSearch = await soap.createClientAsync( + CdkWsdl.CustomerSearch ); - console.log(result); + const soapResponseCustomerSearch = + await soapClientCustomerSearch.executeSearchBulkAsync( + { + arg0: CDK_CREDENTIALS, + arg1: { id: JobData.bodyshop.cdk_dealerid }, + arg2: { + verb: "EXACT", + key: ownerName, + }, + }, + + {} + ); + CheckCdkResponseForError(socket, soapResponseCustomerSearch); + const [result, rawResponse, soapheader, rawRequest] = + soapResponseCustomerSearch; + //result format + // return: [ + // { + // code: 'success', + // carInvStockNo: '', + // errorLevel: '0', + // errorMessage: '', + // newId: 'Y', + // vehiclesVehId: 'HM263407' + // } + // ] + 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 DetermineDMSVid - ${JSON.stringify(error, null, 2)}` + `Error in FindCustomerIdFromDms - ${JSON.stringify(error, null, 2)}` ); } } + +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; + //result format + // return: [ + // { + // code: 'success', + // carInvStockNo: '', + // errorLevel: '0', + // errorMessage: '', + // newId: 'Y', + // vehiclesVehId: 'HM263407' + // } + // ] + 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)}` + ); + } +} + +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; + //result format + // return: [ + // { + // code: 'success', + // carInvStockNo: '', + // errorLevel: '0', + // errorMessage: '', + // newId: 'Y', + // vehiclesVehId: 'HM263407' + // } + // ] + 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)}` + ); + } +} + +function CheckCdkResponseForError(socket, soapResponse) { + const ResultToCheck = Array.isArray(soapResponse[0].return) + ? soapResponse[0].return[0] + : soapResponse[0].return; + + if (ResultToCheck.errorLevel === 0 || ResultToCheck.errorLevel === "0") + //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 { + errorLevel: ResultToCheck.errorLevel, + errorMessage: ResultToCheck.errorMessage, + }; + } +} diff --git a/server/cdk/cdk-wsdl.js b/server/cdk/cdk-wsdl.js index acf66a0b5..9364dcdc3 100644 --- a/server/cdk/cdk-wsdl.js +++ b/server/cdk/cdk-wsdl.js @@ -1,4 +1,33 @@ +const path = require("path"); +require("dotenv").config({ + path: path.resolve( + process.cwd(), + `.env.${process.env.NODE_ENV || "development"}` + ), +}); + +// const cdkDomain = +// process.env.NODE_ENV === "production" +// ? "https://3pa.dmotorworks.com" +// : "https://uat-3pa.dmotorworks.com"; + +const cdkDomain = "https://uat-3pa.dmotorworks.com"; exports.default = { - VehicleSearch: - "https://uat-3pa.dmotorworks.com/pip-vehicle/services/VehicleSearch?wsdl", + // 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`, }; + +// 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 From 4ab0947cc8b290cffc9518b645bce566762b6a75 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Wed, 30 Jun 2021 16:04:01 -0700 Subject: [PATCH 2/4] IO-233 Add customer insert actions. --- client/src/pages/dms/dms.container.jsx | 8 +- server/cdk/cdk-job-export.js | 222 +++++++++++++++++++++---- server/web-sockets/web-socket.js | 4 +- 3 files changed, 202 insertions(+), 32 deletions(-) diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx index 3af437f24..85fb8e233 100644 --- a/client/src/pages/dms/dms.container.jsx +++ b/client/src/pages/dms/dms.container.jsx @@ -55,6 +55,10 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { socket.on("connected", () => { console.log("Connected again."); }); + socket.on("reconnect", () => { + console.log("Connected again."); + setLogs([]); + }); socket.on("log-event", (payload) => { setLogs((logs) => { @@ -119,11 +123,11 @@ function LogLevelHierarchy(level) { case "TRACE": return "pink"; case "DEBUG": - return "orange"; + return "green"; case "INFO": return "blue"; case "WARNING": - return "yellow"; + return "orange"; case "ERROR": return "red"; default: diff --git a/server/cdk/cdk-job-export.js b/server/cdk/cdk-job-export.js index 56362086e..178eab6a7 100644 --- a/server/cdk/cdk-job-export.js +++ b/server/cdk/cdk-job-export.js @@ -61,20 +61,51 @@ exports.default = async function (socket, jobid) { //Array const strIDS = await FindCustomerIdFromDms(socket, JobData); - if (strIDS.length > 0) { - CdkBase.createLogEvent(socket, "DEBUG", `{8.2} Customer ID(s) found.`); + if (strIDS && strIDS.length > 0) { + CdkBase.createLogEvent( + socket, + "DEBUG", + `{8.2} Customer ID(s) found. strIDS: ${JSON.stringify( + strIDS, + null, + 2 + )}` + ); } 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. + clADPC = await CreateCustomerInDms(socket, JobData, newCustomerNumber); + CdkBase.createLogEvent( + socket, + "DEBUG", + `{11.1} New Customer inserted. customer: ${JSON.stringify( + clADPC, + null, + 2 + )}` + ); } } else { CdkBase.createLogEvent( socket, "DEBUG", - `{1.2} clVFV DMSVid does exist. clVFV: ${JSON.stringify( + `{1.1} clVFV DMSVid does exist. clVFV: ${JSON.stringify( clVFV, null, 2 @@ -135,6 +166,125 @@ async function QueryJobData(socket, jobid) { return result.jobs_by_pk; } +async function CreateCustomerInDms(socket, JobData, newCustomerNumber) { + CdkBase.createLogEvent(socket, "DEBUG", `{10} Begin Create Customer in DMS`); + + try { + const soapClientCustomerInsertUpdate = await soap.createClientAsync( + CdkWsdl.CustomerInsertUpdate + ); + 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 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( @@ -148,12 +298,12 @@ async function FindCustomerIdFromDms(socket, JobData) { CdkWsdl.CustomerSearch ); const soapResponseCustomerSearch = - await soapClientCustomerSearch.executeSearchBulkAsync( + await soapClientCustomerSearch.executeSearchAsync( { arg0: CDK_CREDENTIALS, - arg1: { id: JobData.bodyshop.cdk_dealerid }, + arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. arg2: { - verb: "EXACT", + // verb: "EXACT", key: ownerName, }, }, @@ -161,19 +311,9 @@ async function FindCustomerIdFromDms(socket, JobData) { {} ); CheckCdkResponseForError(socket, soapResponseCustomerSearch); - const [result, rawResponse, soapheader, rawRequest] = - soapResponseCustomerSearch; - //result format - // return: [ - // { - // code: 'success', - // carInvStockNo: '', - // errorLevel: '0', - // errorMessage: '', - // newId: 'Y', - // vehiclesVehId: 'HM263407' - // } - // ] + const [ + result, // rawResponse, soapheader, rawRequest + ] = soapResponseCustomerSearch; CdkBase.createLogEvent( socket, "TRACE", @@ -191,6 +331,7 @@ async function FindCustomerIdFromDms(socket, JobData) { "ERROR", `Error in FindCustomerIdFromDms - ${JSON.stringify(error, null, 2)}` ); + throw new Error(error); } } @@ -219,8 +360,9 @@ async function FindVehicleInDms(socket, JobData, clVFV) { {} ); CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); - const [result, rawResponse, soapheader, rawRequest] = - soapResponseVehicleInsertUpdate; + const [ + result, //rawResponse, soapheader, rawRequest + ] = soapResponseVehicleInsertUpdate; //result format // return: [ // { @@ -249,6 +391,7 @@ async function FindVehicleInDms(socket, JobData, clVFV) { "ERROR", `Error in FindVehicleInDms - ${JSON.stringify(error, null, 2)}` ); + throw new Error(error); } } @@ -274,8 +417,9 @@ async function CalculateDmsVid(socket, JobData) { {} ); CheckCdkResponseForError(socket, soapResponseVehicleInsertUpdate); - const [result, rawResponse, soapheader, rawRequest] = - soapResponseVehicleInsertUpdate; + const [ + result, //rawResponse, soapheader, rawRequest + ] = soapResponseVehicleInsertUpdate; //result format // return: [ // { @@ -304,15 +448,32 @@ async function CalculateDmsVid(socket, JobData) { "ERROR", `Error in CalculateDmsVid - ${JSON.stringify(error, null, 2)}` ); + throw new Error(error); } } function CheckCdkResponseForError(socket, soapResponse) { - const ResultToCheck = Array.isArray(soapResponse[0].return) + 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 = Array.isArray(soapResponse[0] && soapResponse[0].return) ? soapResponse[0].return[0] : soapResponse[0].return; - if (ResultToCheck.errorLevel === 0 || ResultToCheck.errorLevel === "0") + if ( + ResultToCheck.errorLevel === 0 || + ResultToCheck.errorLevel === "0" || + ResultToCheck.code === "success" + ) //TODO: Verify that this is the best way to detect errors. return; else { @@ -326,9 +487,12 @@ function CheckCdkResponseForError(socket, soapResponse) { )}` ); - throw { - errorLevel: ResultToCheck.errorLevel, - errorMessage: ResultToCheck.errorMessage, - }; + throw new Error( + `Error found while validating CDK response for ${JSON.stringify( + ResultToCheck, + null, + 2 + )}:` + ); } } diff --git a/server/web-sockets/web-socket.js b/server/web-sockets/web-socket.js index e3a909889..64e498a90 100644 --- a/server/web-sockets/web-socket.js +++ b/server/web-sockets/web-socket.js @@ -1,5 +1,4 @@ const path = require("path"); -const _ = require("lodash"); require("dotenv").config({ path: path.resolve( process.cwd(), @@ -72,6 +71,9 @@ function createLogEvent(socket, level, message) { message, }); } + // if (level === "ERROR") { + // throw new Error(message); + // } } } From 84b39f3d2b21f09251dddaa9e4da150cc889fcae Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Fri, 2 Jul 2021 12:53:18 -0700 Subject: [PATCH 3/4] IO-233 WIP CDK --- .../dms-customer-selector.component.jsx | 79 +++++++++++ client/src/pages/dms/dms.container.jsx | 76 +++++++---- server/cdk/cdk-job-export.js | 128 +++++++++--------- 3 files changed, 197 insertions(+), 86 deletions(-) create mode 100644 client/src/components/dms-customer-selector/dms-customer-selector.component.jsx diff --git a/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx b/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx new file mode 100644 index 000000000..e0f41dd97 --- /dev/null +++ b/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx @@ -0,0 +1,79 @@ +import React, { useEffect, useState } from "react"; +import { socket } from "../../pages/dms/dms.container"; +import { alphaSort } from "../../utils/sorters"; +import { Table } from "antd"; +import { useTranslation } from "react-i18next"; + +export default function DmsCustomerSelector() { + const { t } = useTranslation(); + const [customerList, setcustomerList] = useState([]); + const [selectedCustomer, setSelectedCustomer] = useState(null); + useEffect(() => { + socket.on("cdk-select-customer", (customerList) => { + setcustomerList(customerList); + console.log("Received a customer list.", customerList); + }); + + return () => { + socket.removeListener("cdk-select-customer"); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + const columns = [ + { + title: t("owners.fields.ownr_ln"), + dataIndex: "ownr_ln", + key: "ownr_ln", + sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), + }, + { + title: t("owners.fields.ownr_fn"), + dataIndex: "ownr_fn", + key: "ownr_fn", + sorter: (a, b) => alphaSort(a.ownr_fn, b.ownr_fn), + }, + { + title: t("owners.fields.ownr_co_nm"), + dataIndex: "ownr_co_nm", + key: "ownr_co_nm", + sorter: (a, b) => alphaSort(a.ownr_co_nm, b.ownr_co_nm), + }, + { + title: t("owners.fields.ownr_addr1"), + dataIndex: "ownr_addr1", + key: "ownr_addr1", + sorter: (a, b) => alphaSort(a.ownr_addr1, b.ownr_addr1), + }, + { + title: t("owners.fields.ownr_city"), + dataIndex: "ownr_city", + key: "ownr_city", + sorter: (a, b) => alphaSort(a.ownr_city, b.ownr_city), + }, + { + title: t("owners.fields.ownr_ea"), + dataIndex: "ownr_ea", + key: "ownr_ea", + sorter: (a, b) => alphaSort(a.ownr_ea, b.ownr_ea), + }, + ]; + + return ( + { + setSelectedCustomer(props.id); + }, + type: "radio", + selectedRowKeys: [selectedCustomer], + }} + /> + ); +} diff --git a/client/src/pages/dms/dms.container.jsx b/client/src/pages/dms/dms.container.jsx index 85fb8e233..f171daa75 100644 --- a/client/src/pages/dms/dms.container.jsx +++ b/client/src/pages/dms/dms.container.jsx @@ -1,4 +1,4 @@ -import { Result, Timeline, Space, Tag, Divider, Button } from "antd"; +import { Result, Timeline, Space, Tag, Divider, Button, Select } from "antd"; import React, { useEffect, useState } from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -11,6 +11,7 @@ import { useTranslation } from "react-i18next"; import SocketIO from "socket.io-client"; import { auth } from "../../firebase/firebase.utils"; import moment from "moment"; +import DmsCustomerSelector from "../../components/dms-customer-selector/dms-customer-selector.component"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -38,6 +39,7 @@ export const socket = SocketIO( export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { const { t } = useTranslation(); + const [logLevel, setLogLevel] = useState("DEBUG"); const [logs, setLogs] = useState([]); useEffect(() => { @@ -57,7 +59,16 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { }); socket.on("reconnect", () => { console.log("Connected again."); - setLogs([]); + setLogs((logs) => { + return [ + ...logs, + { + timestamp: new Date(), + level: "WARNING", + message: "Reconnected to CDK Export Service", + }, + ]; + }); }); socket.on("log-event", (payload) => { @@ -67,12 +78,13 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { }); socket.connect(); - socket.emit("set-log-level", "TRACE"); + socket.emit("set-log-level", logLevel); return () => { socket.removeAllListeners(); socket.disconnect(); }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, []); if (!bodyshop.cdk_dealerid) return ; @@ -81,27 +93,43 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) { return (
- - - - + + + + + + + {logs.map((log, idx) => ( diff --git a/server/cdk/cdk-job-export.js b/server/cdk/cdk-job-export.js index 178eab6a7..f09af0edc 100644 --- a/server/cdk/cdk-job-export.js +++ b/server/cdk/cdk-job-export.js @@ -44,13 +44,13 @@ exports.default = async function (socket, jobid) { CdkBase.createLogEvent( socket, "DEBUG", - `{1.2} clVFV DMSVid does *not* exist. clVFV: ${JSON.stringify( - clVFV, - null, - 2 - )}` + `{1.2} clVFV DMSVid does *not* exist.` + ); + CdkBase.createLogEvent( + socket, + "TRACE", + `{1.2} clVFV: ${JSON.stringify(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( @@ -65,12 +65,30 @@ exports.default = async function (socket, jobid) { CdkBase.createLogEvent( socket, "DEBUG", - `{8.2} Customer ID(s) found. strIDS: ${JSON.stringify( - strIDS, - null, - 2 - )}` + `{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); + + //TOOD: Need to find a way to wait and determine which customer to use. + } } else { CdkBase.createLogEvent( socket, @@ -94,22 +112,20 @@ exports.default = async function (socket, jobid) { CdkBase.createLogEvent( socket, "DEBUG", - `{11.1} New Customer inserted. customer: ${JSON.stringify( - clADPC, - null, - 2 - )}` + `{11.1} New Customer inserted.` + ); + CdkBase.createLogEvent( + socket, + "TRACE", + `{11.1} clADPC: ${JSON.stringify(clADPC, null, 2)}` ); } } else { + CdkBase.createLogEvent(socket, "DEBUG", `{1.1} clVFV DMSVid does exist.`); CdkBase.createLogEvent( socket, - "DEBUG", - `{1.1} clVFV DMSVid does exist. clVFV: ${JSON.stringify( - clVFV, - null, - 2 - )}` + "TRACE", + `{1.1} clVFV: ${JSON.stringify(clVFV, null, 2)}` ); //{2} Begin Find Vehicle in DMS @@ -121,22 +137,24 @@ exports.default = async function (socket, jobid) { CdkBase.createLogEvent( socket, "DEBUG", - `{1.4} Vehicle was found in the DMS. clADPV: ${JSON.stringify( - clADPV, - null, - 2 - )}` + `{1.4} Vehicle was found in the DMS.` + ); + CdkBase.createLogEvent( + socket, + "TRACE", + `{1.4} clADPV: ${JSON.stringify(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. clVFV: ${JSON.stringify( - clVFV, - null, - 2 - )}` + `{6.4} Vehicle does not exist in DMS. Will have to create one.` + ); + CdkBase.createLogEvent( + socket, + "TRACE", + `{6.4} clVFV: ${JSON.stringify(clVFV, null, 2)}` ); } } @@ -167,7 +185,7 @@ async function QueryJobData(socket, jobid) { } async function CreateCustomerInDms(socket, JobData, newCustomerNumber) { - CdkBase.createLogEvent(socket, "DEBUG", `{10} Begin Create Customer in DMS`); + CdkBase.createLogEvent(socket, "DEBUG", `{11} Begin Create Customer in DMS`); try { const soapClientCustomerInsertUpdate = await soap.createClientAsync( @@ -209,8 +227,9 @@ async function CreateCustomerInDms(socket, JobData, newCustomerNumber) { {} ); CheckCdkResponseForError(socket, soapResponseCustomerInsertUpdate); - const [result, rawResponse, soapheader, rawRequest] = - soapResponseCustomerInsertUpdate; + const [ + result, //rawResponse, soapheader, rawRequest + ] = soapResponseCustomerInsertUpdate; CdkBase.createLogEvent( socket, @@ -303,7 +322,7 @@ async function FindCustomerIdFromDms(socket, JobData) { arg0: CDK_CREDENTIALS, arg1: { dealerId: JobData.bodyshop.cdk_dealerid }, //TODO: Verify why this does not follow the other standards. arg2: { - // verb: "EXACT", + verb: "EXACT", key: ownerName, }, }, @@ -363,17 +382,6 @@ async function FindVehicleInDms(socket, JobData, clVFV) { const [ result, //rawResponse, soapheader, rawRequest ] = soapResponseVehicleInsertUpdate; - //result format - // return: [ - // { - // code: 'success', - // carInvStockNo: '', - // errorLevel: '0', - // errorMessage: '', - // newId: 'Y', - // vehiclesVehId: 'HM263407' - // } - // ] CdkBase.createLogEvent( socket, "TRACE", @@ -420,17 +428,6 @@ async function CalculateDmsVid(socket, JobData) { const [ result, //rawResponse, soapheader, rawRequest ] = soapResponseVehicleInsertUpdate; - //result format - // return: [ - // { - // code: 'success', - // carInvStockNo: '', - // errorLevel: '0', - // errorMessage: '', - // newId: 'Y', - // vehiclesVehId: 'HM263407' - // } - // ] CdkBase.createLogEvent( socket, "TRACE", @@ -465,14 +462,21 @@ function CheckCdkResponseForError(socket, soapResponse) { return; } - const ResultToCheck = Array.isArray(soapResponse[0] && soapResponse[0].return) - ? soapResponse[0].return[0] - : soapResponse[0].return; + const ResultToCheck = soapResponse[0].return; + if (Array.isArray(ResultToCheck)) { + ResultToCheck.forEach((result) => checkIndividualResult(socket, result)); + } else { + checkIndividualResult(socket, ResultToCheck); + } +} + +function checkIndividualResult(socket, ResultToCheck) { if ( ResultToCheck.errorLevel === 0 || ResultToCheck.errorLevel === "0" || - ResultToCheck.code === "success" + ResultToCheck.code === "success" || + (!ResultToCheck.code && !ResultToCheck.errorLevel) ) //TODO: Verify that this is the best way to detect errors. return; From f0d6c5e1b1e8bcd1caf017fcbd2b98b62ad56da6 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Tue, 6 Jul 2021 09:31:01 -0700 Subject: [PATCH 4/4] IO-233 CDK WIP --- _reference/Responsibility Center Setup.md | 6 ++ bodyshop_translations.babel | 2 +- .../dms-customer-selector.component.jsx | 90 +++++++++---------- server/cdk/cdk-job-export.js | 35 +++++--- server/web-sockets/web-socket.js | 9 ++ 5 files changed, 82 insertions(+), 60 deletions(-) create mode 100644 _reference/Responsibility Center Setup.md diff --git a/_reference/Responsibility Center Setup.md b/_reference/Responsibility Center Setup.md new file mode 100644 index 000000000..b52ef1189 --- /dev/null +++ b/_reference/Responsibility Center Setup.md @@ -0,0 +1,6 @@ +Glass Setup + +{"ap":{"name":"Accounts Payable","accountdesc":"Accounts Payable","accountitem":"Accounts Payable","accountname":"Accounts Payable","accountnumber":"20000"},"ar":{"name":"Accounts Receivable","accountdesc":"Accounts Receivable","accountitem":"Accounts Receivable","accountname":"Accounts Receivable","accountnumber":"12000"},"costs":[{"name":"Auto Glass Parts","accountdesc":"Glass","accountitem":"Auto Glass Parts","accountname":"Cost of Goods:Auto Glass Parts","accountnumber":"Glass"},{"name":"Auto Glass Labour","accountdesc":"Auto Glass Labour","accountitem":"Auto Glass Labour","accountname":"Cost of Goods:Auto Glass Labour","accountnumber":"Auto Glass Labour"},{"name":"Flat Glass Parts","accountdesc":"Flat Glass ","accountitem":"Flat Glass Parts","accountname":"Cost of Goods:Flat Glass Parts","accountnumber":"Flat Glass Parts"},{"name":"Flat Glass Labour","accountdesc":"Flat Glass ","accountitem":"Flat Glass Labour","accountname":"Cost of Goods:Flat Glass Labour","accountnumber":"Flat Glass Labour"},{"name":"Home Glass Parts","accountdesc":"Home Glass Parts","accountitem":"Home Glass Parts","accountname":"Cost of Goods:Home Glass Parts","accountnumber":"Home Glass Parts"},{"name":"Home Glass Labour","accountdesc":"Home Glass Labour","accountitem":"Home Glass Labour","accountname":"Cost of Goods:Home Glass Labour","accountnumber":"Home Glass Labour"},{"name":"Misc Parts","accountdesc":"Misc Parts","accountitem":"Misc Parts","accountname":"Cost of Goods:Misc Parts","accountnumber":"Misc Parts"}],"taxes":{"local":{"name":"n","rate":0,"accountdesc":"n","accountitem":"n","accountname":"n","accountnumber":"n"},"state":{"name":"PST","rate":7,"accountdesc":"Ministry of Finance (BC)","accountitem":"PST (BC)","accountname":"PST PAYABLE","accountnumber":"PST PAYABLE"},"federal":{"name":"GST","rate":5,"accountdesc":"Receiver General - GST","accountitem":"GST","accountname":"HST/GST PAYABLE","accountnumber":"HST/GST PAYABLE"}},"refund":{"name":"Refund","accountdesc":"ACCOUNTS RECEIVABLE","accountitem":"BODY SHOP_CUSTPAY","accountname":"ACCOUNTS RECEIVABLE","accountnumber":"ACCOUNTS RECEIVABLE"},"profits":[{"name":"Auto Glass Parts","accountdesc":"Auto Glass","accountitem":"Auto Glass Parts","accountname":"Sales:Auto Glass Parts","accountnumber":"APG"},{"name":"Auto Glass Labour","accountdesc":"Auto Glass Labour","accountitem":"Auto Glass Labour","accountname":"Sales:Auto Glass Labour","accountnumber":"APL"},{"name":"Flat Glass Parts","accountdesc":"Flat Glass","accountitem":"Flat Glass Parts","accountname":"Sales:Flat Glass Parts","accountnumber":"FGP"},{"name":"Flat Glass Labour","accountdesc":"Flat Glass Labour","accountitem":"Flat Glass Labour","accountname":"Sales:Flat Glass Labour","accountnumber":"FGL"},{"name":"Home Glass Parts","accountdesc":"Home Glass Parts","accountitem":"Home Glass Parts","accountname":"Sales:Home Glass Parts","accountnumber":"HGP"},{"name":"Home Glass Labour","accountdesc":"Home Glass Labour","accountitem":"Home Glass Labour","accountname":"Sales:Home Glass Labour","accountnumber":"HGL"},{"name":"Misc Parts","accountdesc":"Misc Parts","accountitem":"Misc Parts","accountname":"Sales:Misc Parts","accountnumber":"MP"}],"defaults":{"costs":{"ATS":"Auto Glass Labour","LAB":"Auto Glass Labour","LAD":"Auto Glass Labour","LAE":"Auto Glass Labour","LAF":"Auto Glass Labour","LAG":"Auto Glass Labour","LAM":"Auto Glass Labour","LAR":"Auto Glass Labour","LAS":"Auto Glass Labour","LAU":"Auto Glass Labour","PAA":"Auto Glass Parts","PAC":"Auto Glass Parts","PAL":"Auto Glass Parts","PAM":"Auto Glass Parts","PAN":"Auto Glass Parts","PAO":"Auto Glass Parts","PAP":"Auto Glass Parts","PAR":"Auto Glass Parts","PAS":"Auto Glass Parts","TOW":"Auto Glass Parts","MAPA":"Auto Glass Labour","MASH":"Auto Glass Labour"},"profits":{"ATS":"Auto Glass Labour","LAB":"Auto Glass Labour","LAD":"Auto Glass Labour","LAE":"Auto Glass Labour","LAF":"Auto Glass Labour","LAG":"Auto Glass Labour","LAM":"Auto Glass Labour","LAR":"Auto Glass Labour","LAS":"Auto Glass Labour","LAU":"Auto Glass Labour","PAA":"Auto Glass Parts","PAC":"Auto Glass Parts","PAL":"Auto Glass Parts","PAM":"Auto Glass Parts","PAN":"Auto Glass Parts","PAO":"Auto Glass Parts","PAP":"Auto Glass Parts","PAR":"Auto Glass Parts","PAS":"Auto Glass Parts","TOW":"Auto Glass Parts","MAPA":"Auto Glass Parts","MASH":"Auto Glass Parts"}},"sales_tax_codes":[{"code":"G","local":false,"state":false,"federal":true,"description":"GST Only"},{"code":"S","state":true,"federal":true,"description":"Standard"},{"code":"E","local":false,"state":false,"federal":false,"description":"Exempt"}]} + +Regular Dev Setup +{"ap": {"name": "AP", "accountdesc": "Pay to Others", "accountitem": "A/P", "accountname": "AP Acc#", "accountnumber": "Accounts Payable"}, "ar": {"name": "AR", "accountdesc": "1100", "accountitem": "A/R", "accountname": "ACCOUNTS RECEIVABLE", "accountnumber": "1100"}, "costs": [{"name": "Aftermarket", "accountdesc": "Aftermarket", "accountitem": "Aftermarketi", "accountname": "BODY SHOP COST:PARTS:AFTERMARKET", "accountnumber": "Aftermarket"}, {"name": "ATP", "accountdesc": "ATP", "accountitem": "BODY SHOP_ATP", "accountname": "BODY SHOP COST:ATP", "accountnumber": "ATP"}, {"name": "Body", "accountdesc": "BODY SHOP COST:LABOR", "accountitem": "BODY SHOP_LAB", "accountname": "BODY SHOP COST:LABOR:BODY", "accountnumber": "5001"}, {"name": "Detail", "accountdesc": "Detailing", "accountitem": "Detaili", "accountname": "BODY SHOP COST:LABOR:DETAIL", "accountnumber": "Detail"}, {"name": "Daignostic", "accountdesc": "Daignostic", "accountitem": "Daignostici", "accountname": "Daignostic", "accountnumber": "Daignostic"}, {"name": "Electrical", "accountdesc": "Electrical", "accountitem": "Electricali", "accountname": "Electrical", "accountnumber": "Electrical"}, {"name": "Chrome", "accountdesc": "Chrome", "accountitem": "Chromei", "accountname": "Chrome", "accountnumber": "Chrome"}, {"name": "Frame", "accountdesc": "Frame", "accountitem": "Framei", "accountname": "BODY SHOP COST:LABOR:Frame", "accountnumber": "Frame"}, {"name": "Mechanical", "accountdesc": "Mechanical", "accountitem": "Mechanicali", "accountname": "BODY SHOP COST:LABOR:MECHANICAL", "accountnumber": "Mechanical"}, {"name": "Refinish", "accountdesc": "Refinish", "accountitem": "BODY SHOP_LAR", "accountname": "BODY SHOP COST:LABOR:REFINISH", "accountnumber": "5003"}, {"name": "Structural", "accountdesc": "Structural", "accountitem": "Structurali", "accountname": "Structural", "accountnumber": "Structural"}, {"name": "Existing", "accountdesc": "Existing", "accountitem": "Existingi", "accountname": "Existing", "accountnumber": "Existing"}, {"name": "Glass", "accountdesc": "Glass", "accountitem": "Glassi", "accountname": "BODY SHOP COST:PARTS:Glass", "accountnumber": "Glass"}, {"name": "LKQ", "accountdesc": "LKQ", "accountitem": "LKQi", "accountname": "BODY SHOP COST:PARTS:LKQ", "accountnumber": "LKQ"}, {"name": "OEM", "accountdesc": "OEM", "accountitem": "OEMi", "accountname": "BODY SHOP COST:PARTS:OEM", "accountnumber": "OEM"}, {"name": "OEM Partial", "accountdesc": "Partial", "accountitem": "Partial", "accountname": "BODY SHOP COST:PARTS:OEM Partial", "accountnumber": "OEM Partial"}, {"name": "Re-cored", "accountdesc": "cored", "accountitem": "coredi", "accountname": "Re-cored", "accountnumber": "Re-cored"}, {"name": "Remanufactured", "accountdesc": "Remanufactured", "accountitem": "Remanufacturedi", "accountname": "BODY SHOP COST:PARTS:LKQ", "accountnumber": "Remanufactured"}, {"name": "Other", "accountdesc": "Other", "accountitem": "Otheri", "accountname": "Other", "accountnumber": "Other"}, {"name": "Sublet", "accountdesc": "Sublet to Other", "accountitem": "Subleti", "accountname": "BODY SHOP COST:SUBLET", "accountnumber": "Sublet"}, {"name": "Towing", "accountdesc": "Towingd", "accountitem": "Towingi", "accountname": "BODY SHOP COST:TOWING", "accountnumber": "Towing"}, {"name": "Paint Cost", "accountdesc": "Paint Material by Labor", "accountitem": "BODY SHOP_MAPA", "accountname": "BODY SHOP COST:PARTS:Materials", "accountnumber": "paint mat"}, {"name": "Shop Cost", "accountdesc": "Shop Materials by Labor", "accountitem": "BODY SHOP_MASH", "accountname": "BODY SHOP COST:PARTS:Materials", "accountnumber": "shop"}], "taxes": {"local": {"name": "n", "rate": 0, "accountdesc": "n", "accountitem": "n", "accountname": "n", "accountnumber": "n"}, "state": {"name": "PST", "rate": 7, "accountdesc": "Ministry of Finance (BC)", "accountitem": "PST On Sales", "accountname": "PST Payable", "accountnumber": "2220"}, "federal": {"name": "GST", "rate": 5, "accountdesc": "Receiver General - GST", "accountitem": "GST On Sales", "accountname": "GST DUE-NET:GST Collected", "accountnumber": "2200a"}}, "refund": {"name": "Refund", "accountdesc": "1100", "accountitem": "BODY SHOP_CUSTPAY", "accountname": "ACCOUNTS RECEIVABLE", "accountnumber": "1100"}, "profits": [{"name": "Aftermarket", "accountdesc": "Aftermarket", "accountitem": "BODY SHOP_PAA", "accountname": "Aftermarket", "accountnumber": "Aftermarket"}, {"name": "ATP", "accountdesc": "ATP", "accountitem": "BODY SHOP_ATP", "accountname": "ATP", "accountnumber": "ATP"}, {"name": "Body", "accountdesc": "BODY SHOP SALESLABOR:BODY", "accountitem": "BODY SHOP_LAB", "accountname": "BODY SHOP SALES:LABOR:BODY", "accountnumber": "5002"}, {"name": "Detail", "accountdesc": "Detail", "accountitem": "BODY SHOP_DET", "accountname": "Detail", "accountnumber": "Detail"}, {"name": "Daignostic", "accountdesc": "Daignostic", "accountitem": "BODY SHOP_LAD", "accountname": "Daignostic", "accountnumber": "Daignostic"}, {"name": "Electrical", "accountdesc": "Electrical", "accountitem": "BODY SHOP_LAE", "accountname": "Electrical", "accountnumber": "Electrical"}, {"name": "Chrome", "accountdesc": "Chrome", "accountitem": "BODY SHOP_PAC", "accountname": "Chrome", "accountnumber": "Chrome"}, {"name": "Frame", "accountdesc": "Frame", "accountitem": "BODY SHOP_LAF", "accountname": "Frame", "accountnumber": "Frame"}, {"name": "Mechanical", "accountdesc": "Mechanical", "accountitem": "BODY SHOP_LAM", "accountname": "Mechanical", "accountnumber": "Mechanical"}, {"name": "Refinish", "accountdesc": "BODY SHOP SALES:LABOR:REFINISH", "accountitem": "BODY SHOP_LAR", "accountname": "BODY SHOP SALES:LABOR:REFINISH", "accountnumber": "5003"}, {"name": "Structural", "accountdesc": "Structural", "accountitem": "BODY SHOP_LAS", "accountname": "Structural", "accountnumber": "Structural"}, {"name": "Existing", "accountdesc": "Existing", "accountitem": "BODY SHOP_PAE", "accountname": "Existing", "accountnumber": "Existing"}, {"name": "Glass", "accountdesc": "Glass", "accountitem": "BODY SHOP_PAG", "accountname": "Glass", "accountnumber": "Glass"}, {"name": "LKQ", "accountdesc": "LKQ", "accountitem": "BODY SHOP_PAL", "accountname": "BODY SHOP SALES:PARTS:LKQ", "accountnumber": "LKQ"}, {"name": "OEM", "accountdesc": "BODY SHOP SALES:PARTS:OEM", "accountitem": "BODY SHOP_PAN", "accountname": "BODY SHOP SALES:PARTS:OEM", "accountnumber": "OEM"}, {"name": "OEM Partial", "accountdesc": "Partial", "accountitem": "BODY SHOP_PAP", "accountname": "OEM Partial", "accountnumber": "OEM Partial"}, {"name": "Re-cored", "accountdesc": "cored", "accountitem": "BODY SHOP_PAO", "accountname": "Re-cored", "accountnumber": "Re-cored"}, {"name": "Remanufactured", "accountdesc": "Remanufactured", "accountitem": "BODY SHOP_PAO", "accountname": "Remanufactured", "accountnumber": "Remanufactured"}, {"name": "Other", "accountdesc": "Other", "accountitem": "BODY SHOP_PAO", "accountname": "Other", "accountnumber": "Other"}, {"name": "Sublet", "accountdesc": "Sublet", "accountitem": "BODY SHOP_PAS", "accountname": "Sublet", "accountnumber": "Sublet"}, {"name": "Towing", "accountdesc": "Towing", "accountitem": "BODY SHOP_TOW", "accountname": "Towing", "accountnumber": "Towing"}, {"name": "Paint Profit", "accountdesc": "Paint Material Costs by Labor", "accountitem": "BODY SHOP_MAPA", "accountname": "paint", "accountnumber": "paint"}, {"name": "Shop Profit", "accountdesc": "Shop Material Costs by Labor", "accountitem": "BODY SHOP_MASH", "accountname": "shop", "accountnumber": "shop"}], "defaults": {"costs": {"ATS": "ATP", "LAB": "Body", "LAD": "Daignostic", "LAE": "Electrical", "LAF": "Frame", "LAG": "Glass", "LAM": "Mechanical", "LAR": "Refinish", "LAS": "Structural", "LAU": "Detail", "PAA": "Aftermarket", "PAC": "Chrome", "PAL": "LKQ", "PAM": "Remanufactured", "PAN": "OEM", "PAO": "Other", "PAP": "OEM Partial", "PAR": "Re-cored", "PAS": "Sublet", "TOW": "Towing", "MAPA": "Paint Cost", "MASH": "Shop Cost"}, "profits": {"ATS": "ATP", "LAB": "Body", "LAD": "Daignostic", "LAE": "Electrical", "LAF": "Frame", "LAG": "Glass", "LAM": "Mechanical", "LAR": "Refinish", "LAS": "Structural", "LAU": "Detail", "PAA": "Aftermarket", "PAC": "Chrome", "PAL": "LKQ", "PAM": "Remanufactured", "PAN": "OEM", "PAO": "Other", "PAP": "OEM Partial", "PAR": "Re-cored", "PAS": "Sublet", "TOW": "Towing", "MAPA": "Paint Profit", "MASH": "Shop Profit"}}, "sales_tax_codes": [{"code": "G", "local": false, "state": false, "federal": true, "description": "GST Only"}, {"code": "S", "state": true, "federal": true, "description": "Both"}, {"code": "E", "local": false, "state": false, "federal": false, "description": "Exempt"}]} diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index f63a4e31b..cf3050035 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -1,4 +1,4 @@ - +