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

@@ -47,7 +47,7 @@ export function TimeTicketModalComponent({
} = useTreatmentsWithConfig({ } = useTreatmentsWithConfig({
attributes: {}, attributes: {},
names: ["Enhanced_Payroll"], names: ["Enhanced_Payroll"],
splitKey: bodyshop.imexshopid splitKey: bodyshop?.imexshopid
}); });
const [loadLineTicketData, { loading, data: lineTicketData, refetch }] = useLazyQuery(GET_LINE_TICKET_BY_PK, { const [loadLineTicketData, { loading, data: lineTicketData, refetch }] = useLazyQuery(GET_LINE_TICKET_BY_PK, {
@@ -347,7 +347,7 @@ export function LaborAllocationContainer({
} = useTreatmentsWithConfig({ } = useTreatmentsWithConfig({
attributes: {}, attributes: {},
names: ["Enhanced_Payroll"], names: ["Enhanced_Payroll"],
splitKey: bodyshop.imexshopid splitKey: bodyshop?.imexshopid
}); });
if (loading) return <LoadingSkeleton />; if (loading) return <LoadingSkeleton />;

View File

@@ -1,6 +1,7 @@
const { RRClient } = require("./lib/index.cjs"); const { RRClient } = require("./lib/index.cjs");
const { getRRConfigFromBodyshop } = require("./rr-config"); const { getRRConfigFromBodyshop } = require("./rr-config");
const CreateRRLogEvent = require("./rr-logger-event"); const CreateRRLogEvent = require("./rr-logger-event");
const { withRRRequestXml } = require("./rr-log-xml");
const InstanceManager = require("../utils/instanceMgr").default; const InstanceManager = require("../utils/instanceMgr").default;
/** /**
@@ -217,14 +218,24 @@ const createRRCustomer = async ({ bodyshop, job, overrides = {}, socket }) => {
try { try {
response = await client.insertCustomer(safePayload, opts); response = await client.insertCustomer(safePayload, opts);
// Very noisy; only show when log level is cranked to SILLY // Very noisy; only show when log level is cranked to SILLY
CreateRRLogEvent(socket, "SILLY", "{CU} insertCustomer: raw response", { response }); CreateRRLogEvent(
socket,
"SILLY",
"{CU} insertCustomer: raw response",
withRRRequestXml(response, { response })
);
} catch (e) { } catch (e) {
CreateRRLogEvent(socket, "ERROR", "RR insertCustomer transport error", { CreateRRLogEvent(
message: e?.message, socket,
code: e?.code, "ERROR",
status: e?.meta?.status || e?.status, "RR insertCustomer transport error",
payload: safePayload withRRRequestXml(e, {
}); message: e?.message,
code: e?.code,
status: e?.meta?.status || e?.status,
payload: safePayload
})
);
throw e; throw e;
} }
@@ -233,12 +244,17 @@ const createRRCustomer = async ({ bodyshop, job, overrides = {}, socket }) => {
let customerNo = data?.dmsRecKey; let customerNo = data?.dmsRecKey;
if (!customerNo) { if (!customerNo) {
CreateRRLogEvent(socket, "ERROR", "RR insertCustomer returned no dmsRecKey/custNo", { CreateRRLogEvent(
status: trx?.status, socket,
statusCode: trx?.statusCode, "ERROR",
message: trx?.message, "RR insertCustomer returned no dmsRecKey/custNo",
data withRRRequestXml(response, {
}); status: trx?.status,
statusCode: trx?.statusCode,
message: trx?.message,
data
})
);
throw new Error( throw new Error(
`RR insertCustomer returned no dmsRecKey (status=${trx?.status ?? "?"} code=${trx?.statusCode ?? "?"}${ `RR insertCustomer returned no dmsRecKey (status=${trx?.status ?? "?"} code=${trx?.statusCode ?? "?"}${

View File

@@ -1,6 +1,7 @@
const { GraphQLClient } = require("graphql-request"); const { GraphQLClient } = require("graphql-request");
const queries = require("../graphql-client/queries"); const queries = require("../graphql-client/queries");
const CreateRRLogEvent = require("./rr-logger-event"); const CreateRRLogEvent = require("./rr-logger-event");
const { extractRRXmlPair } = require("./rr-log-xml");
/** Get bearer token from the socket (same approach used elsewhere) */ /** Get bearer token from the socket (same approach used elsewhere) */
const getAuthToken = (socket) => const getAuthToken = (socket) =>
@@ -178,11 +179,23 @@ const insertRRFailedExportLog = async ({ socket, jobId, job, bodyshop, error, cl
const client = new GraphQLClient(endpoint, {}); const client = new GraphQLClient(endpoint, {});
client.setHeaders({ Authorization: `Bearer ${token}` }); client.setHeaders({ Authorization: `Bearer ${token}` });
const { requestXml, responseXml } = extractRRXmlPair(error);
const xmlFromError =
requestXml || responseXml
? {
...(requestXml ? { request: requestXml } : {}),
...(responseXml ? { response: responseXml } : {})
}
: undefined;
const meta = buildRRExportMeta({ const meta = buildRRExportMeta({
result, result,
extra: { extra: {
error: error?.message || String(error), error: error?.message || String(error),
classification: classification || undefined classification: classification || undefined,
...(requestXml ? { requestXml } : {}),
...(responseXml ? { responseXml } : {}),
...(xmlFromError && !result?.xml ? { xml: xmlFromError } : {})
} }
}); });

View File

@@ -1,6 +1,7 @@
const { buildRRRepairOrderPayload } = require("./rr-job-helpers"); const { buildRRRepairOrderPayload } = require("./rr-job-helpers");
const { buildClientAndOpts } = require("./rr-lookup"); const { buildClientAndOpts } = require("./rr-lookup");
const CreateRRLogEvent = require("./rr-logger-event"); const CreateRRLogEvent = require("./rr-logger-event");
const { withRRRequestXml } = require("./rr-log-xml");
const { extractRrResponsibilityCenters } = require("./rr-responsibility-centers"); const { extractRrResponsibilityCenters } = require("./rr-responsibility-centers");
const CdkCalculateAllocations = require("./rr-calculate-allocations").default; const CdkCalculateAllocations = require("./rr-calculate-allocations").default;
const { resolveRROpCodeFromBodyshop } = require("./rr-utils"); const { resolveRROpCodeFromBodyshop } = require("./rr-utils");
@@ -147,10 +148,7 @@ const createMinimalRRRepairOrder = async (args) => {
const response = await client.createRepairOrder(payload, finalOpts); const response = await client.createRepairOrder(payload, finalOpts);
CreateRRLogEvent(socket, "INFO", "RR minimal Repair Order created", { CreateRRLogEvent(socket, "INFO", "RR minimal Repair Order created", withRRRequestXml(response, { payload, response }));
payload,
response
});
const data = response?.data || null; const data = response?.data || null;
const statusBlocks = response?.statusBlocks || {}; const statusBlocks = response?.statusBlocks || {};
@@ -327,7 +325,7 @@ const updateRRRepairOrderWithFullData = async (args) => {
// Without this, Reynolds won't recognize the OpCode when we send rogg operations // Without this, Reynolds won't recognize the OpCode when we send rogg operations
// The rolabor section tells Reynolds "these jobs exist" even with minimal data // The rolabor section tells Reynolds "these jobs exist" even with minimal data
CreateRRLogEvent(socket, "INFO", "Sending full data for early RO (using create with roNo)", { CreateRRLogEvent(socket, "INFO", "Preparing full data for early RO (using create with roNo)", {
roNo: String(roNo), roNo: String(roNo),
hasRolabor: !!payload.rolabor, hasRolabor: !!payload.rolabor,
hasRogg: !!payload.rogg, hasRogg: !!payload.rogg,
@@ -338,10 +336,18 @@ const updateRRRepairOrderWithFullData = async (args) => {
// Reynolds will merge this with the existing RO header // Reynolds will merge this with the existing RO header
const response = await client.createRepairOrder(payload, finalOpts); const response = await client.createRepairOrder(payload, finalOpts);
CreateRRLogEvent(socket, "INFO", "RR Repair Order full data sent", { CreateRRLogEvent(
payload, socket,
response "INFO",
}); "Sending full data for early RO (using create with roNo)",
withRRRequestXml(response, {
roNo: String(roNo),
hasRolabor: !!payload.rolabor,
hasRogg: !!payload.rogg,
payload,
response
})
);
const data = response?.data || null; const data = response?.data || null;
const statusBlocks = response?.statusBlocks || {}; const statusBlocks = response?.statusBlocks || {};
@@ -501,10 +507,7 @@ const exportJobToRR = async (args) => {
const response = await client.createRepairOrder(payload, finalOpts); const response = await client.createRepairOrder(payload, finalOpts);
CreateRRLogEvent(socket, "INFO", "RR raw Repair Order created", { CreateRRLogEvent(socket, "INFO", "RR raw Repair Order created", withRRRequestXml(response, { payload, response }));
payload,
response
});
const data = response?.data || null; const data = response?.data || null;
const statusBlocks = response?.statusBlocks || {}; const statusBlocks = response?.statusBlocks || {};
@@ -603,10 +606,15 @@ const finalizeRRRepairOrder = async (args) => {
const rrRes = await client.updateRepairOrder(payload, finalOpts); const rrRes = await client.updateRepairOrder(payload, finalOpts);
CreateRRLogEvent(socket, "SILLY", "RR Repair Order finalized", { CreateRRLogEvent(
payload, socket,
response: rrRes "SILLY",
}); "RR Repair Order finalized",
withRRRequestXml(rrRes, {
payload,
response: rrRes
})
);
const data = rrRes?.data || null; const data = rrRes?.data || null;
const statusBlocks = rrRes?.statusBlocks || {}; const statusBlocks = rrRes?.statusBlocks || {};

63
server/rr/rr-log-xml.js Normal file
View File

@@ -0,0 +1,63 @@
/**
* 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 ?? rrObj?.meta?.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 (!requestXml && typeof rrObj?.meta?.requestXml === "string") requestXml = rrObj.meta.requestXml;
if (!requestXml && typeof rrObj?.meta?.reqXml === "string") requestXml = rrObj.meta.reqXml;
if (!requestXml && typeof rrObj?.meta?.request === "string") requestXml = rrObj.meta.request;
if (!responseXml && typeof rrObj?.responseXml === "string") responseXml = rrObj.responseXml;
if (!responseXml && typeof rrObj?.meta?.responseXml === "string") responseXml = rrObj.meta.responseXml;
if (!responseXml && typeof rrObj?.meta?.resXml === "string") responseXml = rrObj.meta.resXml;
if (!responseXml && typeof rrObj?.meta?.response === "string") responseXml = rrObj.meta.response;
// If wrapped HTTP response data contains raw XML, surface it.
if (!responseXml && typeof rrObj?.response?.data === "string") {
const xmlData = rrObj.response.data.trim();
if (xmlData.startsWith("<")) responseXml = xmlData;
}
// Try one level down when errors are wrapped.
if ((!requestXml || !responseXml) && rrObj?.cause && rrObj.cause !== rrObj) {
const nested = extractRRXmlPair(rrObj.cause);
if (!requestXml) requestXml = nested.requestXml;
if (!responseXml) responseXml = nested.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;
};
module.exports = {
extractRRXmlPair,
withRRRequestXml
};

View File

@@ -12,6 +12,7 @@ const { createRRCustomer } = require("./rr-customers");
const { ensureRRServiceVehicle } = require("./rr-service-vehicles"); const { ensureRRServiceVehicle } = require("./rr-service-vehicles");
const { classifyRRVendorError } = require("./rr-errors"); const { classifyRRVendorError } = require("./rr-errors");
const { markRRExportSuccess, insertRRFailedExportLog } = require("./rr-export-logs"); const { markRRExportSuccess, insertRRFailedExportLog } = require("./rr-export-logs");
const { withRRRequestXml } = require("./rr-log-xml");
const { const {
makeVehicleSearchPayloadFromJob, makeVehicleSearchPayloadFromJob,
ownersFromVinBlocks, 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; 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. * Sort vehicle owners first in the list, preserving original order otherwise.
* @param list * @param list
@@ -279,7 +240,12 @@ const rrMultiCustomerSearch = async ({ bodyshop, job, socket, redisHelpers }) =>
const multiResponse = await rrCombinedSearch(bodyshop, q); 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) { if (fromVin) {
const multiBlocks = Array.isArray(multiResponse?.data) ? multiResponse.data : []; const multiBlocks = Array.isArray(multiResponse?.data) ? multiResponse.data : [];
@@ -300,7 +266,7 @@ const rrMultiCustomerSearch = async ({ bodyshop, job, socket, redisHelpers }) =>
const norm = normalizeCustomerCandidates(multiResponse, { ownersSet }); const norm = normalizeCustomerCandidates(multiResponse, { ownersSet });
merged.push(...norm); merged.push(...norm);
} catch (e) { } 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 count: decorated.length
}); });
} catch (e) { } 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 }); cb?.({ jobid, error: e.message });
} }
}); });
@@ -425,7 +391,7 @@ const registerRREvents = ({ socket, redisHelpers }) => {
fromCache fromCache
}); });
} catch (err) { } 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" }); 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) anyOwner: decorated.some((c) => c.vinOwner || c.isVehicleOwner)
}); });
} catch (error) { } catch (error) {
CreateRRLogEvent(socket, "ERROR", `Error during RR early RO creation (prepare)`, { CreateRRLogEvent(
error: error.message, socket,
stack: error.stack, "ERROR",
jobid: rid `Error during RR early RO creation (prepare)`,
}); withRRRequestXml(error, {
error: error.message,
stack: error.stack,
jobid: rid
})
);
try { try {
socket.emit("export-failed", { vendor: "rr", jobId: rid, error: error.message }); 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) { if (vehQ && vehQ.kind === "vin" && job?.v_vin) {
const vinResponse = await rrCombinedSearch(bodyshop, vehQ); 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 : []; const vinBlocks = Array.isArray(vinResponse?.data) ? vinResponse.data : [];
@@ -630,9 +606,14 @@ const registerRREvents = ({ socket, redisHelpers }) => {
} }
} }
} catch (e) { } catch (e) {
CreateRRLogEvent(socket, "WARN", `VIN owner pre-check failed; continuing with selected customer (early RO)`, { CreateRRLogEvent(
error: e?.message socket,
}); "WARN",
`VIN owner pre-check failed; continuing with selected customer (early RO)`,
withRRRequestXml(e, {
error: e?.message
})
);
} }
// Cache final/effective customer selection // Cache final/effective customer selection
@@ -905,14 +886,19 @@ const registerRREvents = ({ socket, redisHelpers }) => {
} catch (error) { } catch (error) {
const cls = classifyRRVendorError(error); const cls = classifyRRVendorError(error);
CreateRRLogEvent(socket, "ERROR", `Error during RR early RO creation (customer-selected)`, { CreateRRLogEvent(
error: error.message, socket,
vendorStatusCode: cls.vendorStatusCode, "ERROR",
code: cls.errorCode, `Error during RR early RO creation (customer-selected)`,
friendly: cls.friendlyMessage, withRRRequestXml(error, {
stack: error.stack, error: error.message,
jobid: rid vendorStatusCode: cls.vendorStatusCode,
}); code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
})
);
try { try {
if (!bodyshop || !job) { if (!bodyshop || !job) {
@@ -1097,7 +1083,28 @@ const registerRREvents = ({ socket, redisHelpers }) => {
roNo: job.dms_id 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) { 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"); 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) anyOwner: decorated.some((c) => c.vinOwner || c.isVehicleOwner)
}); });
} catch (error) { } catch (error) {
CreateRRLogEvent(socket, "ERROR", `Error during RR export (prepare)`, { CreateRRLogEvent(
error: error.message, socket,
stack: error.stack, "ERROR",
jobid: rid `Error during RR export (prepare)`,
}); withRRRequestXml(error, {
error: error.message,
stack: error.stack,
jobid: rid
})
);
try { try {
socket.emit("export-failed", { vendor: "rr", jobId: rid, error: error.message }); 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) { if (vehQ && vehQ.kind === "vin" && job?.v_vin) {
const vinResponse = await rrCombinedSearch(bodyshop, vehQ); 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 : []; const vinBlocks = Array.isArray(vinResponse?.data) ? vinResponse.data : [];
@@ -1253,9 +1270,14 @@ const registerRREvents = ({ socket, redisHelpers }) => {
} }
} }
} catch (e) { } catch (e) {
CreateRRLogEvent(socket, "WARN", `VIN owner pre-check failed; continuing with selected customer`, { CreateRRLogEvent(
error: e?.message socket,
}); "WARN",
`VIN owner pre-check failed; continuing with selected customer`,
withRRRequestXml(e, {
error: e?.message
})
);
} }
// Cache final/effective customer selection // Cache final/effective customer selection
@@ -1532,14 +1554,19 @@ const registerRREvents = ({ socket, redisHelpers }) => {
} catch (error) { } catch (error) {
const cls = classifyRRVendorError(error); const cls = classifyRRVendorError(error);
CreateRRLogEvent(socket, "ERROR", `Error during RR export (selected-customer)`, { CreateRRLogEvent(
error: error.message, socket,
vendorStatusCode: cls.vendorStatusCode, "ERROR",
code: cls.errorCode, `Error during RR export (selected-customer)`,
friendly: cls.friendlyMessage, withRRRequestXml(error, {
stack: error.stack, error: error.message,
jobid: rid vendorStatusCode: cls.vendorStatusCode,
}); code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
})
);
try { try {
if (!bodyshop || !job) { if (!bodyshop || !job) {
@@ -1707,14 +1734,19 @@ const registerRREvents = ({ socket, redisHelpers }) => {
} }
} catch (error) { } catch (error) {
const cls = classifyRRVendorError(error); const cls = classifyRRVendorError(error);
CreateRRLogEvent(socket, "ERROR", `Error during RR finalize`, { CreateRRLogEvent(
error: error.message, socket,
vendorStatusCode: cls.vendorStatusCode, "ERROR",
code: cls.errorCode, `Error during RR finalize`,
friendly: cls.friendlyMessage, withRRRequestXml(error, {
stack: error.stack, error: error.message,
jobid: rid vendorStatusCode: cls.vendorStatusCode,
}); code: cls.errorCode,
friendly: cls.friendlyMessage,
stack: error.stack,
jobid: rid
})
);
try { try {
if (!bodyshop || !job) { if (!bodyshop || !job) {

View File

@@ -1,5 +1,6 @@
const { buildClientAndOpts, rrCombinedSearch } = require("./rr-lookup"); const { buildClientAndOpts, rrCombinedSearch } = require("./rr-lookup");
const CreateRRLogEvent = require("./rr-logger-event"); const CreateRRLogEvent = require("./rr-logger-event");
const { withRRRequestXml } = require("./rr-log-xml");
/** /**
* Pick and normalize VIN from inputs * Pick and normalize VIN from inputs
* @param vin * @param vin
@@ -168,9 +169,12 @@ const ensureRRServiceVehicle = async (args = {}) => {
if (bodyshop) { if (bodyshop) {
const combinedSearchResponse = await rrCombinedSearch(bodyshop, { kind: "vin", vin: vinStr, maxResults: 50 }); const combinedSearchResponse = await rrCombinedSearch(bodyshop, { kind: "vin", vin: vinStr, maxResults: 50 });
CreateRRLogEvent(socket, "silly", "{SV} Preflight combined search by VIN: raw response", { CreateRRLogEvent(
response: combinedSearchResponse socket,
}); "silly",
"{SV} Preflight combined search by VIN: raw response",
withRRRequestXml(combinedSearchResponse, { response: combinedSearchResponse })
);
owners = ownersFromCombined(combinedSearchResponse, vinStr); owners = ownersFromCombined(combinedSearchResponse, vinStr);
} }
@@ -194,10 +198,15 @@ const ensureRRServiceVehicle = async (args = {}) => {
} }
} catch (e) { } catch (e) {
// Preflight shouldn't be fatal; log and continue to insert (idempotency will still be handled) // Preflight shouldn't be fatal; log and continue to insert (idempotency will still be handled)
CreateRRLogEvent(socket, "warn", "{SV} VIN preflight lookup failed; continuing to insert", { CreateRRLogEvent(
vin: vinStr, socket,
error: e?.message "warn",
}); "{SV} VIN preflight lookup failed; continuing to insert",
withRRRequestXml(e, {
vin: vinStr,
error: e?.message
})
);
} }
// Vendor says: MODEL DESCRIPTION HAS MAXIMUM LENGTH OF 20 // Vendor says: MODEL DESCRIPTION HAS MAXIMUM LENGTH OF 20
@@ -271,7 +280,7 @@ const ensureRRServiceVehicle = async (args = {}) => {
try { try {
const res = await client.insertServiceVehicle(insertPayload, insertOpts); const res = await client.insertServiceVehicle(insertPayload, insertOpts);
CreateRRLogEvent(socket, "silly", "{SV} insertServiceVehicle: raw response", { res }); CreateRRLogEvent(socket, "silly", "{SV} insertServiceVehicle: raw response", withRRRequestXml(res, { res }));
const data = res?.data ?? {}; const data = res?.data ?? {};
const svId = data?.dmsRecKey || data?.svId || undefined; const svId = data?.dmsRecKey || data?.svId || undefined;
@@ -309,11 +318,16 @@ const ensureRRServiceVehicle = async (args = {}) => {
}; };
} }
CreateRRLogEvent(socket, "error", "{SV} insertServiceVehicle: failure", { CreateRRLogEvent(
message: e?.message, socket,
code: e?.code, "error",
status: e?.meta?.status || e?.status "{SV} insertServiceVehicle: failure",
}); withRRRequestXml(e, {
message: e?.message,
code: e?.code,
status: e?.meta?.status || e?.status
})
);
throw e; throw e;
} }