/** * @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 };