Added decimal precision and SGI groupings.
Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
@@ -65,10 +65,18 @@ async function DecodeEstimate(filePath, includeFilePathInReturnJob = false, clos
|
||||
delete job.mat_rates;
|
||||
job.insp_date = ad2.INSP_DATE;
|
||||
|
||||
const ins_rule_set = store.get("ins_rule_set");
|
||||
|
||||
if (job.OWNR_FN === "" || !job.OWNR_FN) job.OWNR_FN = ad2.CLMT_FN;
|
||||
if (job.OWNR_LN === "" || !job.OWNR_LN) job.OWNR_LN = ad2.CLMT_LN;
|
||||
if (ins_rule_set === "SGI") {
|
||||
if (job.OWNR_FN === "" || !job.OWNR_FN) job.OWNR_FN = job.INSD_FN;
|
||||
if (job.OWNR_LN === "" || !job.OWNR_LN) job.OWNR_LN = job.INSD_LN;
|
||||
}
|
||||
if (job.OWNR_CO_NM) job.OWNR_LN = `${job.OWNR_LN} ${job.OWNR_CO_NM}`;
|
||||
delete job.OWNR_CO_NM;
|
||||
delete job.INSD_LN;
|
||||
delete job.INSD_FN;
|
||||
const accepted_ins_co = store.get("accepted_ins_co");
|
||||
|
||||
let returnValue;
|
||||
@@ -77,7 +85,6 @@ async function DecodeEstimate(filePath, includeFilePathInReturnJob = false, clos
|
||||
// returnValue = { ERROR: "Vehicle mileage is less than 20,000kms." };
|
||||
// } else
|
||||
|
||||
const ins_rule_set = store.get("ins_rule_set");
|
||||
|
||||
if (!accepted_ins_co.includes(job.INS_CO_NM)) {
|
||||
returnValue = {
|
||||
@@ -192,8 +199,8 @@ async function DecodeAd1File(extensionlessFilePath) {
|
||||
// "CAT_NO",
|
||||
"TLOS_IND",
|
||||
// "CUST_PR",
|
||||
// "INSD_LN",
|
||||
// "INSD_FN",
|
||||
"INSD_LN",
|
||||
"INSD_FN",
|
||||
// "INSD_TITLE",
|
||||
// "INSD_CO_NM",
|
||||
// "INSD_ADDR1",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"productName": "ImEX RPS",
|
||||
"author": "ImEX Systems Inc. <support@thinkimex.com>",
|
||||
"description": "ImEX RPS",
|
||||
"version": "1.6.0-alpha.7",
|
||||
"version": "1.6.0-alpha.8",
|
||||
"main": "electron/main.js",
|
||||
"homepage": "./",
|
||||
"dependencies": {
|
||||
|
||||
@@ -5,28 +5,25 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectSelectedJobTargetPc } from "../../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../../redux/user/user.selectors";
|
||||
import "./price-diff-pc-formatter.styles.scss";
|
||||
import { getDecimalPrecision } from "../../../util/decimalPrecision";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
selectedJobTargetPc: selectSelectedJobTargetPc,
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
export function PriceDiffPcFormatterAtom({
|
||||
bodyshop,
|
||||
price_diff_pc,
|
||||
selectedJobTargetPc,
|
||||
}) {
|
||||
export function PriceDiffPcFormatterAtom({ bodyshop, price_diff_pc, selectedJobTargetPc }) {
|
||||
const precision = getDecimalPrecision();
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
color: price_diff_pc > selectedJobTargetPc ? "green" : "red",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
{(price_diff_pc * 100).toFixed(1)}%
|
||||
{price_diff_pc === 1 ||
|
||||
(price_diff_pc <= bodyshop.ppd_diff_alert && price_diff_pc > 0) ? (
|
||||
{(price_diff_pc * 100).toFixed(precision)}%
|
||||
{price_diff_pc === 1 || (price_diff_pc <= bodyshop.ppd_diff_alert && price_diff_pc > 0) ? (
|
||||
<AlertFilled style={{ color: "tomato" }} className="blink_me" />
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@@ -5,6 +5,7 @@ import { InfoCircleFilled } from "@ant-design/icons";
|
||||
import { FakedGroupsForV3WithMake } from "../../../ipc/ipc-estimate-utils";
|
||||
import { WhichMPIRulesetToApply } from "../../../util/constants";
|
||||
import { alphaSort } from "../../../util/sorters";
|
||||
import { getDecimalPrecision } from "../../../util/decimalPrecision";
|
||||
|
||||
const data = [
|
||||
{
|
||||
@@ -366,7 +367,7 @@ const v3DataSource = _.sortBy(
|
||||
export function JobsGroupV3ModalMolecule() {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [search, setSearch] = useState("");
|
||||
|
||||
const precision = getDecimalPrecision();
|
||||
const v3DataSourceFiltered =
|
||||
search === null || search.trim() === ""
|
||||
? v3DataSource
|
||||
@@ -420,7 +421,7 @@ export function JobsGroupV3ModalMolecule() {
|
||||
title: "Target",
|
||||
dataIndex: "target",
|
||||
key: "target",
|
||||
render: (text, record) => `${(record.target * 100).toFixed(1)}%`
|
||||
render: (text, record) => `${(record.target * 100).toFixed(precision)}%`
|
||||
}
|
||||
]}
|
||||
/>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { CalculateJobRpsDollars, CalculateJobRpsPc } from "../../../util/Calcula
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
import { WhichMPIRulesetToApply } from "../../../util/constants";
|
||||
import { selectBodyshop } from "../../../redux/user/user.selectors";
|
||||
import { getDecimalPrecision } from "../../../util/decimalPrecision";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
selectedJobTargetPc: selectSelectedJobTargetPc,
|
||||
@@ -39,7 +40,7 @@ export function JobsTargetsStatsMolecule({ loading, job, selectedJobTargetPc, bo
|
||||
const targetRpsDollars = dbPriceSum.percentage(selectedJobTargetPc * 100);
|
||||
const dollarDiff = jobRpsDollars.subtract(targetRpsDollars);
|
||||
const MPIRulesetToApply = WhichMPIRulesetToApply(job.close_date);
|
||||
|
||||
const precision = getDecimalPrecision();
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
@@ -53,7 +54,7 @@ export function JobsTargetsStatsMolecule({ loading, job, selectedJobTargetPc, bo
|
||||
<Space>
|
||||
<Statistic
|
||||
title="Target RPS %"
|
||||
value={(selectedJobTargetPc * 100).toFixed(1)}
|
||||
value={(selectedJobTargetPc * 100).toFixed(precision)}
|
||||
suffix={
|
||||
<Space size="small">
|
||||
%
|
||||
@@ -72,7 +73,7 @@ export function JobsTargetsStatsMolecule({ loading, job, selectedJobTargetPc, bo
|
||||
valueStyle={{
|
||||
color: selectedJobTargetPc > (jobRpsPc || 0) ? "tomato" : "seagreen"
|
||||
}}
|
||||
value={((jobRpsPc || 0) * 100).toFixed(1)}
|
||||
value={((jobRpsPc || 0) * 100).toFixed(precision)}
|
||||
suffix="%"
|
||||
/>
|
||||
</Space>
|
||||
|
||||
@@ -19,6 +19,7 @@ import VehicleGroupAlertAtom from "../../atoms/vehicle-group-alert/vehicle-group
|
||||
import GroupVerifySwitch from "../group-verify-switch/group-verify-switch.component";
|
||||
import JobsClaimsClerkMolecule from "../jobs-claims-clerk/jobs-claims-clerk.molecule.jsx";
|
||||
import { addExcludedId, removeExcludedId } from "../../../redux/reporting/reporting.actions.js";
|
||||
import { getDecimalPrecision } from "../../../util/decimalPrecision.js";
|
||||
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
@@ -44,7 +45,7 @@ export function ReportingJobsListMolecule({
|
||||
removeExcludedId
|
||||
}) {
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const precision = getDecimalPrecision();
|
||||
const columns = [
|
||||
{
|
||||
title: "Claim No.",
|
||||
@@ -172,7 +173,7 @@ export function ReportingJobsListMolecule({
|
||||
color: record.jobRpsPc > record.jobTarget ? "seagreen" : "tomato"
|
||||
}}
|
||||
>
|
||||
{`${(record.jobRpsPc * 100 || 0).toFixed(1)}% / ${(record.jobTarget * 100).toFixed(1)}%`}
|
||||
{`${(record.jobRpsPc * 100 || 0).toFixed(precision)}% / ${(record.jobTarget * 100).toFixed(precision)}%`}
|
||||
</Space>
|
||||
)
|
||||
},
|
||||
@@ -186,7 +187,7 @@ export function ReportingJobsListMolecule({
|
||||
onChange={(checked) => {
|
||||
checked ? addExcludedId(record.id) : removeExcludedId(record.id);
|
||||
ipcRenderer.send(ipcTypes.app.toMain.track, {
|
||||
event: "TOGGLE_SCENARIO_MANAGER",
|
||||
event: "TOGGLE_SCENARIO_MANAGER"
|
||||
});
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,10 +1,4 @@
|
||||
import {
|
||||
Card,
|
||||
Radio,
|
||||
Skeleton,
|
||||
Tooltip as AntdToolTip,
|
||||
Typography,
|
||||
} from "antd";
|
||||
import { Card, Radio, Skeleton, Tooltip as AntdToolTip, Typography } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import {
|
||||
@@ -16,37 +10,31 @@ import {
|
||||
Tooltip,
|
||||
XAxis,
|
||||
YAxis,
|
||||
ZAxis,
|
||||
ZAxis
|
||||
} from "recharts";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
selectReportLoading,
|
||||
selectScorecard,
|
||||
} from "../../../redux/reporting/reporting.selectors";
|
||||
import { selectReportLoading, selectScorecard } from "../../../redux/reporting/reporting.selectors";
|
||||
import DataLabelAtom from "../../atoms/data-label/data-label.atom";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
import { getDecimalPrecision } from "../../../util/decimalPrecision";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
reportingLoading: selectReportLoading,
|
||||
scoreCard: selectScorecard,
|
||||
scoreCard: selectScorecard
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ReportingScatterChartMolecule);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ReportingScatterChartMolecule);
|
||||
|
||||
export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) {
|
||||
const [type, setType] = useState("percent");
|
||||
|
||||
if (reportingLoading) return <Skeleton active />;
|
||||
if (!scoreCard)
|
||||
return <ErrorResultAtom title="Error displaying score card data." />;
|
||||
if (!scoreCard) return <ErrorResultAtom title="Error displaying score card data." />;
|
||||
|
||||
const handleTypeChange = (e) => {
|
||||
setType(e.target.value);
|
||||
};
|
||||
|
||||
const precision = getDecimalPrecision();
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
@@ -54,7 +42,7 @@ export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) {
|
||||
marginTop: "1rem",
|
||||
marginBottom: "1rem",
|
||||
width: "100%",
|
||||
height: "30rem",
|
||||
height: "30rem"
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
@@ -63,19 +51,12 @@ export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) {
|
||||
placement="bottomLeft"
|
||||
title="Calculated as Actual Job RPS % less Target Job RPS %. E.g. 10% - 8% = 2%"
|
||||
>
|
||||
<Typography.Title level={4}>
|
||||
% Variance from Target
|
||||
</Typography.Title>
|
||||
<Typography.Title level={4}>% Variance from Target</Typography.Title>
|
||||
</AntdToolTip>
|
||||
)}
|
||||
{type === "dollars" && (
|
||||
<AntdToolTip
|
||||
placement="bottomLeft"
|
||||
title="Calculated as Actual Job RPS $ less Target Job RPS $."
|
||||
>
|
||||
<Typography.Title level={4}>
|
||||
$ Variance from Target
|
||||
</Typography.Title>
|
||||
<AntdToolTip placement="bottomLeft" title="Calculated as Actual Job RPS $ less Target Job RPS $.">
|
||||
<Typography.Title level={4}>$ Variance from Target</Typography.Title>
|
||||
</AntdToolTip>
|
||||
)}
|
||||
|
||||
@@ -103,13 +84,7 @@ export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) {
|
||||
unit="%"
|
||||
/>
|
||||
)}
|
||||
{type === "dollars" && (
|
||||
<XAxis
|
||||
dataKey="deviationDollars"
|
||||
type="number"
|
||||
name="Deviation ($)"
|
||||
/>
|
||||
)}
|
||||
{type === "dollars" && <XAxis dataKey="deviationDollars" type="number" name="Deviation ($)" />}
|
||||
|
||||
<YAxis type="number" dataKey="age" name="Age" unit="Years" />
|
||||
<ZAxis dataKey="dbPriceSumAmt" name="DB Price Total" />
|
||||
@@ -120,24 +95,12 @@ export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) {
|
||||
return (
|
||||
<Card title={item.clm_no}>
|
||||
<DataLabelAtom label="Owner">{item.owner}</DataLabelAtom>
|
||||
<DataLabelAtom label="Vehicle">
|
||||
{item.vehicle}
|
||||
</DataLabelAtom>
|
||||
<DataLabelAtom label="Job RPS $">
|
||||
{item.jobRpsDollars.toFormat()}
|
||||
</DataLabelAtom>
|
||||
<DataLabelAtom label="Job RPS %">
|
||||
{(item.jobRpsPc * 100).toFixed(1)}%
|
||||
</DataLabelAtom>
|
||||
<DataLabelAtom label="DB Price">
|
||||
{item.dbPriceSum.toFormat()}
|
||||
</DataLabelAtom>
|
||||
<DataLabelAtom label="Variance %">
|
||||
{`${item.deviationPc}%`}
|
||||
</DataLabelAtom>
|
||||
<DataLabelAtom label="Variance $">
|
||||
${item.deviationDollars}
|
||||
</DataLabelAtom>
|
||||
<DataLabelAtom label="Vehicle">{item.vehicle}</DataLabelAtom>
|
||||
<DataLabelAtom label="Job RPS $">{item.jobRpsDollars.toFormat()}</DataLabelAtom>
|
||||
<DataLabelAtom label="Job RPS %">{(item.jobRpsPc * 100).toFixed(precision)}%</DataLabelAtom>
|
||||
<DataLabelAtom label="DB Price">{item.dbPriceSum.toFormat()}</DataLabelAtom>
|
||||
<DataLabelAtom label="Variance %">{`${item.deviationPc.toFixed(precision)}%`}</DataLabelAtom>
|
||||
<DataLabelAtom label="Variance $">${item.deviationDollars}</DataLabelAtom>
|
||||
</Card>
|
||||
);
|
||||
}}
|
||||
@@ -145,12 +108,7 @@ export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) {
|
||||
/>
|
||||
<Legend />
|
||||
{Object.keys(scoreCard.scatterChart).map((key, idx) => (
|
||||
<Scatter
|
||||
name={key}
|
||||
key={idx}
|
||||
data={scoreCard.scatterChart[key]}
|
||||
fill={colors[idx]}
|
||||
></Scatter>
|
||||
<Scatter name={key} key={idx} data={scoreCard.scatterChart[key]} fill={colors[idx]}></Scatter>
|
||||
))}
|
||||
</ScatterChart>
|
||||
</ResponsiveContainer>
|
||||
@@ -159,11 +117,4 @@ export function ReportingScatterChartMolecule({ reportingLoading, scoreCard }) {
|
||||
);
|
||||
}
|
||||
|
||||
const colors = [
|
||||
"#0c344d",
|
||||
"#6cc314",
|
||||
"#f5782a",
|
||||
"#f5be2a",
|
||||
"#fbff90",
|
||||
"dodgerblue",
|
||||
];
|
||||
const colors = ["#0c344d", "#6cc314", "#f5782a", "#f5be2a", "#fbff90", "dodgerblue"];
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Alert, Button, Skeleton, Statistic } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { clearExcludedIds } from "../../../redux/reporting/reporting.actions";
|
||||
import { selectExcludedIds, selectReportLoading, selectScorecard } from "../../../redux/reporting/reporting.selectors";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
import { clearExcludedIds } from "../../../redux/reporting/reporting.actions";
|
||||
|
||||
import { getDecimalPrecision } from "../../../util/decimalPrecision";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
reportingLoading: selectReportLoading,
|
||||
scoreCard: selectScorecard,
|
||||
@@ -20,7 +20,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(ReportingTotalsStats
|
||||
export function ReportingTotalsStatsMolecule({ reportingLoading, scoreCard, excludedJobIds, clearExcludedIds }) {
|
||||
if (reportingLoading) return <Skeleton active />;
|
||||
if (!scoreCard) return <ErrorResultAtom title="Error displaying score card data." />;
|
||||
|
||||
const precision = getDecimalPrecision();
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -36,7 +36,7 @@ export function ReportingTotalsStatsMolecule({ reportingLoading, scoreCard, excl
|
||||
<Statistic
|
||||
title="Target RPS %"
|
||||
style={{ margin: "0rem .5rem" }}
|
||||
value={((scoreCard.targetRpsPc || 0) * 100).toFixed(1)}
|
||||
value={((scoreCard.targetRpsPc || 0) * 100).toFixed(precision)}
|
||||
suffix="%"
|
||||
/>
|
||||
<Statistic
|
||||
@@ -45,7 +45,7 @@ export function ReportingTotalsStatsMolecule({ reportingLoading, scoreCard, excl
|
||||
valueStyle={{
|
||||
color: (scoreCard.currentRpsPc || 0) <= (scoreCard.targetRpsPc || 0) ? "tomato" : "seagreen"
|
||||
}}
|
||||
value={((scoreCard.currentRpsPc || 0) * 100).toFixed(1)}
|
||||
value={((scoreCard.currentRpsPc || 0) * 100).toFixed(precision)}
|
||||
suffix="%"
|
||||
/>
|
||||
<Statistic
|
||||
@@ -54,7 +54,7 @@ export function ReportingTotalsStatsMolecule({ reportingLoading, scoreCard, excl
|
||||
valueStyle={{
|
||||
color: scoreCard.variancePc < 0 ? "tomato" : "seagreen"
|
||||
}}
|
||||
value={((scoreCard.variancePc || 0) * 100).toFixed(2)}
|
||||
value={((scoreCard.variancePc || 0) * 100).toFixed(precision)}
|
||||
suffix="%"
|
||||
/>
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
import { V3TargetFinder } from "../ipc/ipc-estimate-utils";
|
||||
import { V3TargetFinder, SgiGroupsV12026April } from "../ipc/ipc-estimate-utils";
|
||||
import { store } from "../redux/store";
|
||||
import { WhichMPIRulesetToApply } from "./constants";
|
||||
|
||||
@@ -7,7 +7,13 @@ export default function GetJobTarget({ group, v_age, targets, close_date, v_mile
|
||||
|
||||
switch (ins_rule_set) {
|
||||
case "SGI":
|
||||
return 0;
|
||||
let type = job.v_type === "PC" || job.v_type === "SUV" ? "PC" : job.v_type;
|
||||
const sgiTarget = SgiGroupsV12026April.find((f) => f.make === job.v_makedesc.toUpperCase()
|
||||
&& (f.type === type || f.type === null)
|
||||
&& job.v_age >= f.ageGte
|
||||
&& (f.ageLt === null ? true : job.v_age < f.ageLt)
|
||||
);
|
||||
return sgiTarget?.target || 0;
|
||||
|
||||
case "MPI":
|
||||
default:
|
||||
|
||||
8
src/util/decimalPrecision.js
Normal file
8
src/util/decimalPrecision.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import { store } from "../redux/store";
|
||||
|
||||
export function getDecimalPrecision() {
|
||||
const ins_rule_set = store.getState().user.bodyshop.ins_rule_set;
|
||||
return ins_rule_set === "SGI" ? 2 : 1;
|
||||
}
|
||||
|
||||
export default getDecimalPrecision;
|
||||
Reference in New Issue
Block a user