Merge remote-tracking branch 'origin/master-AIO' into feature/IO-3255-simplified-part-management

# Conflicts:
#	client/src/components/jobs-detail-header/jobs-detail-header.component.jsx
This commit is contained in:
Dave Richer
2025-07-07 11:18:16 -04:00
10 changed files with 3992 additions and 3974 deletions

View File

@@ -1,5 +1,5 @@
import { Form, Statistic, Tooltip } from "antd"; import { Form, Statistic, Tooltip } from "antd";
import React, { useMemo } from "react"; import { useMemo } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";

View File

@@ -343,7 +343,11 @@ export function JobsDetailHeader({ job, bodyshop, disabled, insertAuditTrail, pa
</Col> </Col>
{!partsManagementOnly && ( {!partsManagementOnly && (
<Col {...colSpan}> <Col {...colSpan}>
<Card style={{ height: "100%" }} title={t("jobs.labels.employeeassignments")}> <Card
style={{ height: "100%" }}
title={<span id="job-employee-assignments-title">{t("jobs.labels.employeeassignments")}</span>}
id={"job-employee-assignments"}
>
<div> <div>
<JobEmployeeAssignments job={job} /> <JobEmployeeAssignments job={job} />
<Divider style={{ margin: ".5rem" }} /> <Divider style={{ margin: ".5rem" }} />

View File

@@ -1,5 +1,5 @@
import { Col, Row } from "antd"; import { Col, Row } from "antd";
import React, { useEffect } from "react"; import { useEffect } from "react";
import ScoreboardChart from "../scoreboard-chart/scoreboard-chart.component"; import ScoreboardChart from "../scoreboard-chart/scoreboard-chart.component";
import ScoreboardLastDays from "../scoreboard-last-days/scoreboard-last-days.component"; import ScoreboardLastDays from "../scoreboard-last-days/scoreboard-last-days.component";
import ScoreboardTargetsTable from "../scoreboard-targets-table/scoreboard-targets-table.component"; import ScoreboardTargetsTable from "../scoreboard-targets-table/scoreboard-targets-table.component";
@@ -26,18 +26,18 @@ export function ScoreboardDisplayComponent({ bodyshop }) {
start: dayjs().startOf("month"), start: dayjs().startOf("month"),
end: dayjs().endOf("month") end: dayjs().endOf("month")
}, },
pollInterval: 60000*5 pollInterval: 60000 * 5
}); });
const { data } = scoreboardSubscription; const { data } = scoreboardSubscription;
const client = useApolloClient(); const client = useApolloClient();
const scoreBoardlist = (data && data.scoreboard) || []; const scoreBoardlist = data?.scoreboard || [];
const sbEntriesByDate = {}; const sbEntriesByDate = {};
scoreBoardlist.forEach((i) => { scoreBoardlist.forEach((i) => {
const entryDate = i.date; const entryDate = i.date;
if (!!!sbEntriesByDate[entryDate]) { if (!sbEntriesByDate[entryDate]) {
sbEntriesByDate[entryDate] = []; sbEntriesByDate[entryDate] = [];
} }
sbEntriesByDate[entryDate].push(i); sbEntriesByDate[entryDate].push(i);
@@ -58,10 +58,9 @@ export function ScoreboardDisplayComponent({ bodyshop }) {
}); });
appointments = data.appointments; appointments = data.appointments;
} }
dayjs.updateLocale(dayjs.locale(), {
dayjs.updateLocale("ca", {
workingWeekdays: translateSettingsToWorkingDays(bodyshop.workingdays), workingWeekdays: translateSettingsToWorkingDays(bodyshop.workingdays),
...(appointments ...(appointments?.length
? { ? {
holidays: appointments.map((h) => dayjs(h.start).format("MM-DD-YYYY")) holidays: appointments.map((h) => dayjs(h.start).format("MM-DD-YYYY"))
} }
@@ -78,11 +77,9 @@ export function ScoreboardDisplayComponent({ bodyshop }) {
<Col span={24}> <Col span={24}>
<ScoreboardTargetsTable scoreBoardlist={scoreBoardlist} /> <ScoreboardTargetsTable scoreBoardlist={scoreBoardlist} />
</Col> </Col>
<Col span={24}> <Col span={24}>
<ScoreboardLastDays sbEntriesByDate={sbEntriesByDate} /> <ScoreboardLastDays sbEntriesByDate={sbEntriesByDate} />
</Col> </Col>
<Col span={24}> <Col span={24}>
<ScoreboardChart sbEntriesByDate={sbEntriesByDate} /> <ScoreboardChart sbEntriesByDate={sbEntriesByDate} />
</Col> </Col>

View File

@@ -1,13 +1,15 @@
import { DeleteFilled } from "@ant-design/icons"; import { DeleteFilled } from "@ant-design/icons";
import { useApolloClient, useMutation, useQuery } from "@apollo/client"; import { useApolloClient, useMutation, useQuery } from "@apollo/client";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { Button, Card, Form, Input, InputNumber, Select, Switch, Table } from "antd"; import { Button, Card, Form, Input, InputNumber, Select, Switch, Table } from "antd";
import { useForm } from "antd/es/form/Form"; import { useForm } from "antd/es/form/Form";
import dayjs from "../../utils/day"; import queryString from "query-string";
import React, { useEffect } from "react"; import { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation, useNavigate } from "react-router-dom"; import { useLocation, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { import {
CHECK_EMPLOYEE_NUMBER, CHECK_EMPLOYEE_NUMBER,
@@ -20,19 +22,17 @@ import {
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CiecaSelect from "../../utils/Ciecaselect"; import CiecaSelect from "../../utils/Ciecaselect";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component"; import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component"; import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component";
import queryString from "query-string";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = () => ({
//setUserLanguage: language => dispatch(setUserLanguage(language)) //setUserLanguage: language => dispatch(setUserLanguage(language))
}); });
@@ -83,7 +83,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
} }
} }
}) })
.then((r) => { .then(() => {
notification["success"]({ notification["success"]({
message: t("employees.successes.save") message: t("employees.successes.save")
}); });
@@ -120,13 +120,13 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
title: t("employees.fields.vacation.start"), title: t("employees.fields.vacation.start"),
dataIndex: "start", dataIndex: "start",
key: "start", key: "start",
render: (text, record) => <DateFormatter>{text}</DateFormatter> render: (text) => <DateFormatter>{text}</DateFormatter>
}, },
{ {
title: t("employees.fields.vacation.end"), title: t("employees.fields.vacation.end"),
dataIndex: "end", dataIndex: "end",
key: "end", key: "end",
render: (text, record) => <DateFormatter>{text}</DateFormatter> render: (text) => <DateFormatter>{text}</DateFormatter>
}, },
{ {
title: t("employees.fields.vacation.length"), title: t("employees.fields.vacation.length"),
@@ -210,7 +210,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
required: true required: true
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, },
({ getFieldValue }) => ({ () => ({
async validator(rule, value) { async validator(rule, value) {
if (value) { if (value) {
const response = await client.query({ const response = await client.query({
@@ -369,8 +369,9 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
add(); add();
}} }}
style={{ width: "100%" }} style={{ width: "100%" }}
id="add-employee-rate-button"
> >
{t("employees.actions.newrate")} <span id="new-employee-rate">{t("employees.actions.newrate")}</span>
</Button> </Button>
</Form.Item> </Form.Item>
</div> </div>

View File

@@ -14,6 +14,7 @@ import PhoneFormItem, { PhoneItemFormatterValidation } from "../form-items-forma
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component"; import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
// eslint-disable-next-line no-undef
const timeZonesList = Intl.supportedValuesOf("timeZone"); const timeZonesList = Intl.supportedValuesOf("timeZone");
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
@@ -143,236 +144,246 @@ export function ShopInfoGeneral({ form, bodyshop }) {
<InputNumber min={0} /> <InputNumber min={0} />
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<FeatureWrapper featureName="export" noauth={() => null}> <LayoutFormRow header={t("bodyshop.labels.accountingsetup")} id="accountingsetup">
<LayoutFormRow header={t("bodyshop.labels.accountingsetup")} id="accountingsetup"> {HasFeatureAccess({ featureName: "export", bodyshop }) && (
<Form.Item label={t("bodyshop.labels.qbo")} valuePropName="checked" name={["accountingconfig", "qbo"]}> <>
<Switch /> <Form.Item label={t("bodyshop.labels.qbo")} valuePropName="checked" name={["accountingconfig", "qbo"]}>
</Form.Item> <Switch />
{InstanceRenderManager({ </Form.Item>
imex: ( {InstanceRenderManager({
<Form.Item shouldUpdate noStyle> imex: (
{() => ( <Form.Item shouldUpdate noStyle>
{() => (
<Form.Item
label={t("bodyshop.labels.qbo_usa")}
shouldUpdate
valuePropName="checked"
name={["accountingconfig", "qbo_usa"]}
>
<Switch disabled={!form.getFieldValue(["accountingconfig", "qbo"])} />
</Form.Item>
)}
</Form.Item>
)
})}
<Form.Item label={t("bodyshop.labels.qbo_departmentid")} name={["accountingconfig", "qbo_departmentid"]}>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.labels.accountingtiers")}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
name={["accountingconfig", "tiers"]}
>
<Radio.Group>
<Radio value={2}>2</Radio>
<Radio value={3}>3</Radio>
</Radio.Group>
</Form.Item>
<Form.Item shouldUpdate>
{() => {
return (
<Form.Item <Form.Item
label={t("bodyshop.labels.qbo_usa")} label={t("bodyshop.labels.2tiersetup")}
shouldUpdate shouldUpdate
valuePropName="checked" rules={[
name={["accountingconfig", "qbo_usa"]} {
required: form.getFieldValue(["accountingconfig", "tiers"]) === 2
//message: t("general.validation.required"),
}
]}
name={["accountingconfig", "twotierpref"]}
> >
<Switch disabled={!form.getFieldValue(["accountingconfig", "qbo"])} /> <Radio.Group disabled={form.getFieldValue(["accountingconfig", "tiers"]) === 3}>
<Radio value="name">{t("bodyshop.labels.2tiername")}</Radio>
<Radio value="source">{t("bodyshop.labels.2tiersource")}</Radio>
</Radio.Group>
</Form.Item> </Form.Item>
)} );
</Form.Item> }}
) </Form.Item>
})} <Form.Item
<Form.Item label={t("bodyshop.labels.qbo_departmentid")} name={["accountingconfig", "qbo_departmentid"]}> label={t("bodyshop.labels.printlater")}
<Input /> valuePropName="checked"
</Form.Item> name={["accountingconfig", "printlater"]}
<Form.Item >
label={t("bodyshop.labels.accountingtiers")} <Switch />
rules={[ </Form.Item>
{ <Form.Item
required: true label={t("bodyshop.labels.emaillater")}
//message: t("general.validation.required"), valuePropName="checked"
} name={["accountingconfig", "emaillater"]}
]} >
name={["accountingconfig", "tiers"]} <Switch />
> </Form.Item>
<Radio.Group> </>
<Radio value={2}>2</Radio> )}
<Radio value={3}>3</Radio> <Form.Item
</Radio.Group> label={t("bodyshop.fields.inhousevendorid")}
</Form.Item> name={"inhousevendorid"}
<Form.Item shouldUpdate> rules={[
{() => { {
return ( required: true
//message: t("general.validation.required"),
}
]}
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.default_adjustment_rate")}
name={"default_adjustment_rate"}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber min={0} precision={2} />
</Form.Item>
{InstanceRenderManager({
imex: (
<Form.Item label={t("bodyshop.fields.federal_tax_id")} name="federal_tax_id">
<Input />
</Form.Item>
)
})}
<Form.Item label={t("bodyshop.fields.state_tax_id")} name="state_tax_id">
<Input />
</Form.Item>
{HasFeatureAccess({ featureName: "bills", bodyshop }) && (
<>
{InstanceRenderManager({
imex: (
<Form.Item <Form.Item
label={t("bodyshop.labels.2tiersetup")} label={t("bodyshop.fields.invoice_federal_tax_rate")}
shouldUpdate name={["bill_tax_rates", "federal_tax_rate"]}
rules={[ rules={[
{ {
required: form.getFieldValue(["accountingconfig", "tiers"]) === 2 required: true
//message: t("general.validation.required"), //message: t("general.validation.required"),
} }
]} ]}
name={["accountingconfig", "twotierpref"]}
> >
<Radio.Group disabled={form.getFieldValue(["accountingconfig", "tiers"]) === 3}> <InputNumber />
<Radio value="name">{t("bodyshop.labels.2tiername")}</Radio>
<Radio value="source">{t("bodyshop.labels.2tiersource")}</Radio>
</Radio.Group>
</Form.Item> </Form.Item>
); )
}} })}
</Form.Item> <Form.Item
<Form.Item label={t("bodyshop.fields.invoice_state_tax_rate")}
label={t("bodyshop.labels.printlater")} name={["bill_tax_rates", "state_tax_rate"]}
valuePropName="checked" rules={[
name={["accountingconfig", "printlater"]} {
> required: true
<Switch /> //message: t("general.validation.required"),
</Form.Item> }
<Form.Item ]}
label={t("bodyshop.labels.emaillater")} >
valuePropName="checked" <InputNumber />
name={["accountingconfig", "emaillater"]} </Form.Item>
> <Form.Item
<Switch /> label={t("bodyshop.fields.invoice_local_tax_rate")}
</Form.Item> name={["bill_tax_rates", "local_tax_rate"]}
<Form.Item rules={[
label={t("bodyshop.fields.inhousevendorid")} {
name={"inhousevendorid"} required: true
rules={[ //message: t("general.validation.required"),
{ }
required: true ]}
//message: t("general.validation.required"), >
} <InputNumber />
]} </Form.Item>
> </>
<Input /> )}
</Form.Item> <Form.Item
<Form.Item name={["md_payment_types"]}
label={t("bodyshop.fields.default_adjustment_rate")} label={t("bodyshop.fields.md_payment_types")}
name={"default_adjustment_rate"} rules={[
rules={[ {
{ required: true,
required: true //message: t("general.validation.required"),
//message: t("general.validation.required"), type: "array"
} }
]} ]}
> >
<InputNumber min={0} precision={2} /> <Select mode="tags" />
</Form.Item> </Form.Item>
{InstanceRenderManager({ <Form.Item
imex: ( name={["md_categories"]}
<Form.Item label={t("bodyshop.fields.federal_tax_id")} name="federal_tax_id"> label={t("bodyshop.fields.md_categories")}
rules={[
{
//message: t("general.validation.required"),
type: "array"
}
]}
>
<Select mode="tags" />
</Form.Item>
{HasFeatureAccess({ featureName: "export", bodyshop }) && (
<>
<Form.Item
name={["accountingconfig", "ReceivableCustomField1"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 1 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField2"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 2 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField3"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 3 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["md_classes"]}
label={t("bodyshop.fields.md_classes")}
rules={[
({ getFieldValue }) => {
return {
required: getFieldValue("enforce_class"),
//message: t("general.validation.required"),
type: "array"
};
}
]}
>
<Select mode="tags" />
</Form.Item>
<Form.Item name={["enforce_class"]} label={t("bodyshop.fields.enforce_class")} valuePropName="checked">
<Switch />
</Form.Item>
{ClosingPeriod.treatment === "on" && (
<Form.Item
name={["accountingconfig", "ClosingPeriod"]}
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")}
>
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
</Form.Item>
)}
{ADPPayroll.treatment === "on" && (
<Form.Item name={["accountingconfig", "companyCode"]} label={t("bodyshop.fields.companycode")}>
<Input /> <Input />
</Form.Item> </Form.Item>
) )}
})} {ADPPayroll.treatment === "on" && (
<Form.Item label={t("bodyshop.fields.state_tax_id")} name="state_tax_id"> <Form.Item name={["accountingconfig", "batchID"]} label={t("bodyshop.fields.batchid")}>
<Input /> <Input />
</Form.Item>
{InstanceRenderManager({
imex: (
<Form.Item
label={t("bodyshop.fields.invoice_federal_tax_rate")}
name={["bill_tax_rates", "federal_tax_rate"]}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber />
</Form.Item> </Form.Item>
) )}
})} </>
<Form.Item )}
label={t("bodyshop.fields.invoice_state_tax_rate")} </LayoutFormRow>
name={["bill_tax_rates", "state_tax_rate"]}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.invoice_local_tax_rate")}
name={["bill_tax_rates", "local_tax_rate"]}
rules={[
{
required: true
//message: t("general.validation.required"),
}
]}
>
<InputNumber />
</Form.Item>
<Form.Item
name={["md_payment_types"]}
label={t("bodyshop.fields.md_payment_types")}
rules={[
{
required: true,
//message: t("general.validation.required"),
type: "array"
}
]}
>
<Select mode="tags" />
</Form.Item>
<Form.Item
name={["md_categories"]}
label={t("bodyshop.fields.md_categories")}
rules={[
{
//message: t("general.validation.required"),
type: "array"
}
]}
>
<Select mode="tags" />
</Form.Item>
<Form.Item name={["enforce_class"]} label={t("bodyshop.fields.enforce_class")} valuePropName="checked">
<Switch />
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField1"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 1 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField2"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 2 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["accountingconfig", "ReceivableCustomField3"]}
label={t("bodyshop.fields.ReceivableCustomField", { number: 3 })}
>
{ReceivableCustomFieldSelect}
</Form.Item>
<Form.Item
name={["md_classes"]}
label={t("bodyshop.fields.md_classes")}
rules={[
({ getFieldValue }) => {
return {
required: getFieldValue("enforce_class"),
//message: t("general.validation.required"),
type: "array"
};
}
]}
>
<Select mode="tags" />
</Form.Item>
{ClosingPeriod.treatment === "on" && (
<Form.Item
name={["accountingconfig", "ClosingPeriod"]}
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")}
>
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
</Form.Item>
)}
{ADPPayroll.treatment === "on" && (
<Form.Item name={["accountingconfig", "companyCode"]} label={t("bodyshop.fields.companycode")}>
<Input />
</Form.Item>
)}
{ADPPayroll.treatment === "on" && (
<Form.Item name={["accountingconfig", "batchID"]} label={t("bodyshop.fields.batchid")}>
<Input />
</Form.Item>
)}
</LayoutFormRow>
</FeatureWrapper>
<FeatureWrapper featureName="scoreboard" noauth={() => null}> <FeatureWrapper featureName="scoreboard" noauth={() => null}>
<LayoutFormRow header={t("bodyshop.labels.scoreboardsetup")} id="scoreboardsetup"> <LayoutFormRow header={t("bodyshop.labels.scoreboardsetup")} id="scoreboardsetup">
<Form.Item <Form.Item
@@ -822,7 +833,11 @@ export function ShopInfoGeneral({ form, bodyshop }) {
}} }}
</Form.List> </Form.List>
</LayoutFormRow> </LayoutFormRow>
<LayoutFormRow grow header=<span id="insurancecos-header">{t("bodyshop.labels.insurancecos")}</span> id="insurancecos"> <LayoutFormRow
grow
header=<span id="insurancecos-header">{t("bodyshop.labels.insurancecos")}</span>
id="insurancecos"
>
<Form.List name={["md_ins_cos"]}> <Form.List name={["md_ins_cos"]}>
{(fields, { add, remove, move }) => { {(fields, { add, remove, move }) => {
return ( return (

View File

@@ -13,7 +13,7 @@ import { ColorPicker } from "./shop-info.rostatus.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop bodyshop: selectBodyshop
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = () => ({
//setUserLanguage: language => dispatch(setUserLanguage(language)) //setUserLanguage: language => dispatch(setUserLanguage(language))
}); });
@@ -22,7 +22,7 @@ export function ShopInfoSchedulingComponent({ form, bodyshop }) {
return ( return (
<div> <div>
<LayoutFormRow> <LayoutFormRow id="shopinfo-scheduling">
<Form.Item <Form.Item
label={t("bodyshop.fields.appt_length")} label={t("bodyshop.fields.appt_length")}
name={"appt_length"} name={"appt_length"}
@@ -44,6 +44,7 @@ export function ShopInfoSchedulingComponent({ form, bodyshop }) {
//message: t("general.validation.required"), //message: t("general.validation.required"),
} }
]} ]}
id="schedule_start_time"
> >
<TimePicker disableSeconds={true} format="HH:mm" /> <TimePicker disableSeconds={true} format="HH:mm" />
</Form.Item> </Form.Item>
@@ -56,6 +57,7 @@ export function ShopInfoSchedulingComponent({ form, bodyshop }) {
//message: t("general.validation.required"), //message: t("general.validation.required"),
} }
]} ]}
id="schedule_end_time"
> >
<TimePicker disableSeconds={true} format="HH:mm" /> <TimePicker disableSeconds={true} format="HH:mm" />
</Form.Item> </Form.Item>

View File

@@ -1,7 +1,7 @@
import Icon, { FieldTimeOutlined } from "@ant-design/icons"; import Icon, { FieldTimeOutlined } from "@ant-design/icons";
import { Card, Tabs } from "antd"; import { Card, Tabs } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useEffect } from "react"; import { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FaShieldAlt } from "react-icons/fa"; import { FaShieldAlt } from "react-icons/fa";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -78,7 +78,7 @@ export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
<RbacWrapper action="scoreboard:view"> <RbacWrapper action="scoreboard:view">
<Tabs <Tabs
activeKey={tab || "sb"} activeKey={tab || "sb"}
destroyInactiveTabPane destroyOnHidden
onChange={(key) => { onChange={(key) => {
searchParams.tab = key; searchParams.tab = key;
history({ history({

View File

@@ -381,7 +381,7 @@ async function CalculateRatesTotals({ job, client }) {
if (item.mod_lbr_ty) { if (item.mod_lbr_ty) {
//Check to see if it has 0 hours and a price instead. //Check to see if it has 0 hours and a price instead.
if (item.mod_lb_hrs === 0 && item.act_price > 0 && item.lbr_op === "OP14") { if (item.lbr_op === "OP14" && item.act_price > 0 && (!item.part_type || item.mod_lb_hrs === 0)) {
//Scenario where SGI may pay out hours using a part price. //Scenario where SGI may pay out hours using a part price.
if (!ret[item.mod_lbr_ty.toLowerCase()].total) { if (!ret[item.mod_lbr_ty.toLowerCase()].total) {
ret[item.mod_lbr_ty.toLowerCase()].total = Dinero(); ret[item.mod_lbr_ty.toLowerCase()].total = Dinero();

View File

@@ -314,7 +314,8 @@ function CalculateRatesTotals(ratesList) {
if (item.mod_lbr_ty) { if (item.mod_lbr_ty) {
//Check to see if it has 0 hours and a price instead. //Check to see if it has 0 hours and a price instead.
if (item.mod_lb_hrs === 0 && item.act_price > 0 && item.lbr_op === "OP14") { //Extend for when there are hours and a price.
if (item.lbr_op === "OP14" && item.act_price > 0 && (!item.part_type || item.mod_lb_hrs === 0)) {
//Scenario where SGI may pay out hours using a part price. //Scenario where SGI may pay out hours using a part price.
if (!ret[item.mod_lbr_ty.toLowerCase()].total) { if (!ret[item.mod_lbr_ty.toLowerCase()].total) {
ret[item.mod_lbr_ty.toLowerCase()].total = Dinero(); ret[item.mod_lbr_ty.toLowerCase()].total = Dinero();