From ff33b924b200c7b212527ae5c96a3e0db3ced602 Mon Sep 17 00:00:00 2001 From: Allan Carr Date: Mon, 8 Jul 2024 18:07:33 -0700 Subject: [PATCH] IO-2835 CDK Calculate Allocation Route Signed-off-by: Allan Carr --- server/cdk/cdk-calculate-allocations.js | 777 ++++++++++++------------ server/routes/cdkRoutes.js | 2 + 2 files changed, 390 insertions(+), 389 deletions(-) diff --git a/server/cdk/cdk-calculate-allocations.js b/server/cdk/cdk-calculate-allocations.js index b557f322d..c47addbfe 100644 --- a/server/cdk/cdk-calculate-allocations.js +++ b/server/cdk/cdk-calculate-allocations.js @@ -16,403 +16,402 @@ const { DiscountNotAlreadyCounted } = InstanceManager({ promanager: "USE_ROME" }); +exports.defaultRoute = async function (req, res) { + try { + CdkBase.createLogEvent(req, "DEBUG", `Received request to calculate allocations for ${req.body.jobid}`); + const jobData = await QueryJobData(req, req.BearerToken, req.body.jobid); + return res.status(200).json({ data: calculateAllocations(req, jobData) }); + } catch (error) { + console.log(error); + CdkBase.createLogEvent(req, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`); + res.status(500).json({ error: `Error encountered in CdkCalculateAllocations. ${error}` }); + } +}; + exports.default = async function (socket, jobid) { try { - CdkBase.createLogEvent(socket, "DEBUG", `Received request to calculate allocations for ${jobid}`); - const job = await QueryJobData(socket, jobid); - const { bodyshop } = job; - - const taxAllocations = InstanceManager({ - executeFunction: true, - deubg: true, - args: [], - imex: () => ({ - local: { - center: bodyshop.md_responsibility_centers.taxes.local.name, - sale: Dinero(job.job_totals.totals.local_tax), - cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes.local, - costCenter: bodyshop.md_responsibility_centers.taxes.local - }, - state: { - center: bodyshop.md_responsibility_centers.taxes.state.name, - sale: Dinero(job.job_totals.totals.state_tax), - cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes.state, - costCenter: bodyshop.md_responsibility_centers.taxes.state - }, - federal: { - center: bodyshop.md_responsibility_centers.taxes.federal.name, - sale: Dinero(job.job_totals.totals.federal_tax), - cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes.federal, - costCenter: bodyshop.md_responsibility_centers.taxes.federal - } - }), - rome: () => ({ - tax_ty1: { - center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name, - sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]), - cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`], - costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`] - }, - tax_ty2: { - center: bodyshop.md_responsibility_centers.taxes[`tax_ty2`].name, - sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty2Tax`]), - cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`], - costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`] - }, - tax_ty3: { - center: bodyshop.md_responsibility_centers.taxes[`tax_ty3`].name, - sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty3Tax`]), - cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`], - costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`] - }, - tax_ty4: { - center: bodyshop.md_responsibility_centers.taxes[`tax_ty4`].name, - sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty4Tax`]), - cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`], - costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`] - }, - tax_ty5: { - center: bodyshop.md_responsibility_centers.taxes[`tax_ty5`].name, - sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty5Tax`]), - cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`], - costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`] - } - }) - }); - - //Determine if there are MAPA and MASH lines already on the estimate. - //If there are, don't do anything extra (mitchell estimate) - //Otherwise, calculate them and add them to the default MAPA and MASH centers. - let hasMapaLine = false; - let hasMashLine = false; - - const profitCenterHash = job.joblines.reduce((acc, val) => { - //Check the Parts Assignment - if (val.db_ref === "936008") { - //If either of these DB REFs change, they also need to change in job-totals/job-costing calculations. - hasMapaLine = true; - } - if (val.db_ref === "936007") { - hasMashLine = true; - } - - if (val.profitcenter_part) { - if (!acc[val.profitcenter_part]) acc[val.profitcenter_part] = Dinero(); - - let DineroAmount = Dinero({ - amount: Math.round(val.act_price * 100) - }).multiply(val.part_qty || 1); - - DineroAmount = DineroAmount.add( - ((val.prt_dsmk_m && val.prt_dsmk_m !== 0) || (val.prt_dsmk_p && val.prt_dsmk_p !== 0)) && - DiscountNotAlreadyCounted(val, job.joblines) - ? val.prt_dsmk_m - ? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) }) - : Dinero({ - amount: Math.round(val.act_price * 100) - }) - .multiply(val.part_qty || 0) - .percentage(Math.abs(val.prt_dsmk_p || 0)) - .multiply(val.prt_dsmk_p > 0 ? 1 : -1) - : Dinero() - ); - - acc[val.profitcenter_part] = acc[val.profitcenter_part].add(DineroAmount); - } - if (val.profitcenter_labor && val.mod_lbr_ty) { - //Check the Labor Assignment. - - if (!acc[val.profitcenter_labor]) acc[val.profitcenter_labor] = Dinero(); - - acc[val.profitcenter_labor] = acc[val.profitcenter_labor].add( - Dinero({ - amount: Math.round(job[`rate_${val.mod_lbr_ty.toLowerCase()}`] * 100) - }).multiply(val.mod_lb_hrs) - ); - } - return acc; - }, {}); - - const selectedDmsAllocationConfig = bodyshop.md_responsibility_centers.dms_defaults.find( - (d) => d.name === job.dms_allocation - ); - CdkBase.createLogEvent( - socket, - "DEBUG", - `Using DMS Allocation ${selectedDmsAllocationConfig && selectedDmsAllocationConfig.name} for cost export.` - ); - - let costCenterHash = {}; - //Check whether to skip this if PBS and using AP module. - const disablebillwip = !!bodyshop?.pbs_configuration?.disablebillwip; - - if (!disablebillwip) { - costCenterHash = job.bills.reduce((bill_acc, bill_val) => { - bill_val.billlines.map((line_val) => { - if (!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]]) - bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = Dinero(); - - let lineDinero = Dinero({ - amount: Math.round((line_val.actual_cost || 0) * 100) - }) - .multiply(line_val.quantity) - .multiply(bill_val.is_credit_memo ? -1 : 1); - - bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = - bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]].add(lineDinero); - return null; - }); - return bill_acc; - }, {}); - } - - job.timetickets.forEach((ticket) => { - //Get the total amount of the ticket. - let TicketTotal = Dinero({ - amount: Math.round( - ticket.rate * - (ticket.employee && ticket.employee.flat_rate ? ticket.productivehrs || 0 : ticket.actualhrs || 0) * - 100 - ) - }); - //Add it to the right cost center. - if (!costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]]) - costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] = Dinero(); - - costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] = - costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]].add(TicketTotal); - }); - - if (!hasMapaLine && job.job_totals.rates.mapa.total.amount > 0) { - // console.log("Adding MAPA Line Manually."); - const mapaAccountName = selectedDmsAllocationConfig.profits.MAPA; - - const mapaAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mapaAccountName); - - if (mapaAccount) { - if (!profitCenterHash[mapaAccountName]) profitCenterHash[mapaAccountName] = Dinero(); - - profitCenterHash[mapaAccountName] = profitCenterHash[mapaAccountName].add( - Dinero(job.job_totals.rates.mapa.total) - ); - } else { - //console.log("NO MAPA ACCOUNT FOUND!!"); - } - } - - if (!hasMashLine && job.job_totals.rates.mash.total.amount > 0) { - // console.log("Adding MASH Line Manually."); - - const mashAccountName = selectedDmsAllocationConfig.profits.MASH; - - const mashAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mashAccountName); - - if (mashAccount) { - if (!profitCenterHash[mashAccountName]) profitCenterHash[mashAccountName] = Dinero(); - - profitCenterHash[mashAccountName] = profitCenterHash[mashAccountName].add( - Dinero(job.job_totals.rates.mash.total) - ); - } else { - // console.log("NO MASH ACCOUNT FOUND!!"); - } - } - console.log( - Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting), - typeof Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting) - ); - if (!!bodyshop?.cdk_configuration?.sendmaterialscosting) { - //Manually send the percentage of the costing. - - //Paint Mat - const mapaAccountName = selectedDmsAllocationConfig.costs.MAPA; - const mapaAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mapaAccountName); - if (mapaAccount) { - if (!costCenterHash[mapaAccountName]) - costCenterHash[mapaAccountName] = Dinero(); - if (job.bodyshop.use_paint_scale_data === true) { - if (job.mixdata.length > 0) { - costCenterHash[mapaAccountName] = costCenterHash[ - mapaAccountName - ].add( - Dinero({ - amount: Math.round( - ((job.mixdata[0] && job.mixdata[0].totalliquidcost) || 0) * - 100 - ), - }) - ); - } else { - costCenterHash[mapaAccountName] = costCenterHash[ - mapaAccountName - ].add( - Dinero(job.job_totals.rates.mapa.total).percentage( - bodyshop?.cdk_configuration?.sendmaterialscosting - ) - ); - } - } else { - costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add( - Dinero(job.job_totals.rates.mapa.total).percentage( - bodyshop?.cdk_configuration?.sendmaterialscosting - ) - ); - } - } else { - //console.log("NO MAPA ACCOUNT FOUND!!"); - } - - //Shop Mat - const mashAccountName = selectedDmsAllocationConfig.costs.MASH; - const mashAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mashAccountName); - if (mashAccount) { - if (!costCenterHash[mashAccountName]) costCenterHash[mashAccountName] = Dinero(); - costCenterHash[mashAccountName] = costCenterHash[mashAccountName].add( - Dinero(job.job_totals.rates.mash.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting) - ); - } else { - // console.log("NO MASH ACCOUNT FOUND!!"); - } - } - - const { ca_bc_pvrt } = job; - if (ca_bc_pvrt) { - // const pvrtAccount = bodyshop.md_responsibility_centers.profits.find( - // (c) => c.name === mashAccountName - // ); - - taxAllocations.state.sale = taxAllocations.state.sale.add( - Dinero({ amount: Math.round((ca_bc_pvrt || 0) * 100) }) - ); - } - - if (job.towing_payable && job.towing_payable !== 0) { - const towAccountName = selectedDmsAllocationConfig.profits.TOW; - - const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === towAccountName); - - if (towAccount) { - if (!profitCenterHash[towAccountName]) profitCenterHash[towAccountName] = Dinero(); - - profitCenterHash[towAccountName] = profitCenterHash[towAccountName].add( - Dinero({ - amount: Math.round((job.towing_payable || 0) * 100) - }) - ); - } else { - // console.log("NO MASH ACCOUNT FOUND!!"); - } - } - if (job.storage_payable && job.storage_payable !== 0) { - const storageAccountName = selectedDmsAllocationConfig.profits.TOW; - - const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === storageAccountName); - - if (towAccount) { - if (!profitCenterHash[storageAccountName]) profitCenterHash[storageAccountName] = Dinero(); - - profitCenterHash[storageAccountName] = profitCenterHash[storageAccountName].add( - Dinero({ - amount: Math.round((job.storage_payable || 0) * 100) - }) - ); - } else { - // console.log("NO MASH ACCOUNT FOUND!!"); - } - } - - if (job.adjustment_bottom_line && job.adjustment_bottom_line !== 0) { - const otherAccountName = selectedDmsAllocationConfig.profits.PAO; - - const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === otherAccountName); - - if (otherAccount) { - if (!profitCenterHash[otherAccountName]) profitCenterHash[otherAccountName] = Dinero(); - - profitCenterHash[otherAccountName] = profitCenterHash[otherAccountName].add( - Dinero({ - amount: Math.round((job.adjustment_bottom_line || 0) * 100) - }) - ); - } else { - // console.log("NO MASH ACCOUNT FOUND!!"); - } - } - if (InstanceManager({ rome: true })) { - //profile level adjustments - Object.keys(job.job_totals.parts.adjustments).forEach((key) => { - const accountName = selectedDmsAllocationConfig.profits[key]; - - const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName); - - if (otherAccount) { - if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero(); - - profitCenterHash[accountName] = profitCenterHash[accountName].add( - Dinero(job.job_totals.parts.adjustments[key]) - ); - } else { - CdkBase.createLogEvent( - socket, - "ERROR", - `Error encountered in CdkCalculateAllocations. Unable to find adjustment account. ${error}` - ); - } - }); - } - - const jobAllocations = _.union(Object.keys(profitCenterHash), Object.keys(costCenterHash)).map((key) => { - const profitCenter = bodyshop.md_responsibility_centers.profits.find((c) => c.name === key); - const costCenter = bodyshop.md_responsibility_centers.costs.find((c) => c.name === key); - - return { - center: key, - sale: profitCenterHash[key] ? profitCenterHash[key] : Dinero(), - cost: costCenterHash[key] ? costCenterHash[key] : Dinero(), - profitCenter, - costCenter - }; - }); - - return [ - ...jobAllocations, - ...Object.keys(taxAllocations) - .filter((key) => taxAllocations[key].sale.getAmount() > 0 || taxAllocations[key].cost.getAmount() > 0) - .map((key) => { - if ( - key === "federal" && - selectedDmsAllocationConfig.gst_override && - selectedDmsAllocationConfig.gst_override !== "" - ) { - const ret = { ...taxAllocations[key], tax: key }; - ret.costCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override; - ret.profitCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override; - return ret; - } else { - return { ...taxAllocations[key], tax: key }; - } - }) - ]; + const jobData = await QueryJobData(socket, "Bearer " + socket.handshake.auth.token, jobid); + return calculateAllocations(socket, jobData); } catch (error) { console.log(error); CdkBase.createLogEvent(socket, "ERROR", `Error encountered in CdkCalculateAllocations. ${error}`); } }; -async function QueryJobData(socket, jobid) { - CdkBase.createLogEvent(socket, "DEBUG", `Querying job data for id ${jobid}`); +async function QueryJobData(connectionData, token, jobid) { + CdkBase.createLogEvent(connectionData, "DEBUG", `Querying job data for id ${jobid}`); const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {}); - const result = await client - .setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` }) - .request(queries.GET_CDK_ALLOCATIONS, { id: jobid }); - CdkBase.createLogEvent(socket, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`); + const result = await client.setHeaders({ Authorization: token }).request(queries.GET_CDK_ALLOCATIONS, { id: jobid }); + CdkBase.createLogEvent(connectionData, "TRACE", `Job data query result ${JSON.stringify(result, null, 2)}`); return result.jobs_by_pk; } + +function calculateAllocations(connectionData, job) { + const { bodyshop } = job; + + const taxAllocations = InstanceManager({ + executeFunction: true, + deubg: true, + args: [], + imex: () => ({ + local: { + center: bodyshop.md_responsibility_centers.taxes.local.name, + sale: Dinero(job.job_totals.totals.local_tax), + cost: Dinero(), + profitCenter: bodyshop.md_responsibility_centers.taxes.local, + costCenter: bodyshop.md_responsibility_centers.taxes.local + }, + state: { + center: bodyshop.md_responsibility_centers.taxes.state.name, + sale: Dinero(job.job_totals.totals.state_tax), + cost: Dinero(), + profitCenter: bodyshop.md_responsibility_centers.taxes.state, + costCenter: bodyshop.md_responsibility_centers.taxes.state + }, + federal: { + center: bodyshop.md_responsibility_centers.taxes.federal.name, + sale: Dinero(job.job_totals.totals.federal_tax), + cost: Dinero(), + profitCenter: bodyshop.md_responsibility_centers.taxes.federal, + costCenter: bodyshop.md_responsibility_centers.taxes.federal + } + }), + rome: () => ({ + tax_ty1: { + center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name, + sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]), + cost: Dinero(), + profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`], + costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`] + }, + tax_ty2: { + center: bodyshop.md_responsibility_centers.taxes[`tax_ty2`].name, + sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty2Tax`]), + cost: Dinero(), + profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`], + costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`] + }, + tax_ty3: { + center: bodyshop.md_responsibility_centers.taxes[`tax_ty3`].name, + sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty3Tax`]), + cost: Dinero(), + profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`], + costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty3`] + }, + tax_ty4: { + center: bodyshop.md_responsibility_centers.taxes[`tax_ty4`].name, + sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty4Tax`]), + cost: Dinero(), + profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`], + costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty4`] + }, + tax_ty5: { + center: bodyshop.md_responsibility_centers.taxes[`tax_ty5`].name, + sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty5Tax`]), + cost: Dinero(), + profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`], + costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`] + } + }) + }); + + //Determine if there are MAPA and MASH lines already on the estimate. + //If there are, don't do anything extra (mitchell estimate) + //Otherwise, calculate them and add them to the default MAPA and MASH centers. + let hasMapaLine = false; + let hasMashLine = false; + + const profitCenterHash = job.joblines.reduce((acc, val) => { + //Check the Parts Assignment + if (val.db_ref === "936008") { + //If either of these DB REFs change, they also need to change in job-totals/job-costing calculations. + hasMapaLine = true; + } + if (val.db_ref === "936007") { + hasMashLine = true; + } + + if (val.profitcenter_part) { + if (!acc[val.profitcenter_part]) acc[val.profitcenter_part] = Dinero(); + + let DineroAmount = Dinero({ + amount: Math.round(val.act_price * 100) + }).multiply(val.part_qty || 1); + + DineroAmount = DineroAmount.add( + ((val.prt_dsmk_m && val.prt_dsmk_m !== 0) || (val.prt_dsmk_p && val.prt_dsmk_p !== 0)) && + DiscountNotAlreadyCounted(val, job.joblines) + ? val.prt_dsmk_m + ? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) }) + : Dinero({ + amount: Math.round(val.act_price * 100) + }) + .multiply(val.part_qty || 0) + .percentage(Math.abs(val.prt_dsmk_p || 0)) + .multiply(val.prt_dsmk_p > 0 ? 1 : -1) + : Dinero() + ); + + acc[val.profitcenter_part] = acc[val.profitcenter_part].add(DineroAmount); + } + if (val.profitcenter_labor && val.mod_lbr_ty) { + //Check the Labor Assignment. + + if (!acc[val.profitcenter_labor]) acc[val.profitcenter_labor] = Dinero(); + + acc[val.profitcenter_labor] = acc[val.profitcenter_labor].add( + Dinero({ + amount: Math.round(job[`rate_${val.mod_lbr_ty.toLowerCase()}`] * 100) + }).multiply(val.mod_lb_hrs) + ); + } + return acc; + }, {}); + + const selectedDmsAllocationConfig = bodyshop.md_responsibility_centers.dms_defaults.find( + (d) => d.name === job.dms_allocation + ); + CdkBase.createLogEvent( + connectionData, + "DEBUG", + `Using DMS Allocation ${selectedDmsAllocationConfig && selectedDmsAllocationConfig.name} for cost export.` + ); + + let costCenterHash = {}; + //Check whether to skip this if PBS and using AP module. + const disablebillwip = !!bodyshop?.pbs_configuration?.disablebillwip; + + if (!disablebillwip) { + costCenterHash = job.bills.reduce((bill_acc, bill_val) => { + bill_val.billlines.map((line_val) => { + if (!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]]) + bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = Dinero(); + + let lineDinero = Dinero({ + amount: Math.round((line_val.actual_cost || 0) * 100) + }) + .multiply(line_val.quantity) + .multiply(bill_val.is_credit_memo ? -1 : 1); + + bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = + bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]].add(lineDinero); + return null; + }); + return bill_acc; + }, {}); + } + + job.timetickets.forEach((ticket) => { + //Get the total amount of the ticket. + let TicketTotal = Dinero({ + amount: Math.round( + ticket.rate * + (ticket.employee && ticket.employee.flat_rate ? ticket.productivehrs || 0 : ticket.actualhrs || 0) * + 100 + ) + }); + //Add it to the right cost center. + if (!costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]]) + costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] = Dinero(); + + costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]] = + costCenterHash[selectedDmsAllocationConfig.costs[ticket.ciecacode]].add(TicketTotal); + }); + + if (!hasMapaLine && job.job_totals.rates.mapa.total.amount > 0) { + // console.log("Adding MAPA Line Manually."); + const mapaAccountName = selectedDmsAllocationConfig.profits.MAPA; + + const mapaAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mapaAccountName); + + if (mapaAccount) { + if (!profitCenterHash[mapaAccountName]) profitCenterHash[mapaAccountName] = Dinero(); + + profitCenterHash[mapaAccountName] = profitCenterHash[mapaAccountName].add( + Dinero(job.job_totals.rates.mapa.total) + ); + } else { + //console.log("NO MAPA ACCOUNT FOUND!!"); + } + } + + if (!hasMashLine && job.job_totals.rates.mash.total.amount > 0) { + // console.log("Adding MASH Line Manually."); + + const mashAccountName = selectedDmsAllocationConfig.profits.MASH; + + const mashAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === mashAccountName); + + if (mashAccount) { + if (!profitCenterHash[mashAccountName]) profitCenterHash[mashAccountName] = Dinero(); + + profitCenterHash[mashAccountName] = profitCenterHash[mashAccountName].add( + Dinero(job.job_totals.rates.mash.total) + ); + } else { + // console.log("NO MASH ACCOUNT FOUND!!"); + } + } + // console.log( + // Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting), + // typeof Number.isInteger(bodyshop?.cdk_configuration?.sendmaterialscosting) + // ); + if (!!bodyshop?.cdk_configuration?.sendmaterialscosting) { + //Manually send the percentage of the costing. + + //Paint Mat + const mapaAccountName = selectedDmsAllocationConfig.costs.MAPA; + const mapaAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mapaAccountName); + if (mapaAccount) { + if (!costCenterHash[mapaAccountName]) costCenterHash[mapaAccountName] = Dinero(); + if (job.bodyshop.use_paint_scale_data === true) { + if (job.mixdata.length > 0) { + costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add( + Dinero({ + amount: Math.round(((job.mixdata[0] && job.mixdata[0].totalliquidcost) || 0) * 100) + }) + ); + } else { + costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add( + Dinero(job.job_totals.rates.mapa.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting) + ); + } + } else { + costCenterHash[mapaAccountName] = costCenterHash[mapaAccountName].add( + Dinero(job.job_totals.rates.mapa.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting) + ); + } + } else { + //console.log("NO MAPA ACCOUNT FOUND!!"); + } + + //Shop Mat + const mashAccountName = selectedDmsAllocationConfig.costs.MASH; + const mashAccount = bodyshop.md_responsibility_centers.costs.find((c) => c.name === mashAccountName); + if (mashAccount) { + if (!costCenterHash[mashAccountName]) costCenterHash[mashAccountName] = Dinero(); + costCenterHash[mashAccountName] = costCenterHash[mashAccountName].add( + Dinero(job.job_totals.rates.mash.total).percentage(bodyshop?.cdk_configuration?.sendmaterialscosting) + ); + } else { + // console.log("NO MASH ACCOUNT FOUND!!"); + } + } + + const { ca_bc_pvrt } = job; + if (ca_bc_pvrt) { + // const pvrtAccount = bodyshop.md_responsibility_centers.profits.find( + // (c) => c.name === mashAccountName + // ); + + taxAllocations.state.sale = taxAllocations.state.sale.add(Dinero({ amount: Math.round((ca_bc_pvrt || 0) * 100) })); + } + + if (job.towing_payable && job.towing_payable !== 0) { + const towAccountName = selectedDmsAllocationConfig.profits.TOW; + + const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === towAccountName); + + if (towAccount) { + if (!profitCenterHash[towAccountName]) profitCenterHash[towAccountName] = Dinero(); + + profitCenterHash[towAccountName] = profitCenterHash[towAccountName].add( + Dinero({ + amount: Math.round((job.towing_payable || 0) * 100) + }) + ); + } else { + // console.log("NO MASH ACCOUNT FOUND!!"); + } + } + if (job.storage_payable && job.storage_payable !== 0) { + const storageAccountName = selectedDmsAllocationConfig.profits.TOW; + + const towAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === storageAccountName); + + if (towAccount) { + if (!profitCenterHash[storageAccountName]) profitCenterHash[storageAccountName] = Dinero(); + + profitCenterHash[storageAccountName] = profitCenterHash[storageAccountName].add( + Dinero({ + amount: Math.round((job.storage_payable || 0) * 100) + }) + ); + } else { + // console.log("NO MASH ACCOUNT FOUND!!"); + } + } + + if (job.adjustment_bottom_line && job.adjustment_bottom_line !== 0) { + const otherAccountName = selectedDmsAllocationConfig.profits.PAO; + + const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === otherAccountName); + + if (otherAccount) { + if (!profitCenterHash[otherAccountName]) profitCenterHash[otherAccountName] = Dinero(); + + profitCenterHash[otherAccountName] = profitCenterHash[otherAccountName].add( + Dinero({ + amount: Math.round((job.adjustment_bottom_line || 0) * 100) + }) + ); + } else { + // console.log("NO MASH ACCOUNT FOUND!!"); + } + } + if (InstanceManager({ rome: true })) { + //profile level adjustments + Object.keys(job.job_totals.parts.adjustments).forEach((key) => { + const accountName = selectedDmsAllocationConfig.profits[key]; + + const otherAccount = bodyshop.md_responsibility_centers.profits.find((c) => c.name === accountName); + + if (otherAccount) { + if (!profitCenterHash[accountName]) profitCenterHash[accountName] = Dinero(); + + profitCenterHash[accountName] = profitCenterHash[accountName].add( + Dinero(job.job_totals.parts.adjustments[key]) + ); + } else { + CdkBase.createLogEvent( + connectionData, + "ERROR", + `Error encountered in CdkCalculateAllocations. Unable to find adjustment account. ${error}` + ); + } + }); + } + + const jobAllocations = _.union(Object.keys(profitCenterHash), Object.keys(costCenterHash)).map((key) => { + const profitCenter = bodyshop.md_responsibility_centers.profits.find((c) => c.name === key); + const costCenter = bodyshop.md_responsibility_centers.costs.find((c) => c.name === key); + + return { + center: key, + sale: profitCenterHash[key] ? profitCenterHash[key] : Dinero(), + cost: costCenterHash[key] ? costCenterHash[key] : Dinero(), + profitCenter, + costCenter + }; + }); + + return [ + ...jobAllocations, + ...Object.keys(taxAllocations) + .filter((key) => taxAllocations[key].sale.getAmount() > 0 || taxAllocations[key].cost.getAmount() > 0) + .map((key) => { + if ( + key === "federal" && + selectedDmsAllocationConfig.gst_override && + selectedDmsAllocationConfig.gst_override !== "" + ) { + const ret = { ...taxAllocations[key], tax: key }; + ret.costCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override; + ret.profitCenter.dms_acctnumber = selectedDmsAllocationConfig.gst_override; + return ret; + } else { + return { ...taxAllocations[key], tax: key }; + } + }) + ]; +} diff --git a/server/routes/cdkRoutes.js b/server/routes/cdkRoutes.js index 5fd0536cb..614e59d2b 100644 --- a/server/routes/cdkRoutes.js +++ b/server/routes/cdkRoutes.js @@ -1,11 +1,13 @@ const express = require("express"); const router = express.Router(); const cdkGetMake = require("../cdk/cdk-get-makes"); +const cdkCalculateAllocations = require("../cdk/cdk-calculate-allocations"); const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware"); const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware"); router.use(validateFirebaseIdTokenMiddleware); router.post("/getvehicles", withUserGraphQLClientMiddleware, cdkGetMake.default); +router.post("/calculate-allocations", withUserGraphQLClientMiddleware, cdkCalculateAllocations.defaultRoute); module.exports = router;