Final adjustments to job totals calculation for 99% accuracy.
This commit is contained in:
@@ -62,8 +62,8 @@ async function TotalsServerSide(req, res) {
|
||||
let ret = {
|
||||
rates: await CalculateRatesTotals({ job, client }),
|
||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates, job),
|
||||
additional: CalculateAdditional(job),
|
||||
};
|
||||
ret.additional = CalculateAdditional(job);
|
||||
ret.totals = CalculateTaxesTotals(job, ret);
|
||||
|
||||
return ret;
|
||||
@@ -96,8 +96,8 @@ async function Totals(req, res) {
|
||||
let ret = {
|
||||
rates: await CalculateRatesTotals({ job, client }),
|
||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates, job),
|
||||
additional: CalculateAdditional(job),
|
||||
};
|
||||
ret.additional = CalculateAdditional(job);
|
||||
ret.totals = CalculateTaxesTotals(job, ret);
|
||||
|
||||
res.status(200).json(ret);
|
||||
@@ -261,6 +261,7 @@ async function CalculateRatesTotals({ job, client }) {
|
||||
let hasMapaLine = false;
|
||||
let hasMashLine = false;
|
||||
let hasMahwLine = false;
|
||||
let hasCustomMahwLine;
|
||||
let mapaOpCodes = ParseCalopCode(job.materials["mapa"]?.cal_opcode);
|
||||
let mashOpCodes = ParseCalopCode(job.materials["mash"]?.cal_opcode);
|
||||
|
||||
@@ -279,9 +280,21 @@ async function CalculateRatesTotals({ job, client }) {
|
||||
amount: Math.round((item.act_price || 0) * 100),
|
||||
});
|
||||
}
|
||||
if (item.line_desc?.toLowerCase().includes("hazardous waste")) {
|
||||
//We might add a hazardous waste line. So we'll need to make sure we only pick up the CCC one.
|
||||
if (
|
||||
item.line_desc?.toLowerCase().includes("hazardous waste") &&
|
||||
!item.manual_line &&
|
||||
item.part_type === null &&
|
||||
item.lbr_op !== "OP16" //Seems to be that it is OP16 for sublet lines.
|
||||
) {
|
||||
hasMahwLine = item;
|
||||
}
|
||||
if (
|
||||
item.line_desc?.toLowerCase().includes("hazardous waste") &&
|
||||
item.manual_line
|
||||
) {
|
||||
hasCustomMahwLine = item;
|
||||
}
|
||||
|
||||
if (item.mod_lbr_ty) {
|
||||
//Check to see if it has 0 hours and a price instead.
|
||||
@@ -377,30 +390,39 @@ async function CalculateRatesTotals({ job, client }) {
|
||||
stlMahw.ttl_amt !== 0 &&
|
||||
(!hasMahwLine || hasMahwLine.act_price !== stlMahw.ttl_amt)
|
||||
) {
|
||||
//The Mahw line that has been added doesn't match with what we have in the STL. Add/update the adjusting line so that the balance is correct.
|
||||
|
||||
//Add a hazardous waste material line in case there isn't one on the estimate.
|
||||
if (hasMahwLine) {
|
||||
let newPrice = stlMahw.ttl_amt;
|
||||
if (hasCustomMahwLine) {
|
||||
//Update it
|
||||
job.joblines.forEach((jl) => {
|
||||
if (jl.id === hasMahwLine.id) {
|
||||
jl.act_price = stlMahw.ttl_amt;
|
||||
if (jl.id === hasCustomMahwLine.id) {
|
||||
jl.act_price = newPrice;
|
||||
jl.manual_line = true;
|
||||
jl.tax_part = stlMahw.tax_amt > 0 ? true : false;
|
||||
}
|
||||
});
|
||||
await client.request(queries.UPDATE_JOB_LINE, {
|
||||
lineId: hasMahwLine.id,
|
||||
line: { act_price: stlMahw.ttl_amt },
|
||||
lineId: hasCustomMahwLine.id,
|
||||
line: {
|
||||
act_price: newPrice,
|
||||
manual_line: true,
|
||||
tax_part: stlMahw.tax_amt > 0 ? true : false,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
const newMahwLine = {
|
||||
line_desc: "Hazardous Waste Removal*",
|
||||
part_type: "PAS",
|
||||
part_type: null,
|
||||
oem_partno: null,
|
||||
db_price: 0,
|
||||
act_price: stlMahw.ttl_amt,
|
||||
act_price: newPrice,
|
||||
part_qty: 1,
|
||||
//mod_lbr_ty: "LAB",
|
||||
mod_lbr_ty: "LAB",
|
||||
db_hrs: 0,
|
||||
mod_lb_hrs: 0,
|
||||
lbr_op: "OP11",
|
||||
lbr_op: "OP0",
|
||||
lbr_amt: 0,
|
||||
op_code_desc: "REMOVE / REPLACE",
|
||||
tax_part: stlMahw.tax_amt > 0 ? true : false,
|
||||
@@ -710,6 +732,9 @@ function IsAdditionalCost(jobLine) {
|
||||
}
|
||||
|
||||
function CalculateAdditional(job) {
|
||||
const stlTowing = job.cieca_stl?.data.find((c) => c.ttl_type === "OTTW");
|
||||
const stlStorage = job.cieca_stl?.data.find((c) => c.ttl_type === "OTST");
|
||||
|
||||
let ret = {
|
||||
additionalCosts: null,
|
||||
additionalCostItems: [],
|
||||
@@ -720,9 +745,11 @@ function CalculateAdditional(job) {
|
||||
pvrt: null,
|
||||
total: null,
|
||||
};
|
||||
ret.towing = Dinero({
|
||||
amount: Math.round((job.towing_payable || 0) * 100),
|
||||
});
|
||||
ret.towing = stlTowing
|
||||
? Dinero({ amount: Math.round(stlTowing.ttl_amt * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round((job.towing_payable || 0) * 100),
|
||||
});
|
||||
|
||||
ret.additionalCosts = job.joblines
|
||||
.filter((jl) => !jl.removed && IsAdditionalCost(jl))
|
||||
@@ -747,9 +774,11 @@ function CalculateAdditional(job) {
|
||||
ret.adjustments = Dinero({
|
||||
amount: Math.round((job.adjustment_bottom_line || 0) * 100),
|
||||
});
|
||||
ret.storage = Dinero({
|
||||
amount: Math.round((job.storage_payable || 0) * 100),
|
||||
});
|
||||
ret.storage = stlStorage
|
||||
? Dinero({ amount: Math.round(stlStorage.ttl_amt * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round((job.storage_payable || 0) * 100),
|
||||
});
|
||||
ret.pvrt = Dinero({
|
||||
amount: Math.round((job.ca_bc_pvrt || 0) * 100),
|
||||
});
|
||||
@@ -812,6 +841,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
|
||||
MAPA: Dinero(),
|
||||
MASH: Dinero(),
|
||||
TOW: Dinero(),
|
||||
STOR: Dinero(),
|
||||
};
|
||||
|
||||
if (
|
||||
@@ -876,9 +907,21 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
);
|
||||
}
|
||||
});
|
||||
//Add towing and storage taxable amounts
|
||||
const stlTowing = job.cieca_stl?.data.find((c) => c.ttl_typecd === "OTTW");
|
||||
const stlStorage = job.cieca_stl?.data.find((c) => c.ttl_typecd === "OTST");
|
||||
|
||||
console.log("*** Taxable Amounts***");
|
||||
console.table(JSON.parse(JSON.stringify(taxableAmounts)));
|
||||
if (stlTowing)
|
||||
taxableAmounts.TOW = Dinero({
|
||||
amount: Math.round(stlTowing.t_amt * 100),
|
||||
});
|
||||
if (stlStorage)
|
||||
taxableAmounts.TOW = Dinero({
|
||||
amount: Math.round(stlStorage.t_amt * 100),
|
||||
});
|
||||
|
||||
// console.log("*** Taxable Amounts***");
|
||||
// console.table(JSON.parse(JSON.stringify(taxableAmounts)));
|
||||
|
||||
//For the taxable amounts, figure out which tax type applies.
|
||||
//Then sum up the total of that tax type and then calculate the thresholds.
|
||||
@@ -903,6 +946,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
const pfp = job.parts_tax_rates;
|
||||
const pfl = job.cieca_pfl;
|
||||
const pfm = job.materials;
|
||||
const pfo = job.cieca_pfo;
|
||||
Object.keys(taxableAmounts).map((key) => {
|
||||
try {
|
||||
if (key.startsWith("PA")) {
|
||||
@@ -926,7 +970,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
].add(taxableAmounts[key]);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if (key.startsWith("LA")) {
|
||||
//Labor.
|
||||
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
||||
if (IsTrueOrYes(pfl[key][`lbr_tx_in${tyCounter}`])) {
|
||||
@@ -936,6 +980,24 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
].add(taxableAmounts[key]);
|
||||
}
|
||||
}
|
||||
} else if (key === "TOW") {
|
||||
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
||||
if (IsTrueOrYes(pfo[`tow_t_in${tyCounter}`])) {
|
||||
//This amount is taxable for this type.
|
||||
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[
|
||||
`ty${tyCounter}Tax`
|
||||
].add(taxableAmounts[key]);
|
||||
}
|
||||
}
|
||||
} else if (key === "STOR") {
|
||||
for (let tyCounter = 1; tyCounter <= 5; tyCounter++) {
|
||||
if (IsTrueOrYes(pfo[`stor_t_in${tyCounter}`])) {
|
||||
//This amount is taxable for this type.
|
||||
taxableAmountsByTier[`ty${tyCounter}Tax`] = taxableAmountsByTier[
|
||||
`ty${tyCounter}Tax`
|
||||
].add(taxableAmounts[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Key with issue", key);
|
||||
@@ -943,8 +1005,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
});
|
||||
|
||||
const remainingTaxableAmounts = taxableAmountsByTier;
|
||||
console.log("*** Taxable Amounts by Tier***");
|
||||
console.table(JSON.parse(JSON.stringify(taxableAmountsByTier)));
|
||||
// console.log("*** Taxable Amounts by Tier***");
|
||||
// console.table(JSON.parse(JSON.stringify(taxableAmountsByTier)));
|
||||
|
||||
Object.keys(taxableAmountsByTier).forEach((taxTierKey) => {
|
||||
try {
|
||||
@@ -998,8 +1060,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
}
|
||||
});
|
||||
|
||||
console.log("*** Total Tax by Tier Amounts***");
|
||||
console.table(JSON.parse(JSON.stringify(totalTaxByTier)));
|
||||
// console.log("*** Total Tax by Tier Amounts***");
|
||||
// console.table(JSON.parse(JSON.stringify(totalTaxByTier)));
|
||||
|
||||
statePartsTax = statePartsTax
|
||||
.add(totalTaxByTier.ty1Tax)
|
||||
@@ -1009,7 +1071,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
.add(totalTaxByTier.ty5Tax)
|
||||
.add(totalTaxByTier.ty6Tax);
|
||||
us_sales_tax_breakdown = totalTaxByTier;
|
||||
console.log("Tiered Taxes Total for Parts/Labor", statePartsTax.toFormat());
|
||||
//console.log("Tiered Taxes Total for Parts/Labor", statePartsTax.toFormat());
|
||||
} else {
|
||||
//Use the old thing.
|
||||
job.joblines
|
||||
@@ -1061,7 +1123,6 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
)
|
||||
);
|
||||
}
|
||||
console.log(statePartsTax.toFormat(), val.line_desc);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1077,7 +1138,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
); // THis is currently using the lbr tax rate from PFH not PFL.
|
||||
}
|
||||
|
||||
console.log("Labor Tax Total", laborTaxTotal.toFormat());
|
||||
//console.log("Labor Tax Total", laborTaxTotal.toFormat());
|
||||
|
||||
let ret = {
|
||||
subtotal: subtotal,
|
||||
federal_tax: subtotal
|
||||
@@ -1089,34 +1151,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
),
|
||||
statePartsTax,
|
||||
us_sales_tax_breakdown,
|
||||
state_tax: statePartsTax
|
||||
//.add(laborTaxTotal)
|
||||
.add(
|
||||
otherTotals.additional.adjustments.percentage(
|
||||
(job.tax_lbr_rt || 0) * 100
|
||||
)
|
||||
)
|
||||
.add(
|
||||
otherTotals.additional.towing.percentage((job.tax_tow_rt || 0) * 100)
|
||||
)
|
||||
.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()
|
||||
// )
|
||||
state_tax: statePartsTax,
|
||||
local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100),
|
||||
};
|
||||
ret.total_repairs = ret.subtotal
|
||||
@@ -1153,6 +1188,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
exports.default = Totals;
|
||||
|
||||
function DiscountNotAlreadyCounted(jobline, joblines) {
|
||||
return false;
|
||||
//CCC already factors in the discount. If the difference between the 2 is exactly the discount, it's all good.
|
||||
if (
|
||||
Math.round(
|
||||
|
||||
Reference in New Issue
Block a user