Compare commits

...

29 Commits

Author SHA1 Message Date
Allan Carr
b2239351f6 IO-2952 RBAC Defaults
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-01-20 15:11:13 -08:00
Dave Richer
0e218abbf4 Merged in release/2025-01-17 (pull request #2067)
Release/2025 01 17 into master-AIO - IO-999 IO-1927 IO-2951 IO-3022 IO-3060 IO-3063 IO-3065 IO-3076 IO-3078 IO-3080 IO-3082 IO-3083 IO-3094 IO-3096
2025-01-18 04:04:26 +00:00
Dave Richer
0cf7961d7d Merged in hotfix/AdditionalProductFruitIds (pull request #2066)
hotfix/AdditionalProductFruitsIds - Add additional IDs for product fruits
2025-01-17 18:15:56 +00:00
Dave Richer
ca02937461 Merged in hotfix/AdditionalProductFruitIds (pull request #2064)
hotfix/AdditionalProductFruitsIds - Add additional IDs for product fruits
2025-01-17 18:14:26 +00:00
Dave Richer
fa7e0a107b hotfix/AdditionalProductFruitsIds - Add additional IDs for product fruits 2025-01-17 10:13:41 -08:00
Allan Carr
9ccffd73ba Merged in feature/IO-999-Part-Tax-rate-Label (pull request #2062)
IO-999 Part Tax Rate Label

Approved-by: Dave Richer
2025-01-17 17:53:05 +00:00
Dave Richer
f68ad181e4 feature/IO-999-Part-Tax-rate-Label 2025-01-17 09:52:35 -08:00
Dave Richer
23bd6085a8 feature/IO-3096-Global-Notifications-Preferences
-  Package Updates
2025-01-17 09:51:55 -08:00
Allan Carr
e4325e39bf Merged in feature/IO-2951-Ro-Guard-Labor-Warning (pull request #2061)
IO-2951 RO Guard Labor Warning

Approved-by: Dave Richer
2025-01-17 15:32:51 +00:00
Allan Carr
584c2e5de2 IO-999 Part Tax Rate Label
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-01-16 18:39:41 -08:00
Allan Carr
eccc992cfa IO-2951 RO Guard Labor Warning
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-01-16 18:28:54 -08:00
Allan Carr
f293e80d0d Merged in feature/IO-3063-LOU-on-Schedule-PopOver (pull request #2059)
IO-3063 LOU on Schedule PopOver

Approved-by: Dave Richer
2025-01-16 15:23:59 +00:00
Allan Carr
eea2a758b0 IO-3063 LOU on Schedule PopOver
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-01-15 17:14:08 -08:00
Allan Carr
8d7d4ab4ac Merged in feature/IO-3083-i18-Translation-Shop-Info-Warning (pull request #2044)
IO-3083 i18 Translation Warning in Shop Info

Approved-by: Dave Richer
2025-01-15 15:49:37 +00:00
Dave Richer
f9105806ba feature/IO-3083-i18-Translation-Shop-Info-Warning
resolve conflicts
2025-01-15 07:49:19 -08:00
Dave Richer
acd278f5b4 Merged in release/2025-01-17 (pull request #2057)
Release/2025 01 17 IO-3065, IO-3076, IO-3094
2025-01-15 15:40:44 +00:00
Allan Carr
a4a6fac224 Merged in feature/IO-3094-Purchases-by-Date-Excel (pull request #2056)
IO-3094 Purchases by Date - Excel Report

Approved-by: Dave Richer
2025-01-15 15:39:12 +00:00
Patrick Fic
b2b7064007 Merged in feature/IO-3065-0-dollar-parts-status (pull request #2055)
feature/IO-3065-0-dollar-parts-status

Approved-by: Dave Richer
2025-01-15 15:38:42 +00:00
Allan Carr
4a56fbb135 IO-3094 Purchases by Date - Excel Report
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-01-14 18:00:46 -08:00
Allan Carr
e1fcb0ecba IO-3083 Merge Conflit Resolution
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-01-14 17:54:12 -08:00
Allan Carr
ee5e091118 Merge branch 'release/2025-01-17' into feature/IO-3083-i18-Translation-Shop-Info-Warning
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>

# Conflicts:
#	client/src/translations/en_us/common.json
2025-01-14 17:48:10 -08:00
Dave Richer
494c8b6867 Merged in release/2025-01-17 (pull request #2053)
Release/2025 01 17 into test-AIO - IO-1927, IO-3022, IO-3060, IO-3078, IO-3080, IO-3082
2025-01-14 17:02:26 +00:00
Dave Richer
5fcb5a3a3e Merged in release/2025-01-17 (pull request #2051)
Release/2025 01 17
2025-01-14 01:44:03 +00:00
Patrick Fic
d187ed6f73 Merged in release/2025-01-10 (pull request #2049)
Release/2025 01 10
2025-01-10 22:03:04 +00:00
Patrick Fic
13a57406d9 Merged in release/2025-01-10 (pull request #2048)
Release/2025 01 10
2025-01-10 20:06:28 +00:00
Patrick Fic
68c1ac3e70 Merged in feature/IO-3076-daily-usage-reports (pull request #2047)
Feature/IO-3076 daily usage reports

Approved-by: Dave Richer
2025-01-10 19:47:37 +00:00
Allan Carr
54a9beb37f IO-3083 i18 Translation Warning in Shop Info
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2025-01-09 19:00:23 -08:00
Patrick Fic
91c3ac56fa Merged in release/2025-01-10 (pull request #2039)
Release/2025 01 10
2025-01-08 18:39:00 +00:00
Patrick Fic
7d21cb7d70 Merged in feature/IO-3067-implement-learn-more-link-for-rome-upsells (pull request #2037)
Revert "IO-3067 Add learn more link for Rome."
2025-01-07 18:24:52 +00:00
12 changed files with 11275 additions and 11246 deletions

View File

@@ -1,30 +1,30 @@
import { AlertFilled } from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import { Button, Divider, Dropdown, Form, Input, notification, Popover, Select, Space } from "antd";
import parsePhoneNumber from "libphonenumber-js";
import dayjs from "../../utils/day";
import queryString from "query-string";
import React, { useContext, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import dayjs from "../../utils/day";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import DataLabel from "../data-label/data-label.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component";
import ScheduleAtChange from "./job-at-change.component";
import ScheduleEventColor from "./schedule-event.color.component";
import ScheduleEventNote from "./schedule-event.note.component";
import { useMutation } from "@apollo/client";
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
@@ -127,6 +127,7 @@ export function ScheduleEventComponent({
<DataLabel label={t("jobs.fields.ownr_ph2")}>
<ChatOpenButton phone={event.job && event.job.ownr_ph2} jobid={event.job.id} />
</DataLabel>
<DataLabel hideIfNull label={t("jobs.fields.loss_of_use")}>{(event.job && event.job.loss_of_use) || ""}</DataLabel>
<DataLabel label={t("jobs.fields.alt_transport")}>
{(event.job && event.job.alt_transport) || ""}
<ScheduleAtChange job={event && event.job} />

View File

@@ -519,6 +519,7 @@ export function JobLinesComponent({
{selectedLines.length > 0 && ` (${selectedLines.length})`}
</Button>
<Button
id="job-lines-order-parts-button"
disabled={(job && !job.converted) || (selectedLines.length > 0 ? false : true) || jobRO || technician}
onClick={() => {
setPartsOrderContext({
@@ -541,6 +542,7 @@ export function JobLinesComponent({
{selectedLines.length > 0 && ` (${selectedLines.length})`}
</Button>
<Button
id="job-lines-filter-parts-only-button"
onClick={() => {
setState((state) => ({
...state,
@@ -554,7 +556,7 @@ export function JobLinesComponent({
<FilterFilled /> {t("jobs.actions.filterpartsonly")}
</Button>
<Dropdown menu={markMenu} trigger={["click"]}>
<Button>{t("jobs.actions.mark")}</Button>
<Button id="repair-data-mark-button">{t("jobs.actions.mark")}</Button>
</Dropdown>
<Button
disabled={jobRO || technician}

View File

@@ -982,7 +982,7 @@ export function JobsDetailRatesParts({ jobRO, expanded, required = true, form })
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow>
<LayoutFormRow header={t("jobs.labels.cieca_pfo")}>
<Form.Item label={t("jobs.fields.tax_tow_rt")} name="tax_tow_rt">
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
</Form.Item>

View File

@@ -1,6 +1,5 @@
import { EditFilled } from "@ant-design/icons";
import { Alert, Card, Col, Row, Space, Table, Typography } from "antd";
import _ from "lodash";
import React, { useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -9,11 +8,11 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort } from "../../utils/sorters";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import LaborAllocationsAdjustmentEdit from "../labor-allocations-adjustment-edit/labor-allocations-adjustment-edit.component";
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
import "./labor-allocations-table.styles.scss";
import { CalculateAllocationsTotals } from "./labor-allocations-table.utility";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
technician: selectTechnician
@@ -65,6 +64,7 @@ export function LaborAllocationsTable({
key: "total",
sorter: (a, b) => a.total - b.total,
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
align: "right",
render: (text, record) => record.total.toFixed(1)
},
{
@@ -73,6 +73,7 @@ export function LaborAllocationsTable({
key: "hrs_claimed",
sorter: (a, b) => a.claimed - b.claimed,
sortOrder: state.sortedInfo.columnKey === "claimed" && state.sortedInfo.order,
align: "right",
render: (text, record) => record.claimed && record.claimed.toFixed(1)
},
{
@@ -81,6 +82,7 @@ export function LaborAllocationsTable({
key: "adjustments",
sorter: (a, b) => a.adjustments - b.adjustments,
sortOrder: state.sortedInfo.columnKey === "adjustments" && state.sortedInfo.order,
align: "right",
render: (text, record) => (
<Space wrap>
{record.adjustments.toFixed(1)}
@@ -100,17 +102,17 @@ export function LaborAllocationsTable({
{
title: t("jobs.labels.difference"),
dataIndex: "difference",
key: "difference",
sorter: (a, b) => a.difference - b.difference,
sortOrder: state.sortedInfo.columnKey === "difference" && state.sortedInfo.order,
align: "right",
render: (text, record) => (
<strong
style={{
color: record.difference >= 0 ? "green" : "red"
color: record.difference.toFixed(1) >= 0 ? "green" : "red"
}}
>
{_.round(record.difference, 1)}
{(Math.abs(record.difference) < 0.05 ? 0 : record.difference).toFixed(1)}
</strong>
)
}
@@ -129,7 +131,6 @@ export function LaborAllocationsTable({
ellipsis: true,
render: (text, record) => `${record.op_code_desc || ""}${record.alt_partm ? ` ${record.alt_partm}` : ""}`
},
{
title: t("joblines.fields.act_price"),
dataIndex: "act_price",
@@ -187,7 +188,7 @@ export function LaborAllocationsTable({
{ hrs_total: 0, hrs_claimed: 0, adjustments: 0, difference: 0 }
);
if (summary.difference !== 0 && typeof warningCallback === "function") {
if (Math.abs(summary.difference.toFixed(1)) !== 0 && typeof warningCallback === "function") {
warningCallback({ key: "labor", warning: t("jobs.labels.outstandinghours") });
}
@@ -217,19 +218,21 @@ export function LaborAllocationsTable({
summary={() => (
<Table.Summary.Row>
<Table.Summary.Cell>
<Typography.Title level={4}>{t("general.labels.totals")}</Typography.Title>
<Typography.Title level={4} style={{ margin: 0, lineHeight: 1 }}>
{t("general.labels.totals")}
</Typography.Title>
</Table.Summary.Cell>
<Table.Summary.Cell>{summary.hrs_total.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell>{summary.hrs_claimed.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell>{summary.adjustments.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell>
<Table.Summary.Cell align="right">{summary.hrs_total.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell align="right">{summary.hrs_claimed.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell align="right">{summary.adjustments.toFixed(1)}</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<Typography.Text
style={{
fontWeight: "bold",
color: summary.difference >= 0 ? "green" : "red"
color: summary.difference.toFixed(1) >= 0 ? "green" : "red"
}}
>
{summary.difference.toFixed(1)}
{(Math.abs(summary.difference) < 0.05 ? 0 : summary.difference).toFixed(1)}
</Typography.Text>
</Table.Summary.Cell>
</Table.Summary.Row>
@@ -261,11 +264,10 @@ export function LaborAllocationsTable({
</Card>
</Col>
)}
{showWarning && summary.difference !== 0 && (
{showWarning && Math.abs(summary.difference.toFixed(1)) !== 0 && (
<Alert style={{ margin: "8px 0px" }} type="warning" message={t("jobs.labels.outstandinghours")} />
)}
</Row>
);
}
export default connect(mapStateToProps, null)(LaborAllocationsTable);

View File

@@ -38,7 +38,11 @@ export default function OwnerFindModalContainer({
}, [callSearchowners, modalProps.open, owner]);
return (
<Modal title={t("owners.labels.existing_owners")} width={"80%"} {...modalProps}>
<Modal
title={<span id="owner-find-modal-title">{t("owners.labels.existing_owners")}</span>}
width={"80%"}
{...modalProps}
>
{loading ? <LoadingSpinner /> : null}
{error ? <AlertComponent message={error.message} type="error" /> : null}
{owner ? (

View File

@@ -35,6 +35,7 @@ const ret = {
"bills:reexport": 3,
"employees:page": 5,
"employee_teams:page": 5,
"owners:list": 2,
"owners:detail": 3,
@@ -67,6 +68,9 @@ const ret = {
"timetickets:list": 3,
"timetickets:edit": 4,
"timetickets:shiftedit": 5,
"timetickets:editcommitted": 5,
"ttapprovals:view": 5,
"ttapprovals:approve": 5,
"users:editaccess": 4,

View File

@@ -555,7 +555,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
</Form.Item>
<Form.Item
name={["md_email_cc", "parts_order"]}
label={t("bodyshop.fields.md_email_cc", { template: "parts_order" })}
label={t("bodyshop.fields.md_email_cc", { template: "parts_orders" })}
rules={[
{
//message: t("general.validation.required"),
@@ -567,9 +567,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
</Form.Item>
<Form.Item
name={["md_email_cc", "parts_return_slip"]}
label={t("bodyshop.fields.md_email_cc", {
template: "parts_return_slip"
})}
label={t("bodyshop.fields.md_email_cc", { template: "parts_returns" })}
rules={[
{
//message: t("general.validation.required"),

View File

@@ -49,6 +49,7 @@ export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
est_ct_fn
est_ct_ln
comment
loss_of_use
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }) {
aggregate {
sum {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -2229,7 +2229,19 @@ export const TemplateList = (type, context) => {
field: i18n.t("jobs.fields.date_open")
},
group: "jobs"
}
},
purchases_by_date_excel: {
title: i18n.t("reportcenter.templates.purchases_by_date_excel"),
subject: i18n.t("reportcenter.templates.purchases_by_date_excel"),
key: "purchases_by_date_excel",
reporttype: "excel",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.bills"),
field: i18n.t("bills.fields.date")
},
group: "purchases"
},
}
: {}),
...(!type || type === "courtesycarcontract"