Add UI elements for part tax and improve calculations.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
const Dinero = require("dinero.js");
|
||||
const queries = require("../graphql-client/queries");
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
const adminClient = require("../graphql-client/graphql-client").client;
|
||||
const _ = require("lodash");
|
||||
const logger = require("../utils/logger");
|
||||
// Dinero.defaultCurrency = "USD";
|
||||
// Dinero.globalLocale = "en-CA";
|
||||
@@ -59,7 +61,7 @@ async function TotalsServerSide(req, res) {
|
||||
try {
|
||||
let ret = {
|
||||
rates: await CalculateRatesTotals({ job, client }),
|
||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates),
|
||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates, job),
|
||||
additional: CalculateAdditional(job),
|
||||
};
|
||||
ret.totals = CalculateTaxesTotals(job, ret);
|
||||
@@ -93,7 +95,7 @@ async function Totals(req, res) {
|
||||
try {
|
||||
let ret = {
|
||||
rates: await CalculateRatesTotals({ job, client }),
|
||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates),
|
||||
parts: CalculatePartsTotals(job.joblines, job.parts_tax_rates, job),
|
||||
additional: CalculateAdditional(job),
|
||||
};
|
||||
ret.totals = CalculateTaxesTotals(job, ret);
|
||||
@@ -389,7 +391,7 @@ async function CalculateRatesTotals({ job, client }) {
|
||||
lbr_op: "OP11",
|
||||
lbr_amt: 0,
|
||||
op_code_desc: "REMOVE / REPLACE",
|
||||
tax_part: hasMahwLine.tax_amt > 0 ? true : false,
|
||||
tax_part: stlMahw.tax_amt > 0 ? true : false,
|
||||
db_ref: null,
|
||||
manual_line: true,
|
||||
jobid: job.id,
|
||||
@@ -427,7 +429,7 @@ async function CalculateRatesTotals({ job, client }) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
function CalculatePartsTotals(jobLines, parts_tax_rates) {
|
||||
function CalculatePartsTotals(jobLines, parts_tax_rates, job) {
|
||||
const jl = jobLines.filter((jl) => !jl.removed);
|
||||
const ret = jl.reduce(
|
||||
(acc, value) => {
|
||||
@@ -564,23 +566,27 @@ function CalculatePartsTotals(jobLines, parts_tax_rates) {
|
||||
PAS: Dinero(),
|
||||
PAT: Dinero(),
|
||||
};
|
||||
//Track all adjustments that need to be made.
|
||||
|
||||
const linesToAdjustForDiscount = [];
|
||||
Object.keys(parts_tax_rates).forEach((key) => {
|
||||
//Check if there's a discount or a mark up.
|
||||
let disc = Dinero(),
|
||||
markup = Dinero();
|
||||
|
||||
let discountRate, markupRate;
|
||||
if (
|
||||
parts_tax_rates[key].prt_discp !== undefined &&
|
||||
parts_tax_rates[key].prt_discp >= 0
|
||||
) {
|
||||
//Check if there's any parts in this part type.
|
||||
if (ret.parts.list[key] !== undefined) {
|
||||
disc = ret.parts.list[key].total
|
||||
.percentage(
|
||||
Math.abs(parts_tax_rates[key].prt_discp) > 1
|
||||
? parts_tax_rates[key].prt_discp
|
||||
: parts_tax_rates[key].prt_discp * 100
|
||||
)
|
||||
.multiply(-1);
|
||||
discountRate =
|
||||
Math.abs(parts_tax_rates[key].prt_discp) > 1
|
||||
? parts_tax_rates[key].prt_discp
|
||||
: parts_tax_rates[key].prt_discp * 100;
|
||||
|
||||
disc = ret.parts.list[key].total.percentage(discountRate).multiply(-1);
|
||||
}
|
||||
}
|
||||
if (
|
||||
@@ -589,26 +595,70 @@ function CalculatePartsTotals(jobLines, parts_tax_rates) {
|
||||
) {
|
||||
//Check if there's any parts in this part type.
|
||||
if (ret.parts.list[key] !== undefined) {
|
||||
markup = ret.parts.list[key].total.percentage(
|
||||
markupRate =
|
||||
Math.abs(parts_tax_rates[key].prt_mkupp) > 1
|
||||
? parts_tax_rates[key].prt_mkupp
|
||||
: parts_tax_rates[key].prt_mkupp * 100 //Seems that mark up is written as decimal not %.
|
||||
);
|
||||
: parts_tax_rates[key].prt_mkupp * 100; //Seems that mark up is written as decimal not %.
|
||||
|
||||
markup = ret.parts.list[key].total.percentage(markupRate);
|
||||
}
|
||||
}
|
||||
let adjustment = disc.add(markup);
|
||||
adjustments[key] = adjustment;
|
||||
|
||||
const correspondingCiecaStlTotalLine = job.cieca_stl?.data.find(
|
||||
(c) => c.ttl_typecd === key
|
||||
);
|
||||
|
||||
//If the difference is greater than a penny, fix it.
|
||||
|
||||
if (
|
||||
correspondingCiecaStlTotalLine &&
|
||||
Math.abs(
|
||||
ret.parts.list[key]?.total.getAmount() -
|
||||
correspondingCiecaStlTotalLine.ttl_amt * 100
|
||||
) > 1
|
||||
) {
|
||||
// Update the total.
|
||||
console.log(
|
||||
key,
|
||||
ret.parts.list[key]?.total.getAmount(),
|
||||
correspondingCiecaStlTotalLine?.ttl_amt
|
||||
);
|
||||
//Find the corresponding lines. Update the discount/markup for them.
|
||||
|
||||
console.warn("There's a difference! Type: ", key);
|
||||
let totalDiscountToAdjustBy = Dinero();
|
||||
job.joblines.forEach((jobline) => {
|
||||
//Modify the line in place to add the mark up/discount.
|
||||
if (jobline.part_type === key) {
|
||||
const discountAmountDinero = Dinero({
|
||||
amount: Math.round(jobline.act_price * 100),
|
||||
}).percentage(discountRate);
|
||||
|
||||
const discountAmount = parseFloat(
|
||||
discountAmountDinero.toFormat("0.00")
|
||||
);
|
||||
totalDiscountToAdjustBy =
|
||||
totalDiscountToAdjustBy.add(discountAmountDinero);
|
||||
jobline.prt_dsmk_m = discountAmount * -1;
|
||||
jobline.prt_dsmk_p = discountRate * -1;
|
||||
|
||||
linesToAdjustForDiscount.push(jobline);
|
||||
}
|
||||
});
|
||||
// ret.parts.list[key].total = ret.parts.list[key]?.total.subtract(
|
||||
// totalDiscountToAdjustBy
|
||||
// );
|
||||
ret.parts.prt_dsmk_total = ret.parts.prt_dsmk_total.add(
|
||||
totalDiscountToAdjustBy
|
||||
);
|
||||
ret.parts.subtotal = ret.parts.subtotal.subtract(totalDiscountToAdjustBy);
|
||||
ret.parts.total = ret.parts.total.subtract(totalDiscountToAdjustBy);
|
||||
}
|
||||
});
|
||||
|
||||
//Temporarily commenting this out since these totals appear to be already included in the calculation.
|
||||
// Object.keys(adjustments).forEach((key) => {
|
||||
// if (ret.parts.list[key] !== undefined) {
|
||||
// ret.parts.list[key].total = ret.parts.list[key].total.add(
|
||||
// adjustments[key]
|
||||
// );
|
||||
// ret.parts.subtotal = ret.parts.subtotal.add(adjustments[key]);
|
||||
// }
|
||||
// });
|
||||
//UpdateJobLines(linesToAdjustForDiscount.filter((l) => l.prt_dsmk_m !== 0));
|
||||
|
||||
return {
|
||||
adjustments,
|
||||
@@ -779,8 +829,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
};
|
||||
|
||||
const remainingTaxableAmounts = taxableAmounts;
|
||||
console.log("Taxable Parts Totals", JSON.stringify(taxableAmounts, null, 2));
|
||||
|
||||
console.log("Taxable Amounts");
|
||||
console.table(JSON.parse(JSON.stringify(taxableAmounts)));
|
||||
Object.keys(taxableAmounts).forEach((part_type) => {
|
||||
//Check it's taxability in the PFP
|
||||
try {
|
||||
@@ -793,14 +843,12 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
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}`
|
||||
// );
|
||||
const thresholdAmount = parseFloat(
|
||||
job.cieca_pft[`ty${tyCounter}_thres${threshCounter}`]
|
||||
);
|
||||
const thresholdTaxRate = parseFloat(
|
||||
job.cieca_pft[`ty${tyCounter}_rate${threshCounter}`]
|
||||
);
|
||||
|
||||
let taxableAmountInThisThreshold;
|
||||
if (thresholdAmount === 9999.99) {
|
||||
@@ -820,7 +868,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
} 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),
|
||||
amount: Math.round(thresholdAmount * 100),
|
||||
});
|
||||
remainingTaxableAmounts[typeOfPart] = remainingTaxableAmounts[
|
||||
typeOfPart
|
||||
@@ -842,7 +890,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Shit the bed.");
|
||||
console.error("Shit the bed.");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -976,13 +1024,13 @@ function DiscountNotAlreadyCounted(jobline, joblines) {
|
||||
}
|
||||
|
||||
//Check it against the database price too? If it's an OE part.
|
||||
if (
|
||||
Math.abs(jobline.db_price - jobline.act_price) -
|
||||
Math.abs(jobline.prt_dsmk_m) <
|
||||
0.01
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
// if (
|
||||
// Math.abs(jobline.db_price - jobline.act_price) -
|
||||
// Math.abs(jobline.prt_dsmk_m) <
|
||||
// 0.01
|
||||
// ) {
|
||||
// return false;
|
||||
// }
|
||||
|
||||
if (
|
||||
//If it's not a discount line, then it definitely hasn't been counted yet.
|
||||
@@ -1006,3 +1054,31 @@ function ParseCalopCode(opcode) {
|
||||
function IsTrueOrYes(value) {
|
||||
return value === true || value === "Y" || value === "y";
|
||||
}
|
||||
|
||||
async function UpdateJobLines(joblinesToUpdate) {
|
||||
if (joblinesToUpdate.length === 0) return;
|
||||
const updateQueries = joblinesToUpdate.map((line, index) =>
|
||||
generateUpdateQuery(_.pick(line, ["id", "prt_dsmk_m", "prt_dsmk_p"]), index)
|
||||
);
|
||||
const query = `
|
||||
mutation UPDATE_EST_LINES{
|
||||
${updateQueries}
|
||||
}
|
||||
`;
|
||||
|
||||
const result = await adminClient.request(query);
|
||||
}
|
||||
|
||||
const generateUpdateQuery = (lineToUpdate, index) => {
|
||||
return `
|
||||
update_joblines${index}: update_joblines(where: { id: { _eq: "${
|
||||
lineToUpdate.id
|
||||
}" } }, _set: ${JSON.stringify(lineToUpdate).replace(
|
||||
/"(\w+)"\s*:/g,
|
||||
"$1:"
|
||||
)}) {
|
||||
returning {
|
||||
id
|
||||
}
|
||||
}`;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user