Add part quantity selector to shop setup.
This commit is contained in:
@@ -198,5 +198,10 @@
|
||||
"title": "Release Notes for 1.4.1",
|
||||
"date": "07/04/2025",
|
||||
"notes": "Improvements:\r\n* Increased performance of scenario manager.\r\n* Report lines will now display better on smaller screens.\r\n* Job RPS printouts will now display in landscape mode and ignore dark mode styling."
|
||||
},
|
||||
"1.4.2-beta.4": {
|
||||
"title": "Release Notes for 1.4.2-beta.4",
|
||||
"date": "09/16/2025",
|
||||
"notes": "New Features:\r\n* Added part quantity toggle to shop setup. This will use the part quantity from the job lines when calculating RPS instead of assuming 1 per MPI guidelines.\r\n\r\nImprovements:\r\n* Updated ES integration to use newly specified API keys."
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ select_permissions:
|
||||
- features
|
||||
- groups
|
||||
- id
|
||||
- mpi_count_quantity
|
||||
- phone
|
||||
- ppd_diff_alert
|
||||
- shopname
|
||||
@@ -51,6 +52,7 @@ update_permissions:
|
||||
columns:
|
||||
- accepted_ins_co
|
||||
- groups
|
||||
- mpi_count_quantity
|
||||
- ppd_diff_alert
|
||||
- shopname
|
||||
- targets
|
||||
|
||||
@@ -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 "mpi_count_quantity" boolean
|
||||
-- not null default 'false';
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."bodyshops" add column "mpi_count_quantity" boolean
|
||||
not null default 'false';
|
||||
@@ -3,7 +3,7 @@
|
||||
"productName": "ImEX RPS",
|
||||
"author": "ImEX Systems Inc. <support@thinkimex.com>",
|
||||
"description": "ImEX RPS",
|
||||
"version": "1.4.2-alpha.13",
|
||||
"version": "1.4.2-beta.4",
|
||||
"main": "electron/main.js",
|
||||
"homepage": "./",
|
||||
"dependencies": {
|
||||
|
||||
@@ -8,31 +8,33 @@ import { selectSelectedJobTargetPc } from "../../../redux/application/applicatio
|
||||
import { CalculateJobRpsDollars, CalculateJobRpsPc } from "../../../util/CalculateJobRps";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
import { WhichRulesetToApply } from "../../../util/constants";
|
||||
import { selectBodyshop } from "../../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
selectedJobTargetPc: selectSelectedJobTargetPc
|
||||
selectedJobTargetPc: selectSelectedJobTargetPc,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsTargetsStatsMolecule);
|
||||
|
||||
export function JobsTargetsStatsMolecule({ loading, job, selectedJobTargetPc }) {
|
||||
export function JobsTargetsStatsMolecule({ loading, job, selectedJobTargetPc, bodyshop }) {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const { actPriceSum, jobRpsDollars } = useCallback(CalculateJobRpsDollars(job, true), [job, CalculateJobRpsDollars]);
|
||||
const { actPriceSum, jobRpsDollars } = useCallback(CalculateJobRpsDollars(job, true, bodyshop.mpi_count_quantity), [
|
||||
job,
|
||||
CalculateJobRpsDollars
|
||||
]);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const { dbPriceSum, jobRpsPc } = useCallback(CalculateJobRpsPc(job, jobRpsDollars, true), [
|
||||
job,
|
||||
jobRpsDollars,
|
||||
CalculateJobRpsPc
|
||||
]);
|
||||
const { dbPriceSum, jobRpsPc } = useCallback(
|
||||
CalculateJobRpsPc(job, jobRpsDollars, true, bodyshop.mpi_count_quantity),
|
||||
[job, jobRpsDollars, CalculateJobRpsPc]
|
||||
);
|
||||
|
||||
if (loading) return <Skeleton active />;
|
||||
if (!job)
|
||||
return (
|
||||
<ErrorResultAtom title="Error displaying job." errorMessage="It looks like this job doesn't exist." />
|
||||
);
|
||||
return <ErrorResultAtom title="Error displaying job." errorMessage="It looks like this job doesn't exist." />;
|
||||
|
||||
const targetRpsDollars = dbPriceSum.percentage(selectedJobTargetPc * 100);
|
||||
const dollarDiff = jobRpsDollars.subtract(targetRpsDollars);
|
||||
@@ -43,7 +45,7 @@ export function JobsTargetsStatsMolecule({ loading, job, selectedJobTargetPc })
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-around",
|
||||
justifyContent: "space-around"
|
||||
//marginTop: "2rem",
|
||||
//marginBottom: "1rem"
|
||||
}}
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
Popconfirm,
|
||||
Select,
|
||||
Typography,
|
||||
} from "antd";
|
||||
import { Button, Form, Input, InputNumber, Popconfirm, Select, Switch, Typography } from "antd";
|
||||
import React from "react";
|
||||
import LayoutFormRow from "../../atoms/layout-form-row/layout-form-row.atom";
|
||||
|
||||
@@ -29,8 +21,8 @@ export default function ShopSettingsFormMolecule({ form, saveLoading }) {
|
||||
name="shopname"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
@@ -42,8 +34,8 @@ export default function ShopSettingsFormMolecule({ form, saveLoading }) {
|
||||
{
|
||||
required: true,
|
||||
|
||||
type: "array",
|
||||
},
|
||||
type: "array"
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Select mode="tags" />
|
||||
@@ -54,12 +46,31 @@ export default function ShopSettingsFormMolecule({ form, saveLoading }) {
|
||||
name="ppd_diff_alert"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Alert when Parts Price Difference Less Than"
|
||||
name="ppd_diff_alert"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label="Calculate using Part Quantity"
|
||||
tooltip="MPI guidelines indicate that the quantity for a part should always be 1. However, their calculations do not always reflect this. Set this to true to use the quantity from the part line."
|
||||
name="mpi_count_quantity"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -13,6 +13,7 @@ export const QUERY_BODYSHOP = gql`
|
||||
zip_post
|
||||
phone
|
||||
es_api_key
|
||||
mpi_count_quantity
|
||||
}
|
||||
targets {
|
||||
id
|
||||
@@ -39,6 +40,10 @@ export const UPDATE_SHOP = gql`
|
||||
groups
|
||||
ppd_diff_alert
|
||||
features
|
||||
zip_post
|
||||
phone
|
||||
es_api_key
|
||||
mpi_count_quantity
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,11 +145,13 @@ export function* handleCalculateScoreCard({ payload: queriedJobs }) {
|
||||
)
|
||||
};
|
||||
|
||||
const bodyshop = yield select((state) => state.user.bodyshop);
|
||||
|
||||
//Get the RPS on a per job basis.
|
||||
jobs = jobs.map((job) => {
|
||||
const isJobExcludedFromCalculation = excludedJobIds.includes(job.id);
|
||||
const { actPriceSum, jobRpsDollars } = CalculateJobRpsDollars(job, true);
|
||||
const { dbPriceSum, jobRpsPc } = CalculateJobRpsPc(job, jobRpsDollars, true);
|
||||
const { actPriceSum, jobRpsDollars } = CalculateJobRpsDollars(job, true, bodyshop.mpi_count_quantity);
|
||||
const { dbPriceSum, jobRpsPc } = CalculateJobRpsPc(job, jobRpsDollars, true, bodyshop.mpi_count_quantity);
|
||||
const jobTarget = GetJobTarget({
|
||||
group: job.group,
|
||||
v_age: job.v_age,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import Dinero from "dinero.js";
|
||||
|
||||
export function CalculateJobRpsDollars(job, returnSumActPrice) {
|
||||
export function CalculateJobRpsDollars(job, returnSumActPrice, mpi_count_quantity = false) {
|
||||
if (!job) {
|
||||
return 0;
|
||||
}
|
||||
@@ -10,16 +10,16 @@ export function CalculateJobRpsDollars(job, returnSumActPrice) {
|
||||
.reduce((acc, val) => {
|
||||
actPriceSum = actPriceSum.add(
|
||||
Dinero({ amount: Math.round((val.act_price || 0) * 100) })
|
||||
// .multiply(
|
||||
// val.part_qty || 1
|
||||
// )
|
||||
.multiply(
|
||||
mpi_count_quantity ? (val.part_qty || 1) : 1
|
||||
)
|
||||
);
|
||||
// if (val.price_diff > 0) { //
|
||||
return acc.add(
|
||||
Dinero({ amount: Math.round((val.price_diff || 0) * 100) })
|
||||
// .multiply(
|
||||
// val.part_qty || 1
|
||||
// )
|
||||
.multiply(
|
||||
mpi_count_quantity ? (val.part_qty || 1) : 1
|
||||
)
|
||||
);
|
||||
// } else {
|
||||
// return acc;
|
||||
@@ -31,7 +31,8 @@ export function CalculateJobRpsDollars(job, returnSumActPrice) {
|
||||
export function CalculateJobRpsPc(
|
||||
job,
|
||||
currentRpsDollars,
|
||||
returnSumDbPrice = false
|
||||
returnSumDbPrice = false,
|
||||
mpi_count_quantity = false
|
||||
) {
|
||||
//TODO Redo this to do total of db price - act price / db price
|
||||
if (!job) {
|
||||
@@ -42,9 +43,9 @@ export function CalculateJobRpsPc(
|
||||
.reduce((acc, val) => {
|
||||
return acc.add(
|
||||
Dinero({ amount: Math.round((val.db_price || 0) * 100) })
|
||||
// .multiply(
|
||||
// val.part_qty || 1
|
||||
// )
|
||||
.multiply(
|
||||
mpi_count_quantity ? (val.part_qty || 1) : 1
|
||||
)
|
||||
);
|
||||
}, Dinero());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user