Compare commits
5 Commits
release/20
...
hotfix/IO-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2336617077 | ||
|
|
98f7147378 | ||
|
|
54b8f564e4 | ||
|
|
591284c972 | ||
|
|
9e0dae2adf |
@@ -9,6 +9,7 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
import { HasFeatureAccess } from './../feature-wrapper/feature-wrapper.component';
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
printCenterModal: selectPrintCenter,
|
||||
@@ -43,10 +44,12 @@ export function PrintCenterItemComponent({
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
if (disabled || item.featureNameRestricted)
|
||||
if (disabled || (item.featureNameRestricted && !HasFeatureAccess({"featureName": item.featureNameRestricted, bodyshop})))
|
||||
return (
|
||||
<li className="print-center-item">
|
||||
<LockWrapperComponent featureName={item.featureNameRestricted}>{item.title}</LockWrapperComponent>
|
||||
<LockWrapperComponent featureName={item.featureNameRestricted} bodyshop={bodyshop}>
|
||||
{item.title}
|
||||
</LockWrapperComponent>
|
||||
</li>
|
||||
);
|
||||
return (
|
||||
|
||||
@@ -8,6 +8,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import { UpsellMaskWrapper, upsellEnum } from "../upsell/upsell.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -35,6 +36,28 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
|
||||
[]
|
||||
);
|
||||
}, [loadData, ssbuckets]);
|
||||
const hasSmartSchedulingAccess = HasFeatureAccess({ featureName: "smartscheduling", bodyshop });
|
||||
|
||||
const chartContents = (
|
||||
<>
|
||||
<RadarChart
|
||||
// cx={300}
|
||||
// cy={250}
|
||||
// outerRadius={150}
|
||||
width={800}
|
||||
height={600}
|
||||
data={data}
|
||||
>
|
||||
<PolarGrid />
|
||||
<PolarAngleAxis dataKey="bucket" />
|
||||
<PolarRadiusAxis angle={90} />
|
||||
<Radar name="Ideal Load" dataKey="target" stroke="darkgreen" fill="white" fillOpacity={0} />
|
||||
<Radar name="EOD Load" dataKey="current" stroke="dodgerblue" fill="dodgerblue" fillOpacity={0.6} />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
</RadarChart>
|
||||
</>
|
||||
);
|
||||
|
||||
const popContent = (
|
||||
<div>
|
||||
@@ -48,26 +71,13 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
|
||||
<strong>{loadData?.expectedJobCount}</strong>
|
||||
</BlurWrapperComponent>
|
||||
</Space>
|
||||
<UpsellMaskWrapper upsell={upsellEnum().smartscheduling.general}>
|
||||
<BlurWrapperComponent featureName="smartscheduling">
|
||||
<RadarChart
|
||||
// cx={300}
|
||||
// cy={250}
|
||||
// outerRadius={150}
|
||||
width={800}
|
||||
height={600}
|
||||
data={data}
|
||||
>
|
||||
<PolarGrid />
|
||||
<PolarAngleAxis dataKey="bucket" />
|
||||
<PolarRadiusAxis angle={90} />
|
||||
<Radar name="Ideal Load" dataKey="target" stroke="darkgreen" fill="white" fillOpacity={0} />
|
||||
<Radar name="EOD Load" dataKey="current" stroke="dodgerblue" fill="dodgerblue" fillOpacity={0.6} />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
</RadarChart>
|
||||
</BlurWrapperComponent>
|
||||
</UpsellMaskWrapper>
|
||||
<BlurWrapperComponent featureName="smartscheduling">
|
||||
{hasSmartSchedulingAccess ? (
|
||||
chartContents
|
||||
) : (
|
||||
<UpsellMaskWrapper upsell={upsellEnum().smartscheduling.general}>{chartContents}</UpsellMaskWrapper>
|
||||
)}
|
||||
</BlurWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import OwnerNameDisplay from "../owner-name-display/owner-name-display.component
|
||||
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
||||
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
|
||||
import UpsellComponent, { upsellEnum, UpsellMaskWrapper } from "../upsell/upsell.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -52,6 +53,7 @@ export function ScheduleCalendarHeaderComponent({
|
||||
|
||||
const { t } = useTranslation();
|
||||
const loadData = load[date.toISOString().substr(0, 10)];
|
||||
const hasSmartSchedulingAccess = HasFeatureAccess({ featureName: "smartscheduling", bodyshop });
|
||||
|
||||
const jobsOutPopup = () => (
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
@@ -89,9 +91,11 @@ export function ScheduleCalendarHeaderComponent({
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
<Card style={{ maxWidth: "30rem" }}>
|
||||
<UpsellComponent size="small" upsell={upsellEnum().smartscheduling.hrsdelta} />
|
||||
</Card>
|
||||
{!hasSmartSchedulingAccess && (
|
||||
<Card style={{ maxWidth: "30rem" }}>
|
||||
<UpsellComponent size="small" upsell={upsellEnum().smartscheduling.hrsdelta} />
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -129,9 +133,11 @@ export function ScheduleCalendarHeaderComponent({
|
||||
</BlurWrapperComponent>
|
||||
</tr>
|
||||
)}
|
||||
<Card style={{ maxWidth: "30rem" }}>
|
||||
<UpsellComponent size="small" upsell={upsellEnum().smartscheduling.hrsdelta} />
|
||||
</Card>
|
||||
{!hasSmartSchedulingAccess && (
|
||||
<Card style={{ maxWidth: "30rem" }}>
|
||||
<UpsellComponent size="small" upsell={upsellEnum().smartscheduling.hrsdelta} />
|
||||
</Card>
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -16,7 +16,7 @@ import ScheduleDayViewContainer from "../schedule-day-view/schedule-day-view.con
|
||||
import ScheduleExistingAppointmentsList from "../schedule-existing-appointments-list/schedule-existing-appointments-list.component";
|
||||
import "./schedule-job-modal.scss";
|
||||
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
import { BlurWrapper } from "../feature-wrapper/blur-wrapper.component";
|
||||
import BlurWrapper from "../feature-wrapper/blur-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -138,7 +138,7 @@ export function ScheduleJobModalComponent({
|
||||
</BlurWrapper>
|
||||
</Button>
|
||||
))}
|
||||
{smartOptions.length > 1 && hasSmartSchedulingAccess && (
|
||||
{!smartOptions.length > 1 && hasSmartSchedulingAccess && (
|
||||
<UpsellComponent upsell={upsellEnum().smartscheduling.general} />
|
||||
)}
|
||||
</Space>
|
||||
|
||||
@@ -19,7 +19,6 @@ export default function UpsellComponent({ featureName, subFeatureName, upsell, d
|
||||
const { t } = useTranslation();
|
||||
const resultProps = upsell || upsellEnum[featureName][subFeatureName];
|
||||
|
||||
console.trace("***LOG ~ file: upsell.component.jsx:22 ~ UpsellComponent ~ resultProps:", resultProps);
|
||||
const componentRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -49,7 +49,8 @@ exports.totalsSsu = async function (req, res) {
|
||||
} catch (error) {
|
||||
logger.log("job-totals-ssu-USA-error", "ERROR", req?.user?.email, id, {
|
||||
jobid: id,
|
||||
error: error.message
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
res.status(503).send();
|
||||
}
|
||||
@@ -68,59 +69,63 @@ async function TotalsServerSide(req, res) {
|
||||
ret.additional = CalculateAdditional(job);
|
||||
ret.totals = CalculateTaxesTotals(job, ret);
|
||||
|
||||
// Sub total scrubbbing.
|
||||
const emsTotal =
|
||||
job.cieca_ttl.data.n_ttl_amt === job.cieca_ttl.data.g_ttl_amt //It looks like sometimes, gross and net are the same, but they shouldn't be.
|
||||
? job.cieca_ttl.data.n_ttl_amt - job.cieca_ttl.data.g_tax
|
||||
: job.cieca_ttl.data.g_ttl_amt - job.cieca_ttl.data.g_tax; //If they are, adjust the gross total down by the tax amount.
|
||||
const ttlDifference =
|
||||
emsTotal -
|
||||
ret.totals.subtotal
|
||||
.add(
|
||||
Dinero({
|
||||
amount: Math.round((job.adjustment_bottom_line || 0) * 100)
|
||||
}).multiply(-1) //Add back in the adjustment to the subtotal. We don't want to scrub it twice.
|
||||
)
|
||||
.getAmount() /
|
||||
//If we don't have the CIECA_TTL, we can't scrub. E.g. a private estimate.
|
||||
if (job.cieca_ttl) {
|
||||
// Sub total scrubbbing.
|
||||
const emsTotal =
|
||||
job.cieca_ttl.data.n_ttl_amt === job.cieca_ttl.data.g_ttl_amt //It looks like sometimes, gross and net are the same, but they shouldn't be.
|
||||
? job.cieca_ttl.data.n_ttl_amt - job.cieca_ttl.data.g_tax
|
||||
: job.cieca_ttl.data.g_ttl_amt - job.cieca_ttl.data.g_tax; //If they are, adjust the gross total down by the tax amount.
|
||||
const ttlDifference =
|
||||
emsTotal -
|
||||
ret.totals.subtotal
|
||||
.add(
|
||||
Dinero({
|
||||
amount: Math.round((job.adjustment_bottom_line || 0) * 100)
|
||||
}).multiply(-1) //Add back in the adjustment to the subtotal. We don't want to scrub it twice.
|
||||
)
|
||||
.getAmount() /
|
||||
100;
|
||||
|
||||
if (Math.abs(ttlDifference) > 0.0) {
|
||||
//If difference is greater than a pennny, we need to adjust it.
|
||||
ret.totals.ttl_adjustment = Dinero({ amount: Math.round(ttlDifference * 100) });
|
||||
ret.totals.subtotal = ret.totals.subtotal.add(ret.totals.ttl_adjustment);
|
||||
ret.totals.total_repairs = ret.totals.total_repairs.add(ret.totals.ttl_adjustment);
|
||||
ret.totals.net_repairs = ret.totals.net_repairs.add(ret.totals.ttl_adjustment);
|
||||
logger.log("job-totals-USA-ttl-adj", "DEBUG", null, job.id, {
|
||||
adjAmount: ttlDifference
|
||||
});
|
||||
}
|
||||
|
||||
//Taxes Scrubbing
|
||||
const emsTaxTotal = job.cieca_ttl.data.g_tax;
|
||||
const totalUsTaxes =
|
||||
(ret.totals.us_sales_tax_breakdown.ty1Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty2Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty3Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty4Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty5Tax.getAmount()) /
|
||||
100;
|
||||
const ttlTaxDifference = emsTaxTotal - totalUsTaxes;
|
||||
|
||||
if (Math.abs(ttlDifference) > 0.0) {
|
||||
//If difference is greater than a pennny, we need to adjust it.
|
||||
ret.totals.ttl_adjustment = Dinero({ amount: Math.round(ttlDifference * 100) });
|
||||
ret.totals.subtotal = ret.totals.subtotal.add(ret.totals.ttl_adjustment);
|
||||
ret.totals.total_repairs = ret.totals.total_repairs.add(ret.totals.ttl_adjustment);
|
||||
ret.totals.net_repairs = ret.totals.net_repairs.add(ret.totals.ttl_adjustment);
|
||||
logger.log("job-totals-USA-ttl-adj", "DEBUG", null, job.id, {
|
||||
adjAmount: ttlDifference
|
||||
});
|
||||
}
|
||||
|
||||
//Taxes Scrubbing
|
||||
const emsTaxTotal = job.cieca_ttl.data.g_tax;
|
||||
const totalUsTaxes =
|
||||
(ret.totals.us_sales_tax_breakdown.ty1Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty2Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty3Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty4Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty5Tax.getAmount()) /
|
||||
100;
|
||||
const ttlTaxDifference = emsTaxTotal - totalUsTaxes;
|
||||
|
||||
if (Math.abs(ttlTaxDifference) > 0.0) {
|
||||
//If difference is greater than a pennny, we need to adjust it.
|
||||
ret.totals.ttl_tax_adjustment = Dinero({ amount: Math.round(ttlTaxDifference * 100) });
|
||||
ret.totals.total_repairs = ret.totals.total_repairs.add(ret.totals.ttl_tax_adjustment);
|
||||
ret.totals.net_repairs = ret.totals.net_repairs.add(ret.totals.ttl_tax_adjustment);
|
||||
logger.log("job-totals-USA-ttl-tax-adj", "DEBUG", null, job.id, {
|
||||
adjAmount: ttlTaxDifference
|
||||
});
|
||||
if (Math.abs(ttlTaxDifference) > 0.0) {
|
||||
//If difference is greater than a pennny, we need to adjust it.
|
||||
ret.totals.ttl_tax_adjustment = Dinero({ amount: Math.round(ttlTaxDifference * 100) });
|
||||
ret.totals.total_repairs = ret.totals.total_repairs.add(ret.totals.ttl_tax_adjustment);
|
||||
ret.totals.net_repairs = ret.totals.net_repairs.add(ret.totals.ttl_tax_adjustment);
|
||||
logger.log("job-totals-USA-ttl-tax-adj", "DEBUG", null, job.id, {
|
||||
adjAmount: ttlTaxDifference
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (error) {
|
||||
logger.log("job-totals-ssu-USA-error", "ERROR", req.user?.email, job.id, {
|
||||
jobid: job.id,
|
||||
error
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
@@ -150,7 +155,8 @@ async function Totals(req, res) {
|
||||
} catch (error) {
|
||||
logger.log("job-totals-USA-error", "ERROR", req.user.email, job.id, {
|
||||
jobid: job.id,
|
||||
error
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
res.status(400).send(JSON.stringify(error));
|
||||
}
|
||||
@@ -1075,7 +1081,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log("job-totals-USA - PFP Calculation Error", "error", null, job.id, {
|
||||
error: error.message
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user