101 lines
3.6 KiB
JavaScript
101 lines
3.6 KiB
JavaScript
// server/rr/rr-selected-customer.js
|
|
const RRLogger = require("./rr-logger");
|
|
const { insertCustomer, updateCustomer } = require("./rr-customer");
|
|
const { withClient } = require("./withClient");
|
|
const { QueryJobData, getTransactionType } = require("./rr-job-helpers");
|
|
|
|
/**
|
|
* Selects/creates/updates the RR customer for a job and persists the choice in the session tx.
|
|
* - If selectedCustomerId is given: cache and return.
|
|
* - Else: upsert from the job's current customer data, cache resulting dmsRecKey.
|
|
*/
|
|
async function SelectedCustomer({ socket, jobid, bodyshopId, selectedCustomerId, redisHelpers }) {
|
|
const log = RRLogger(socket);
|
|
|
|
// 1) Load JobData (we'll also use it for bodyshopId if missing)
|
|
const JobData = await QueryJobData({ socket, jobid });
|
|
const resolvedBodyshopId = bodyshopId || JobData?.bodyshop?.id;
|
|
if (!resolvedBodyshopId) throw new Error("Unable to resolve bodyshopId for RR SelectedCustomer");
|
|
|
|
const txKey = getTransactionType(jobid);
|
|
const { setSessionTransactionData, getSessionTransactionData } = redisHelpers || {};
|
|
const current = (await getSessionTransactionData?.(txKey)) || {};
|
|
|
|
// 2) If the UI already chose a DMS customer, just persist it
|
|
if (selectedCustomerId) {
|
|
await setSessionTransactionData?.(txKey, {
|
|
...current,
|
|
selectedCustomerId
|
|
});
|
|
log("info", "RR SelectedCustomer: using provided selectedCustomerId", { selectedCustomerId, jobid });
|
|
return { selectedCustomerId };
|
|
}
|
|
|
|
// 3) Otherwise, upsert based on job's customer info (fallback), and cache the new id.
|
|
const j = JobData || {};
|
|
const c = j.customer || {};
|
|
|
|
if (!c && !j?.vehicle?.vin) {
|
|
log("warn", "RR SelectedCustomer: no customer on job and no VIN; nothing to do", { jobid });
|
|
return { selectedCustomerId: null };
|
|
}
|
|
|
|
// Upsert customer: prefer update if we have a NameRecId; else insert.
|
|
const customerPayload = mapJobCustomerToRR(c);
|
|
const upsert = c?.nameRecId
|
|
? await updateCustomer({ bodyshopId: resolvedBodyshopId, payload: customerPayload })
|
|
: await insertCustomer({ bodyshopId: resolvedBodyshopId, payload: customerPayload });
|
|
|
|
const dmsRecKey =
|
|
upsert?.data?.dmsRecKey ||
|
|
upsert?.data?.DMSRecKey ||
|
|
upsert?.data?.dmsRecKeyId ||
|
|
c?.customerNo ||
|
|
c?.nameRecId ||
|
|
null;
|
|
|
|
// Optionally ensure a ServiceVehicle record exists when VIN present (best effort).
|
|
if (j?.vehicle?.vin) {
|
|
try {
|
|
await withClient(resolvedBodyshopId, async (client, routing) => {
|
|
await client.insertServiceVehicle(
|
|
{ vin: j.vehicle.vin, vehicleServInfo: { customerNo: dmsRecKey } },
|
|
{ routing }
|
|
);
|
|
});
|
|
log("info", "RR SelectedCustomer: ensured ServiceVehicle for VIN", { vin: j.vehicle.vin, dmsRecKey });
|
|
} catch (e) {
|
|
log("warn", `RR SelectedCustomer: insertServiceVehicle skipped (${e.message})`, { vin: j?.vehicle?.vin });
|
|
}
|
|
}
|
|
|
|
// Save in session tx
|
|
await setSessionTransactionData?.(txKey, {
|
|
...current,
|
|
selectedCustomerId: dmsRecKey
|
|
});
|
|
|
|
log("info", "RR SelectedCustomer: upsert complete", { dmsRecKey, jobid });
|
|
return { selectedCustomerId: dmsRecKey };
|
|
}
|
|
|
|
function mapJobCustomerToRR(c = {}) {
|
|
// Mirrors the mapping used by rr-job-export (kept local to avoid cross-module exports)
|
|
return {
|
|
nameRecId: c.nameRecId, // for update path
|
|
firstName: c.firstName || c.given_name,
|
|
lastName: c.lastName || c.family_name || c.last_name,
|
|
phone: c.phone || c.mobile,
|
|
email: c.email,
|
|
address: {
|
|
line1: c.address1 || c.address || c.street,
|
|
line2: c.address2 || "",
|
|
city: c.city,
|
|
state: c.province || c.state,
|
|
postalCode: c.postal || c.zip
|
|
}
|
|
};
|
|
}
|
|
|
|
module.exports = { SelectedCustomer };
|