Improved totals calculations
This commit is contained in:
@@ -58,15 +58,15 @@ async function TotalsServerSide(req, res) {
|
||||
|
||||
try {
|
||||
let ret = {
|
||||
rates: await CalculateRatesTotals({ job, client }),
|
||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates),
|
||||
rates: CalculateRatesTotals(job),
|
||||
additional: CalculateAdditional(job),
|
||||
};
|
||||
ret.totals = CalculateTaxesTotals(job, ret);
|
||||
|
||||
return ret;
|
||||
} catch (error) {
|
||||
logger.log("job-totals-ssu-error", "ERROR", req.user.email, job.id, {
|
||||
logger.log("job-totals-ssu-error", "ERROR", req.user?.email, job.id, {
|
||||
jobid: job.id,
|
||||
error,
|
||||
});
|
||||
@@ -92,8 +92,8 @@ async function Totals(req, res) {
|
||||
await AutoAddAtsIfRequired({ job, client });
|
||||
try {
|
||||
let ret = {
|
||||
rates: await CalculateRatesTotals({ job, client }),
|
||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates),
|
||||
rates: CalculateRatesTotals(job),
|
||||
additional: CalculateAdditional(job),
|
||||
};
|
||||
ret.totals = CalculateTaxesTotals(job, ret);
|
||||
@@ -183,72 +183,72 @@ async function AutoAddAtsIfRequired({ job, client }) {
|
||||
}
|
||||
}
|
||||
|
||||
function CalculateRatesTotals(ratesList) {
|
||||
const jobLines = ratesList.joblines.filter((jl) => !jl.removed);
|
||||
async function CalculateRatesTotals({ job, client }) {
|
||||
const jobLines = job.joblines.filter((jl) => !jl.removed);
|
||||
|
||||
let ret = {
|
||||
la1: {
|
||||
hours: 0,
|
||||
rate: ratesList.rate_la1 || 0,
|
||||
rate: job.rate_la1 || 0,
|
||||
},
|
||||
la2: {
|
||||
hours: 0,
|
||||
rate: ratesList.rate_la2 || 0,
|
||||
rate: job.rate_la2 || 0,
|
||||
},
|
||||
la3: {
|
||||
rate: ratesList.rate_la3 || 0,
|
||||
rate: job.rate_la3 || 0,
|
||||
hours: 0,
|
||||
},
|
||||
la4: {
|
||||
rate: ratesList.rate_la4 || 0,
|
||||
rate: job.rate_la4 || 0,
|
||||
hours: 0,
|
||||
},
|
||||
laa: {
|
||||
rate: ratesList.rate_laa || 0,
|
||||
rate: job.rate_laa || 0,
|
||||
hours: 0,
|
||||
},
|
||||
lab: {
|
||||
rate: ratesList.rate_lab || 0,
|
||||
rate: job.rate_lab || 0,
|
||||
hours: 0,
|
||||
},
|
||||
lad: {
|
||||
rate: ratesList.rate_lad || 0,
|
||||
rate: job.rate_lad || 0,
|
||||
hours: 0,
|
||||
},
|
||||
lae: {
|
||||
rate: ratesList.rate_lae || 0,
|
||||
rate: job.rate_lae || 0,
|
||||
hours: 0,
|
||||
},
|
||||
laf: {
|
||||
rate: ratesList.rate_laf || 0,
|
||||
rate: job.rate_laf || 0,
|
||||
hours: 0,
|
||||
},
|
||||
lag: {
|
||||
rate: ratesList.rate_lag || 0,
|
||||
rate: job.rate_lag || 0,
|
||||
hours: 0,
|
||||
},
|
||||
lam: {
|
||||
rate: ratesList.rate_lam || 0,
|
||||
rate: job.rate_lam || 0,
|
||||
hours: 0,
|
||||
},
|
||||
lar: {
|
||||
rate: ratesList.rate_lar || 0,
|
||||
rate: job.rate_lar || 0,
|
||||
hours: 0,
|
||||
},
|
||||
las: {
|
||||
rate: ratesList.rate_las || 0,
|
||||
rate: job.rate_las || 0,
|
||||
hours: 0,
|
||||
},
|
||||
lau: {
|
||||
rate: ratesList.rate_lau || 0,
|
||||
rate: job.rate_lau || 0,
|
||||
hours: 0,
|
||||
},
|
||||
mapa: {
|
||||
rate: ratesList.rate_mapa || 0,
|
||||
rate: job.rate_mapa || 0,
|
||||
hours: 0,
|
||||
},
|
||||
mash: {
|
||||
rate: ratesList.rate_mash || 0,
|
||||
rate: job.rate_mash || 0,
|
||||
hours: 0,
|
||||
},
|
||||
};
|
||||
@@ -258,8 +258,9 @@ function CalculateRatesTotals(ratesList) {
|
||||
//Otherwise, calculate them and add them to the default MAPA and MASH centers.
|
||||
let hasMapaLine = false;
|
||||
let hasMashLine = false;
|
||||
let mapaOpCodes = ParseCalopCode(ratesList.materials["mapa"]?.cal_opcode);
|
||||
let mashOpCodes = ParseCalopCode(ratesList.materials["mash"]?.cal_opcode);
|
||||
let hasMahwLine = false;
|
||||
let mapaOpCodes = ParseCalopCode(job.materials["mapa"]?.cal_opcode);
|
||||
let mashOpCodes = ParseCalopCode(job.materials["mash"]?.cal_opcode);
|
||||
|
||||
jobLines.forEach((item) => {
|
||||
//IO-1317 Use the lines on the estimate if they exist instead.
|
||||
@@ -276,6 +277,9 @@ function CalculateRatesTotals(ratesList) {
|
||||
amount: Math.round((item.act_price || 0) * 100),
|
||||
});
|
||||
}
|
||||
if (item.line_desc.toLowerCase().includes("hazardous waste")) {
|
||||
hasMahwLine = item;
|
||||
}
|
||||
|
||||
if (item.mod_lbr_ty) {
|
||||
//Check to see if it has 0 hours and a price instead.
|
||||
@@ -333,16 +337,16 @@ function CalculateRatesTotals(ratesList) {
|
||||
}
|
||||
let threshold;
|
||||
//Check if there is a max for this type.
|
||||
if (ratesList.materials && ratesList.materials[property]) {
|
||||
if (job.materials && job.materials[property]) {
|
||||
//
|
||||
|
||||
if (
|
||||
ratesList.materials[property].cal_maxdlr !== undefined &&
|
||||
ratesList.materials[property].cal_maxdlr >= 0
|
||||
job.materials[property].cal_maxdlr !== undefined &&
|
||||
job.materials[property].cal_maxdlr >= 0
|
||||
) {
|
||||
//It has an upper threshhold.
|
||||
threshold = Dinero({
|
||||
amount: Math.round(ratesList.materials[property].cal_maxdlr * 100),
|
||||
amount: Math.round(job.materials[property].cal_maxdlr * 100),
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -364,6 +368,37 @@ function CalculateRatesTotals(ratesList) {
|
||||
rates_subtotal = rates_subtotal.add(ret[property].total);
|
||||
}
|
||||
|
||||
const stlMahw = job.cieca_stl.data.find((c) => c.ttl_typecd === "MAHW");
|
||||
|
||||
if (
|
||||
stlMahw &&
|
||||
stlMahw.ttl_amt !== 0 &&
|
||||
(!hasMahwLine || hasMahwLine.act_price !== stlMahw.ttl_amt)
|
||||
) {
|
||||
//Add a hazardous waste material line in case there isn't one on the estimate.
|
||||
const newMahwLine = {
|
||||
line_desc: "Hazardous Waste Removal*",
|
||||
part_type: "PAS",
|
||||
oem_partno: null,
|
||||
db_price: 0,
|
||||
act_price: stlMahw.ttl_amt,
|
||||
part_qty: 1,
|
||||
//mod_lbr_ty: "LAB",
|
||||
db_hrs: 0,
|
||||
mod_lb_hrs: 0,
|
||||
lbr_op: "OP11",
|
||||
lbr_amt: 0,
|
||||
op_code_desc: "REMOVE / REPLACE",
|
||||
tax_part: true,
|
||||
db_ref: null,
|
||||
manual_line: true,
|
||||
jobid: job.id,
|
||||
};
|
||||
job.joblines.push(newMahwLine);
|
||||
await client.request(queries.INSERT_NEW_JOB_LINE, {
|
||||
lineInput: [newMahwLine],
|
||||
});
|
||||
}
|
||||
ret.subtotal = subtotal;
|
||||
ret.rates_subtotal = rates_subtotal;
|
||||
|
||||
@@ -374,6 +409,54 @@ function CalculateRatesTotals(ratesList) {
|
||||
|
||||
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) => {
|
||||
@@ -715,7 +798,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
}
|
||||
console.log(statePartsTax.toFormat(), val.line_desc);
|
||||
});
|
||||
console.log("State Parts Tax", statePartsTax.toFormat());
|
||||
|
||||
let ret = {
|
||||
subtotal: subtotal,
|
||||
federal_tax: subtotal
|
||||
@@ -742,21 +825,21 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
otherTotals.additional.storage.percentage((job.tax_str_rt || 0) * 100)
|
||||
)
|
||||
.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(
|
||||
(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_paint_mat_rt || 0) * 100
|
||||
)
|
||||
: Dinero()
|
||||
),
|
||||
|
||||
.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_paint_mat_rt || 0) * 100
|
||||
)
|
||||
: Dinero()
|
||||
),
|
||||
|
||||
local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100),
|
||||
};
|
||||
ret.total_repairs = ret.subtotal
|
||||
@@ -803,6 +886,17 @@ function DiscountNotAlreadyCounted(jobline, joblines) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check it against the database price too? If it's an OE part.
|
||||
console.log(jobline.db_price - jobline.act_price);
|
||||
if (
|
||||
Math.abs(jobline.db_price - jobline.act_price) -
|
||||
Math.abs(jobline.prt_dsmk_m) <
|
||||
0.01
|
||||
) {
|
||||
console.log(jobline.line_desc, "Already had the discount counted.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
//If it's not a discount line, then it definitely hasn't been counted yet.
|
||||
jobline.db_ref !== "900510" &&
|
||||
|
||||
Reference in New Issue
Block a user