Add parts tax calculations.
This commit is contained in:
@@ -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!]!) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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";
|
||||||
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user