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

186 lines
5.7 KiB
JavaScript

const path = require("path");
require("dotenv").config({
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
});
const uuid = require("uuid").v4;
const AxiosLib = require("axios").default;
const axios = AxiosLib.create();
const CreateRRLogEvent = require("./rr-logger");
// --- ENV / mode
const isProduction = process.env.NODE_ENV === "production";
// --- Public cache keys (mirrors FortellisCacheEnums)
const RRCacheEnums = {
txEnvelope: "txEnvelope",
SubscriptionMeta: "SubscriptionMeta", // keep shape parity with fortellis if you reuse UI/redis
JobData: "JobData",
DMSVid: "DMSVid", // vehicle id result
DMSVeh: "DMSVeh", // vehicle read
DMSVehCustomer: "DMSVehCustomer",
DMSCustList: "DMSCustList",
DMSCust: "DMSCust",
selectedCustomerId: "selectedCustomerId",
DMSTransHeader: "DMSTransHeader",
transWips: "transWips",
DMSBatchTxn: "DMSBatchTxn",
DmsBatchTxnPost: "DmsBatchTxnPost",
DMSVehHistory: "DMSVehHistory"
};
// --- Transaction namespacing in Redis
const getTransactionType = (jobid) => `rr:${jobid}`;
const defaultRRTTL = 60 * 60;
// --- API catalog (stub URLs: swap in real ones from Rome specs)
const RRActions = {
SearchCustomer: {
apiName: "RR Search Customer",
url: isProduction ? "https://rr.example.com/api/customer/search" : "https://rr-uat.example.com/api/customer/search",
type: "get"
},
ReadCustomer: {
apiName: "RR Read Customer",
url: isProduction ? "https://rr.example.com/api/customer/" : "https://rr-uat.example.com/api/customer/",
type: "get" // append /{id}
},
CreateCustomer: {
apiName: "RR Create Customer",
url: isProduction ? "https://rr.example.com/api/customer" : "https://rr-uat.example.com/api/customer",
type: "post"
},
InsertVehicle: {
apiName: "RR Insert Vehicle",
url: isProduction ? "https://rr.example.com/api/service-vehicle" : "https://rr-uat.example.com/api/service-vehicle",
type: "post"
},
ReadVehicle: {
apiName: "RR Read Vehicle",
url: isProduction
? "https://rr.example.com/api/service-vehicle/"
: "https://rr-uat.example.com/api/service-vehicle/",
type: "get" // append /{vehicleId}
},
GetVehicleId: {
apiName: "RR Get Vehicle Id By VIN",
url: isProduction
? "https://rr.example.com/api/service-vehicle/by-vin/"
: "https://rr-uat.example.com/api/service-vehicle/by-vin/",
type: "get" // append /{vin}
},
StartWip: {
apiName: "RR Start WIP",
url: isProduction ? "https://rr.example.com/api/gl/start-wip" : "https://rr-uat.example.com/api/gl/start-wip",
type: "post"
},
TranBatchWip: {
apiName: "RR Trans Batch WIP",
url: isProduction
? "https://rr.example.com/api/gl/trans-batch-wip"
: "https://rr-uat.example.com/api/gl/trans-batch-wip",
type: "post"
},
PostBatchWip: {
apiName: "RR Post Batch WIP",
url: isProduction
? "https://rr.example.com/api/gl/post-batch-wip"
: "https://rr-uat.example.com/api/gl/post-batch-wip",
type: "post"
},
QueryErrorWip: {
apiName: "RR Query Error WIP",
url: isProduction ? "https://rr.example.com/api/gl/error-wip/" : "https://rr-uat.example.com/api/gl/error-wip/",
type: "get" // append /{transId}
},
ServiceHistoryInsert: {
apiName: "RR Insert Service Vehicle History",
url: isProduction
? "https://rr.example.com/api/service-vehicle-history"
: "https://rr-uat.example.com/api/service-vehicle-history",
type: "post"
}
};
// --- Auth (stub). Replace with RR auth handshake from Rome specs.
async function getRRToken() {
// TODO: implement RR token retrieval (client credentials, basic, or session) per spec
// Return a bearer (or session cookie) string
return process.env.RR_FAKE_TOKEN || "rr-dev-token";
}
// --- URL constructor (same shape as Fortellis)
function constructFullUrl({ url, pathParams = "", requestSearchParams = [] }) {
const base = url.replace(/\/+$/, "/");
const fullPath = pathParams ? `${base}${pathParams}` : base;
const qs = new URLSearchParams(requestSearchParams).toString();
return qs ? `${fullPath}?${qs}` : fullPath;
}
// --- General caller (same ergonomics as MakeFortellisCall)
async function MakeRRCall({
apiName,
url,
headers = {},
body = {},
type = "post",
requestPathParams,
requestSearchParams = [],
debug = true,
jobid,
redisHelpers,
socket
}) {
const ReqId = uuid();
const fullUrl = constructFullUrl({ url, pathParams: requestPathParams, requestSearchParams });
const access_token = await getRRToken();
if (debug) {
console.log(`[RR] ${apiName} | ${type.toUpperCase()} ${fullUrl} | ReqId=${ReqId}`);
if (type !== "get") console.log(`[RR] payload: ${JSON.stringify(body, null, 2)}`);
}
try {
const commonHeaders = {
Authorization: `Bearer ${access_token}`,
"X-Request-Id": ReqId,
...headers
};
let resp;
switch (type) {
case "get":
resp = await axios.get(fullUrl, { headers: commonHeaders });
break;
case "put":
resp = await axios.put(fullUrl, body, { headers: commonHeaders });
break;
case "post":
default:
resp = await axios.post(fullUrl, body, { headers: commonHeaders });
break;
}
if (debug) console.log(`[RR] ${apiName} OK | ReqId=${ReqId}`);
return resp.data;
} catch (error) {
CreateRRLogEvent(socket, "ERROR", `[RR] ${apiName} failed: ${error.message}`, {
reqId: ReqId,
url: fullUrl,
apiName,
errorData: error.response?.data,
errorStatus: error.response?.status,
errorStatusText: error.response?.statusText,
stack: error.stack
});
throw error;
}
}
module.exports = {
RRActions,
MakeRRCall,
RRCacheEnums,
getTransactionType,
defaultRRTTL
};