diff --git a/server/integrations/partsManagement/partsManagement.queries.js b/server/integrations/partsManagement/partsManagement.queries.js index 45a88ad58..e0ba6088c 100644 --- a/server/integrations/partsManagement/partsManagement.queries.js +++ b/server/integrations/partsManagement/partsManagement.queries.js @@ -32,9 +32,76 @@ const INSERT_JOB_WITH_LINES = ` } `; +const GET_JOB_BY_CLAIM = ` + query GetJobByClaim($shopid: uuid!, $clm_no: String!) { + jobs( + where: { shopid: { _eq: $shopid }, clm_no: { _eq: $clm_no } } + order_by: { created_at: desc } + limit: 1 + ) { + id + } + } +`; + +const UPDATE_JOB_BY_ID = ` + mutation UpdateJobById($id: uuid!, $job: jobs_set_input!) { + update_jobs_by_pk(pk_columns: { id: $id }, _set: $job) { + id + } + } +`; + +const UPSERT_JOBLINES = ` + mutation UpsertJoblines($joblines: [joblines_insert_input!]!) { + insert_joblines( + objects: $joblines + on_conflict: { + constraint: joblines_jobid_line_no_unq_seq_key + update_columns: [ + status + line_desc + part_type + part_qty + oem_partno + db_price + act_price + mod_lbr_ty + mod_lb_hrs + lbr_op + lbr_amt + notes + ] + } + ) { + affected_rows + } + } +`; +const DELETE_JOBLINES_BY_JOBID = ` + mutation DeleteJoblinesByJobId($jobid: uuid!) { + delete_joblines(where: { jobid: { _eq: $jobid } }) { + affected_rows + } + } +`; + +const INSERT_JOBLINES = ` + mutation InsertJoblines($joblines: [joblines_insert_input!]!) { + insert_joblines(objects: $joblines) { + affected_rows + } + } +`; + module.exports = { GET_BODYSHOP_STATUS, GET_VEHICLE_BY_SHOP_VIN, INSERT_OWNER, - INSERT_JOB_WITH_LINES + INSERT_JOB_WITH_LINES, + GET_JOB_BY_CLAIM, + UPDATE_JOB_BY_ID, + DELETE_JOBLINES_BY_JOBID, + UPSERT_JOBLINES, + INSERT_JOBLINES }; diff --git a/server/integrations/partsManagement/partsManagementVehicleDamageEstimateAddRq.js b/server/integrations/partsManagement/partsManagementVehicleDamageEstimateAddRq.js index 1ab8e4e64..ea3803725 100644 --- a/server/integrations/partsManagement/partsManagementVehicleDamageEstimateAddRq.js +++ b/server/integrations/partsManagement/partsManagementVehicleDamageEstimateAddRq.js @@ -9,7 +9,11 @@ const { GET_BODYSHOP_STATUS, GET_VEHICLE_BY_SHOP_VIN, INSERT_OWNER, - INSERT_JOB_WITH_LINES + INSERT_JOB_WITH_LINES, + GET_JOB_BY_CLAIM, + UPDATE_JOB_BY_ID, + INSERT_JOBLINES, + DELETE_JOBLINES_BY_JOBID } = require("./partsManagement.queries"); // Defaults @@ -436,6 +440,18 @@ const extractJobLines = (rq) => { }); }; +/** + * Checks if the request is a supplement or a document portion delta. + * TODO: This is a temporary check, should be replaced with a proper field in the XML. + * @param rq + * @returns {boolean} + */ +const isSupplement = (rq) => { + const docStatus = rq.DocumentInfo?.DocumentStatus; + const historyType = rq.RepairTotalsHistory?.HistoryTotalType; + return docStatus === "S" || historyType === "DocumentPortionDelta"; +}; + /** * Finds an existing vehicle by shopId and VIN. * @param {string} shopId - The bodyshop UUID. @@ -458,6 +474,26 @@ const findExistingVehicle = async (shopId, v_vin, logger) => { return null; }; +/** + * Finds an existing job by shopid and claim number. + * @param shopid + * @param clm_no + * @param logger + * @returns {Promise<*|null>} + */ +const findExistingJob = async (shopid, clm_no, logger) => { + try { + const { jobs } = await client.request(GET_JOB_BY_CLAIM, { + shopid, + clm_no + }); + return jobs?.[0] || null; + } catch (err) { + logger.log("parts-job-fetch-failed", "warn", null, null, { error: err }); + return null; + } +}; + /** * Inserts an owner and returns the owner ID. * @param {object} ownerInput - The owner data to insert. @@ -532,6 +568,21 @@ const partsManagementVehicleDamageEstimateAddRq = async (req, res) => { const joblinesData = extractJobLines(rq); const insuranceData = extractInsuranceData(rq); + // Uncomment for debugging + // console.dir( + // { + // joblinesData, + // lossInfo, + // insuranceData, + // vehicleData, + // ownerData, + // adjusterData, + // repairFacilityData, + // estimatorData + // }, + // { depth: null } + // ); + // Find or create relationships const ownerid = await insertOwner(ownerData, logger); const vehicleid = await findExistingVehicle(shopId, vehicleData.v_vin, logger); @@ -577,6 +628,36 @@ const partsManagementVehicleDamageEstimateAddRq = async (req, res) => { joblines: { data: joblinesData } }; + // Check if this is a supplement or document portion delta. + if (isSupplement(rq)) { + console.log("----------------------IS SUPPLEMENT----------------------"); + const existingJob = await findExistingJob(shopId, clm_no, logger); + if (existingJob) { + const { joblines, ...jobWithoutLines } = jobInput; + + await client.request(UPDATE_JOB_BY_ID, { + id: existingJob.id, + job: jobWithoutLines + }); + + await client.request(DELETE_JOBLINES_BY_JOBID, { + jobid: existingJob.id + }); + + if (joblines?.data?.length) { + const joblinesWithJobId = joblines.data.map((line) => ({ + ...line, + jobid: existingJob.id + })); + + await client.request(INSERT_JOBLINES, { joblines: joblinesWithJobId }); + } + + logger.log("parts-job-updated", "info", existingJob.id); + return res.status(200).json({ success: true, jobId: existingJob.id }); + } + } + // Insert job const { insert_jobs_one: newJob } = await client.request(INSERT_JOB_WITH_LINES, { job: jobInput }); logger.log("parts-job-created", "info", newJob.id, null);