Add parts tax calculations.
This commit is contained in:
@@ -429,55 +429,6 @@ async function CalculateRatesTotals({ job, client }) {
|
||||
|
||||
function CalculatePartsTotals(jobLines, parts_tax_rates) {
|
||||
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(
|
||||
(acc, value) => {
|
||||
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.towing)
|
||||
.add(ret.storage);
|
||||
//.add(ret.pvrt);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -767,23 +717,35 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
job.parts_tax_rates.PAGQ ||
|
||||
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
|
||||
.filter((jl) => !jl.removed)
|
||||
.forEach((val) => {
|
||||
if (!val.tax_part) return;
|
||||
if (!val.part_type && IsAdditionalCost(val)) {
|
||||
additionalItemsTax = additionalItemsTax.add(
|
||||
Dinero({ amount: Math.round((val.act_price || 0) * 100) })
|
||||
.multiply(val.part_qty || 0)
|
||||
.percentage(
|
||||
((job.parts_tax_rates &&
|
||||
job.parts_tax_rates["PAN"] &&
|
||||
job.parts_tax_rates["PAN"].prt_tax_rt) ||
|
||||
0) * 100
|
||||
)
|
||||
taxableAmounts.PAO = taxableAmounts.PAO.add(
|
||||
Dinero({ amount: Math.round((val.act_price || 0) * 100) }).multiply(
|
||||
val.part_qty || 0
|
||||
)
|
||||
);
|
||||
} else if (!val.part_type) {
|
||||
//Do nothing for now.
|
||||
} 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) })
|
||||
.multiply(val.part_qty || 0)
|
||||
.add(
|
||||
@@ -800,24 +762,98 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
.multiply(val.prt_dsmk_p > 0 ? 1 : -1)
|
||||
: 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();
|
||||
|
||||
if (Object.keys(job.cieca_pfl).length > 0) {
|
||||
@@ -853,6 +889,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
(job.tax_lbr_rt || 0) * 100
|
||||
); // THis is currently using the lbr tax rate from PFH not PFL.
|
||||
}
|
||||
|
||||
console.log("Labor Tax Total", laborTaxTotal.toFormat());
|
||||
let ret = {
|
||||
subtotal: subtotal,
|
||||
federal_tax: subtotal
|
||||
@@ -876,7 +914,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
.add(
|
||||
otherTotals.additional.storage.percentage((job.tax_str_rt || 0) * 100)
|
||||
)
|
||||
.add(additionalItemsTax)
|
||||
// .add(additionalItemsTax)
|
||||
.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(
|
||||
@@ -964,3 +1002,7 @@ function ParseCalopCode(opcode) {
|
||||
if (!opcode) return [];
|
||||
return opcode.trim().split(" ");
|
||||
}
|
||||
|
||||
function IsTrueOrYes(value) {
|
||||
return value === true || value === "Y" || value === "y";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user