diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 53e83750f..525f35692 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -10237,6 +10237,27 @@ + + recalculate + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + reconcile false diff --git a/client/package.json b/client/package.json index c1a92049e..c92eae16e 100644 --- a/client/package.json +++ b/client/package.json @@ -7,20 +7,20 @@ "@lourenci/react-kanban": "^2.0.0", "@stripe/react-stripe-js": "^1.1.2", "@stripe/stripe-js": "^1.9.0", - "@tanem/react-nprogress": "^3.0.39", + "@tanem/react-nprogress": "^3.0.40", "@tinymce/tinymce-react": "^3.6.0", - "antd": "^4.5.4", + "antd": "^4.6.1", "apollo-boost": "^0.4.9", "apollo-link-context": "^1.0.20", "apollo-link-error": "^1.1.13", "apollo-link-logger": "^1.2.3", "apollo-link-retry": "^2.2.16", "apollo-link-ws": "^1.0.20", - "axios": "^0.19.2", + "axios": "^0.20.0", "dinero.js": "^1.8.1", "dotenv": "^8.2.0", "fingerprintjs2": "^2.1.2", - "firebase": "^7.18.0", + "firebase": "^7.19.0", "graphql": "^15.3.0", "i18next": "^19.7.0", "i18next-browser-languagedetector": "^6.0.1", @@ -34,16 +34,16 @@ "react": "^16.13.1", "react-apollo": "^3.1.5", "react-barcode": "^1.4.0", - "react-big-calendar": "^0.26.0", + "react-big-calendar": "^0.26.1", "react-dom": "^16.13.1", "react-drag-listview": "^0.1.7", "react-email-editor": "^1.1.1", "react-ga": "^3.1.2", "react-grid-gallery": "^0.5.5", "react-grid-layout": "^1.0.0", - "react-i18next": "^11.7.0", + "react-i18next": "^11.7.1", "react-icons": "^3.11.0", - "react-image-file-resizer": "^0.3.1", + "react-image-file-resizer": "^0.3.6", "react-moment": "^0.9.7", "react-number-format": "^4.4.1", "react-redux": "^7.2.1", @@ -64,7 +64,7 @@ "scripts": { "analyze": "source-map-explorer 'build/static/js/*.js'", "start": "react-scripts start", - "build": "react-scripts build", + "build": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, @@ -88,6 +88,6 @@ "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.3", "redux-logger": "^3.0.6", - "source-map-explorer": "^2.4.2" + "source-map-explorer": "^2.5.0" } } diff --git a/client/src/components/job-calculate-totals/job-calculate-totals.component.jsx b/client/src/components/job-calculate-totals/job-calculate-totals.component.jsx new file mode 100644 index 000000000..f742d71dc --- /dev/null +++ b/client/src/components/job-calculate-totals/job-calculate-totals.component.jsx @@ -0,0 +1,59 @@ +import { Button, notification } from "antd"; +import Axios from "axios"; +import React, { useState } from "react"; +import { useMutation } from "react-apollo"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { UPDATE_JOB } from "../../graphql/jobs.queries"; +import { selectBodyshop } from "../../redux/user/user.selectors"; + +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, +}); + +export function JobCalculateTotals({ bodyshop, job }) { + const { t } = useTranslation(); + const [loading, setLoading] = useState(false); + const [updateJob] = useMutation(UPDATE_JOB); + + const handleCalculate = async () => { + setLoading(true); + const newTotals = ( + await Axios.post("/job/totals", { + job: job, + shoprates: bodyshop.shoprates, + }) + ).data; + + const result = await updateJob({ + refetchQueries: ["GET_JOB_BY_PK"], + awaitRefetchQueries: true, + variables: { + jobId: job.id, + job: { + job_totals: newTotals, + }, + }, + }); + if (!!!result.errors) { + notification["success"]({ message: t("jobs.successes.updated") }); + } else { + notification["error"]({ + message: t("jobs.errors.updating", { + error: JSON.stringify(result.errors), + }), + }); + } + setLoading(false); + }; + + return ( +
+ +
+ ); +} +export default connect(mapStateToProps, null)(JobCalculateTotals); diff --git a/client/src/components/job-totals-table/job-totals-table.component.jsx b/client/src/components/job-totals-table/job-totals-table.component.jsx index 016cf6c01..def44dea3 100644 --- a/client/src/components/job-totals-table/job-totals-table.component.jsx +++ b/client/src/components/job-totals-table/job-totals-table.component.jsx @@ -1,12 +1,12 @@ -import { Statistic, Typography, Row, Col } from "antd"; -import React, { useEffect, useState } from "react"; +import { Col, Result, Row, Statistic, Typography } from "antd"; +import Dinero from "dinero.js"; +import React from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; -import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component"; +import JobCalculateTotals from "../job-calculate-totals/job-calculate-totals.component"; import "./job-totals-table.styles.scss"; -import { CalculateJob } from "./job-totals.utility"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser @@ -20,28 +20,16 @@ const colSpan = { export function JobsTotalsTableComponent({ bodyshop, job }) { const { t } = useTranslation(); - const [totals, setTotals] = useState(null); - useEffect(() => { - setTotals(CalculateJob(job, bodyshop.shoprates)); - }, [bodyshop, job]); + console.log("job", job); - // useEffect(() => { - // const Calculate = async () => { - // const newTotals = ( - // await Axios.post("/job/totals", { - // job: job, - // shoprates: bodyshop.shoprates, - // }) - // ).data; - // setTotals(newTotals); - // }; - - // Calculate(); - // }, [bodyshop, job]); - - if (!!!totals) { - return ; + if (!!!job.job_totals) { + return ( + } + /> + ); } return ( @@ -57,142 +45,142 @@ export function JobsTotalsTableComponent({ bodyshop, job }) { {t("jobs.fields.rate_laa")} - {totals.rates.laa.total.toFormat()} + {Dinero(job.job_totals.rates.laa.total).toFormat()} - {`(${totals.rates.laa.hours.toFixed(2)} @ ${ - totals.rates.laa.rate + {`(${job.job_totals.rates.laa.hours.toFixed(2)} @ ${ + job.job_totals.rates.laa.rate })`} {t("jobs.fields.rate_lab")} - {totals.rates.lab.total.toFormat()} + {Dinero(job.job_totals.rates.lab.total).toFormat()} - {`(${totals.rates.lab.hours.toFixed(2)} @ ${ - totals.rates.lab.rate + {`(${job.job_totals.rates.lab.hours.toFixed(2)} @ ${ + job.job_totals.rates.lab.rate })`} {t("jobs.fields.rate_lad")} - {totals.rates.lad.total.toFormat()} + {Dinero(job.job_totals.rates.lad.total).toFormat()} - {`(${totals.rates.lad.hours.toFixed(2)} @ ${ - totals.rates.lad.rate + {`(${job.job_totals.rates.lad.hours.toFixed(2)} @ ${ + job.job_totals.rates.lad.rate })`} {t("jobs.fields.rate_lae")} - {totals.rates.lae.total.toFormat()} + {Dinero(job.job_totals.rates.lae.total).toFormat()} - {`(${totals.rates.lae.hours.toFixed(2)} @ ${ - totals.rates.lae.rate + {`(${job.job_totals.rates.lae.hours.toFixed(2)} @ ${ + job.job_totals.rates.lae.rate })`} {t("jobs.fields.rate_laf")} - {totals.rates.laf.total.toFormat()} + {Dinero(job.job_totals.rates.laf.total).toFormat()} - {`(${totals.rates.laf.hours.toFixed(2)} @ ${ - totals.rates.laf.rate + {`(${job.job_totals.rates.laf.hours.toFixed(2)} @ ${ + job.job_totals.rates.laf.rate })`} {t("jobs.fields.rate_lag")} - {totals.rates.lag.total.toFormat()} + {Dinero(job.job_totals.rates.lag.total).toFormat()} - {`(${totals.rates.lag.hours.toFixed(2)} @ ${ - totals.rates.lag.rate + {`(${job.job_totals.rates.lag.hours.toFixed(2)} @ ${ + job.job_totals.rates.lag.rate })`} {t("jobs.fields.rate_lam")} - {totals.rates.lam.total.toFormat()} + {Dinero(job.job_totals.rates.lam.total).toFormat()} - {`(${totals.rates.lam.hours.toFixed(2)} @ ${ - totals.rates.lam.rate + {`(${job.job_totals.rates.lam.hours.toFixed(2)} @ ${ + job.job_totals.rates.lam.rate })`} {t("jobs.fields.rate_lar")} - {totals.rates.lar.total.toFormat()} + {Dinero(job.job_totals.rates.lar.total).toFormat()} - {`(${totals.rates.lar.hours.toFixed(2)} @ ${ - totals.rates.lar.rate + {`(${job.job_totals.rates.lar.hours.toFixed(2)} @ ${ + job.job_totals.rates.lar.rate })`} {t("jobs.fields.rate_las")} - {totals.rates.las.total.toFormat()} + {Dinero(job.job_totals.rates.las.total).toFormat()} - {`(${totals.rates.las.hours.toFixed(2)} @ ${ - totals.rates.las.rate + {`(${job.job_totals.rates.las.hours.toFixed(2)} @ ${ + job.job_totals.rates.las.rate })`} {t("jobs.fields.rate_lau")} - {totals.rates.lau.total.toFormat()} + {Dinero(job.job_totals.rates.lau.total).toFormat()} - {`(${totals.rates.lau.hours.toFixed(2)} @ ${ - totals.rates.lau.rate + {`(${job.job_totals.rates.lau.hours.toFixed(2)} @ ${ + job.job_totals.rates.lau.rate })`} {t("jobs.fields.rate_la1")} - {totals.rates.la1.total.toFormat()} + {Dinero(job.job_totals.rates.la1.total).toFormat()} - {`(${totals.rates.la1.hours.toFixed(2)} @ ${ - totals.rates.la1.rate + {`(${job.job_totals.rates.la1.hours.toFixed(2)} @ ${ + job.job_totals.rates.la1.rate })`} {t("jobs.fields.rate_la2")} - {totals.rates.la2.total.toFormat()} + {Dinero(job.job_totals.rates.la2.total).toFormat()} - {`(${totals.rates.la2.hours.toFixed(2)} @ ${ - totals.rates.la2.rate + {`(${job.job_totals.rates.la2.hours.toFixed(2)} @ ${ + job.job_totals.rates.la2.rate })`} {t("jobs.fields.rate_la3")} - {totals.rates.la3.total.toFormat()} + {Dinero(job.job_totals.rates.la3.total).toFormat()} - {`(${totals.rates.la3.hours.toFixed(2)} @ ${ - totals.rates.la3.rate + {`(${job.job_totals.rates.la3.hours.toFixed(2)} @ ${ + job.job_totals.rates.la3.rate })`} {t("jobs.fields.rate_la4")} - {totals.rates.la4.total.toFormat()} + {Dinero(job.job_totals.rates.la4.total).toFormat()} - {`(${totals.rates.la4.hours.toFixed(2)} @ ${ - totals.rates.la4.rate + {`(${job.job_totals.rates.la4.hours.toFixed(2)} @ ${ + job.job_totals.rates.la4.rate })`} {t("jobs.fields.rate_atp")} - {totals.rates.atp.total.toFormat()} + {Dinero(job.job_totals.rates.atp.total).toFormat()} - {`(${totals.rates.atp.hours.toFixed(2)} @ ${ - totals.rates.atp.rate + {`(${job.job_totals.rates.atp.hours.toFixed(2)} @ ${ + job.job_totals.rates.atp.rate })`} {t("jobs.labels.rates_subtotal")} - {totals.rates.subtotal.toFormat()} + {Dinero(job.job_totals.rates.subtotal).toFormat()} @@ -203,45 +191,57 @@ export function JobsTotalsTableComponent({ bodyshop, job }) {
- {Object.keys(totals.parts.parts.list).map((key, idx) => ( - - - - - - ))} + {Object.keys(job.job_totals.parts.parts.list).map( + (key, idx) => ( + + + + + + ) + )} - + - + - - @@ -260,15 +260,15 @@ export function JobsTotalsTableComponent({ bodyshop, job }) { >
+ diff --git a/client/src/components/job-totals-table/job-totals.utility.js b/client/src/components/job-totals-table/job-totals.utility.js index 5688e92fa..8d7ab40f6 100644 --- a/client/src/components/job-totals-table/job-totals.utility.js +++ b/client/src/components/job-totals-table/job-totals.utility.js @@ -1,322 +1,322 @@ -import Dinero from "dinero.js"; -import { logImEXEvent } from "../../firebase/firebase.utils"; +// import Dinero from "dinero.js"; +// import { logImEXEvent } from "../../firebase/firebase.utils"; -export function CalculateJob(job, shoprates) { - logImEXEvent("job_calculate_total"); +// export function CalculateJob(job, shoprates) { +// logImEXEvent("job_calculate_total"); - let ret = { - parts: CalculatePartsTotals(job.joblines), - rates: CalculateRatesTotals(job, shoprates), - custPayable: CalculateCustPayable(job), - }; - ret.totals = CalculateTaxesTotals(job, ret); - console.log("CalculateJob -> Final", ret); - return ret; -} +// let ret = { +// parts: CalculatePartsTotals(job.joblines), +// rates: CalculateRatesTotals(job, shoprates), +// custPayable: CalculateCustPayable(job), +// }; +// ret.totals = CalculateTaxesTotals(job, ret); +// console.log("CalculateJob -> Final", ret); +// return ret; +// } -function CalculateTaxesTotals(job, otherTotals) { - const subtotal = otherTotals.parts.parts.subtotal - .add(otherTotals.parts.sublets.subtotal) - .add(otherTotals.rates.subtotal) - .add(Dinero({ amount: (job.towing_payable || 0) * 100 })) - .add(Dinero({ amount: (job.storage_payable || 0) * 100 })); - //TODO Levies should be included?? +// function CalculateTaxesTotals(job, otherTotals) { +// const subtotal = otherTotals.parts.parts.subtotal +// .add(otherTotals.parts.sublets.subtotal) +// .add(otherTotals.rates.subtotal) +// .add(Dinero({ amount: (job.towing_payable || 0) * 100 })) +// .add(Dinero({ amount: (job.storage_payable || 0) * 100 })); +// //TODO Levies should be included?? - const statePartsTax = job.joblines.reduce((acc, val) => { - if (!!!val.tax_part) return acc; - if (!!job.parts_tax_rates[val.part_type]) { - return acc.add( - Dinero({ amount: Math.round(val.act_price * 100) }) - .multiply(val.part_qty) - .percentage( - (job.parts_tax_rates[val.part_type].prt_tax_rt || 0) * 100 - ) - ); - } else { - return acc; - } - }, Dinero({ amount: 0 })); - let ret = { - subtotal: subtotal, - federal_tax: subtotal.percentage((job.federal_tax_rate || 0) * 100), - statePartsTax, - state_tax: statePartsTax - .add( - otherTotals.rates.rates_subtotal.percentage((job.tax_lbr_rt || 0) * 100) - ) - .add( - Dinero({ - amount: Math.round((job.towing_payable || 0) * 100), - }).percentage((job.tax_tow_rt || 0) * 100) - ) - .add( - Dinero({ - amount: Math.round((job.storage_payable || 0) * 100), - }).percentage((job.tax_str_rt || 0) * 100) - ) - .add( - otherTotals.rates.mapa.total - .add(otherTotals.rates.mash.total) - .percentage((job.tax_paint_mat_rt || 0) * 100) - ), - local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100), - }; - ret.total_repairs = ret.subtotal - .add(ret.federal_tax) - .add(ret.state_tax) - .add(ret.local_tax); - ret.net_repairs = ret.total_repairs.subtract(otherTotals.custPayable.total); +// const statePartsTax = job.joblines.reduce((acc, val) => { +// if (!!!val.tax_part) return acc; +// if (!!job.parts_tax_rates[val.part_type]) { +// return acc.add( +// Dinero({ amount: Math.round(val.act_price * 100) }) +// .multiply(val.part_qty) +// .percentage( +// (job.parts_tax_rates[val.part_type].prt_tax_rt || 0) * 100 +// ) +// ); +// } else { +// return acc; +// } +// }, Dinero({ amount: 0 })); +// let ret = { +// subtotal: subtotal, +// federal_tax: subtotal.percentage((job.federal_tax_rate || 0) * 100), +// statePartsTax, +// state_tax: statePartsTax +// .add( +// otherTotals.rates.rates_subtotal.percentage((job.tax_lbr_rt || 0) * 100) +// ) +// .add( +// Dinero({ +// amount: Math.round((job.towing_payable || 0) * 100), +// }).percentage((job.tax_tow_rt || 0) * 100) +// ) +// .add( +// Dinero({ +// amount: Math.round((job.storage_payable || 0) * 100), +// }).percentage((job.tax_str_rt || 0) * 100) +// ) +// .add( +// otherTotals.rates.mapa.total +// .add(otherTotals.rates.mash.total) +// .percentage((job.tax_paint_mat_rt || 0) * 100) +// ), +// local_tax: subtotal.percentage((job.local_tax_rate || 0) * 100), +// }; +// ret.total_repairs = ret.subtotal +// .add(ret.federal_tax) +// .add(ret.state_tax) +// .add(ret.local_tax); +// ret.net_repairs = ret.total_repairs.subtract(otherTotals.custPayable.total); - return ret; -} +// return ret; +// } -//Rates are multipled by 10 to reduce the errors of rounding. -//Adjusted for when adding to total by dividing by 10. -function CalculateRatesTotals(ratesList, shoprates) { - const jobLines = ratesList.joblines; +// //Rates are multipled by 10 to reduce the errors of rounding. +// //Adjusted for when adding to total by dividing by 10. +// function CalculateRatesTotals(ratesList, shoprates) { +// const jobLines = ratesList.joblines; - let ret = { - la1: { - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LA1") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - rate: ratesList.rate_la1 || 0, - }, - la2: { - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LA2") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - rate: ratesList.rate_la2 || 0, - }, - la3: { - rate: ratesList.rate_la3 || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LA3") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - la4: { - rate: ratesList.rate_la4 || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LA4") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - laa: { - rate: ratesList.rate_laa || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAA") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - lab: { - rate: ratesList.rate_lab || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAB") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - lad: { - rate: ratesList.rate_lad || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAD") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - lae: { - rate: ratesList.rate_lae || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAE") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - laf: { - rate: ratesList.rate_laf || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAF") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - lag: { - rate: ratesList.rate_lag || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAG") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - lam: { - rate: ratesList.rate_lam || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAM") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - lar: { - rate: ratesList.rate_lar || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAR") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - las: { - rate: ratesList.rate_las || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAS") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - lau: { - rate: ratesList.rate_lau || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAU") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - atp: { - rate: shoprates.rate_atp || 0, - hours: - jobLines.filter((item) => item.line_desc.includes("ATS Amount")) - .length > 0 - ? 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 * 10, 0) - : 0, - }, - mapa: { - rate: ratesList.rate_mapa || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty === "LAR") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - mash: { - rate: ratesList.rate_mash || 0, - hours: jobLines - .filter((item) => item.mod_lbr_ty !== "LAR") - .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), - }, - }; +// let ret = { +// la1: { +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LA1") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// rate: ratesList.rate_la1 || 0, +// }, +// la2: { +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LA2") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// rate: ratesList.rate_la2 || 0, +// }, +// la3: { +// rate: ratesList.rate_la3 || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LA3") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// la4: { +// rate: ratesList.rate_la4 || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LA4") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// laa: { +// rate: ratesList.rate_laa || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAA") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// lab: { +// rate: ratesList.rate_lab || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAB") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// lad: { +// rate: ratesList.rate_lad || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAD") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// lae: { +// rate: ratesList.rate_lae || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAE") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// laf: { +// rate: ratesList.rate_laf || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAF") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// lag: { +// rate: ratesList.rate_lag || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAG") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// lam: { +// rate: ratesList.rate_lam || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAM") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// lar: { +// rate: ratesList.rate_lar || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAR") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// las: { +// rate: ratesList.rate_las || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAS") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// lau: { +// rate: ratesList.rate_lau || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAU") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// atp: { +// rate: shoprates.rate_atp || 0, +// hours: +// jobLines.filter((item) => item.line_desc.includes("ATS Amount")) +// .length > 0 +// ? 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 * 10, 0) +// : 0, +// }, +// mapa: { +// rate: ratesList.rate_mapa || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty === "LAR") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// mash: { +// rate: ratesList.rate_mash || 0, +// hours: jobLines +// .filter((item) => item.mod_lbr_ty !== "LAR") +// .reduce((acc, value) => acc + value.mod_lb_hrs * 10, 0), +// }, +// }; - let subtotal = Dinero({ amount: 0 }); - let rates_subtotal = Dinero({ amount: 0 }); - for (const property in ret) { - ret[property].total = Dinero({ amount: ret[property].rate * 100 }) - .multiply(ret[property].hours) - .divide(10); - subtotal = subtotal.add(ret[property].total); - if ( - property !== "mapa" && - property !== "mash" - //&& property !== "rate_atp" - ) - rates_subtotal = rates_subtotal.add(ret[property].total); - } - ret.subtotal = subtotal; - ret.rates_subtotal = rates_subtotal; +// let subtotal = Dinero({ amount: 0 }); +// let rates_subtotal = Dinero({ amount: 0 }); +// for (const property in ret) { +// ret[property].total = Dinero({ amount: ret[property].rate * 100 }) +// .multiply(ret[property].hours) +// .divide(10); +// subtotal = subtotal.add(ret[property].total); +// if ( +// property !== "mapa" && +// property !== "mash" +// //&& property !== "rate_atp" +// ) +// rates_subtotal = rates_subtotal.add(ret[property].total); +// } +// ret.subtotal = subtotal; +// ret.rates_subtotal = rates_subtotal; - return ret; -} +// return ret; +// } -function CalculatePartsTotals(jobLines) { - const ret = jobLines.reduce( - (acc, value) => { - switch (value.part_type) { - case "PAS": - case "PASL": - return { - ...acc, - sublets: { - ...acc.sublets, - subtotal: acc.sublets.subtotal.add( - Dinero({ amount: Math.round(value.act_price * 100) }) - ), - //TODO Add Adjustments in - }, - }; - // case "PAA": - // case "PAC": - // case "PAG": - // case "PAL": - // case "PAM": - // case "PAN": - // case "PAO": - // case "PAP": - // case "PAR": - default: - if (value.part_type === null) return acc; - return { - ...acc, - parts: { - ...acc.parts, - list: { - ...acc.parts.list, - [value.part_type]: - acc.parts.list[value.part_type] && - acc.parts.list[value.part_type].total - ? { - total: acc.parts.list[value.part_type].total.add( - Dinero({ - amount: Math.round((value.act_price || 0) * 100), - }).multiply(value.part_qty || 1) - ), - } - : { - total: Dinero({ - amount: Math.round((value.act_price || 0) * 100), - }).multiply(value.part_qty || 1), - }, - }, - subtotal: acc.parts.subtotal.add( - Dinero({ amount: Math.round(value.act_price * 100) }).multiply( - value.part_qty - ) - ), - //TODO Add Adjustments in - }, - }; - // default: - // return acc; - } - }, - { - parts: { - list: {}, - subtotal: Dinero({ amount: 0 }), - adjustments: Dinero({ amount: 0 }), - total: Dinero({ amount: 0 }), - }, - sublets: { - subtotal: Dinero({ amount: 0 }), - adjustments: Dinero({ amount: 0 }), - total: Dinero({ amount: 0 }), - }, - } - ); +// function CalculatePartsTotals(jobLines) { +// const ret = jobLines.reduce( +// (acc, value) => { +// switch (value.part_type) { +// case "PAS": +// case "PASL": +// return { +// ...acc, +// sublets: { +// ...acc.sublets, +// subtotal: acc.sublets.subtotal.add( +// Dinero({ amount: Math.round(value.act_price * 100) }) +// ), +// //TODO Add Adjustments in +// }, +// }; +// // case "PAA": +// // case "PAC": +// // case "PAG": +// // case "PAL": +// // case "PAM": +// // case "PAN": +// // case "PAO": +// // case "PAP": +// // case "PAR": +// default: +// if (value.part_type === null) return acc; +// return { +// ...acc, +// parts: { +// ...acc.parts, +// list: { +// ...acc.parts.list, +// [value.part_type]: +// acc.parts.list[value.part_type] && +// acc.parts.list[value.part_type].total +// ? { +// total: acc.parts.list[value.part_type].total.add( +// Dinero({ +// amount: Math.round((value.act_price || 0) * 100), +// }).multiply(value.part_qty || 1) +// ), +// } +// : { +// total: Dinero({ +// amount: Math.round((value.act_price || 0) * 100), +// }).multiply(value.part_qty || 1), +// }, +// }, +// subtotal: acc.parts.subtotal.add( +// Dinero({ amount: Math.round(value.act_price * 100) }).multiply( +// value.part_qty +// ) +// ), +// //TODO Add Adjustments in +// }, +// }; +// // default: +// // return acc; +// } +// }, +// { +// parts: { +// list: {}, +// subtotal: Dinero({ amount: 0 }), +// adjustments: Dinero({ amount: 0 }), +// total: Dinero({ amount: 0 }), +// }, +// sublets: { +// subtotal: Dinero({ amount: 0 }), +// adjustments: Dinero({ amount: 0 }), +// total: Dinero({ amount: 0 }), +// }, +// } +// ); - return { - parts: { - ...ret.parts, - total: ret.parts.subtotal, //+ ret.parts.adjustments - }, - sublets: { - ...ret.sublets, - total: ret.sublets.subtotal, // + ret.sublets.adjustments, - }, - }; -} +// return { +// parts: { +// ...ret.parts, +// total: ret.parts.subtotal, //+ ret.parts.adjustments +// }, +// sublets: { +// ...ret.sublets, +// total: ret.sublets.subtotal, // + ret.sublets.adjustments, +// }, +// }; +// } -function CalculateCustPayable(job) { - let ret = { - deductible: Dinero({ amount: (job.ded_amt || 0) * 100 }) || 0, - federal_tax: Dinero({ amount: (job.federal_tax_payable || 0) * 100 }), //TODO Should this be renamed to make it more clear this is customer GST? - other_customer_amount: Dinero({ - amount: (job.other_amount_payable || 0) * 100, - }), - dep_taxes: Dinero({ amount: job.depreciation_taxes || 0 }), - }; +// function CalculateCustPayable(job) { +// let ret = { +// deductible: Dinero({ amount: (job.ded_amt || 0) * 100 }) || 0, +// federal_tax: Dinero({ amount: (job.federal_tax_payable || 0) * 100 }), //TODO Should this be renamed to make it more clear this is customer GST? +// other_customer_amount: Dinero({ +// amount: (job.other_amount_payable || 0) * 100, +// }), +// dep_taxes: Dinero({ amount: job.depreciation_taxes || 0 }), +// }; - ret.total = ret.deductible - .add(ret.federal_tax) - .add(ret.federal_tax) - .add(ret.other_customer_amount) - .add(ret.dep_taxes); +// ret.total = ret.deductible +// .add(ret.federal_tax) +// .add(ret.federal_tax) +// .add(ret.other_customer_amount) +// .add(ret.dep_taxes); - return ret; -} +// return ret; +// } diff --git a/client/src/components/jobs-available-new/jobs-available-new.container.jsx b/client/src/components/jobs-available-new/jobs-available-new.container.jsx index 8cb8ae400..b1e1b7bc7 100644 --- a/client/src/components/jobs-available-new/jobs-available-new.container.jsx +++ b/client/src/components/jobs-available-new/jobs-available-new.container.jsx @@ -1,11 +1,13 @@ import { useMutation, useQuery } from "@apollo/react-hooks"; import { notification } from "antd"; +import Axios from "axios"; +import Dinero from "dinero.js"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { useHistory } from "react-router-dom"; import { createStructuredSelector } from "reselect"; -import { CalculateJob } from "../../components/job-totals-table/job-totals.utility"; +import { logImEXEvent } from "../../firebase/firebase.utils"; import { DELETE_ALL_AVAILABLE_NEW_JOBS, QUERY_AVAILABLE_NEW_JOBS, @@ -15,7 +17,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors"; import AlertComponent from "../alert/alert.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import JobsAvailableComponent from "./jobs-available-new.component"; -import { logImEXEvent } from "../../firebase/firebase.utils"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -40,7 +41,7 @@ export function JobsAvailableContainer({ const [insertNewJob] = useMutation(INSERT_NEW_JOB); const [loadEstData, estData] = estDataLazyLoad; - const onModalOk = () => { + const onModalOk = async () => { logImEXEvent("job_import_new"); setModalVisible(false); @@ -59,19 +60,21 @@ export function JobsAvailableContainer({ message: t("jobs.errors.creating", { error: "No job data present." }), }); } else { - const newTotals = CalculateJob( - { - ...estData.data.available_jobs_by_pk.est_data, - joblines: estData.data.available_jobs_by_pk.est_data.joblines.data, - }, - bodyshop.shoprates - ); + const newTotals = ( + await Axios.post("/job/totals", { + job: { + ...estData.data.available_jobs_by_pk.est_data, + joblines: estData.data.available_jobs_by_pk.est_data.joblines.data, + }, + shoprates: bodyshop.shoprates, + }) + ).data; const newJob = { ...estData.data.available_jobs_by_pk.est_data, - clm_total: newTotals.totals.total_repairs.toFormat("0.00"), - owner_owing: newTotals.custPayable.total.toFormat("0.00"), - job_totals: JSON.stringify(newTotals), + clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"), + owner_owing: Dinero(newTotals.custPayable.total).toFormat("0.00"), + job_totals: newTotals, }; insertNewJob({ diff --git a/client/src/components/jobs-available-supplement/jobs-available-supplement.container.jsx b/client/src/components/jobs-available-supplement/jobs-available-supplement.container.jsx index f2cbadd80..2b2ce5eeb 100644 --- a/client/src/components/jobs-available-supplement/jobs-available-supplement.container.jsx +++ b/client/src/components/jobs-available-supplement/jobs-available-supplement.container.jsx @@ -1,12 +1,14 @@ import { useApolloClient, useMutation, useQuery } from "@apollo/react-hooks"; import { notification } from "antd"; +import Axios from "axios"; +import Dinero from "dinero.js"; import gql from "graphql-tag"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; import { useHistory } from "react-router-dom"; import { createStructuredSelector } from "reselect"; -import { CalculateJob } from "../../components/job-totals-table/job-totals.utility"; +import { logImEXEvent } from "../../firebase/firebase.utils"; import { DELETE_ALL_AVAILABLE_SUPPLEMENT_JOBS, QUERY_AVAILABLE_SUPPLEMENT_JOBS, @@ -18,7 +20,6 @@ import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import JobsAvailableSupplementComponent from "./jobs-available-supplement.component"; import { GetSupplementDelta } from "./jobs-available-supplement.estlines.util"; import HeaderFields from "./jobs-available-supplement.headerfields"; -import { logImEXEvent } from "../../firebase/firebase.utils"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -74,13 +75,15 @@ export function JobsAvailableSupplementContainer({ HeaderFields.forEach((item) => delete supp[item]); } - const newTotals = CalculateJob( - { - ...estData.data.available_jobs_by_pk.est_data, - joblines: estData.data.available_jobs_by_pk.est_data.joblines.data, - }, - bodyshop.shoprates - ); + const newTotals = ( + await Axios.post("/job/totals", { + job: { + ...estData.data.available_jobs_by_pk.est_data, + joblines: estData.data.available_jobs_by_pk.est_data.joblines.data, + }, + shoprates: bodyshop.shoprates, + }) + ).data; let suppDelta = await GetSupplementDelta( client, @@ -99,9 +102,9 @@ export function JobsAvailableSupplementContainer({ jobId: selectedJob, job: { ...supp, - clm_total: newTotals.totals.total_repairs.toFormat("0.00"), - owner_owing: newTotals.custPayable.total.toFormat("0.00"), - job_totals: JSON.stringify(newTotals), + clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"), + owner_owing: Dinero(newTotals.custPayable.total).toFormat("0.00"), + job_totals: newTotals, }, }, }) diff --git a/client/src/components/jobs-close-save-button/jobs-close-save-button.component.jsx b/client/src/components/jobs-close-save-button/jobs-close-save-button.component.jsx index d4a6889f7..7ffaaf315 100644 --- a/client/src/components/jobs-close-save-button/jobs-close-save-button.component.jsx +++ b/client/src/components/jobs-close-save-button/jobs-close-save-button.component.jsx @@ -16,7 +16,7 @@ export function JobsCloseSaveButton({ bodyshop, suspenseAmount, jobId, - jobTotals, + labMatAllocations, partsAllocations, setInvoicedState, @@ -60,9 +60,10 @@ export function JobsCloseSaveButton({ return ( ); diff --git a/client/src/components/jobs-close-totals/jobs-close-totals.component.jsx b/client/src/components/jobs-close-totals/jobs-close-totals.component.jsx index 0c7f05f02..1fb739d58 100644 --- a/client/src/components/jobs-close-totals/jobs-close-totals.component.jsx +++ b/client/src/components/jobs-close-totals/jobs-close-totals.component.jsx @@ -1,6 +1,8 @@ import { Descriptions, Statistic } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; +import Dinero from "dinero.js"; + export default function JobsCloseTotals({ jobTotals, labMatTotal, @@ -17,47 +19,57 @@ export default function JobsCloseTotals({ > - + - + - + - + ; if (error) return ; - const jobTotals = CalculateJob(data.jobs_by_pk, bodyshop.shoprates); return (
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 57413dcc8..34808f65c 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -661,6 +661,7 @@ "mark": "Mark", "postInvoices": "Post Invoices", "printCenter": "Print Center", + "recalculate": "Recalculate", "reconcile": "Reconcile", "schedule": "Schedule", "sendcsi": "Send CSI" diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 06f68b8d2..7201b5da6 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -661,6 +661,7 @@ "mark": "", "postInvoices": "Contabilizar facturas", "printCenter": "Centro de impresión", + "recalculate": "", "reconcile": "", "schedule": "Programar", "sendcsi": "" diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 74d30c69d..0e66c4c2e 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -661,6 +661,7 @@ "mark": "", "postInvoices": "Poster des factures", "printCenter": "Centre d'impression", + "recalculate": "", "reconcile": "", "schedule": "Programme", "sendcsi": "" diff --git a/client/yarn.lock b/client/yarn.lock index 46a626095..8a040559e 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -9,6 +9,13 @@ dependencies: tinycolor2 "^1.4.1" +"@ant-design/colors@^4.0.5": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-4.0.5.tgz#d7d100d7545cca8f624954604a6892fc48ba5aae" + integrity sha512-3mnuX2prnWOWvpFTS2WH2LoouWlOgtnIpc6IarWN6GOzzLF8dW/U8UctuvIPhoboETehZfJ61XP+CGakBEPJ3Q== + dependencies: + tinycolor2 "^1.4.1" + "@ant-design/css-animation@^1.7.2": version "1.7.2" resolved "https://registry.yarnpkg.com/@ant-design/css-animation/-/css-animation-1.7.2.tgz#4ee5d2ec0fb7cc0a78b44e1c82628bd4621ac7e3" @@ -31,6 +38,18 @@ insert-css "^2.0.0" rc-util "^5.0.1" +"@ant-design/icons@^4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@ant-design/icons/-/icons-4.2.2.tgz#6533c5a02aec49238ec4748074845ad7d85a4f5e" + integrity sha512-DrVV+wcupnHS7PehJ6KiTcJtAR5c25UMgjGECCc6pUT9rsvw0AuYG+a4HDjfxEQuDqKTHwW+oX/nIvCymyLE8Q== + dependencies: + "@ant-design/colors" "^3.1.0" + "@ant-design/icons-svg" "^4.0.0" + "@babel/runtime" "^7.10.4" + classnames "^2.2.6" + insert-css "^2.0.0" + rc-util "^5.0.1" + "@ant-design/react-slick@~0.27.0": version "0.27.0" resolved "https://registry.yarnpkg.com/@ant-design/react-slick/-/react-slick-0.27.0.tgz#c5d4bfd879885b74024ffbce42cccb5f7bff41e9" @@ -1355,10 +1374,10 @@ resolved "https://registry.yarnpkg.com/@firebase/firestore-types/-/firestore-types-1.12.0.tgz#511e572e946b07f5a603c90e078f0cd714923fac" integrity sha512-OqNxVb63wPZdUc7YnpacAW1WNIMSKERSewCRi+unCQ0YI0KNfrDSypyGCyel+S3GdOtKMk9KnvDknaGbnaFX4g== -"@firebase/firestore@1.16.4": - version "1.16.4" - resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-1.16.4.tgz#29cb121f5686cab6e310bf16a1094f06f3678385" - integrity sha512-Ur+I8a8RkkbbJRsebkYAUwKFkbh9FemDxTFD/2Vp01pAPM8S3MoIcVegAfTvnPlG/ObBq5O7wI4CRA6b/G/Iyg== +"@firebase/firestore@1.16.5": + version "1.16.5" + resolved "https://registry.yarnpkg.com/@firebase/firestore/-/firestore-1.16.5.tgz#b80b63f18bd70cc101f66c5e0a79dce93f036384" + integrity sha512-GjCL4Ngy46qSdXAg9obXBuIKG2m/7a21dQktqRPaPH9xpHnymq8LxUK7sdUfyY8FBIQp6Si6O61e9fko4FjSMw== dependencies: "@firebase/component" "0.1.18" "@firebase/firestore-types" "1.12.0" @@ -1429,10 +1448,10 @@ resolved "https://registry.yarnpkg.com/@firebase/performance-types/-/performance-types-0.0.13.tgz#58ce5453f57e34b18186f74ef11550dfc558ede6" integrity sha512-6fZfIGjQpwo9S5OzMpPyqgYAUZcFzZxHFqOyNtorDIgNXq33nlldTL/vtaUZA8iT9TT5cJlCrF/jthKU7X21EA== -"@firebase/performance@0.3.11": - version "0.3.11" - resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.3.11.tgz#833c8abe5f5554f25545c8d28b487d8ac3ff3f95" - integrity sha512-L00vBUa2zzoSSOq3StTN43fPxtJ+myF+t+2kP5bQGHN5WOmf22lIsuEjAy1FAscDjVjhL1k5rKMY332ZwEfblg== +"@firebase/performance@0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@firebase/performance/-/performance-0.4.0.tgz#7f5bb47ef085cd83bf331b19d3213e11fbe88941" + integrity sha512-LZG89G2wAjTRsIcuewIx152+DyRzQf8UtPCAjifkFiMcAY4GmZZKeIbIC3b4oQDwTgH5i0IKKd4EOv7dLD97gw== dependencies: "@firebase/component" "0.1.18" "@firebase/installations" "0.4.16" @@ -1934,10 +1953,10 @@ "@svgr/plugin-svgo" "^4.3.1" loader-utils "^1.2.3" -"@tanem/react-nprogress@^3.0.39": - version "3.0.39" - resolved "https://registry.yarnpkg.com/@tanem/react-nprogress/-/react-nprogress-3.0.39.tgz#0ef9af7acb2cf6f701fd0436771c5aa2a0eec2a4" - integrity sha512-XCvqjlydWzjJ88QC5pKEcKKSMofTncULUBv0kEhjuyO4HVcJLKDzKg3DPhN+624M3eATkHK1YW9viqDkzU1ewA== +"@tanem/react-nprogress@^3.0.40": + version "3.0.40" + resolved "https://registry.yarnpkg.com/@tanem/react-nprogress/-/react-nprogress-3.0.40.tgz#dc1ce391aa1ba00bd8f069e4ad9777886356919c" + integrity sha512-ktwQPIJJr6ooe9lWhA/0RtKkYmBUHMGpzxvJ7Oy0hW3Joi4y+xHSUK/01uUi0+f5koNBrzlkVLAYTUqwmFunTQ== dependencies: "@babel/runtime" "^7.11.2" hoist-non-react-statics "^3.3.2" @@ -2526,11 +2545,12 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: "@types/color-name" "^1.1.1" color-convert "^2.0.1" -antd@^4.5.4: - version "4.5.4" - resolved "https://registry.yarnpkg.com/antd/-/antd-4.5.4.tgz#1eaebcba7a0d9a2e69ad3365366026546fbf7b0f" - integrity sha512-ToBwPaEfRXpDwkFZwEeQc8TynqVLMRX/P4V2IA2cfS4H+w4HXi89kQik4/Gx48UphHmt6fcfwtfm8QZIn3nerA== +antd@^4.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/antd/-/antd-4.6.1.tgz#d204215d3d00a3ac51a2e93ec2ee1a49adbdb705" + integrity sha512-RsqbFvUNSZ5K114492BNo4p+4MpCUpzIsZLu0XFlufYLyIE3pyw184OZjPnJ7b4qlMEvlIoE14N8qCb4BnZF0w== dependencies: + "@ant-design/colors" "^4.0.5" "@ant-design/css-animation" "^1.7.2" "@ant-design/icons" "^4.2.1" "@ant-design/react-slick" "~0.27.0" @@ -2538,7 +2558,7 @@ antd@^4.5.4: array-tree-filter "^2.1.0" classnames "^2.2.6" copy-to-clipboard "^3.2.0" - lodash "^4.17.13" + lodash "^4.17.20" moment "^2.25.3" omit.js "^2.0.2" raf "^3.4.1" @@ -2549,23 +2569,24 @@ antd@^4.5.4: rc-dialog "~8.1.0" rc-drawer "~4.1.0" rc-dropdown "~3.1.2" - rc-field-form "~1.8.0" + rc-field-form "~1.10.0" + rc-image "~3.0.2" rc-input-number "~6.0.0" rc-mentions "~1.4.0" rc-menu "~8.5.2" rc-motion "^1.0.0" rc-notification "~4.4.0" - rc-pagination "~2.4.5" - rc-picker "~1.15.1" + rc-pagination "~3.0.3" + rc-picker "~2.0.6" rc-progress "~3.0.0" rc-rate "~2.8.2" rc-resize-observer "^0.2.3" - rc-select "~11.0.12" + rc-select "~11.1.0" rc-slider "~9.3.0" rc-steps "~4.1.0" rc-switch "~3.2.0" - rc-table "~7.8.0" - rc-tabs "~11.5.0" + rc-table "~7.9.2" + rc-tabs "~11.6.0" rc-textarea "~0.3.0" rc-tooltip "~4.2.0" rc-tree "~3.9.0" @@ -2981,12 +3002,12 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== -axios@^0.19.2: - version "0.19.2" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" - integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA== +axios@^0.20.0: + version "0.20.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.20.0.tgz#057ba30f04884694993a8cd07fa394cff11c50bd" + integrity sha512-ANA4rr2BDcmmAQLOKft2fufrtuvlqR+cXNNinUmvfeSNCOF98PZL+7M/v1zIdGo7OLjEA9J2gXJL+j4zGsl0bA== dependencies: - follow-redirects "1.5.10" + follow-redirects "^1.10.0" axobject-query@^2.0.2: version "2.2.0" @@ -3660,14 +3681,6 @@ chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" @@ -4628,7 +4641,7 @@ debug@2, debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@3.1.0, debug@=3.1.0: +debug@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== @@ -5019,10 +5032,10 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -ejs@^3.0.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.3.tgz#514d967a8894084d18d3d47bd169a1c0560f093d" - integrity sha512-wmtrUGyfSC23GC/B1SMv2ogAUgbQEtDmTIhfqielrG5ExIM9TP4UoYdi90jLF1aTcsWCJNEO0UrgKzP0y3nTSg== +ejs@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.5.tgz#aed723844dc20acb4b170cd9ab1017e476a0d93b" + integrity sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w== dependencies: jake "^10.6.1" @@ -5906,21 +5919,21 @@ fingerprintjs2@^2.1.2: resolved "https://registry.yarnpkg.com/fingerprintjs2/-/fingerprintjs2-2.1.2.tgz#d4812e627356f04b279c63b995b72591b2ab5ed5" integrity sha512-ZPsLgjziFRbUb5tXWpEMtWp4XFnzSah8SiNfl3aoURDZ+2zi2tuIOYUULqDBV+Cb6paN+raWT+Q2qpOaCbX/Yw== -firebase@^7.18.0: - version "7.18.0" - resolved "https://registry.yarnpkg.com/firebase/-/firebase-7.18.0.tgz#00e3967f5bc608f3e12c1a5f0192f559de87943e" - integrity sha512-RGq0rWX25EDsM21TjRe1FbnygJwHXL7yN4P0Zh2Z7dWrBcfJ8tQpDxgwMDtiJTuo9UYExK3py4wjgpGJBau6wg== +firebase@^7.19.0: + version "7.19.0" + resolved "https://registry.yarnpkg.com/firebase/-/firebase-7.19.0.tgz#cfa64ebc56f3ef095df31d20f1de4dc5fa80f793" + integrity sha512-gS0nFagMfDLEucgcMD/tCfpLH+crnTurpyMsh6JEvith7GA8cRA4S3T3300xPL6dSZliI7EiGsCNBXBil6sAUw== dependencies: "@firebase/analytics" "0.4.2" "@firebase/app" "0.6.10" "@firebase/app-types" "0.6.1" "@firebase/auth" "0.14.9" "@firebase/database" "0.6.11" - "@firebase/firestore" "1.16.4" + "@firebase/firestore" "1.16.5" "@firebase/functions" "0.4.50" "@firebase/installations" "0.4.16" "@firebase/messaging" "0.7.0" - "@firebase/performance" "0.3.11" + "@firebase/performance" "0.4.0" "@firebase/polyfill" "0.3.36" "@firebase/remote-config" "0.1.27" "@firebase/storage" "0.3.42" @@ -5958,18 +5971,16 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -follow-redirects@1.5.10: - version "1.5.10" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a" - integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ== - dependencies: - debug "=3.1.0" - follow-redirects@^1.0.0: version "1.12.1" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.12.1.tgz#de54a6205311b93d60398ebc01cf7015682312b6" integrity sha512-tmRv0AVuR7ZyouUHLeNSiO6pqulF7dYa3s19c6t+wz9LD69/uSzdMxJ2S91nTI9U3rt/IldxpzMOFejp6f0hjg== +follow-redirects@^1.10.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.13.0.tgz#b42e8d93a2a7eea5ed88633676d6597bc8e384db" + integrity sha512-aq6gF1BEKje4a9i9+5jimNFIpq4Q1WiwBToeRK5NvZBd/TRsmW8BsJfOEGkr76TbOyPVD3OVDN910EcUNtRYEA== + for-in@^0.1.3: version "0.1.8" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" @@ -8335,6 +8346,11 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b" integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ== +lodash@^4.17.20: + version "4.17.20" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" + integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== + loglevel@^1.6.8: version "1.6.8" resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.8.tgz#8a25fb75d092230ecd4457270d80b54e28011171" @@ -9210,7 +9226,7 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@^7.0.2, open@^7.0.3: +open@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/open/-/open-7.0.4.tgz#c28a9d315e5c98340bf979fdcb2e58664aa10d83" integrity sha512-brSA+/yq+b08Hsr4c8fsEW2CRzk1BmfN3SAK/5VCHQ9bdoZJ4qa/+AfR0xHjlbbZUyPkUHs1b8x1RqdyZdkVqQ== @@ -9218,6 +9234,14 @@ open@^7.0.2, open@^7.0.3: is-docker "^2.0.0" is-wsl "^2.1.1" +open@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/open/-/open-7.2.0.tgz#212959bd7b0ce2e8e3676adc76e3cf2f0a2498b4" + integrity sha512-4HeyhxCvBTI5uBePsAdi55C5fmqnWZ2e2MlmvWi5KW5tdH5rxoiv/aMtbeVxKZc3eWkT1GymMnLG8XC4Rq4TDQ== + dependencies: + is-docker "^2.0.0" + is-wsl "^2.1.1" + opn@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc" @@ -10753,6 +10777,14 @@ rc-collapse@~2.0.0: react-is "^16.7.0" shallowequal "^1.1.0" +rc-dialog@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-8.1.1.tgz#ce54bd78e940c030b69d3acfc87874536966a27b" + integrity sha512-ToyHiMlV94z8LfnmeKoVvu04Pd9+HdwwSHhY2a8IWeYGA5Cjk1WyIZvS+njCsm8rSMM4NqPqFkMZA0N/Iw0NrQ== + dependencies: + rc-animate "3.x" + rc-util "^5.0.1" + rc-dialog@~8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/rc-dialog/-/rc-dialog-8.1.0.tgz#393910963bb05ac19d6d136620bd09622f1d677a" @@ -10779,15 +10811,26 @@ rc-dropdown@^3.1.0, rc-dropdown@~3.1.2: classnames "^2.2.6" rc-trigger "^4.0.0" -rc-field-form@~1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-1.8.0.tgz#c51312321409727e5a333873311f9c1f5e13e8c2" - integrity sha512-WQyC3yBEKIWehNzkRMTBK/Lzdjronov9GsB9C9bgVcfpDqsIQSSBgGFAJMmWUAGs2IrCbgh9RBY0Ste4foHzvg== +rc-field-form@~1.10.0: + version "1.10.1" + resolved "https://registry.yarnpkg.com/rc-field-form/-/rc-field-form-1.10.1.tgz#f6eb76b5f24b58938ebadfc03cdd814c24de7db3" + integrity sha512-aosTtNTqLYX2jsG5GyCv7axe+b57XH73T7TmmrX/cmhemhtFjvNE6RkRkmtP9VOJnZg5YGC5HfK172cnJ1Ij7Q== dependencies: "@babel/runtime" "^7.8.4" async-validator "^3.0.3" rc-util "^5.0.0" +rc-image@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rc-image/-/rc-image-3.0.2.tgz#5f57cc08a0cfe41a6a56c6c81a094f1f5c5272dc" + integrity sha512-kzUQw0EuxjTatIY6ZJXLtwtm9jDPUK6RnQ8HBxWPCZl1trgEbddU9TwxLfyNs030qztD1j/2juRCYKsEiSgAKQ== + dependencies: + "@ant-design/icons" "^4.2.2" + "@babel/runtime" "^7.11.2" + classnames "^2.2.6" + rc-dialog "^8.1.0" + rc-util "^5.0.6" + rc-input-number@~6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/rc-input-number/-/rc-input-number-6.0.0.tgz#0c0af57c8183f3ca6b87f7edf6fed3bd5a3ba16f" @@ -10859,18 +10902,18 @@ rc-notification@~4.4.0: rc-animate "3.x" rc-util "^5.0.1" -rc-pagination@~2.4.5: - version "2.4.6" - resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-2.4.6.tgz#cc030c9693c730b43592bdb6974fb32c1502a500" - integrity sha512-1ykd3Jti+JuOFdzEFXGfVpkuH+hKxLYz3FKV6BSwnnWXLr9Y8bbm7YiTSwBmdDcOg6tinH8b4IYaKzxBWRC6EA== +rc-pagination@~3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/rc-pagination/-/rc-pagination-3.0.3.tgz#48ce55822e153ed9f9b8961fcb3bb8ecab8df37c" + integrity sha512-xm6LsiSOAWlxferiL5e0jcun1B9vbvYzcIkqpYZR7YvC5ZrcU9KKihb+DZe3DY+oUc49xhX2qGS4D66ITHqekQ== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.2.1" -rc-picker@~1.15.1: - version "1.15.1" - resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-1.15.1.tgz#b0d647f3827468f844bc95c9255436ea787d26ce" - integrity sha512-YW6I91R1rMDTKpWY2yYjUk3mX4ttk7l8dx5fuojGBj86TGPj0R5vh+wFoRNzOeA4qAHcRzGWGPP60HFnoxL1TA== +rc-picker@~2.0.6: + version "2.0.7" + resolved "https://registry.yarnpkg.com/rc-picker/-/rc-picker-2.0.7.tgz#cb8a6179a3bfcd925ebfa8a178ca5d526fdfa445" + integrity sha512-0G8vSPRe4EGUx5TpKBL/4evB6N1qx6J8y2rXDqQPHetUbrLEhRSzWLIJ4RZpBNSqa0iOwLJ8RIW+a/1q8Wcopg== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.2.1" @@ -10879,7 +10922,6 @@ rc-picker@~1.15.1: moment "^2.24.0" rc-trigger "^4.0.0" rc-util "^5.0.1" - react "^16.0.0" shallowequal "^1.1.0" rc-progress@~3.0.0: @@ -10921,17 +10963,17 @@ rc-select@^11.1.1: rc-virtual-list "^1.1.2" warning "^4.0.3" -rc-select@~11.0.12: - version "11.0.13" - resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-11.0.13.tgz#fe5718af819d3e0bc12a55334bc1717257ef2dac" - integrity sha512-4/GDmBkGnDhYre3Dvq5UkIRXQJW8hbGdpdH8SjquSbCktAVitYV+opd/lKI28qMcBxCgjOHgYXwZ18TF+kP2VQ== +rc-select@~11.1.0: + version "11.1.6" + resolved "https://registry.yarnpkg.com/rc-select/-/rc-select-11.1.6.tgz#39bb7c685dc61f65d5d73554df58979587c45b16" + integrity sha512-X5kCwUGIe3uF5las4bFiXzD3F/hxs5Nz+wpf3xG6esg352ThP5kBROmMOeb91Yo2nOPZyiH6jnLsZLecnyWbZQ== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" rc-motion "^1.0.1" rc-trigger "^4.3.0" rc-util "^5.0.1" - rc-virtual-list "^1.1.2" + rc-virtual-list "^3.0.3" warning "^4.0.3" rc-slider@~9.3.0: @@ -10963,22 +11005,22 @@ rc-switch@~3.2.0: classnames "^2.2.1" rc-util "^5.0.1" -rc-table@~7.8.0: - version "7.8.4" - resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.8.4.tgz#493e6e8ccd9f078a073f0f7cf46bbb02c55f74d7" - integrity sha512-+8JPFD4oGy/4/VdXsPE/12oEkopiZoIi4cS6DJGzjf2CjhrM7KevUOjrs0MhFlXZp/Pnb8qSKoVdVHN1JYtL7Q== +rc-table@~7.9.2: + version "7.9.4" + resolved "https://registry.yarnpkg.com/rc-table/-/rc-table-7.9.4.tgz#d9fd41578b1d422c8f98b772bf3f0dfcb93c5b83" + integrity sha512-af3Figjca+K3ZEzIHHc0m7jgg0Z2vdValPU2i6XEMpfrjBJIgDqkQy6qmClqQ54F0CEXaw9y2j16CI8y3jK7MQ== dependencies: "@babel/runtime" "^7.10.1" classnames "^2.2.5" raf "^3.4.1" rc-resize-observer "^0.2.0" - rc-util "^5.0.0" + rc-util "^5.0.4" shallowequal "^1.1.0" -rc-tabs@~11.5.0: - version "11.5.4" - resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-11.5.4.tgz#1fc3469605fc28d47fb64c582ec83f97113dbd5a" - integrity sha512-J7duEePQbF9G1VESfEDH05GYIa/5uS/tmMoTy4IXfohql/b/2mjR3YzKahxi0x/wQJovgBRrdfNQA5Ph99lwIw== +rc-tabs@~11.6.0: + version "11.6.1" + resolved "https://registry.yarnpkg.com/rc-tabs/-/rc-tabs-11.6.1.tgz#a31a277b12f807cc7bdc31476c0d21124ce93e14" + integrity sha512-fJZUOmwBo2E4WTbucCSZO/N1ZK+d9K/QchgDeycTIqxl5D/xtX0Dw/vC2DFi140OFjAy2JL7H0EmsSeOFfCgzw== dependencies: "@babel/runtime" "^7.10.1" classnames "2.x" @@ -11078,18 +11120,18 @@ rc-util@^5.0.0, rc-util@^5.0.1: react-is "^16.12.0" shallowequal "^1.1.0" -rc-util@^5.0.5, rc-util@^5.0.6: - version "5.0.6" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.0.6.tgz#2b828bc87a818a66384b813f76a561ad4609e9b0" - integrity sha512-uLGxF9WjbpJSjd6iDnIjl8ZeMUglpcuh1DwO26aaXh++yAmlB6eIAJMUwwJCuqJvo4quCvsDPg1VkqHILc4U0A== +rc-util@^5.0.4, rc-util@^5.0.7: + version "5.0.7" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.0.7.tgz#125c3a2fd917803afbb685f9eadc789b085dc813" + integrity sha512-nr98b5aMqqvIqxm16nF+zC3K3f81r+HsflT5E9Encr5itRwV7Vo/5GjJMNds/WiFV33rilq7vzb3xeAbCycmwg== dependencies: react-is "^16.12.0" shallowequal "^1.1.0" -rc-util@^5.0.7: - version "5.0.7" - resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.0.7.tgz#125c3a2fd917803afbb685f9eadc789b085dc813" - integrity sha512-nr98b5aMqqvIqxm16nF+zC3K3f81r+HsflT5E9Encr5itRwV7Vo/5GjJMNds/WiFV33rilq7vzb3xeAbCycmwg== +rc-util@^5.0.5, rc-util@^5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/rc-util/-/rc-util-5.0.6.tgz#2b828bc87a818a66384b813f76a561ad4609e9b0" + integrity sha512-uLGxF9WjbpJSjd6iDnIjl8ZeMUglpcuh1DwO26aaXh++yAmlB6eIAJMUwwJCuqJvo4quCvsDPg1VkqHILc4U0A== dependencies: react-is "^16.12.0" shallowequal "^1.1.0" @@ -11112,6 +11154,15 @@ rc-virtual-list@^2.1.1: rc-resize-observer "^0.2.3" rc-util "^5.0.7" +rc-virtual-list@^3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/rc-virtual-list/-/rc-virtual-list-3.0.4.tgz#d2d517b2c913f09ad51a6a572e496ffad887bbd2" + integrity sha512-rWNQTMLUlFKeqYZK/Zy5aXY00KKjc0YzzmY6l68t8g6f1ivalozCvvJcKhQ9Azt5HmHdiyvUODCVk1/ZQrL5KA== + dependencies: + classnames "^2.2.6" + rc-resize-observer "^0.2.3" + rc-util "^5.0.7" + react-apollo@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/react-apollo/-/react-apollo-3.1.5.tgz#36692d393c47e7ccc37f0a885c7cc5a8b4961c91" @@ -11156,10 +11207,10 @@ react-beautiful-dnd@^13.0.0: redux "^4.0.4" use-memo-one "^1.1.1" -react-big-calendar@^0.26.0: - version "0.26.0" - resolved "https://registry.yarnpkg.com/react-big-calendar/-/react-big-calendar-0.26.0.tgz#a8b4d7262e5d7890c10c53ba23db8631a02ef788" - integrity sha512-TSyP+B+ZJhaj+em2brQzRCYip4Slx+7SM2Vf9SfmnMO1eWZr9DahEyy4LL+TOoF50BZXyzU5EaPqaxbuZ23xqw== +react-big-calendar@^0.26.1: + version "0.26.1" + resolved "https://registry.yarnpkg.com/react-big-calendar/-/react-big-calendar-0.26.1.tgz#48e26eeeee049227436bb23457025705f070105b" + integrity sha512-8OuWNUauoCEibrXcQpjP7tMo887yRujij1a5lgaYNbdJQzlmb1QTWl/+N0xgPfeLW/Nwiqnw3lYRgFoQiFjpSw== dependencies: "@babel/runtime" "^7.1.5" clsx "^1.0.4" @@ -11262,10 +11313,10 @@ react-grid-layout@^1.0.0: react-draggable "^4.0.0" react-resizable "^1.10.0" -react-i18next@^11.7.0: - version "11.7.0" - resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.7.0.tgz#f27c4c237a274e007a48ac1210db83e33719908b" - integrity sha512-8tvVkpuxQlubcszZON+jmoCgiA9gCZ74OAYli9KChPhETtq8pJsANBTe9KRLRLmX3ubumgvidURWr0VvKz1tww== +react-i18next@^11.7.1: + version "11.7.1" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.7.1.tgz#80c993bf7c4f07937ce0e5ff4e2d7d97bfe3f42f" + integrity sha512-K7qWaQ03Nc25BqSqdKz1iGU5inwNQnDVcen/tpiILEXyd0w/z+untrsuUy5Y3PqAkwJ7m1FACwBttSSitxDKQA== dependencies: "@babel/runtime" "^7.3.1" html-parse-stringify2 "2.0.1" @@ -11277,10 +11328,10 @@ react-icons@^3.11.0: dependencies: camelcase "^5.0.0" -react-image-file-resizer@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/react-image-file-resizer/-/react-image-file-resizer-0.3.1.tgz#4ea645f7702a2d9b475e67b4b82d735207ccba0b" - integrity sha512-hP6qXLyOFhPwaz+tkufsDiaHgnl5NlBVl208xlW6nlQBylzkmMCwtNCOZYgEie0sUSUYKVaTrQsbfhXxV20fbQ== +react-image-file-resizer@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/react-image-file-resizer/-/react-image-file-resizer-0.3.6.tgz#9c879971da6cdef143fb3808f641061f54a974a1" + integrity sha512-/lu4KDwau9EHY5rj5NCNypIse19OeEm51dEruS0FWwSr42JKAGzIrxd4+HXJsoONf/xffShMqnRBU+bO0WFHfw== react-images@^0.5.16: version "0.5.19" @@ -11578,7 +11629,7 @@ react-virtualized@^9.22.2: prop-types "^15.7.2" react-lifecycles-compat "^3.0.4" -"react@>= 16.3", react@^16.0.0, react@^16.13.1: +"react@>= 16.3", react@^16.13.1: version "16.13.1" resolved "https://registry.yarnpkg.com/react/-/react-16.13.1.tgz#2e818822f1a9743122c063d6410d85c1e3afe48e" integrity sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w== @@ -12623,23 +12674,23 @@ source-list-map@^2.0.0: resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== -source-map-explorer@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/source-map-explorer/-/source-map-explorer-2.4.2.tgz#fb23f86c3112eacde5683f24efaf4ddc9f677985" - integrity sha512-3ECQLffCFV8QgrTqcmddLkWL4/aQs6ljYfgWCLselo5QtizOfOeUCKnS4rFn7MIrdeZLM6TZrseOtsrWZhWKoQ== +source-map-explorer@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/source-map-explorer/-/source-map-explorer-2.5.0.tgz#42e12c76743e8a0ca0579d472ea5ba623e0d0498" + integrity sha512-kWhlt0celEwwuULIY+sRoZKibc/8/Ec4ckcKThDMQW3hT7KxReYW1XktwFJIbZ2VF9Yf/hA74bcoIZOSXXQIgQ== dependencies: btoa "^1.2.1" - chalk "^3.0.0" + chalk "^4.1.0" convert-source-map "^1.7.0" - ejs "^3.0.2" + ejs "^3.1.5" escape-html "^1.0.3" glob "^7.1.6" gzip-size "^5.1.1" - lodash "^4.17.15" - open "^7.0.3" + lodash "^4.17.20" + open "^7.1.0" source-map "^0.7.3" temp "^0.9.1" - yargs "^15.3.1" + yargs "^15.4.1" source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: version "0.5.3" @@ -14405,7 +14456,7 @@ yargs@^13.3.0, yargs@^13.3.2: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^15.3.1: +yargs@^15.4.1: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== diff --git a/package.json b/package.json index 6f16b4ce1..098f8961f 100644 --- a/package.json +++ b/package.json @@ -26,15 +26,16 @@ "dotenv": "8.2.0", "express": "^4.16.4", "express-sslify": "^1.2.0", - "firebase-admin": "^9.1.0", - "graphql-request": "^2.0.0", + "firebase-admin": "^9.1.1", + "graphql": "^15.3.0", + "graphql-request": "^3.0.0", "handlebars": "^4.7.6", "lodash": "^4.17.20", "moment": "^2.27.0", "node-fetch": "^2.6.0", "node-mailjet": "^3.3.1", "phone": "^2.4.15", - "stripe": "^8.88.0", + "stripe": "^8.89.0", "twilio": "^3.49.0", "xmlbuilder": "^15.1.1" }, @@ -42,6 +43,6 @@ "concurrently": "^5.3.0", "eslint": "^6.6.0", "eslint-plugin-promise": "^4.2.1", - "source-map-explorer": "^2.4.2" + "source-map-explorer": "^2.5.0" } } diff --git a/server/job/job-totals.js b/server/job/job-totals.js index 0d57fe965..543ef77e0 100644 --- a/server/job/job-totals.js +++ b/server/job/job-totals.js @@ -2,6 +2,7 @@ const Dinero = require("dinero.js"); exports.default = async function (req, res) { const { job, shoprates } = req.body; + console.log(`Calculating Job Totals for ${job.id} - ${job.ro_number}`); try { let ret = { parts: CalculatePartsTotals(job.joblines), diff --git a/yarn.lock b/yarn.lock index 0aaece151..b003e9732 100644 --- a/yarn.lock +++ b/yarn.lock @@ -410,6 +410,11 @@ astral-regex@^1.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== +async@0.9.x: + version "0.9.2" + resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" + integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -515,14 +520,6 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" - integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - chalk@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" @@ -742,6 +739,13 @@ cors@2.8.5: object-assign "^4" vary "^1" +cross-fetch@^3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.0.5.tgz#2739d2981892e7ab488a7ad03b92df2816e03f4c" + integrity sha512-FFLcLtraisj5eteosnX1gf01qYDCOc4fDy0+euOt8Kn9YBY2NtXL/pCoYPavw24NIQkQqm5ZOLsGD5Zzj0gyew== + dependencies: + node-fetch "2.6.0" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -908,10 +912,12 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= -ejs@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.0.2.tgz#745b01cdcfe38c1c6a2da3bbb2d9957060a31226" - integrity sha512-IncmUpn1yN84hy2shb0POJ80FWrfGNY0cxO9f4v+/sG7qcBvAtVWUA1IdzY/8EYUmOVhoKJVdJjNd3AZcnxOjA== +ejs@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.5.tgz#aed723844dc20acb4b170cd9ab1017e476a0d93b" + integrity sha512-dldq3ZfFtgVTJMLjOe+/3sROTzALlL9E34V4/sDtUd/KlBSS0s6U1/+WPE1B4sj9CXHJpL1M6rhNJnc9Wbal9w== + dependencies: + jake "^10.6.1" emoji-regex@^7.0.1: version "7.0.3" @@ -1213,6 +1219,13 @@ file-uri-to-path@1: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +filelist@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.1.tgz#f10d1a3ae86c1694808e8f20906f43d4c9132dbb" + integrity sha512-8zSK6Nu0DQIC08mUC46sWGXi+q3GGpKydAG36k+JDba6VRpkevvOWUW5a/PhShij4+vHT9M+ghgG7eM+a9JDUQ== + dependencies: + minimatch "^3.0.4" + finalhandler@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" @@ -1241,10 +1254,10 @@ find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" -firebase-admin@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/firebase-admin/-/firebase-admin-9.1.0.tgz#c8b7f8da32cc52d5f15b0be47fd88979c5e86618" - integrity sha512-tGGREJpoRM/mbV/5bs/q9SQRZkVhxMMq1HIJEzSEh3mtz5hC9VtaCkuLt6chuAsqHMBoc1pvnrGTOC5nOme9VQ== +firebase-admin@^9.1.1: + version "9.1.1" + resolved "https://registry.yarnpkg.com/firebase-admin/-/firebase-admin-9.1.1.tgz#153aff515140a41d92ebc51231c12c7b2f4c3e69" + integrity sha512-HkzY9yN/kOe1EQgjheURAQ4pFBerI54TBL0+nj1fwzKnAnGCpcI73Bbwx99Pk3u2x4rj6bDcsZfz9bA8y7DWtQ== dependencies: "@firebase/database" "^0.6.10" "@firebase/database-types" "^0.5.2" @@ -1441,10 +1454,17 @@ graceful-fs@^4.1.2: resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== -graphql-request@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-2.0.0.tgz#8dd12cf1eb2ce0c80f4114fd851741e091134862" - integrity sha512-Ww3Ax+G3l2d+mPT8w7HC9LfrKjutnCKtnDq7ZZp2ghVk5IQDjwAk3/arRF1ix17Ky15rm0hrSKVKxRhIVlSuoQ== +graphql-request@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/graphql-request/-/graphql-request-3.0.0.tgz#942d81bbd621cc2223d35fbf2b42edf8be822b83" + integrity sha512-zW8AuLnKMYOnpVKdANU9FzLDoj4u4AoU6KZ79e+BcJaNiuw/vgCJ0p7ppDMSDrW77a12Moa7J7Mg4w0f9Kd/Kg== + dependencies: + cross-fetch "^3.0.4" + +graphql@^15.3.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.3.0.tgz#3ad2b0caab0d110e3be4a5a9b2aa281e362b5278" + integrity sha512-GTCJtzJmkFLWRfFJuoo9RWWa/FfamUHgiFosxi/X1Ani4AVWbeyBenZTNX6dM+7WSbbFfTo/25eh0LLkwHMw2w== gtoken@^5.0.0: version "5.0.3" @@ -1702,6 +1722,16 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +jake@^10.6.1: + version "10.8.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.2.tgz#ebc9de8558160a66d82d0eadc6a2e58fbc500a7b" + integrity sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A== + dependencies: + async "0.9.x" + chalk "^2.4.2" + filelist "^1.0.1" + minimatch "^3.0.4" + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -2037,7 +2067,7 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-fetch@^2.2.0, node-fetch@^2.3.0, node-fetch@^2.6.0: +node-fetch@2.6.0, node-fetch@^2.2.0, node-fetch@^2.3.0, node-fetch@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== @@ -2099,10 +2129,10 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" -open@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/open/-/open-7.0.3.tgz#db551a1af9c7ab4c7af664139930826138531c48" - integrity sha512-sP2ru2v0P290WFfv49Ap8MF6PkzGNnGlAwHweB4WR4mr5d2d0woiCluUeJ218w7/+PmoBy9JmYgD5A4mLcWOFA== +open@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/open/-/open-7.2.0.tgz#212959bd7b0ce2e8e3676adc76e3cf2f0a2498b4" + integrity sha512-4HeyhxCvBTI5uBePsAdi55C5fmqnWZ2e2MlmvWi5KW5tdH5rxoiv/aMtbeVxKZc3eWkT1GymMnLG8XC4Rq4TDQ== dependencies: is-docker "^2.0.0" is-wsl "^2.1.1" @@ -2669,23 +2699,23 @@ socks@^1.1.10: ip "^1.1.4" smart-buffer "^1.0.13" -source-map-explorer@^2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/source-map-explorer/-/source-map-explorer-2.4.2.tgz#fb23f86c3112eacde5683f24efaf4ddc9f677985" - integrity sha512-3ECQLffCFV8QgrTqcmddLkWL4/aQs6ljYfgWCLselo5QtizOfOeUCKnS4rFn7MIrdeZLM6TZrseOtsrWZhWKoQ== +source-map-explorer@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/source-map-explorer/-/source-map-explorer-2.5.0.tgz#42e12c76743e8a0ca0579d472ea5ba623e0d0498" + integrity sha512-kWhlt0celEwwuULIY+sRoZKibc/8/Ec4ckcKThDMQW3hT7KxReYW1XktwFJIbZ2VF9Yf/hA74bcoIZOSXXQIgQ== dependencies: btoa "^1.2.1" - chalk "^3.0.0" + chalk "^4.1.0" convert-source-map "^1.7.0" - ejs "^3.0.2" + ejs "^3.1.5" escape-html "^1.0.3" glob "^7.1.6" gzip-size "^5.1.1" - lodash "^4.17.15" - open "^7.0.3" + lodash "^4.17.20" + open "^7.1.0" source-map "^0.7.3" temp "^0.9.1" - yargs "^15.3.1" + yargs "^15.4.1" source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" @@ -2811,10 +2841,10 @@ strip-json-comments@^3.0.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -stripe@^8.88.0: - version "8.88.0" - resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.88.0.tgz#ba7e9eec21bbf5459491366081d04a811b55f0de" - integrity sha512-aeixfX6Gem5UiRdoH9wphQ344abxgAQrLg2sAY/0IddZ5mprZKS568Pb3WX0qy2E5OJGute+jEAn2Za7DKLQtw== +stripe@^8.89.0: + version "8.89.0" + resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.89.0.tgz#fcd48ba7e298d547c89b686dea155f0507c25e67" + integrity sha512-XiAuNAyv2ORCWZrIaG22frr7rXP1J5+XsHA4QUBwB0fePB5kxV0O6FFMrZ8nipYZ43pnez5EIJ/Oxb1jLq6w6g== dependencies: "@types/node" ">=8.1.0" qs "^6.6.0" @@ -3216,7 +3246,7 @@ yargs-parser@^13.1.1: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@^18.1.1: +yargs-parser@^18.1.2: version "18.1.3" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== @@ -3240,10 +3270,10 @@ yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.1" -yargs@^15.3.1: - version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" - integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== +yargs@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== dependencies: cliui "^6.0.0" decamelize "^1.2.0" @@ -3255,4 +3285,4 @@ yargs@^15.3.1: string-width "^4.2.0" which-module "^2.0.0" y18n "^4.0.0" - yargs-parser "^18.1.1" + yargs-parser "^18.1.2"
{t(`jobs.fields.${key.toLowerCase()}`)} - {totals.parts.parts.list[key].total.toFormat()} -
{t(`jobs.fields.${key.toLowerCase()}`)} + {Dinero( + job.job_totals.parts.parts.list[key].total + ).toFormat()} +
{t("jobs.labels.partstotal")} - {totals.parts.parts.total.toFormat()} + {Dinero(job.job_totals.parts.parts.total).toFormat()} {`(${totals.parts.parts.subtotal.toFormat()} ± ${totals.parts.parts.adjustments.toFormat()})`}{`(${Dinero( + job.job_totals.parts.parts.subtotal + ).toFormat()} ± ${Dinero( + job.job_totals.parts.parts.adjustments + ).toFormat()})`}
{t("jobs.labels.subletstotal")} - {totals.parts.sublets.total.toFormat()} + {Dinero(job.job_totals.parts.sublets.total).toFormat()} {`(${totals.parts.sublets.subtotal.toFormat()} ± ${totals.parts.sublets.adjustments.toFormat()})`}{`(${Dinero( + job.job_totals.parts.sublets.subtotal + ).toFormat()} ± ${Dinero( + job.job_totals.parts.sublets.adjustments + ).toFormat()})`}
{t("jobs.labels.mapa")} - {totals.rates.mapa.total.toFormat()} + {Dinero(job.job_totals.rates.mapa.total).toFormat()} {`(${totals.rates.mapa.hours.toFixed(2)} @ ${ - totals.rates.mapa.rate + {`(${job.job_totals.rates.mapa.hours.toFixed(2)} @ ${ + job.job_totals.rates.mapa.rate })`}
{t("jobs.labels.mash")} - {totals.rates.mash.total.toFormat()} + {Dinero(job.job_totals.rates.mash.total).toFormat()} {`(${totals.rates.mash.hours.toFixed(2)} @ ${ - totals.rates.mash.rate + {`(${job.job_totals.rates.mash.hours.toFixed(2)} @ ${ + job.job_totals.rates.mash.rate })`}