diff --git a/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx b/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx
index dcfbad6d4..4ae308f57 100644
--- a/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx
+++ b/client/src/components/dms-customer-selector/dms-customer-selector.component.jsx
@@ -28,11 +28,38 @@ function normalizeRrList(list) {
(custNo ? String(custNo) : "");
if (!custNo) return null;
const vinOwner = !!(row.vinOwner ?? row.isVehicleOwner);
- return { custNo: String(custNo), name, vinOwner };
+
+ // Pass through address from backend if present; tolerate various shapes
+ const address =
+ row.address && typeof row.address === "object"
+ ? {
+ line1: row.address.line1 ?? row.address.addr1 ?? row.address.Address1 ?? undefined,
+ line2: row.address.line2 ?? row.address.addr2 ?? row.address.Address2 ?? undefined,
+ city: row.address.city ?? undefined,
+ state: row.address.state ?? row.address.stateOrProvince ?? undefined,
+ postalCode: row.address.postalCode ?? row.address.zip ?? undefined,
+ country: row.address.country ?? row.address.countryCode ?? undefined
+ }
+ : undefined;
+
+ return { custNo: String(custNo), name, vinOwner, address };
})
.filter(Boolean);
}
+// Small formatter used by the RR Address column render
+function rrAddressToString(addr) {
+ if (!addr) return "";
+ const parts = [
+ addr.line1,
+ addr.line2,
+ [addr.city, addr.state].filter(Boolean).join(" "),
+ addr.postalCode,
+ addr.country
+ ].filter(Boolean);
+ return parts.join(", ");
+}
+
export function DmsCustomerSelector({ bodyshop, jobid }) {
const { t } = useTranslation();
const [customerList, setcustomerList] = useState([]);
@@ -278,6 +305,12 @@ export function DmsCustomerSelector({ bodyshop, jobid }) {
const rrColumns = [
{ title: t("jobs.fields.dms.id"), dataIndex: "custNo", key: "custNo" },
+ {
+ title: t("jobs.fields.dms.vinowner"),
+ dataIndex: "vinOwner",
+ key: "vinOwner",
+ render: (_t, r) =>
+ },
{
title: t("jobs.fields.dms.name1"),
dataIndex: "name",
@@ -285,10 +318,9 @@ export function DmsCustomerSelector({ bodyshop, jobid }) {
sorter: (a, b) => alphaSort(a?.name, b?.name)
},
{
- title: t("jobs.fields.dms.vinowner"),
- dataIndex: "vinOwner",
- key: "vinOwner",
- render: (_t, r) =>
+ title: t("jobs.fields.dms.address"),
+ key: "address",
+ render: (record) => rrAddressToString(record.address)
}
];
diff --git a/server/rr/rr-utils.js b/server/rr/rr-utils.js
index 0569b20f7..b6f73cdf4 100644
--- a/server/rr/rr-utils.js
+++ b/server/rr/rr-utils.js
@@ -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;
};
/**