@@ -4388,6 +4388,27 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<concept_node>
|
||||
<name>last_name_first</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>lastnumberworkingdays</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -29965,6 +29986,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>cancelallappointments</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>closejob</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32672,6 +32714,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>notyetordered</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>oec</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -12,6 +12,7 @@ import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -76,14 +77,12 @@ export function AccountingPayablesTableComponent({
|
||||
render: (text, record) => {
|
||||
return record.job.owner ? (
|
||||
<Link to={"/manage/owners/" + record.job.owner.id}>
|
||||
{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
||||
record.job.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record.job} />
|
||||
</Link>
|
||||
) : (
|
||||
<span>{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
||||
record.job.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record.job} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -13,6 +13,8 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
@@ -85,14 +87,12 @@ export function AccountingReceivablesTableComponent({
|
||||
render: (text, record) => {
|
||||
return record.owner ? (
|
||||
<Link to={"/manage/owners/" + record.owner.id}>
|
||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</Link>
|
||||
) : (
|
||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import { selectSelectedConversation } from "../../redux/messaging/messaging.sele
|
||||
import { TimeAgoFormatter } from "../../utils/DateFormatter";
|
||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||
import "./chat-conversation-list.styles.scss";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
selectedConversation: selectSelectedConversation,
|
||||
@@ -40,9 +41,9 @@ export function ChatConversationListComponent({
|
||||
{item.job_conversations.length > 0 ? (
|
||||
<div className="chat-name">
|
||||
{item.job_conversations.map((j, idx) => (
|
||||
<div key={idx}>{`${j.job.ownr_fn || ""} ${
|
||||
j.job.ownr_ln || ""
|
||||
} ${j.job.ownr_co_nm || ""} `}</div>
|
||||
<div key={idx}>
|
||||
<OwnerNameDisplay ownerObject={j.job} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -4,6 +4,7 @@ import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { REMOVE_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function ChatConversationTitleTags({ jobConversations }) {
|
||||
const [removeJobConversation] = useMutation(REMOVE_CONVERSATION_TAG);
|
||||
@@ -45,9 +46,8 @@ export default function ChatConversationTitleTags({ jobConversations }) {
|
||||
onClose={() => handleRemoveTag(item.job.id)}
|
||||
>
|
||||
<Link to={`/manage/jobs/${item.job.id}`}>
|
||||
{`${item.job.ro_number || "?"} | ${item.job.ownr_fn || ""} ${
|
||||
item.job.ownr_ln || ""
|
||||
} ${item.job.ownr_co_nm || ""}`}
|
||||
{`${item.job.ro_number || "?"} | `}
|
||||
<OwnerNameDisplay ownerObject={item.job} />
|
||||
</Link>
|
||||
</Tag>
|
||||
))}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { CloseCircleOutlined, LoadingOutlined } from "@ant-design/icons";
|
||||
import { Select, Empty, Space } from "antd";
|
||||
import { Empty, Select, Space } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function ChatTagRoComponent({
|
||||
roOptions,
|
||||
@@ -27,9 +28,7 @@ export default function ChatTagRoComponent({
|
||||
>
|
||||
{roOptions.map((item, idx) => (
|
||||
<Select.Option key={item.id || idx}>
|
||||
{` ${item.ro_number || ""} | ${item.ownr_fn || ""} ${
|
||||
item.ownr_ln || ""
|
||||
} ${item.ownr_co_nm || ""}`}
|
||||
{` ${item.ro_number || ""} | ${OwnerNameDisplayFunction(item)}`}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import DataLabel from "../data-label/data-label.component";
|
||||
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
export default function ContractJobBlock({ job }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
@@ -23,9 +23,7 @@ export default function ContractJobBlock({ job }) {
|
||||
} ${(job && job.v_model_desc) || ""}`}
|
||||
</DataLabel>
|
||||
<DataLabel label={t("jobs.fields.owner")}>
|
||||
{`${(job && job.ownr_fn) || ""} ${(job && job.ownr_ln) || ""} ${
|
||||
(job && job.ownr_co_nm) || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={job} />
|
||||
</DataLabel>
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -3,6 +3,7 @@ import React, { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function ContractsJobsComponent({
|
||||
loading,
|
||||
@@ -43,17 +44,7 @@ export default function ContractsJobsComponent({
|
||||
width: "25%",
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.owner ? (
|
||||
<span>
|
||||
{record.ownr_fn} {record.ownr_ln} {record.ownr_co_nm || ""}
|
||||
</span>
|
||||
) : (
|
||||
<span>{`${record.ownr_fn} ${record.ownr_ln} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
);
|
||||
},
|
||||
render: (text, record) => <OwnerNameDisplay ownerObject={record} />,
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
|
||||
@@ -12,17 +12,22 @@ import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import moment from "moment";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
setContractFinderContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "contractFinder" })),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ContractsList);
|
||||
|
||||
export function ContractsList({
|
||||
bodyshop,
|
||||
loading,
|
||||
contracts,
|
||||
refetch,
|
||||
@@ -72,7 +77,9 @@ export function ContractsList({
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "driver_ln" && state.sortedInfo.order,
|
||||
render: (text, record) =>
|
||||
`${record.driver_fn || ""} ${record.driver_ln || ""}`,
|
||||
bodyshop.last_name_first
|
||||
? `${record.driver_ln || ""}, ${record.driver_fn || ""}`
|
||||
: `${record.driver_fn || ""} ${record.driver_ln || ""}`,
|
||||
},
|
||||
{
|
||||
title: t("contracts.labels.vehicle"),
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { Table, Button, Input, Card, Space } from "antd";
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { Button, Card, Input, Space, Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
@@ -97,9 +99,9 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||
render: (text, record) =>
|
||||
record.cccontracts.length === 1 ? (
|
||||
<Link to={`/manage/jobs/${record.cccontracts[0].job.id}`}>
|
||||
{`${record.cccontracts[0].job.ro_number} - ${
|
||||
record.cccontracts[0].job.ownr_fn || ""
|
||||
} ${record.cccontracts[0].job.ownr_ln || ""} ${record.cccontracts[0].job.ownr_co_nm || ""}`}
|
||||
{`${
|
||||
record.cccontracts[0].job.ro_number
|
||||
} - ${OwnerNameDisplayFunction(record.cccontracts[0].job)}`}
|
||||
</Link>
|
||||
) : null,
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function CsiResponseListPaginated({
|
||||
refetch,
|
||||
@@ -48,14 +49,12 @@ export default function CsiResponseListPaginated({
|
||||
render: (text, record) => {
|
||||
return record.job.owner ? (
|
||||
<Link to={"/manage/owners/" + record.job.owner.id}>
|
||||
{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
||||
record.job.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record.job} />
|
||||
</Link>
|
||||
) : (
|
||||
<span>{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
||||
record.job.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record.job} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -7,7 +7,9 @@ import { Link } from "react-router-dom";
|
||||
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
|
||||
import OwnerNameDisplay, {
|
||||
OwnerNameDisplayFunction,
|
||||
} from "../owner-name-display/owner-name-display.component";
|
||||
export default function GlobalSearch() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -39,9 +41,9 @@ export default function GlobalSearch() {
|
||||
<Space size="small" split={<Divider type="vertical" />}>
|
||||
<strong>{job.ro_number || t("general.labels.na")}</strong>
|
||||
<span>{`${job.status || ""}`}</span>
|
||||
<span>{`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
|
||||
job.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={job} />
|
||||
</span>
|
||||
<span>{`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${
|
||||
job.v_model_desc || ""
|
||||
}`}</span>
|
||||
@@ -57,15 +59,13 @@ export default function GlobalSearch() {
|
||||
options: data.search_owners.map((owner) => {
|
||||
return {
|
||||
key: owner.id,
|
||||
value: `${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
|
||||
owner.ownr_co_nm || ""
|
||||
}`,
|
||||
value: OwnerNameDisplayFunction(owner),
|
||||
label: (
|
||||
<Link to={`/manage/owners/${owner.id}`}>
|
||||
<Space size="small" split={<Divider type="vertical" />} wrap>
|
||||
<span>{`${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
|
||||
owner.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={owner} />
|
||||
</span>
|
||||
<PhoneNumberFormatter>
|
||||
{owner.ownr_ph1}
|
||||
</PhoneNumberFormatter>
|
||||
|
||||
@@ -31,6 +31,7 @@ import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.
|
||||
import ScheduleAtChange from "./job-at-change.component";
|
||||
import ScheduleEventColor from "./schedule-event.color.component";
|
||||
import ScheduleEventNote from "./schedule-event.note.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -73,9 +74,9 @@ export function ScheduleEventComponent({
|
||||
</Space>
|
||||
) : (
|
||||
<Space>
|
||||
<strong>{`${(event.job && event.job.ownr_fn) || ""} ${
|
||||
(event.job && event.job.ownr_ln) || ""
|
||||
}`}</strong>
|
||||
<strong>
|
||||
<OwnerNameDisplay ownerObject={event.job} />
|
||||
</strong>
|
||||
<span style={{ margin: 4 }}>
|
||||
{`${(event.job && event.job.v_model_yr) || ""} ${
|
||||
(event.job && event.job.v_make_desc) || ""
|
||||
@@ -256,9 +257,9 @@ export function ScheduleEventComponent({
|
||||
<Space>
|
||||
{event.note && <AlertFilled className="production-alert" />}
|
||||
<strong>{`${event.job.ro_number || t("general.labels.na")}`}</strong>
|
||||
<span>{`${(event.job && event.job.ownr_fn) || ""} ${
|
||||
(event.job && event.job.ownr_ln) || ""
|
||||
} ${(event.job && event.job.ownr_co_nm) || ""}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={event.job} />
|
||||
</span>
|
||||
</Space>
|
||||
<Space>
|
||||
<span>
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Row, Col, Timeline, Typography, Space, Divider, Skeleton } from "antd";
|
||||
import React from "react";
|
||||
import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export default function JobLinesExpander({ jobline, jobid }) {
|
||||
const { t } = useTranslation();
|
||||
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
joblineid: jobline.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (loading) return <Skeleton />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
return (
|
||||
<Row>
|
||||
<Col md={24} lg={12}>
|
||||
<Typography.Title level={4}>
|
||||
{t("parts_orders.labels.parts_orders")}
|
||||
</Typography.Title>
|
||||
<Timeline>
|
||||
{data.parts_order_lines.length > 0 ? (
|
||||
data.parts_order_lines.map((line) => (
|
||||
<Timeline.Item key={line.id}>
|
||||
<Space split={<Divider type="vertical" />} wrap>
|
||||
<Link
|
||||
to={`/manage/jobs/${jobid}?partsorderid=${line.parts_order.id}`}
|
||||
>
|
||||
{line.parts_order.order_number}
|
||||
</Link>
|
||||
<DateFormatter>{line.parts_order.order_date}</DateFormatter>
|
||||
{line.parts_order.vendor.name}
|
||||
</Space>
|
||||
</Timeline.Item>
|
||||
))
|
||||
) : (
|
||||
<Timeline.Item>
|
||||
{t("parts_orders.labels.notyetordered")}
|
||||
</Timeline.Item>
|
||||
)}
|
||||
</Timeline>
|
||||
</Col>
|
||||
<Col md={24} lg={12}></Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,8 @@ import {
|
||||
SyncOutlined,
|
||||
WarningFilled,
|
||||
EditFilled,
|
||||
PlusCircleTwoTone,
|
||||
MinusCircleTwoTone,
|
||||
} from "@ant-design/icons";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import {
|
||||
@@ -38,6 +40,7 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re
|
||||
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
||||
import _ from "lodash";
|
||||
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
|
||||
import JobLinesExpander from "./job-lines-expander.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -449,6 +452,19 @@ export function JobLinesComponent({
|
||||
scroll={{
|
||||
x: true,
|
||||
}}
|
||||
expandable={{
|
||||
expandedRowRender: (record) => (
|
||||
<JobLinesExpander jobline={record} jobid={job.id} />
|
||||
),
|
||||
rowExpandable: (record) => true,
|
||||
expandRowByClick: true,
|
||||
expandIcon: ({ expanded, onExpand, record }) =>
|
||||
expanded ? (
|
||||
<MinusCircleTwoTone onClick={(e) => onExpand(record, e)} />
|
||||
) : (
|
||||
<PlusCircleTwoTone onClick={(e) => onExpand(record, e)} />
|
||||
),
|
||||
}}
|
||||
onRow={(record, rowIndex) => {
|
||||
return {
|
||||
onDoubleClick: (event) => {
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
SEARCH_JOBS_FOR_AUTOCOMPLETE,
|
||||
} from "../../graphql/jobs.queries";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
const { Option } = Select;
|
||||
|
||||
const JobSearchSelect = (
|
||||
@@ -86,11 +87,9 @@ const JobSearchSelect = (
|
||||
<span>
|
||||
{`${clm_no && o.clm_no ? `${o.clm_no} | ` : ""}${
|
||||
o.ro_number || t("general.labels.na")
|
||||
} | ${o.ownr_ln || ""} ${o.ownr_fn || ""} ${
|
||||
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""
|
||||
}| ${o.v_model_yr || ""} ${o.v_make_desc || ""} ${
|
||||
o.v_model_desc || ""
|
||||
}`}
|
||||
} | ${OwnerNameDisplayFunction(o)} | ${
|
||||
o.v_model_yr || ""
|
||||
} ${o.v_make_desc || ""} ${o.v_model_desc || ""}`}
|
||||
</span>
|
||||
<Tag>
|
||||
<strong>{o.status}</strong>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { connect } from "react-redux";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { CANCEL_APPOINTMENTS_BY_JOB_ID } from "../../graphql/appointments.queries";
|
||||
import { DELETE_JOB, UPDATE_JOB, VOID_JOB } from "../../graphql/jobs.queries";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
@@ -56,6 +57,7 @@ export function JobsDetailHeaderActions({
|
||||
const [deleteJob] = useMutation(DELETE_JOB);
|
||||
const [updateJob] = useMutation(UPDATE_JOB);
|
||||
const [voidJob] = useMutation(VOID_JOB);
|
||||
const [cancelAllAppointments] = useMutation(CANCEL_APPOINTMENTS_BY_JOB_ID);
|
||||
const jobInProduction = useMemo(() => {
|
||||
return bodyshop.md_ro_statuses.production_statuses.includes(job.status);
|
||||
}, [job, bodyshop.md_ro_statuses.production_statuses]);
|
||||
@@ -121,6 +123,39 @@ export function JobsDetailHeaderActions({
|
||||
>
|
||||
{t("jobs.actions.schedule")}
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled}
|
||||
>
|
||||
<Popconfirm
|
||||
title={t("general.labels.areyousure")}
|
||||
okText="Yes"
|
||||
cancelText="No"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled}
|
||||
onConfirm={async () => {
|
||||
const jobUpdate = await cancelAllAppointments({
|
||||
variables: {
|
||||
jobid: job.id,
|
||||
job: {
|
||||
date_scheduled: null,
|
||||
scheduled_in: null,
|
||||
scheduled_completion: null,
|
||||
status: bodyshop.md_ro_statuses.default_imported,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (!jobUpdate.errors) {
|
||||
notification["success"]({
|
||||
message: t("appointments.successes.canceled"),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}}
|
||||
getPopupContainer={(trigger) => trigger.parentNode}
|
||||
>
|
||||
{t("menus.jobsactions.cancelallappointments")}
|
||||
</Popconfirm>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
disabled={
|
||||
!!job.intakechecklist ||
|
||||
|
||||
@@ -22,6 +22,7 @@ import "./jobs-detail-header.styles.scss";
|
||||
import JobsRelatedRos from "../jobs-related-ros/jobs-related-ros.component";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
|
||||
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
@@ -64,9 +65,7 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
||||
${job.v_make_desc || ""}
|
||||
${job.v_model_desc || ""}`.trim();
|
||||
|
||||
const ownerTitle = `${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
|
||||
job.ownr_co_nm || ""
|
||||
}`.trim();
|
||||
const ownerTitle = OwnerNameDisplayFunction(job).trim();
|
||||
|
||||
return (
|
||||
<Row gutter={[16, 16]} style={{ alignItems: "stretch" }}>
|
||||
|
||||
@@ -4,6 +4,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function JobsFindModalComponent({
|
||||
selectedJob,
|
||||
@@ -43,15 +44,12 @@ export default function JobsFindModalComponent({
|
||||
render: (text, record) => {
|
||||
return record.owner ? (
|
||||
<Link to={"/manage/owners/" + record.owner.id}>
|
||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</Link>
|
||||
) : (
|
||||
// t("jobs.errors.noowner")
|
||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import StartChatButton from "../chat-open-button/chat-open-button.component";
|
||||
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -52,14 +52,12 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
||||
render: (text, record) => {
|
||||
return record.ownerid ? (
|
||||
<Link to={"/manage/owners/" + record.ownerid}>
|
||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</Link>
|
||||
) : (
|
||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -18,6 +18,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -141,14 +142,12 @@ export function JobsList({ bodyshop }) {
|
||||
to={"/manage/owners/" + record.owner.id}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</Link>
|
||||
) : (
|
||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ import { QUERY_SEARCH_OWNER_BY_IDX } from "../../graphql/owners.queries";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import OwnerFindModalComponent from "./owner-find-modal.component";
|
||||
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function OwnerFindModalContainer({
|
||||
loading,
|
||||
@@ -30,9 +31,7 @@ export default function OwnerFindModalContainer({
|
||||
|
||||
useEffect(() => {
|
||||
if (modalProps.visible && owner) {
|
||||
const s = `${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
|
||||
owner.ownr_co_nm || ""
|
||||
}`;
|
||||
const s = OwnerNameDisplayFunction(owner);
|
||||
|
||||
setSearchText(s.trim());
|
||||
callSearchowners({ variables: { search: s.trim() } });
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { store } from "../../redux/store";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(OwnerNameDisplay);
|
||||
|
||||
export function OwnerNameDisplay({ bodyshop, ownerObject }) {
|
||||
const emptyTest =
|
||||
ownerObject.ownr_fn + ownerObject.ownr_ln + ownerObject.ownr_co_nm;
|
||||
|
||||
if (!emptyTest || emptyTest === "null" || emptyTest.trim() === "")
|
||||
return "N/A";
|
||||
|
||||
if (bodyshop.last_name_first)
|
||||
return `${ownerObject.ownr_ln || ""}, ${ownerObject.ownr_fn || ""} ${
|
||||
ownerObject.ownr_co_nm || ""
|
||||
}`.trim();
|
||||
|
||||
return `${ownerObject.ownr_fn || ""} ${ownerObject.ownr_ln || ""} ${
|
||||
ownerObject.ownr_co_nm || ""
|
||||
}`.trim();
|
||||
}
|
||||
|
||||
export function OwnerNameDisplayFunction(ownerObject) {
|
||||
const emptyTest =
|
||||
ownerObject.ownr_fn + ownerObject.ownr_ln + ownerObject.ownr_co_nm;
|
||||
|
||||
if (!emptyTest || emptyTest === "null" || emptyTest.trim() === "")
|
||||
return "N/A";
|
||||
|
||||
const rdxStore = store.getState();
|
||||
|
||||
if (rdxStore.user.bodyshop.last_name_first)
|
||||
return `${ownerObject.ownr_ln || ""}, ${ownerObject.ownr_fn || ""} ${
|
||||
ownerObject.ownr_co_nm || ""
|
||||
}`.trim();
|
||||
|
||||
return `${ownerObject.ownr_fn || ""} ${ownerObject.ownr_ln || ""} ${
|
||||
ownerObject.ownr_co_nm || ""
|
||||
}`.trim();
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
SEARCH_OWNERS_FOR_AUTOCOMPLETE,
|
||||
} from "../../graphql/owners.queries";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
@@ -16,10 +17,8 @@ const OwnerSearchSelect = ({ value, onChange, onBlur, disabled }, ref) => {
|
||||
SEARCH_OWNERS_FOR_AUTOCOMPLETE
|
||||
);
|
||||
|
||||
const [
|
||||
callIdSearch,
|
||||
{ loading: idLoading, error: idError, data: idData },
|
||||
] = useLazyQuery(SEARCH_OWNERS_BY_ID_FOR_AUTOCOMPLETE);
|
||||
const [callIdSearch, { loading: idLoading, error: idError, data: idData }] =
|
||||
useLazyQuery(SEARCH_OWNERS_BY_ID_FOR_AUTOCOMPLETE);
|
||||
|
||||
const executeSearch = (v) => {
|
||||
callSearch(v);
|
||||
@@ -78,9 +77,7 @@ const OwnerSearchSelect = ({ value, onChange, onBlur, disabled }, ref) => {
|
||||
{theOptions
|
||||
? theOptions.map((o) => (
|
||||
<Option key={o.id} value={o.id}>
|
||||
{`${o.ownr_ln || ""} ${o.ownr_fn || ""} ${
|
||||
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""
|
||||
}| ${o.ownr_addr1 || ""} `}
|
||||
{`${OwnerNameDisplayFunction(o)} | ${o.ownr_addr1 || ""} `}
|
||||
</Option>
|
||||
))
|
||||
: null}
|
||||
|
||||
@@ -3,6 +3,10 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||
import OwnerNameDisplay, {
|
||||
OwnerNameDisplayFunction,
|
||||
} from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function OwnerTagPopoverComponent({ job }) {
|
||||
const { t } = useTranslation();
|
||||
const content = (
|
||||
@@ -10,9 +14,9 @@ export default function OwnerTagPopoverComponent({ job }) {
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<Descriptions title={t("owners.labels.fromclaim")} column={1}>
|
||||
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>{`${
|
||||
job.ownr_fn || ""
|
||||
} ${job.ownr_ln || ""} ${job.ownr_co_nm || ""}`}</Descriptions.Item>
|
||||
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>
|
||||
<OwnerNameDisplay ownerObject={job} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph1")}>
|
||||
<PhoneFormatter>{job.ownr_ph1 || ""}</PhoneFormatter>
|
||||
</Descriptions.Item>
|
||||
@@ -31,11 +35,9 @@ export default function OwnerTagPopoverComponent({ job }) {
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Descriptions title={t("owners.labels.fromowner")} column={1}>
|
||||
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>{`${
|
||||
job.owner.ownr_fn || ""
|
||||
} ${job.owner.ownr_ln || ""} ${
|
||||
job.owner.ownr_co_nm || ""
|
||||
}`}</Descriptions.Item>
|
||||
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>
|
||||
<OwnerNameDisplay ownerObject={job.owner} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph1")}>
|
||||
<PhoneFormatter>{job.owner.ownr_ph1 || ""}</PhoneFormatter>
|
||||
</Descriptions.Item>
|
||||
@@ -68,9 +70,7 @@ export default function OwnerTagPopoverComponent({ job }) {
|
||||
<Popover placement="bottom" content={content}>
|
||||
<Tag color="cyan">
|
||||
<Link to={`/manage/owners/${job.owner.id}`}>
|
||||
{job.owner
|
||||
? `${job.ownr_co_nm || ""}${job.ownr_fn || ""} ${job.ownr_ln || ""}`
|
||||
: t("jobs.errors.noowner")}
|
||||
{job.owner ? OwnerNameDisplayFunction(job) : t("jobs.errors.noowner")}
|
||||
</Link>
|
||||
</Tag>
|
||||
</Popover>
|
||||
|
||||
@@ -5,6 +5,7 @@ import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function OwnersListComponent({
|
||||
loading,
|
||||
@@ -33,9 +34,7 @@ export default function OwnersListComponent({
|
||||
key: "name",
|
||||
render: (text, record) => (
|
||||
<Link to={"/manage/owners/" + record.id}>
|
||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@ import { alphaSort } from "../../utils/sorters";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import CaBcEtfTableModalContainer from "../ca-bc-etf-table-modal/ca-bc-etf-table-modal.container";
|
||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const stripeTestEnv = process.env.REACT_APP_STRIPE_PUBLIC_KEY; //.includes("test");
|
||||
|
||||
@@ -78,14 +79,12 @@ export function PaymentsListPaginated({
|
||||
render: (text, record) => {
|
||||
return record.job.owner ? (
|
||||
<Link to={"/manage/owners/" + record.job.owner.id}>
|
||||
{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
||||
record.job.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</Link>
|
||||
) : (
|
||||
<span>{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
||||
record.job.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -13,6 +13,7 @@ import ProductionListColumnProductionNote from "../production-list-columns/produ
|
||||
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
||||
import "./production-board-card.styles.scss";
|
||||
import moment from "moment";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
export default function ProductionBoardCard(
|
||||
technician,
|
||||
@@ -87,9 +88,9 @@ export default function ProductionBoardCard(
|
||||
card.ownr_co_nm || ""
|
||||
}`}</div>
|
||||
) : (
|
||||
<div className="ellipses">{`${card.ownr_ln || ""}, ${
|
||||
card.ownr_fn || ""
|
||||
} ${card.ownr_co_nm || ""}`}</div>
|
||||
<div className="ellipses">
|
||||
<OwnerNameDisplay ownerObject={card} />
|
||||
</div>
|
||||
)}
|
||||
</Col>
|
||||
)}
|
||||
|
||||
@@ -22,6 +22,7 @@ import ProductionListColumnCategory from "./production-list-columns.status.categ
|
||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
||||
import ProductionListColumnComment from "./production-list-columns.comment.component";
|
||||
import ProductionListColumnPartsReceived from "./production-list-columns.partsreceived.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
return [
|
||||
@@ -68,11 +69,7 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
dataIndex: "ownr",
|
||||
key: "ownr",
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
),
|
||||
render: (text, record) => <OwnerNameDisplay ownerObject={record} />,
|
||||
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
|
||||
|
||||
@@ -17,7 +17,7 @@ import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
|
||||
import JobAtChange from "../job-at-change/job-at-change.component";
|
||||
import { PrinterFilled } from "@ant-design/icons";
|
||||
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
@@ -107,9 +107,7 @@ export function ProductionListDetail({ jobs, setPrintCenterContext }) {
|
||||
{theJob.ins_co_nm || ""}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("jobs.fields.owner")}>
|
||||
{`${theJob.ownr_fn || ""} ${theJob.ownr_ln || ""} ${
|
||||
theJob.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={theJob} />
|
||||
<StartChatButton
|
||||
phone={data.jobs_by_pk.ownr_ph1}
|
||||
jobid={data.jobs_by_pk.id}
|
||||
|
||||
@@ -9,7 +9,7 @@ import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import "./schedule-production-list.styles.scss";
|
||||
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
export default function ScheduleProductionList() {
|
||||
const { t } = useTranslation();
|
||||
const [callQuery, { loading, error, data }] = useLazyQuery(
|
||||
@@ -36,9 +36,7 @@ export default function ScheduleProductionList() {
|
||||
<td>
|
||||
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
||||
</td>
|
||||
<td>{`${j.ownr_fn || ""} ${j.ownr_ln || ""} ${
|
||||
j.ownr_co_nm || ""
|
||||
}`}</td>
|
||||
<td><OwnerNameDisplay ownerObject={j} /></td>
|
||||
<td>{`${j.v_model_yr || ""} ${j.v_make_desc || ""} ${
|
||||
j.v_model_desc || ""
|
||||
}`}</td>
|
||||
|
||||
@@ -520,7 +520,6 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<CurrencyInput />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={["attach_pdf_to_email"]}
|
||||
label={t("bodyshop.fields.attach_pdf_to_email")}
|
||||
@@ -571,6 +570,13 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<Select mode="tags" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["last_name_first"]}
|
||||
label={t("bodyshop.fields.last_name_first")}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow header={t("bodyshop.labels.messagingpresets")}>
|
||||
<Form.List name={["md_messaging_presets"]}>
|
||||
|
||||
@@ -12,6 +12,7 @@ import AlertComponent from "../alert/alert.component";
|
||||
import DataLabel from "../data-label/data-label.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import TechClockOffButton from "../tech-job-clock-out-button/tech-job-clock-out-button.component";
|
||||
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
@@ -60,11 +61,9 @@ export function TechClockedInList({ technician }) {
|
||||
<Card
|
||||
title={
|
||||
<Link to={`/tech/joblookup?selected=${ticket.job.id}`}>
|
||||
{`${ticket.job.ro_number || t("general.labels.na")} ${
|
||||
ticket.job.ownr_fn || ""
|
||||
} ${ticket.job.ownr_ln || ""} ${
|
||||
ticket.job.ownr_co_nm || ""
|
||||
}`}
|
||||
{`${
|
||||
ticket.job.ro_number || t("general.labels.na")
|
||||
} ${OwnerNameDisplayFunction(ticket.job)}`}
|
||||
</Link>
|
||||
}
|
||||
actions={[
|
||||
|
||||
@@ -12,6 +12,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { onlyUnique } from "../../utils/arrayHelper";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -108,9 +109,9 @@ export function TechLookupJobsList({ bodyshop }) {
|
||||
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -237,7 +237,7 @@ export function TimeTicketModalComponent({
|
||||
return Promise.reject(
|
||||
t("timetickets.validation.clockoffwithoutclockon")
|
||||
);
|
||||
if (!value.isSameOrAfter(clockon))
|
||||
if (value && !value.isSameOrAfter(clockon))
|
||||
return Promise.reject(
|
||||
t("timetickets.validation.clockoffmustbeafterclockon")
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import VehicleDetailUpdateJobsComponent from "../vehicle-detail-update-jobs/vehicle-detail-update-jobs.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -34,9 +35,7 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
|
||||
key: "owner",
|
||||
render: (text, record) => (
|
||||
<Link to={`/manage/owners/${record.owner.id}`}>
|
||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -245,6 +245,27 @@ export const CANCEL_APPOINTMENT_BY_ID = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
export const CANCEL_APPOINTMENTS_BY_JOB_ID = gql`
|
||||
mutation CANCEL_APPOINTMENTS_BY_JOB_ID($jobid: uuid!, $job: jobs_set_input) {
|
||||
update_appointments(
|
||||
where: { _and: { jobid: { _eq: $jobid }, arrived: { _eq: false } } }
|
||||
_set: { canceled: true }
|
||||
) {
|
||||
returning {
|
||||
id
|
||||
canceled
|
||||
}
|
||||
}
|
||||
update_jobs_by_pk(pk_columns: { id: $jobid }, _set: $job) {
|
||||
date_scheduled
|
||||
id
|
||||
scheduled_in
|
||||
scheduled_completion
|
||||
status
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_APPOINTMENTS_BY_JOBID = gql`
|
||||
query QUERY_APPOINTMENTS_BY_JOBID($jobid: uuid!) {
|
||||
appointments(where: { jobid: { _eq: $jobid } }, order_by: { start: desc }) {
|
||||
|
||||
@@ -103,6 +103,7 @@ export const QUERY_BODYSHOP = gql`
|
||||
timezone
|
||||
ss_configuration
|
||||
md_from_emails
|
||||
last_name_first
|
||||
employees {
|
||||
user_email
|
||||
id
|
||||
@@ -203,6 +204,7 @@ export const UPDATE_SHOP = gql`
|
||||
timezone
|
||||
ss_configuration
|
||||
md_from_emails
|
||||
last_name_first
|
||||
employees {
|
||||
id
|
||||
first_name
|
||||
|
||||
@@ -146,7 +146,7 @@ export const QUERY_EXACT_JOB_IN_PRODUCTION = gql`
|
||||
employee_refinish
|
||||
employee_prep
|
||||
employee_csr
|
||||
joblines_status{
|
||||
joblines_status {
|
||||
part_type
|
||||
status
|
||||
count
|
||||
@@ -224,7 +224,7 @@ export const QUERY_EXACT_JOBS_IN_PRODUCTION = gql`
|
||||
employee_refinish
|
||||
employee_prep
|
||||
employee_csr
|
||||
joblines_status{
|
||||
joblines_status {
|
||||
part_type
|
||||
status
|
||||
count
|
||||
@@ -304,7 +304,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
|
||||
employee_prep
|
||||
employee_csr
|
||||
suspended
|
||||
joblines_status{
|
||||
joblines_status {
|
||||
part_type
|
||||
status
|
||||
count
|
||||
@@ -721,20 +721,6 @@ export const GET_JOB_BY_PK = gql`
|
||||
}
|
||||
}
|
||||
}
|
||||
parts_order_lines {
|
||||
id
|
||||
parts_order {
|
||||
id
|
||||
order_number
|
||||
comments
|
||||
order_date
|
||||
user_email
|
||||
vendor {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
payments {
|
||||
id
|
||||
@@ -2114,3 +2100,23 @@ export const DELETE_RELATED_RO = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const GET_JOB_LINE_ORDERS = gql`
|
||||
query GET_JOB_LINE_ORDERS($joblineid: uuid!) {
|
||||
parts_order_lines(where: { job_line_id: { _eq: $joblineid } }) {
|
||||
id
|
||||
act_price
|
||||
parts_order {
|
||||
id
|
||||
order_date
|
||||
order_number
|
||||
orderedby
|
||||
return
|
||||
comments
|
||||
vendor {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
setSelectedHeader,
|
||||
} from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -143,9 +144,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
<Link to={`/manage/jobs/${data && data.jobs_by_pk.id}`}>{`${
|
||||
data && data.jobs_by_pk && data.jobs_by_pk.ro_number
|
||||
}`}</Link>
|
||||
{` | ${data.jobs_by_pk.ownr_fn || ""} ${
|
||||
data.jobs_by_pk.ownr_ln || ""
|
||||
} ${data.jobs_by_pk.ownr_co_nm || ""} | ${
|
||||
{` | ${OwnerNameDisplayFunction(data.jobs_by_pk)} | ${
|
||||
data.jobs_by_pk.v_model_yr || ""
|
||||
} ${data.jobs_by_pk.v_make_desc || ""} ${
|
||||
data.jobs_by_pk.v_model_desc || ""
|
||||
|
||||
@@ -6,6 +6,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import { GET_JOB_BY_PK, UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import {
|
||||
@@ -78,11 +79,10 @@ function JobsDetailPageContainer({
|
||||
CreateRecentItem(
|
||||
jobId,
|
||||
"job",
|
||||
`${data.jobs_by_pk.ro_number || t("general.labels.na")} | ${
|
||||
data.jobs_by_pk.ownr_fn || ""
|
||||
} ${data.jobs_by_pk.ownr_ln || ""} ${
|
||||
data.jobs_by_pk.ownr_co_nm || ""
|
||||
}`,
|
||||
|
||||
`${
|
||||
data.jobs_by_pk.ro_number || t("general.labels.na")
|
||||
} | ${OwnerNameDisplayFunction(data.jobs_by_pk)}`,
|
||||
`/manage/jobs/${jobId}`
|
||||
)
|
||||
);
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
import { CreateRecentItem } from "../../utils/create-recent-item";
|
||||
import OwnersDetailComponent from "./owners-detail.page.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
@@ -38,11 +39,7 @@ export function OwnersDetailContainer({
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.owners-detail", {
|
||||
name: data
|
||||
? `${(data.owners_by_pk && data.owners_by_pk.ownr_fn) || ""} ${
|
||||
(data.owners_by_pk && data.owners_by_pk.ownr_ln) || ""
|
||||
} ${(data.owners_by_pk && data.owners_by_pk.ownr_co_nm) || ""}`
|
||||
: "",
|
||||
name: data ? OwnerNameDisplayFunction(data.owners_by_pk) : "",
|
||||
});
|
||||
setSelectedHeader("owners");
|
||||
setBreadcrumbs([
|
||||
@@ -50,11 +47,7 @@ export function OwnersDetailContainer({
|
||||
{
|
||||
link: `/manage/owners/${ownerId}`,
|
||||
label: t("titles.bc.owner-detail", {
|
||||
name: data
|
||||
? `${(data.owners_by_pk && data.owners_by_pk.ownr_fn) || ""} ${
|
||||
(data.owners_by_pk && data.owners_by_pk.ownr_ln) || ""
|
||||
} ${(data.owners_by_pk && data.owners_by_pk.ownr_co_nm) || ""}`
|
||||
: "",
|
||||
name: data ? OwnerNameDisplayFunction(data.owners_by_pk) : "",
|
||||
}),
|
||||
},
|
||||
]);
|
||||
@@ -64,9 +57,7 @@ export function OwnersDetailContainer({
|
||||
CreateRecentItem(
|
||||
ownerId,
|
||||
"owner",
|
||||
`${data.owners_by_pk.ownr_fn || ""} ${
|
||||
data.owners_by_pk.ownr_ln || ""
|
||||
} ${data.owners_by_pk.ownr_co_nm || ""}`,
|
||||
OwnerNameDisplayFunction(data.owners_by_pk),
|
||||
`/manage/owners/${ownerId}`
|
||||
)
|
||||
);
|
||||
|
||||
@@ -17,6 +17,7 @@ import { alphaSort } from "../../utils/sorters";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import queryString from "query-string";
|
||||
import _ from "lodash";
|
||||
import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -120,14 +121,12 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
||||
render: (text, record) => {
|
||||
return record.ownerid ? (
|
||||
<Link to={"/manage/owners/" + record.ownerid}>
|
||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</Link>
|
||||
) : (
|
||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
||||
record.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
@@ -275,6 +275,7 @@
|
||||
"mapa": "Job Costing - Paint Materials Hourly Cost Rate",
|
||||
"mash": "Job Costing - Shop Materials Hourly Cost Rate"
|
||||
},
|
||||
"last_name_first": "Display Owner Info as <Last>, <First>",
|
||||
"lastnumberworkingdays": "Scoreboard - Last Number of Working Days",
|
||||
"logo_img_footer_margin": "Footer Margin (px)",
|
||||
"logo_img_header_margin": "Header Margin (px)",
|
||||
@@ -1082,7 +1083,7 @@
|
||||
"mod_lbr_ty": "Labor Type",
|
||||
"notes": "Notes",
|
||||
"oem_partno": "OEM Part #",
|
||||
"op_code_desc": "Operation Code Description",
|
||||
"op_code_desc": "Op Code Description",
|
||||
"part_qty": "Qty.",
|
||||
"part_type": "Part Type",
|
||||
"part_types": {
|
||||
@@ -1759,6 +1760,7 @@
|
||||
},
|
||||
"jobsactions": {
|
||||
"admin": "Admin",
|
||||
"cancelallappointments": "Cancel all appointments",
|
||||
"closejob": "Close Job",
|
||||
"deletejob": "Delete Job",
|
||||
"duplicate": "Duplicate this Job",
|
||||
@@ -1939,6 +1941,7 @@
|
||||
"email": "Send by Email",
|
||||
"inthisorder": "Parts in this Order",
|
||||
"newpartsorder": "New Parts Order",
|
||||
"notyetordered": "This part has not yet been ordered.",
|
||||
"oec": "Order via OEC",
|
||||
"orderhistory": "Order History",
|
||||
"parts_orders": "Parts Orders",
|
||||
|
||||
@@ -275,6 +275,7 @@
|
||||
"mapa": "",
|
||||
"mash": ""
|
||||
},
|
||||
"last_name_first": "",
|
||||
"lastnumberworkingdays": "",
|
||||
"logo_img_footer_margin": "",
|
||||
"logo_img_header_margin": "",
|
||||
@@ -1759,6 +1760,7 @@
|
||||
},
|
||||
"jobsactions": {
|
||||
"admin": "",
|
||||
"cancelallappointments": "",
|
||||
"closejob": "",
|
||||
"deletejob": "",
|
||||
"duplicate": "",
|
||||
@@ -1939,6 +1941,7 @@
|
||||
"email": "Enviar por correo electrónico",
|
||||
"inthisorder": "Partes en este pedido",
|
||||
"newpartsorder": "",
|
||||
"notyetordered": "",
|
||||
"oec": "",
|
||||
"orderhistory": "Historial de pedidos",
|
||||
"parts_orders": "",
|
||||
|
||||
@@ -275,6 +275,7 @@
|
||||
"mapa": "",
|
||||
"mash": ""
|
||||
},
|
||||
"last_name_first": "",
|
||||
"lastnumberworkingdays": "",
|
||||
"logo_img_footer_margin": "",
|
||||
"logo_img_header_margin": "",
|
||||
@@ -1759,6 +1760,7 @@
|
||||
},
|
||||
"jobsactions": {
|
||||
"admin": "",
|
||||
"cancelallappointments": "",
|
||||
"closejob": "",
|
||||
"deletejob": "",
|
||||
"duplicate": "",
|
||||
@@ -1939,6 +1941,7 @@
|
||||
"email": "Envoyé par email",
|
||||
"inthisorder": "Pièces dans cette commande",
|
||||
"newpartsorder": "",
|
||||
"notyetordered": "",
|
||||
"oec": "",
|
||||
"orderhistory": "Historique des commandes",
|
||||
"parts_orders": "",
|
||||
|
||||
@@ -826,6 +826,7 @@
|
||||
- intakechecklist
|
||||
- jc_hourly_rates
|
||||
- jobsizelimit
|
||||
- last_name_first
|
||||
- logo_img_path
|
||||
- md_categories
|
||||
- md_ccc_rates
|
||||
@@ -909,6 +910,7 @@
|
||||
- insurance_vendor_id
|
||||
- intakechecklist
|
||||
- jc_hourly_rates
|
||||
- last_name_first
|
||||
- logo_img_path
|
||||
- md_categories
|
||||
- md_ccc_rates
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."bodyshops" add column "last_name_first" boolean
|
||||
-- not null default 'false';
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."bodyshops" add column "last_name_first" boolean
|
||||
not null default 'false';
|
||||
Reference in New Issue
Block a user