From ec45454b3d7daad7d1eba29bd2e86d989f0da8e1 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 13 Apr 2023 09:25:52 -0700 Subject: [PATCH] IO-2244 Restrict claimable productive hours based on remaining hours --- bodyshop_translations.babel | 189 ++++++++++++++++++ .../labor-allocations-table.utility.js | 4 - .../shop-info/shop-info.general.component.jsx | 7 + .../tech-job-clock-out-button.component.jsx | 67 ++++++- .../time-ticket-modal.component.jsx | 79 ++++++-- client/src/graphql/bodyshop.queries.js | 2 + client/src/translations/en_us/common.json | 6 +- client/src/translations/es/common.json | 5 +- client/src/translations/fr/common.json | 5 +- hasura/metadata/tables.yaml | 26 ++- .../down.sql | 4 + .../up.sql | 2 + 12 files changed, 360 insertions(+), 36 deletions(-) create mode 100644 hasura/migrations/1681331289298_alter_table_public_bodyshops_add_column_tt_enforce_hours_for_tech_console/down.sql create mode 100644 hasura/migrations/1681331289298_alter_table_public_bodyshops_add_column_tt_enforce_hours_for_tech_console/up.sql diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index 23707d6e7..f453df8c6 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -8864,6 +8864,27 @@ + + tt_enforce_hours_for_tech_console + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + use_fippa false @@ -17310,6 +17331,27 @@ + + total + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + totals false @@ -33806,6 +33848,27 @@ errors + + deleting + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + noaccess false @@ -34367,6 +34430,27 @@ + + deleteconfirm + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + existing_owners false @@ -34477,6 +34561,27 @@ successes + + delete + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + save false @@ -44980,6 +45085,27 @@ + + hoursenteredmorethanavailable + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + @@ -47292,6 +47418,27 @@ errors + + deleting + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + noaccess false @@ -47916,6 +48063,27 @@ labels + + deleteconfirm + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + fromvehicle false @@ -48005,6 +48173,27 @@ successes + + delete + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + save false diff --git a/client/src/components/labor-allocations-table/labor-allocations-table.utility.js b/client/src/components/labor-allocations-table/labor-allocations-table.utility.js index 2ce5b4a0b..d236de913 100644 --- a/client/src/components/labor-allocations-table/labor-allocations-table.utility.js +++ b/client/src/components/labor-allocations-table/labor-allocations-table.utility.js @@ -6,10 +6,6 @@ export const CalculateAllocationsTotals = ( timetickets, adjustments = [] ) => { - console.log( - "🚀 ~ file: labor-allocations-table.utility.js ~ line 9 ~ adjustments", - adjustments - ); const responsibilitycenters = bodyshop.md_responsibility_centers; const jobCodes = joblines.map((item) => item.mod_lbr_ty); //.filter((value, index, self) => self.indexOf(value) === index && !!value); diff --git a/client/src/components/shop-info/shop-info.general.component.jsx b/client/src/components/shop-info/shop-info.general.component.jsx index 3e9b1ed2c..32ac5aa5d 100644 --- a/client/src/components/shop-info/shop-info.general.component.jsx +++ b/client/src/components/shop-info/shop-info.general.component.jsx @@ -589,6 +589,13 @@ export default function ShopInfoGeneral({ form }) { > + + + e.id === (technician && technician.id) @@ -129,6 +141,51 @@ export function TechClockOffButton({ required: true, //message: t("general.validation.required"), }, + ({ getFieldValue }) => ({ + validator(rule, value) { + console.log( + bodyshop.tt_enforce_hours_for_tech_console + ); + if (!bodyshop.tt_enforce_hours_for_tech_console) { + return Promise.resolve(); + } + if ( + !value || + getFieldValue("cost_center") === null || + !lineTicketData + ) + return Promise.resolve(); + + //Check the cost center, + const totals = CalculateAllocationsTotals( + bodyshop, + lineTicketData.joblines, + lineTicketData.timetickets, + lineTicketData.jobs_by_pk.lbr_adjustments + ); + + const fieldTypeToCheck = + bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber + ? "mod_lbr_ty" + : "cost_center"; + + const costCenterDiff = totals.find( + (total) => + total[fieldTypeToCheck] === + getFieldValue("cost_center") + )?.difference; + + if (value > costCenterDiff) + return Promise.reject( + t( + "timetickets.validation.hoursenteredmorethanavailable" + ) + ); + else { + return Promise.resolve(); + } + }, + }), ]} > @@ -178,7 +235,11 @@ export function TechClockOffButton({ {!isShiftTicket && ( - + )} diff --git a/client/src/components/time-ticket-modal/time-ticket-modal.component.jsx b/client/src/components/time-ticket-modal/time-ticket-modal.component.jsx index 6f61fccf0..6451a2c94 100644 --- a/client/src/components/time-ticket-modal/time-ticket-modal.component.jsx +++ b/client/src/components/time-ticket-modal/time-ticket-modal.component.jsx @@ -1,4 +1,4 @@ -import { useQuery } from "@apollo/client"; +import { useLazyQuery, useQuery } from "@apollo/client"; import { Form, Input, InputNumber, Select, Switch } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; @@ -18,6 +18,7 @@ import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component"; import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component"; import TimeTicketList from "../time-ticket-list/time-ticket-list.component"; +import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -38,7 +39,11 @@ export function TimeTicketModalComponent({ employeeSelectDisabled, }) { const { t } = useTranslation(); - + const [loadLineTicketData, { called, loading, data: lineTicketData }] = + useLazyQuery(GET_LINE_TICKET_BY_PK, { + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + }); const CostCenterSelect = ({ emps, value, ...props }) => { return (