Merge remote-tracking branch 'origin/master-AIO' into release/2026-02-27

This commit is contained in:
Dave
2026-03-04 12:38:59 -05:00
200 changed files with 5476 additions and 7441 deletions

View File

@@ -155,13 +155,15 @@ const setJobDmsIdForSocket = async ({ socket, jobId, dmsId, dmsCustomerId, dmsAd
if (!token) throw new Error("Missing auth token for setJobDmsIdForSocket");
const client = new GraphQLClient(endpoint, {});
await client.setHeaders({ Authorization: `Bearer ${token}` }).request(queries.SET_JOB_DMS_ID, {
id: jobId,
dms_id: String(dmsId),
dms_customer_id: dmsCustomerId ? String(dmsCustomerId) : null,
dms_advisor_id: dmsAdvisorId ? String(dmsAdvisorId) : null,
kmin: mileageIn != null && mileageIn > 0 ? parseInt(mileageIn, 10) : null
});
await client
.setHeaders({ Authorization: `Bearer ${token}` })
.request(queries.SET_JOB_DMS_ID, {
id: jobId,
dms_id: String(dmsId),
dms_customer_id: dmsCustomerId ? String(dmsCustomerId) : null,
dms_advisor_id: dmsAdvisorId ? String(dmsAdvisorId) : null,
kmin: mileageIn != null && mileageIn > 0 ? parseInt(mileageIn, 10) : null
});
CreateRRLogEvent(socket, "INFO", "Linked job.dms_id to RR RO", {
jobId,
@@ -520,11 +522,7 @@ const registerRREvents = ({ socket, redisHelpers }) => {
});
// Filter out invalid values
if (
selectedCustNo === "undefined" ||
selectedCustNo === "null" ||
(selectedCustNo && selectedCustNo.trim() === "")
) {
if (selectedCustNo === "undefined" || selectedCustNo === "null" || (selectedCustNo && selectedCustNo.trim() === "")) {
selectedCustNo = null;
}
@@ -728,52 +726,42 @@ const registerRREvents = ({ socket, redisHelpers }) => {
const outsdRoNo = data?.outsdRoNo ?? job?.ro_number ?? job?.id ?? null;
CreateRRLogEvent(
socket,
"DEBUG",
"Early RO created - checking dmsRoNo",
withRRRequestXml(result, {
dmsRoNo,
resultRoNo: result?.roNo,
dataRoNo: data?.dmsRoNo,
jobId: rid
})
);
CreateRRLogEvent(socket, "DEBUG", "Early RO created - checking dmsRoNo", {
dmsRoNo,
resultRoNo: result?.roNo,
dataRoNo: data?.dmsRoNo,
jobId: rid
});
// ✅ Persist DMS RO number, customer ID, advisor ID, and mileage on the job
if (dmsRoNo) {
const mileageIn = txEnvelope?.kmin ?? null;
CreateRRLogEvent(socket, "DEBUG", "Calling setJobDmsIdForSocket", {
jobId: rid,
CreateRRLogEvent(socket, "DEBUG", "Calling setJobDmsIdForSocket", {
jobId: rid,
dmsId: dmsRoNo,
customerId: effectiveCustNo,
advisorId: String(advisorNo),
mileageIn
});
await setJobDmsIdForSocket({
socket,
jobId: rid,
await setJobDmsIdForSocket({
socket,
jobId: rid,
dmsId: dmsRoNo,
dmsCustomerId: effectiveCustNo,
dmsAdvisorId: String(advisorNo),
mileageIn
});
} else {
CreateRRLogEvent(
socket,
"WARN",
"RR early RO creation succeeded but no DMS RO number was returned",
withRRRequestXml(result, {
jobId: rid,
resultPreview: {
roNo: result?.roNo,
data: {
dmsRoNo: data?.dmsRoNo,
outsdRoNo: data?.outsdRoNo
}
CreateRRLogEvent(socket, "WARN", "RR early RO creation succeeded but no DMS RO number was returned", {
jobId: rid,
resultPreview: {
roNo: result?.roNo,
data: {
dmsRoNo: data?.dmsRoNo,
outsdRoNo: data?.outsdRoNo
}
})
);
}
});
}
await redisHelpers.setSessionTransactionData(
@@ -791,15 +779,10 @@ const registerRREvents = ({ socket, redisHelpers }) => {
defaultRRTTL
);
CreateRRLogEvent(
socket,
"INFO",
`{EARLY-5} Minimal RO created successfully`,
withRRRequestXml(result, {
dmsRoNo: dmsRoNo || null,
outsdRoNo: outsdRoNo || null
})
);
CreateRRLogEvent(socket, "INFO", `{EARLY-5} Minimal RO created successfully`, {
dmsRoNo: dmsRoNo || null,
outsdRoNo: outsdRoNo || null
});
// Mark success in export logs
await markRRExportSuccess({
@@ -848,16 +831,11 @@ const registerRREvents = ({ socket, redisHelpers }) => {
message: vendorMessage
});
CreateRRLogEvent(
socket,
"ERROR",
`Early RO creation failed`,
withRRRequestXml(result, {
roStatus: result?.roStatus,
statusBlocks: result?.statusBlocks,
classification: cls
})
);
CreateRRLogEvent(socket, "ERROR", `Early RO creation failed`, {
roStatus: result?.roStatus,
statusBlocks: result?.statusBlocks,
classification: cls
});
await insertRRFailedExportLog({
socket,
@@ -988,14 +966,14 @@ const registerRREvents = ({ socket, redisHelpers }) => {
// Check if this job already has an early RO - if so, use stored IDs and skip customer search
const hasEarlyRO = !!job?.dms_id;
if (hasEarlyRO) {
CreateRRLogEvent(socket, "DEBUG", `{2} Early RO exists - using stored customer/advisor`, {
dms_id: job.dms_id,
dms_customer_id: job.dms_customer_id,
dms_advisor_id: job.dms_advisor_id
});
// Cache the stored customer/advisor IDs for the next step
if (job.dms_customer_id) {
await redisHelpers.setSessionTransactionData(
@@ -1015,18 +993,18 @@ const registerRREvents = ({ socket, redisHelpers }) => {
defaultRRTTL
);
}
// Emit empty customer list to frontend (won't show modal)
socket.emit("rr-select-customer", []);
// Continue directly with the export by calling the selected customer handler logic inline
// This is essentially the same as if user selected the stored customer
const selectedCustNo = job.dms_customer_id;
if (!selectedCustNo) {
throw new Error("Early RO exists but no customer ID stored");
}
// Continue with ensureRRServiceVehicle and export (same as rr-selected-customer handler)
const { client, opts } = await buildClientAndOpts(bodyshop);
const routing = opts?.routing || client?.opts?.routing || null;
@@ -1059,12 +1037,7 @@ const registerRREvents = ({ socket, redisHelpers }) => {
redisHelpers
});
const advisorNo =
job.dms_advisor_id ||
readAdvisorNo(
{ txEnvelope },
await redisHelpers.getSessionTransactionData(socket.id, getTransactionType(rid), RRCacheEnums.AdvisorNo)
);
const advisorNo = job.dms_advisor_id || readAdvisorNo({ txEnvelope }, await redisHelpers.getSessionTransactionData(socket.id, getTransactionType(rid), RRCacheEnums.AdvisorNo));
if (!advisorNo) {
throw new Error("Advisor is required (advisorNo).");
@@ -1133,20 +1106,15 @@ const registerRREvents = ({ socket, redisHelpers }) => {
defaultRRTTL
);
CreateRRLogEvent(
socket,
"INFO",
`RR Repair Order updated successfully`,
withRRRequestXml(result, {
dmsRoNo,
jobId: rid
})
);
CreateRRLogEvent(socket, "INFO", `RR Repair Order updated successfully`, {
dmsRoNo,
jobId: rid
});
// For early RO flow, only emit validation-required (not export-job:result)
// since the export is not complete yet - we're just waiting for validation
socket.emit("rr-validation-required", { dmsRoNo, jobId: rid });
return ack?.({ ok: true, skipCustomerSelection: true, dmsRoNo });
}
@@ -1371,25 +1339,25 @@ const registerRREvents = ({ socket, redisHelpers }) => {
// When updating an early RO, use stored customer/advisor IDs
let finalEffectiveCustNo = effectiveCustNo;
let finalAdvisorNo = advisorNo;
if (shouldUpdate && job?.dms_customer_id) {
CreateRRLogEvent(socket, "DEBUG", `Using stored customer ID from early RO`, {
CreateRRLogEvent(socket, "DEBUG", `Using stored customer ID from early RO`, {
storedCustomerId: job.dms_customer_id,
originalCustomerId: effectiveCustNo
originalCustomerId: effectiveCustNo
});
finalEffectiveCustNo = String(job.dms_customer_id);
}
if (shouldUpdate && job?.dms_advisor_id) {
CreateRRLogEvent(socket, "DEBUG", `Using stored advisor ID from early RO`, {
CreateRRLogEvent(socket, "DEBUG", `Using stored advisor ID from early RO`, {
storedAdvisorId: job.dms_advisor_id,
originalAdvisorId: advisorNo
originalAdvisorId: advisorNo
});
finalAdvisorNo = String(job.dms_advisor_id);
}
let result;
if (shouldUpdate) {
// UPDATE existing RO with full data
CreateRRLogEvent(socket, "DEBUG", `{4} Updating existing RR RO with full data`, { dmsRoNo: existingDmsId });
@@ -1438,21 +1406,16 @@ const registerRREvents = ({ socket, redisHelpers }) => {
if (dmsRoNo) {
await setJobDmsIdForSocket({ socket, jobId: rid, dmsId: dmsRoNo });
} else {
CreateRRLogEvent(
socket,
"WARN",
"RR export succeeded but no DMS RO number was returned",
withRRRequestXml(result, {
jobId: rid,
resultPreview: {
roNo: result?.roNo,
data: {
dmsRoNo: data?.dmsRoNo,
outsdRoNo: data?.outsdRoNo
}
CreateRRLogEvent(socket, "WARN", "RR export succeeded but no DMS RO number was returned", {
jobId: rid,
resultPreview: {
roNo: result?.roNo,
data: {
dmsRoNo: data?.dmsRoNo,
outsdRoNo: data?.outsdRoNo
}
})
);
}
});
}
await redisHelpers.setSessionTransactionData(
@@ -1469,15 +1432,10 @@ const registerRREvents = ({ socket, redisHelpers }) => {
defaultRRTTL
);
CreateRRLogEvent(
socket,
"INFO",
`{5} RO created. Waiting for validation.`,
withRRRequestXml(result, {
dmsRoNo: dmsRoNo || null,
outsdRoNo: outsdRoNo || null
})
);
CreateRRLogEvent(socket, "INFO", `{5} RO created. Waiting for validation.`, {
dmsRoNo: dmsRoNo || null,
outsdRoNo: outsdRoNo || null
});
// Tell FE to prompt for "Finished/Close"
socket.emit("rr-validation-required", { jobId: rid, dmsRoNo, outsdRoNo });
@@ -1516,16 +1474,11 @@ const registerRREvents = ({ socket, redisHelpers }) => {
message: vendorMessage
});
CreateRRLogEvent(
socket,
"ERROR",
`Export failed (step 1)`,
withRRRequestXml(result, {
roStatus: result?.roStatus,
statusBlocks: result?.statusBlocks,
classification: cls
})
);
CreateRRLogEvent(socket, "ERROR", `Export failed (step 1)`, {
roStatus: result?.roStatus,
statusBlocks: result?.statusBlocks,
classification: cls
});
await insertRRFailedExportLog({
socket,
@@ -1655,12 +1608,7 @@ const registerRREvents = ({ socket, redisHelpers }) => {
});
if (finalizeResult?.success) {
CreateRRLogEvent(
socket,
"INFO",
`{7} Finalize success; marking exported`,
withRRRequestXml(finalizeResult, { dmsRoNo, outsdRoNo })
);
CreateRRLogEvent(socket, "INFO", `{7} Finalize success; marking exported`, { dmsRoNo, outsdRoNo });
// ✅ Mark exported + success log
await markRRExportSuccess({
@@ -1703,17 +1651,6 @@ const registerRREvents = ({ socket, redisHelpers }) => {
message: vendorMessage
});
CreateRRLogEvent(
socket,
"ERROR",
"Finalize failed",
withRRRequestXml(finalizeResult, {
roStatus: finalizeResult?.roStatus,
statusBlocks: finalizeResult?.statusBlocks,
classification: cls
})
);
await insertRRFailedExportLog({
socket,
jobId: rid,