Add parts tax calculations.

This commit is contained in:
Patrick Fic
2023-09-11 20:44:12 -07:00
parent d163d145d0
commit 6a9e871b08
4 changed files with 121 additions and 78 deletions

View File

@@ -19,8 +19,8 @@ require("dotenv").config({
}); });
async function RunTheTest() { async function RunTheTest() {
const bodyshopids = ["6c63a820-542c-497e-8c82-0cc38fb2bbca"]; const bodyshopids = ["a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"];
const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImM2MGI5ZGUwODBmZmFmYmZjMTgzMzllY2Q0NGFjNzdmN2ZhNGU4ZDMiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUm9tZSBEZXZlbG9wbWVudCIsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoiYWRtaW4iLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbImFkbWluIl0sIngtaGFzdXJhLXVzZXItaWQiOiJ0NlltMU5EbENET1BacjNGOWJndVdINExoU1gyIn0sImlvYWRtaW4iOnRydWUsImlzcyI6Imh0dHBzOi8vc2VjdXJldG9rZW4uZ29vZ2xlLmNvbS9yb21lLXByb2QtMSIsImF1ZCI6InJvbWUtcHJvZC0xIiwiYXV0aF90aW1lIjoxNjkyODk5ODE2LCJ1c2VyX2lkIjoidDZZbTFORGxDRE9QWnIzRjliZ3VXSDRMaFNYMiIsInN1YiI6InQ2WW0xTkRsQ0RPUFpyM0Y5Ymd1V0g0TGhTWDIiLCJpYXQiOjE2OTMyNTA1NjIsImV4cCI6MTY5MzI1NDE2MiwiZW1haWwiOiJwYXRyaWNrQHJvbWUuZGV2IiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJmaXJlYmFzZSI6eyJpZGVudGl0aWVzIjp7ImVtYWlsIjpbInBhdHJpY2tAcm9tZS5kZXYiXX0sInNpZ25faW5fcHJvdmlkZXIiOiJwYXNzd29yZCJ9fQ.POr8U2pP4XtTJEDRJ_BveRkCs92CIfDDdfU24OYe_aZh6LFPN0bQukNHXrLt3gaD30SUcg5mgmI2VUphgmwviMEGY-zizPC9o6GUKEEppZWQXfrfTyJNa1VKKH9h5zZPPFFW8UJRMi131pCc0ev26GS8Do-FJAgwHLJd6Jp2RbbqiCIeafNMhQCEoXohOk-VArNe7tPAb6-IjxqGVyNqvVyIo6niSXYvmgNjyF1WnnIw0CsnPoJlc5kVMtRdYeshJI7V117MOlUwZicF62vsm32eCunjn3qhN5XsujI7gy9us3vzwhdR1lxISZCLhLOXEYHPL373HJh7I_KN1C3NuA`; const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjE5MGFkMTE4YTk0MGFkYzlmMmY1Mzc2YjM1MjkyZmVkZThjMmQwZWUiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUm9tZSBEZXZlbG9wbWVudCIsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciJdLCJ4LWhhc3VyYS11c2VyLWlkIjoidDZZbTFORGxDRE9QWnIzRjliZ3VXSDRMaFNYMiJ9LCJpb2FkbWluIjp0cnVlLCJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vcm9tZS1wcm9kLTEiLCJhdWQiOiJyb21lLXByb2QtMSIsImF1dGhfdGltZSI6MTY5NDQ2NjM3OCwidXNlcl9pZCI6InQ2WW0xTkRsQ0RPUFpyM0Y5Ymd1V0g0TGhTWDIiLCJzdWIiOiJ0NlltMU5EbENET1BacjNGOWJndVdINExoU1gyIiwiaWF0IjoxNjk0NDY5OTY3LCJleHAiOjE2OTQ0NzM1NjcsImVtYWlsIjoicGF0cmlja0Byb21lLmRldiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJwYXRyaWNrQHJvbWUuZGV2Il19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.cL1tTMmFwnyg-mXqRRaFLGSn92pwCDrbTGZviVFKTPqwejDDe_OTla6zizy5w5XBk1_S2CA4SrsH6-8uXkrRSLECd1QMsYK1XKUj0zkfe-o3Z1dMva9gPpVrs-fiCXzjcfs-P12hPfvubNZgqpj1EwZmQ6imq8MidkAo1c4V-IWGpxsmCTNBLN_09N0071spsabwtMosXHJVnkG44StXEM2w-FRak6dE0uZZkbPGgg_2uDwFQb3um6MJ8FbK398pLMs3cUrdQiB-5YozYoIuEI-L00s7dDTvjOKUzOvcDme5UCAS6RmwWoZYkTWrMJU3jf5ivAvjHNIhy3aMGyQxzg`;
const { jobs } = await client.request( const { jobs } = await client.request(
gql` gql`
query GET_JOBS($bodyshopids: [uuid!]!) { query GET_JOBS($bodyshopids: [uuid!]!) {

View File

@@ -1168,6 +1168,7 @@ exports.GET_JOB_BY_PK = `query GET_JOB_BY_PK($id: uuid!) {
shopid shopid
est_ct_ln est_ct_ln
cieca_pfl cieca_pfl
cieca_pft
vehicle{ vehicle{
id id
notes notes

View File

@@ -429,55 +429,6 @@ async function CalculateRatesTotals({ job, client }) {
function CalculatePartsTotals(jobLines, parts_tax_rates) { function CalculatePartsTotals(jobLines, parts_tax_rates) {
const jl = jobLines.filter((jl) => !jl.removed); const jl = jobLines.filter((jl) => !jl.removed);
// jl.forEach((line) => {
// //Some profile based estimates don't automatically add the discount to the line, some do.
// //Clean up the ones that don't to add it in.
// //Apply a discount to the line if there is a profile discount, but it isn't added to the line itself.
// const partTax = parts_tax_rates[line.part_type];
// if (
// line.act_price > 0 &&
// partTax &&
// partTax.prt_discp &&
// partTax.prt_discp > 0
// ) {
// //apply a discount
// const discount = Dinero({
// amount: Math.round(line.act_price * 100),
// }).percentage(
// Math.abs(partTax.prt_discp) > 1
// ? partTax.prt_discp
// : partTax.prt_discp * 100
// );
// line.prt_dsmk_m = discount.toFormat("0.0");
// line.prt_dsmk_p = partTax.prt_discp;
// line.act_price = Dinero({
// amount: Math.round(line.act_price * 100),
// })
// .subtract(discount)
// .toFormat("0.0");
// } else if (
// line.act_price > 0 &&
// partTax &&
// partTax.prt_mkupp &&
// partTax.prt_mkupp > 0
// ) {
// //apply a mark up
// const markup = Dinero({
// amount: Math.round(line.act_price * 100),
// }).percentage(
// Math.abs(partTax.prt_mkupp) > 1
// ? partTax.prt_mkupp
// : partTax.prt_mkupp * 100
// );
// line.prt_dsmk_m = markup.toFormat("0.0");
// line.prt_dsmk_p = partTax.prt_mkupp;
// line.act_price = Dinero({ amount: Math.round(line.act_price * 100) })
// .add(markup)
// .toFormat("0.0");
// }
// });
const ret = jl.reduce( const ret = jl.reduce(
(acc, value) => { (acc, value) => {
switch (value.part_type) { switch (value.part_type) {
@@ -738,7 +689,6 @@ function CalculateAdditional(job) {
.add(ret.adjustments) //IO-813 Adjustment takes care of GST & PST at labor rate. .add(ret.adjustments) //IO-813 Adjustment takes care of GST & PST at labor rate.
.add(ret.towing) .add(ret.towing)
.add(ret.storage); .add(ret.storage);
//.add(ret.pvrt);
return ret; return ret;
} }
@@ -767,23 +717,35 @@ function CalculateTaxesTotals(job, otherTotals) {
job.parts_tax_rates.PAGQ || job.parts_tax_rates.PAGQ ||
job.parts_tax_rates.PAGR); job.parts_tax_rates.PAGR);
const taxableAmounts = {
PAA: Dinero(),
PAN: Dinero(),
PAL: Dinero(),
PAR: Dinero(),
PAC: Dinero(),
PAG: Dinero(),
PAO: Dinero(),
PAS: Dinero(),
PAP: Dinero(),
PAM: Dinero(),
};
//For each line, determine if it's taxable, and if it is, add the line amount to the taxable amounts total.
job.joblines job.joblines
.filter((jl) => !jl.removed) .filter((jl) => !jl.removed)
.forEach((val) => { .forEach((val) => {
if (!val.tax_part) return; if (!val.tax_part) return;
if (!val.part_type && IsAdditionalCost(val)) { if (!val.part_type && IsAdditionalCost(val)) {
additionalItemsTax = additionalItemsTax.add( taxableAmounts.PAO = taxableAmounts.PAO.add(
Dinero({ amount: Math.round((val.act_price || 0) * 100) }) Dinero({ amount: Math.round((val.act_price || 0) * 100) }).multiply(
.multiply(val.part_qty || 0) val.part_qty || 0
.percentage( )
((job.parts_tax_rates &&
job.parts_tax_rates["PAN"] &&
job.parts_tax_rates["PAN"].prt_tax_rt) ||
0) * 100
)
); );
} else if (!val.part_type) {
//Do nothing for now.
} else { } else {
statePartsTax = statePartsTax.add( const typeOfPart = val.part_type === "PAM" ? "PAC" : val.part_type;
taxableAmounts[typeOfPart] = taxableAmounts[typeOfPart].add(
Dinero({ amount: Math.round((val.act_price || 0) * 100) }) Dinero({ amount: Math.round((val.act_price || 0) * 100) })
.multiply(val.part_qty || 0) .multiply(val.part_qty || 0)
.add( .add(
@@ -800,24 +762,98 @@ function CalculateTaxesTotals(job, otherTotals) {
.multiply(val.prt_dsmk_p > 0 ? 1 : -1) .multiply(val.prt_dsmk_p > 0 ? 1 : -1)
: Dinero() : Dinero()
) )
.percentage(
((job.parts_tax_rates &&
job.parts_tax_rates[val.part_type] &&
job.parts_tax_rates[val.part_type].prt_tax_rt) ||
(val.part_type &&
val.part_type.startsWith("PAG") &&
BackupGlassTax &&
BackupGlassTax.prt_tax_rt) ||
(!val.part_type &&
val.db_ref === "900510" &&
job.parts_tax_rates["PAN"] &&
job.parts_tax_rates["PAN"].prt_tax_rt) ||
0) * 100
)
); );
} }
}); });
//Taxable amounts should match with what is in the STL file.
//Now that we have the taxable amounts, apply the tax.
const tieredTaxAmounts = {
ty1Tax: Dinero(),
ty2Tax: Dinero(),
ty3Tax: Dinero(),
ty4Tax: Dinero(),
ty5Tax: Dinero(),
ty6Tax: Dinero(),
};
const remainingTaxableAmounts = taxableAmounts;
console.log("Taxable Parts Totals", JSON.stringify(taxableAmounts, null, 2));
Object.keys(taxableAmounts).forEach((part_type) => {
//Check it's taxability in the PFP
try {
const pfp = job.parts_tax_rates;
const typeOfPart = part_type === "PAM" ? "PAC" : part_type;
if (IsTrueOrYes(pfp[typeOfPart].prt_tax_in)) {
//At least one of these scenarios must be taxable.
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
if (IsTrueOrYes(pfp[typeOfPart][`prt_tx_in${tyCounter}`])) {
//i represents the tax number. If we got here, this type of tax is applicable. Now we need to add based on the thresholds.
for (let threshCounter = 1; threshCounter <= 5; threshCounter++) {
const thresholdAmount =
job.cieca_pft[`ty${tyCounter}_thres${threshCounter}`];
const thresholdTaxRate =
job.cieca_pft[`ty${tyCounter}_rate${threshCounter}`];
// console.log(
// `P: ${typeOfPart} tyCount: ${tyCounter} theshCount: ${threshCounter} TaxRt: ${thresholdTaxRate}`
// );
let taxableAmountInThisThreshold;
if (thresholdAmount === 9999.99) {
// THis is the last threshold. Tax the entire remaining amount.
taxableAmountInThisThreshold =
remainingTaxableAmounts[typeOfPart];
remainingTaxableAmounts[typeOfPart] = Dinero();
} else {
if (
thresholdAmount >=
remainingTaxableAmounts[typeOfPart].getAmount() / 100
) {
//This threshold is bigger than the remaining taxable balance. Add it all.
taxableAmountInThisThreshold =
remainingTaxableAmounts[typeOfPart];
remainingTaxableAmounts[typeOfPart] = Dinero();
} else {
//Take the size of the threshold from the remaining amount, tax it, and do it all over.
taxableAmountInThisThreshold = Dinero({
amount: Math.round(taxableAmountInThisThreshold * 100),
});
remainingTaxableAmounts[typeOfPart] = remainingTaxableAmounts[
typeOfPart
].subtract(
Dinero({
amount: Math.round(taxableAmountInThisThreshold * 100),
})
);
}
}
const taxAmountToAdd =
taxableAmountInThisThreshold.percentage(thresholdTaxRate);
tieredTaxAmounts[`ty${tyCounter}Tax`] =
tieredTaxAmounts[`ty${tyCounter}Tax`].add(taxAmountToAdd);
}
}
}
}
} catch (error) {
console.log("Shit the bed.");
}
});
statePartsTax = statePartsTax
.add(tieredTaxAmounts.ty1Tax)
.add(tieredTaxAmounts.ty2Tax)
.add(tieredTaxAmounts.ty3Tax)
.add(tieredTaxAmounts.ty4Tax)
.add(tieredTaxAmounts.ty5Tax)
.add(tieredTaxAmounts.ty6Tax);
console.log("Tiered Taxes Total for Parts", statePartsTax.toFormat());
let laborTaxTotal = Dinero(); let laborTaxTotal = Dinero();
if (Object.keys(job.cieca_pfl).length > 0) { if (Object.keys(job.cieca_pfl).length > 0) {
@@ -853,6 +889,8 @@ function CalculateTaxesTotals(job, otherTotals) {
(job.tax_lbr_rt || 0) * 100 (job.tax_lbr_rt || 0) * 100
); // THis is currently using the lbr tax rate from PFH not PFL. ); // THis is currently using the lbr tax rate from PFH not PFL.
} }
console.log("Labor Tax Total", laborTaxTotal.toFormat());
let ret = { let ret = {
subtotal: subtotal, subtotal: subtotal,
federal_tax: subtotal federal_tax: subtotal
@@ -876,7 +914,7 @@ function CalculateTaxesTotals(job, otherTotals) {
.add( .add(
otherTotals.additional.storage.percentage((job.tax_str_rt || 0) * 100) otherTotals.additional.storage.percentage((job.tax_str_rt || 0) * 100)
) )
.add(additionalItemsTax) // .add(additionalItemsTax)
.add( .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.hasMapaLine === false //If parts and materials were not added as lines, we must calculate the taxes on them.
? otherTotals.rates.mapa.total.percentage( ? otherTotals.rates.mapa.total.percentage(
@@ -964,3 +1002,7 @@ function ParseCalopCode(opcode) {
if (!opcode) return []; if (!opcode) return [];
return opcode.trim().split(" "); return opcode.trim().split(" ");
} }
function IsTrueOrYes(value) {
return value === true || value === "Y" || value === "y";
}

View File

@@ -1,6 +1,6 @@
var { admin } = require("./server/firebase/firebase-handler"); var { admin } = require("./server/firebase/firebase-handler");
const uidToMakeAdmin = "yTvpfkcNnGckLd1JnoXC7bTdvtu1"; const uidToMakeAdmin = "fIaZcVQQfUR12Fu14I2fyA5vXbp1";
admin admin
.auth() .auth()