Final adjustments to job totals calculation for 99% accuracy.
This commit is contained in:
@@ -6,7 +6,7 @@ import {
|
|||||||
useQuery,
|
useQuery,
|
||||||
} from "@apollo/client";
|
} from "@apollo/client";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { Col, Row, notification } from "antd";
|
import { Button, Col, Row, notification } from "antd";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
@@ -90,13 +90,15 @@ export function JobsAvailableContainer({
|
|||||||
const modalSearchState = useState("");
|
const modalSearchState = useState("");
|
||||||
|
|
||||||
//Import Scenario
|
//Import Scenario
|
||||||
const onOwnerFindModalOk = async () => {
|
const onOwnerFindModalOk = async (lazyData) => {
|
||||||
logImEXEvent("job_import_new");
|
logImEXEvent("job_import_new");
|
||||||
|
|
||||||
setOwnerModalVisible(false);
|
setOwnerModalVisible(false);
|
||||||
setInsertLoading(true);
|
setInsertLoading(true);
|
||||||
|
console.log("Using this as the data.", lazyData || estDataRaw);
|
||||||
const estData = replaceEmpty(estDataRaw.data.available_jobs_by_pk);
|
const estData = replaceEmpty(
|
||||||
|
lazyData?.available_jobs_by_pk || estDataRaw.data.available_jobs_by_pk
|
||||||
|
);
|
||||||
|
|
||||||
if (!(estData && estData.est_data)) {
|
if (!(estData && estData.est_data)) {
|
||||||
//We don't have the right data. Error!
|
//We don't have the right data. Error!
|
||||||
@@ -165,47 +167,46 @@ export function JobsAvailableContainer({
|
|||||||
newJob.kmin = null;
|
newJob.kmin = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
insertNewJob({
|
try {
|
||||||
variables: {
|
const r = await insertNewJob({
|
||||||
job: newJob,
|
variables: {
|
||||||
},
|
job: newJob,
|
||||||
})
|
},
|
||||||
.then((r) => {
|
});
|
||||||
Axios.post("/job/totalsssu", {
|
await Axios.post("/job/totalsssu", {
|
||||||
id: r.data.insert_jobs.returning[0].id,
|
id: r.data.insert_jobs.returning[0].id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (CriticalPartsScanning.treatment === "on") {
|
if (CriticalPartsScanning.treatment === "on") {
|
||||||
CriticalPartsScan(r.data.insert_jobs.returning[0].id);
|
CriticalPartsScan(r.data.insert_jobs.returning[0].id);
|
||||||
}
|
}
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
message: t("jobs.successes.created"),
|
message: t("jobs.successes.created"),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
history.push(`/manage/jobs/${r.data.insert_jobs.returning[0].id}`);
|
history.push(`/manage/jobs/${r.data.insert_jobs.returning[0].id}`);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
//Job has been inserted. Clean up the available jobs record.
|
//Job has been inserted. Clean up the available jobs record.
|
||||||
|
|
||||||
insertAuditTrail({
|
insertAuditTrail({
|
||||||
jobid: r.data.insert_jobs.returning[0].id,
|
jobid: r.data.insert_jobs.returning[0].id,
|
||||||
operation: AuditTrailMapping.jobimported(),
|
operation: AuditTrailMapping.jobimported(),
|
||||||
});
|
});
|
||||||
|
|
||||||
deleteJob({
|
await deleteJob({
|
||||||
variables: { id: estData.id },
|
variables: { id: estData.id },
|
||||||
}).then((r) => {
|
}).then((r) => {
|
||||||
refetch();
|
if (!lazyData) refetch();
|
||||||
setInsertLoading(false);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch((r) => {
|
|
||||||
//error while inserting
|
|
||||||
notification["error"]({
|
|
||||||
message: t("jobs.errors.creating", { error: r.message }),
|
|
||||||
});
|
|
||||||
refetch();
|
|
||||||
setInsertLoading(false);
|
setInsertLoading(false);
|
||||||
});
|
});
|
||||||
|
} catch (r) {
|
||||||
|
//error while inserting
|
||||||
|
notification["error"]({
|
||||||
|
message: t("jobs.errors.creating", { error: r.message }),
|
||||||
|
});
|
||||||
|
refetch();
|
||||||
|
setInsertLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Suplement scenario
|
//Suplement scenario
|
||||||
@@ -392,6 +393,21 @@ export function JobsAvailableContainer({
|
|||||||
onCancel={onJobModalCancel}
|
onCancel={onJobModalCancel}
|
||||||
modalSearchState={modalSearchState}
|
modalSearchState={modalSearchState}
|
||||||
/>
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={async () => {
|
||||||
|
for (const record of data.available_jobs) {
|
||||||
|
//Query the data
|
||||||
|
console.log("Start Job", record.id);
|
||||||
|
const { data } = await loadEstData({
|
||||||
|
variables: { id: record.id },
|
||||||
|
});
|
||||||
|
console.log("Query has been awaited and is complete");
|
||||||
|
await onOwnerFindModalOk(data);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Add all jobs as new.
|
||||||
|
</Button>
|
||||||
<Row gutter={[16, 16]}>
|
<Row gutter={[16, 16]}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<JobsAvailableTableComponent
|
<JobsAvailableTableComponent
|
||||||
@@ -469,6 +485,12 @@ async function CheckTaxRates(estData, bodyshop) {
|
|||||||
// estData.parts_tax_rates.PAC.prt_tax_in = true;
|
// estData.parts_tax_rates.PAC.prt_tax_in = true;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
//PAM Check
|
||||||
|
if (!estData.parts_tax_rates?.PAM) {
|
||||||
|
estData.parts_tax_rates.PAM = estData.parts_tax_rates.PAC;
|
||||||
|
}
|
||||||
|
|
||||||
// //PAM Check
|
// //PAM Check
|
||||||
// if (
|
// if (
|
||||||
// !estData.parts_tax_rates?.PAM ||
|
// !estData.parts_tax_rates?.PAM ||
|
||||||
@@ -542,8 +564,7 @@ async function ResolveCCCLineIssues(estData, bodyshop) {
|
|||||||
//This needs to be done before cleansing unq_seq since some misc prices could move over.
|
//This needs to be done before cleansing unq_seq since some misc prices could move over.
|
||||||
estData.joblines.data.forEach((line) => {
|
estData.joblines.data.forEach((line) => {
|
||||||
if (line.misc_amt && line.misc_amt !== 0) {
|
if (line.misc_amt && line.misc_amt !== 0) {
|
||||||
line.act_price = line.misc_amt;
|
line.act_price = line.act_price + line.misc_amt;
|
||||||
line.part_type = "PAS";
|
|
||||||
line.tax_part = !!line.misc_tax;
|
line.tax_part = !!line.misc_tax;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ require("dotenv").config({
|
|||||||
|
|
||||||
async function RunTheTest() {
|
async function RunTheTest() {
|
||||||
const bodyshopids = ["a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"];
|
const bodyshopids = ["a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"];
|
||||||
const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImFhMDhlN2M3ODNkYjhjOGFjNGNhNzJhZjdmOWRkN2JiMzk4ZjE2ZGMiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUm9tZSBEZXZlbG9wbWVudCIsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciJdLCJ4LWhhc3VyYS11c2VyLWlkIjoidDZZbTFORGxDRE9QWnIzRjliZ3VXSDRMaFNYMiJ9LCJpb2FkbWluIjp0cnVlLCJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vcm9tZS1wcm9kLTEiLCJhdWQiOiJyb21lLXByb2QtMSIsImF1dGhfdGltZSI6MTY5NTE1MDU0NywidXNlcl9pZCI6InQ2WW0xTkRsQ0RPUFpyM0Y5Ymd1V0g0TGhTWDIiLCJzdWIiOiJ0NlltMU5EbENET1BacjNGOWJndVdINExoU1gyIiwiaWF0IjoxNjk1Mzk5MTM0LCJleHAiOjE2OTU0MDI3MzQsImVtYWlsIjoicGF0cmlja0Byb21lLmRldiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJwYXRyaWNrQHJvbWUuZGV2Il19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.X8PeG0Y0TW08Tx1sBqpWw9N1YYxJWd4lOEAH2KA7Xel6ehg50WdHf42W4RXdGBc-TPzbJgzLJg4jc8_cmSiDiDojSnVzrmfBrbugLRd1Hk31784SvYKb_i1GU1p3s5W-rBHbi1htnNyXqV0nhOgbnOJphJL2l91WG_YaBRA_QiGgy4rAdBhi12LLS5KWGlrP9T99hOfL7o8kG1rhO5y1bGadlpmXAjUpMQAlMX8QVXAe6DB-61vDJPyTpTbfT3yUZfNppNSqqu1wK2c08QwniXf5qhIyGBNeB6qunlDQhFBP-grGcUvVb9ijHHtX7WiFb7wd-AY3oNCx1i5hi5UdPQ`;
|
const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImFkNWM1ZTlmNTdjOWI2NDYzYzg1ODQ1YTA4OTlhOWQ0MTI5MmM4YzMiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUm9tZSBEZXZlbG9wbWVudCIsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciJdLCJ4LWhhc3VyYS11c2VyLWlkIjoidDZZbTFORGxDRE9QWnIzRjliZ3VXSDRMaFNYMiJ9LCJpb2FkbWluIjp0cnVlLCJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vcm9tZS1wcm9kLTEiLCJhdWQiOiJyb21lLXByb2QtMSIsImF1dGhfdGltZSI6MTY5NTE1MDU0NywidXNlcl9pZCI6InQ2WW0xTkRsQ0RPUFpyM0Y5Ymd1V0g0TGhTWDIiLCJzdWIiOiJ0NlltMU5EbENET1BacjNGOWJndVdINExoU1gyIiwiaWF0IjoxNjk1ODQ5OTQxLCJleHAiOjE2OTU4NTM1NDEsImVtYWlsIjoicGF0cmlja0Byb21lLmRldiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJwYXRyaWNrQHJvbWUuZGV2Il19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.pLA1hXPQrlVmFNlo-US2MkvGfWm4kDbBFVHtwKenGu6aNBEw_NdiN6BxIy35EuHLuZjSF6HrLbVYP2FE_7U85SPf5IhpO3aED1avxiI2d557ylcZQZasgWmJmPpufE1HFQtUwTt4PxHmvQVp2b-9l_uYDHNlzE_MUdJoDEA262UQxIkost2kBK_3D3PgBRB6CVHDNLWkb8DbMjx1gyYzmEW7RqChP9NGePaZDDL3VS8PhglQ1MFPyMI-UdaIp_nWeb-AQScNvRQscyQy3LkmVKeKXqacUcTKWHPBZjING3Thzfnek0IzSR7GjMgPZ3TQiK_N12UYga9-z31qqUgctg`;
|
||||||
const { jobs } = await client.request(
|
const { jobs } = await client.request(
|
||||||
gql`
|
gql`
|
||||||
query GET_JOBS($bodyshopids: [uuid!]!) {
|
query GET_JOBS($bodyshopids: [uuid!]!) {
|
||||||
@@ -42,7 +42,10 @@ async function RunTheTest() {
|
|||||||
|
|
||||||
const results = [];
|
const results = [];
|
||||||
|
|
||||||
for (const job of jobs) {
|
for (const [index, job] of jobs.entries()) {
|
||||||
|
process.stdout.cursorTo(0);
|
||||||
|
process.stdout.write(`Processing job ${index + 1} of ${jobs.length}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await axios.post(
|
await axios.post(
|
||||||
`http://localhost:4000/job/totalsssu`,
|
`http://localhost:4000/job/totalsssu`,
|
||||||
@@ -87,7 +90,7 @@ async function RunTheTest() {
|
|||||||
} else {
|
} else {
|
||||||
result.result = "PASS";
|
result.result = "PASS";
|
||||||
}
|
}
|
||||||
// console.log(`${result.result} => RO ${job.ro_number} - ${job.id} `);
|
// console.log(`${result.result} => RO ${job.ro_number} - ${job.id} `);
|
||||||
|
|
||||||
results.push(result);
|
results.push(result);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -117,3 +120,15 @@ async function RunTheTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
RunTheTest();
|
RunTheTest();
|
||||||
|
|
||||||
|
// mutation {
|
||||||
|
// delete_jobs(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
|
||||||
|
// affected_rows
|
||||||
|
// }
|
||||||
|
// delete_owners(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
|
||||||
|
// affected_rows
|
||||||
|
// }
|
||||||
|
// delete_vehicles(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
|
||||||
|
// affected_rows
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|||||||
@@ -34,15 +34,10 @@ exports.default = function ({
|
|||||||
}
|
}
|
||||||
//Parts Lines Mappings.
|
//Parts Lines Mappings.
|
||||||
if (jobline.profitcenter_part) {
|
if (jobline.profitcenter_part) {
|
||||||
let DineroAmount = Dinero({
|
const discountAmount =
|
||||||
amount: Math.round((jobline.act_price || 0) * 100),
|
|
||||||
}).multiply(jobline.part_qty || 1);
|
|
||||||
|
|
||||||
// console.log("Have a part discount", jobline);
|
|
||||||
DineroAmount = DineroAmount.add(
|
|
||||||
((jobline.prt_dsmk_m && jobline.prt_dsmk_m !== 0) ||
|
((jobline.prt_dsmk_m && jobline.prt_dsmk_m !== 0) ||
|
||||||
(jobline.prt_dsmk_p && jobline.prt_dsmk_p !== 0)) &&
|
(jobline.prt_dsmk_p && jobline.prt_dsmk_p !== 0)) &&
|
||||||
DiscountNotAlreadyCounted(jobline, jobs_by_pk.joblines)
|
DiscountNotAlreadyCounted(jobline, jobs_by_pk.joblines)
|
||||||
? jobline.prt_dsmk_m
|
? jobline.prt_dsmk_m
|
||||||
? Dinero({ amount: Math.round(jobline.prt_dsmk_m * 100) })
|
? Dinero({ amount: Math.round(jobline.prt_dsmk_m * 100) })
|
||||||
: Dinero({
|
: Dinero({
|
||||||
@@ -51,8 +46,13 @@ exports.default = function ({
|
|||||||
.multiply(jobline.part_qty || 0)
|
.multiply(jobline.part_qty || 0)
|
||||||
.percentage(Math.abs(jobline.prt_dsmk_p || 0))
|
.percentage(Math.abs(jobline.prt_dsmk_p || 0))
|
||||||
.multiply(jobline.prt_dsmk_p > 0 ? 1 : -1)
|
.multiply(jobline.prt_dsmk_p > 0 ? 1 : -1)
|
||||||
: Dinero()
|
: Dinero();
|
||||||
);
|
|
||||||
|
let DineroAmount = Dinero({
|
||||||
|
amount: Math.round((jobline.act_price || 0) * 100),
|
||||||
|
})
|
||||||
|
.multiply(jobline.part_qty || 0)
|
||||||
|
.add(discountAmount);
|
||||||
|
|
||||||
const account = responsibilityCenters.profits.find(
|
const account = responsibilityCenters.profits.find(
|
||||||
(i) => jobline.profitcenter_part.toLowerCase() === i.name.toLowerCase()
|
(i) => jobline.profitcenter_part.toLowerCase() === i.name.toLowerCase()
|
||||||
@@ -575,13 +575,13 @@ exports.default = function ({
|
|||||||
|
|
||||||
const federal_tax = Dinero(job_totals.totals.federal_tax);
|
const federal_tax = Dinero(job_totals.totals.federal_tax);
|
||||||
const QboTaxId =
|
const QboTaxId =
|
||||||
process.env.COUNTRY === "USA"
|
process.env.COUNTRY === "USA"
|
||||||
? CheckQBOUSATaxID({
|
? CheckQBOUSATaxID({
|
||||||
// jobline: jobline,
|
// jobline: jobline,
|
||||||
type: "adjustment",
|
type: "adjustment",
|
||||||
job: jobs_by_pk,
|
job: jobs_by_pk,
|
||||||
})
|
})
|
||||||
: taxCodes[taxAccountCode];
|
: taxCodes[taxAccountCode];
|
||||||
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
||||||
const taxAmount = Dinero(
|
const taxAmount = Dinero(
|
||||||
job_totals.totals.us_sales_tax_breakdown[`ty${tyCounter}Tax`]
|
job_totals.totals.us_sales_tax_breakdown[`ty${tyCounter}Tax`]
|
||||||
|
|||||||
@@ -1169,10 +1169,7 @@ exports.GET_JOB_BY_PK = `query GET_JOB_BY_PK($id: uuid!) {
|
|||||||
est_ct_ln
|
est_ct_ln
|
||||||
cieca_pfl
|
cieca_pfl
|
||||||
cieca_pft
|
cieca_pft
|
||||||
vehicle{
|
cieca_pfo
|
||||||
id
|
|
||||||
notes
|
|
||||||
}
|
|
||||||
est_ph1
|
est_ph1
|
||||||
est_ea
|
est_ea
|
||||||
selling_dealer
|
selling_dealer
|
||||||
@@ -1293,19 +1290,6 @@ vehicle{
|
|||||||
prt_dsmk_m
|
prt_dsmk_m
|
||||||
misc_amt
|
misc_amt
|
||||||
misc_tax
|
misc_tax
|
||||||
parts_order_lines {
|
|
||||||
id
|
|
||||||
parts_order {
|
|
||||||
id
|
|
||||||
order_number
|
|
||||||
order_date
|
|
||||||
user_email
|
|
||||||
vendor {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
|
|||||||
@@ -62,8 +62,8 @@ async function TotalsServerSide(req, res) {
|
|||||||
let ret = {
|
let ret = {
|
||||||
rates: await CalculateRatesTotals({ job, client }),
|
rates: await CalculateRatesTotals({ job, client }),
|
||||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates, job),
|
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates, job),
|
||||||
additional: CalculateAdditional(job),
|
|
||||||
};
|
};
|
||||||
|
ret.additional = CalculateAdditional(job);
|
||||||
ret.totals = CalculateTaxesTotals(job, ret);
|
ret.totals = CalculateTaxesTotals(job, ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -96,8 +96,8 @@ async function Totals(req, res) {
|
|||||||
let ret = {
|
let ret = {
|
||||||
rates: await CalculateRatesTotals({ job, client }),
|
rates: await CalculateRatesTotals({ job, client }),
|
||||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates, job),
|
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates, job),
|
||||||
additional: CalculateAdditional(job),
|
|
||||||
};
|
};
|
||||||
|
ret.additional = CalculateAdditional(job);
|
||||||
ret.totals = CalculateTaxesTotals(job, ret);
|
ret.totals = CalculateTaxesTotals(job, ret);
|
||||||
|
|
||||||
res.status(200).json(ret);
|
res.status(200).json(ret);
|
||||||
@@ -261,6 +261,7 @@ async function CalculateRatesTotals({ job, client }) {
|
|||||||
let hasMapaLine = false;
|
let hasMapaLine = false;
|
||||||
let hasMashLine = false;
|
let hasMashLine = false;
|
||||||
let hasMahwLine = false;
|
let hasMahwLine = false;
|
||||||
|
let hasCustomMahwLine;
|
||||||
let mapaOpCodes = ParseCalopCode(job.materials["mapa"]?.cal_opcode);
|
let mapaOpCodes = ParseCalopCode(job.materials["mapa"]?.cal_opcode);
|
||||||
let mashOpCodes = ParseCalopCode(job.materials["mash"]?.cal_opcode);
|
let mashOpCodes = ParseCalopCode(job.materials["mash"]?.cal_opcode);
|
||||||
|
|
||||||
@@ -279,9 +280,21 @@ async function CalculateRatesTotals({ job, client }) {
|
|||||||
amount: Math.round((item.act_price || 0) * 100),
|
amount: Math.round((item.act_price || 0) * 100),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (item.line_desc?.toLowerCase().includes("hazardous waste")) {
|
//We might add a hazardous waste line. So we'll need to make sure we only pick up the CCC one.
|
||||||
|
if (
|
||||||
|
item.line_desc?.toLowerCase().includes("hazardous waste") &&
|
||||||
|
!item.manual_line &&
|
||||||
|
item.part_type === null &&
|
||||||
|
item.lbr_op !== "OP16" //Seems to be that it is OP16 for sublet lines.
|
||||||
|
) {
|
||||||
hasMahwLine = item;
|
hasMahwLine = item;
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
item.line_desc?.toLowerCase().includes("hazardous waste") &&
|
||||||
|
item.manual_line
|
||||||
|
) {
|
||||||
|
hasCustomMahwLine = item;
|
||||||
|
}
|
||||||
|
|
||||||
if (item.mod_lbr_ty) {
|
if (item.mod_lbr_ty) {
|
||||||
//Check to see if it has 0 hours and a price instead.
|
//Check to see if it has 0 hours and a price instead.
|
||||||
@@ -377,30 +390,39 @@ async function CalculateRatesTotals({ job, client }) {
|
|||||||
stlMahw.ttl_amt !== 0 &&
|
stlMahw.ttl_amt !== 0 &&
|
||||||
(!hasMahwLine || hasMahwLine.act_price !== stlMahw.ttl_amt)
|
(!hasMahwLine || hasMahwLine.act_price !== stlMahw.ttl_amt)
|
||||||
) {
|
) {
|
||||||
|
//The Mahw line that has been added doesn't match with what we have in the STL. Add/update the adjusting line so that the balance is correct.
|
||||||
|
|
||||||
//Add a hazardous waste material line in case there isn't one on the estimate.
|
//Add a hazardous waste material line in case there isn't one on the estimate.
|
||||||
if (hasMahwLine) {
|
let newPrice = stlMahw.ttl_amt;
|
||||||
|
if (hasCustomMahwLine) {
|
||||||
//Update it
|
//Update it
|
||||||
job.joblines.forEach((jl) => {
|
job.joblines.forEach((jl) => {
|
||||||
if (jl.id === hasMahwLine.id) {
|
if (jl.id === hasCustomMahwLine.id) {
|
||||||
jl.act_price = stlMahw.ttl_amt;
|
jl.act_price = newPrice;
|
||||||
|
jl.manual_line = true;
|
||||||
|
jl.tax_part = stlMahw.tax_amt > 0 ? true : false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await client.request(queries.UPDATE_JOB_LINE, {
|
await client.request(queries.UPDATE_JOB_LINE, {
|
||||||
lineId: hasMahwLine.id,
|
lineId: hasCustomMahwLine.id,
|
||||||
line: { act_price: stlMahw.ttl_amt },
|
line: {
|
||||||
|
act_price: newPrice,
|
||||||
|
manual_line: true,
|
||||||
|
tax_part: stlMahw.tax_amt > 0 ? true : false,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const newMahwLine = {
|
const newMahwLine = {
|
||||||
line_desc: "Hazardous Waste Removal*",
|
line_desc: "Hazardous Waste Removal*",
|
||||||
part_type: "PAS",
|
part_type: null,
|
||||||
oem_partno: null,
|
oem_partno: null,
|
||||||
db_price: 0,
|
db_price: 0,
|
||||||
act_price: stlMahw.ttl_amt,
|
act_price: newPrice,
|
||||||
part_qty: 1,
|
part_qty: 1,
|
||||||
//mod_lbr_ty: "LAB",
|
mod_lbr_ty: "LAB",
|
||||||
db_hrs: 0,
|
db_hrs: 0,
|
||||||
mod_lb_hrs: 0,
|
mod_lb_hrs: 0,
|
||||||
lbr_op: "OP11",
|
lbr_op: "OP0",
|
||||||
lbr_amt: 0,
|
lbr_amt: 0,
|
||||||
op_code_desc: "REMOVE / REPLACE",
|
op_code_desc: "REMOVE / REPLACE",
|
||||||
tax_part: stlMahw.tax_amt > 0 ? true : false,
|
tax_part: stlMahw.tax_amt > 0 ? true : false,
|
||||||
@@ -710,6 +732,9 @@ function IsAdditionalCost(jobLine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function CalculateAdditional(job) {
|
function CalculateAdditional(job) {
|
||||||
|
const stlTowing = job.cieca_stl?.data.find((c) => c.ttl_type === "OTTW");
|
||||||
|
const stlStorage = job.cieca_stl?.data.find((c) => c.ttl_type === "OTST");
|
||||||
|
|
||||||
let ret = {
|
let ret = {
|
||||||
additionalCosts: null,
|
additionalCosts: null,
|
||||||
additionalCostItems: [],
|
additionalCostItems: [],
|
||||||
@@ -720,9 +745,11 @@ function CalculateAdditional(job) {
|
|||||||
pvrt: null,
|
pvrt: null,
|
||||||
total: null,
|
total: null,
|
||||||
};
|
};
|
||||||
ret.towing = Dinero({
|
ret.towing = stlTowing
|
||||||
amount: Math.round((job.towing_payable || 0) * 100),
|
? Dinero({ amount: Math.round(stlTowing.ttl_amt * 100) })
|
||||||
});
|
: Dinero({
|
||||||
|
amount: Math.round((job.towing_payable || 0) * 100),
|
||||||
|
});
|
||||||
|
|
||||||
ret.additionalCosts = job.joblines
|
ret.additionalCosts = job.joblines
|
||||||
.filter((jl) => !jl.removed && IsAdditionalCost(jl))
|
.filter((jl) => !jl.removed && IsAdditionalCost(jl))
|
||||||
@@ -747,9 +774,11 @@ function CalculateAdditional(job) {
|
|||||||
ret.adjustments = Dinero({
|
ret.adjustments = Dinero({
|
||||||
amount: Math.round((job.adjustment_bottom_line || 0) * 100),
|
amount: Math.round((job.adjustment_bottom_line || 0) * 100),
|
||||||
});
|
});
|
||||||
ret.storage = Dinero({
|
ret.storage = stlStorage
|
||||||
amount: Math.round((job.storage_payable || 0) * 100),
|
? Dinero({ amount: Math.round(stlStorage.ttl_amt * 100) })
|
||||||
});
|
: Dinero({
|
||||||
|
amount: Math.round((job.storage_payable || 0) * 100),
|
||||||
|
});
|
||||||
ret.pvrt = Dinero({
|
ret.pvrt = Dinero({
|
||||||
amount: Math.round((job.ca_bc_pvrt || 0) * 100),
|
amount: Math.round((job.ca_bc_pvrt || 0) * 100),
|
||||||
});
|
});
|
||||||
@@ -812,6 +841,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
|
|
||||||
MAPA: Dinero(),
|
MAPA: Dinero(),
|
||||||
MASH: Dinero(),
|
MASH: Dinero(),
|
||||||
|
TOW: Dinero(),
|
||||||
|
STOR: Dinero(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@@ -876,9 +907,21 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
//Add towing and storage taxable amounts
|
||||||
|
const stlTowing = job.cieca_stl?.data.find((c) => c.ttl_typecd === "OTTW");
|
||||||
|
const stlStorage = job.cieca_stl?.data.find((c) => c.ttl_typecd === "OTST");
|
||||||
|
|
||||||
console.log("*** Taxable Amounts***");
|
if (stlTowing)
|
||||||
console.table(JSON.parse(JSON.stringify(taxableAmounts)));
|
taxableAmounts.TOW = Dinero({
|
||||||
|
amount: Math.round(stlTowing.t_amt * 100),
|
||||||
|
});
|
||||||
|
if (stlStorage)
|
||||||
|
taxableAmounts.TOW = Dinero({
|
||||||
|
amount: Math.round(stlStorage.t_amt * 100),
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log("*** Taxable Amounts***");
|
||||||
|
// console.table(JSON.parse(JSON.stringify(taxableAmounts)));
|
||||||
|
|
||||||
//For the taxable amounts, figure out which tax type applies.
|
//For the taxable amounts, figure out which tax type applies.
|
||||||
//Then sum up the total of that tax type and then calculate the thresholds.
|
//Then sum up the total of that tax type and then calculate the thresholds.
|
||||||
@@ -903,6 +946,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
const pfp = job.parts_tax_rates;
|
const pfp = job.parts_tax_rates;
|
||||||
const pfl = job.cieca_pfl;
|
const pfl = job.cieca_pfl;
|
||||||
const pfm = job.materials;
|
const pfm = job.materials;
|
||||||
|
const pfo = job.cieca_pfo;
|
||||||
Object.keys(taxableAmounts).map((key) => {
|
Object.keys(taxableAmounts).map((key) => {
|
||||||
try {
|
try {
|
||||||
if (key.startsWith("PA")) {
|
if (key.startsWith("PA")) {
|
||||||
@@ -926,7 +970,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
].add(taxableAmounts[key]);
|
].add(taxableAmounts[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else if (key.startsWith("LA")) {
|
||||||
//Labor.
|
//Labor.
|
||||||
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
||||||
if (IsTrueOrYes(pfl[key][`lbr_tx_in${tyCounter}`])) {
|
if (IsTrueOrYes(pfl[key][`lbr_tx_in${tyCounter}`])) {
|
||||||
@@ -936,6 +980,24 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
].add(taxableAmounts[key]);
|
].add(taxableAmounts[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (key === "TOW") {
|
||||||
|
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
||||||
|
if (IsTrueOrYes(pfo[`tow_t_in${tyCounter}`])) {
|
||||||
|
//This amount is taxable for this type.
|
||||||
|
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[
|
||||||
|
`ty${tyCounter}Tax`
|
||||||
|
].add(taxableAmounts[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (key === "STOR") {
|
||||||
|
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
||||||
|
if (IsTrueOrYes(pfo[`stor_t_in${tyCounter}`])) {
|
||||||
|
//This amount is taxable for this type.
|
||||||
|
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[
|
||||||
|
`ty${tyCounter}Tax`
|
||||||
|
].add(taxableAmounts[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Key with issue", key);
|
console.error("Key with issue", key);
|
||||||
@@ -943,8 +1005,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const remainingTaxableAmounts = taxableAmountsByTier;
|
const remainingTaxableAmounts = taxableAmountsByTier;
|
||||||
console.log("*** Taxable Amounts by Tier***");
|
// console.log("*** Taxable Amounts by Tier***");
|
||||||
console.table(JSON.parse(JSON.stringify(taxableAmountsByTier)));
|
// console.table(JSON.parse(JSON.stringify(taxableAmountsByTier)));
|
||||||
|
|
||||||
Object.keys(taxableAmountsByTier).forEach((taxTierKey) => {
|
Object.keys(taxableAmountsByTier).forEach((taxTierKey) => {
|
||||||
try {
|
try {
|
||||||
@@ -998,8 +1060,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("*** Total Tax by Tier Amounts***");
|
// console.log("*** Total Tax by Tier Amounts***");
|
||||||
console.table(JSON.parse(JSON.stringify(totalTaxByTier)));
|
// console.table(JSON.parse(JSON.stringify(totalTaxByTier)));
|
||||||
|
|
||||||
statePartsTax = statePartsTax
|
statePartsTax = statePartsTax
|
||||||
.add(totalTaxByTier.ty1Tax)
|
.add(totalTaxByTier.ty1Tax)
|
||||||
@@ -1009,7 +1071,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
.add(totalTaxByTier.ty5Tax)
|
.add(totalTaxByTier.ty5Tax)
|
||||||
.add(totalTaxByTier.ty6Tax);
|
.add(totalTaxByTier.ty6Tax);
|
||||||
us_sales_tax_breakdown = totalTaxByTier;
|
us_sales_tax_breakdown = totalTaxByTier;
|
||||||
console.log("Tiered Taxes Total for Parts/Labor", statePartsTax.toFormat());
|
//console.log("Tiered Taxes Total for Parts/Labor", statePartsTax.toFormat());
|
||||||
} else {
|
} else {
|
||||||
//Use the old thing.
|
//Use the old thing.
|
||||||
job.joblines
|
job.joblines
|
||||||
@@ -1061,7 +1123,6 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
console.log(statePartsTax.toFormat(), val.line_desc);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1077,7 +1138,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
); // THis is currently using the lbr tax rate from PFH not PFL.
|
); // THis is currently using the lbr tax rate from PFH not PFL.
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log("Labor Tax Total", laborTaxTotal.toFormat());
|
//console.log("Labor Tax Total", laborTaxTotal.toFormat());
|
||||||
|
|
||||||
let ret = {
|
let ret = {
|
||||||
subtotal: subtotal,
|
subtotal: subtotal,
|
||||||
federal_tax: subtotal
|
federal_tax: subtotal
|
||||||
@@ -1089,34 +1151,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
),
|
),
|
||||||
statePartsTax,
|
statePartsTax,
|
||||||
us_sales_tax_breakdown,
|
us_sales_tax_breakdown,
|
||||||
state_tax: statePartsTax
|
state_tax: statePartsTax,
|
||||||
//.add(laborTaxTotal)
|
|
||||||
.add(
|
|
||||||
otherTotals.additional.adjustments.percentage(
|
|
||||||
(job.tax_lbr_rt || 0) * 100
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.add(
|
|
||||||
otherTotals.additional.towing.percentage((job.tax_tow_rt || 0) * 100)
|
|
||||||
)
|
|
||||||
.add(
|
|
||||||
otherTotals.additional.storage.percentage((job.tax_str_rt || 0) * 100)
|
|
||||||
),
|
|
||||||
// .add(additionalItemsTax) // 0 if using PFP method.
|
|
||||||
// .add(
|
|
||||||
// otherTotals.rates.mapa.hasMapaLine === false //If parts and materials were not added as lines, we must calculate the taxes on them.
|
|
||||||
// ? otherTotals.rates.mapa.total.percentage(
|
|
||||||
// (job.tax_paint_mat_rt || 0) * 100
|
|
||||||
// )
|
|
||||||
// : Dinero()
|
|
||||||
// )
|
|
||||||
// .add(
|
|
||||||
// otherTotals.rates.mash.hasMashLine === false //If parts and materials were not added as lines, we must calculate the taxes on them.
|
|
||||||
// ? otherTotals.rates.mash.total.percentage(
|
|
||||||
// (job.tax_shop_mat_rt || 0) * 100
|
|
||||||
// )
|
|
||||||
// : Dinero()
|
|
||||||
// )
|
|
||||||
local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100),
|
local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100),
|
||||||
};
|
};
|
||||||
ret.total_repairs = ret.subtotal
|
ret.total_repairs = ret.subtotal
|
||||||
@@ -1153,6 +1188,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
|||||||
exports.default = Totals;
|
exports.default = Totals;
|
||||||
|
|
||||||
function DiscountNotAlreadyCounted(jobline, joblines) {
|
function DiscountNotAlreadyCounted(jobline, joblines) {
|
||||||
|
return false;
|
||||||
//CCC already factors in the discount. If the difference between the 2 is exactly the discount, it's all good.
|
//CCC already factors in the discount. If the difference between the 2 is exactly the discount, it's all good.
|
||||||
if (
|
if (
|
||||||
Math.round(
|
Math.round(
|
||||||
|
|||||||
Reference in New Issue
Block a user