From 84959209e64a5713286ece67a813d397ddb67dae Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Mon, 12 Apr 2021 10:19:37 -0700 Subject: [PATCH] IO-836 Added all job costing data. --- client/package-lock.json | 14 ++-- server/job/job-costing.js | 141 +++++++++++++++++++++++++++++++++++--- 2 files changed, 139 insertions(+), 16 deletions(-) diff --git a/client/package-lock.json b/client/package-lock.json index 80e6658b5..d9687e26f 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -2292,9 +2292,9 @@ } }, "@popperjs/core": { - "version": "2.9.1", - "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.1.tgz", - "integrity": "sha512-DvJbbn3dUgMxDnJLH+RZQPnXak1h4ZVYQ7CWiFWjQwBFkVajT4rfw2PdpHLTSTwxrYfnoEXkuBiwkDm6tPMQeA==" + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz", + "integrity": "sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q==" }, "@protobufjs/aspromise": { "version": "1.1.2", @@ -14417,13 +14417,13 @@ } }, "react-big-calendar": { - "version": "0.32.0", - "resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.32.0.tgz", - "integrity": "sha512-IidodG2oCd9VH7f9AsZAMyPZw12wLoicjHzEECrqdg3PIOuKOTScYhsqrSdNq+5j3vfy5sby5cWdBxgViMz9Mg==", + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-0.33.2.tgz", + "integrity": "sha512-bUpkLdkHyAHj7wYdPdAXbhPE1S3y0eFJ69m4Hi2rz41gdgP3Ti10rTOhRYYsO7GS4RGqsCUtUrn37iHqdcOJog==", "requires": { "@babel/runtime": "^7.1.5", "clsx": "^1.0.4", - "date-arithmetic": "^4.0.1", + "date-arithmetic": "^4.1.0", "dom-helpers": "^5.1.0", "invariant": "^2.2.4", "lodash": "^4.17.11", diff --git a/server/job/job-costing.js b/server/job/job-costing.js index ed9a50145..5059e14cc 100644 --- a/server/job/job-costing.js +++ b/server/job/job-costing.js @@ -57,16 +57,129 @@ async function JobCostingMulti(req, res) { }); //for Each!*************** + + const multiSummary = { + costCenterData: [], + summaryData: { + totalLaborSales: Dinero({ amount: 0 }), + totalPartsSales: Dinero({ amount: 0 }), + totalSales: Dinero({ amount: 0 }), + totalLaborCost: Dinero({ amount: 0 }), + totalPartsCost: Dinero({ amount: 0 }), + totalCost: Dinero({ amount: 0 }), + gpdollars: Dinero({ amount: 0 }), + gppercent: null, + gppercentFormatted: null, + }, + }; + const ret = {}; resp.jobs.map((job) => { console.time(`CostingData-${job.id}`); - ret[job.id] = GenerateCostingData(job); + const costingData = GenerateCostingData(job); + ret[job.id] = costingData; console.timeEnd(`CostingData-${job.id}`); + + console.time(`SummaryOfCostingData-${job.id}`); + + //Merge on a cost center basis. + + costingData.costCenterData.forEach((c) => { + //Find the Cost Center if it exists. + + const CostCenterIndex = multiSummary.costCenterData.findIndex( + (x) => x.cost_center === c.cost_center + ); + + console.log(`CostCenterIndex`, CostCenterIndex); + if (CostCenterIndex >= 0) { + //Add it in place + multiSummary.costCenterData[CostCenterIndex] = { + ...multiSummary.costCenterData[CostCenterIndex], + sale_labor_dinero: multiSummary.costCenterData[ + CostCenterIndex + ].sale_labor_dinero.add(c.sale_labor_dinero), + sale_parts_dinero: multiSummary.costCenterData[ + CostCenterIndex + ].sale_parts_dinero.add(c.sale_parts_dinero), + cost_labor_dinero: multiSummary.costCenterData[ + CostCenterIndex + ].cost_labor_dinero.add(c.cost_labor_dinero), + cost_parts_dinero: multiSummary.costCenterData[ + CostCenterIndex + ].cost_parts_dinero.add(c.cost_parts_dinero), + gpdollars_dinero: multiSummary.costCenterData[ + CostCenterIndex + ].gpdollars_dinero.add(c.gpdollars_dinero), + costs_dinero: multiSummary.costCenterData[ + CostCenterIndex + ].costs_dinero.add(c.costs_dinero), + sales_dinero: multiSummary.costCenterData[ + CostCenterIndex + ].sales_dinero.add(c.sales_dinero), + }; + } else { + //Add it to the list instead. + multiSummary.costCenterData.push(c); + } + }); + + //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 + ); + console.timeEnd(`SummaryOfCostingData-${job.id}`); + //Take the summary data & add it to total summary data. }); + //For each center, recalculate and toFormat() the values. + + const finalCostingdata = multiSummary.costCenterData.map((c) => { + return { + ...c, + sale_labor: c.sale_labor_dinero && c.sale_labor_dinero.toFormat(), + sale_parts: c.sale_parts_dinero && c.sale_parts_dinero.toFormat(), + sales: c.sale_labor_dinero.add(c.sale_parts_dinero).toFormat(), + cost_parts: c.cost_parts_dinero && c.cost_parts_dinero.toFormat(), + cost_labor: c.cost_labor_dinero && c.cost_labor_dinero.toFormat(), + costs: c.cost_parts_dinero.add(c.cost_labor_dinero).toFormat(), + gpdollars: c.gpdollars_dinero.toFormat(), + gppercent: formatGpPercent( + ( + (c.gpdollars_dinero.getAmount() / c.sales_dinero.getAmount()) * + 100 + ).toFixed(2) + ), + }; + }); + + //Calculate thte total gross profit percentages. + console.timeEnd("JobCostingMultiQueryExecution"); - res.status(200).json(ret); + res.status(200).json({ + costCenterData: finalCostingdata, + summaryData: multiSummary.summaryData, + data: ret, + }); } catch (error) { console.log("error", error); res.status(400).send(JSON.stringify(error)); @@ -191,12 +304,6 @@ function GenerateCostingData(job) { 100 ).toFixed(2); - let gppercentFormatted; - if (isNaN(gppercent)) gppercentFormatted = "0%"; - else if (!isFinite(gppercent)) gppercentFormatted = "- ∞"; - else { - gppercentFormatted = `${gppercent}%`; - } //Push summary data to avoid extra loop. summaryData.totalLaborSales = summaryData.totalLaborSales.add(sale_labor); summaryData.totalPartsSales = summaryData.totalPartsSales.add(sale_parts); @@ -211,15 +318,20 @@ function GenerateCostingData(job) { id: idx, cost_center: ccVal, sale_labor: sale_labor && sale_labor.toFormat(), + sale_labor_dinero: sale_labor, sale_parts: sale_parts && sale_parts.toFormat(), + sale_parts_dinero: sale_parts, sales: sale_labor.add(sale_parts).toFormat(), sales_dinero: sale_labor.add(sale_parts), cost_parts: cost_parts && cost_parts.toFormat(), + cost_parts_dinero: cost_parts, cost_labor: cost_labor && cost_labor.toFormat(), + cost_labor_dinero: cost_labor, costs: cost_parts.add(cost_labor).toFormat(), costs_dinero: cost_parts.add(cost_labor), + gpdollars_dinero: gpdollars, gpdollars: gpdollars.toFormat(), - gppercent: gppercentFormatted, + gppercent: formatGpPercent(gppercent), }; }); @@ -243,3 +355,14 @@ function GenerateCostingData(job) { exports.JobCosting = JobCosting; exports.JobCostingMulti = JobCostingMulti; + +const formatGpPercent = (gppercent) => { + let gppercentFormatted; + if (isNaN(gppercent)) gppercentFormatted = "0%"; + else if (!isFinite(gppercent)) gppercentFormatted = "- ∞"; + else { + gppercentFormatted = `${gppercent}%`; + } + + return gppercentFormatted; +};