diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index 3ed050f80..e9ba2d511 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -1030,6 +1030,7 @@ exports.QUERY_JOB_COSTING_DETAILS = ` query QUERY_JOB_COSTING_DETAILS($id: uuid! status ca_bc_pvrt ca_customer_gst + dms_allocation joblines(where: { removed: { _eq: false } }) { id db_ref @@ -1073,11 +1074,14 @@ exports.QUERY_JOB_COSTING_DETAILS = ` query QUERY_JOB_COSTING_DETAILS($id: uuid! actualhrs productivehrs flat_rate + ciecacode } bodyshop{ id md_responsibility_centers jc_hourly_rates + cdk_dealerid + pbs_serialnumber } } }`; @@ -1133,6 +1137,7 @@ exports.QUERY_JOB_COSTING_DETAILS_MULTI = ` query QUERY_JOB_COSTING_DETAILS_MULT status ca_bc_pvrt ca_customer_gst + dms_allocation joblines(where: {removed: {_eq: false}}) { id db_ref @@ -1176,11 +1181,14 @@ exports.QUERY_JOB_COSTING_DETAILS_MULTI = ` query QUERY_JOB_COSTING_DETAILS_MULT actualhrs productivehrs flat_rate + ciecacode } bodyshop { id md_responsibility_centers jc_hourly_rates + cdk_dealerid + pbs_serialnumber } } } diff --git a/server/job/job-costing.js b/server/job/job-costing.js index 7756810f6..4a7ebadb4 100644 --- a/server/job/job-costing.js +++ b/server/job/job-costing.js @@ -261,7 +261,7 @@ function GenerateCostingData(job) { val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "?"; if (laborProfitCenter === "?") - console.log("Unknown type", val.mod_lbr_ty); + console.log("Unknown type", val.line_desc, val.mod_lbr_ty); const rateName = `rate_${(val.mod_lbr_ty || "").toLowerCase()}`; const laborAmount = Dinero({ @@ -285,11 +285,12 @@ function GenerateCostingData(job) { val.profitcenter_part || defaultProfits[val.part_type] || "?"; if (partsProfitCenter === "?") - console.log("Unknown type", val.part_type); + console.log("Unknown type", val.line_desc, val.part_type); if (!partsProfitCenter) console.log( "Unknown cost/profit center mapping for parts.", + val.line_desc, val.part_type ); const partsAmount = Dinero({ @@ -298,13 +299,13 @@ function GenerateCostingData(job) { .multiply(val.part_qty || 1) .add( val.prt_dsmk_m && val.prt_dsmk_m !== 0 - ? 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({ 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) ); if (!acc.parts[partsProfitCenter]) acc.parts[partsProfitCenter] = Dinero(); @@ -322,7 +323,7 @@ function GenerateCostingData(job) { "?"; if (partsProfitCenter === "?") { - console.log("Unknown type", val.part_type); + console.log("Unknown type", val.line_desc, val.part_type); } else { const partsAmount = Dinero({ amount: Math.round((val.act_price || 0) * 100), @@ -330,13 +331,13 @@ function GenerateCostingData(job) { .multiply(val.part_qty || 1) .add( val.prt_dsmk_m && val.prt_dsmk_m !== 0 - ? 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({ 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) ); if (!acc.parts[partsProfitCenter]) @@ -372,21 +373,41 @@ function GenerateCostingData(job) { ); } + //Is it a DMS Setup? + const selectedDmsAllocationConfig = + job.bodyshop.md_responsibility_centers.dms_defaults.find( + (d) => d.name === job.dms_allocation + ) || job.bodyshop.md_responsibility_centers.defaults; + const billTotalsByCostCenters = job.bills.reduce((bill_acc, bill_val) => { //At the bill level. bill_val.billlines.map((line_val) => { //At the bill line level. - //console.log("JobCostingPartsTable -> line_val", line_val); - if (!bill_acc[line_val.cost_center]) - bill_acc[line_val.cost_center] = Dinero(); + if (job.bodyshop.pbs_serialnumber || job.bodyshop.cdk_dealerid) { + if (!bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]]) + bill_acc[selectedDmsAllocationConfig.costs[line_val.cost_center]] = + Dinero(); - bill_acc[line_val.cost_center] = bill_acc[line_val.cost_center].add( - 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( + Dinero({ + amount: Math.round((line_val.actual_cost || 0) * 100), + }) + .multiply(line_val.quantity) + .multiply(bill_val.is_credit_memo ? -1 : 1) + ); + } else { + if (!bill_acc[line_val.cost_center]) + bill_acc[line_val.cost_center] = Dinero(); + + bill_acc[line_val.cost_center] = bill_acc[line_val.cost_center].add( + Dinero({ + amount: Math.round((line_val.actual_cost || 0) * 100), + }) + .multiply(line_val.quantity) + .multiply(bill_val.is_credit_memo ? -1 : 1) + ); + } return null; }); @@ -443,20 +464,38 @@ function GenerateCostingData(job) { const ticketTotalsByCostCenter = job.timetickets.reduce( (ticket_acc, ticket_val) => { //At the invoice level. - if (!ticket_acc[ticket_val.cost_center]) - ticket_acc[ticket_val.cost_center] = Dinero(); - ticket_acc[ticket_val.cost_center] = ticket_acc[ - ticket_val.cost_center - ].add( - Dinero({ - amount: Math.round((ticket_val.rate || 0) * 100), - }).multiply( - ticket_val.flat_rate - ? ticket_val.productivehrs || ticket_val.actualhrs || 0 - : ticket_val.actualhrs || ticket_val.productivehrs || 0 - ) //Should base this on the employee. - ); + if (job.bodyshop.pbs_serialnumber || job.bodyshop.cdk_dealerid) { + if (!ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]]) + ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]] = + Dinero(); + + ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]] = + ticket_acc[selectedDmsAllocationConfig.costs[ticket_val.ciecacode]].add( + Dinero({ + amount: Math.round((ticket_val.rate || 0) * 100), + }).multiply( + ticket_val.flat_rate + ? ticket_val.productivehrs || ticket_val.actualhrs || 0 + : ticket_val.actualhrs || ticket_val.productivehrs || 0 + ) //Should base this on the employee. + ); + } else { + if (!ticket_acc[ticket_val.cost_center]) + ticket_acc[ticket_val.cost_center] = Dinero(); + + ticket_acc[ticket_val.cost_center] = ticket_acc[ + ticket_val.cost_center + ].add( + Dinero({ + amount: Math.round((ticket_val.rate || 0) * 100), + }).multiply( + ticket_val.flat_rate + ? ticket_val.productivehrs || ticket_val.actualhrs || 0 + : ticket_val.actualhrs || ticket_val.productivehrs || 0 + ) //Should base this on the employee. + ); + } return ticket_acc; },