diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index 3e26652fd..9d91b0a8c 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -6344,6 +6344,27 @@
+
+ pasl
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
refund
false
@@ -24800,6 +24821,27 @@
+
+ relatedros
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
returntotals
false
diff --git a/client/package.json b/client/package.json
index 3e76fd995..8cdb60e5b 100644
--- a/client/package.json
+++ b/client/package.json
@@ -8,8 +8,8 @@
"@craco/craco": "^6.2.0",
"@fingerprintjs/fingerprintjs": "^3.3.0",
"@lourenci/react-kanban": "^2.1.0",
- "@openreplay/tracker": "^3.2.5",
- "@openreplay/tracker-assist": "^3.0.4",
+ "@openreplay/tracker": "^3.3.1",
+ "@openreplay/tracker-assist": "^3.1.1",
"@openreplay/tracker-graphql": "^3.0.0",
"@openreplay/tracker-redux": "^3.0.0",
"@sentry/react": "^6.11.0",
@@ -19,7 +19,7 @@
"@tanem/react-nprogress": "^3.0.79",
"antd": "^4.16.13",
"apollo-link-logger": "^2.0.0",
- "axios": "^0.21.1",
+ "axios": "^0.21.4",
"craco-less": "^1.20.0",
"dinero.js": "^1.9.0",
"dotenv": "^10.0.0",
@@ -27,12 +27,12 @@
"env-cmd": "^10.1.0",
"exifr": "^7.1.3",
"firebase": "^9.0.0",
- "graphql": "^15.5.2",
+ "graphql": "^15.5.3",
"i18next": "^20.4.0",
"i18next-browser-languagedetector": "^6.1.2",
"jsoneditor": "^9.5.4",
"jsreport-browser-client-dist": "^1.3.0",
- "libphonenumber-js": "^1.9.25",
+ "libphonenumber-js": "^1.9.26",
"logrocket": "^2.0.0",
"markerjs2": "^2.11.2",
"moment-business-days": "^1.2.0",
@@ -53,9 +53,9 @@
"react-i18next": "^11.11.4",
"react-icons": "^4.2.0",
"react-number-format": "^4.7.3",
- "react-redux": "^7.2.4",
+ "react-redux": "^7.2.5",
"react-resizable": "^3.0.4",
- "react-router-dom": "^5.2.1",
+ "react-router-dom": "^5.3.0",
"react-scripts": "^4.0.3",
"react-sublime-video": "^0.2.5",
"react-virtualized": "^9.22.3",
diff --git a/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.component.jsx b/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.component.jsx
index 520154f08..05b909d8c 100644
--- a/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.component.jsx
+++ b/client/src/components/job-lines-upsert-modal/job-lines-upsert-modal.component.jsx
@@ -115,18 +115,18 @@ export default function JobLinesUpsertModalComponent({
({
- // validator(rule, value) {
- // if (!!getFieldValue("mod_lbr_ty") === !!value) {
- // return Promise.resolve();
- // }
- // return Promise.reject(
- // t("joblines.validations.hrsrequirediflbrtyp")
- // );
- // },
- // }),
- // ]}
+ rules={[
+ ({ getFieldValue }) => ({
+ validator(rule, value) {
+ if (!!getFieldValue("mod_lbr_ty") === !!value) {
+ return Promise.resolve();
+ }
+ return Promise.reject(
+ t("joblines.validations.hrsrequirediflbrtyp")
+ );
+ },
+ }),
+ ]}
>
@@ -169,18 +169,18 @@ export default function JobLinesUpsertModalComponent({
({
- // validator(rule, value) {
- // if (!!getFieldValue("part_type") === !!value) {
- // return Promise.resolve();
- // }
- // return Promise.reject(
- // t("joblines.validations.requiredifparttype")
- // );
- // },
- // }),
- // ]}
+ rules={[
+ ({ getFieldValue }) => ({
+ validator(rule, value) {
+ if (!!getFieldValue("part_type") === !!value) {
+ return Promise.resolve();
+ }
+ return Promise.reject(
+ t("joblines.validations.requiredifparttype")
+ );
+ },
+ }),
+ ]}
>
@@ -190,28 +190,28 @@ export default function JobLinesUpsertModalComponent({
({
- // validator(rule, value) {
- // if (!value || getFieldValue("part_type") !== "PAE") {
- // return Promise.resolve();
- // }
- // return Promise.reject(
- // t("joblines.validations.zeropriceexistingpart")
- // );
- // },
- // }),
- // ({ getFieldValue }) => ({
- // validator(rule, value) {
- // if (!!getFieldValue("part_type") === !!value) {
- // return Promise.resolve();
- // }
- // return Promise.reject(
- // t("joblines.validations.requiredifparttype")
- // );
- // },
- // }),
- // ]}
+ rules={[
+ ({ getFieldValue }) => ({
+ validator(rule, value) {
+ if (!value || getFieldValue("part_type") !== "PAE") {
+ return Promise.resolve();
+ }
+ return Promise.reject(
+ t("joblines.validations.zeropriceexistingpart")
+ );
+ },
+ }),
+ ({ getFieldValue }) => ({
+ validator(rule, value) {
+ if (!!getFieldValue("part_type") === !!value) {
+ return Promise.resolve();
+ }
+ return Promise.reject(
+ t("joblines.validations.requiredifparttype")
+ );
+ },
+ }),
+ ]}
>
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 134946530..d77d5c1d3 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
@@ -98,23 +98,7 @@ export function JobsAvailableContainer({
return;
}
//IO-539 Check for Parts Rate on PAL for SGI use case.
-
- if (
- estData.est_data.parts_tax_rates &&
- estData.est_data.parts_tax_rates.PAL &&
- (estData.est_data.parts_tax_rates.PAL.prt_tax_rt === null ||
- estData.est_data.parts_tax_rates.PAL.prt_tax_rt === 0)
- ) {
- console.log("checking");
- const res = await confirmDialog(
- `ImEX Online has detected that there is a missing tax rate for used parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}%.`
- );
- if (res) {
- estData.est_data.parts_tax_rates.PAL.prt_tax_rt =
- bodyshop.bill_tax_rates.state_tax_rate / 100;
- estData.est_data.parts_tax_rates.PAL.prt_tax_in = true;
- }
- }
+ await CheckTaxRates(estData, bodyshop);
const newTotals = (
await Axios.post("/job/totals", {
@@ -215,22 +199,7 @@ export function JobsAvailableContainer({
});
} else {
//IO-539 Check for Parts Rate on PAL for SGI use case.
- if (
- estData.est_data.parts_tax_rates &&
- estData.est_data.parts_tax_rates.PAL &&
- (estData.est_data.parts_tax_rates.PAL.prt_tax_rt === null ||
- estData.est_data.parts_tax_rates.PAL.prt_tax_rt === 0)
- ) {
- console.log("checking");
- const res = await confirmDialog(
- `ImEX Online has detected that there is a missing tax rate for used parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}%.`
- );
- if (res) {
- estData.est_data.parts_tax_rates.PAL.prt_tax_rt =
- bodyshop.bill_tax_rates.state_tax_rate / 100;
- estData.est_data.parts_tax_rates.PAL.prt_tax_in = true;
- }
- }
+ await CheckTaxRates(estData, bodyshop);
//create upsert job
let supp = replaceEmpty({ ...estData.est_data });
@@ -432,3 +401,98 @@ function confirmDialog(msg) {
return confirmed ? resolve(true) : resolve(false);
});
}
+
+async function CheckTaxRates(estData, bodyshop) {
+ //LKQ Check
+ if (
+ !estData.est_data.parts_tax_rates?.PAL ||
+ estData.est_data.parts_tax_rates?.PAL?.prt_tax_rt === null ||
+ estData.est_data.parts_tax_rates?.PAL?.prt_tax_rt === 0
+ ) {
+ const res = await confirmDialog(
+ `ImEX Online has detected that there is a missing tax rate for LKQ parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
+ );
+ if (res) {
+ if (!estData.est_data.parts_tax_rates.PAL) {
+ estData.est_data.parts_tax_rates.PAL = {
+ prt_discp: 0,
+ prt_mktyp: true,
+ prt_mkupp: 0,
+ prt_type: "PAL",
+ };
+ }
+ estData.est_data.parts_tax_rates.PAL.prt_tax_rt =
+ bodyshop.bill_tax_rates.state_tax_rate / 100;
+ estData.est_data.parts_tax_rates.PAL.prt_tax_in = true;
+ }
+ }
+ //PAC Check
+ if (
+ !estData.est_data.parts_tax_rates?.PAC ||
+ estData.est_data.parts_tax_rates?.PAC?.prt_tax_rt === null ||
+ estData.est_data.parts_tax_rates?.PAC?.prt_tax_rt === 0
+ ) {
+ const res = await confirmDialog(
+ `ImEX Online has detected that there is a missing tax rate for rechromed parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
+ );
+ if (res) {
+ if (!estData.est_data.parts_tax_rates.PAC) {
+ estData.est_data.parts_tax_rates.PAC = {
+ prt_discp: 0,
+ prt_mktyp: true,
+ prt_mkupp: 0,
+ prt_type: "PAC",
+ };
+ }
+ estData.est_data.parts_tax_rates.PAC.prt_tax_rt =
+ bodyshop.bill_tax_rates.state_tax_rate / 100;
+ estData.est_data.parts_tax_rates.PAC.prt_tax_in = true;
+ }
+ }
+ //PAM Check
+ if (
+ !estData.est_data.parts_tax_rates?.PAM ||
+ estData.est_data.parts_tax_rates?.PAM?.prt_tax_rt === null ||
+ estData.est_data.parts_tax_rates?.PAM?.prt_tax_rt === 0
+ ) {
+ const res = await confirmDialog(
+ `ImEX Online has detected that there is a missing tax rate for remanufactured parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
+ );
+ if (res) {
+ if (!estData.est_data.parts_tax_rates.PAM) {
+ estData.est_data.parts_tax_rates.PAM = {
+ prt_discp: 0,
+ prt_mktyp: true,
+ prt_mkupp: 0,
+ prt_type: "PAM",
+ };
+ }
+ estData.est_data.parts_tax_rates.PAM.prt_tax_rt =
+ bodyshop.bill_tax_rates.state_tax_rate / 100;
+ estData.est_data.parts_tax_rates.PAM.prt_tax_in = true;
+ }
+ }
+
+ if (
+ !estData.est_data.parts_tax_rates?.PAR ||
+ estData.est_data.parts_tax_rates?.PAR?.prt_tax_rt === null ||
+ estData.est_data.parts_tax_rates?.PAR?.prt_tax_rt === 0
+ ) {
+ const res = await confirmDialog(
+ `ImEX Online has detected that there is a missing tax rate for recored parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
+ );
+ if (res) {
+ if (!estData.est_data.parts_tax_rates.PAR) {
+ estData.est_data.parts_tax_rates.PAR = {
+ prt_discp: 0,
+ prt_mktyp: true,
+ prt_mkupp: 0,
+ prt_type: "PAR",
+ };
+ }
+ estData.est_data.parts_tax_rates.PAR.prt_tax_rt =
+ bodyshop.bill_tax_rates.state_tax_rate / 100;
+ estData.est_data.parts_tax_rates.PAR.prt_tax_in = true;
+ }
+ }
+}
diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
index 8beebc60d..83ade9d5c 100644
--- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
+++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
@@ -15,6 +15,7 @@ import JobAltTransportChange from "../job-at-change/job-at-change.component";
import JobEmployeeAssignments from "../job-employee-assignments/job-employee-assignments.container";
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
import "./jobs-detail-header.styles.scss";
+import JobsRelatedRos from "../jobs-related-ros/jobs-related-ros.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -80,6 +81,7 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
/
{job.owner_owing}
+
{job.alt_transport}
@@ -177,6 +179,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
{`${job.v_vin || t("general.labels.na")}`}
+
+
+
diff --git a/client/src/components/jobs-related-ros/jobs-related-ros.component.jsx b/client/src/components/jobs-related-ros/jobs-related-ros.component.jsx
new file mode 100644
index 000000000..dce3f0393
--- /dev/null
+++ b/client/src/components/jobs-related-ros/jobs-related-ros.component.jsx
@@ -0,0 +1,19 @@
+import { Space, Tag } from "antd";
+import React from "react";
+import { Link } from "react-router-dom";
+
+export default function JobsRelatedRos({ jobid, job }) {
+ return (
+
+ {job.vehicle.jobs
+ .filter((j) => j.id !== job.id)
+ .map((j) => (
+
+ {`${j.ro_number || "N/A"}${
+ j.clm_no ? ` | ${j.clm_no}` : ""
+ }${j.status ? ` | ${j.status}` : ""}`}
+
+ ))}
+
+ );
+}
diff --git a/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx b/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx
index c50b7b9b0..0da65dd3d 100644
--- a/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx
+++ b/client/src/components/shop-info/shop-info.responsibilitycenters.component.jsx
@@ -871,6 +871,27 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
))}
+
+
+
+
+
+
+
+
+
+
+
+
0
- ) {
+ if (jobline.profitcenter_labor && jobline.mod_lb_hrs) {
const DineroAmount = Dinero({
amount: Math.round(
jobs_by_pk[`rate_${jobline.mod_lbr_ty.toLowerCase()}`] * 100
diff --git a/server/job/job-totals.js b/server/job/job-totals.js
index 54b94f5e1..e0c069bba 100644
--- a/server/job/job-totals.js
+++ b/server/job/job-totals.js
@@ -242,7 +242,16 @@ function CalculatePartsTotals(jobLines) {
subtotal: acc.sublets.subtotal.add(
Dinero({
amount: Math.round(value.act_price * 100),
- }).multiply(value.part_qty || 0)
+ })
+ .multiply(value.part_qty || 0)
+ .add(
+ Dinero({
+ amount: Math.round(value.act_price * 100),
+ })
+ .multiply(value.part_qty || 0)
+ .percentage(Math.abs(value.prt_dsmk_p || 0))
+ .multiply(value.prt_dsmk_p > 0 ? 1 : -1)
+ )
),
},
};
@@ -306,6 +315,7 @@ function CalculatePartsTotals(jobLines) {
},
sublets: {
subtotal: Dinero({ amount: 0 }),
+
total: Dinero({ amount: 0 }),
},
}
diff --git a/yarn.lock b/yarn.lock
index bc81cad4d..47706165c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1947,10 +1947,10 @@ graphql-request@^3.4.0:
extract-files "^9.0.0"
form-data "^3.0.0"
-graphql@^15.5.2:
- version "15.5.2"
- resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.2.tgz#efa19f8f2bf1a48eb7d5c85bf17e144ba8bb0480"
- integrity sha512-dZjLPWNQqYv0dqV2RNbiFed0LtSp6yd4jchsDGnuhDKa9OQHJYCfovaOEvY91w9gqbYO7Se9LKDTl3xxYva/3w==
+graphql@^15.5.3:
+ version "15.5.3"
+ resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.3.tgz#c72349017d5c9f5446a897fe6908b3186db1da00"
+ integrity sha512-sM+jXaO5KinTui6lbK/7b7H/Knj9BpjGxZ+Ki35v7YbUJxxdBCUqNM0h3CRVU1ZF9t5lNiBzvBCSYPvIwxPOQA==
graylog2@^0.2.1:
version "0.2.1"