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] &&