diff --git a/electron/changelog.json b/electron/changelog.json index 0e4f78f..d02278b 100644 --- a/electron/changelog.json +++ b/electron/changelog.json @@ -98,5 +98,10 @@ "title": "Release Notes for 1.0.28", "date": "05/26/2022", "notes": "Bug Fix: \n- Improved SUV detection." + }, + "1.1.0": { + "title": "Release Notes for 1.1.0", + "date": "TBD", + "notes": "Bug Fix: \n- Improved vehicle detection.\n- Updates for MPIs new rule base effective in 2023.\n- Security updates." } } diff --git a/electron/decoder/decoder.js b/electron/decoder/decoder.js index 86404ca..0629c25 100644 --- a/electron/decoder/decoder.js +++ b/electron/decoder/decoder.js @@ -27,7 +27,7 @@ async function ImportJob(path) { }); } else { log.info(`Ignored job. ${newJob.ERROR}`); - // Nucleus.track("IGNORE_JOB", { reason: newJob.ERROR }); + // Nucleus.track("IGNORE_JOB", { reason: newJob.ERROR }); NewNotification({ title: "Job Ignored", body: newJob.ERROR, @@ -345,177 +345,17 @@ async function DecodeLinFile(extensionlessFilePath) { } ); }); - // .filter( - // (jobline) => - // jobline.part_type && - // !jobline.db_ref.startsWith("900") && - // !jobline.line_desc.toLowerCase().startsWith("urethane") && - // !jobline.line_desc.toLowerCase().startsWith("wheel") && - // !jobline.line_desc.toLowerCase().startsWith("hazardous") && - // !jobline.line_desc.toLowerCase().startsWith("detail") && - // !jobline.line_desc.toLowerCase().startsWith("clean") && - // jobline.part_type.toUpperCase() !== "PAG" && - // jobline.part_type.toUpperCase() !== "PAS" && - // jobline.part_type.toUpperCase() !== "PASL" && - // jobline.part_type.toUpperCase() !== "PAE" && - // jobline.glass_flag === false - // ) + + //Apply ruleset. joblines.map((jobline) => { - //Removed as a result of conversation with Norm. - // Appears you are calculating based on ‘N.A.’ part values in the Mitchell database. - // Reminder – if Mitchell DB has $0.00 price updates can be tracked, if it has N.A. it cannot calculate RPS value. - - //Removed as a part of $0db removal on 12/17/2022. - // if ( - // (jobline.db_price === null || jobline.db_price === 0) && - // !!jobline.act_price && - // jobline.act_price > 0 - // ) { - // // log.info( - // // "DB Price null/lower than act price", - // // jobline.line_desc, - // // jobline.db_price, - // // jobline.act_price - // // ); - // jobline.db_price = jobline.act_price; - // } - - //*****TODO LINE**** - //Any PAL, Remanufactured, Recycled, Aftermarket, Used, - // If DB Price 0, ignore them. - // if ( - // (jobline.part_type === "PAL" || - // jobline.part_type === "PAM" || - // jobline.part_type === "PAR" || - // jobline.part_type === "PAA") && - // jobline.db_price === 0 - // ) { - // jobline.ignore = true; - // } - jobline.ignore = false; - //Wheel Repair Pricing PRS-82 - //Verified on 08/24/21 - if ( - jobline.part_type === "PAN" && - jobline.line_desc.toLowerCase().includes("wheel") && - Math.abs(jobline.prt_dsmk_m) === - Math.round((jobline.act_price / 2) * 100) / 100 - ) { - log.info(`Jobline '${jobline.line_desc}' ignored due to wheel repair.`); - jobline.ignore = true; + if (false) { + jobline = V2Ruleset(jobline); + } else { + jobline = V1Ruleset(jobline); } - - //RPS-46 Ignore NA Line Items. - //Removed on 05/20. We are seeing more $0DB lines than NA lines and they are getting incorrectly ignored. - // if ( - // jobline.part_type === "PAN" && - // jobline.price_j === true && - // jobline.db_price === 0 - // ) { - // jobline.ignore = true; - // } - - //RPS-39 - OEM ON OEM SAVINGS - //Verified on 08/24/21 - if ( - jobline.part_type === "PAN" && - jobline.db_price !== jobline.act_price && - jobline.db_price !== 0 - ) { - jobline.db_price = jobline.act_price; - } - - //Remove all $0DB line items 02/17/2022. - if ( - (jobline.part_type === "PAA" || - jobline.part_type === "PAL" || - jobline.part_type === "PAN") && - jobline.db_price === 0 - ) { - jobline.ignore = true; - } - - //05/20 - //We’ll have to apply a rule that will not count any A/M, Reman or new part price that is manually changed to $0.00. - //Only recycled parts that are changed to $0.00 can be counted towards RPS. - // This is separate from $0.00 DB prices that need to be updated to the manually entered price. - //Verified on 08/24/21 - if ( - jobline.part_type !== "PAL" && - jobline.act_price === 0 && - jobline.price_j - ) { - log.info( - `Jobline '${jobline.line_desc}' ignored because it was manually changed to 0..` - ); - jobline.ignore = true; - } - - //08/24/21 - Norm to take as action item to determine what the final set of rules were per Derek. - // if (jobline.glass_flag && jobline.part_type !== "PAL") { - // jobline.ignore = true; - - // } - - //09/2021 Detect NAGS lines using RegEx for the Part Number - if ( - jobline.line_desc.toLowerCase().includes("glass") && - jobline.oem_partno.match(`[A-Z]{2}[0-9]{5,6}[A-Z]{3}`) - ) { - console.log(jobline.line_desc, "NAGS Line ignored"); - jobline.ignore = true; - } - - //Logic Based Exclusions. - //Verified on 08/24/21 - if ( - !jobline.part_type || - jobline.db_ref.startsWith("900") || - jobline.line_desc.toLowerCase().startsWith("urethane") || - jobline.line_desc.toLowerCase().startsWith("w/shield adhesive") || - //jobline.line_desc.toLowerCase().includes("wheel") || Removed as a part of RPS-41 - jobline.line_desc.toLowerCase().includes("tire") || - jobline.line_desc.toLowerCase().startsWith("hazardous") || - jobline.line_desc.toLowerCase().startsWith("detail") || - jobline.line_desc.toLowerCase().startsWith("clean") || - // jobline.part_type.toUpperCase() === "PAG" ||Removed for RPS-43. - jobline.part_type.toUpperCase() === "PAS" || - jobline.part_type.toUpperCase() === "PASL" || - jobline.part_type.toUpperCase() === "PAE" - //jobline.glass_flag === true //Removed for RPS-43. - ) { - jobline.ignore = true; - } - - //Check to see if this is a discount line i.e. a 900511 - if (jobline.db_ref === "900511" && jobline.prt_dsmk_p !== 50) { - jobline.ignore = false; - //Calculate the discount to be added as a negative. - jobline.act_price = jobline.prt_dsmk_m; - //Check to see if the parent line has a discount. - const parentLine = joblines.find( - (r) => parseInt(r.unq_seq) === jobline.line_ref - ); - if (parentLine && parentLine.ignore) { - jobline.ignore = true; - } - } - - //RPS-42 Dynamic Inclusion or Exclusion of Lines based on RPS-EXCLUDE or RPS. - if (jobline.oem_partno.toLowerCase().includes("/rps-exclude")) { - jobline.ignore = true; - } else if (jobline.oem_partno.toLowerCase().includes("/rps")) { - jobline.ignore = false; - } - - delete jobline.prt_dsmk_m; //Delete price markup for wheel repair - delete jobline.prt_dsmk_p; - delete jobline.glass_flag; - delete jobline.price_j; - delete jobline.line_ref; return jobline; }); @@ -526,3 +366,130 @@ async function DecodeLinFile(extensionlessFilePath) { exports.DecodeEstimate = DecodeEstimate; exports.ImportJob = ImportJob; + +function V1Ruleset(jobline) { + //These set of MPI rules are valid until April 1, 2023. + log.info(`Using V1 ruleset for line scanning.`); + + //Wheel Repair Pricing PRS-82 + //Verified on 08/24/21 + if ( + jobline.part_type === "PAN" && + jobline.line_desc.toLowerCase().includes("wheel") && + Math.abs(jobline.prt_dsmk_m) === + Math.round((jobline.act_price / 2) * 100) / 100 + ) { + log.info(`Jobline '${jobline.line_desc}' ignored due to wheel repair.`); + jobline.ignore = true; + } + + //RPS-39 - OEM ON OEM SAVINGS + //Verified on 08/24/21 + if ( + jobline.part_type === "PAN" && + jobline.db_price !== jobline.act_price && + jobline.db_price !== 0 + ) { + jobline.db_price = jobline.act_price; + } + + //Remove all $0DB line items 02/17/2022. + if ( + (jobline.part_type === "PAA" || + jobline.part_type === "PAL" || + jobline.part_type === "PAN") && + jobline.db_price === 0 + ) { + jobline.ignore = true; + } + + //05/20 + //We’ll have to apply a rule that will not count any A/M, Reman or new part price that is manually changed to $0.00. + //Only recycled parts that are changed to $0.00 can be counted towards RPS. + // This is separate from $0.00 DB prices that need to be updated to the manually entered price. + //Verified on 08/24/21 + if ( + jobline.part_type !== "PAL" && + jobline.act_price === 0 && + jobline.price_j + ) { + log.info( + `Jobline '${jobline.line_desc}' ignored because it was manually changed to 0..` + ); + jobline.ignore = true; + } + + //09/2021 Detect NAGS lines using RegEx for the Part Number + if ( + jobline.line_desc.toLowerCase().includes("glass") && + jobline.oem_partno.match(`[A-Z]{2}[0-9]{5,6}[A-Z]{3}`) + ) { + console.log(jobline.line_desc, "NAGS Line ignored"); + jobline.ignore = true; + } + + //Logic Based Exclusions. + //Verified on 08/24/21 + if ( + !jobline.part_type || + jobline.db_ref.startsWith("900") || + jobline.line_desc.toLowerCase().startsWith("urethane") || + jobline.line_desc.toLowerCase().startsWith("w/shield adhesive") || + //jobline.line_desc.toLowerCase().includes("wheel") || Removed as a part of RPS-41 + jobline.line_desc.toLowerCase().includes("tire") || + jobline.line_desc.toLowerCase().startsWith("hazardous") || + jobline.line_desc.toLowerCase().startsWith("detail") || + jobline.line_desc.toLowerCase().startsWith("clean") || + // jobline.part_type.toUpperCase() === "PAG" ||Removed for RPS-43. + jobline.part_type.toUpperCase() === "PAS" || + jobline.part_type.toUpperCase() === "PASL" || + jobline.part_type.toUpperCase() === "PAE" + //jobline.glass_flag === true //Removed for RPS-43. + ) { + jobline.ignore = true; + } + + //Check to see if this is a discount line i.e. a 900511 + if (jobline.db_ref === "900511" && jobline.prt_dsmk_p !== 50) { + jobline.ignore = false; + //Calculate the discount to be added as a negative. + jobline.act_price = jobline.prt_dsmk_m; + //Check to see if the parent line has a discount. + const parentLine = joblines.find( + (r) => parseInt(r.unq_seq) === jobline.line_ref + ); + if (parentLine && parentLine.ignore) { + jobline.ignore = true; + } + } + + //RPS-42 Dynamic Inclusion or Exclusion of Lines based on RPS-EXCLUDE or RPS. + if (jobline.oem_partno.toLowerCase().includes("/rps-exclude")) { + jobline.ignore = true; + } else if (jobline.oem_partno.toLowerCase().includes("/rps")) { + jobline.ignore = false; + } + + delete jobline.prt_dsmk_m; //Delete price markup for wheel repair + delete jobline.prt_dsmk_p; + delete jobline.glass_flag; + delete jobline.price_j; + delete jobline.line_ref; + return jobline; +} + +function V2Ruleset(jobline) { + //This is the rules psot 04/01/2023. They are a further restrictive set, and therefore + //V1 rules are called first, and then run through this filter as well. + + V1Ruleset(jobline); + + //Remove any glass related items. + if (jobline.part_type.toUpperCase() === "PAG") { + jobline.ignore = true; + } + + //ADAS Part Line + + return jobline; +} diff --git a/hasura/metadata/databases/default/tables/public_jobs.yaml b/hasura/metadata/databases/default/tables/public_jobs.yaml index 1de9572..91d50c8 100644 --- a/hasura/metadata/databases/default/tables/public_jobs.yaml +++ b/hasura/metadata/databases/default/tables/public_jobs.yaml @@ -35,6 +35,7 @@ insert_permissions: - loss_date - ownr_fn - ownr_ln + - requires_reimport - ro_number - updated_at - v_age @@ -60,6 +61,7 @@ select_permissions: - loss_date - ownr_fn - ownr_ln + - requires_reimport - ro_number - updated_at - v_age @@ -92,6 +94,7 @@ update_permissions: - loss_date - ownr_fn - ownr_ln + - requires_reimport - ro_number - updated_at - v_age diff --git a/hasura/migrations/default/1669163590028_alter_table_public_jobs_add_column_requires_reimport/down.sql b/hasura/migrations/default/1669163590028_alter_table_public_jobs_add_column_requires_reimport/down.sql new file mode 100644 index 0000000..814dd81 --- /dev/null +++ b/hasura/migrations/default/1669163590028_alter_table_public_jobs_add_column_requires_reimport/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."jobs" add column "requires_reimport" boolean +-- not null default 'false'; diff --git a/hasura/migrations/default/1669163590028_alter_table_public_jobs_add_column_requires_reimport/up.sql b/hasura/migrations/default/1669163590028_alter_table_public_jobs_add_column_requires_reimport/up.sql new file mode 100644 index 0000000..71857eb --- /dev/null +++ b/hasura/migrations/default/1669163590028_alter_table_public_jobs_add_column_requires_reimport/up.sql @@ -0,0 +1,2 @@ +alter table "public"."jobs" add column "requires_reimport" boolean + not null default 'false'; diff --git a/src/components/molecules/close-date-display/close-date-display.molecule.jsx b/src/components/molecules/close-date-display/close-date-display.molecule.jsx index 215485f..e23bca6 100644 --- a/src/components/molecules/close-date-display/close-date-display.molecule.jsx +++ b/src/components/molecules/close-date-display/close-date-display.molecule.jsx @@ -1,16 +1,15 @@ import { WarningOutlined } from "@ant-design/icons"; import { useMutation } from "@apollo/client"; -import { DatePicker, message, Spin } from "antd"; +import { DatePicker, message, notification, Spin } from "antd"; import moment from "moment"; import React, { useState } from "react"; import { UPDATE_JOB } from "../../../graphql/jobs.queries"; import ipcTypes from "../../../ipc.types"; import { CalculateVehicleAge } from "../../../ipc/ipc-estimate-utils"; -import { DateFormat } from "../../../util/constants"; +import { ChangeOfRuleSet, DateFormat } from "../../../util/constants"; const { ipcRenderer } = window; export default function CloseDateDisplayMolecule({ job, jobId, close_date }) { - const [editMode, setEditMode] = useState(false); const [value, setValue] = useState(moment(close_date)); const [loading, setLoading] = useState(false); const [updateJob] = useMutation(UPDATE_JOB); @@ -21,8 +20,17 @@ export default function CloseDateDisplayMolecule({ job, jobId, close_date }) { }); setLoading(true); setValue(newDate); - console.log("New R4P Date", newDate); - //Recalculate vehicle age. + const requires_reimport = ChangeOfRuleSet({ + prevDateMoment: job.close_date ? moment(job.close_date) : moment(), + newDateMoment: newDate ? newDate : moment(), + }); + if (requires_reimport) { + notification.open({ + type: "warning", + message: + "Changing the R4P date has changed the applicable ruleset. Please re-import the job for accurate scoring.", + }); + } const result = await updateJob({ variables: { @@ -30,6 +38,7 @@ export default function CloseDateDisplayMolecule({ job, jobId, close_date }) { job: { close_date: newDate, v_age: CalculateVehicleAge({ ...job, close_date: newDate }), + requires_reimport: job.requires_reimport || requires_reimport, }, }, }); @@ -42,23 +51,15 @@ export default function CloseDateDisplayMolecule({ job, jobId, close_date }) { setLoading(false); }; - if (editMode) - return ( -