export function CalculateJob(job, shoprates) { let ret = { parts: CalculatePartsTotals(job.joblines), rates: CalculateRatesTotals(job, shoprates), custPayable: CalculateCustPayable(job) }; ret.totals = CalculateTaxesTotals(job, ret); return ret; } function CalculateTaxesTotals(job, otherTotals) { const subtotal = otherTotals.parts.parts.subtotal + otherTotals.parts.sublets.subtotal + otherTotals.rates.subtotal; let ret = { subtotal: subtotal, federal_tax: subtotal * job.federal_tax_rate || 0, state_tax: subtotal * job.state_tax_rate || 0, local_tax: subtotal * job.local_tax_rate || 0 }; ret.total_repairs = ret.subtotal + ret.federal_tax + ret.state_tax + ret.local_tax; ret.net_repairs = ret.total_repairs - otherTotals.custPayable.total; return ret; } function CalculateRatesTotals(ratesList, shoprates) { const jobLines = ratesList.joblines; let ret = { rate_la1: { hours: jobLines .filter(item => item.mod_lbr_ty === "LA1") .reduce((acc, value) => acc + value.mod_lb_hrs, 0), rate: ratesList.rate_la1 }, rate_la2: { hours: jobLines .filter(item => item.mod_lbr_ty === "LA2") .reduce((acc, value) => acc + value.mod_lb_hrs, 0), rate: ratesList.rate_la2 }, rate_la3: { rate: ratesList.rate_la3, hours: jobLines .filter(item => item.mod_lbr_ty === "LA3") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_la4: { rate: ratesList.rate_la4, hours: jobLines .filter(item => item.mod_lbr_ty === "LA4") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_laa: { rate: ratesList.rate_laa, hours: jobLines .filter(item => item.mod_lbr_ty === "LAA") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_lab: { rate: ratesList.rate_lab, hours: jobLines .filter(item => item.mod_lbr_ty === "LAB") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_lad: { rate: ratesList.rate_lad, hours: jobLines .filter(item => item.mod_lbr_ty === "LAD") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_lae: { rate: ratesList.rate_lae, hours: jobLines .filter(item => item.mod_lbr_ty === "LAE") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_laf: { rate: ratesList.rate_laf, hours: jobLines .filter(item => item.mod_lbr_ty === "LAF") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_lag: { rate: ratesList.rate_lag, hours: jobLines .filter(item => item.mod_lbr_ty === "LAG") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_lam: { rate: ratesList.rate_lam, hours: jobLines .filter(item => item.mod_lbr_ty === "LAM") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_lar: { rate: ratesList.rate_lar, hours: jobLines .filter(item => item.mod_lbr_ty === "LAR") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_las: { rate: ratesList.rate_las, hours: jobLines .filter(item => item.mod_lbr_ty === "LAS") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_lau: { rate: ratesList.rate_lau, hours: jobLines .filter(item => item.mod_lbr_ty === "LAU") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, rate_atp: { rate: shoprates.rate_atp || 0, hours: jobLines .filter( item => item.mod_lbr_ty !== "LA1" && item.mod_lbr_ty !== "LA2" && item.mod_lbr_ty !== "LA3" && item.mod_lbr_ty !== "LA4" && item.mod_lbr_ty !== "LAU" && item.mod_lbr_ty !== "LAG" && item.mod_lbr_ty !== "LAS" && item.mod_lbr_ty !== "LAA" ) .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, paint_mat: { rate: ratesList.rate_mapa, hours: jobLines .filter(item => item.mod_lbr_ty === "LAR") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) }, shop_mat: { rate: ratesList.rate_mash, hours: jobLines .filter(item => item.mod_lbr_ty !== "LAR") .reduce((acc, value) => acc + value.mod_lb_hrs, 0) } }; let subtotal = 0; for (const property in ret) { ret[property].total = ret[property].hours * ret[property].rate; subtotal = subtotal + ret[property].hours * ret[property].rate; } ret.subtotal = subtotal; return ret; } function CalculatePartsTotals(jobLines) { const ret = jobLines.reduce( (acc, value) => { switch (value.part_type) { case "PAA": case "PAC": case "PAG": case "PAL": case "PAM": case "PAN": case "PAO": case "PAP": case "PAR": return { ...acc, parts: { ...acc.parts, subtotal: acc.parts.subtotal + value.act_price //TODO Add Adjustments in } }; case "PAS": case "PASL": return { ...acc, sublets: { ...acc.sublets, subtotal: acc.sublets.subtotal + value.act_price //TODO Add Adjustments in } }; default: return acc; } }, { parts: { subtotal: 0, adjustments: 0, total: 0 }, sublets: { subtotal: 0, adjustments: 0, total: 0 } } ); return { parts: { ...ret.parts, total: ret.parts.subtotal + ret.parts.adjustments }, sublets: { ...ret.sublets, total: ret.sublets.subtotal + ret.sublets.adjustments } }; } function CalculateCustPayable(job) { return { deductible: job.ded_amt || 0, federal_tax: job.federal_tax_payable || 0, other_customer_amount: job.other_amount_payable || 0, dep_taxes: job.depreciation_taxes || 0, total: job.ded_amt || 0 + job.federal_tax_payable || 0 + job.other_amount_payable || 0 + job.depreciation_taxes || 0 }; }