Files
bodyshop/server/rr/rr-lookup.js

167 lines
5.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const { RRClient } = require("./lib/index.cjs");
const { getRRConfigFromBodyshop } = require("./rr-config");
/**
* Build an RR client + common opts from a bodyshop row
*/
function buildClientAndOpts(bodyshop) {
const cfg = getRRConfigFromBodyshop(bodyshop);
const client = new RRClient({
baseUrl: cfg.baseUrl,
username: cfg.username,
password: cfg.password,
timeoutMs: cfg.timeoutMs,
retries: cfg.retries
// optional debug logger already inside lib; leave defaults
});
// Common CallOptions for all ops; routing is CRITICAL for Destination block
const opts = {
routing: cfg.routing,
envelope: {
// You can override these per-call if needed
sender: {
component: "Rome",
task: "CVC",
referenceId: "Query",
creator: "RCI",
senderName: "RCI"
}
// bodId/creationDateTime auto-filled by the client if omitted
}
};
return { client, opts };
}
/**
* Normalize the combined-search arguments into the RR shape.
* We infer `kind` if not provided, based on the first detectable field.
*/
function toCombinedSearchPayload(args = {}) {
const q = { ...args };
let kind = (q.kind || "").toString().trim().toLowerCase();
if (!kind) {
if (q.phone) kind = "phone";
else if (q.license) kind = "license";
else if (q.vin) kind = "vin";
else if (q.nameRecId || q.custId) kind = "namerecid";
else if (q.name && (q.name.fname || q.name.lname || q.name.mname || q.name.name)) kind = "name";
else if (q.stkNo || q.stock) kind = "stkno";
}
// Map loose aliases into the RR builders expected fields
const payload = { maxResults: q.maxResults || q.maxRecs || 50, kind };
switch (kind) {
case "phone":
payload.kind = "phone";
payload.phone = q.phone;
break;
case "license":
payload.kind = "license";
payload.license = q.license;
break;
case "vin":
payload.kind = "vin";
payload.vin = q.vin;
break;
case "namerecid":
payload.kind = "nameRecId";
payload.nameRecId = q.nameRecId || q.custId;
break;
case "name": {
payload.kind = "name";
const name = q.name;
if (name.name) {
payload.name = { name: name.name }; // For LName
} else if (name.fname && name.lname) {
payload.name = {
fname: name.fname,
lname: name.lname,
...(name.mname ? { mname: name.mname } : {})
}; // For FullName
} else if (name.lname) {
payload.name = { name: name.lname }; // Fallback to LName if only lname
} else {
// Invalid; but to handle gracefully, perhaps throw or skip
}
break;
}
case "stkno":
payload.kind = "stkNo";
payload.stkNo = q.stkNo || q.stock;
break;
default:
// Let the RR builder throw the canonical “Unsupported CombinedSearch kind”
payload.kind = q.kind; // may be undefined; RR lib will validate
}
// Add compatible secondary fields for combinations
if (q.vin && kind !== "vin") payload.vin = q.vin;
if (q.phone && kind !== "phone") payload.phone = q.phone;
if (q.license && kind !== "license") payload.license = q.license;
// Optional vehicle narrowing; the RR builder defaults to ANY/ANY/ANY if omitted
if (q.make || q.model || q.year) {
payload.make = q.make || "ANY";
payload.model = q.model || "ANY";
payload.year = q.year || "ANY";
}
return payload;
}
/**
* Combined customer/service/vehicle search
* @param bodyshop - bodyshop row (must include rr_dealerid & rr_configuration with store/branch)
* @param args - search inputs (phone | license | vin | nameRecId | name | stkNo)
*/
async function rrCombinedSearch(bodyshop, args = {}) {
const { client, opts } = buildClientAndOpts(bodyshop);
const payload = toCombinedSearchPayload(args);
const res = await client.combinedSearch(payload, opts);
return res?.data ?? res; // lib returns { success, data, ... }
}
/**
* Advisors lookup
* @param bodyshop
* @param args - { department: 'B'|'S'|'P'|string, advisorNumber?: string }
*/
async function rrGetAdvisors(bodyshop, args = {}) {
const { client, opts } = buildClientAndOpts(bodyshop);
// Allow friendly department values
const dep = (args.department || "").toString().toUpperCase();
const department =
dep === "BODY" || dep === "BODYSHOP" ? "B" : dep === "SERVICE" ? "S" : dep === "PARTS" ? "P" : dep || "B";
const payload = {
department,
advisorNumber: args.advisorNumber ? String(args.advisorNumber) : undefined
};
const res = await client.getAdvisors(payload, opts);
return res?.data ?? res;
}
/**
* Parts on an internal RO
* @param bodyshop
* @param args - { roNumber: string } (ERA/DMS internal RO number)
*/
async function rrGetParts(bodyshop, args = {}) {
const { client, opts } = buildClientAndOpts(bodyshop);
const payload = { roNumber: String(args.roNumber || "").trim() };
const res = await client.getParts(payload, opts);
return res?.data ?? res;
}
module.exports = {
rrCombinedSearch,
rrGetAdvisors,
rrGetParts,
buildClientAndOpts
};