Merged in release/2022-04-08 (pull request #443)

Release/2022 04 08
This commit is contained in:
Patrick Fic
2022-04-08 20:42:13 +00:00
49 changed files with 431 additions and 198 deletions

View File

@@ -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>

View File

@@ -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>
);
},
},

View File

@@ -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>
);
},
},

View File

@@ -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>
) : (

View File

@@ -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>
))}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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"),

View File

@@ -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"),

View File

@@ -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,
},

View File

@@ -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>
);
},
},

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>
);
}

View File

@@ -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) => {

View File

@@ -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>

View File

@@ -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 ||

View File

@@ -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" }}>

View File

@@ -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>
);
},
},

View File

@@ -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>
);
},
},

View File

@@ -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>
);
},
},

View File

@@ -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() } });

View File

@@ -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();
}

View File

@@ -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}

View File

@@ -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>

View File

@@ -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>
),
},

View File

@@ -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>
);
},
},

View File

@@ -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>
)}

View File

@@ -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,

View File

@@ -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}

View File

@@ -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>

View File

@@ -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"]}>

View File

@@ -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={[

View File

@@ -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>
),
},
{

View File

@@ -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")
);

View File

@@ -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>
),
},

View File

@@ -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 }) {

View File

@@ -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

View File

@@ -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
}
}
}
}
`;

View File

@@ -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 || ""

View File

@@ -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}`
)
);

View File

@@ -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}`
)
);

View File

@@ -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>
);
},
},

View File

@@ -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",

View File

@@ -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": "",

View File

@@ -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": "",

View File

@@ -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

View File

@@ -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';

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "last_name_first" boolean
not null default 'false';