feature/IO-3357-Reynolds-and-Reynolds-DMS-API-Integration - Checkpoint
This commit is contained in:
@@ -91,9 +91,9 @@ async function createRRCustomer({ bodyshop, job, overrides = {}, socket }) {
|
|||||||
const trx = res?.statusBlocks?.transaction;
|
const trx = res?.statusBlocks?.transaction;
|
||||||
|
|
||||||
// Primary: map dmsRecKey -> custNo
|
// Primary: map dmsRecKey -> custNo
|
||||||
let custNo = data?.dmsRecKey;
|
let customerNo = data?.dmsRecKey;
|
||||||
|
|
||||||
if (!custNo) {
|
if (!customerNo) {
|
||||||
log("error", "RR insertCustomer returned no dmsRecKey/custNo", {
|
log("error", "RR insertCustomer returned no dmsRecKey/custNo", {
|
||||||
status: trx?.status,
|
status: trx?.status,
|
||||||
statusCode: trx?.statusCode,
|
statusCode: trx?.statusCode,
|
||||||
@@ -108,10 +108,10 @@ async function createRRCustomer({ bodyshop, job, overrides = {}, socket }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Normalize to string for safety
|
// Normalize to string for safety
|
||||||
custNo = String(custNo);
|
customerNo = String(customerNo);
|
||||||
|
|
||||||
// Preserve existing return shape so callers don’t need changes
|
// Preserve existing return shape so callers don’t need changes
|
||||||
return { custNo, raw: data };
|
return { customerNo, raw: data };
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -14,16 +14,17 @@ async function exportJobToRR(args) {
|
|||||||
const log = RRLogger(socket, { ns: "rr-export" });
|
const log = RRLogger(socket, { ns: "rr-export" });
|
||||||
|
|
||||||
if (!bodyshop) throw new Error("exportJobToRR: bodyshop is required");
|
if (!bodyshop) throw new Error("exportJobToRR: bodyshop is required");
|
||||||
|
|
||||||
if (!job) throw new Error("exportJobToRR: job is required");
|
if (!job) throw new Error("exportJobToRR: job is required");
|
||||||
|
|
||||||
if (advisorNo == null || String(advisorNo).trim() === "") {
|
if (advisorNo == null || String(advisorNo).trim() === "") {
|
||||||
throw new Error("exportJobToRR: advisorNo is required for RR");
|
throw new Error("exportJobToRR: advisorNo is required for RR");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now strictly require custNo here
|
// Resolve customer number (accept multiple shapes)
|
||||||
const custNo =
|
const selected = selectedCustomer?.customerNo;
|
||||||
(selectedCustomer && (selectedCustomer.custNo || selectedCustomer.CustNo || selectedCustomer.customerNo)) ||
|
|
||||||
(typeof selectedCustomer === "string" || typeof selectedCustomer === "number" ? String(selectedCustomer) : null);
|
if (!selected) throw new Error("exportJobToRR: selectedCustomer.custNo/customerNo is required");
|
||||||
if (!custNo) throw new Error("exportJobToRR: selectedCustomer.custNo is required");
|
|
||||||
|
|
||||||
const { client, opts } = buildClientAndOpts(bodyshop);
|
const { client, opts } = buildClientAndOpts(bodyshop);
|
||||||
const finalOpts = {
|
const finalOpts = {
|
||||||
@@ -42,7 +43,14 @@ async function exportJobToRR(args) {
|
|||||||
let svId = null;
|
let svId = null;
|
||||||
if (!existing?.dmsRepairOrderId) {
|
if (!existing?.dmsRepairOrderId) {
|
||||||
try {
|
try {
|
||||||
const svRes = await ensureRRServiceVehicle({ bodyshop, custNo, job, overrides: {}, socket });
|
// Provide both customerNo and custNo for safety
|
||||||
|
const svRes = await ensureRRServiceVehicle({
|
||||||
|
bodyshop,
|
||||||
|
job,
|
||||||
|
overrides: {},
|
||||||
|
customerNo: String(selected),
|
||||||
|
socket
|
||||||
|
});
|
||||||
svId = svRes?.svId || null;
|
svId = svRes?.svId || null;
|
||||||
log("info", "RR service vehicle ensured", { created: svRes?.created, svId });
|
log("info", "RR service vehicle ensured", { created: svRes?.created, svId });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -50,10 +58,11 @@ async function exportJobToRR(args) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Build RO payload (now includes both customerNo & custNo; advisorNo & advNo)
|
||||||
const payload = buildRRRepairOrderPayload({
|
const payload = buildRRRepairOrderPayload({
|
||||||
job,
|
job,
|
||||||
selectedCustomer: { custNo },
|
selectedCustomer: { customerNo: String(selected) },
|
||||||
advisorNo
|
advisorNo: String(advisorNo)
|
||||||
});
|
});
|
||||||
|
|
||||||
const rrRes = existing?.dmsRepairOrderId
|
const rrRes = existing?.dmsRepairOrderId
|
||||||
@@ -69,7 +78,7 @@ async function exportJobToRR(args) {
|
|||||||
statusBlocks: rrRes?.statusBlocks || [],
|
statusBlocks: rrRes?.statusBlocks || [],
|
||||||
xml: rrRes?.xml,
|
xml: rrRes?.xml,
|
||||||
parsed: rrRes?.parsed,
|
parsed: rrRes?.parsed,
|
||||||
custNo,
|
customerNo: String(selected),
|
||||||
svId
|
svId
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,3 @@
|
|||||||
// server/rr/rr-job-helpers.js
|
|
||||||
// Utilities to fetch and map job data into RR payloads using the shared Hasura client.
|
|
||||||
|
|
||||||
const client = require("../graphql-client/graphql-client").client;
|
const client = require("../graphql-client/graphql-client").client;
|
||||||
const { GET_JOB_BY_PK } = require("../graphql-client/queries");
|
const { GET_JOB_BY_PK } = require("../graphql-client/queries");
|
||||||
|
|
||||||
@@ -52,33 +49,28 @@ async function QueryJobData(ctx = {}, jobId) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Build minimal RR RO payload (keys match your RR client’s expectations).
|
|
||||||
* Uses fields that exist in your schema (v_vin, ro_number, owner fields, etc).
|
|
||||||
*/
|
|
||||||
/**
|
/**
|
||||||
* Build minimal RR RO payload (keys match RR client expectations).
|
* Build minimal RR RO payload (keys match RR client expectations).
|
||||||
* - Requires advisorNo (maps to advNo)
|
* - Requires advisor number and customer number.
|
||||||
* - Uses custNo (normalized) and a cleaned VIN (17 chars, A–Z/0–9)
|
* - We provide BOTH "customerNo" and "custNo" (and BOTH "advisorNo" and "advNo")
|
||||||
|
* to be compatible with the compiled RR CJS lib which currently requires
|
||||||
|
* "customerNo (or CustNo)".
|
||||||
*/
|
*/
|
||||||
function buildRRRepairOrderPayload({ job, selectedCustomer, advisorNo }) {
|
function buildRRRepairOrderPayload({ job, selectedCustomer, advisorNo }) {
|
||||||
// Resolve custNo from object or primitive
|
// Resolve customerNo from object or primitive; accept multiple incoming shapes
|
||||||
const custNoRaw =
|
|
||||||
(selectedCustomer &&
|
|
||||||
(selectedCustomer.custNo ||
|
|
||||||
selectedCustomer.customerNo || // legacy alias, normalized below
|
|
||||||
selectedCustomer.CustNo)) ||
|
|
||||||
(typeof selectedCustomer === "string" || typeof selectedCustomer === "number" ? String(selectedCustomer) : null);
|
|
||||||
|
|
||||||
const custNo = custNoRaw ? String(custNoRaw).trim() : null;
|
const customerNo = selectedCustomer?.customerNo ? String(selectedCustomer?.customerNo).trim() : null;
|
||||||
if (!custNo) throw new Error("No RR customer selected (custNo missing)");
|
|
||||||
|
|
||||||
// Advisor is required for RR
|
if (!customerNo) throw new Error("No RR customer selected (customerNo/CustNo missing)");
|
||||||
const advNo = advisorNo != null && String(advisorNo).trim() !== "" ? String(advisorNo).trim() : null;
|
|
||||||
if (!advNo) throw new Error("advisorNo is required for RR export");
|
// Advisor number (accepts advisorNo string, map to both keys)
|
||||||
|
const adv = advisorNo != null && String(advisorNo).trim() !== "" ? String(advisorNo).trim() : null;
|
||||||
|
|
||||||
|
if (!adv) throw new Error("advisorNo is required for RR export");
|
||||||
|
|
||||||
// Clean/normalize VIN if present
|
// Clean/normalize VIN if present
|
||||||
const vinRaw = job?.v_vin || job?.vehicle?.vin || job?.vin;
|
const vinRaw = job?.v_vin;
|
||||||
|
|
||||||
const vin =
|
const vin =
|
||||||
typeof vinRaw === "string"
|
typeof vinRaw === "string"
|
||||||
? vinRaw
|
? vinRaw
|
||||||
@@ -88,17 +80,17 @@ function buildRRRepairOrderPayload({ job, selectedCustomer, advisorNo }) {
|
|||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
// Pick a stable external RO number
|
// Pick a stable external RO number
|
||||||
const ro =
|
const ro = job?.ro_number != null ? job.ro_number : job?.id != null ? job.id : null;
|
||||||
job?.ro_number != null ? job.ro_number : job?.job_number != null ? job.job_number : job?.id != null ? job.id : null;
|
|
||||||
|
|
||||||
if (ro == null) throw new Error("Missing repair order identifier (ro_number/job_number/id).");
|
if (ro == null) throw new Error("Missing repair order identifier (ro_number/job_number/id)");
|
||||||
|
|
||||||
|
// Provide superset of keys for maximum compatibility with the RR client
|
||||||
return {
|
return {
|
||||||
repairOrderNumber: String(ro),
|
repairOrderNumber: String(ro),
|
||||||
deptType: "B",
|
deptType: "B",
|
||||||
vin, // undefined if absent/empty after cleaning
|
vin,
|
||||||
custNo: String(custNo),
|
customerNo: String(customerNo),
|
||||||
advNo // mapped from advisorNo
|
advisorNo: adv
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,6 +162,8 @@ function normalizeCustomerCandidates(res) {
|
|||||||
*/
|
*/
|
||||||
function normalizeVehicleCandidates(res) {
|
function normalizeVehicleCandidates(res) {
|
||||||
const blocks = blocksFromCombinedSearchResult(res);
|
const blocks = blocksFromCombinedSearchResult(res);
|
||||||
|
console.log("Normalized vehicle Candiadates!!!!!!!!!!!!!!!!!!!!!");
|
||||||
|
console.dir({ res, blocks }, { depth: null });
|
||||||
const out = [];
|
const out = [];
|
||||||
for (const blk of blocks) {
|
for (const blk of blocks) {
|
||||||
const serv = Array.isArray(blk?.ServVehicle) ? blk.ServVehicle : [];
|
const serv = Array.isArray(blk?.ServVehicle) ? blk.ServVehicle : [];
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ function buildClientAndOpts(bodyshop) {
|
|||||||
|
|
||||||
function buildServiceVehiclePayload({ job, custNo, overrides = {} }) {
|
function buildServiceVehiclePayload({ job, custNo, overrides = {} }) {
|
||||||
return {
|
return {
|
||||||
custNo: String(custNo), // tie SV to customer
|
customerNo: String(custNo), // tie SV to customer
|
||||||
vin: overrides.vin ?? job?.v_vin,
|
vin: overrides.vin ?? job?.v_vin,
|
||||||
year: overrides.year ?? job?.v_model_yr,
|
year: overrides.year ?? job?.v_model_yr,
|
||||||
make: overrides.make ?? job?.dms_make ?? job?.v_make,
|
make: overrides.make ?? job?.v_make_des,
|
||||||
model: overrides.model ?? job?.dms_model ?? job?.v_model,
|
model: overrides.model ?? job?.v_model_desc,
|
||||||
licensePlate: overrides.plate ?? job?.plate_no
|
licensePlate: overrides.plate ?? job?.plate_no
|
||||||
// add other safe keys your RR client supports (color, mileage, etc.)
|
// add other safe keys your RR client supports (color, mileage, etc.)
|
||||||
};
|
};
|
||||||
@@ -68,9 +68,6 @@ async function ensureRRServiceVehicle({ bodyshop, custNo, job, overrides = {}, s
|
|||||||
|
|
||||||
const payload = buildServiceVehiclePayload({ job, custNo, overrides });
|
const payload = buildServiceVehiclePayload({ job, custNo, overrides });
|
||||||
|
|
||||||
console.log("Inserting RR Service Vehicle with payload:");
|
|
||||||
console.dir({ payload }, { depth: null });
|
|
||||||
|
|
||||||
const res = await client.insertServiceVehicle(payload, opts);
|
const res = await client.insertServiceVehicle(payload, opts);
|
||||||
const data = res?.data ?? res;
|
const data = res?.data ?? res;
|
||||||
|
|
||||||
|
|||||||
@@ -315,9 +315,7 @@ function registerRREvents({ socket, redisHelpers }) {
|
|||||||
if (create === true || !selectedCustNo) {
|
if (create === true || !selectedCustNo) {
|
||||||
CreateRRLogEvent(socket, "DEBUG", `{3.1} Creating RR customer`);
|
CreateRRLogEvent(socket, "DEBUG", `{3.1} Creating RR customer`);
|
||||||
const created = await createRRCustomer({ bodyshop, job, socket });
|
const created = await createRRCustomer({ bodyshop, job, socket });
|
||||||
selectedCustNo = String(
|
selectedCustNo = String(created?.customerNo);
|
||||||
created?.custNo || created?.customerNo || created?.CustomerNo || created?.dmsRecKey || ""
|
|
||||||
);
|
|
||||||
if (!selectedCustNo) throw new Error("RR create customer returned no custNo");
|
if (!selectedCustNo) throw new Error("RR create customer returned no custNo");
|
||||||
CreateRRLogEvent(socket, "DEBUG", `{3.2} Created customer`, { custNo: selectedCustNo });
|
CreateRRLogEvent(socket, "DEBUG", `{3.2} Created customer`, { custNo: selectedCustNo });
|
||||||
}
|
}
|
||||||
@@ -350,7 +348,7 @@ function registerRREvents({ socket, redisHelpers }) {
|
|||||||
const result = await exportJobToRR({
|
const result = await exportJobToRR({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
job,
|
job,
|
||||||
selectedCustomer: { custNo: String(selectedCustNo) },
|
selectedCustomer: { customerNo: String(selectedCustNo), custNo: String(selectedCustNo) },
|
||||||
advisorNo: String(advisorNo),
|
advisorNo: String(advisorNo),
|
||||||
existing: txEnvelope?.existing,
|
existing: txEnvelope?.existing,
|
||||||
socket
|
socket
|
||||||
|
|||||||
Reference in New Issue
Block a user