release/2026-02-27 - Fix Time ticket issue, add additional logging around reynolds

This commit is contained in:
Dave
2026-03-04 12:21:29 -05:00
parent e251e5f8f6
commit f56a540b2f
7 changed files with 278 additions and 132 deletions

View File

@@ -12,6 +12,7 @@ const { createRRCustomer } = require("./rr-customers");
const { ensureRRServiceVehicle } = require("./rr-service-vehicles");
const { classifyRRVendorError } = require("./rr-errors");
const { markRRExportSuccess, insertRRFailedExportLog } = require("./rr-export-logs");
const { withRRRequestXml } = require("./rr-log-xml");
const {
makeVehicleSearchPayloadFromJob,
ownersFromVinBlocks,
@@ -48,46 +49,6 @@ const resolveJobId = (explicit, payload, job) => explicit || payload?.jobId || j
*/
const resolveVin = ({ tx, job }) => tx?.jobData?.vin || job?.v_vin || null;
/**
* Extract request/response XML from RR response/result shapes.
* @param rrObj
* @returns {{requestXml: string|null, responseXml: string|null}}
*/
const extractRRXmlPair = (rrObj) => {
const xml = rrObj?.xml;
let requestXml = null;
let responseXml = null;
if (typeof xml === "string") {
requestXml = xml;
} else {
if (typeof xml?.request === "string") requestXml = xml.request;
else if (typeof xml?.req === "string") requestXml = xml.req;
else if (typeof xml?.starXml === "string") requestXml = xml.starXml;
if (typeof xml?.response === "string") responseXml = xml.response;
}
if (!requestXml && typeof rrObj?.requestXml === "string") requestXml = rrObj.requestXml;
if (!responseXml && typeof rrObj?.responseXml === "string") responseXml = rrObj.responseXml;
return { requestXml, responseXml };
};
/**
* Add Reynolds request/response XML to RR log metadata when available.
* @param rrObj
* @param meta
* @returns {*}
*/
const withRRRequestXml = (rrObj, meta = {}) => {
const { requestXml, responseXml } = extractRRXmlPair(rrObj);
const xmlMeta = {};
if (requestXml) xmlMeta.requestXml = requestXml;
if (responseXml) xmlMeta.responseXml = responseXml;
return Object.keys(xmlMeta).length ? { ...meta, ...xmlMeta } : meta;
};
/**
* Sort vehicle owners first in the list, preserving original order otherwise.
* @param list
@@ -279,7 +240,12 @@ const rrMultiCustomerSearch = async ({ bodyshop, job, socket, redisHelpers }) =>
const multiResponse = await rrCombinedSearch(bodyshop, q);
CreateRRLogEvent(socket, "SILLY", "Multi Customer Search - raw combined search", { response: multiResponse });
CreateRRLogEvent(
socket,
"SILLY",
"Multi Customer Search - raw combined search",
withRRRequestXml(multiResponse, { response: multiResponse })
);
if (fromVin) {
const multiBlocks = Array.isArray(multiResponse?.data) ? multiResponse.data : [];
@@ -300,7 +266,7 @@ const rrMultiCustomerSearch = async ({ bodyshop, job, socket, redisHelpers }) =>
const norm = normalizeCustomerCandidates(multiResponse, { ownersSet });
merged.push(...norm);
} catch (e) {
CreateRRLogEvent(socket, "WARN", "Multi-search subquery failed", { kind: q.kind, error: e.message });
CreateRRLogEvent(socket, "WARN", "Multi-search subquery failed", withRRRequestXml(e, { kind: q.kind, error: e.message }));
}
}
@@ -348,7 +314,7 @@ const registerRREvents = ({ socket, redisHelpers }) => {
count: decorated.length
});
} catch (e) {
CreateRRLogEvent(socket, "ERROR", "RR combined lookup error", { error: e.message, jobid });
CreateRRLogEvent(socket, "ERROR", "RR combined lookup error", withRRRequestXml(e, { error: e.message, jobid }));
cb?.({ jobid, error: e.message });
}
});
@@ -425,7 +391,7 @@ const registerRREvents = ({ socket, redisHelpers }) => {
fromCache
});
} catch (err) {
CreateRRLogEvent(socket, "ERROR", "rr-get-advisors: failed", { error: err?.message });
CreateRRLogEvent(socket, "ERROR", "rr-get-advisors: failed", withRRRequestXml(err, { error: err?.message }));
ack?.({ ok: false, error: err?.message || "get advisors failed" });
}
});
@@ -496,11 +462,16 @@ const registerRREvents = ({ socket, redisHelpers }) => {
anyOwner: decorated.some((c) => c.vinOwner || c.isVehicleOwner)
});
} catch (error) {
CreateRRLogEvent(socket, "ERROR", `Error during RR early RO creation (prepare)`, {
error: error.message,
stack: error.stack,
jobid: rid
});
CreateRRLogEvent(
socket,
"ERROR",
`Error during RR early RO creation (prepare)`,
withRRRequestXml(error, {
error: error.message,
stack: error.stack,
jobid: rid
})
);
try {
socket.emit("export-failed", { vendor: "rr", jobId: rid, error: error.message });
@@ -597,7 +568,12 @@ const registerRREvents = ({ socket, redisHelpers }) => {
if (vehQ && vehQ.kind === "vin" && job?.v_vin) {
const vinResponse = await rrCombinedSearch(bodyshop, vehQ);
CreateRRLogEvent(socket, "SILLY", `VIN owner pre-check response (early RO)`, { response: vinResponse });
CreateRRLogEvent(
socket,
"SILLY",
`VIN owner pre-check response (early RO)`,
withRRRequestXml(vinResponse, { response: vinResponse })
);
const vinBlocks = Array.isArray(vinResponse?.data) ? vinResponse.data : [];
@@ -630,9 +606,14 @@ const registerRREvents = ({ socket, redisHelpers }) => {
}
}
} catch (e) {
CreateRRLogEvent(socket, "WARN", `VIN owner pre-check failed; continuing with selected customer (early RO)`, {
error: e?.message
});
CreateRRLogEvent(
socket,
"WARN",
`VIN owner pre-check failed; continuing with selected customer (early RO)`,
withRRRequestXml(e, {
error: e?.message
})
);
}
// Cache final/effective customer selection
@@ -905,14 +886,19 @@ const registerRREvents = ({ socket, redisHelpers }) => {
} catch (error) {
const cls = classifyRRVendorError(error);
CreateRRLogEvent(socket, "ERROR", `Error during RR early RO creation (customer-selected)`, {
error: error.message,
vendorStatusCode: cls.vendorStatusCode,
code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
});
CreateRRLogEvent(
socket,
"ERROR",
`Error during RR early RO creation (customer-selected)`,
withRRRequestXml(error, {
error: error.message,
vendorStatusCode: cls.vendorStatusCode,
code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
})
);
try {
if (!bodyshop || !job) {
@@ -1097,7 +1083,28 @@ const registerRREvents = ({ socket, redisHelpers }) => {
roNo: job.dms_id
});
CreateRRLogEvent(
socket,
"SILLY",
"{4.1} RR RO update response received",
withRRRequestXml(result, {
dmsRoNo: job.dms_id,
success: !!result?.success
})
);
if (!result?.success) {
CreateRRLogEvent(
socket,
"ERROR",
"RR Repair Order update failed",
withRRRequestXml(result, {
jobId: rid,
dmsRoNo: job.dms_id,
roStatus: result?.roStatus,
statusBlocks: result?.statusBlocks
})
);
throw new Error(result?.roStatus?.message || "Failed to update RR Repair Order");
}
@@ -1154,11 +1161,16 @@ const registerRREvents = ({ socket, redisHelpers }) => {
anyOwner: decorated.some((c) => c.vinOwner || c.isVehicleOwner)
});
} catch (error) {
CreateRRLogEvent(socket, "ERROR", `Error during RR export (prepare)`, {
error: error.message,
stack: error.stack,
jobid: rid
});
CreateRRLogEvent(
socket,
"ERROR",
`Error during RR export (prepare)`,
withRRRequestXml(error, {
error: error.message,
stack: error.stack,
jobid: rid
})
);
try {
socket.emit("export-failed", { vendor: "rr", jobId: rid, error: error.message });
@@ -1220,7 +1232,12 @@ const registerRREvents = ({ socket, redisHelpers }) => {
if (vehQ && vehQ.kind === "vin" && job?.v_vin) {
const vinResponse = await rrCombinedSearch(bodyshop, vehQ);
CreateRRLogEvent(socket, "SILLY", `VIN owner pre-check response`, { response: vinResponse });
CreateRRLogEvent(
socket,
"SILLY",
`VIN owner pre-check response`,
withRRRequestXml(vinResponse, { response: vinResponse })
);
const vinBlocks = Array.isArray(vinResponse?.data) ? vinResponse.data : [];
@@ -1253,9 +1270,14 @@ const registerRREvents = ({ socket, redisHelpers }) => {
}
}
} catch (e) {
CreateRRLogEvent(socket, "WARN", `VIN owner pre-check failed; continuing with selected customer`, {
error: e?.message
});
CreateRRLogEvent(
socket,
"WARN",
`VIN owner pre-check failed; continuing with selected customer`,
withRRRequestXml(e, {
error: e?.message
})
);
}
// Cache final/effective customer selection
@@ -1532,14 +1554,19 @@ const registerRREvents = ({ socket, redisHelpers }) => {
} catch (error) {
const cls = classifyRRVendorError(error);
CreateRRLogEvent(socket, "ERROR", `Error during RR export (selected-customer)`, {
error: error.message,
vendorStatusCode: cls.vendorStatusCode,
code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
});
CreateRRLogEvent(
socket,
"ERROR",
`Error during RR export (selected-customer)`,
withRRRequestXml(error, {
error: error.message,
vendorStatusCode: cls.vendorStatusCode,
code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
})
);
try {
if (!bodyshop || !job) {
@@ -1707,14 +1734,19 @@ const registerRREvents = ({ socket, redisHelpers }) => {
}
} catch (error) {
const cls = classifyRRVendorError(error);
CreateRRLogEvent(socket, "ERROR", `Error during RR finalize`, {
error: error.message,
vendorStatusCode: cls.vendorStatusCode,
code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
});
CreateRRLogEvent(
socket,
"ERROR",
`Error during RR finalize`,
withRRRequestXml(error, {
error: error.message,
vendorStatusCode: cls.vendorStatusCode,
code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
})
);
try {
if (!bodyshop || !job) {