Merged in feature/IO-3570-Fortellis-Multiple-Veh-Records (pull request #3012)

IO-3570 Filter Vehicle Results from VIN Query to records that only have a vehicleVehID
This commit is contained in:
Allan Carr
2026-02-19 17:56:50 +00:00

View File

@@ -198,7 +198,7 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
); );
const existingCustomerInDMSCustList = DMSCustList.find((c) => c.customerId === selectedCustomerId); const existingCustomerInDMSCustList = DMSCustList.find((c) => c.customerId === selectedCustomerId);
DMSCust = existingCustomerInDMSCustList || { DMSCust = existingCustomerInDMSCustList || {
customerId: selectedCustomerId //This is the fall back in case it is the generic customer. customerId: selectedCustomerId //This is the fall back in case it is the generic customer.
}; };
await setSessionTransactionData( await setSessionTransactionData(
socket.id, socket.id,
@@ -207,8 +207,6 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
DMSCust, DMSCust,
defaultFortellisTTL defaultFortellisTTL
); );
} else { } else {
CreateFortellisLogEvent(socket, "DEBUG", `{3.2} Creating new customer.`); CreateFortellisLogEvent(socket, "DEBUG", `{3.2} Creating new customer.`);
const DMSCustomerInsertResponse = await InsertDmsCustomer({ socket, redisHelpers, JobData }); const DMSCustomerInsertResponse = await InsertDmsCustomer({ socket, redisHelpers, JobData });
@@ -227,14 +225,10 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
CreateFortellisLogEvent(socket, "DEBUG", `{4.1} Inserting new vehicle with ID: ID ${DMSVid.vehiclesVehId}`); CreateFortellisLogEvent(socket, "DEBUG", `{4.1} Inserting new vehicle with ID: ID ${DMSVid.vehiclesVehId}`);
DMSVeh = await InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMSVid, DMSCust }); DMSVeh = await InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMSVid, DMSCust });
} else { } else {
DMSVeh = await getSessionTransactionData( DMSVeh = await getSessionTransactionData(socket.id, getTransactionType(jobid), FortellisCacheEnums.DMSVeh);
socket.id,
getTransactionType(jobid),
FortellisCacheEnums.DMSVeh
)
CreateFortellisLogEvent(socket, "DEBUG", `{4.3} Updating Existing Vehicle to associate to owner.`); CreateFortellisLogEvent(socket, "DEBUG", `{4.3} Updating Existing Vehicle to associate to owner.`);
//Check to see if the vehicle needs to be updated - i.e. the owner is not the selected customer. //Check to see if the vehicle needs to be updated - i.e. the owner is not the selected customer.
if (!DMSVeh?.owners.find((o) => o.id.value === DMSCust.customerId && o.id.assigningPartyId === "CURRENT")) { if (!DMSVeh?.owners.find((o) => o.id.value === DMSCust.customerId && o.id.assigningPartyId === "CURRENT")) {
DMSVeh = await UpdateDmsVehicle({ DMSVeh = await UpdateDmsVehicle({
socket, socket,
@@ -271,7 +265,11 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
if (DMSTransHeader.rtnCode === "0") { if (DMSTransHeader.rtnCode === "0") {
try { try {
CreateFortellisLogEvent(socket, "DEBUG", `{6} Attempting to post Transaction with ID ${DMSTransHeader.transID}`); CreateFortellisLogEvent(
socket,
"DEBUG",
`{6} Attempting to post Transaction with ID ${DMSTransHeader.transID}`
);
const DmsBatchTxnPost = await PostDmsBatchWip({ socket, redisHelpers, JobData }); // 2 in 1 call that includes a post and the transactions. const DmsBatchTxnPost = await PostDmsBatchWip({ socket, redisHelpers, JobData }); // 2 in 1 call that includes a post and the transactions.
await setSessionTransactionData( await setSessionTransactionData(
@@ -282,7 +280,6 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
defaultFortellisTTL defaultFortellisTTL
); );
if (DmsBatchTxnPost.rtnCode === "0") { if (DmsBatchTxnPost.rtnCode === "0") {
//TODO: Validate this is a string and not # //TODO: Validate this is a string and not #
//something //something
@@ -291,7 +288,6 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
await MarkJobExported({ socket, jobid: JobData.id, JobData }); await MarkJobExported({ socket, jobid: JobData.id, JobData });
try { try {
CreateFortellisLogEvent(socket, "DEBUG", `{7} Updating Service Vehicle History.`); CreateFortellisLogEvent(socket, "DEBUG", `{7} Updating Service Vehicle History.`);
const DMSVehHistory = await InsertServiceVehicleHistory({ socket, redisHelpers, JobData }); const DMSVehHistory = await InsertServiceVehicleHistory({ socket, redisHelpers, JobData });
await setSessionTransactionData( await setSessionTransactionData(
@@ -302,24 +298,19 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
defaultFortellisTTL defaultFortellisTTL
); );
} catch (error) { } catch (error) {
CreateFortellisLogEvent(socket, "ERROR", `{7.1} Error posting vehicle service history. ${error.message}`); CreateFortellisLogEvent(socket, "ERROR", `{7.1} Error posting vehicle service history. ${error.message}`);
} }
socket.emit("export-success", JobData.id); socket.emit("export-success", JobData.id);
} else { } else {
//There was something wrong. Throw an error to trigger clean up. //There was something wrong. Throw an error to trigger clean up.
//throw new Error("Error posting DMS Batch Transaction"); //throw new Error("Error posting DMS Batch Transaction");
} }
} catch (error) { } catch (error) {
//Clean up the transaction and insert a faild error code //Clean up the transaction and insert a faild error code
// //Get the error code // //Get the error code
CreateFortellisLogEvent(socket, "DEBUG", `{6.1} Getting errors for Transaction ID ${DMSTransHeader.transID}`); CreateFortellisLogEvent(socket, "DEBUG", `{6.1} Getting errors for Transaction ID ${DMSTransHeader.transID}`);
const DmsError = await QueryDmsErrWip({ socket, redisHelpers, JobData }); const DmsError = await QueryDmsErrWip({ socket, redisHelpers, JobData });
// //Delete the transaction // //Delete the transaction
CreateFortellisLogEvent(socket, "DEBUG", `{6.2} Deleting Transaction ID ${DMSTransHeader.transID}`); CreateFortellisLogEvent(socket, "DEBUG", `{6.2} Deleting Transaction ID ${DMSTransHeader.transID}`);
@@ -345,7 +336,11 @@ async function FortellisSelectedCustomer({ socket, redisHelpers, selectedCustome
stack: error.stack, stack: error.stack,
data: error.errorData data: error.errorData
}); });
await InsertFailedExportLog({ socket, JobData, error: error.errorData?.issues || [JSON.stringify(error.errorData)] }); await InsertFailedExportLog({
socket,
JobData,
error: error.errorData?.issues || [JSON.stringify(error.errorData)]
});
} finally { } finally {
//Ensure we always insert logEvents //Ensure we always insert logEvents
//GQL to insert logevents. //GQL to insert logevents.
@@ -373,7 +368,7 @@ async function CalculateDmsVid({ socket, JobData, redisHelpers }) {
socket, socket,
jobid: JobData.id, jobid: JobData.id,
body: {} body: {}
}); }).filter((v) => v.vehiclesVehId !== null && v.vehiclesVehId !== "");
return result; return result;
} catch (error) { } catch (error) {
handleFortellisApiError(socket, error, "CalculateDmsVid", { handleFortellisApiError(socket, error, "CalculateDmsVid", {
@@ -429,12 +424,12 @@ async function QueryDmsCustomerById({ socket, redisHelpers, JobData, CustomerId
async function QueryDmsCustomerByName({ socket, redisHelpers, JobData }) { async function QueryDmsCustomerByName({ socket, redisHelpers, JobData }) {
const ownerName = const ownerName =
JobData.ownr_co_nm && JobData.ownr_co_nm.trim() !== "" JobData.ownr_co_nm && JobData.ownr_co_nm.trim() !== ""
//? [["firstName", JobData.ownr_co_nm.replace(replaceSpecialRegex, "").toUpperCase()]] // Commented out until we receive direction. ? //? [["firstName", JobData.ownr_co_nm.replace(replaceSpecialRegex, "").toUpperCase()]] // Commented out until we receive direction.
? [["phone", JobData.ownr_ph1?.replace(replaceSpecialRegex, "")]] [["phone", JobData.ownr_ph1?.replace(replaceSpecialRegex, "")]]
: [ : [
["firstName", JobData.ownr_fn?.replace(/[^a-zA-Z-]/g, "").toUpperCase()], ["firstName", JobData.ownr_fn?.replace(/[^a-zA-Z-]/g, "").toUpperCase()],
["lastName", JobData.ownr_ln?.replace(/[^a-zA-Z-]/g, "").toUpperCase()] ["lastName", JobData.ownr_ln?.replace(/[^a-zA-Z-]/g, "").toUpperCase()]
]; ];
try { try {
const result = await MakeFortellisCall({ const result = await MakeFortellisCall({
...FortellisActions.QueryCustomerByName, ...FortellisActions.QueryCustomerByName,
@@ -457,7 +452,7 @@ async function QueryDmsCustomerByName({ socket, redisHelpers, JobData }) {
async function InsertDmsCustomer({ socket, redisHelpers, JobData }) { async function InsertDmsCustomer({ socket, redisHelpers, JobData }) {
try { try {
const isBusiness = (JobData.ownr_co_nm && JobData.ownr_co_nm.replace(replaceSpecialRegex, "").trim() !== "") const isBusiness = JobData.ownr_co_nm && JobData.ownr_co_nm.replace(replaceSpecialRegex, "").trim() !== "";
const result = await MakeFortellisCall({ const result = await MakeFortellisCall({
...FortellisActions.CreateCustomer, ...FortellisActions.CreateCustomer,
headers: {}, headers: {},
@@ -466,21 +461,23 @@ async function InsertDmsCustomer({ socket, redisHelpers, JobData }) {
jobid: JobData.id, jobid: JobData.id,
body: { body: {
customerType: isBusiness ? "BUSINESS" : "INDIVIDUAL", customerType: isBusiness ? "BUSINESS" : "INDIVIDUAL",
...isBusiness ? { ...(isBusiness
companyName: JobData.ownr_co_nm && JobData.ownr_co_nm.replace(replaceSpecialRegex, "").toUpperCase(), ? {
secondaryCustomerName: { companyName: JobData.ownr_co_nm && JobData.ownr_co_nm.replace(replaceSpecialRegex, "").toUpperCase(),
//lastName: JobData.ownr_co_nm && JobData.ownr_co_nm.replace(replaceSpecialRegex, "").toUpperCase() secondaryCustomerName: {
} //lastName: JobData.ownr_co_nm && JobData.ownr_co_nm.replace(replaceSpecialRegex, "").toUpperCase()
} : { }
customerName: { }
//"suffix": "Mr.", : {
firstName: JobData.ownr_fn && JobData.ownr_fn.replace(/[^a-zA-Z-]/g, "").toUpperCase(), customerName: {
//"middleName": "", //"suffix": "Mr.",
lastName: JobData.ownr_ln && JobData.ownr_ln.replace(/[^a-zA-Z-]/g, "").toUpperCase() firstName: JobData.ownr_fn && JobData.ownr_fn.replace(/[^a-zA-Z-]/g, "").toUpperCase(),
//"title": "", //"middleName": "",
//"nickName": "" lastName: JobData.ownr_ln && JobData.ownr_ln.replace(/[^a-zA-Z-]/g, "").toUpperCase()
} //"title": "",
}, //"nickName": ""
}
}),
postalAddress: { postalAddress: {
addressLine1: JobData.ownr_addr1?.replace(replaceSpecialRegex, "").trim().toUpperCase(), addressLine1: JobData.ownr_addr1?.replace(replaceSpecialRegex, "").trim().toUpperCase(),
addressLine2: JobData.ownr_addr2?.replace(replaceSpecialRegex, "").trim().toUpperCase(), addressLine2: JobData.ownr_addr2?.replace(replaceSpecialRegex, "").trim().toUpperCase(),
@@ -490,7 +487,7 @@ async function InsertDmsCustomer({ socket, redisHelpers, JobData }) {
rome: JobData.ownr_zip rome: JobData.ownr_zip
}), }),
state: JobData.ownr_st?.replace(replaceSpecialRegex, "").trim().toUpperCase(), state: JobData.ownr_st?.replace(replaceSpecialRegex, "").trim().toUpperCase(),
country: JobData.ownr_ctry?.replace(replaceSpecialRegex, "").trim().toUpperCase(), country: JobData.ownr_ctry?.replace(replaceSpecialRegex, "").trim().toUpperCase()
//"territory": "" //"territory": ""
}, },
// "birthDate": { // "birthDate": {
@@ -540,18 +537,18 @@ async function InsertDmsCustomer({ socket, redisHelpers, JobData }) {
emailAddresses: [ emailAddresses: [
...(!_.isEmpty(JobData.ownr_ea) ...(!_.isEmpty(JobData.ownr_ea)
? [ ? [
{ {
//"uuid": "", //"uuid": "",
address: JobData.ownr_ea.toUpperCase(), address: JobData.ownr_ea.toUpperCase(),
type: "PERSONAL" type: "PERSONAL"
// "doNotEmailSource": "", // "doNotEmailSource": "",
// "doNotEmail": false, // "doNotEmail": false,
// "isPreferred": true, // "isPreferred": true,
// "transactionEmailNotificationOptIn": false, // "transactionEmailNotificationOptIn": false,
// "optInRequestDate": null, // "optInRequestDate": null,
// "optInDate": null // "optInDate": null
} }
] ]
: []) : [])
// { // {
// "uuid": "", // "uuid": "",
@@ -691,9 +688,9 @@ async function InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMS
txEnvelope.dms_unsold === true txEnvelope.dms_unsold === true
? "" ? ""
: moment(txEnvelope.inservicedate) : moment(txEnvelope.inservicedate)
//.tz(JobData.bodyshop.timezone) //.tz(JobData.bodyshop.timezone)
.startOf("day") .startOf("day")
.toISOString() .toISOString()
}), }),
//"lastServiceDate": "2011-11-23", //"lastServiceDate": "2011-11-23",
vehicleId: DMSVid.vehiclesVehId vehicleId: DMSVid.vehiclesVehId
@@ -735,8 +732,8 @@ async function InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMS
txEnvelope.dms_unsold === true txEnvelope.dms_unsold === true
? "" ? ""
: moment() : moment()
// .tz(JobData.bodyshop.timezone) // .tz(JobData.bodyshop.timezone)
.format("YYYY-MM-DD"), .format("YYYY-MM-DD"),
// "deliveryMileage": 4, // "deliveryMileage": 4,
// "doorsQuantity": 4, // "doorsQuantity": 4,
// "engineNumber": "", // "engineNumber": "",
@@ -753,8 +750,8 @@ async function InsertDmsVehicle({ socket, redisHelpers, JobData, txEnvelope, DMS
: String(JobData.plate_no).replace(/([^\w]|_)/g, "").length === 0 : String(JobData.plate_no).replace(/([^\w]|_)/g, "").length === 0
? null ? null
: String(JobData.plate_no) : String(JobData.plate_no)
.replace(/([^\w]|_)/g, "") .replace(/([^\w]|_)/g, "")
.toUpperCase(), .toUpperCase(),
make: txEnvelope.dms_make, make: txEnvelope.dms_make,
// "model": "CC10753", // "model": "CC10753",
modelAbrev: txEnvelope.dms_model, modelAbrev: txEnvelope.dms_model,
@@ -900,13 +897,13 @@ async function UpdateDmsVehicle({ socket, redisHelpers, JobData, DMSVeh, DMSCust
}, },
...(oldOwner ...(oldOwner
? [ ? [
{ {
id: { id: {
assigningPartyId: "PREVIOUS", assigningPartyId: "PREVIOUS",
value: oldOwner.id.value value: oldOwner.id.value
}
} }
} ]
]
: []) : [])
]; ];
} }
@@ -936,24 +933,24 @@ async function UpdateDmsVehicle({ socket, redisHelpers, JobData, DMSVeh, DMSCust
txEnvelope.dms_unsold === true txEnvelope.dms_unsold === true
? "" ? ""
: moment(DMSVehToSend.dealer.inServiceDate || txEnvelope.inservicedate) : moment(DMSVehToSend.dealer.inServiceDate || txEnvelope.inservicedate)
// .tz(JobData.bodyshop.timezone) // .tz(JobData.bodyshop.timezone)
.toISOString() .toISOString()
}) })
}, },
vehicle: { vehicle: {
...DMSVehToSend.vehicle, ...DMSVehToSend.vehicle,
...(txEnvelope.dms_model_override ...(txEnvelope.dms_model_override
? { ? {
make: txEnvelope.dms_make, make: txEnvelope.dms_make,
modelAbrev: txEnvelope.dms_model modelAbrev: txEnvelope.dms_model
} }
: {}), : {}),
deliveryDate: deliveryDate:
txEnvelope.dms_unsold === true txEnvelope.dms_unsold === true
? "" ? ""
: moment(DMSVehToSend.vehicle.deliveryDate) : moment(DMSVehToSend.vehicle.deliveryDate)
//.tz(JobData.bodyshop.timezone) //.tz(JobData.bodyshop.timezone)
.toISOString() .toISOString()
}, },
owners: ids owners: ids
} }
@@ -1061,7 +1058,7 @@ async function InsertDmsStartWip({ socket, redisHelpers, JobData }) {
// transID: "", // transID: "",
// userID: "partprgm", // userID: "partprgm",
// userName: "PROGRAM, PARTNER" // userName: "PROGRAM, PARTNER"
}, }
}); });
return result; return result;
} catch (error) { } catch (error) {
@@ -1091,9 +1088,9 @@ async function GenerateTransWips({ socket, redisHelpers, JobData }) {
acct: alloc.profitCenter.dms_acctnumber, acct: alloc.profitCenter.dms_acctnumber,
cntl: cntl:
alloc.profitCenter.dms_control_override && alloc.profitCenter.dms_control_override &&
alloc.profitCenter.dms_control_override !== null && alloc.profitCenter.dms_control_override !== null &&
alloc.profitCenter.dms_control_override !== undefined && alloc.profitCenter.dms_control_override !== undefined &&
alloc.profitCenter.dms_control_override?.trim() !== "" alloc.profitCenter.dms_control_override?.trim() !== ""
? alloc.profitCenter.dms_control_override ? alloc.profitCenter.dms_control_override
: JobData.ro_number, : JobData.ro_number,
cntl2: null, cntl2: null,
@@ -1114,9 +1111,9 @@ async function GenerateTransWips({ socket, redisHelpers, JobData }) {
acct: alloc.costCenter.dms_acctnumber, acct: alloc.costCenter.dms_acctnumber,
cntl: cntl:
alloc.costCenter.dms_control_override && alloc.costCenter.dms_control_override &&
alloc.costCenter.dms_control_override !== null && alloc.costCenter.dms_control_override !== null &&
alloc.costCenter.dms_control_override !== undefined && alloc.costCenter.dms_control_override !== undefined &&
alloc.costCenter.dms_control_override?.trim() !== "" alloc.costCenter.dms_control_override?.trim() !== ""
? alloc.costCenter.dms_control_override ? alloc.costCenter.dms_control_override
: JobData.ro_number, : JobData.ro_number,
cntl2: null, cntl2: null,
@@ -1134,9 +1131,9 @@ async function GenerateTransWips({ socket, redisHelpers, JobData }) {
acct: alloc.costCenter.dms_wip_acctnumber, acct: alloc.costCenter.dms_wip_acctnumber,
cntl: cntl:
alloc.costCenter.dms_control_override && alloc.costCenter.dms_control_override &&
alloc.costCenter.dms_control_override !== null && alloc.costCenter.dms_control_override !== null &&
alloc.costCenter.dms_control_override !== undefined && alloc.costCenter.dms_control_override !== undefined &&
alloc.costCenter.dms_control_override?.trim() !== "" alloc.costCenter.dms_control_override?.trim() !== ""
? alloc.costCenter.dms_control_override ? alloc.costCenter.dms_control_override
: JobData.ro_number, : JobData.ro_number,
cntl2: null, cntl2: null,
@@ -1158,9 +1155,9 @@ async function GenerateTransWips({ socket, redisHelpers, JobData }) {
acct: alloc.profitCenter.dms_acctnumber, acct: alloc.profitCenter.dms_acctnumber,
cntl: cntl:
alloc.profitCenter.dms_control_override && alloc.profitCenter.dms_control_override &&
alloc.profitCenter.dms_control_override !== null && alloc.profitCenter.dms_control_override !== null &&
alloc.profitCenter.dms_control_override !== undefined && alloc.profitCenter.dms_control_override !== undefined &&
alloc.profitCenter.dms_control_override?.trim() !== "" alloc.profitCenter.dms_control_override?.trim() !== ""
? alloc.profitCenter.dms_control_override ? alloc.profitCenter.dms_control_override
: JobData.ro_number, : JobData.ro_number,
cntl2: null, cntl2: null,
@@ -1228,7 +1225,7 @@ async function PostDmsBatchWip({ socket, redisHelpers, JobData }) {
opCode: "P", opCode: "P",
transID: DMSTransHeader.transID, transID: DMSTransHeader.transID,
transWipReqList: await GenerateTransWips({ socket, redisHelpers, JobData }) transWipReqList: await GenerateTransWips({ socket, redisHelpers, JobData })
}, }
}); });
return result; return result;
} catch (error) { } catch (error) {
@@ -1256,7 +1253,7 @@ async function QueryDmsErrWip({ socket, redisHelpers, JobData }) {
socket, socket,
jobid: JobData.id, jobid: JobData.id,
requestPathParams: DMSTransHeader.transID, requestPathParams: DMSTransHeader.transID,
body: {}, body: {}
}); });
return result; return result;
} catch (error) { } catch (error) {
@@ -1286,7 +1283,7 @@ async function DeleteDmsWip({ socket, redisHelpers, JobData }) {
body: { body: {
opCode: "D", opCode: "D",
transID: DMSTransHeader.transID transID: DMSTransHeader.transID
}, }
}); });
return result; return result;
} catch (error) { } catch (error) {
@@ -1338,13 +1335,15 @@ async function InsertFailedExportLog({ socket, JobData, error }) {
const result = await client const result = await client
.setHeaders({ Authorization: `Bearer ${currentToken}` }) .setHeaders({ Authorization: `Bearer ${currentToken}` })
.request(queries.INSERT_EXPORT_LOG, { .request(queries.INSERT_EXPORT_LOG, {
logs: [{ logs: [
bodyshopid: JobData.bodyshop.id, {
jobid: JobData.id, bodyshopid: JobData.bodyshop.id,
successful: false, jobid: JobData.id,
message: JSON.stringify(error), successful: false,
useremail: socket.user.email message: JSON.stringify(error),
}] useremail: socket.user.email
}
]
}); });
return result; return result;