feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration - rr-Utils hardening

This commit is contained in:
Dave
2025-11-07 15:28:23 -05:00
parent 5a8a5bf7ab
commit fa250f10a2
2 changed files with 117 additions and 26 deletions

View File

@@ -45,8 +45,7 @@ const makeVehicleSearchPayloadFromJob = (job) => {
};
/**
* Normalize customer candidates from VIN blocks
* Adds `vinOwner` (and keeps `isVehicleOwner` for backward compat).
* Normalize customer candidates from VIN/name blocks, including address + owner flag
* @param res
* @param ownersSet
* @returns {any[]}
@@ -54,6 +53,51 @@ const makeVehicleSearchPayloadFromJob = (job) => {
const normalizeCustomerCandidates = (res, { ownersSet = null } = {}) => {
const blocks = Array.isArray(res?.data) ? res.data : Array.isArray(res) ? res : [];
const out = [];
const pickAddr = (addrArr) => {
const arr = Array.isArray(addrArr) ? addrArr : addrArr ? [addrArr] : [];
if (!arr.length) return null;
const chosen = arr.find((a) => (a?.Type || a?.type || "").toString().toUpperCase() === "P") || arr[0];
// NEW: include County
const line1 = chosen?.Addr1 ?? chosen?.AddressLine1 ?? chosen?.Line1 ?? chosen?.Street1 ?? undefined;
const line2 = chosen?.Addr2 ?? chosen?.AddressLine2 ?? chosen?.Line2 ?? chosen?.Street2 ?? undefined;
const city = chosen?.City ?? chosen?.city ?? undefined;
const state = chosen?.State ?? chosen?.StateOrProvince ?? chosen?.state ?? undefined;
const postalCode = chosen?.Zip ?? chosen?.PostalCode ?? chosen?.zip ?? undefined;
const country = chosen?.Country ?? chosen?.CountryCode ?? chosen?.country ?? undefined;
const county = chosen?.County ?? chosen?.county ?? undefined; // << added
// instrumentation (kept minimal; County is now expected)
if ((process.env.RR_DEBUG_ADDR ?? "1") !== "0") {
const allowed = new Set([
"Type",
"Addr1",
"AddressLine1",
"Line1",
"Street1",
"Addr2",
"AddressLine2",
"Line2",
"Street2",
"City",
"State",
"StateOrProvince",
"Zip",
"PostalCode",
"Country",
"CountryCode",
"County" // << allow County
]);
const unknown = Object.keys(chosen || {}).filter((k) => !allowed.has(k));
if (unknown.length) console.log("[RR:normCandidates] Unexpected address keys seen:", unknown);
}
if (!line1 && !city && !state && !postalCode && !country && !county) return null;
return { line1, line2, city, state, postalCode, country, county };
};
for (const blk of blocks) {
const serv = Array.isArray(blk?.ServVehicle) ? blk.ServVehicle : [];
const custNos = serv.map((sv) => sv?.VehicleServInfo?.CustomerNo).filter(Boolean);
@@ -61,35 +105,49 @@ const normalizeCustomerCandidates = (res, { ownersSet = null } = {}) => {
const nci = blk?.NameContactId;
const ind = nci?.NameId?.IndName;
const bus = nci?.NameId?.BusName;
const personal = [ind?.FirstName || ind?.FName, ind?.LastName || ind?.LName].filter(Boolean).join(" ").trim();
const company = bus?.CompanyName || bus?.BName;
const personal = [ind?.FirstName ?? ind?.FName, ind?.LastName ?? ind?.LName].filter(Boolean).join(" ").trim();
const company = bus?.CompanyName ?? bus?.BName;
const name = (personal || company || "").trim();
const address = pickAddr(nci?.Address);
for (const custNo of custNos) {
const cno = String(custNo).trim();
const isOwner = !!(ownersSet && ownersSet.has(cno));
if (!cno) continue;
const item = {
custNo: cno,
name: name || `Customer ${cno}`,
vinOwner: isOwner,
isVehicleOwner: isOwner // legacy key kept for any older FE code
address: address || undefined
};
if (ownersSet && ownersSet.has(cno)) {
item.isVehicleOwner = true;
item.vinOwner = true;
}
out.push(item);
}
}
// Dedup by custNo, keep vinOwner/isVehicleOwner if any
const seen = new Map();
const byId = new Map();
for (const c of out) {
const key = (c.custNo || "").trim();
if (!key) continue;
const prev = seen.get(key);
if (!prev) {
seen.set(key, c);
} else if ((c.vinOwner || c.isVehicleOwner) && !(prev.vinOwner || prev.isVehicleOwner)) {
seen.set(key, { ...prev, vinOwner: true, isVehicleOwner: true });
const prev = byId.get(key);
if (!prev) byId.set(key, c);
else {
byId.set(key, {
...prev,
isVehicleOwner: prev.isVehicleOwner || c.isVehicleOwner,
vinOwner: prev.vinOwner || c.vinOwner,
address: prev.address || c.address
});
}
}
return Array.from(seen.values());
return Array.from(byId.values());
};
/**
@@ -99,12 +157,13 @@ const normalizeCustomerCandidates = (res, { ownersSet = null } = {}) => {
* @returns {string|null}
*/
const readAdvisorNo = (payload, cached) => {
const v =
(payload?.txEnvelope?.advisorNo != null && String(payload.txEnvelope.advisorNo)) ||
(payload?.advisorNo != null && String(payload.advisorNo)) ||
(cached != null && String(cached)) ||
null;
return v && v.trim() !== "" ? v : null;
const tx = payload?.txEnvelope || payload?.envelope || {};
const get = (v) => (v != null && String(v).trim() !== "" ? String(v).trim() : null);
let value = get(tx?.advisorNo) || get(payload?.advisorNo) || get(cached) || null;
return value;
};
/**