From d2fe9b0590e78a44d78e317b5efe91b3377de959 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Tue, 26 Sep 2023 12:35:49 -0700 Subject: [PATCH] Updates to QuickBooks and DMS export. --- .../jobs-available-table.container.jsx | 182 ++++++++--------- job-totals-testing-util.js | 4 +- server/accounting/qb-receivables-lines.js | 183 ++++++------------ server/cdk/cdk-calculate-allocations.js | 65 +++++-- server/job/job-totals.js | 130 ++++++++----- 5 files changed, 280 insertions(+), 284 deletions(-) diff --git a/client/src/components/jobs-available-table/jobs-available-table.container.jsx b/client/src/components/jobs-available-table/jobs-available-table.container.jsx index 1478b9082..7765c1b91 100644 --- a/client/src/components/jobs-available-table/jobs-available-table.container.jsx +++ b/client/src/components/jobs-available-table/jobs-available-table.container.jsx @@ -422,98 +422,98 @@ function replaceEmpty(someObj, replaceValue = null) { } async function CheckTaxRates(estData, bodyshop) { - //LKQ Check - if ( - !estData.parts_tax_rates?.PAL || - estData.parts_tax_rates?.PAL?.prt_tax_rt === null || - estData.parts_tax_rates?.PAL?.prt_tax_rt === 0 - ) { - const res = await confirmDialog( - `Rome Online has detected that there is a missing tax rate for LKQ parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.` - ); - if (res) { - if (!estData.parts_tax_rates.PAL) { - estData.parts_tax_rates.PAL = { - prt_discp: 0, - prt_mktyp: true, - prt_mkupp: 0, - prt_type: "PAL", - }; - } - estData.parts_tax_rates.PAL.prt_tax_rt = - bodyshop.bill_tax_rates.state_tax_rate / 100; - estData.parts_tax_rates.PAL.prt_tax_in = true; - } - } - //PAC Check - if ( - !estData.parts_tax_rates?.PAC || - estData.parts_tax_rates?.PAC?.prt_tax_rt === null || - estData.parts_tax_rates?.PAC?.prt_tax_rt === 0 - ) { - const res = await confirmDialog( - `Rome Online has detected that there is a missing tax rate for rechromed parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.` - ); - if (res) { - if (!estData.parts_tax_rates.PAC) { - estData.parts_tax_rates.PAC = { - prt_discp: 0, - prt_mktyp: true, - prt_mkupp: 0, - prt_type: "PAC", - }; - } - estData.parts_tax_rates.PAC.prt_tax_rt = - bodyshop.bill_tax_rates.state_tax_rate / 100; - estData.parts_tax_rates.PAC.prt_tax_in = true; - } - } - //PAM Check - if ( - !estData.parts_tax_rates?.PAM || - estData.parts_tax_rates?.PAM?.prt_tax_rt === null || - estData.parts_tax_rates?.PAM?.prt_tax_rt === 0 - ) { - const res = await confirmDialog( - `Rome Online has detected that there is a missing tax rate for remanufactured parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.` - ); - if (res) { - if (!estData.parts_tax_rates.PAM) { - estData.parts_tax_rates.PAM = { - prt_discp: 0, - prt_mktyp: true, - prt_mkupp: 0, - prt_type: "PAM", - }; - } - estData.parts_tax_rates.PAM.prt_tax_rt = - bodyshop.bill_tax_rates.state_tax_rate / 100; - estData.parts_tax_rates.PAM.prt_tax_in = true; - } - } + // //LKQ Check + // if ( + // !estData.parts_tax_rates?.PAL || + // estData.parts_tax_rates?.PAL?.prt_tax_rt === null || + // estData.parts_tax_rates?.PAL?.prt_tax_rt === 0 + // ) { + // const res = await confirmDialog( + // `Rome Online has detected that there is a missing tax rate for LKQ parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.` + // ); + // if (res) { + // if (!estData.parts_tax_rates.PAL) { + // estData.parts_tax_rates.PAL = { + // prt_discp: 0, + // prt_mktyp: true, + // prt_mkupp: 0, + // prt_type: "PAL", + // }; + // } + // estData.parts_tax_rates.PAL.prt_tax_rt = + // bodyshop.bill_tax_rates.state_tax_rate / 100; + // estData.parts_tax_rates.PAL.prt_tax_in = true; + // } + // } + // //PAC Check + // if ( + // !estData.parts_tax_rates?.PAC || + // estData.parts_tax_rates?.PAC?.prt_tax_rt === null || + // estData.parts_tax_rates?.PAC?.prt_tax_rt === 0 + // ) { + // const res = await confirmDialog( + // `Rome Online has detected that there is a missing tax rate for rechromed parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.` + // ); + // if (res) { + // if (!estData.parts_tax_rates.PAC) { + // estData.parts_tax_rates.PAC = { + // prt_discp: 0, + // prt_mktyp: true, + // prt_mkupp: 0, + // prt_type: "PAC", + // }; + // } + // estData.parts_tax_rates.PAC.prt_tax_rt = + // bodyshop.bill_tax_rates.state_tax_rate / 100; + // estData.parts_tax_rates.PAC.prt_tax_in = true; + // } + // } + // //PAM Check + // if ( + // !estData.parts_tax_rates?.PAM || + // estData.parts_tax_rates?.PAM?.prt_tax_rt === null || + // estData.parts_tax_rates?.PAM?.prt_tax_rt === 0 + // ) { + // const res = await confirmDialog( + // `Rome Online has detected that there is a missing tax rate for remanufactured parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.` + // ); + // if (res) { + // if (!estData.parts_tax_rates.PAM) { + // estData.parts_tax_rates.PAM = { + // prt_discp: 0, + // prt_mktyp: true, + // prt_mkupp: 0, + // prt_type: "PAM", + // }; + // } + // estData.parts_tax_rates.PAM.prt_tax_rt = + // bodyshop.bill_tax_rates.state_tax_rate / 100; + // estData.parts_tax_rates.PAM.prt_tax_in = true; + // } + // } - if ( - !estData.parts_tax_rates?.PAR || - estData.parts_tax_rates?.PAR?.prt_tax_rt === null || - estData.parts_tax_rates?.PAR?.prt_tax_rt === 0 - ) { - const res = await confirmDialog( - `Rome Online has detected that there is a missing tax rate for recored parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.` - ); - if (res) { - if (!estData.parts_tax_rates.PAR) { - estData.parts_tax_rates.PAR = { - prt_discp: 0, - prt_mktyp: true, - prt_mkupp: 0, - prt_type: "PAR", - }; - } - estData.parts_tax_rates.PAR.prt_tax_rt = - bodyshop.bill_tax_rates.state_tax_rate / 100; - estData.parts_tax_rates.PAR.prt_tax_in = true; - } - } + // if ( + // !estData.parts_tax_rates?.PAR || + // estData.parts_tax_rates?.PAR?.prt_tax_rt === null || + // estData.parts_tax_rates?.PAR?.prt_tax_rt === 0 + // ) { + // const res = await confirmDialog( + // `Rome Online has detected that there is a missing tax rate for recored parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.` + // ); + // if (res) { + // if (!estData.parts_tax_rates.PAR) { + // estData.parts_tax_rates.PAR = { + // prt_discp: 0, + // prt_mktyp: true, + // prt_mkupp: 0, + // prt_type: "PAR", + // }; + // } + // estData.parts_tax_rates.PAR.prt_tax_rt = + // bodyshop.bill_tax_rates.state_tax_rate / 100; + // estData.parts_tax_rates.PAR.prt_tax_in = true; + // } + // } //IO-1387 If a sublet line is NOT R&R, use the labor tax. If it is, use the sublet tax rate. //Currently limited to SK shops only. diff --git a/job-totals-testing-util.js b/job-totals-testing-util.js index b69ec111b..352c6ab70 100644 --- a/job-totals-testing-util.js +++ b/job-totals-testing-util.js @@ -20,7 +20,7 @@ require("dotenv").config({ async function RunTheTest() { const bodyshopids = ["a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"]; - const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjE5MGFkMTE4YTk0MGFkYzlmMmY1Mzc2YjM1MjkyZmVkZThjMmQwZWUiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUm9tZSBEZXZlbG9wbWVudCIsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciJdLCJ4LWhhc3VyYS11c2VyLWlkIjoidDZZbTFORGxDRE9QWnIzRjliZ3VXSDRMaFNYMiJ9LCJpb2FkbWluIjp0cnVlLCJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vcm9tZS1wcm9kLTEiLCJhdWQiOiJyb21lLXByb2QtMSIsImF1dGhfdGltZSI6MTY5NDQ2NjM3OCwidXNlcl9pZCI6InQ2WW0xTkRsQ0RPUFpyM0Y5Ymd1V0g0TGhTWDIiLCJzdWIiOiJ0NlltMU5EbENET1BacjNGOWJndVdINExoU1gyIiwiaWF0IjoxNjk0NTQ4MTIwLCJleHAiOjE2OTQ1NTE3MjAsImVtYWlsIjoicGF0cmlja0Byb21lLmRldiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJwYXRyaWNrQHJvbWUuZGV2Il19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.hIR3tAIOZFydmuCC5OS1KmIAG3Rq3mB1ZJAcnWUrJRuioNw1DeezAiUvXlb2iQ3Pow3zpyTkZgNMrLhWNpZmywyjPQQaTU7krw2gNhmRfrILmIWjODepvRcp4mcwvdf65WkqXm88S82b-8nkgvPhogvXmYWHrrDFl9EP4nMXdhjJ8rZ-euBcH9wz9o4BehsW4x91JJxeTU_jk4Fa0h6ppG6XdTmPyTlQb79g-WgLbqtyXEIjQr9q_ZbE4br_PLLhFd7SnUV0e-raw3FcK9m4Mc-n37M4KtKEpDbhXM_2MtGSCWbKZ7m3lfydFaV8LlgnCTiX_gSCvoAmCeRyH5w1yQ`; + const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImFhMDhlN2M3ODNkYjhjOGFjNGNhNzJhZjdmOWRkN2JiMzk4ZjE2ZGMiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUm9tZSBEZXZlbG9wbWVudCIsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciJdLCJ4LWhhc3VyYS11c2VyLWlkIjoidDZZbTFORGxDRE9QWnIzRjliZ3VXSDRMaFNYMiJ9LCJpb2FkbWluIjp0cnVlLCJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vcm9tZS1wcm9kLTEiLCJhdWQiOiJyb21lLXByb2QtMSIsImF1dGhfdGltZSI6MTY5NTE1MDU0NywidXNlcl9pZCI6InQ2WW0xTkRsQ0RPUFpyM0Y5Ymd1V0g0TGhTWDIiLCJzdWIiOiJ0NlltMU5EbENET1BacjNGOWJndVdINExoU1gyIiwiaWF0IjoxNjk1Mzk5MTM0LCJleHAiOjE2OTU0MDI3MzQsImVtYWlsIjoicGF0cmlja0Byb21lLmRldiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJwYXRyaWNrQHJvbWUuZGV2Il19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.X8PeG0Y0TW08Tx1sBqpWw9N1YYxJWd4lOEAH2KA7Xel6ehg50WdHf42W4RXdGBc-TPzbJgzLJg4jc8_cmSiDiDojSnVzrmfBrbugLRd1Hk31784SvYKb_i1GU1p3s5W-rBHbi1htnNyXqV0nhOgbnOJphJL2l91WG_YaBRA_QiGgy4rAdBhi12LLS5KWGlrP9T99hOfL7o8kG1rhO5y1bGadlpmXAjUpMQAlMX8QVXAe6DB-61vDJPyTpTbfT3yUZfNppNSqqu1wK2c08QwniXf5qhIyGBNeB6qunlDQhFBP-grGcUvVb9ijHHtX7WiFb7wd-AY3oNCx1i5hi5UdPQ`; const { jobs } = await client.request( gql` query GET_JOBS($bodyshopids: [uuid!]!) { @@ -87,7 +87,7 @@ async function RunTheTest() { } else { result.result = "PASS"; } - console.log(`${result.result} => RO ${job.ro_number} - ${job.id} `); + // console.log(`${result.result} => RO ${job.ro_number} - ${job.id} `); results.push(result); } catch (error) { diff --git a/server/accounting/qb-receivables-lines.js b/server/accounting/qb-receivables-lines.js index c27de4e84..63b942e5d 100644 --- a/server/accounting/qb-receivables-lines.js +++ b/server/accounting/qb-receivables-lines.js @@ -574,123 +574,54 @@ exports.default = function ({ const job_totals = jobs_by_pk.job_totals; const federal_tax = Dinero(job_totals.totals.federal_tax); - const state_tax = Dinero(job_totals.totals.state_tax); - const local_tax = Dinero(job_totals.totals.local_tax); - - if (federal_tax.getAmount() > 0) { - if (qbo) { - // do qbo - } else { - InvoiceLineAdd.push({ - ItemRef: { - FullName: - bodyshop.md_responsibility_centers.taxes.federal.accountitem, - }, - Desc: bodyshop.md_responsibility_centers.taxes.federal.accountdesc, - Amount: federal_tax.toFormat(DineroQbFormat), - }); - } - } - - if (state_tax.getAmount() > 0) { - if (qbo) { - // do qbo - } else { - InvoiceLineAdd.push({ - ItemRef: { - FullName: bodyshop.md_responsibility_centers.taxes.state.accountitem, - }, - Desc: bodyshop.md_responsibility_centers.taxes.state.accountdesc, - Amount: state_tax.toFormat(DineroQbFormat), - }); - } - } - - if (local_tax.getAmount() > 0) { - if (qbo) { - // do qbo - } else { - InvoiceLineAdd.push({ - ItemRef: { - FullName: bodyshop.md_responsibility_centers.taxes.local.accountitem, - }, - Desc: bodyshop.md_responsibility_centers.taxes.local.accountdesc, - Amount: local_tax.toFormat(DineroQbFormat), - }); - } - } - - //Region Specific - const { ca_bc_pvrt } = jobs_by_pk; - if (ca_bc_pvrt) { - if (qbo) { - InvoiceLineAdd.push({ - DetailType: "SalesItemLineDetail", - Amount: Dinero({ amount: (ca_bc_pvrt || 0) * 100 }).toFormat( - DineroQbFormat - ), - SalesItemLineDetail: { - ...(jobs_by_pk.class - ? { ClassRef: { value: classes[jobs_by_pk.class] } } - : {}), + const QboTaxId = + process.env.COUNTRY === "USA" + ? CheckQBOUSATaxID({ + // jobline: jobline, + type: "adjustment", + job: jobs_by_pk, + }) + : taxCodes[taxAccountCode]; + for (let tyCounter = 1; tyCounter <= 5; tyCounter++) { + const taxAmount = Dinero( + job_totals.totals.us_sales_tax_breakdown[`ty${tyCounter}Tax`] + ); + if (taxAmount.getAmount() > 0) { + if (qbo) { + InvoiceLineAdd.push({ + DetailType: "SalesItemLineDetail", + Amount: taxAmount.toFormat(DineroQbFormat), + SalesItemLineDetail: { + ...(jobs_by_pk.class + ? { ClassRef: { value: classes[jobs_by_pk.class] } } + : {}), + ItemRef: { + value: + items[ + responsibilityCenters.taxes[`tax_ty${tyCounter}`].accountitem + ], + }, + TaxCodeRef: { + value: QboTaxId, + }, + Qty: 1, + }, + }); + } else { + InvoiceLineAdd.push({ ItemRef: { - value: items["PVRT"], + FullName: + bodyshop.md_responsibility_centers.taxes[`tax_ty${tyCounter}`] + .accountitem, }, - Qty: 1, - TaxCodeRef: { - value: - taxCodes[ - findTaxCode( - { - local: false, - federal: process.env.COUNTRY === "USA" ? false : true, - state: false, - }, - bodyshop.md_responsibility_centers.sales_tax_codes - ) - ], - }, - }, - }); - } else { - InvoiceLineAdd.push({ - ItemRef: { - FullName: bodyshop.md_responsibility_centers.taxes.state.accountitem, - }, - Desc: "PVRT", - Amount: Dinero({ amount: (ca_bc_pvrt || 0) * 100 }).toFormat( - DineroQbFormat - ), - }); + Desc: bodyshop.md_responsibility_centers.taxes[`tax_ty${tyCounter}`] + .accountdesc, + Amount: taxAmount.toFormat(DineroQbFormat), + }); + } } } - //QB USA with GST - //This was required for the No. 1 Collision Group. - // if ( - // bodyshop.accountingconfig && - // bodyshop.accountingconfig.qbo && - // bodyshop.accountingconfig.qbo_usa && - // bodyshop.region_config.includes("CA_") - // ) { - // InvoiceLineAdd.push({ - // DetailType: "SalesItemLineDetail", - // Amount: Dinero(jobs_by_pk.job_totals.totals.federal_tax).toFormat( - // DineroQbFormat - // ), - // SalesItemLineDetail: { - // ...(jobs_by_pk.class - // ? { ClassRef: { value: classes[jobs_by_pk.class] } } - // : {}), - // ItemRef: { - // value: - // items[bodyshop.md_responsibility_centers.taxes.federal.accountitem], - // }, - // Qty: 1, - // }, - // }); - // } - if (!qbo && InvoiceLineAdd.length === 0) { //Handle the scenario where there is a $0 sale invoice. InvoiceLineAdd.push({ @@ -832,17 +763,19 @@ exports.createMultiQbPayerLines = function ({ }; function CheckQBOUSATaxID({ jobline, job, type }) { - if (type === "labor") { - return jobline.lbr_tax ? "TAX" : "NON"; - } else if (type === "part") { - return jobline.tax_part ? "TAX" : "NON"; - } else if (type === "materials") { - return job.tax_paint_mat_rt > 0 ? "TAX" : "NON"; - } else if (type === " towing") { - return true ? "TAX" : "NON"; - } else if (type === "adjustment") { - return false ? "TAX" : "NON"; - } else { - throw new Error(`Unknown type to calculate tax id: ${type} `); - } + //Replacing this to be all non-taxable items with the refactor of parts tax rates. + return "NON"; + // if (type === "labor") { + // return jobline.lbr_tax ? "TAX" : "NON"; + // } else if (type === "part") { + // return jobline.tax_part ? "TAX" : "NON"; + // } else if (type === "materials") { + // return job.tax_paint_mat_rt > 0 ? "TAX" : "NON"; + // } else if (type === " towing") { + // return true ? "TAX" : "NON"; + // } else if (type === "adjustment") { + // return false ? "TAX" : "NON"; + // } else { + // throw new Error(`Unknown type to calculate tax id: ${type} `); + // } } diff --git a/server/cdk/cdk-calculate-allocations.js b/server/cdk/cdk-calculate-allocations.js index cd75dc6ec..2066a04aa 100644 --- a/server/cdk/cdk-calculate-allocations.js +++ b/server/cdk/cdk-calculate-allocations.js @@ -25,26 +25,61 @@ exports.default = async function (socket, jobid) { const { bodyshop } = job; const taxAllocations = { - local: { - center: bodyshop.md_responsibility_centers.taxes.local.name, - sale: Dinero(job.job_totals.totals.local_tax), + // 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, + // }, + tax_ty1: { + center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name, + sale: Dinero(job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]), cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes.local, - costCenter: bodyshop.md_responsibility_centers.taxes.local, + profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`], + costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty1`], }, - state: { - center: bodyshop.md_responsibility_centers.taxes.state.name, - sale: Dinero(job.job_totals.totals.state_tax), + tax_ty2: { + center: bodyshop.md_responsibility_centers.taxes[`tax_ty2`].name, + sale: Dinero(job_totals.totals.us_sales_tax_breakdown[`ty2Tax`]), cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes.state, - costCenter: bodyshop.md_responsibility_centers.taxes.state, + profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`], + costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty2`], }, - federal: { - center: bodyshop.md_responsibility_centers.taxes.federal.name, - sale: Dinero(job.job_totals.totals.federal_tax), + tax_ty3: { + center: bodyshop.md_responsibility_centers.taxes[`tax_ty3`].name, + sale: Dinero(job_totals.totals.us_sales_tax_breakdown[`ty3Tax`]), cost: Dinero(), - profitCenter: bodyshop.md_responsibility_centers.taxes.federal, - costCenter: bodyshop.md_responsibility_centers.taxes.federal, + 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_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_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`], }, }; diff --git a/server/job/job-totals.js b/server/job/job-totals.js index c3b3d4c9c..8ebbb6f1a 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -483,24 +483,25 @@ function CalculatePartsTotals(jobLines, parts_tax_rates, job) { value.db_ref !== "900511" ) return acc; + + const discountAmount = + ((value.prt_dsmk_m && value.prt_dsmk_m !== 0) || + (value.prt_dsmk_p && value.prt_dsmk_p !== 0)) && + DiscountNotAlreadyCounted(value, jl) + ? value.prt_dsmk_m + ? Dinero({ amount: Math.round(value.prt_dsmk_m * 100) }) + : Dinero({ + amount: Math.round(value.act_price * 100), + }) + .multiply(value.part_qty || 0) + .percentage(Math.abs(value.prt_dsmk_p || 0)) + .multiply(value.prt_dsmk_p > 0 ? 1 : -1) + : Dinero(); return { ...acc, parts: { ...acc.parts, - prt_dsmk_total: acc.parts.prt_dsmk_total.add( - ((value.prt_dsmk_m && value.prt_dsmk_m !== 0) || - (value.prt_dsmk_p && value.prt_dsmk_p !== 0)) && - DiscountNotAlreadyCounted(value, jl) - ? value.prt_dsmk_m - ? Dinero({ amount: Math.round(value.prt_dsmk_m * 100) }) - : Dinero({ - amount: Math.round(value.act_price * 100), - }) - .multiply(value.part_qty || 0) - .percentage(Math.abs(value.prt_dsmk_p || 0)) - .multiply(value.prt_dsmk_p > 0 ? 1 : -1) - : Dinero() - ), + prt_dsmk_total: acc.parts.prt_dsmk_total.add(discountAmount), ...(value.part_type ? { list: { @@ -509,20 +510,24 @@ function CalculatePartsTotals(jobLines, parts_tax_rates, job) { acc.parts.list[value.part_type] && acc.parts.list[value.part_type].total ? { - total: acc.parts.list[value.part_type].total.add( - Dinero({ - amount: Math.round( - (value.act_price || 0) * 100 - ), - }).multiply(value.part_qty || 0) - ), + total: acc.parts.list[value.part_type].total + .add( + Dinero({ + amount: Math.round( + (value.act_price || 0) * 100 + ), + }).multiply(value.part_qty || 0) + ) + .add(discountAmount), } : { total: Dinero({ amount: Math.round( (value.act_price || 0) * 100 ), - }).multiply(value.part_qty || 0), + }) + .multiply(value.part_qty || 0) + .add(discountAmount), }, }, } @@ -624,7 +629,7 @@ function CalculatePartsTotals(jobLines, parts_tax_rates, job) { ); //If the difference is greater than a penny, fix it. - + //This usually ties into whether or not the profile has part type discounts overall in the PFP. if ( correspondingCiecaStlTotalLine && Math.abs( @@ -663,7 +668,7 @@ function CalculatePartsTotals(jobLines, parts_tax_rates, job) { // ret.parts.list[key].total = ret.parts.list[key]?.total.subtract( // totalDiscountToAdjustBy // ); - ret.parts.prt_dsmk_total = ret.parts.prt_dsmk_total.add( + ret.parts.prt_dsmk_total = ret.parts.prt_dsmk_total.subtract( totalDiscountToAdjustBy ); ret.parts.subtotal = ret.parts.subtotal.subtract(totalDiscountToAdjustBy); @@ -671,7 +676,7 @@ function CalculatePartsTotals(jobLines, parts_tax_rates, job) { } }); - //UpdateJobLines(linesToAdjustForDiscount.filter((l) => l.prt_dsmk_m !== 0)); + UpdateJobLines(linesToAdjustForDiscount.filter((l) => l.prt_dsmk_m !== 0)); return { adjustments, @@ -804,6 +809,9 @@ function CalculateTaxesTotals(job, otherTotals) { LAM: Dinero(), LAR: Dinero(), LAS: Dinero(), + + MAPA: Dinero(), + MASH: Dinero(), }; if ( @@ -824,14 +832,14 @@ function CalculateTaxesTotals(job, otherTotals) { } else if (!val.part_type) { //Do nothing for now. } else { - const typeOfPart = val.part_type; // === "PAM" ? "PAC" : val.part_type; + const typeOfPart = val.part_type; taxableAmounts[typeOfPart] = taxableAmounts[typeOfPart].add( Dinero({ amount: Math.round((val.act_price || 0) * 100) }) .multiply(val.part_qty || 0) .add( val.prt_dsmk_m && val.prt_dsmk_m !== 0 && - DiscountNotAlreadyCounted(val, job.joblines) + DiscountNotAlreadyCounted(val, job.joblines) // DO WE NEED TO COUNT PFP DISCOUNT HERE? ? val.prt_dsmk_m ? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) }) : Dinero({ @@ -858,6 +866,17 @@ function CalculateTaxesTotals(job, otherTotals) { } }); + Object.keys(taxableAmounts) + .filter((key) => key.startsWith("MA")) + .map((key) => { + const isTypeTaxable = job.materials[key]?.tax_ind; + if (isTypeTaxable) { + taxableAmounts[key] = taxableAmounts[key].add( + otherTotals.rates[key.toLowerCase()].total + ); + } + }); + console.log("*** Taxable Amounts***"); console.table(JSON.parse(JSON.stringify(taxableAmounts))); @@ -883,6 +902,7 @@ function CalculateTaxesTotals(job, otherTotals) { const pfp = job.parts_tax_rates; const pfl = job.cieca_pfl; + const pfm = job.materials; Object.keys(taxableAmounts).map((key) => { try { if (key.startsWith("PA")) { @@ -896,6 +916,16 @@ function CalculateTaxesTotals(job, otherTotals) { ].add(taxableAmounts[typeOfPart]); } } + } else if (key.startsWith("MA")) { + //Materials Handling + for (let tyCounter = 1; tyCounter <= 5; tyCounter++) { + if (IsTrueOrYes(pfm[key][`mat_tx_in${tyCounter}`])) { + //This amount is taxable for this type. + taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[ + `ty${tyCounter}Tax` + ].add(taxableAmounts[key]); + } + } } else { //Labor. for (let tyCounter = 1; tyCounter <= 5; tyCounter++) { @@ -1060,7 +1090,7 @@ function CalculateTaxesTotals(job, otherTotals) { statePartsTax, us_sales_tax_breakdown, state_tax: statePartsTax - .add(laborTaxTotal) + //.add(laborTaxTotal) .add( otherTotals.additional.adjustments.percentage( (job.tax_lbr_rt || 0) * 100 @@ -1071,22 +1101,22 @@ function CalculateTaxesTotals(job, otherTotals) { ) .add( otherTotals.additional.storage.percentage((job.tax_str_rt || 0) * 100) - ) - .add(additionalItemsTax) // 0 if using PFP method. - .add( - otherTotals.rates.mapa.hasMapaLine === false //If parts and materials were not added as lines, we must calculate the taxes on them. - ? otherTotals.rates.mapa.total.percentage( - (job.tax_paint_mat_rt || 0) * 100 - ) - : Dinero() - ) - .add( - otherTotals.rates.mash.hasMashLine === false //If parts and materials were not added as lines, we must calculate the taxes on them. - ? otherTotals.rates.mash.total.percentage( - (job.tax_shop_mat_rt || 0) * 100 - ) - : Dinero() ), + // .add(additionalItemsTax) // 0 if using PFP method. + // .add( + // otherTotals.rates.mapa.hasMapaLine === false //If parts and materials were not added as lines, we must calculate the taxes on them. + // ? otherTotals.rates.mapa.total.percentage( + // (job.tax_paint_mat_rt || 0) * 100 + // ) + // : Dinero() + // ) + // .add( + // otherTotals.rates.mash.hasMashLine === false //If parts and materials were not added as lines, we must calculate the taxes on them. + // ? otherTotals.rates.mash.total.percentage( + // (job.tax_shop_mat_rt || 0) * 100 + // ) + // : Dinero() + // ) local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100), }; ret.total_repairs = ret.subtotal @@ -1132,14 +1162,12 @@ function DiscountNotAlreadyCounted(jobline, joblines) { return false; } - //Check it against the database price too? If it's an OE part. - // if ( - // Math.abs(jobline.db_price - jobline.act_price) - - // Math.abs(jobline.prt_dsmk_m) < - // 0.01 - // ) { - // return false; - // } + if ( + jobline.db_price !== jobline.act_price && + jobline.db_price - jobline.act_price - Math.abs(jobline.prt_dsmk_m) < 0.02 + ) { + return false; + } if ( //If it's not a discount line, then it definitely hasn't been counted yet.