const queries = require("../graphql-client/queries"); const logger = require("../utils/logger"); const predefinedPartTypes = ["PAN", "PAC", "PAR", "PAL", "PAA", "PAM", "PAP", "PAS", "PASL", "PAG"]; const predefinedModLbrTypes = [ "LAA", "LAB", "LAD", "LAE", "LAF", "LAG", "LAM", "LAR", "LAS", "LAU", "LA1", "LA2", "LA3", "LA4" ]; exports.partsScan = async function (req, res) { const { jobid } = req.body; const BearerToken = req.BearerToken; const client = req.userGraphQLClient; logger.log("job-parts-scan", "DEBUG", req.user?.email, jobid, null); try { const data = await client .setHeaders({ Authorization: BearerToken }) .request(queries.QUERY_PARTS_SCAN, { id: jobid }); const rules = data.jobs_by_pk.bodyshop.md_parts_scan || []; if (!Array.isArray(rules)) { // noinspection ExceptionCaughtLocallyJS throw new Error("Invalid md_parts_scan format. Expected an array of rules."); } const compiledRules = rules.map((rule) => ({ ...rule, regex: typeof rule.value === "string" && rule.caseInsensitive ? new RegExp(rule.value, "i") : typeof rule.value === "string" ? new RegExp(rule.value) : null })); const criticalIds = new Set(); for (const jobline of data.jobs_by_pk.joblines) { for (const { field, regex, operation, value, mark_critical, update_field, update_value } of compiledRules) { // IO-3077 - Remove skip as this is extended to include line updates. // if (criticalIds.has(jobline.id)) break; // Skip further evaluation if already critical let jobValue = jobline[field]; let match = false; if (field === "part_number") { match = regex ? regex.test(jobline.oem_partno || "") || regex.test(jobline.alt_partno || "") : jobline.oem_partno === value || jobline.alt_partno === value; } else if (field === "part_type") { match = predefinedPartTypes.includes(value) && value === jobValue; } else if (field === "mod_lbr_ty") { match = predefinedModLbrTypes.includes(value) && value === jobValue; } else if (regex && typeof jobValue === "string") { if (operation === "contains") match = regex.test(jobValue); if (operation === "startsWith") match = new RegExp(`^${value}`).test(jobValue); if (operation === "endsWith") match = new RegExp(`${value}$`).test(jobValue); if (operation === "equals") match = jobValue === value; } else if (typeof jobValue === "number") { if (operation === ">") match = jobValue > value; if (operation === "<") match = jobValue < value; if (operation === "=") match = jobValue === value; } if (match) { if (mark_critical) { //Could technically lead to duplicates, but they'd only be n positives, ultimately leading a positive. criticalIds.add(jobline.id); } if (update_field && update_value) { const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.UPDATE_JOB_LINE, { lineId: jobline.id, line: { [update_field]: update_value, manual_line: true } }); const auditResult = await client .setHeaders({ Authorization: BearerToken }) .request(queries.INSERT_AUDIT_TRAIL, { auditObj: { bodyshopid: data.jobs_by_pk.bodyshop.id, jobid, operation: `Jobline (${jobline.line_desc}/${jobline.id}) ${update_field} updated from ${jobline[update_field]} to ${update_value}. Lined marked as manual line.`, type: "partscanupdate", useremail: req.user.email } }); } //break; // No need to evaluate further rules for this jobline } } } const result = await client .setHeaders({ Authorization: BearerToken }) .request(queries.UPDATE_PARTS_CRITICAL, { IdsToMarkCritical: Array.from(criticalIds), jobid }); res.status(200).json(result); } catch (error) { logger.log("job-parts-scan-error", "ERROR", req.user?.email, jobid, { jobid, error: error.message, stack: error.stack }); res.status(400).json(JSON.stringify({ message: error?.message })); } };