From 3bc06532300a7f40f63e7d16d27acff6b983ec1d Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 14 Mar 2023 12:29:45 -0700 Subject: [PATCH] IO-2215 Critical Parts scanning. IO-2215 Critical Parts Scanning IO-2215 critical parts scanning --- bodyshop_translations.babel | 89 +++++++++++++++++++ .../job-detail-lines/job-lines.component.jsx | 2 +- .../job-lines-upsert-modal.container.jsx | 13 +++ .../jobs-available-table.container.jsx | 20 ++++- .../shop-info/shop-info.component.jsx | 14 ++- client/src/translations/en_us/common.json | 6 ++ client/src/translations/es/common.json | 6 ++ client/src/translations/fr/common.json | 6 ++ client/src/utils/criticalPartsScan.js | 12 +++ server/parts-scan/parts-scan.js | 17 ++-- 10 files changed, 168 insertions(+), 17 deletions(-) create mode 100644 client/src/utils/criticalPartsScan.js diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 9565bcccb..7d1d27464 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -3665,6 +3665,27 @@ + + addpartsrule + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + addspeedprint false @@ -5453,6 +5474,53 @@ + + md_parts_scan + + + expression + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + flags + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + md_payment_types false @@ -9630,6 +9698,27 @@ + + partsscan + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + printlater false diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx index 66dcc78d5..89debdf45 100644 --- a/client/src/components/job-detail-lines/job-lines.component.jsx +++ b/client/src/components/job-detail-lines/job-lines.component.jsx @@ -348,7 +348,7 @@ export function JobLinesComponent({ onClick={() => { setJobLineEditContext({ actions: { refetch: refetch, submit: form && form.submit }, - context: record, + context: { ...record, jobid: job.id }, }); }} > diff --git a/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx b/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx index f4c7d87a4..7c55046b9 100644 --- a/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx +++ b/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx @@ -14,8 +14,12 @@ import UndefinedToNull from "../../utils/undefinedtonull"; import JobLinesUpdsertModal from "./job-lines-upsert-modal.component"; import Axios from "axios"; import Dinero from "dinero.js"; +import CriticalPartsScan from "../../utils/criticalPartsScan"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import { useTreatments } from "@splitsoftware/splitio-react"; const mapStateToProps = createStructuredSelector({ jobLineEditModal: selectJobLineEditModal, + bodyshop: selectBodyshop, }); const mapDispatchToProps = (dispatch) => ({ toggleModalVisible: () => dispatch(toggleModalVisible("jobLineEdit")), @@ -24,7 +28,13 @@ const mapDispatchToProps = (dispatch) => ({ function JobLinesUpsertModalContainer({ jobLineEditModal, toggleModalVisible, + bodyshop, }) { + const { CriticalPartsScanning } = useTreatments( + ["CriticalPartsScanning"], + {}, + bodyshop.imexshopid + ); const { t } = useTranslation(); const [insertJobLine] = useMutation(INSERT_NEW_JOB_LINE); const [updateJobLine] = useMutation(UPDATE_JOB_LINE); @@ -109,6 +119,9 @@ function JobLinesUpsertModalContainer({ } toggleModalVisible(); } + if (CriticalPartsScanning.treatment === "on") { + CriticalPartsScan(jobLineEditModal.context.jobid); + } setLoading(false); }; diff --git a/client/src/components/jobs-available-table/jobs-available-table.container.jsx b/client/src/components/jobs-available-table/jobs-available-table.container.jsx index 1aba56a47..d632324b5 100644 --- a/client/src/components/jobs-available-table/jobs-available-table.container.jsx +++ b/client/src/components/jobs-available-table/jobs-available-table.container.jsx @@ -3,8 +3,9 @@ import { useApolloClient, useLazyQuery, useMutation, - useQuery, + useQuery } from "@apollo/client"; +import { useTreatments } from "@splitsoftware/splitio-react"; import { Col, notification, Row } from "antd"; import Axios from "axios"; import Dinero from "dinero.js"; @@ -19,7 +20,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils"; import { DELETE_AVAILABLE_JOB, QUERY_AVAILABLE_JOBS, - QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK, + QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK } from "../../graphql/available-jobs.queries"; import { INSERT_NEW_JOB, UPDATE_JOB } from "../../graphql/jobs.queries"; import { INSERT_NEW_NOTE } from "../../graphql/notes.queries"; @@ -27,10 +28,11 @@ import { SEARCH_VEHICLE_BY_VIN } from "../../graphql/vehicles.queries"; import { insertAuditTrail } from "../../redux/application/application.actions"; import { selectBodyshop, - selectCurrentUser, + selectCurrentUser } from "../../redux/user/user.selectors"; import confirmDialog from "../../utils/asyncConfirm"; import AuditTrailMapping from "../../utils/AuditTrailMappings"; +import CriticalPartsScan from "../../utils/criticalPartsScan"; import AlertComponent from "../alert/alert.component"; import JobsAvailableScan from "../jobs-available-scan/jobs-available-scan.component"; import JobsFindModalContainer from "../jobs-find-modal/jobs-find-modal.container"; @@ -53,6 +55,11 @@ export function JobsAvailableContainer({ currentUser, insertAuditTrail, }) { + const { CriticalPartsScanning } = useTreatments( + ["CriticalPartsScanning"], + {}, + bodyshop.imexshopid + ); const { loading, error, data, refetch } = useQuery(QUERY_AVAILABLE_JOBS, { fetchPolicy: "network-only", nextFetchPolicy: "network-only", @@ -155,6 +162,9 @@ export function JobsAvailableContainer({ }, }) .then((r) => { + if (CriticalPartsScanning.treatment === "on") { + CriticalPartsScan(r.data.insert_jobs.returning[0].id); + } notification["success"]({ message: t("jobs.successes.created"), onClick: () => { @@ -241,7 +251,9 @@ export function JobsAvailableContainer({ }, }, }); - + if (CriticalPartsScanning.treatment === "on") { + CriticalPartsScan(updateResult.data.update_jobs.returning[0].id); + } if (updateResult.errors) { //error while inserting notification["error"]({ diff --git a/client/src/components/shop-info/shop-info.component.jsx b/client/src/components/shop-info/shop-info.component.jsx index d166ae5f1..9baeb2c58 100644 --- a/client/src/components/shop-info/shop-info.component.jsx +++ b/client/src/components/shop-info/shop-info.component.jsx @@ -1,3 +1,4 @@ +import { useTreatments } from "@splitsoftware/splitio-react"; import { Button, Card, Tabs } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; @@ -24,6 +25,11 @@ const mapDispatchToProps = (dispatch) => ({ export default connect(mapStateToProps, mapDispatchToProps)(ShopInfoComponent); export function ShopInfoComponent({ bodyshop, form, saveLoading }) { + const { CriticalPartsScanning } = useTreatments( + ["CriticalPartsScanning"], + {}, + bodyshop.imexshopid + ); const { t } = useTranslation(); return ( - - - + {CriticalPartsScanning.treatment === "on" && ( + + + + )} ); diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 29847872b..ab797cddc 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -230,6 +230,7 @@ "addapptcolor": "Add Appointment Color", "addbucket": "Add Definition", "addpartslocation": "Add Parts Location", + "addpartsrule": "Add Parts Scan Rule", "addspeedprint": "Add Speed Print", "addtemplate": "Add Template", "newlaborrate": "New Labor Rate", @@ -331,6 +332,10 @@ "md_jobline_presets": "Jobline Presets", "md_lost_sale_reasons": "Lost Sale Reasons", "md_parts_order_comment": "Parts Orders Comments", + "md_parts_scan": { + "expression": "RegEX Expression", + "flags": "Flags" + }, "md_payment_types": "Payment Types", "md_referral_sources": "Referral Sources", "messaginglabel": "Messaging Preset Label", @@ -581,6 +586,7 @@ "notespresets": "Notes Presets", "orderstatuses": "Order Statuses", "partslocations": "Parts Locations", + "partsscan": "Critical Parts Scanning", "printlater": "Print Later", "qbo": "Use QuickBooks Online?", "qbo_departmentid": "QBO Department ID", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 1ad5220b7..375272c4b 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -230,6 +230,7 @@ "addapptcolor": "", "addbucket": "", "addpartslocation": "", + "addpartsrule": "", "addspeedprint": "", "addtemplate": "", "newlaborrate": "", @@ -331,6 +332,10 @@ "md_jobline_presets": "", "md_lost_sale_reasons": "", "md_parts_order_comment": "", + "md_parts_scan": { + "expression": "", + "flags": "" + }, "md_payment_types": "", "md_referral_sources": "", "messaginglabel": "", @@ -581,6 +586,7 @@ "notespresets": "", "orderstatuses": "", "partslocations": "", + "partsscan": "", "printlater": "", "qbo": "", "qbo_departmentid": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index b6012465a..b727dc0de 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -230,6 +230,7 @@ "addapptcolor": "", "addbucket": "", "addpartslocation": "", + "addpartsrule": "", "addspeedprint": "", "addtemplate": "", "newlaborrate": "", @@ -331,6 +332,10 @@ "md_jobline_presets": "", "md_lost_sale_reasons": "", "md_parts_order_comment": "", + "md_parts_scan": { + "expression": "", + "flags": "" + }, "md_payment_types": "", "md_referral_sources": "", "messaginglabel": "", @@ -581,6 +586,7 @@ "notespresets": "", "orderstatuses": "", "partslocations": "", + "partsscan": "", "printlater": "", "qbo": "", "qbo_departmentid": "", diff --git a/client/src/utils/criticalPartsScan.js b/client/src/utils/criticalPartsScan.js new file mode 100644 index 000000000..11e96b69b --- /dev/null +++ b/client/src/utils/criticalPartsScan.js @@ -0,0 +1,12 @@ +import axios from "axios"; +import { notification } from "antd"; + +async function CriticalPartsScan(jobid) { + try { + await axios.post("/job/partsscan", { jobid }); + } catch (error) { + notification.open({ type: "error", message: JSON.stringify(error) }); + } +} + +export default CriticalPartsScan; diff --git a/server/parts-scan/parts-scan.js b/server/parts-scan/parts-scan.js index d3305f9c6..c5b619303 100644 --- a/server/parts-scan/parts-scan.js +++ b/server/parts-scan/parts-scan.js @@ -3,6 +3,7 @@ const queries = require("../graphql-client/queries"); const { job } = require("../scheduling/scheduling-job"); const GraphQLClient = require("graphql-request").GraphQLClient; const logger = require("../utils/logger"); +const _ = require("lodash"); // Dinero.defaultCurrency = "USD"; // Dinero.globalLocale = "en-CA"; @@ -17,43 +18,41 @@ exports.partsScan = async function (req, res) { }); try { + //Query all jobline data using the user's authorization. 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) ); + //Check each line against each regex rule. data.jobs_by_pk.joblines.forEach((jobline) => { RegExpressions.forEach((rExp) => { if (jobline.line_desc.match(rExp)) { - console.log("Critical Parts Match", jobline.line_desc, rExp); IdsToMarkCritical.push(jobline); } }); }); - console.log(IdsToMarkCritical); - - //Mark off ids not critical and critical. - const result = await client .setHeaders({ Authorization: BearerToken }) .request(queries.UPDATE_PARTS_CRITICAL, { - IdsToMarkCritical: IdsToMarkCritical.map((i) => i.id), + IdsToMarkCritical: _.uniqBy(IdsToMarkCritical, "id").map((i) => i.id), jobid: jobid, }); res.status(200).json(result); } catch (error) { - logger.log("job-parts-scan-error", "ERROR", req.user.email, id, { - jobid: id, + logger.log("job-parts-scan-error", "ERROR", req.user.email, jobid, { + jobid, error, }); - res.status(503).send(); + res.status(400).json(JSON.stringify(error)); } };