feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration -Dedupe
This commit is contained in:
@@ -160,36 +160,8 @@ async function rrGetAdvisors(bodyshop, args = {}) {
|
|||||||
return res?.data ?? res;
|
return res?.data ?? res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parts lookup (graceful if the underlying lib exposes a different name)
|
|
||||||
* @param bodyshop
|
|
||||||
* @param args - common fields like { partNumber, description, make, model, year }
|
|
||||||
*/
|
|
||||||
async function rrGetParts(bodyshop, args = {}) {
|
|
||||||
const { client, opts } = buildClientAndOpts(bodyshop);
|
|
||||||
const payload = {
|
|
||||||
partNumber: args.partNumber ?? args.partNo ?? args.number ?? undefined,
|
|
||||||
description: args.description ?? undefined,
|
|
||||||
make: args.make ?? undefined,
|
|
||||||
model: args.model ?? undefined,
|
|
||||||
year: args.year ?? undefined
|
|
||||||
};
|
|
||||||
|
|
||||||
// Try common method names. If none exist, return an empty list to avoid crashes.
|
|
||||||
if (typeof client.getParts === "function") {
|
|
||||||
const res = await client.getParts(payload, opts);
|
|
||||||
return res?.data ?? res;
|
|
||||||
}
|
|
||||||
if (typeof client.getPartNumbers === "function") {
|
|
||||||
const res = await client.getPartNumbers(payload, opts);
|
|
||||||
return res?.data ?? res;
|
|
||||||
}
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
rrCombinedSearch,
|
rrCombinedSearch,
|
||||||
rrGetAdvisors,
|
rrGetAdvisors,
|
||||||
rrGetParts,
|
|
||||||
buildClientAndOpts
|
buildClientAndOpts
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// RR events aligned to Fortellis flow with Fortellis-style logging via CreateRRLogEvent
|
// RR events aligned to Fortellis flow with Fortellis-style logging via CreateRRLogEvent
|
||||||
|
|
||||||
const CreateRRLogEvent = require("../rr/rr-logger-event");
|
const CreateRRLogEvent = require("../rr/rr-logger-event");
|
||||||
const { rrCombinedSearch, rrGetAdvisors, rrGetParts, buildClientAndOpts } = require("../rr/rr-lookup");
|
const { rrCombinedSearch, rrGetAdvisors, buildClientAndOpts } = require("../rr/rr-lookup");
|
||||||
const { QueryJobData } = require("../rr/rr-job-helpers");
|
const { QueryJobData } = require("../rr/rr-job-helpers");
|
||||||
const { exportJobToRR } = require("../rr/rr-job-export");
|
const { exportJobToRR } = require("../rr/rr-job-export");
|
||||||
const CdkCalculateAllocations = require("../cdk/cdk-calculate-allocations").default;
|
const CdkCalculateAllocations = require("../cdk/cdk-calculate-allocations").default;
|
||||||
@@ -46,6 +46,33 @@ function sortVehicleOwnerFirst(list) {
|
|||||||
.map(({ v }) => v);
|
.map(({ v }) => v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NEW: merge candidates coming from multiple queries (name + vin) by custNo.
|
||||||
|
* - keeps first non-empty name
|
||||||
|
* - preserves/ORs vinOwner/isVehicleOwner
|
||||||
|
* - keeps first non-empty address
|
||||||
|
*/
|
||||||
|
function mergeByCustNo(items = []) {
|
||||||
|
const byId = new Map();
|
||||||
|
for (const c of items) {
|
||||||
|
const id = (c?.custNo || "").trim();
|
||||||
|
if (!id) continue;
|
||||||
|
const prev = byId.get(id);
|
||||||
|
if (!prev) {
|
||||||
|
byId.set(id, { ...c, isVehicleOwner: !!(c.vinOwner || c.isVehicleOwner) });
|
||||||
|
} else {
|
||||||
|
byId.set(id, {
|
||||||
|
...prev,
|
||||||
|
name: prev.name || c.name,
|
||||||
|
isVehicleOwner: !!(prev.isVehicleOwner || prev.vinOwner || c.isVehicleOwner || c.vinOwner),
|
||||||
|
vinOwner: !!(prev.vinOwner || c.vinOwner || prev.isVehicleOwner || c.isVehicleOwner),
|
||||||
|
address: prev.address || c.address
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Array.from(byId.values());
|
||||||
|
}
|
||||||
|
|
||||||
async function getSessionOrSocket(redisHelpers, socket) {
|
async function getSessionOrSocket(redisHelpers, socket) {
|
||||||
let sess = null;
|
let sess = null;
|
||||||
try {
|
try {
|
||||||
@@ -142,7 +169,10 @@ async function rrMultiCustomerSearch({ bodyshop, job, socket, redisHelpers }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sortVehicleOwnerFirst(merged);
|
// NEW: dedupe across queries (name + vin)
|
||||||
|
const deduped = mergeByCustNo(merged);
|
||||||
|
|
||||||
|
return sortVehicleOwnerFirst(deduped);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------- register handlers ----------------
|
// ---------------- register handlers ----------------
|
||||||
@@ -253,24 +283,6 @@ function registerRREvents({ socket, redisHelpers }) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// ---------- Parts ----------
|
|
||||||
socket.on("rr-get-parts", async (args = {}, ack) => {
|
|
||||||
try {
|
|
||||||
const { bodyshopId } = await getSessionOrSocket(redisHelpers, socket);
|
|
||||||
const bodyshop = await getBodyshopForSocket({ bodyshopId, socket });
|
|
||||||
CreateRRLogEvent(socket, "DEBUG", "rr-get-parts: begin", { args });
|
|
||||||
const res = await rrGetParts(bodyshop, args);
|
|
||||||
ack?.({ ok: true, result: res });
|
|
||||||
socket.emit("rr-get-parts:result", res);
|
|
||||||
CreateRRLogEvent(socket, "DEBUG", "rr-get-parts: success", {
|
|
||||||
count: Array.isArray(res) ? res.length : undefined
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
CreateRRLogEvent(socket, "ERROR", "rr-get-parts: failed", { error: err?.message });
|
|
||||||
ack?.({ ok: false, error: err?.message || "get parts failed" });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// ================= Fortellis-style two-step export =================
|
// ================= Fortellis-style two-step export =================
|
||||||
// 1) Stage export -> search (Full Name + VIN) -> emit rr-select-customer
|
// 1) Stage export -> search (Full Name + VIN) -> emit rr-select-customer
|
||||||
socket.on("rr-export-job", async ({ jobid, jobId, txEnvelope } = {}) => {
|
socket.on("rr-export-job", async ({ jobid, jobId, txEnvelope } = {}) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user