Initial bifurcation of SGI logic.

This commit is contained in:
Patrick Fic
2026-03-20 15:45:41 -07:00
parent 232192fa17
commit fe6dec09db
16 changed files with 107 additions and 57 deletions

View File

@@ -384,25 +384,38 @@ async function DecodeLinFile(extensionlessFilePath, close_date) {
});
//Apply ruleset.
const ins_rule_set = store.get("ins_rule_set");
joblines.map((jobline) => {
jobline.ignore = false;
const rulesetToApply = WhichRulesetToApply(close_date);
switch (ins_rule_set) {
case "MPI":
const rulesetToApply = WhichRulesetToApply(close_date);
switch (rulesetToApply) {
case "V1":
jobline = V1Ruleset(jobline, joblines);
switch (rulesetToApply) {
case "V1":
jobline = V1Ruleset(jobline, joblines);
break;
case "V2":
jobline = V2Ruleset(jobline, joblines);
break;
case "V3":
jobline = V3Ruleset(jobline, joblines);
break;
default:
jobline = V3Ruleset(jobline, joblines);
break;
}
break;
case "V2":
jobline = V2Ruleset(jobline, joblines);
break;
case "V3":
jobline = V3Ruleset(jobline, joblines);
case "SGI":
log.info("Using SGI ruleset. Line will be automatically counted until rules are added.");
break;
default:
jobline = V3Ruleset(jobline, joblines);
log.info("Using default ruleset (MPI).");
break;
}
//2025-05-27 Commenting out to prepare release without claims clerk.
// jobline.alerts = claimsClerk({ jobline, joblines });

View File

@@ -13,6 +13,7 @@ const store = new Store({
enabled: false,
pollingInterval: 30000,
},
ins_rule_set: null
},
});

View File

@@ -5,6 +5,7 @@ const { BrowserWindow } = require("electron");
const { default: ipcTypes } = require("../../src/ipc.types.commonjs");
const { promises: fsPromises } = require("fs");
const { autoUpdater } = require("electron-updater");
const { store } = require("../electron-store")
// Function to write job object to logs subfolder
async function writeJobToLogsFolder(job, fileName) {
@@ -60,10 +61,23 @@ async function ScrubEstimate({ job }) {
return;
}
let association_switch
switch (store.get("ins_rule_set")) {
case "MPI":
association_switch = "ATAM";
break;
case "SGI":
association_switch = "SAAR";
break;
default:
association_switch = "ATAM";
break;
}
//Set shop metrics
job.sending_entity_id = sendingEntityId;
job.sending_entity_accept_terms_of_use = true;
job.association_switch = "ATAM";
job.association_switch = association_switch;
job.rf_zip = job.bodyshop.zip_post;
job.rf_ph1 = job.bodyshop.phone;
job.g_ttl_amt = job.clm_total;

View File

@@ -93,3 +93,7 @@ ipcMain.on(ipcTypes.app.toMain.openExternalWindow, (event, url) => {
});
});
ipcMain.on(ipcTypes.app.toMain.setInsRuleSet, (event, ins_rule_set) => {
store.set("ins_rule_set", ins_rule_set);
});

View File

@@ -34,6 +34,7 @@ select_permissions:
- features
- groups
- id
- ins_rule_set
- mpi_count_quantity
- phone
- ppd_diff_alert

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."bodyshops" add column "ins_rule_set" text
-- not null default 'MPI';

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "ins_rule_set" text
not null default 'MPI';

View File

