feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration - Expanded Logs / Formatting change

This commit is contained in:
Dave
2025-11-12 17:01:54 -05:00
parent 556cd993b9
commit 90f653c0b7
13 changed files with 444 additions and 254 deletions

View File

@@ -1,8 +1,11 @@
// File: server/rr/rr-customers.js
const { RRClient } = require("./lib/index.cjs");
const { getRRConfigFromBodyshop } = require("./rr-config");
const RRLogger = require("./rr-logger");
/**
* Country code map for normalization
* @type {{US: string, USA: string, "UNITED STATES": string, CA: string, CAN: string, CANADA: string}}
*/
const COUNTRY_MAP = {
US: "US",
USA: "US",
@@ -12,7 +15,12 @@ const COUNTRY_MAP = {
CANADA: "CA"
};
function toCountry2(v) {
/**
* Normalize country input to 2-char code
* @param v
* @returns {*|string}
*/
const toCountry2 = (v) => {
const s = String(v || "")
.trim()
.toUpperCase();
@@ -20,22 +28,38 @@ function toCountry2(v) {
if (COUNTRY_MAP[s]) return COUNTRY_MAP[s];
// fallbacks: prefer 2-char; last resort: take first 2
return s.length === 2 ? s : s.slice(0, 2);
}
};
function normalizePhone(num) {
/**
* Normalize phone number to 10-digit string
* @param num
* @returns {string}
*/
const normalizePhone = (num) => {
const d = String(num || "").replace(/\D/g, "");
const n = d.length === 11 && d.startsWith("1") ? d.slice(1) : d;
return n.slice(0, 10);
}
};
function normalizePostal(pc, country) {
/**
* Normalize postal code based on country
* @param pc
* @param country
* @returns {string}
*/
const normalizePostal = (pc, country) => {
const s = String(pc || "").trim();
if (country === "US") return s.replace(/[^0-9]/g, "").slice(0, 5);
if (country === "CA") return s.toUpperCase().replace(/\s+/g, "").slice(0, 6);
return s;
}
};
function sanitizeRRCustomerPayload(payload = {}) {
/**
* Sanitize RR customer payload (addresses, phones, names)
* @param payload
* @returns {{}}
*/
const sanitizeRRCustomerPayload = (payload = {}) => {
const out = { ...payload };
out.addresses = (payload.addresses || []).map((a) => {
@@ -60,14 +84,14 @@ function sanitizeRRCustomerPayload(payload = {}) {
if (out.lastName) out.lastName = String(out.lastName).trim().slice(0, 30);
return out;
}
};
/**
* Build an RR client + common opts from a bodyshop row
* @param bodyshop
* @returns {{client: *, opts: {routing: {dealerNumber: *, storeNumber: *, areaNumber: *}, envelope: {sender: {component: string, task: string, referenceId: string, creator: string, senderName: string}}}}}
*/
function buildClientAndOpts(bodyshop) {
const buildClientAndOpts = (bodyshop) => {
const cfg = getRRConfigFromBodyshop(bodyshop);
const client = new RRClient({
baseUrl: cfg.baseUrl,
@@ -90,25 +114,25 @@ function buildClientAndOpts(bodyshop) {
}
};
return { client, opts };
}
};
/**
* Strip all non-digit characters from a string
* @param s
* @returns {string}
*/
function digitsOnly(s) {
const digitsOnly = (s) => {
return String(s || "").replace(/\D/g, "");
}
};
/**
* Return a new array with only unique values from the input array
* @param arr
* @returns {any[]}
*/
function uniq(arr) {
const uniq = (arr) => {
return Array.from(new Set(arr));
}
};
/**
* Build RR customer payload from job.ownr_* fields, with optional overrides.
@@ -116,7 +140,7 @@ function uniq(arr) {
* @param overrides
* @returns {{ibFlag: string, firstName, lastName, customerName, createdBy, customerType, addresses: [{type, line1: *, line2, city, state, postalCode, country}], phones: {number: *}[], emails: [{address: string}]}}
*/
function buildCustomerPayloadFromJob(job, overrides = {}) {
const buildCustomerPayloadFromJob = (job, overrides = {}) => {
// Pull ONLY from job.ownr_* fields (no job.customer.*)
const firstName = overrides.firstName ?? job?.ownr_fn ?? undefined;
const lastName = overrides.lastName ?? job?.ownr_ln ?? undefined;
@@ -174,13 +198,13 @@ function buildCustomerPayloadFromJob(job, overrides = {}) {
Object.keys(payload).forEach((k) => payload[k] === undefined && delete payload[k]);
return payload;
}
};
/**
* Create a customer in RR and return { customerNo, raw }.
* Maps data.dmsRecKey -> customerNo for compatibility with existing callers.
*/
async function createRRCustomer({ bodyshop, job, overrides = {}, socket }) {
const createRRCustomer = async ({ bodyshop, job, overrides = {}, socket }) => {
const log = RRLogger(socket, { ns: "rr" });
const { client, opts } = buildClientAndOpts(bodyshop);
const payload = buildCustomerPayloadFromJob(job, overrides);
@@ -213,7 +237,7 @@ async function createRRCustomer({ bodyshop, job, overrides = {}, socket }) {
}
return { customerNo: String(customerNo), raw: data };
}
};
module.exports = {
createRRCustomer