From e8b7e2f0b9c6c00052396a07baa0de936f0a269c Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Wed, 26 May 2021 09:06:05 -0700
Subject: [PATCH] IO-1152 Add in part mark up for BC Economical claims.
---
bodyshop_translations.babel | 21 +++++
.../job-detail-lines/job-lines.component.jsx | 9 +-
.../job-totals.table.parts.component.jsx | 31 ++++---
client/src/graphql/jobs.queries.js | 1 +
client/src/translations/en_us/common.json | 1 +
client/src/translations/es/common.json | 1 +
client/src/translations/fr/common.json | 1 +
server/accounting/qbxml/qbxml-receivables.js | 13 ++-
server/graphql-client/queries.js | 1 +
server/job/job-costing.js | 84 ++++++++++++-------
server/job/job-totals.js | 34 ++++++--
11 files changed, 147 insertions(+), 50 deletions(-)
diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index 446075c77..0faad2b83 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -22179,6 +22179,27 @@
+
+ prt_dsmk_total
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
rates
false
diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx
index 02c73382a..cd88da672 100644
--- a/client/src/components/job-detail-lines/job-lines.component.jsx
+++ b/client/src/components/job-detail-lines/job-lines.component.jsx
@@ -155,7 +155,14 @@ export function JobLinesComponent({
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
ellipsis: true,
render: (text, record) => (
- {record.act_price}
+ <>
+ {record.act_price}
+ {record.prt_dsmk_p !== 0 && (
+ {`(${record.prt_dsmk_p}%)`}
+ )}
+ >
),
},
{
diff --git a/client/src/components/job-totals-table/job-totals.table.parts.component.jsx b/client/src/components/job-totals-table/job-totals.table.parts.component.jsx
index 7f1b884d6..93ed6eea6 100644
--- a/client/src/components/job-totals-table/job-totals.table.parts.component.jsx
+++ b/client/src/components/job-totals-table/job-totals.table.parts.component.jsx
@@ -69,17 +69,28 @@ export default function JobTotalsTableParts({ job }) {
x: true,
}}
summary={() => (
-
-
- {t("jobs.labels.partstotal")}
-
+ <>
+
+
+ {t("jobs.labels.prt_dsmk_total")}
+
-
-
- {Dinero(job.job_totals.parts.parts.total).toFormat()}
-
-
-
+
+ {Dinero(job.job_totals.parts.parts.prt_dsmk_total).toFormat()}
+
+
+
+
+ {t("jobs.labels.partstotal")}
+
+
+
+
+ {Dinero(job.job_totals.parts.parts.total).toFormat()}
+
+
+
+ >
)}
/>
);
diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js
index 0f1d23141..9d1dbea66 100644
--- a/client/src/graphql/jobs.queries.js
+++ b/client/src/graphql/jobs.queries.js
@@ -528,6 +528,7 @@ export const GET_JOB_BY_PK = gql`
tax_part
db_ref
manual_line
+ prt_dsmk_p
billlines(limit: 1, order_by: { bill: { date: desc } }) {
id
quantity
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index 97730f5e4..86345398c 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -1316,6 +1316,7 @@
"partstotal": "This is the total of all parts and sublet amounts on the vehicle (some of these may require an in-house invoice).
\nItems such as shop and paint materials, labor online lines, etc. are not included in this total.",
"totalreturns": "The total amount of returns created for this job."
},
+ "prt_dsmk_total": "Line Item Markup",
"rates": "Rates",
"rates_subtotal": "All Rates Subtotal",
"reconciliation": {
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index ccbcc56ad..ac60ee51a 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -1316,6 +1316,7 @@
"partstotal": "",
"totalreturns": ""
},
+ "prt_dsmk_total": "",
"rates": "Tarifas",
"rates_subtotal": "",
"reconciliation": {
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index b34210452..7dc82bfce 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -1316,6 +1316,7 @@
"partstotal": "",
"totalreturns": ""
},
+ "prt_dsmk_total": "",
"rates": "Les taux",
"rates_subtotal": "",
"reconciliation": {
diff --git a/server/accounting/qbxml/qbxml-receivables.js b/server/accounting/qbxml/qbxml-receivables.js
index ac24f4408..49f67f397 100644
--- a/server/accounting/qbxml/qbxml-receivables.js
+++ b/server/accounting/qbxml/qbxml-receivables.js
@@ -203,7 +203,8 @@ const generateInvoiceQbxml = (
//Create the invoice lines mapping.
jobs_by_pk.joblines.map((jobline) => {
//Parts Lines
- if (jobline.db_ref === "936008") { //If either of these DB REFs change, they also need to change in job-totals calculations.
+ if (jobline.db_ref === "936008") {
+ //If either of these DB REFs change, they also need to change in job-totals calculations.
hasMapaLine = true;
}
if (jobline.db_ref === "936007") {
@@ -213,7 +214,15 @@ const generateInvoiceQbxml = (
if (jobline.profitcenter_part && jobline.act_price) {
const DineroAmount = Dinero({
amount: Math.round(jobline.act_price * 100),
- }).multiply(jobline.part_qty || 1);
+ })
+ .multiply(jobline.part_qty || 1)
+ .add(
+ Dinero({
+ amount: Math.round((jobline.act_price || 0) * 100),
+ })
+ .multiply(jobline.part_qty || 0)
+ .percentage(jobline.prt_dsmk_p)
+ );
const account = responsibilityCenters.profits.find(
(i) => jobline.profitcenter_part.toLowerCase() === i.name.toLowerCase()
);
diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js
index c9d7f3173..fd3a07228 100644
--- a/server/graphql-client/queries.js
+++ b/server/graphql-client/queries.js
@@ -566,6 +566,7 @@ exports.GET_JOB_BY_PK = ` query GET_JOB_BY_PK($id: uuid!) {
tax_part
db_ref
manual_line
+ prt_dsmk_p
parts_order_lines {
id
parts_order {
diff --git a/server/job/job-costing.js b/server/job/job-costing.js
index 7a15b4f29..7b98acf1e 100644
--- a/server/job/job-costing.js
+++ b/server/job/job-costing.js
@@ -122,27 +122,34 @@ async function JobCostingMulti(req, res) {
});
//Add all summary data.
- multiSummary.summaryData.totalPartsSales = multiSummary.summaryData.totalPartsSales.add(
- costingData.summaryData.totalPartsSales
- );
- multiSummary.summaryData.totalSales = multiSummary.summaryData.totalSales.add(
- costingData.summaryData.totalSales
- );
- multiSummary.summaryData.totalLaborCost = multiSummary.summaryData.totalLaborCost.add(
- costingData.summaryData.totalLaborCost
- );
- multiSummary.summaryData.totalLaborSales = multiSummary.summaryData.totalLaborSales.add(
- costingData.summaryData.totalLaborSales
- );
- multiSummary.summaryData.totalPartsCost = multiSummary.summaryData.totalPartsCost.add(
- costingData.summaryData.totalPartsCost
- );
- multiSummary.summaryData.totalCost = multiSummary.summaryData.totalCost.add(
- costingData.summaryData.totalCost
- );
- multiSummary.summaryData.gpdollars = multiSummary.summaryData.gpdollars.add(
- costingData.summaryData.gpdollars
- );
+ multiSummary.summaryData.totalPartsSales =
+ multiSummary.summaryData.totalPartsSales.add(
+ costingData.summaryData.totalPartsSales
+ );
+ multiSummary.summaryData.totalSales =
+ multiSummary.summaryData.totalSales.add(
+ costingData.summaryData.totalSales
+ );
+ multiSummary.summaryData.totalLaborCost =
+ multiSummary.summaryData.totalLaborCost.add(
+ costingData.summaryData.totalLaborCost
+ );
+ multiSummary.summaryData.totalLaborSales =
+ multiSummary.summaryData.totalLaborSales.add(
+ costingData.summaryData.totalLaborSales
+ );
+ multiSummary.summaryData.totalPartsCost =
+ multiSummary.summaryData.totalPartsCost.add(
+ costingData.summaryData.totalPartsCost
+ );
+ multiSummary.summaryData.totalCost =
+ multiSummary.summaryData.totalCost.add(
+ costingData.summaryData.totalCost
+ );
+ multiSummary.summaryData.gpdollars =
+ multiSummary.summaryData.gpdollars.add(
+ costingData.summaryData.gpdollars
+ );
console.timeEnd(`SummaryOfCostingData-${job.id}`);
//Take the summary data & add it to total summary data.
});
@@ -220,9 +227,8 @@ function GenerateCostingData(job) {
}).multiply(val.mod_lb_hrs || 0);
if (!acc.labor[laborProfitCenter])
acc.labor[laborProfitCenter] = Dinero();
- acc.labor[laborProfitCenter] = acc.labor[laborProfitCenter].add(
- laborAmount
- );
+ acc.labor[laborProfitCenter] =
+ acc.labor[laborProfitCenter].add(laborAmount);
if (val.mod_lbr_ty === "LAR") {
if (!acc.labor[defaultProfits["MAPA"]])
@@ -265,12 +271,19 @@ function GenerateCostingData(job) {
);
const partsAmount = Dinero({
amount: Math.round((val.act_price || 0) * 100),
- }).multiply(val.part_qty || 1);
+ })
+ .multiply(val.part_qty || 1)
+ .add(
+ Dinero({
+ amount: Math.round((val.act_price || 0) * 100),
+ })
+ .multiply(val.part_qty || 0)
+ .percentage(val.prt_dsmk_p)
+ );
if (!acc.parts[partsProfitCenter])
acc.parts[partsProfitCenter] = Dinero();
- acc.parts[partsProfitCenter] = acc.parts[partsProfitCenter].add(
- partsAmount
- );
+ acc.parts[partsProfitCenter] =
+ acc.parts[partsProfitCenter].add(partsAmount);
}
//To deal with additional costs.
@@ -287,7 +300,15 @@ function GenerateCostingData(job) {
} else {
const partsAmount = Dinero({
amount: Math.round((val.act_price || 0) * 100),
- }).multiply(val.part_qty || 1);
+ })
+ .multiply(val.part_qty || 1)
+ .add(
+ Dinero({
+ amount: Math.round((val.act_price || 0) * 100),
+ })
+ .multiply(val.part_qty || 0)
+ .percentage(val.prt_dsmk_p)
+ );
console.log(
`*** partsAmount`,
val.line_desc,
@@ -296,9 +317,8 @@ function GenerateCostingData(job) {
);
if (!acc.parts[partsProfitCenter])
acc.parts[partsProfitCenter] = Dinero();
- acc.parts[partsProfitCenter] = acc.parts[partsProfitCenter].add(
- partsAmount
- );
+ acc.parts[partsProfitCenter] =
+ acc.parts[partsProfitCenter].add(partsAmount);
}
}
diff --git a/server/job/job-totals.js b/server/job/job-totals.js
index b0798c62d..dea522a89 100644
--- a/server/job/job-totals.js
+++ b/server/job/job-totals.js
@@ -86,6 +86,7 @@ async function Totals(req, res) {
res.status(400).send(JSON.stringify(error));
}
}
+
function CalculateRatesTotals(ratesList) {
const jobLines = ratesList.joblines.filter((jl) => !jl.removed);
@@ -211,6 +212,13 @@ function CalculatePartsTotals(jobLines) {
...acc,
parts: {
...acc.parts,
+ prt_dsmk_total: acc.parts.prt_dsmk_total.add(
+ Dinero({
+ amount: Math.round((value.act_price || 0) * 100),
+ })
+ .multiply(value.part_qty || 0)
+ .percentage(value.prt_dsmk_p)
+ ),
list: {
...acc.parts.list,
[value.part_type]:
@@ -229,11 +237,19 @@ function CalculatePartsTotals(jobLines) {
}).multiply(value.part_qty || 0),
},
},
- subtotal: acc.parts.subtotal.add(
- Dinero({
- amount: Math.round(value.act_price * 100),
- }).multiply(value.part_qty || 0)
- ),
+ subtotal: acc.parts.subtotal
+ .add(
+ Dinero({
+ amount: Math.round(value.act_price * 100),
+ }).multiply(value.part_qty || 0)
+ )
+ .add(
+ Dinero({
+ amount: Math.round((value.act_price || 0) * 100),
+ })
+ .multiply(value.part_qty || 0)
+ .percentage(value.prt_dsmk_p)
+ ),
},
};
}
@@ -241,6 +257,7 @@ function CalculatePartsTotals(jobLines) {
{
parts: {
list: {},
+ prt_dsmk_total: Dinero(),
subtotal: Dinero({ amount: 0 }),
total: Dinero({ amount: 0 }),
},
@@ -360,6 +377,13 @@ function CalculateTaxesTotals(job, otherTotals) {
statePartsTax = statePartsTax.add(
Dinero({ amount: Math.round((val.act_price || 0) * 100) })
.multiply(val.part_qty || 1)
+ .add(
+ Dinero({
+ amount: Math.round((val.act_price || 0) * 100),
+ })
+ .multiply(val.part_qty || 0)
+ .percentage(val.prt_dsmk_p)
+ )
.percentage(
((job.parts_tax_rates &&
job.parts_tax_rates[val.part_type] &&