// ----------------------------------------------------------------------------- // RR (Reynolds & Reynolds) HTTP routes // - Mirrors /cdk shape so the UI can switch providers with minimal changes // - Uses validateFirebaseIdTokenMiddleware + withUserGraphQLClientMiddleware // - Calls into rr/* modules which wrap MakeRRCall from rr-helpers // // TODO:RR — As you wire the real RR endpoints + schemas, adjust the request // bodies, query params, and response normalization inside rr/* files. // ----------------------------------------------------------------------------- const express = require("express"); const router = express.Router(); const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware"); const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware"); const { RrCombinedSearch, RrGetAdvisors, RrGetParts } = require("../rr/rr-lookup"); const { RrCustomerInsert, RrCustomerUpdate } = require("../rr/rr-customer"); // NOTE: correct filename is rr-repair-orders.js (plural) const { CreateRepairOrder, UpdateRepairOrder } = require("../rr/rr-repair-orders"); // Require auth on all RR routes (keep parity with /cdk) router.use(validateFirebaseIdTokenMiddleware); // ----------------------------------------------------------------------------- // Accounting parity / scaffolding // ----------------------------------------------------------------------------- // Reuse CDK allocations for now; keep the endpoint name identical to /cdk router.post("/calculate-allocations", withUserGraphQLClientMiddleware, async (req, res) => { try { const CalculateAllocations = require("../cdk/cdk-calculate-allocations").default; const result = await CalculateAllocations(req, req.body.jobid, true); // verbose=true (like Fortellis flow) res.status(200).json({ data: result }); } catch (e) { req.logger?.log("rr-calc-allocations-route", "ERROR", "api", "rr", { message: e.message, stack: e.stack }); res.status(500).json({ error: e.message }); } }); // Placeholder for a future RR "get vehicles" endpoint to match /cdk/getvehicles router.post("/getvehicles", withUserGraphQLClientMiddleware, async (_req, res) => { res.status(501).json({ error: "RR getvehicles not implemented yet" }); }); // ----------------------------------------------------------------------------- // Lookup endpoints // ----------------------------------------------------------------------------- // GET /rr/lookup/combined?vin=...&lastName=... router.get("/lookup/combined", async (req, res) => { try { const params = Object.entries(req.query); // [["vin","..."], ["lastName","..."]] const data = await RrCombinedSearch({ socket: req, redisHelpers: req.sessionUtils, jobid: "ad-hoc", params }); res.status(200).json({ data }); } catch (e) { req.logger?.log("rr-lookup-combined", "ERROR", "api", "rr", { message: e.message, stack: e.stack }); res.status(500).json({ error: e.message }); } }); // GET /rr/advisors?locationId=... router.get("/advisors", async (req, res) => { try { const params = Object.entries(req.query); const data = await RrGetAdvisors({ socket: req, redisHelpers: req.sessionUtils, jobid: "ad-hoc", params }); res.status(200).json({ data }); } catch (e) { req.logger?.log("rr-get-advisors", "ERROR", "api", "rr", { message: e.message, stack: e.stack }); res.status(500).json({ error: e.message }); } }); // GET /rr/parts?partNumber=...&make=... router.get("/parts", async (req, res) => { try { const params = Object.entries(req.query); const data = await RrGetParts({ socket: req, redisHelpers: req.sessionUtils, jobid: "ad-hoc", params }); res.status(200).json({ data }); } catch (e) { req.logger?.log("rr-get-parts", "ERROR", "api", "rr", { message: e.message, stack: e.stack }); res.status(500).json({ error: e.message }); } }); // ----------------------------------------------------------------------------- // Customer endpoints // ----------------------------------------------------------------------------- // POST /rr/customer/insert // Body: { ...JobData-like shape used by rr-mappers } router.post("/customer/insert", async (req, res) => { try { const data = await RrCustomerInsert({ socket: req, redisHelpers: req.sessionUtils, JobData: req.body }); res.status(200).json({ data }); } catch (e) { req.logger?.log("rr-customer-insert", "ERROR", "api", "rr", { message: e.message, stack: e.stack }); res.status(500).json({ error: e.message }); } }); // PUT /rr/customer/update/:id // Body: { JobData, existingCustomer, patch } router.put("/customer/update/:id", async (req, res) => { try { const data = await RrCustomerUpdate({ socket: req, redisHelpers: req.sessionUtils, JobData: req.body?.JobData, existingCustomer: req.body?.existingCustomer, patch: req.body?.patch }); res.status(200).json({ data }); } catch (e) { req.logger?.log("rr-customer-update", "ERROR", "api", "rr", { message: e.message, stack: e.stack }); res.status(500).json({ error: e.message }); } }); // ----------------------------------------------------------------------------- // Repair Order endpoints // ----------------------------------------------------------------------------- // POST /rr/repair-order/create // Body: { JobData, txEnvelope } router.post("/repair-order/create", async (req, res) => { try { const data = await CreateRepairOrder({ socket: req, redisHelpers: req.sessionUtils, JobData: req.body?.JobData, txEnvelope: req.body?.txEnvelope }); res.status(200).json({ data }); } catch (e) { req.logger?.log("rr-ro-create", "ERROR", "api", "rr", { message: e.message, stack: e.stack }); res.status(500).json({ error: e.message }); } }); // PUT /rr/repair-order/update/:id // Body: { JobData, txEnvelope } router.put("/repair-order/update/:id", async (req, res) => { try { const data = await UpdateRepairOrder({ socket: req, redisHelpers: req.sessionUtils, JobData: req.body?.JobData, txEnvelope: req.body?.txEnvelope }); res.status(200).json({ data }); } catch (e) { req.logger?.log("rr-ro-update", "ERROR", "api", "rr", { message: e.message, stack: e.stack }); res.status(500).json({ error: e.message }); } }); module.exports = router;