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 }; // Decide kind if not provided let kind = (q.kind || "").toString().trim(); 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 (typeof q.name === "string" || (q.name && (q.name.fname || q.name.lname || q.name.mname || q.name.name))) { kind = "name"; } else if (q.stkNo || q.stock) kind = "stkNo"; } const payload = { maxResults: q.maxResults || q.maxRecs || 50, kind }; switch ((kind || "").toLowerCase()) { case "phone": payload.kind = "phone"; payload.phone = String(q.phone ?? "").trim(); break; case "license": payload.kind = "license"; payload.license = String(q.license ?? "").trim(); break; case "vin": payload.kind = "vin"; payload.vin = String(q.vin ?? "").trim(); break; case "namerecid": payload.kind = "nameRecId"; payload.nameRecId = String(q.nameRecId ?? q.custId ?? "").trim(); break; case "stkno": case "stkNo": payload.kind = "stkNo"; payload.stkNo = String(q.stkNo ?? q.stock ?? "").trim(); break; case "name": { payload.kind = "name"; const n = q.name; // STRING => last-name-only intent if (typeof n === "string") { const last = n.trim(); if (last) payload.name = { name: last }; // break; } // OBJECT => always treat as FullName (even if only one of the parts is present) const fname = n?.fname && String(n.fname).trim(); const lname = n?.lname && String(n.lname).trim(); const mname = n?.mname && String(n.mname).trim(); const lastOnly = n?.name && String(n.name).trim(); if (fname || lname || mname) { const full = {}; if (fname) full.fname = fname; if (mname) full.mname = mname; if (lname) full.lname = lname; payload.name = full; // will render } else if (lastOnly) { payload.name = { name: lastOnly }; // explicit last-only } break; } default: payload.kind = kind; } if (q.make || q.model || q.year) { payload.make = q.make || "ANY"; payload.model = q.model || "ANY"; payload.year = q.year || "ANY"; } if (q.vin && payload.kind !== "vin") payload.vin = String(q.vin).trim(); if (q.phone && payload.kind !== "phone") payload.phone = String(q.phone).trim(); if (q.license && payload.kind !== "license") payload.license = String(q.license).trim(); 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 };