feature/IO-2968-Parts-Scanning-Extension

This commit is contained in:
Dave Richer
2024-12-10 11:15:24 -08:00
parent cec5f6e6e7
commit b8a298fc28
8 changed files with 311 additions and 119 deletions

View File

@@ -2234,18 +2234,25 @@ exports.QUERY_PARTS_SCAN = `query QUERY_PARTS_SCAN ($id: uuid!) {
id
line_desc
critical
part_type
act_price
part_qty
mod_lbr_ty
mod_lb_hrs
oem_partno
alt_partno
}
}
}`;
exports.UPDATE_PARTS_CRITICAL = `mutation UPDATE_PARTS_CRITICAL ($IdsToMarkCritical:[uuid!]!, $jobid: uuid!){
critical: update_joblines(where:{id:{_in:$IdsToMarkCritical}}, _set:{critical: true}){
exports.UPDATE_PARTS_CRITICAL = `mutation UPDATE_PARTS_CRITICAL ($IdsToMarkCritical:[uuid!]!, $jobid: uuid!) {
critical: update_joblines(where: {id: {_in: $IdsToMarkCritical}}, _set: {critical: true}) {
affected_rows
}
notcritical: update_joblines(where:{id:{_nin:$IdsToMarkCritical}, jobid: {_eq: $jobid}}, _set:{critical: false}){
notcritical: update_joblines(where: {id: {_nin: $IdsToMarkCritical}, jobid: {_eq: $jobid}}, _set: {critical: false}) {
affected_rows
}
}`;
}`
exports.ACTIVE_SHOP_BY_USER = `query ACTIVE_SHOP_BY_USER($user: String) {
associations(where: {active: {_eq: true}, useremail: {_eq: $user}}) {

View File

@@ -1,50 +1,90 @@
const Dinero = require("dinero.js");
const queries = require("../graphql-client/queries");
const logger = require("../utils/logger");
const { job } = require("../scheduling/scheduling-job");
const _ = require("lodash");
// Dinero.defaultCurrency = "USD";
// Dinero.globalLocale = "en-CA";
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) {
console.log('hello')
const { jobid } = req.body;
const BearerToken = req.BearerToken;
const client = req.userGraphQLClient;
logger.log("job-parts-scan", "DEBUG", req.user?.email, jobid, null);
try {
//Query all jobline data using the user's authorization.
const data = await client.setHeaders({ Authorization: BearerToken }).request(queries.QUERY_PARTS_SCAN, {
id: jobid
});
const data = await client.setHeaders({ Authorization: BearerToken }).request(
queries.QUERY_PARTS_SCAN,
{ id: jobid }
);
//Create RegExps once for better performance.
const IdsToMarkCritical = [];
const RegExpressions = data.jobs_by_pk.bodyshop.md_parts_scan.map((r) => new RegExp(r.expression, r.flags));
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.");
}
//Check each line against each regex rule.
data.jobs_by_pk.joblines.forEach((jobline) => {
RegExpressions.forEach((rExp) => {
if (jobline.line_desc.match(rExp)) {
IdsToMarkCritical.push(jobline);
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 } of compiledRules) {
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;
}
});
});
const result = await client.setHeaders({ Authorization: BearerToken }).request(queries.UPDATE_PARTS_CRITICAL, {
IdsToMarkCritical: _.uniqBy(IdsToMarkCritical, "id").map((i) => i.id),
jobid: jobid
});
if (match) {
criticalIds.add(jobline.id);
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, {
logger.log("job-parts-scan-error", "ERROR", req.user?.email, jobid, {
jobid,
error
error: error.message,
});
res.status(400).json(JSON.stringify(error));
res.status(400).json(JSON.stringify({ message: error?.message }));
}
};