diff --git a/os-loader.js b/os-loader.js index 54a799ce2..865a617ae 100644 --- a/os-loader.js +++ b/os-loader.js @@ -174,10 +174,7 @@ async function OpenSearchUpdateHandler(req, res) { const bulkOperation = []; slicedArray.forEach((bill) => { bulkOperation.push({ index: { _index: "bills", _id: bill.id } }); - bulkOperation.push({ - ...omit(bill, ["job"]), - bodyshopid: bill.job.bodyshopid - }); + bulkOperation.push({ ...bill, bodyshopid: bill.job.bodyshopid }); }); promiseQueue.push(bulkOperation); } diff --git a/server/accounting/qb-receivables-lines.js b/server/accounting/qb-receivables-lines.js index a19fe64d7..4be412ac9 100644 --- a/server/accounting/qb-receivables-lines.js +++ b/server/accounting/qb-receivables-lines.js @@ -71,16 +71,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes { local: false, federal: InstanceManager({ imex: true, rome: false }), - state: - jobs_by_pk.state_tax_rate === 0 - ? false - : jobline.db_ref === "900511" || - jobline.db_ref === "900510" || - (jobline.mod_lb_hrs === 0 && //Extending IO-1375 as a part of IO-2023 - jobline.act_price > 0 && - jobline.lbr_op === "OP14") - ? true - : jobline.tax_part + state: checkStateTax(jobline, jobs_by_pk) }, bodyshop.md_responsibility_centers.sales_tax_codes ); @@ -156,7 +147,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes { local: false, federal: InstanceManager({ imex: true, rome: false }), - state: jobs_by_pk.state_tax_rate === 0 ? false : true + state: jobs_by_pk.tax_lbr_rt === 0 ? false : true }, bodyshop.md_responsibility_centers.sales_tax_codes ); @@ -224,7 +215,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes { local: false, federal: InstanceManager({ imex: true, rome: false }), - state: jobs_by_pk.state_tax_rate === 0 ? false : true + state: jobs_by_pk.tax_paint_mat_rt === 0 ? false : true }, bodyshop.md_responsibility_centers.sales_tax_codes ); @@ -293,7 +284,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes { local: false, federal: InstanceManager({ imex: true, rome: false }), - state: jobs_by_pk.state_tax_rate === 0 ? false : true + state: jobs_by_pk.tax_shop_mat_rt === 0 ? false : true }, bodyshop.md_responsibility_centers.sales_tax_codes ); @@ -379,7 +370,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes { local: false, federal: InstanceManager({ imex: true, rome: false }), - state: jobs_by_pk.state_tax_rate === 0 ? false : true + state: jobs_by_pk.tax_tow_rt === 0 ? false : true }, bodyshop.md_responsibility_centers.sales_tax_codes ); @@ -439,7 +430,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes { local: false, federal: InstanceManager({ imex: true, rome: false }), - state: jobs_by_pk.state_tax_rate === 0 ? false : true + state: jobs_by_pk.tax_str_rt === 0 ? false : true }, bodyshop.md_responsibility_centers.sales_tax_codes ); @@ -499,7 +490,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes { local: false, federal: InstanceManager({ imex: true, rome: false }), - state: jobs_by_pk.state_tax_rate === 0 ? false : true + state: jobs_by_pk.tax_lbr_rt === 0 ? false : true }, bodyshop.md_responsibility_centers.sales_tax_codes ); @@ -879,6 +870,66 @@ exports.createMultiQbPayerLines = function ({ bodyshop, jobs_by_pk, qbo = false, return InvoiceLineAdd; }; +function checkStateTax(jobline, jobs_by_pk) { + const isPaintOrShopMat = jobline.db_ref === "936008" || jobline.db_ref === "936007"; + + if (isPaintOrShopMat) { + if (jobline.db_ref === "936008") { + if (jobs_by_pk.tax_paint_mat_rt === 0) { + return false; + } else { + return true; + } + } + if (jobline.db_ref === "936007") { + if (jobs_by_pk.tax_shop_mat_rt === 0) { + return false; + } else { + return true; + } + } + } + + const isAdditionalCost = + (jobline.lbr_op === "OP13" || (jobline.db_ref && jobline.db_ref.startsWith("9360"))) && !isPaintOrShopMat; + + if (!jobline.part_type && isAdditionalCost) { + if (jobs_by_pk.tax_lbr_rt === 0) { + return false; + } else { + return true; + } + } + + if ( + jobline.db_ref === "900511" || + jobline.db_ref === "900510" || + (jobline.mod_lb_hrs === 0 && jobline.act_price > 0 && jobline.lbr_op === "OP14") + ) + return true; //Extending IO-1375 as a part of IO-2023 + + if (jobline.tax_part === false) { + return false; + } else { + if (jobline.part_type) { + if ( + jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_in === false || + jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_rt === 0 + ) { + return false; + } else { + return true; + } + } else { + if (jobs_by_pk.tax_lbr_rt === 0) { + return false; + } else { + return true; + } + } + } +} + function CheckQBOUSATaxID({ jobline, job, type }) { //Replacing this to be all non-taxable items with the refactor of parts tax rates. return "NON"; diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index d26db1405..cd707bc0f 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -206,8 +206,13 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) { adjustment_bottom_line state_tax_rate qb_multiple_payers + parts_tax_rates tax_paint_mat_rt tax_lbr_rt + tax_shop_mat_rt + tax_sub_rt + tax_tow_rt + tax_str_rt owner { accountingid } @@ -1534,6 +1539,7 @@ exports.QUERY_JOB_COSTING_DETAILS = ` query QUERY_JOB_COSTING_DETAILS($id: uuid! op_code_desc profitcenter_part profitcenter_labor + act_price_before_ppc } bills { id diff --git a/server/job/job-costing.js b/server/job/job-costing.js index d82d0ac42..8b966140e 100644 --- a/server/job/job-costing.js +++ b/server/job/job-costing.js @@ -269,7 +269,7 @@ function GenerateCostingData(job) { job && job.joblines.reduce( (acc, val) => { - //Parts Lines + //Shop or Paint Material Flags 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; @@ -277,6 +277,8 @@ function GenerateCostingData(job) { if (val.db_ref === "936007") { hasMashLine = true; } + + //Labor Profit Center if (val.mod_lbr_ty) { const laborProfitCenter = val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "Unknown"; @@ -307,6 +309,7 @@ function GenerateCostingData(job) { } } + // Part Profit Center if (val.part_type && val.part_type !== "PAE" && val.part_type !== "PAS" && val.part_type !== "PASL") { const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown"; @@ -315,7 +318,7 @@ function GenerateCostingData(job) { if (!partsProfitCenter) console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type); const partsAmount = Dinero({ - amount: Math.round((val.act_price || 0) * 100) + amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) : Math.round(val.act_price * 100) }) .multiply(val.part_qty || 1) .add( @@ -324,7 +327,7 @@ function GenerateCostingData(job) { ? val.prt_dsmk_m ? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) }) : Dinero({ - amount: Math.round(val.act_price * 100) + amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) : Math.round(val.act_price * 100) }) .multiply(val.part_qty || 0) .percentage(Math.abs(val.prt_dsmk_p || 0)) @@ -334,6 +337,8 @@ function GenerateCostingData(job) { if (!acc.parts[partsProfitCenter]) acc.parts[partsProfitCenter] = Dinero(); acc.parts[partsProfitCenter] = acc.parts[partsProfitCenter].add(partsAmount); } + + //Sublet Profit Center if (val.part_type && val.part_type !== "PAE" && (val.part_type === "PAS" || val.part_type === "PASL")) { const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown"; @@ -362,8 +367,8 @@ function GenerateCostingData(job) { acc.sublet[partsProfitCenter] = acc.sublet[partsProfitCenter].add(partsAmount); } - //To deal with additional costs. - if (!val.part_type && !val.mod_lbr_ty) { + //Additional Profit Center + if ((!val.part_type && !val.mod_lbr_ty) || (!val.part_type && val.mod_lbr_ty)) { //Does it already have a defined profit center? //If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate. const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown";