feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration - Checkpoint
This commit is contained in:
@@ -1,143 +1,136 @@
|
||||
/**
|
||||
* @file rr-lookup.js
|
||||
* @description Reynolds & Reynolds lookup operations
|
||||
* (Combined Search, Get Advisors, Get Parts) via SOAP/XML templates.
|
||||
* @description Rome (Reynolds & Reynolds) lookup operations — Advisors, Parts, and CombinedSearch
|
||||
*/
|
||||
|
||||
const { MakeRRCall, RRActions, getDealerConfig } = require("./rr-helpers");
|
||||
const { assertRrOkXml, extractRrResponseData } = require("./rr-error");
|
||||
const { mapCombinedSearchVars, mapGetAdvisorsVars, mapGetPartsVars } = require("./rr-mappers");
|
||||
const { MakeRRCall, parseRRResponse } = require("./rr-helpers");
|
||||
const { mapAdvisorLookup, mapPartsLookup, mapCombinedSearch } = require("./rr-mappers");
|
||||
const RRLogger = require("./rr-logger");
|
||||
const { RrApiError } = require("./rr-error");
|
||||
|
||||
/**
|
||||
* Combined Search
|
||||
* Maps to "Search Customer Service Vehicle Combined" spec (Rome)
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {object} options.socket - Socket or Express req (used for auth + bodyshopId)
|
||||
* @param {object} options.redisHelpers - (unused, kept for parity)
|
||||
* @param {string} options.jobid - Job reference for correlation
|
||||
* @param {Array<[string, string]>} [options.params] - e.g. [["VIN","1HG..."],["LastName","DOE"]]
|
||||
* Get a list of service advisors from Rome.
|
||||
*/
|
||||
async function RrCombinedSearch({ socket, redisHelpers, jobid, params = [] }) {
|
||||
async function getAdvisors(socket, criteria = {}, bodyshopConfig) {
|
||||
const action = "GetAdvisors";
|
||||
const template = "GetAdvisors";
|
||||
|
||||
try {
|
||||
RRLogger(socket, "info", "Starting RR Combined Search", { jobid, params });
|
||||
RRLogger(socket, "info", `Starting RR ${action} lookup`);
|
||||
const data = mapAdvisorLookup(criteria, bodyshopConfig);
|
||||
|
||||
const bodyshopId = socket?.bodyshopId || socket?.user?.bodyshopid;
|
||||
const dealerConfig = bodyshopId ? await getDealerConfig(bodyshopId) : {};
|
||||
|
||||
// Build Mustache variables for server/rr/xml-templates/CombinedSearch.xml
|
||||
const variables = mapCombinedSearchVars({ params, dealerConfig });
|
||||
|
||||
const xml = await MakeRRCall({
|
||||
action: RRActions.CombinedSearch,
|
||||
body: { template: "CombinedSearch", data: variables },
|
||||
redisHelpers,
|
||||
const resultXml = await MakeRRCall({
|
||||
action,
|
||||
body: { template, data },
|
||||
socket,
|
||||
jobid
|
||||
dealerConfig: bodyshopConfig
|
||||
});
|
||||
|
||||
// Validate + normalize
|
||||
const ok = assertRrOkXml(xml, { apiName: "RR Combined Search", allowEmpty: true });
|
||||
const normalized = extractRrResponseData(ok, { action: "CombinedSearch" });
|
||||
const parsed = parseRRResponse(resultXml);
|
||||
if (!parsed.success) throw new RrApiError(parsed.message, parsed.code);
|
||||
|
||||
RRLogger(socket, "debug", "RR Combined Search complete", {
|
||||
jobid,
|
||||
count: Array.isArray(normalized) ? normalized.length : 0
|
||||
});
|
||||
return normalized;
|
||||
const advisors = parsed.parsed?.Advisors?.Advisor || parsed.parsed?.AdvisorList?.Advisor || [];
|
||||
const advisorList = Array.isArray(advisors) ? advisors : [advisors];
|
||||
|
||||
RRLogger(socket, "debug", `${action} lookup returned ${advisorList.length} advisors`);
|
||||
return { success: true, dms: "Rome", action, advisors: advisorList };
|
||||
} catch (error) {
|
||||
RRLogger(socket, "error", `RR Combined Search failed: ${error.message}`, { jobid });
|
||||
throw error;
|
||||
RRLogger(socket, "error", `Error in ${action} lookup`, {
|
||||
message: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
throw new RrApiError(`RR ${action} failed: ${error.message}`, "GET_ADVISORS_ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Advisors
|
||||
* Maps to "Get Advisors Specification" (Rome)
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {object} options.socket
|
||||
* @param {object} options.redisHelpers
|
||||
* @param {string} options.jobid
|
||||
* @param {Array<[string, string]>} [options.params]
|
||||
* Get parts information from Rome.
|
||||
*/
|
||||
async function RrGetAdvisors({ socket, redisHelpers, jobid, params = [] }) {
|
||||
async function getParts(socket, criteria = {}, bodyshopConfig) {
|
||||
const action = "GetParts";
|
||||
const template = "GetParts";
|
||||
|
||||
try {
|
||||
RRLogger(socket, "info", "Starting RR Get Advisors", { jobid, params });
|
||||
RRLogger(socket, "info", `Starting RR ${action} lookup`);
|
||||
const data = mapPartsLookup(criteria, bodyshopConfig);
|
||||
|
||||
const bodyshopId = socket?.bodyshopId || socket?.user?.bodyshopid;
|
||||
const dealerConfig = bodyshopId ? await getDealerConfig(bodyshopId) : {};
|
||||
|
||||
// Build Mustache variables for server/rr/xml-templates/GetAdvisors.xml
|
||||
const variables = mapGetAdvisorsVars({ params, dealerConfig });
|
||||
|
||||
const xml = await MakeRRCall({
|
||||
action: RRActions.GetAdvisors,
|
||||
body: { template: "GetAdvisors", data: variables },
|
||||
redisHelpers,
|
||||
const resultXml = await MakeRRCall({
|
||||
action,
|
||||
body: { template, data },
|
||||
socket,
|
||||
jobid
|
||||
dealerConfig: bodyshopConfig
|
||||
});
|
||||
|
||||
const ok = assertRrOkXml(xml, { apiName: "RR Get Advisors", allowEmpty: true });
|
||||
const normalized = extractRrResponseData(ok, { action: "GetAdvisors" });
|
||||
const parsed = parseRRResponse(resultXml);
|
||||
if (!parsed.success) throw new RrApiError(parsed.message, parsed.code);
|
||||
|
||||
RRLogger(socket, "debug", "RR Get Advisors complete", {
|
||||
jobid,
|
||||
count: Array.isArray(normalized) ? normalized.length : 0
|
||||
});
|
||||
return normalized;
|
||||
const parts = parsed.parsed?.Parts?.Part || parsed.parsed?.PartList?.Part || [];
|
||||
const partList = Array.isArray(parts) ? parts : [parts];
|
||||
|
||||
RRLogger(socket, "debug", `${action} lookup returned ${partList.length} parts`);
|
||||
return { success: true, dms: "Rome", action, parts: partList };
|
||||
} catch (error) {
|
||||
RRLogger(socket, "error", `RR Get Advisors failed: ${error.message}`, { jobid });
|
||||
throw error;
|
||||
RRLogger(socket, "error", `Error in ${action} lookup`, {
|
||||
message: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
throw new RrApiError(`RR ${action} failed: ${error.message}`, "GET_PARTS_ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Parts
|
||||
* Maps to "Get Part Specification" (Rome)
|
||||
*
|
||||
* @param {object} options
|
||||
* @param {object} options.socket
|
||||
* @param {object} options.redisHelpers
|
||||
* @param {string} options.jobid
|
||||
* @param {Array<[string, string]>} [options.params]
|
||||
* Perform a combined customer / vehicle / company search.
|
||||
* Equivalent to Rome CombinedSearchRq / Resp.
|
||||
* @param {Socket} socket
|
||||
* @param {Object} criteria - { VIN, LicensePlate, CustomerName, Phone, Email }
|
||||
* @param {Object} bodyshopConfig
|
||||
* @returns {Promise<Object>} { customers, vehicles, companies }
|
||||
*/
|
||||
async function RrGetParts({ socket, redisHelpers, jobid, params = [] }) {
|
||||
async function combinedSearch(socket, criteria = {}, bodyshopConfig) {
|
||||
const action = "CombinedSearch";
|
||||
const template = "CombinedSearch";
|
||||
|
||||
try {
|
||||
RRLogger(socket, "info", "Starting RR Get Parts", { jobid, params });
|
||||
RRLogger(socket, "info", `Starting RR ${action} request`);
|
||||
const data = mapCombinedSearch(criteria, bodyshopConfig);
|
||||
|
||||
const bodyshopId = socket?.bodyshopId || socket?.user?.bodyshopid;
|
||||
const dealerConfig = bodyshopId ? await getDealerConfig(bodyshopId) : {};
|
||||
|
||||
// Build Mustache variables for server/rr/xml-templates/GetParts.xml
|
||||
const variables = mapGetPartsVars({ params, dealerConfig });
|
||||
|
||||
const xml = await MakeRRCall({
|
||||
action: RRActions.GetParts,
|
||||
body: { template: "GetParts", data: variables },
|
||||
redisHelpers,
|
||||
const resultXml = await MakeRRCall({
|
||||
action,
|
||||
body: { template, data },
|
||||
socket,
|
||||
jobid
|
||||
dealerConfig: bodyshopConfig
|
||||
});
|
||||
|
||||
const ok = assertRrOkXml(xml, { apiName: "RR Get Parts", allowEmpty: true });
|
||||
const normalized = extractRrResponseData(ok, { action: "GetParts" });
|
||||
const parsed = parseRRResponse(resultXml);
|
||||
if (!parsed.success) throw new RrApiError(parsed.message, parsed.code);
|
||||
|
||||
RRLogger(socket, "debug", "RR Get Parts complete", {
|
||||
jobid,
|
||||
count: Array.isArray(normalized) ? normalized.length : 0
|
||||
});
|
||||
return normalized;
|
||||
const customers = parsed.parsed?.Customers?.Customer || [];
|
||||
const vehicles = parsed.parsed?.Vehicles?.ServiceVehicle || [];
|
||||
const companies = parsed.parsed?.Companies?.Company || [];
|
||||
|
||||
const result = {
|
||||
customers: Array.isArray(customers) ? customers : [customers],
|
||||
vehicles: Array.isArray(vehicles) ? vehicles : [vehicles],
|
||||
companies: Array.isArray(companies) ? companies : [companies]
|
||||
};
|
||||
|
||||
RRLogger(
|
||||
socket,
|
||||
"debug",
|
||||
`${action} returned ${result.customers.length} customers, ${result.vehicles.length} vehicles, ${result.companies.length} companies`
|
||||
);
|
||||
return { success: true, dms: "Rome", action, ...result };
|
||||
} catch (error) {
|
||||
RRLogger(socket, "error", `RR Get Parts failed: ${error.message}`, { jobid });
|
||||
throw error;
|
||||
RRLogger(socket, "error", `Error in ${action}`, {
|
||||
message: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
throw new RrApiError(`RR ${action} failed: ${error.message}`, "COMBINED_SEARCH_ERROR");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
RrCombinedSearch,
|
||||
RrGetAdvisors,
|
||||
RrGetParts
|
||||
getAdvisors,
|
||||
getParts,
|
||||
combinedSearch
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user