Files
bodyshop/server/rr/rr-job-export.js

134 lines
4.2 KiB
JavaScript

/**
* @file rr-job-export.js
* @description Orchestrates the full Reynolds & Reynolds DMS export flow.
* Creates/updates customers, vehicles, and repair orders according to Rome specs.
*/
const { RrCustomerInsert, RrCustomerUpdate } = require("./rr-customer");
const { CreateRepairOrder, UpdateRepairOrder } = require("./rr-repair-orders");
const { MakeRRCall, RRActions, getDealerConfig } = require("./rr-helpers");
const { assertRrOkXml, extractRrResponseData } = require("./rr-error");
const RRLogger = require("./rr-logger");
const { mapServiceVehicleInsert } = require("./rr-mappers");
/**
* Inserts a service vehicle record for the repair order.
* Follows the "Rome Insert Service Vehicle Interface Specification" via SOAP/XML.
*/
async function RrServiceVehicleInsert({ socket, redisHelpers, JobData, dealerConfig }) {
try {
RRLogger(socket, "info", "RR Insert Service Vehicle started", { jobid: JobData?.id });
// Build Mustache variables for server/rr/xml-templates/InsertServiceVehicle.xml
const variables = mapServiceVehicleInsert(JobData, dealerConfig);
const xml = await MakeRRCall({
action: RRActions.InsertServiceVehicle,
body: { template: "InsertServiceVehicle", data: variables },
redisHelpers,
socket,
jobid: JobData.id,
dealerConfig
});
const ok = assertRrOkXml(xml, { apiName: "RR Insert Service Vehicle" });
const normalized = extractRrResponseData(ok, { action: "InsertServiceVehicle" });
RRLogger(socket, "debug", "RR Insert Service Vehicle success", {
jobid: JobData?.id,
vehicleId: normalized?.VehicleId || normalized?.vehicleId
});
return normalized;
} catch (error) {
RRLogger(socket, "error", `RR Insert Service Vehicle failed: ${error.message}`, { jobid: JobData?.id });
throw error;
}
}
/**
* Full DMS export sequence for Reynolds & Reynolds.
*
* 1. Ensure customer exists (insert or update)
* 2. Ensure vehicle exists/linked
* 3. Create or update repair order
*/
async function ExportJobToRR({ socket, redisHelpers, JobData }) {
const jobid = JobData?.id;
const bodyshopId = socket?.bodyshopId || JobData?.bodyshopid;
RRLogger(socket, "info", "Starting RR job export", { jobid, bodyshopId });
try {
// Pull dealer-level overrides once (DB), env/platform secrets come from rr-helpers internally.
const dealerConfig = bodyshopId ? await getDealerConfig(bodyshopId) : {};
//
// STEP 1: CUSTOMER
//
RRLogger(socket, "info", "RR Step 1: Customer check/insert", { jobid });
let rrCustomerResult;
if (JobData?.rr_customer_id) {
rrCustomerResult = await RrCustomerUpdate({
socket,
redisHelpers,
JobData,
existingCustomer: { CustomerId: JobData.rr_customer_id },
patch: JobData.customer_patch
});
} else {
rrCustomerResult = await RrCustomerInsert({ socket, redisHelpers, JobData });
}
//
// STEP 2: VEHICLE
//
RRLogger(socket, "info", "RR Step 2: Vehicle insert", { jobid });
const rrVehicleResult = await RrServiceVehicleInsert({ socket, redisHelpers, JobData, dealerConfig });
//
// STEP 3: REPAIR ORDER
//
RRLogger(socket, "info", "RR Step 3: Repair Order create/update", { jobid });
let rrRepairOrderResult;
if (JobData?.rr_ro_id) {
rrRepairOrderResult = await UpdateRepairOrder({ socket, redisHelpers, JobData });
} else {
rrRepairOrderResult = await CreateRepairOrder({ socket, redisHelpers, JobData });
}
//
// FINALIZE
//
RRLogger(socket, "info", "RR Export completed successfully", {
jobid,
rr_customer_id: rrCustomerResult?.CustomerId || rrCustomerResult?.customerId,
rr_vehicle_id: rrVehicleResult?.VehicleId || rrVehicleResult?.vehicleId,
rr_ro_id: rrRepairOrderResult?.RepairOrderId || rrRepairOrderResult?.repairOrderId
});
return {
success: true,
data: {
customer: rrCustomerResult,
vehicle: rrVehicleResult,
repairOrder: rrRepairOrderResult
}
};
} catch (error) {
RRLogger(socket, "error", `RR job export failed: ${error.message}`, { jobid });
return {
success: false,
error: error.message,
stack: error.stack
};
}
}
module.exports = {
ExportJobToRR,
RrServiceVehicleInsert
};