@@ -3,7 +3,7 @@
"productName": "ImEX RPS",
"author": "ImEX Systems Inc. <support@thinkimex.com>",
"description": "ImEX RPS",
"version": "1.5.2",
"version": "1.6.0-alpha.1",
"main": "electron/main.js",
"homepage": "./",
"dependencies": {

View File

@@ -1,10 +1,10 @@
import { Button, Form, Input, InputNumber, Popconfirm, Select, Switch, Typography } from "antd";
import { Button, Form, Input, InputNumber, Popconfirm, Select, Space, Switch, Typography } from "antd";
import React from "react";
import LayoutFormRow from "../../atoms/layout-form-row/layout-form-row.atom";
export default function ShopSettingsFormMolecule({ form, saveLoading }) {
return (
<div>
<Space direction="vertical">
<Typography.Title>Shop Settings</Typography.Title>
<Popconfirm
title="Changing these settings will require manually restarting RPS on all machines."
@@ -15,7 +15,7 @@ export default function ShopSettingsFormMolecule({ form, saveLoading }) {
</Button>
</Popconfirm>
<LayoutFormRow grow>
<Space wrap>
<Form.Item
label="Shop Name"
name="shopname"
@@ -40,6 +40,9 @@ export default function ShopSettingsFormMolecule({ form, saveLoading }) {
>
<Select mode="tags" />
</Form.Item>
<Form.Item name="ins_rule_set" label="Insurance Rule Set">
<Input disabled />
</Form.Item>
<Form.Item
label="Alert when Parts Price Difference Less Than"
name="ppd_diff_alert"
@@ -59,7 +62,7 @@ export default function ShopSettingsFormMolecule({ form, saveLoading }) {
>
<Switch />
</Form.Item>
</LayoutFormRow>
</div>
</Space>
</Space>
);
}

View File

@@ -28,7 +28,7 @@ export function ShopSettingsOrganism({ setBodyshop }) {
if (data) form.resetFields();
}, [form, data]);
const handleFinish = async (values) => {
const handleFinish = async ({ ins_rule_set, ...values }) => {
setSaveLoading(true);
ipcRenderer.send(ipcTypes.app.toMain.track, {
event: "UPDATE_SHOP_DETAILS"
@@ -74,6 +74,7 @@ export function ShopSettingsOrganism({ setBodyshop }) {
})
.catch(() => {
// Form validation failed, don't save
setSaveLoading(false);
});
}
}, 250);

View File

@@ -1,4 +1,4 @@
import { Layout } from "antd";
import { Alert, Layout, notification } from "antd";
import React from "react";
import { connect } from "react-redux";
import { Routes } from "react-router-dom";
@@ -29,6 +29,17 @@ export function RoutesPage({ bodyshop, darkMode }) {
/>
);
if (bodyshop?.ins_rule_set === "SGI") {
notification.warning({
message: "SGI Target Warning",
description: "SGI has not yet released savings targets. Targets will be displayed as $0.",
placement: "bottomLeft",
key: "sgi-target-warning",
duration: -1,
closable: false
});
}
return (
<Layout style={{ height: "100vh" }} hasSider>
<Layout.Sider style={{ background: !darkMode && "#fff" }} collapsible defaultCollapsed="true">

View File

@@ -14,6 +14,7 @@ export const QUERY_BODYSHOP = gql`
phone
es_api_key
mpi_count_quantity
ins_rule_set
}
targets {
id

View File

@@ -18,6 +18,7 @@
"setReleaseChannel": "app_setReleaseChannel",
"scrubEstimate": "app_scrubEstimate",
"openExternalWindow": "app_openExternalWindow",
"setInsRuleSet": "app_setInsRuleSet",
"log": {
"info": "app_logInfo",
"debug": "app_logDebug",

View File

@@ -8,9 +8,10 @@ export function* onSetTargetPc() {
}
export function* CalculateTarget({ payload }) {
const { group, v_age, close_date, v_mileage, job } = payload;
const targets = yield select((state) => state.user.bodyshop.targets);
yield put(setSelectedJobTargetPcSuccess(GetJobTarget({ group, v_age, targets, close_date, v_mileage, job })));
const { targets, ins_rule_set } = yield select((state) => state.user.bodyshop);
yield put(setSelectedJobTargetPcSuccess(GetJobTarget({ group, v_age, targets, close_date, v_mileage, job, ins_rule_set })));
// const targetsForGroup = targets.filter((t) => t.group === group);
// if (!targetsForGroup) return 0;
// const targetPc = targetsForGroup.filter(

View File

@@ -137,6 +137,8 @@ export function* signInSuccessSaga({ payload }) {
if (shop.data.bodyshops.length > 0) {
yield put(setBodyshop(shop.data.bodyshops[0]));
ipcRenderer.send(ipcTypes.app.toMain.setAcceptableInsCoNm, shop.data.bodyshops[0].accepted_ins_co);
ipcRenderer.send(ipcTypes.app.toMain.setInsRuleSet, shop.data.bodyshops[0].ins_rule_set);
ipcRenderer.send(ipcTypes.app.toMain.setReleaseChannel, shop.data.bodyshops[0].channel);
ipcRenderer.send(ipcTypes.fileWatcher.toMain.start, {
startup: true

View File

@@ -3,45 +3,36 @@ import { store } from "../redux/store";
import { WhichRulesetToApply } from "./constants";
export default function GetJobTarget({ group, v_age, targets, close_date, v_mileage, job }) {
// //Old Validation
// const targetsForGroup = targets.filter((t) => t.group === group);
// console.log(
// "🚀 ~ file: GetJobTarget.js:7 ~ GetJobTarget ~ targetsForGroup",
// targetsForGroup
// );
// if (!targetsForGroup) {
// console.log("Result:", 0);
// }
// const targetPc = targetsForGroup.filter(
// (t) => t.ageGte <= v_age && (t.ageLt ? t.ageLt > v_age : true)
// );
// if (targetPc.length === 0) console.log("Result:", 1);
// else if (targetPc.length === 1) console.log("Result: ", targetPc[0].target);
// else {
// console.log("Result:", 1);
// }
const ins_rule_set = store.getState().user.bodyshop.ins_rule_set;
//V2 Check
const newTargets = store.getState().user.targets;
const rulesToApply = WhichRulesetToApply(close_date);
if (rulesToApply === "V3") {
//V3 Check - If vehicle is less than 20,000KM, there is NO TARGET.
if (v_mileage && v_mileage <= 20000) {
switch (ins_rule_set) {
case "SGI":
return 0;
}
const v3Target = V3TargetFinder(job);
return v3Target;
} else {
const newTargetsForGroup = newTargets.filter((t) => t.name === rulesToApply && t.group === group);
if (!newTargetsForGroup) return 0;
const newTargetPc = newTargetsForGroup.filter((t) => t.ageGte <= v_age && (t.ageLt ? t.ageLt > v_age : true));
case "MPI":
default:
const newTargets = store.getState().user.targets;
const rulesToApply = WhichRulesetToApply(close_date);
if (rulesToApply === "V3") {
//V3 Check - If vehicle is less than 20,000KM, there is NO TARGET.
if (v_mileage && v_mileage <= 20000) {
return 0;
}
const v3Target = V3TargetFinder(job);
return v3Target;
} else {
const newTargetsForGroup = newTargets.filter((t) => t.name === rulesToApply && t.group === group);
if (!newTargetsForGroup) return 0;
const newTargetPc = newTargetsForGroup.filter((t) => t.ageGte <= v_age && (t.ageLt ? t.ageLt > v_age : true));
if (newTargetPc.length === 0) return 1;
else if (newTargetPc.length === 1) return newTargetPc[0].target;
else {
return 1;
}
}
if (newTargetPc.length === 0) return 1;
else if (newTargetPc.length === 1) return newTargetPc[0].target;
else {
return 1;
}
}
}