Compare commits
103 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90ea2cd699 | ||
|
|
94353bb342 | ||
|
|
1dfb309223 | ||
|
|
29c9fb37a1 | ||
|
|
41d6f0a4bc | ||
|
|
af70c80e09 | ||
|
|
b02d4e0fdd | ||
|
|
27bf8d9ed6 | ||
|
|
582ad03e05 | ||
|
|
babdfe4cc5 | ||
|
|
8a7a94dd70 | ||
|
|
2654519277 | ||
|
|
02eddcbbf4 | ||
|
|
b967bb6d4e | ||
|
|
f60870a087 | ||
|
|
39aa21d985 | ||
|
|
512bb5e013 | ||
|
|
7581b8634e | ||
|
|
78f041a34f | ||
|
|
2c456cbf03 | ||
|
|
da76021802 | ||
|
|
6de06e084b | ||
|
|
cb49c91983 | ||
|
|
b0df5fa91c | ||
|
|
0652404334 | ||
|
|
bd7d8068df | ||
|
|
4dd868130c | ||
|
|
71860cf899 | ||
|
|
3512905264 | ||
|
|
2c072a9e7a | ||
|
|
fee5bee569 | ||
|
|
0a1cdbdfe3 | ||
|
|
8af79989ff | ||
|
|
5d2bdc7ee1 | ||
|
|
255d65e47d | ||
|
|
f0805e0a79 | ||
|
|
c875ade35c | ||
|
|
31b4f4e561 | ||
|
|
9b485bfe45 | ||
|
|
91279c27fe | ||
|
|
2c1844fb13 | ||
|
|
3812a0650e | ||
|
|
b1c5bbb01f | ||
|
|
bd59e40761 | ||
|
|
f440a2b022 | ||
|
|
6262b3ff83 | ||
|
|
0652114013 | ||
|
|
307c77b30c | ||
|
|
3150647ff6 | ||
|
|
f1d7a98fe8 | ||
|
|
be259317f9 | ||
|
|
046d104bfa | ||
|
|
e2258bb91f | ||
|
|
9c693a2b74 | ||
|
|
2be0f3de09 | ||
|
|
3dd4b3dd77 | ||
|
|
de8c2cd5a2 | ||
|
|
b791f9846f | ||
|
|
daa7631056 | ||
|
|
d2f7585ea5 | ||
|
|
14b8a2daef | ||
|
|
90b38d817d | ||
|
|
ace48e2890 | ||
|
|
fb810be5d5 | ||
|
|
50230e9f50 | ||
|
|
86e14967ca | ||
|
|
c45c3b4037 | ||
|
|
c4c11528b9 | ||
|
|
1f9c4e92f1 | ||
|
|
371e148e09 | ||
|
|
33af544ded | ||
|
|
6b8d0ec91c | ||
|
|
5a3ddfad0f | ||
|
|
043c44ed51 | ||
|
|
6d5dbf3145 | ||
|
|
6d8463265c | ||
|
|
0669282432 | ||
|
|
1af511be2f | ||
|
|
bf4dc7e158 | ||
|
|
14b38604a3 | ||
|
|
5de2036fdb | ||
|
|
1629663e15 | ||
|
|
e25f2db2b1 | ||
|
|
cbf5d268ea | ||
|
|
a92a95a9fa | ||
|
|
0be7bf2c8e | ||
|
|
56b810dd40 | ||
|
|
40c7b706aa | ||
|
|
000ded6649 | ||
|
|
72181e1ff7 | ||
|
|
d73b1d2220 | ||
|
|
88c03ce655 | ||
|
|
8645b434c8 | ||
|
|
38a13bd082 | ||
|
|
3bc5f5d626 | ||
|
|
86a2351316 | ||
|
|
d5b1496898 | ||
|
|
3486e16d4e | ||
|
|
3641363d3d | ||
|
|
fde13436c9 | ||
|
|
b9a9f07d7b | ||
|
|
f4473d11a8 | ||
|
|
965af6da5f |
@@ -145,7 +145,11 @@
|
|||||||
|
|
||||||
//Update row highlighting on production board.
|
//Update row highlighting on production board.
|
||||||
.ant-table-tbody > tr.ant-table-row:hover > td {
|
.ant-table-tbody > tr.ant-table-row:hover > td {
|
||||||
background: #eaeaea !important;
|
background: #e7f3ff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody > tr.ant-table-row-selected > td {
|
||||||
|
background: #e6f7ff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.job-line-manual {
|
.job-line-manual {
|
||||||
@@ -156,3 +160,11 @@
|
|||||||
td.ant-table-column-sort {
|
td.ant-table-column-sort {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody > tr.ant-table-row:nth-child(2n) > td {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rowWithColor > td {
|
||||||
|
background-color: var(--bgColor) !important;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
import { useApolloClient, useMutation } from "@apollo/client";
|
import { useApolloClient, useMutation } from "@apollo/client";
|
||||||
import { Button, Checkbox, Form, Modal, notification, Space } from "antd";
|
import { Button, Checkbox, Form, Modal, Space, notification } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, { useEffect, useState, useMemo } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { INSERT_NEW_BILL } from "../../graphql/bills.queries";
|
import { INSERT_NEW_BILL } from "../../graphql/bills.queries";
|
||||||
|
import { UPDATE_INVENTORY_LINES } from "../../graphql/inventory.queries";
|
||||||
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
||||||
import {
|
import {
|
||||||
QUERY_JOB_LBR_ADJUSTMENTS,
|
QUERY_JOB_LBR_ADJUSTMENTS,
|
||||||
UPDATE_JOB,
|
UPDATE_JOB,
|
||||||
} from "../../graphql/jobs.queries";
|
} from "../../graphql/jobs.queries";
|
||||||
import { MUTATION_MARK_RETURN_RECEIVED } from "../../graphql/parts-orders.queries";
|
import { MUTATION_MARK_RETURN_RECEIVED } from "../../graphql/parts-orders.queries";
|
||||||
import { UPDATE_INVENTORY_LINES } from "../../graphql/inventory.queries";
|
|
||||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
|
import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
|
||||||
@@ -20,15 +20,15 @@ import {
|
|||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import confirmDialog from "../../utils/asyncConfirm";
|
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import BillFormContainer from "../bill-form/bill-form.container";
|
|
||||||
import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility";
|
|
||||||
import { handleUpload } from "../documents-upload/documents-upload.utility";
|
|
||||||
import { handleUpload as handleLocalUpload } from "../documents-local-upload/documents-local-upload.utility";
|
|
||||||
import useLocalStorage from "../../utils/useLocalStorage";
|
|
||||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
|
import confirmDialog from "../../utils/asyncConfirm";
|
||||||
|
import useLocalStorage from "../../utils/useLocalStorage";
|
||||||
|
import BillFormContainer from "../bill-form/bill-form.container";
|
||||||
|
import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility";
|
||||||
|
import { handleUpload as handleLocalUpload } from "../documents-local-upload/documents-local-upload.utility";
|
||||||
|
import { handleUpload } from "../documents-upload/documents-upload.utility";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
billEnterModal: selectBillEnterModal,
|
billEnterModal: selectBillEnterModal,
|
||||||
@@ -126,6 +126,17 @@ function BillEnterModalContainer({
|
|||||||
deductedfromlbr: deductedfromlbr,
|
deductedfromlbr: deductedfromlbr,
|
||||||
lbr_adjustment,
|
lbr_adjustment,
|
||||||
joblineid: i.joblineid === "noline" ? null : i.joblineid,
|
joblineid: i.joblineid === "noline" ? null : i.joblineid,
|
||||||
|
applicable_taxes: {
|
||||||
|
federal:
|
||||||
|
(i.applicable_taxes && i.applicable_taxes.federal) ||
|
||||||
|
false,
|
||||||
|
state:
|
||||||
|
(i.applicable_taxes && i.applicable_taxes.state) ||
|
||||||
|
false,
|
||||||
|
local:
|
||||||
|
(i.applicable_taxes && i.applicable_taxes.local) ||
|
||||||
|
false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
import { Badge, List, Tag } from "antd";
|
import { Badge, List, Tag } from "antd";
|
||||||
import React, { useEffect } from "react";
|
import React from "react";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
import {
|
||||||
|
AutoSizer,
|
||||||
|
CellMeasurer,
|
||||||
|
CellMeasurerCache,
|
||||||
|
List as VirtualizedList,
|
||||||
|
} from "react-virtualized";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { setSelectedConversation } from "../../redux/messaging/messaging.actions";
|
import { setSelectedConversation } from "../../redux/messaging/messaging.actions";
|
||||||
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
|
import { selectSelectedConversation } from "../../redux/messaging/messaging.selectors";
|
||||||
import { TimeAgoFormatter } from "../../utils/DateFormatter";
|
import { TimeAgoFormatter } from "../../utils/DateFormatter";
|
||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
import { List as VirtualizedList, AutoSizer } from "react-virtualized";
|
|
||||||
|
|
||||||
import "./chat-conversation-list.styles.scss";
|
import "./chat-conversation-list.styles.scss";
|
||||||
|
|
||||||
@@ -24,57 +29,66 @@ function ChatConversationListComponent({
|
|||||||
conversationList,
|
conversationList,
|
||||||
selectedConversation,
|
selectedConversation,
|
||||||
setSelectedConversation,
|
setSelectedConversation,
|
||||||
subscribeToMoreConversations,
|
|
||||||
loadMoreConversations,
|
loadMoreConversations,
|
||||||
}) {
|
}) {
|
||||||
useEffect(
|
const cache = new CellMeasurerCache({
|
||||||
() => subscribeToMoreConversations(),
|
fixedWidth: true,
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
defaultHeight: 60,
|
||||||
[]
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const rowRenderer = ({ index, key, style }) => {
|
const rowRenderer = ({ index, key, style, parent }) => {
|
||||||
const item = conversationList[index];
|
const item = conversationList[index];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<List.Item
|
<CellMeasurer
|
||||||
key={key}
|
key={key}
|
||||||
onClick={() => setSelectedConversation(item.id)}
|
cache={cache}
|
||||||
className={`chat-list-item ${
|
parent={parent}
|
||||||
item.id === selectedConversation
|
columnIndex={0}
|
||||||
? "chat-list-selected-conversation"
|
rowIndex={index}
|
||||||
: null
|
|
||||||
}`}
|
|
||||||
style={style}
|
|
||||||
>
|
>
|
||||||
<div sryle={{ display: "inline-block" }}>
|
<List.Item
|
||||||
{item.label && <div className="chat-name">{item.label}</div>}
|
onClick={() => setSelectedConversation(item.id)}
|
||||||
{item.job_conversations.length > 0 ? (
|
className={`chat-list-item ${
|
||||||
<div className="chat-name">
|
item.id === selectedConversation
|
||||||
{item.job_conversations.map((j, idx) => (
|
? "chat-list-selected-conversation"
|
||||||
<div key={idx}>
|
: null
|
||||||
<OwnerNameDisplay ownerObject={j.job} />
|
}`}
|
||||||
</div>
|
style={style}
|
||||||
))}
|
>
|
||||||
</div>
|
<div
|
||||||
) : (
|
style={{
|
||||||
<PhoneFormatter>{item.phone_num}</PhoneFormatter>
|
display: "inline-block",
|
||||||
)}
|
}}
|
||||||
</div>
|
>
|
||||||
<div sryle={{ display: "inline-block" }}>
|
{item.label && <div className="chat-name">{item.label}</div>}
|
||||||
<div>
|
{item.job_conversations.length > 0 ? (
|
||||||
{item.job_conversations.length > 0
|
<div className="chat-name">
|
||||||
? item.job_conversations.map((j, idx) => (
|
{item.job_conversations.map((j, idx) => (
|
||||||
<Tag key={idx} className="ro-number-tag">
|
<div key={idx}>
|
||||||
{j.job.ro_number}
|
<OwnerNameDisplay ownerObject={j.job} />
|
||||||
</Tag>
|
</div>
|
||||||
))
|
))}
|
||||||
: null}
|
</div>
|
||||||
|
) : (
|
||||||
|
<PhoneFormatter>{item.phone_num}</PhoneFormatter>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>
|
<div style={{ display: "inline-block" }}>
|
||||||
</div>
|
<div>
|
||||||
<Badge count={item.messages_aggregate.aggregate.count || 0} />
|
{item.job_conversations.length > 0
|
||||||
</List.Item>
|
? item.job_conversations.map((j, idx) => (
|
||||||
|
<Tag key={idx} className="ro-number-tag">
|
||||||
|
{j.job.ro_number}
|
||||||
|
</Tag>
|
||||||
|
))
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
|
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>
|
||||||
|
</div>
|
||||||
|
<Badge count={item.messages_aggregate.aggregate.count || 0} />
|
||||||
|
</List.Item>
|
||||||
|
</CellMeasurer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,7 +100,7 @@ function ChatConversationListComponent({
|
|||||||
height={height}
|
height={height}
|
||||||
width={width}
|
width={width}
|
||||||
rowCount={conversationList.length}
|
rowCount={conversationList.length}
|
||||||
rowHeight={60}
|
rowHeight={cache.rowHeight}
|
||||||
rowRenderer={rowRenderer}
|
rowRenderer={rowRenderer}
|
||||||
onScroll={({ scrollTop, scrollHeight, clientHeight }) => {
|
onScroll={({ scrollTop, scrollHeight, clientHeight }) => {
|
||||||
if (scrollTop + clientHeight === scrollHeight) {
|
if (scrollTop + clientHeight === scrollHeight) {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
ShrinkOutlined,
|
ShrinkOutlined,
|
||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { useLazyQuery, useSubscription } from "@apollo/client";
|
import { useLazyQuery, useQuery } from "@apollo/client";
|
||||||
import { Badge, Card, Col, Row, Space, Tag, Tooltip, Typography } from "antd";
|
import { Badge, Card, Col, Row, Space, Tag, Tooltip, Typography } from "antd";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -12,8 +12,7 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import {
|
import {
|
||||||
CONVERSATION_LIST_QUERY,
|
CONVERSATION_LIST_QUERY,
|
||||||
CONVERSATION_LIST_SUBSCRIPTION,
|
UNREAD_CONVERSATION_COUNT,
|
||||||
UNREAD_CONVERSATION_COUNT_SUBSCRIPTION,
|
|
||||||
} from "../../graphql/conversations.queries";
|
} from "../../graphql/conversations.queries";
|
||||||
import { toggleChatVisible } from "../../redux/messaging/messaging.actions";
|
import { toggleChatVisible } from "../../redux/messaging/messaging.actions";
|
||||||
import {
|
import {
|
||||||
@@ -42,19 +41,20 @@ export function ChatPopupComponent({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [pollInterval, setpollInterval] = useState(0);
|
const [pollInterval, setpollInterval] = useState(0);
|
||||||
|
|
||||||
const { data: unreadData } = useSubscription(
|
const { data: unreadData } = useQuery(UNREAD_CONVERSATION_COUNT, {
|
||||||
UNREAD_CONVERSATION_COUNT_SUBSCRIPTION
|
|
||||||
);
|
|
||||||
|
|
||||||
const [
|
|
||||||
getConversations,
|
|
||||||
{ loading, data, called, refetch, fetchMore, subscribeToMore },
|
|
||||||
] = useLazyQuery(CONVERSATION_LIST_QUERY, {
|
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
skip: !chatVisible,
|
...(pollInterval > 0 ? { pollInterval } : {}),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [getConversations, { loading, data, refetch, fetchMore }] =
|
||||||
|
useLazyQuery(CONVERSATION_LIST_QUERY, {
|
||||||
|
fetchPolicy: "network-only",
|
||||||
|
nextFetchPolicy: "network-only",
|
||||||
|
skip: !chatVisible,
|
||||||
|
...(pollInterval > 0 ? { pollInterval } : {}),
|
||||||
|
});
|
||||||
|
|
||||||
const fcmToken = sessionStorage.getItem("fcmtoken");
|
const fcmToken = sessionStorage.getItem("fcmtoken");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -66,13 +66,13 @@ export function ChatPopupComponent({
|
|||||||
}, [fcmToken]);
|
}, [fcmToken]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (called && chatVisible)
|
if (chatVisible)
|
||||||
getConversations({
|
getConversations({
|
||||||
variables: {
|
variables: {
|
||||||
offset: 0,
|
offset: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}, [chatVisible, called, getConversations]);
|
}, [chatVisible, getConversations]);
|
||||||
|
|
||||||
const loadMoreConversations = useCallback(() => {
|
const loadMoreConversations = useCallback(() => {
|
||||||
if (data)
|
if (data)
|
||||||
@@ -119,43 +119,6 @@ export function ChatPopupComponent({
|
|||||||
<ChatConversationListComponent
|
<ChatConversationListComponent
|
||||||
conversationList={data ? data.conversations : []}
|
conversationList={data ? data.conversations : []}
|
||||||
loadMoreConversations={loadMoreConversations}
|
loadMoreConversations={loadMoreConversations}
|
||||||
subscribeToMoreConversations={() =>
|
|
||||||
subscribeToMore({
|
|
||||||
document: CONVERSATION_LIST_SUBSCRIPTION,
|
|
||||||
variables: { offset: 0 },
|
|
||||||
updateQuery: (prev, { subscriptionData }) => {
|
|
||||||
if (
|
|
||||||
!subscriptionData.data ||
|
|
||||||
subscriptionData.data.conversations.length === 0
|
|
||||||
)
|
|
||||||
return prev;
|
|
||||||
|
|
||||||
let conversations = [...prev.conversations];
|
|
||||||
const newConversations =
|
|
||||||
subscriptionData.data.conversations;
|
|
||||||
|
|
||||||
for (const conversation of newConversations) {
|
|
||||||
const index = conversations.findIndex(
|
|
||||||
(prevConversation) =>
|
|
||||||
prevConversation.id === conversation.id
|
|
||||||
);
|
|
||||||
|
|
||||||
if (index !== -1) {
|
|
||||||
conversations.splice(index, 1);
|
|
||||||
conversations.unshift(conversation);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
conversations.unshift(conversation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Object.assign({}, prev, {
|
|
||||||
conversations: conversations,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
import {
|
||||||
|
BranchesOutlined,
|
||||||
|
ExclamationCircleFilled,
|
||||||
|
PauseCircleOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import { Card, Space, Table, Tooltip } from "antd";
|
||||||
|
import moment from "moment";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
||||||
|
import OwnerNameDisplay from "../../owner-name-display/owner-name-display.component";
|
||||||
|
import DashboardRefreshRequired from "../refresh-required.component";
|
||||||
|
|
||||||
|
export default function DashboardScheduledInToday({ data, ...cardProps }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [state, setState] = useState({
|
||||||
|
sortedInfo: {},
|
||||||
|
});
|
||||||
|
if (!data) return null;
|
||||||
|
if (!data.scheduled_in_today)
|
||||||
|
return <DashboardRefreshRequired {...cardProps} />;
|
||||||
|
|
||||||
|
const appt = []; // Flatten Data
|
||||||
|
data.scheduled_in_today.forEach((item) => {
|
||||||
|
var i = {
|
||||||
|
canceled: item.canceled,
|
||||||
|
id: item.id,
|
||||||
|
alt_transport: item.job.alt_transport,
|
||||||
|
clm_no: item.job.clm_no,
|
||||||
|
jobid: item.job.jobid,
|
||||||
|
ins_co_nm: item.job.ins_co_nm,
|
||||||
|
iouparent: item.job.iouparent,
|
||||||
|
ownerid: item.job.ownerid,
|
||||||
|
ownr_co_nm: item.job.ownr_co_nm,
|
||||||
|
ownr_ea: item.job.ownr_ea,
|
||||||
|
ownr_fn: item.job.ownr_fn,
|
||||||
|
ownr_ln: item.job.ownr_ln,
|
||||||
|
ownr_ph1: item.job.ownr_ph1,
|
||||||
|
ownr_ph2: item.job.ownr_ph2,
|
||||||
|
production_vars: item.job.production_vars,
|
||||||
|
ro_number: item.job.ro_number,
|
||||||
|
suspended: item.job.suspended,
|
||||||
|
v_make_desc: item.job.v_make_desc,
|
||||||
|
v_model_desc: item.job.v_model_desc,
|
||||||
|
v_model_yr: item.job.v_model_yr,
|
||||||
|
v_vin: item.job.v_vin,
|
||||||
|
vehicleid: item.job.vehicleid,
|
||||||
|
note: item.note,
|
||||||
|
start: moment(item.start).format("hh:mm a"),
|
||||||
|
title: item.title,
|
||||||
|
};
|
||||||
|
appt.push(i);
|
||||||
|
});
|
||||||
|
appt.sort ( function (a, b) { return new Date(a.start) - new Date(b.start); });
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ro_number"),
|
||||||
|
dataIndex: "ro_number",
|
||||||
|
key: "ro_number",
|
||||||
|
render: (text, record) => (
|
||||||
|
<Link
|
||||||
|
to={"/manage/jobs/" + record.jobid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
{record.ro_number || t("general.labels.na")}
|
||||||
|
{record.production_vars && record.production_vars.alert ? (
|
||||||
|
<ExclamationCircleFilled className="production-alert" />
|
||||||
|
) : null}
|
||||||
|
{record.suspended && (
|
||||||
|
<PauseCircleOutlined style={{ color: "orangered" }} />
|
||||||
|
)}
|
||||||
|
{record.iouparent && (
|
||||||
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
|
<BranchesOutlined style={{ color: "orangered" }} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.owner"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "owner",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.ownerid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/owners/" + record.ownerid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ownr_ph1"),
|
||||||
|
dataIndex: "ownr_ph1",
|
||||||
|
key: "ownr_ph1",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<ChatOpenButton phone={record.ownr_ph1} jobid={record.jobid} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ownr_ph2"),
|
||||||
|
dataIndex: "ownr_ph2",
|
||||||
|
key: "ownr_ph2",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<ChatOpenButton phone={record.ownr_ph2} jobid={record.jobid} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ownr_ea"),
|
||||||
|
dataIndex: "ownr_ea",
|
||||||
|
key: "ownr_ea",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<ChatOpenButton phone={record.ownr_ea} jobid={record.jobid} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.vehicle"),
|
||||||
|
dataIndex: "vehicle",
|
||||||
|
key: "vehicle",
|
||||||
|
ellipsis: true,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.vehicleid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/vehicles/" + record.vehicleid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ins_co_nm"),
|
||||||
|
dataIndex: "ins_co_nm",
|
||||||
|
key: "ins_co_nm",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.time"),
|
||||||
|
dataIndex: "start",
|
||||||
|
key: "start",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.alt_transport"),
|
||||||
|
dataIndex: "alt_transport",
|
||||||
|
key: "alt_transport",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleTableChange = (sorter) => {
|
||||||
|
setState({ ...state, sortedInfo: sorter });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card title={t("dashboard.titles.scheduledintoday", {date: moment().startOf("day").format("MM/DD/YYYY")})} {...cardProps}>
|
||||||
|
<div style={{ height: "100%" }}>
|
||||||
|
<Table
|
||||||
|
onChange={handleTableChange}
|
||||||
|
pagination={{ position: "top", defaultPageSize: 50 }}
|
||||||
|
columns={columns}
|
||||||
|
scroll={{ x: true, y: "calc(100% - 2em)" }}
|
||||||
|
rowKey="id"
|
||||||
|
style={{ height: "85%" }}
|
||||||
|
dataSource={appt}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DashboardScheduledInTodayGql = `
|
||||||
|
scheduled_in_today: appointments(where: {start: {_gte: "${moment()
|
||||||
|
.startOf("day")
|
||||||
|
.toISOString()}", _lte: "${moment()
|
||||||
|
.endOf("day")
|
||||||
|
.toISOString()}"}, canceled: {_eq: false}, block: {_neq: true}}) {
|
||||||
|
canceled
|
||||||
|
id
|
||||||
|
job {
|
||||||
|
alt_transport
|
||||||
|
clm_no
|
||||||
|
jobid: id
|
||||||
|
ins_co_nm
|
||||||
|
iouparent
|
||||||
|
ownerid
|
||||||
|
ownr_co_nm
|
||||||
|
ownr_ea
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
ownr_ph1
|
||||||
|
ownr_ph2
|
||||||
|
production_vars
|
||||||
|
ro_number
|
||||||
|
suspended
|
||||||
|
v_make_desc
|
||||||
|
v_model_desc
|
||||||
|
v_model_yr
|
||||||
|
v_vin
|
||||||
|
vehicleid
|
||||||
|
}
|
||||||
|
note
|
||||||
|
start
|
||||||
|
title
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,210 @@
|
|||||||
|
import {
|
||||||
|
BranchesOutlined,
|
||||||
|
ExclamationCircleFilled,
|
||||||
|
PauseCircleOutlined,
|
||||||
|
} from "@ant-design/icons";
|
||||||
|
import { Card, Space, Table, Tooltip } from "antd";
|
||||||
|
import moment from "moment";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import ChatOpenButton from "../../chat-open-button/chat-open-button.component";
|
||||||
|
import OwnerNameDisplay from "../../owner-name-display/owner-name-display.component";
|
||||||
|
import DashboardRefreshRequired from "../refresh-required.component";
|
||||||
|
|
||||||
|
export default function DashboardScheduledOutToday({ data, ...cardProps }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [state, setState] = useState({
|
||||||
|
sortedInfo: {},
|
||||||
|
});
|
||||||
|
if (!data) return null;
|
||||||
|
if (!data.scheduled_out_today)
|
||||||
|
return <DashboardRefreshRequired {...cardProps} />;
|
||||||
|
|
||||||
|
data.scheduled_out_today.forEach((item) => {
|
||||||
|
item.scheduled_completion= moment(item.scheduled_completion).format("hh:mm a")
|
||||||
|
});
|
||||||
|
data.scheduled_out_today.sort(function (a, b) {
|
||||||
|
return new Date(a.scheduled_completion) - new Date(b.scheduled_completion);
|
||||||
|
});
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ro_number"),
|
||||||
|
dataIndex: "ro_number",
|
||||||
|
key: "ro_number",
|
||||||
|
render: (text, record) => (
|
||||||
|
<Link
|
||||||
|
to={"/manage/jobs/" + record.jobid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<Space>
|
||||||
|
{record.ro_number || t("general.labels.na")}
|
||||||
|
{record.production_vars && record.production_vars.alert ? (
|
||||||
|
<ExclamationCircleFilled className="production-alert" />
|
||||||
|
) : null}
|
||||||
|
{record.suspended && (
|
||||||
|
<PauseCircleOutlined style={{ color: "orangered" }} />
|
||||||
|
)}
|
||||||
|
{record.iouparent && (
|
||||||
|
<Tooltip title={t("jobs.labels.iou")}>
|
||||||
|
<BranchesOutlined style={{ color: "orangered" }} />
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
</Link>
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.owner"),
|
||||||
|
dataIndex: "owner",
|
||||||
|
key: "owner",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.ownerid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/owners/" + record.ownerid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span>
|
||||||
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ownr_ph1"),
|
||||||
|
dataIndex: "ownr_ph1",
|
||||||
|
key: "ownr_ph1",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<ChatOpenButton phone={record.ownr_ph1} jobid={record.jobid} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ownr_ph2"),
|
||||||
|
dataIndex: "ownr_ph2",
|
||||||
|
key: "ownr_ph2",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<ChatOpenButton phone={record.ownr_ph2} jobid={record.jobid} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ownr_ea"),
|
||||||
|
dataIndex: "ownr_ea",
|
||||||
|
key: "ownr_ea",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
render: (text, record) => (
|
||||||
|
<ChatOpenButton phone={record.ownr_ea} jobid={record.jobid} />
|
||||||
|
),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.vehicle"),
|
||||||
|
dataIndex: "vehicle",
|
||||||
|
key: "vehicle",
|
||||||
|
ellipsis: true,
|
||||||
|
render: (text, record) => {
|
||||||
|
return record.vehicleid ? (
|
||||||
|
<Link
|
||||||
|
to={"/manage/vehicles/" + record.vehicleid}
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
>
|
||||||
|
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}
|
||||||
|
</Link>
|
||||||
|
) : (
|
||||||
|
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
|
record.v_model_desc || ""
|
||||||
|
}`}</span>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.ins_co_nm"),
|
||||||
|
dataIndex: "ins_co_nm",
|
||||||
|
key: "ins_co_nm",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.scheduled_completion"),
|
||||||
|
dataIndex: "scheduled_completion",
|
||||||
|
key: "scheduled_completion",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("appointments.fields.alt_transport"),
|
||||||
|
dataIndex: "alt_transport",
|
||||||
|
key: "alt_transport",
|
||||||
|
ellipsis: true,
|
||||||
|
responsive: ["md"],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const handleTableChange = (sorter) => {
|
||||||
|
setState({ ...state, sortedInfo: sorter });
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
title={t("dashboard.titles.scheduledouttoday", {
|
||||||
|
date: moment().startOf("day").format("MM/DD/YYYY"),
|
||||||
|
})}
|
||||||
|
{...cardProps}
|
||||||
|
>
|
||||||
|
<div style={{ height: "100%" }}>
|
||||||
|
<Table
|
||||||
|
onChange={handleTableChange}
|
||||||
|
pagination={{ position: "top", defaultPageSize: 50 }}
|
||||||
|
columns={columns}
|
||||||
|
scroll={{ x: true, y: "calc(100% - 2em)" }}
|
||||||
|
rowKey="id"
|
||||||
|
style={{ height: "85%" }}
|
||||||
|
dataSource={data.scheduled_out_today}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const DashboardScheduledOutTodayGql = `
|
||||||
|
scheduled_out_today: jobs(where: {
|
||||||
|
date_invoiced: {_is_null: true},
|
||||||
|
ro_number: {_is_null: false},
|
||||||
|
voided: {_eq: false},
|
||||||
|
scheduled_completion: {_gte: "${moment().startOf("day").toISOString()}",
|
||||||
|
_lte: "${moment().endOf("day").toISOString()}"}}) {
|
||||||
|
alt_transport
|
||||||
|
clm_no
|
||||||
|
jobid: id
|
||||||
|
ins_co_nm
|
||||||
|
iouparent
|
||||||
|
ownerid
|
||||||
|
ownr_co_nm
|
||||||
|
ownr_ea
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
ownr_ph1
|
||||||
|
ownr_ph2
|
||||||
|
production_vars
|
||||||
|
ro_number
|
||||||
|
scheduled_completion
|
||||||
|
suspended
|
||||||
|
v_make_desc
|
||||||
|
v_model_desc
|
||||||
|
v_model_yr
|
||||||
|
v_vin
|
||||||
|
vehicleid
|
||||||
|
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import Icon, { SyncOutlined } from "@ant-design/icons";
|
import Icon, { SyncOutlined } from "@ant-design/icons";
|
||||||
import { gql, useMutation, useQuery } from "@apollo/client";
|
import { gql, useMutation, useQuery } from "@apollo/client";
|
||||||
import { Button, Dropdown, Menu, notification, PageHeader, Space } from "antd";
|
import { Button, Dropdown, Menu, PageHeader, Space, notification } from "antd";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
@@ -37,6 +37,12 @@ import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
|||||||
//Combination of the following:
|
//Combination of the following:
|
||||||
// /node_modules/react-grid-layout/css/styles.css
|
// /node_modules/react-grid-layout/css/styles.css
|
||||||
// /node_modules/react-resizable/css/styles.css
|
// /node_modules/react-resizable/css/styles.css
|
||||||
|
import DashboardScheduledInToday, {
|
||||||
|
DashboardScheduledInTodayGql,
|
||||||
|
} from "../dashboard-components/scheduled-in-today/scheduled-in-today.component";
|
||||||
|
import DashboardScheduledOutToday, {
|
||||||
|
DashboardScheduledOutTodayGql,
|
||||||
|
} from "../dashboard-components/scheduled-out-today/scheduled-out-today.component";
|
||||||
import "./dashboard-grid.styles.scss";
|
import "./dashboard-grid.styles.scss";
|
||||||
import { GenerateDashboardData } from "./dashboard-grid.utils";
|
import { GenerateDashboardData } from "./dashboard-grid.utils";
|
||||||
|
|
||||||
@@ -268,6 +274,28 @@ const componentList = {
|
|||||||
w: 2,
|
w: 2,
|
||||||
h: 2,
|
h: 2,
|
||||||
},
|
},
|
||||||
|
ScheduleInToday: {
|
||||||
|
label: i18next.t("dashboard.titles.scheduledintoday", {
|
||||||
|
date: moment().startOf("day").format("MM/DD/YYYY"),
|
||||||
|
}),
|
||||||
|
component: DashboardScheduledInToday,
|
||||||
|
gqlFragment: DashboardScheduledInTodayGql,
|
||||||
|
minW: 10,
|
||||||
|
minH: 2,
|
||||||
|
w: 10,
|
||||||
|
h: 2,
|
||||||
|
},
|
||||||
|
ScheduleOutToday: {
|
||||||
|
label: i18next.t("dashboard.titles.scheduledouttoday", {
|
||||||
|
date: moment().startOf("day").format("MM/DD/YYYY"),
|
||||||
|
}),
|
||||||
|
component: DashboardScheduledOutToday,
|
||||||
|
gqlFragment: DashboardScheduledOutTodayGql,
|
||||||
|
minW: 10,
|
||||||
|
minH: 2,
|
||||||
|
w: 10,
|
||||||
|
h: 2,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const createDashboardQuery = (state) => {
|
const createDashboardQuery = (state) => {
|
||||||
@@ -283,8 +311,12 @@ const createDashboardQuery = (state) => {
|
|||||||
monthly_sales: jobs(where: {_and: [
|
monthly_sales: jobs(where: {_and: [
|
||||||
{ voided: {_eq: false}},
|
{ voided: {_eq: false}},
|
||||||
{date_invoiced: {_gte: "${moment()
|
{date_invoiced: {_gte: "${moment()
|
||||||
.startOf("month").startOf('day').toISOString()}"}}, {date_invoiced: {_lte: "${moment()
|
.startOf("month")
|
||||||
.endOf("month").endOf('day').toISOString()}"}}]}) {
|
.startOf("day")
|
||||||
|
.toISOString()}"}}, {date_invoiced: {_lte: "${moment()
|
||||||
|
.endOf("month")
|
||||||
|
.endOf("day")
|
||||||
|
.toISOString()}"}}]}) {
|
||||||
id
|
id
|
||||||
ro_number
|
ro_number
|
||||||
date_invoiced
|
date_invoiced
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ export function DmsAllocationsSummaryAp({ socket, bodyshop, billids, title }) {
|
|||||||
key: "status",
|
key: "status",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.ro_number"),
|
title: t("bills.fields.invoice_number"),
|
||||||
dataIndex: ["Posting", "Reference"],
|
dataIndex: ["Posting", "Reference"],
|
||||||
key: "reference",
|
key: "reference",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
Statistic,
|
||||||
|
Switch,
|
||||||
Typography,
|
Typography,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import Dinero from "dinero.js";
|
import Dinero from "dinero.js";
|
||||||
@@ -183,6 +184,13 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
|
|||||||
<Space>
|
<Space>
|
||||||
<DmsCdkMakes form={form} socket={socket} job={job} />
|
<DmsCdkMakes form={form} socket={socket} job={job} />
|
||||||
<DmsCdkMakesRefetch />
|
<DmsCdkMakesRefetch />
|
||||||
|
<Form.Item
|
||||||
|
name="dms_unsold"
|
||||||
|
label={t("jobs.fields.dms.dms_unsold")}
|
||||||
|
initialValue={false}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -311,7 +311,9 @@ function Header({
|
|||||||
icon={<SettingOutlined />}
|
icon={<SettingOutlined />}
|
||||||
>
|
>
|
||||||
<Menu.Item key="shop" icon={<Icon component={GiSettingsKnobs} />}>
|
<Menu.Item key="shop" icon={<Icon component={GiSettingsKnobs} />}>
|
||||||
<Link to="/manage/shop">{t("menus.header.shop_config")}</Link>
|
<Link to="/manage/shop?tab=info">
|
||||||
|
{t("menus.header.shop_config")}
|
||||||
|
</Link>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item key="dashboard" icon={<DashboardFilled />}>
|
<Menu.Item key="dashboard" icon={<DashboardFilled />}>
|
||||||
<Link to="/manage/dashboard">{t("menus.header.dashboard")}</Link>
|
<Link to="/manage/dashboard">{t("menus.header.dashboard")}</Link>
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
|
|||||||
import JobsDetaiLheaderCsi from "./jobs-detail-header-actions.csi.component";
|
import JobsDetaiLheaderCsi from "./jobs-detail-header-actions.csi.component";
|
||||||
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
|
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
|
||||||
import JobsDetailHeaderActionsExportcustdataComponent from "./jobs-detail-header-actions.exportcustdata.component";
|
import JobsDetailHeaderActionsExportcustdataComponent from "./jobs-detail-header-actions.exportcustdata.component";
|
||||||
|
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -461,54 +462,56 @@ export function JobsDetailHeaderActions({
|
|||||||
)}
|
)}
|
||||||
<JobsDetailHeaderActionsAddevent jobid={job.id} />
|
<JobsDetailHeaderActionsAddevent jobid={job.id} />
|
||||||
{!jobRO && job.converted && (
|
{!jobRO && job.converted && (
|
||||||
<Menu.Item>
|
<RbacWrapper action="jobs:void" noauth>
|
||||||
<Popconfirm
|
<Menu.Item>
|
||||||
title={t("jobs.labels.voidjob")}
|
<Popconfirm
|
||||||
okText="Yes"
|
title={t("jobs.labels.voidjob")}
|
||||||
cancelText="No"
|
okText="Yes"
|
||||||
onClick={(e) => e.stopPropagation()}
|
cancelText="No"
|
||||||
onConfirm={async () => {
|
onClick={(e) => e.stopPropagation()}
|
||||||
//delete the job.
|
onConfirm={async () => {
|
||||||
const result = await voidJob({
|
//delete the job.
|
||||||
variables: {
|
const result = await voidJob({
|
||||||
jobId: job.id,
|
variables: {
|
||||||
job: {
|
jobId: job.id,
|
||||||
status: bodyshop.md_ro_statuses.default_void,
|
job: {
|
||||||
voided: true,
|
status: bodyshop.md_ro_statuses.default_void,
|
||||||
scheduled_in: null,
|
voided: true,
|
||||||
scheduled_completion: null,
|
scheduled_in: null,
|
||||||
inproduction: false,
|
scheduled_completion: null,
|
||||||
},
|
inproduction: false,
|
||||||
note: [
|
|
||||||
{
|
|
||||||
jobid: job.id,
|
|
||||||
created_by: currentUser.email,
|
|
||||||
audit: true,
|
|
||||||
text: t("jobs.labels.voidnote"),
|
|
||||||
},
|
},
|
||||||
],
|
note: [
|
||||||
},
|
{
|
||||||
});
|
jobid: job.id,
|
||||||
|
created_by: currentUser.email,
|
||||||
|
audit: true,
|
||||||
|
text: t("jobs.labels.voidnote"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!!!result.errors) {
|
if (!!!result.errors) {
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
message: t("jobs.successes.voided"),
|
message: t("jobs.successes.voided"),
|
||||||
});
|
});
|
||||||
//go back to jobs list.
|
//go back to jobs list.
|
||||||
history.push(`/manage/`);
|
history.push(`/manage/`);
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.voiding", {
|
message: t("jobs.errors.voiding", {
|
||||||
error: JSON.stringify(result.errors),
|
error: JSON.stringify(result.errors),
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
getPopupContainer={(trigger) => trigger.parentNode}
|
getPopupContainer={(trigger) => trigger.parentNode}
|
||||||
>
|
>
|
||||||
{t("menus.jobsactions.void")}
|
{t("menus.jobsactions.void")}
|
||||||
</Popconfirm>
|
</Popconfirm>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
</RbacWrapper>
|
||||||
)}
|
)}
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -112,7 +112,9 @@ export function JobsList({ bodyshop }) {
|
|||||||
title: t("jobs.fields.ro_number"),
|
title: t("jobs.fields.ro_number"),
|
||||||
dataIndex: "ro_number",
|
dataIndex: "ro_number",
|
||||||
key: "ro_number",
|
key: "ro_number",
|
||||||
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
sorter: (a, b) =>
|
||||||
|
parseInt((a.ro_number || "0").replace(/\D/g, "")) -
|
||||||
|
parseInt((b.ro_number || "0").replace(/\D/g, "")),
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
|
|
||||||
|
|||||||
@@ -23,17 +23,34 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
|
|||||||
const { id: jobId, job } = printCenterModal.context;
|
const { id: jobId, job } = printCenterModal.context;
|
||||||
const tempList = TemplateList("job", {});
|
const tempList = TemplateList("job", {});
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const JobsReportsList = Object.keys(tempList)
|
|
||||||
.map((key) => {
|
const JobsReportsList =
|
||||||
return tempList[key];
|
bodyshop.cdk_dealerid === null && bodyshop.pbs_serialnumber === null
|
||||||
})
|
? Object.keys(tempList)
|
||||||
.filter(
|
.map((key) => {
|
||||||
(temp) =>
|
return tempList[key];
|
||||||
!temp.regions ||
|
})
|
||||||
(temp.regions && temp.regions[bodyshop.region_config]) ||
|
.filter(
|
||||||
(temp.regions &&
|
(temp) =>
|
||||||
bodyshop.region_config.includes(Object.keys(temp.regions)) === true)
|
(!temp.regions ||
|
||||||
);
|
(temp.regions && temp.regions[bodyshop.region_config]) ||
|
||||||
|
(temp.regions &&
|
||||||
|
bodyshop.region_config.includes(Object.keys(temp.regions)) ===
|
||||||
|
true)) &&
|
||||||
|
(!temp.dms || temp.dms === false)
|
||||||
|
)
|
||||||
|
: Object.keys(tempList)
|
||||||
|
.map((key) => {
|
||||||
|
return tempList[key];
|
||||||
|
})
|
||||||
|
.filter(
|
||||||
|
(temp) =>
|
||||||
|
!temp.regions ||
|
||||||
|
(temp.regions && temp.regions[bodyshop.region_config]) ||
|
||||||
|
(temp.regions &&
|
||||||
|
bodyshop.region_config.includes(Object.keys(temp.regions)) ===
|
||||||
|
true)
|
||||||
|
);
|
||||||
|
|
||||||
const filteredJobsReportsList =
|
const filteredJobsReportsList =
|
||||||
search !== ""
|
search !== ""
|
||||||
|
|||||||
@@ -246,11 +246,21 @@ export function ProductionListTable({
|
|||||||
(x) => x.status === record.status
|
(x) => x.status === record.status
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!color) return null;
|
if (!color) {
|
||||||
|
if (index % 2 === 0)
|
||||||
|
return {
|
||||||
|
style: {
|
||||||
|
backgroundColor: `rgb(236, 236, 236)`,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
className: "rowWithColor",
|
||||||
style: {
|
style: {
|
||||||
backgroundColor: `rgb(${color.color.r},${color.color.g},${color.color.b},${color.color.a})`,
|
"--bgColor": `rgb(${color.color.r},${color.color.g},${color.color.b},${color.color.a})`,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -26,6 +26,8 @@ const ret = {
|
|||||||
"jobs:partsqueue": 4,
|
"jobs:partsqueue": 4,
|
||||||
"jobs:checklist-view": 2,
|
"jobs:checklist-view": 2,
|
||||||
"jobs:list-ready": 1,
|
"jobs:list-ready": 1,
|
||||||
|
"jobs:void": 5,
|
||||||
|
|
||||||
"bills:enter": 2,
|
"bills:enter": 2,
|
||||||
"bills:view": 2,
|
"bills:view": 2,
|
||||||
"bills:list": 2,
|
"bills:list": 2,
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ import "./schedule-calendar.styles.scss";
|
|||||||
import JobDetailCards from "../job-detail-cards/job-detail-cards.component";
|
import JobDetailCards from "../job-detail-cards/job-detail-cards.component";
|
||||||
import { selectProblemJobs } from "../../redux/application/application.selectors";
|
import { selectProblemJobs } from "../../redux/application/application.selectors";
|
||||||
import { Alert, Collapse } from "antd";
|
import { Alert, Collapse } from "antd";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation, Trans } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -66,10 +67,21 @@ export function ScheduleCalendarWrapperComponent({
|
|||||||
<Alert
|
<Alert
|
||||||
key={problem.id}
|
key={problem.id}
|
||||||
type="error"
|
type="error"
|
||||||
message={t("appointments.labels.dataconsistency", {
|
message={
|
||||||
ro_number: problem.ro_number,
|
<Trans
|
||||||
code: problem.code,
|
i18nKey="appointments.labels.dataconsistency"
|
||||||
})}
|
components={[
|
||||||
|
<Link
|
||||||
|
to={`/manage/jobs/${problem.id}`}
|
||||||
|
target="_blank"
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
values={{
|
||||||
|
ro_number: problem.ro_number,
|
||||||
|
code: problem.code,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</Collapse.Panel>
|
</Collapse.Panel>
|
||||||
@@ -79,10 +91,18 @@ export function ScheduleCalendarWrapperComponent({
|
|||||||
<Alert
|
<Alert
|
||||||
key={problem.id}
|
key={problem.id}
|
||||||
type="error"
|
type="error"
|
||||||
message={t("appointments.labels.dataconsistency", {
|
message={
|
||||||
ro_number: problem.ro_number,
|
<Trans
|
||||||
code: problem.code,
|
i18nKey="appointments.labels.dataconsistency"
|
||||||
})}
|
components={[
|
||||||
|
<Link to={`/manage/jobs/${problem.id}`} target="_blank" />,
|
||||||
|
]}
|
||||||
|
values={{
|
||||||
|
ro_number: problem.ro_number,
|
||||||
|
code: problem.code,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -52,7 +52,9 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
|
|||||||
<Tabs
|
<Tabs
|
||||||
defaultActiveKey={search.subtab}
|
defaultActiveKey={search.subtab}
|
||||||
onChange={(key) =>
|
onChange={(key) =>
|
||||||
history.push({ search: `?tab=${search.tab}&subtab=${key}` })
|
history.push({
|
||||||
|
search: `?tab=${search.tab}&subtab=${key}`,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Tabs.TabPane key="general" tab={t("bodyshop.labels.shopinfo")}>
|
<Tabs.TabPane key="general" tab={t("bodyshop.labels.shopinfo")}>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { Form, InputNumber } from "antd";
|
import { Form, InputNumber } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|
||||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
@@ -316,6 +316,18 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
|
|||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.rbac.jobs.void")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
name={["md_rbac", "jobs:void"]}
|
||||||
|
>
|
||||||
|
<InputNumber />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.rbac.bills.enter")}
|
label={t("bodyshop.fields.rbac.bills.enter")}
|
||||||
rules={[
|
rules={[
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export function TechClockInComponent({ form, bodyshop, technician }) {
|
|||||||
<JobSearchSelect
|
<JobSearchSelect
|
||||||
convertedOnly={!bodyshop.tt_allow_post_to_invoiced}
|
convertedOnly={!bodyshop.tt_allow_post_to_invoiced}
|
||||||
notExported={!bodyshop.tt_allow_post_to_invoiced}
|
notExported={!bodyshop.tt_allow_post_to_invoiced}
|
||||||
|
notInvoiced={!bodyshop.tt_allow_post_to_invoiced}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import {
|
|||||||
Col,
|
Col,
|
||||||
Form,
|
Form,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
notification,
|
|
||||||
Popover,
|
Popover,
|
||||||
Row,
|
Row,
|
||||||
Select,
|
Select,
|
||||||
|
notification,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
@@ -16,13 +16,14 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
|
||||||
|
import { UPDATE_JOB_STATUS } from "../../graphql/jobs.queries";
|
||||||
import { UPDATE_TIME_TICKET } from "../../graphql/timetickets.queries";
|
import { UPDATE_TIME_TICKET } from "../../graphql/timetickets.queries";
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
|
||||||
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
|
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
|
||||||
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
|
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
|
||||||
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
|
|
||||||
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -40,6 +41,7 @@ export function TechClockOffButton({
|
|||||||
}) {
|
}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
|
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
|
||||||
|
const [updateJobStatus] = useMutation(UPDATE_JOB_STATUS);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const { queryLoading, data: lineTicketData } = useQuery(
|
const { queryLoading, data: lineTicketData } = useQuery(
|
||||||
GET_LINE_TICKET_BY_PK,
|
GET_LINE_TICKET_BY_PK,
|
||||||
@@ -59,7 +61,8 @@ export function TechClockOffButton({
|
|||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
logImEXEvent("tech_clock_out_job");
|
logImEXEvent("tech_clock_out_job");
|
||||||
|
const status = values.status;
|
||||||
|
delete values.status;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const result = await updateTimeticket({
|
const result = await updateTimeticket({
|
||||||
variables: {
|
variables: {
|
||||||
@@ -98,6 +101,26 @@ export function TechClockOffButton({
|
|||||||
message: t("timetickets.successes.clockedout"),
|
message: t("timetickets.successes.clockedout"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (!isShiftTicket) {
|
||||||
|
const job_update_result = await updateJobStatus({
|
||||||
|
variables: {
|
||||||
|
jobId: jobId,
|
||||||
|
status: status,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!!job_update_result.errors) {
|
||||||
|
notification["error"]({
|
||||||
|
message: t("jobs.errors.updating", {
|
||||||
|
message: JSON.stringify(result.errors),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification["success"]({
|
||||||
|
message: t("jobs.successes.updated"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (completedCallback) completedCallback();
|
if (completedCallback) completedCallback();
|
||||||
};
|
};
|
||||||
@@ -195,7 +218,6 @@ export function TechClockOffButton({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="cost_center"
|
name="cost_center"
|
||||||
label={t("timetickets.fields.cost_center")}
|
label={t("timetickets.fields.cost_center")}
|
||||||
@@ -228,6 +250,29 @@ export function TechClockOffButton({
|
|||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
{isShiftTicket ? (
|
||||||
|
<div></div>
|
||||||
|
) : (
|
||||||
|
<Form.Item
|
||||||
|
name="status"
|
||||||
|
label={t("jobs.fields.status")}
|
||||||
|
initialValue={
|
||||||
|
lineTicketData && lineTicketData.jobs_by_pk.status
|
||||||
|
}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select>
|
||||||
|
{bodyshop.md_ro_statuses.production_statuses.map((item) => (
|
||||||
|
<Select.Option key={item}></Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
<Button type="primary" htmlType="submit" loading={loading}>
|
<Button type="primary" htmlType="submit" loading={loading}>
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
import { Alert, Button, Col, Row, Space } from "antd";
|
||||||
|
import i18n from "i18next";
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectUpdateAvailable } from "../../redux/application/application.selectors";
|
||||||
|
import { AlertOutlined } from "@ant-design/icons";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { setUpdateAvailable } from "../../redux/application/application.actions";
|
||||||
|
import { store } from "../../redux/store";
|
||||||
|
import * as serviceWorkerRegistration from "../../serviceWorkerRegistration";
|
||||||
|
|
||||||
|
let globalRegistration;
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
updateAvailable: selectUpdateAvailable,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
|
});
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(UpdateAlert);
|
||||||
|
|
||||||
|
export function UpdateAlert({ updateAvailable }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
if (!updateAvailable) return null;
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
message={t("general.messages.newversiontitle")}
|
||||||
|
showIcon
|
||||||
|
icon={<AlertOutlined />}
|
||||||
|
description={
|
||||||
|
<Row gutter={[16, 16]}>
|
||||||
|
<Col sm={24} md={16} lg={18}>
|
||||||
|
{t("general.messages.newversionmessage")}
|
||||||
|
</Col>
|
||||||
|
<Col sm={24} md={8} lg={6}>
|
||||||
|
<Space wrap>
|
||||||
|
<Button
|
||||||
|
onClick={async () => {
|
||||||
|
window.open("https://imex-online.noticeable.news/", "_blank");
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n.t("general.actions.viewreleasenotes")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
onClick={async () => {
|
||||||
|
if (globalRegistration && globalRegistration.waiting) {
|
||||||
|
await globalRegistration.unregister();
|
||||||
|
// Makes Workbox call skipWaiting()
|
||||||
|
globalRegistration.waiting.postMessage({
|
||||||
|
type: "SKIP_WAITING",
|
||||||
|
});
|
||||||
|
// Once the service worker is unregistered, we can reload the page to let
|
||||||
|
// the browser download a fresh copy of our app (invalidating the cache)
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{i18n.t("general.actions.refresh")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
}
|
||||||
|
closable={false}
|
||||||
|
type="warning"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onServiceWorkerUpdate = (registration) => {
|
||||||
|
console.log("onServiceWorkerUpdate", registration);
|
||||||
|
globalRegistration = registration;
|
||||||
|
store.dispatch(setUpdateAvailable(true));
|
||||||
|
};
|
||||||
|
|
||||||
|
serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate });
|
||||||
@@ -1,37 +1,5 @@
|
|||||||
import { gql } from "@apollo/client";
|
import { gql } from "@apollo/client";
|
||||||
|
|
||||||
export const CONVERSATION_LIST_SUBSCRIPTION = gql`
|
|
||||||
subscription CONVERSATION_LIST_SUBSCRIPTION($offset: Int!) {
|
|
||||||
conversations(
|
|
||||||
order_by: { updated_at: desc }
|
|
||||||
limit: 1
|
|
||||||
offset: $offset
|
|
||||||
where: { archived: { _eq: false } }
|
|
||||||
) {
|
|
||||||
phone_num
|
|
||||||
id
|
|
||||||
updated_at
|
|
||||||
unreadcnt
|
|
||||||
messages_aggregate(
|
|
||||||
where: { read: { _eq: false }, isoutbound: { _eq: false } }
|
|
||||||
) {
|
|
||||||
aggregate {
|
|
||||||
count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
job_conversations {
|
|
||||||
job {
|
|
||||||
id
|
|
||||||
ro_number
|
|
||||||
ownr_fn
|
|
||||||
ownr_ln
|
|
||||||
ownr_co_nm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const UNREAD_CONVERSATION_COUNT = gql`
|
export const UNREAD_CONVERSATION_COUNT = gql`
|
||||||
query UNREAD_CONVERSATION_COUNT {
|
query UNREAD_CONVERSATION_COUNT {
|
||||||
messages_aggregate(
|
messages_aggregate(
|
||||||
@@ -44,18 +12,6 @@ export const UNREAD_CONVERSATION_COUNT = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const UNREAD_CONVERSATION_COUNT_SUBSCRIPTION = gql`
|
|
||||||
subscription UNREAD_CONVERSATION_COUNT_SUBSCRIPTION {
|
|
||||||
messages_aggregate(
|
|
||||||
where: { read: { _eq: false }, isoutbound: { _eq: false } }
|
|
||||||
) {
|
|
||||||
aggregate {
|
|
||||||
count
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
export const CONVERSATION_LIST_QUERY = gql`
|
export const CONVERSATION_LIST_QUERY = gql`
|
||||||
query CONVERSATION_LIST_QUERY($offset: Int!) {
|
query CONVERSATION_LIST_QUERY($offset: Int!) {
|
||||||
conversations(
|
conversations(
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export const GET_LINE_TICKET_BY_PK = gql`
|
|||||||
id
|
id
|
||||||
lbr_adjustments
|
lbr_adjustments
|
||||||
converted
|
converted
|
||||||
|
status
|
||||||
}
|
}
|
||||||
joblines(where: { jobid: { _eq: $id }, removed: { _eq: false } }) {
|
joblines(where: { jobid: { _eq: $id }, removed: { _eq: false } }) {
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -1219,10 +1219,10 @@ export const ACTIVE_JOBS_FOR_AUTOCOMPLETE = gql`
|
|||||||
query ACTIVE_JOBS_FOR_AUTOCOMPLETE($statuses: [String!]!) {
|
query ACTIVE_JOBS_FOR_AUTOCOMPLETE($statuses: [String!]!) {
|
||||||
jobs(where: { status: { _in: $statuses } }) {
|
jobs(where: { status: { _in: $statuses } }) {
|
||||||
id
|
id
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
ro_number
|
ro_number
|
||||||
|
|
||||||
vehicleid
|
vehicleid
|
||||||
v_make_desc
|
v_make_desc
|
||||||
v_model_desc
|
v_model_desc
|
||||||
@@ -1250,6 +1250,7 @@ export const SEARCH_JOBS_FOR_AUTOCOMPLETE = gql`
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
ro_number
|
ro_number
|
||||||
@@ -1266,6 +1267,7 @@ export const SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE = gql`
|
|||||||
query SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE($id: uuid!) {
|
query SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE($id: uuid!) {
|
||||||
jobs_by_pk(id: $id) {
|
jobs_by_pk(id: $id) {
|
||||||
id
|
id
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
ro_number
|
ro_number
|
||||||
@@ -1284,6 +1286,7 @@ export const SEARCH_FOR_JOBS = gql`
|
|||||||
search_jobs(args: { search: $search }, limit: 25) {
|
search_jobs(args: { search: $search }, limit: 25) {
|
||||||
id
|
id
|
||||||
ro_number
|
ro_number
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import queryString from "query-string";
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { useHistory, useLocation, Link } from "react-router-dom";
|
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import SocketIO from "socket.io-client";
|
import SocketIO from "socket.io-client";
|
||||||
import AlertComponent from "../../components/alert/alert.component";
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
@@ -22,6 +22,7 @@ import DmsCustomerSelector from "../../components/dms-customer-selector/dms-cust
|
|||||||
import DmsLogEvents from "../../components/dms-log-events/dms-log-events.component";
|
import DmsLogEvents from "../../components/dms-log-events/dms-log-events.component";
|
||||||
import DmsPostForm from "../../components/dms-post-form/dms-post-form.component";
|
import DmsPostForm from "../../components/dms-post-form/dms-post-form.component";
|
||||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||||
import { auth } from "../../firebase/firebase.utils";
|
import { auth } from "../../firebase/firebase.utils";
|
||||||
import { QUERY_JOB_EXPORT_DMS } from "../../graphql/jobs.queries";
|
import { QUERY_JOB_EXPORT_DMS } from "../../graphql/jobs.queries";
|
||||||
import {
|
import {
|
||||||
@@ -29,7 +30,6 @@ import {
|
|||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -46,6 +46,7 @@ export const socket = SocketIO(
|
|||||||
process.env.NODE_ENV === "production"
|
process.env.NODE_ENV === "production"
|
||||||
? process.env.REACT_APP_AXIOS_BASE_API_URL
|
? process.env.REACT_APP_AXIOS_BASE_API_URL
|
||||||
: window.location.origin,
|
: window.location.origin,
|
||||||
|
// "http://localhost:4000", // for dev testing,
|
||||||
{
|
{
|
||||||
path: "/ws",
|
path: "/ws",
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import {
|
|||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
|
|
||||||
import "./manage.page.styles.scss";
|
import "./manage.page.styles.scss";
|
||||||
|
import UpdateAlert from "../../components/update-alert/update-alert.component";
|
||||||
|
|
||||||
const ManageRootPage = lazy(() =>
|
const ManageRootPage = lazy(() =>
|
||||||
import("../manage-root/manage-root.page.container")
|
import("../manage-root/manage-root.page.container")
|
||||||
@@ -394,6 +395,7 @@ export function Manage({ match, conflict, bodyshop }) {
|
|||||||
<>
|
<>
|
||||||
<ChatAffixContainer />
|
<ChatAffixContainer />
|
||||||
<Layout className="layout-container">
|
<Layout className="layout-container">
|
||||||
|
<UpdateAlert />
|
||||||
<HeaderContainer />
|
<HeaderContainer />
|
||||||
|
|
||||||
<Content className="content-container">
|
<Content className="content-container">
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import AlertComponent from "../../components/alert/alert.component";
|
|||||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||||
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
||||||
import { setBodyshop } from "../../redux/user/user.actions";
|
import { setBodyshop } from "../../redux/user/user.actions";
|
||||||
import "../../utils/RegisterSw";
|
//import "../../utils/RegisterSw";
|
||||||
import ManagePage from "./manage.page.component";
|
import ManagePage from "./manage.page.component";
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
|
|||||||
]);
|
]);
|
||||||
}, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]);
|
}, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!search.tab) history.push({ search: "?tab=info" });
|
||||||
|
}, [history, search]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RbacWrapper action="shop:config">
|
<RbacWrapper action="shop:config">
|
||||||
<Tabs
|
<Tabs
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import TechSider from "../../components/tech-sider/tech-sider.component";
|
|||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
||||||
import "./tech.page.styles.scss";
|
import "./tech.page.styles.scss";
|
||||||
|
import UpdateAlert from "../../components/update-alert/update-alert.component";
|
||||||
const TimeTicketModalContainer = lazy(() =>
|
const TimeTicketModalContainer = lazy(() =>
|
||||||
import("../../components/time-ticket-modal/time-ticket-modal.container")
|
import("../../components/time-ticket-modal/time-ticket-modal.container")
|
||||||
);
|
);
|
||||||
@@ -56,7 +57,9 @@ export function TechPage({ technician, match }) {
|
|||||||
<TechSider />
|
<TechSider />
|
||||||
<Layout>
|
<Layout>
|
||||||
{technician ? null : <Redirect to={`${match.path}/login`} />}
|
{technician ? null : <Redirect to={`${match.path}/login`} />}
|
||||||
|
<UpdateAlert />
|
||||||
<TechHeader />
|
<TechHeader />
|
||||||
|
|
||||||
<Content className="tech-content-container">
|
<Content className="tech-content-container">
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<Suspense
|
<Suspense
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import "../../utils/RegisterSw";
|
//import "../../utils/RegisterSw";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
|||||||
@@ -62,3 +62,8 @@ export const setProblemJobs = (problemJobs) => ({
|
|||||||
type: ApplicationActionTypes.SET_PROBLEM_JOBS,
|
type: ApplicationActionTypes.SET_PROBLEM_JOBS,
|
||||||
payload: problemJobs,
|
payload: problemJobs,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const setUpdateAvailable = (isUpdateAvailable) => ({
|
||||||
|
type: ApplicationActionTypes.SET_UPDATE_AVAILABLE,
|
||||||
|
payload: isUpdateAvailable,
|
||||||
|
});
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import ApplicationActionTypes from "./application.types";
|
|||||||
const INITIAL_STATE = {
|
const INITIAL_STATE = {
|
||||||
loading: false,
|
loading: false,
|
||||||
online: true,
|
online: true,
|
||||||
|
updateAvailable: false,
|
||||||
breadcrumbs: [],
|
breadcrumbs: [],
|
||||||
recentItems: [],
|
recentItems: [],
|
||||||
selectedHeader: "home",
|
selectedHeader: "home",
|
||||||
@@ -18,6 +19,11 @@ const INITIAL_STATE = {
|
|||||||
|
|
||||||
const applicationReducer = (state = INITIAL_STATE, action) => {
|
const applicationReducer = (state = INITIAL_STATE, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case ApplicationActionTypes.SET_UPDATE_AVAILABLE:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
updateAvailable: action.payload,
|
||||||
|
};
|
||||||
case ApplicationActionTypes.SET_SELECTED_HEADER:
|
case ApplicationActionTypes.SET_SELECTED_HEADER:
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
@@ -48,3 +48,7 @@ export const selectProblemJobs = createSelector(
|
|||||||
[selectApplication],
|
[selectApplication],
|
||||||
(application) => application.problemJobs
|
(application) => application.problemJobs
|
||||||
);
|
);
|
||||||
|
export const selectUpdateAvailable = createSelector(
|
||||||
|
[selectApplication],
|
||||||
|
(application) => application.updateAvailable
|
||||||
|
);
|
||||||
|
|||||||
@@ -12,5 +12,6 @@ const ApplicationActionTypes = {
|
|||||||
SET_ONLINE_STATUS: "SET_ONLINE_STATUS",
|
SET_ONLINE_STATUS: "SET_ONLINE_STATUS",
|
||||||
INSERT_AUDIT_TRAIL: "INSERT_AUDIT_TRAIL",
|
INSERT_AUDIT_TRAIL: "INSERT_AUDIT_TRAIL",
|
||||||
SET_PROBLEM_JOBS: "SET_PROBLEM_JOBS",
|
SET_PROBLEM_JOBS: "SET_PROBLEM_JOBS",
|
||||||
|
SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE"
|
||||||
};
|
};
|
||||||
export default ApplicationActionTypes;
|
export default ApplicationActionTypes;
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
"blocked": "Blocked",
|
"blocked": "Blocked",
|
||||||
"cancelledappointment": "Canceled appointment for: ",
|
"cancelledappointment": "Canceled appointment for: ",
|
||||||
"completingjobs": "Completing Jobs",
|
"completingjobs": "Completing Jobs",
|
||||||
"dataconsistency": "{{ro_number}} has a data consistency issue. It may have been excluded for scheduling purposes. CODE: {{code}}.",
|
"dataconsistency": "<0>{{ro_number}}</0> has a data consistency issue. It may have been excluded for scheduling purposes. CODE: {{code}}.",
|
||||||
"expectedjobs": "Expected Jobs in Production: ",
|
"expectedjobs": "Expected Jobs in Production: ",
|
||||||
"expectedprodhrs": "Expected Production Hours:",
|
"expectedprodhrs": "Expected Production Hours:",
|
||||||
"history": "History",
|
"history": "History",
|
||||||
@@ -405,7 +405,8 @@
|
|||||||
"list-active": "Jobs -> List Active",
|
"list-active": "Jobs -> List Active",
|
||||||
"list-all": "Jobs -> List All",
|
"list-all": "Jobs -> List All",
|
||||||
"list-ready": "Jobs -> List Ready",
|
"list-ready": "Jobs -> List Ready",
|
||||||
"partsqueue": "Jobs -> Parts Queue"
|
"partsqueue": "Jobs -> Parts Queue",
|
||||||
|
"void": "Jobs -> Void"
|
||||||
},
|
},
|
||||||
"owners": {
|
"owners": {
|
||||||
"detail": "Owners -> Detail",
|
"detail": "Owners -> Detail",
|
||||||
@@ -857,7 +858,9 @@
|
|||||||
"prodhrssummary": "Production Hours Summary",
|
"prodhrssummary": "Production Hours Summary",
|
||||||
"productiondollars": "Total dollars in Production",
|
"productiondollars": "Total dollars in Production",
|
||||||
"productionhours": "Total hours in Production",
|
"productionhours": "Total hours in Production",
|
||||||
"projectedmonthlysales": "Projected Monthly Sales"
|
"projectedmonthlysales": "Projected Monthly Sales",
|
||||||
|
"scheduledintoday": "Sheduled In Today: {{date}}",
|
||||||
|
"scheduledouttoday": "Sheduled Out Today: {{date}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
@@ -1117,7 +1120,7 @@
|
|||||||
},
|
},
|
||||||
"messages": {
|
"messages": {
|
||||||
"exception": "$t(titles.app) has encountered an error. Please try again. If the problem persists, please submit a support ticket or contact us.",
|
"exception": "$t(titles.app) has encountered an error. Please try again. If the problem persists, please submit a support ticket or contact us.",
|
||||||
"newversionmessage": "Click refresh below to update to the latest available version of ImEX Online. Please make sure all other tabs and windows are closed.",
|
"newversionmessage": "Click refresh to update to the latest available version of ImEX Online. Please make sure all other tabs and windows are closed.",
|
||||||
"newversiontitle": "New version of ImEX Online Available",
|
"newversiontitle": "New version of ImEX Online Available",
|
||||||
"noacctfilepath": "There is no accounting file path set. You will not be able to export any items.",
|
"noacctfilepath": "There is no accounting file path set. You will not be able to export any items.",
|
||||||
"nofeatureaccess": "You do not have access to this feature of ImEX Online. Please contact support to request a license for this feature.",
|
"nofeatureaccess": "You do not have access to this feature of ImEX Online. Please contact support to request a license for this feature.",
|
||||||
@@ -1450,6 +1453,7 @@
|
|||||||
"dms_make": "DMS Make",
|
"dms_make": "DMS Make",
|
||||||
"dms_model": "DMS Model",
|
"dms_model": "DMS Model",
|
||||||
"dms_wip_acctnumber": "Cost WIP DMS Acct #",
|
"dms_wip_acctnumber": "Cost WIP DMS Acct #",
|
||||||
|
"dms_unsold": "New, Unsold Vehicle",
|
||||||
"id": "DMS ID",
|
"id": "DMS ID",
|
||||||
"inservicedate": "In Service Date",
|
"inservicedate": "In Service Date",
|
||||||
"journal": "Journal #",
|
"journal": "Journal #",
|
||||||
@@ -2566,6 +2570,7 @@
|
|||||||
"job_costing_ro_ins_co": "Job Costing by RO Source",
|
"job_costing_ro_ins_co": "Job Costing by RO Source",
|
||||||
"jobs_completed_not_invoiced": "Jobs Completed not Invoiced",
|
"jobs_completed_not_invoiced": "Jobs Completed not Invoiced",
|
||||||
"jobs_invoiced_not_exported": "Jobs Invoiced not Exported",
|
"jobs_invoiced_not_exported": "Jobs Invoiced not Exported",
|
||||||
|
"jobs_scheduled_completion": "Jobs Scheduled Completion",
|
||||||
"jobs_reconcile": "Parts/Sublet/Labor Reconciliation",
|
"jobs_reconcile": "Parts/Sublet/Labor Reconciliation",
|
||||||
"lag_time": "Lag Time",
|
"lag_time": "Lag Time",
|
||||||
"open_orders": "Open Orders by Date",
|
"open_orders": "Open Orders by Date",
|
||||||
|
|||||||
@@ -405,7 +405,8 @@
|
|||||||
"list-active": "",
|
"list-active": "",
|
||||||
"list-all": "",
|
"list-all": "",
|
||||||
"list-ready": "",
|
"list-ready": "",
|
||||||
"partsqueue": ""
|
"partsqueue": "",
|
||||||
|
"void": ""
|
||||||
},
|
},
|
||||||
"owners": {
|
"owners": {
|
||||||
"detail": "",
|
"detail": "",
|
||||||
@@ -857,7 +858,9 @@
|
|||||||
"prodhrssummary": "",
|
"prodhrssummary": "",
|
||||||
"productiondollars": "",
|
"productiondollars": "",
|
||||||
"productionhours": "",
|
"productionhours": "",
|
||||||
"projectedmonthlysales": ""
|
"projectedmonthlysales": "",
|
||||||
|
"scheduledintoday": "",
|
||||||
|
"scheduledouttoday": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
@@ -1450,6 +1453,7 @@
|
|||||||
"dms_make": "",
|
"dms_make": "",
|
||||||
"dms_model": "",
|
"dms_model": "",
|
||||||
"dms_wip_acctnumber": "",
|
"dms_wip_acctnumber": "",
|
||||||
|
"dms_unsold": "",
|
||||||
"id": "",
|
"id": "",
|
||||||
"inservicedate": "",
|
"inservicedate": "",
|
||||||
"journal": "",
|
"journal": "",
|
||||||
@@ -2563,6 +2567,7 @@
|
|||||||
"job_costing_ro_ins_co": "",
|
"job_costing_ro_ins_co": "",
|
||||||
"jobs_completed_not_invoiced": "",
|
"jobs_completed_not_invoiced": "",
|
||||||
"jobs_invoiced_not_exported": "",
|
"jobs_invoiced_not_exported": "",
|
||||||
|
"jobs_scheduled_completion": "",
|
||||||
"jobs_reconcile": "",
|
"jobs_reconcile": "",
|
||||||
"lag_time": "",
|
"lag_time": "",
|
||||||
"open_orders": "",
|
"open_orders": "",
|
||||||
|
|||||||
@@ -405,7 +405,8 @@
|
|||||||
"list-active": "",
|
"list-active": "",
|
||||||
"list-all": "",
|
"list-all": "",
|
||||||
"list-ready": "",
|
"list-ready": "",
|
||||||
"partsqueue": ""
|
"partsqueue": "",
|
||||||
|
"void": ""
|
||||||
},
|
},
|
||||||
"owners": {
|
"owners": {
|
||||||
"detail": "",
|
"detail": "",
|
||||||
@@ -857,7 +858,9 @@
|
|||||||
"prodhrssummary": "",
|
"prodhrssummary": "",
|
||||||
"productiondollars": "",
|
"productiondollars": "",
|
||||||
"productionhours": "",
|
"productionhours": "",
|
||||||
"projectedmonthlysales": ""
|
"projectedmonthlysales": "",
|
||||||
|
"scheduledintoday": "",
|
||||||
|
"scheduledouttoday": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
@@ -1450,6 +1453,7 @@
|
|||||||
"dms_make": "",
|
"dms_make": "",
|
||||||
"dms_model": "",
|
"dms_model": "",
|
||||||
"dms_wip_acctnumber": "",
|
"dms_wip_acctnumber": "",
|
||||||
|
"dms_unsold": "",
|
||||||
"id": "",
|
"id": "",
|
||||||
"inservicedate": "",
|
"inservicedate": "",
|
||||||
"journal": "",
|
"journal": "",
|
||||||
@@ -2563,6 +2567,7 @@
|
|||||||
"job_costing_ro_ins_co": "",
|
"job_costing_ro_ins_co": "",
|
||||||
"jobs_completed_not_invoiced": "",
|
"jobs_completed_not_invoiced": "",
|
||||||
"jobs_invoiced_not_exported": "",
|
"jobs_invoiced_not_exported": "",
|
||||||
|
"jobs_scheduled_completion": "",
|
||||||
"jobs_reconcile": "",
|
"jobs_reconcile": "",
|
||||||
"lag_time": "",
|
"lag_time": "",
|
||||||
"open_orders": "",
|
"open_orders": "",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button, notification, Space } from "antd";
|
|||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import * as serviceWorkerRegistration from "../serviceWorkerRegistration";
|
import * as serviceWorkerRegistration from "../serviceWorkerRegistration";
|
||||||
|
import { store } from "../redux/store";
|
||||||
|
|
||||||
const onServiceWorkerUpdate = (registration) => {
|
const onServiceWorkerUpdate = (registration) => {
|
||||||
console.log("onServiceWorkerUpdate", registration);
|
console.log("onServiceWorkerUpdate", registration);
|
||||||
@@ -33,6 +34,9 @@ const onServiceWorkerUpdate = (registration) => {
|
|||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
store.dispatch()
|
||||||
|
|
||||||
notification.open({
|
notification.open({
|
||||||
icon: <AlertOutlined />,
|
icon: <AlertOutlined />,
|
||||||
message: i18n.t("general.messages.newversiontitle"),
|
message: i18n.t("general.messages.newversiontitle"),
|
||||||
|
|||||||
@@ -512,6 +512,7 @@ export const TemplateList = (type, context) => {
|
|||||||
key: "dms_posting_sheet",
|
key: "dms_posting_sheet",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
group: "financial",
|
group: "financial",
|
||||||
|
dms: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
@@ -1896,6 +1897,18 @@ export const TemplateList = (type, context) => {
|
|||||||
},
|
},
|
||||||
group: "sales",
|
group: "sales",
|
||||||
},
|
},
|
||||||
|
jobs_scheduled_completion: {
|
||||||
|
title: i18n.t("reportcenter.templates.jobs_scheduled_completion"),
|
||||||
|
subject: i18n.t("reportcenter.templates.jobs_scheduled_completion"),
|
||||||
|
key: "jobs_scheduled_completion",
|
||||||
|
//idtype: "vendor",
|
||||||
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||||
|
field: i18n.t("jobs.fields.scheduled_completion"),
|
||||||
|
},
|
||||||
|
group: "jobs",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
...(!type || type === "courtesycarcontract"
|
...(!type || type === "courtesycarcontract"
|
||||||
|
|||||||
@@ -2092,6 +2092,13 @@
|
|||||||
table:
|
table:
|
||||||
name: employee_team_members
|
name: employee_team_members
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: joblines
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: assigned_team
|
||||||
|
table:
|
||||||
|
name: joblines
|
||||||
|
schema: public
|
||||||
insert_permissions:
|
insert_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
@@ -2665,6 +2672,9 @@
|
|||||||
name: joblines
|
name: joblines
|
||||||
schema: public
|
schema: public
|
||||||
object_relationships:
|
object_relationships:
|
||||||
|
- name: employee_team
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: assigned_team
|
||||||
- name: job
|
- name: job
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: jobid
|
foreign_key_constraint_on: jobid
|
||||||
@@ -2690,6 +2700,13 @@
|
|||||||
table:
|
table:
|
||||||
name: inventory
|
name: inventory
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: parts_dispatch_lines
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: joblineid
|
||||||
|
table:
|
||||||
|
name: parts_dispatch_lines
|
||||||
|
schema: public
|
||||||
- name: parts_order_lines
|
- name: parts_order_lines
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -2719,6 +2736,7 @@
|
|||||||
- alt_part_i
|
- alt_part_i
|
||||||
- alt_partm
|
- alt_partm
|
||||||
- alt_partno
|
- alt_partno
|
||||||
|
- assigned_team
|
||||||
- bett_amt
|
- bett_amt
|
||||||
- bett_pctg
|
- bett_pctg
|
||||||
- bett_tax
|
- bett_tax
|
||||||
@@ -2727,6 +2745,7 @@
|
|||||||
- convertedtolbr
|
- convertedtolbr
|
||||||
- convertedtolbr_data
|
- convertedtolbr_data
|
||||||
- created_at
|
- created_at
|
||||||
|
- critical
|
||||||
- db_hrs
|
- db_hrs
|
||||||
- db_price
|
- db_price
|
||||||
- db_ref
|
- db_ref
|
||||||
@@ -2786,6 +2805,7 @@
|
|||||||
- alt_part_i
|
- alt_part_i
|
||||||
- alt_partm
|
- alt_partm
|
||||||
- alt_partno
|
- alt_partno
|
||||||
|
- assigned_team
|
||||||
- bett_amt
|
- bett_amt
|
||||||
- bett_pctg
|
- bett_pctg
|
||||||
- bett_tax
|
- bett_tax
|
||||||
@@ -2865,6 +2885,7 @@
|
|||||||
- alt_part_i
|
- alt_part_i
|
||||||
- alt_partm
|
- alt_partm
|
||||||
- alt_partno
|
- alt_partno
|
||||||
|
- assigned_team
|
||||||
- bett_amt
|
- bett_amt
|
||||||
- bett_pctg
|
- bett_pctg
|
||||||
- bett_tax
|
- bett_tax
|
||||||
@@ -3131,6 +3152,13 @@
|
|||||||
table:
|
table:
|
||||||
name: notes
|
name: notes
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: parts_dispatches
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: jobid
|
||||||
|
table:
|
||||||
|
name: parts_dispatch
|
||||||
|
schema: public
|
||||||
- name: parts_orders
|
- name: parts_orders
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -4556,6 +4584,165 @@
|
|||||||
template_engine: Kriti
|
template_engine: Kriti
|
||||||
url: '{{$base_url}}/opensearch'
|
url: '{{$base_url}}/opensearch'
|
||||||
version: 2
|
version: 2
|
||||||
|
- table:
|
||||||
|
name: parts_dispatch
|
||||||
|
schema: public
|
||||||
|
object_relationships:
|
||||||
|
- name: job
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: jobid
|
||||||
|
array_relationships:
|
||||||
|
- name: parts_dispatch_lines
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: partsdispatchid
|
||||||
|
table:
|
||||||
|
name: parts_dispatch_lines
|
||||||
|
schema: public
|
||||||
|
insert_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
check:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
columns:
|
||||||
|
- id
|
||||||
|
- created_at
|
||||||
|
- updated_at
|
||||||
|
- jobid
|
||||||
|
- number
|
||||||
|
- employeeid
|
||||||
|
- dispatched_at
|
||||||
|
- dispatched_by
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- number
|
||||||
|
- dispatched_by
|
||||||
|
- created_at
|
||||||
|
- dispatched_at
|
||||||
|
- updated_at
|
||||||
|
- employeeid
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
filter:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
update_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- number
|
||||||
|
- dispatched_by
|
||||||
|
- created_at
|
||||||
|
- dispatched_at
|
||||||
|
- updated_at
|
||||||
|
- employeeid
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
filter:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
check: null
|
||||||
|
- table:
|
||||||
|
name: parts_dispatch_lines
|
||||||
|
schema: public
|
||||||
|
object_relationships:
|
||||||
|
- name: jobline
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: joblineid
|
||||||
|
- name: parts_dispatch
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: partsdispatchid
|
||||||
|
insert_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
check:
|
||||||
|
parts_dispatch:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
columns:
|
||||||
|
- id
|
||||||
|
- created_at
|
||||||
|
- updated_at
|
||||||
|
- partsdispatchid
|
||||||
|
- joblineid
|
||||||
|
- quantity
|
||||||
|
- accepted_at
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- quantity
|
||||||
|
- accepted_at
|
||||||
|
- created_at
|
||||||
|
- updated_at
|
||||||
|
- id
|
||||||
|
- joblineid
|
||||||
|
- partsdispatchid
|
||||||
|
filter:
|
||||||
|
parts_dispatch:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
update_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- id
|
||||||
|
- created_at
|
||||||
|
- updated_at
|
||||||
|
- partsdispatchid
|
||||||
|
- joblineid
|
||||||
|
- quantity
|
||||||
|
- accepted_at
|
||||||
|
filter:
|
||||||
|
parts_dispatch:
|
||||||
|
job:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
check: null
|
||||||
- table:
|
- table:
|
||||||
name: parts_order_lines
|
name: parts_order_lines
|
||||||
schema: public
|
schema: public
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."parts_dispatch";
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
CREATE TABLE "public"."parts_dispatch" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "jobid" uuid NOT NULL, "number" serial NOT NULL, "employeeid" uuid NOT NULL, "dispatched_at" timestamptz NOT NULL, "dispatched_by" text NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE cascade ON DELETE cascade);
|
||||||
|
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
DECLARE
|
||||||
|
_new record;
|
||||||
|
BEGIN
|
||||||
|
_new := NEW;
|
||||||
|
_new."updated_at" = NOW();
|
||||||
|
RETURN _new;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
CREATE TRIGGER "set_public_parts_dispatch_updated_at"
|
||||||
|
BEFORE UPDATE ON "public"."parts_dispatch"
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
||||||
|
COMMENT ON TRIGGER "set_public_parts_dispatch_updated_at" ON "public"."parts_dispatch"
|
||||||
|
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."parts_dispatch_lines";
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
CREATE TABLE "public"."parts_dispatch_lines" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "partsdispatchid" UUID NOT NULL, "joblineid" uuid NOT NULL, "quantity" numeric NOT NULL DEFAULT 1, "accepted_at" timestamptz NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("joblineid") REFERENCES "public"."joblines"("id") ON UPDATE cascade ON DELETE cascade);
|
||||||
|
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
DECLARE
|
||||||
|
_new record;
|
||||||
|
BEGIN
|
||||||
|
_new := NEW;
|
||||||
|
_new."updated_at" = NOW();
|
||||||
|
RETURN _new;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
CREATE TRIGGER "set_public_parts_dispatch_lines_updated_at"
|
||||||
|
BEFORE UPDATE ON "public"."parts_dispatch_lines"
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
||||||
|
COMMENT ON TRIGGER "set_public_parts_dispatch_lines_updated_at" ON "public"."parts_dispatch_lines"
|
||||||
|
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."parts_dispatch_lines" drop constraint "parts_dispatch_lines_partsdispatchid_fkey";
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
alter table "public"."parts_dispatch_lines"
|
||||||
|
add constraint "parts_dispatch_lines_partsdispatchid_fkey"
|
||||||
|
foreign key ("partsdispatchid")
|
||||||
|
references "public"."parts_dispatch"
|
||||||
|
("id") on update cascade on delete cascade;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."parts_dispatch_lines" alter column "accepted_at" set not null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."parts_dispatch_lines" alter column "accepted_at" drop not null;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
alter table "public"."job_conversations" drop constraint "job_conversations_conversationid_fkey",
|
||||||
|
add constraint "job_conversations_conversationid_fkey"
|
||||||
|
foreign key ("conversationid")
|
||||||
|
references "public"."conversations"
|
||||||
|
("id") on update restrict on delete restrict;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
alter table "public"."job_conversations" drop constraint "job_conversations_conversationid_fkey",
|
||||||
|
add constraint "job_conversations_conversationid_fkey"
|
||||||
|
foreign key ("conversationid")
|
||||||
|
references "public"."conversations"
|
||||||
|
("id") on update cascade on delete cascade;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."joblines" add column "assigned_team" uuid
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."joblines" add column "assigned_team" uuid
|
||||||
|
null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."joblines" drop constraint "joblines_assigned_team_fkey";
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
alter table "public"."joblines"
|
||||||
|
add constraint "joblines_assigned_team_fkey"
|
||||||
|
foreign key ("assigned_team")
|
||||||
|
references "public"."employee_teams"
|
||||||
|
("id") on update restrict on delete restrict;
|
||||||
@@ -133,7 +133,13 @@ const generateBillLine = (billLine, responsibilityCenters, jobClass) => {
|
|||||||
const findTaxCode = (billLine, taxcode) => {
|
const findTaxCode = (billLine, taxcode) => {
|
||||||
const {
|
const {
|
||||||
applicable_taxes: { local, state, federal },
|
applicable_taxes: { local, state, federal },
|
||||||
} = billLine;
|
} =
|
||||||
|
billLine.applicable_taxes === null
|
||||||
|
? {
|
||||||
|
...billLine,
|
||||||
|
applicable_taxes: { local: false, state: false, federal: false },
|
||||||
|
}
|
||||||
|
: billLine;
|
||||||
const t = taxcode.filter(
|
const t = taxcode.filter(
|
||||||
(t) =>
|
(t) =>
|
||||||
!!t.local === !!local &&
|
!!t.local === !!local &&
|
||||||
|
|||||||
@@ -262,10 +262,10 @@ const generateInvoiceQbxml = (
|
|||||||
RefNumber: jobs_by_pk.ro_number,
|
RefNumber: jobs_by_pk.ro_number,
|
||||||
BillAddress: {
|
BillAddress: {
|
||||||
Addr1: jobs_by_pk.ownr_co_nm
|
Addr1: jobs_by_pk.ownr_co_nm
|
||||||
? jobs_by_pk.ownr_co_nm.substring(0, 30)
|
? jobs_by_pk.ownr_co_nm.substring(0, 30).trim()
|
||||||
: `${`${jobs_by_pk.ownr_ln || ""} ${
|
: `${`${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""}`
|
||||||
jobs_by_pk.ownr_fn || ""
|
.substring(0, 30)
|
||||||
}`.substring(0, 30)}`,
|
.trim()}`,
|
||||||
Addr2: jobs_by_pk.ownr_addr1,
|
Addr2: jobs_by_pk.ownr_addr1,
|
||||||
Addr3: jobs_by_pk.ownr_addr2,
|
Addr3: jobs_by_pk.ownr_addr2,
|
||||||
City: jobs_by_pk.ownr_city,
|
City: jobs_by_pk.ownr_city,
|
||||||
@@ -274,10 +274,10 @@ const generateInvoiceQbxml = (
|
|||||||
},
|
},
|
||||||
ShipAddress: {
|
ShipAddress: {
|
||||||
Addr1: jobs_by_pk.ownr_co_nm
|
Addr1: jobs_by_pk.ownr_co_nm
|
||||||
? jobs_by_pk.ownr_co_nm.substring(0, 30)
|
? jobs_by_pk.ownr_co_nm.substring(0, 30).trim()
|
||||||
: `${`${jobs_by_pk.ownr_ln || ""} ${
|
: `${`${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""}`
|
||||||
jobs_by_pk.ownr_fn || ""
|
.substring(0, 30)
|
||||||
}`.substring(0, 30)}`,
|
.trim()}`,
|
||||||
Addr2: jobs_by_pk.ownr_addr1,
|
Addr2: jobs_by_pk.ownr_addr1,
|
||||||
Addr3: jobs_by_pk.ownr_addr2,
|
Addr3: jobs_by_pk.ownr_addr2,
|
||||||
City: jobs_by_pk.ownr_city,
|
City: jobs_by_pk.ownr_city,
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ exports.generateOwnerTier = (jobs_by_pk, isThreeTier, twotierpref) => {
|
|||||||
? `${jobs_by_pk.ownr_co_nm.substring(0, 30)} #${
|
? `${jobs_by_pk.ownr_co_nm.substring(0, 30)} #${
|
||||||
jobs_by_pk.owner.accountingid || ""
|
jobs_by_pk.owner.accountingid || ""
|
||||||
}`
|
}`
|
||||||
: `${`${jobs_by_pk.ownr_ln || ""} ${
|
: `${`${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""}`
|
||||||
jobs_by_pk.ownr_fn || ""
|
.substring(0, 30)
|
||||||
}`.substring(0, 30)} #${jobs_by_pk.owner.accountingid || ""}`
|
.trim()} #${jobs_by_pk.owner.accountingid || ""}`
|
||||||
)
|
)
|
||||||
.trim()
|
.trim()
|
||||||
.replace(":", " ");
|
.replace(":", " ");
|
||||||
@@ -39,9 +39,9 @@ exports.generateOwnerTier = (jobs_by_pk, isThreeTier, twotierpref) => {
|
|||||||
? `${jobs_by_pk.ownr_co_nm.substring(0, 30)} #${
|
? `${jobs_by_pk.ownr_co_nm.substring(0, 30)} #${
|
||||||
jobs_by_pk.owner.accountingid || ""
|
jobs_by_pk.owner.accountingid || ""
|
||||||
}`
|
}`
|
||||||
: `${`${jobs_by_pk.ownr_ln || ""} ${
|
: `${`${jobs_by_pk.ownr_ln || ""} ${jobs_by_pk.ownr_fn || ""}`
|
||||||
jobs_by_pk.ownr_fn || ""
|
.substring(0, 30)
|
||||||
}`.substring(0, 30)} #${jobs_by_pk.owner.accountingid || ""}`
|
.trim()} #${jobs_by_pk.owner.accountingid || ""}`
|
||||||
)
|
)
|
||||||
.trim()
|
.trim()
|
||||||
.replace(":", " ");
|
.replace(":", " ");
|
||||||
|
|||||||
@@ -717,21 +717,33 @@ async function InsertDmsVehicle(socket) {
|
|||||||
dealer: {
|
dealer: {
|
||||||
dealerNumber: socket.JobData.bodyshop.cdk_dealerid,
|
dealerNumber: socket.JobData.bodyshop.cdk_dealerid,
|
||||||
...(socket.txEnvelope.inservicedate && {
|
...(socket.txEnvelope.inservicedate && {
|
||||||
inServiceDate: moment(socket.txEnvelope.inservicedate)
|
inServiceDate:
|
||||||
//.tz(socket.JobData.bodyshop.timezone)
|
socket.txEnvelope.dms_unsold === true
|
||||||
.startOf("day")
|
? ""
|
||||||
.toISOString(),
|
: moment(socket.txEnvelope.inservicedate)
|
||||||
|
//.tz(socket.JobData.bodyshop.timezone)
|
||||||
|
.startOf("day")
|
||||||
|
.toISOString(),
|
||||||
}),
|
}),
|
||||||
vehicleId: socket.DMSVid.vehiclesVehId,
|
vehicleId: socket.DMSVid.vehiclesVehId,
|
||||||
},
|
},
|
||||||
manufacturer: {},
|
manufacturer: {},
|
||||||
vehicle: {
|
vehicle: {
|
||||||
deliveryDate: moment()
|
deliveryDate:
|
||||||
// .tz(socket.JobData.bodyshop.timezone)
|
socket.txEnvelope.dms_unsold === true
|
||||||
.format("YYYYMMDD"),
|
? ""
|
||||||
licensePlateNo: String(socket.JobData.plate_no)
|
: moment()
|
||||||
.replace(/([^\w]|_)/g, "")
|
// .tz(socket.JobData.bodyshop.timezone)
|
||||||
.toUpperCase(),
|
.format("YYYYMMDD"),
|
||||||
|
licensePlateNo:
|
||||||
|
socket.JobData.plate_no === null
|
||||||
|
? null
|
||||||
|
: String(socket.JobData.plate_no).replace(/([^\w]|_)/g, "")
|
||||||
|
.length === 0
|
||||||
|
? null
|
||||||
|
: String(socket.JobData.plate_no)
|
||||||
|
.replace(/([^\w]|_)/g, "")
|
||||||
|
.toUpperCase(),
|
||||||
make: socket.txEnvelope.dms_make,
|
make: socket.txEnvelope.dms_make,
|
||||||
modelAbrev: socket.txEnvelope.dms_model,
|
modelAbrev: socket.txEnvelope.dms_model,
|
||||||
modelYear: socket.JobData.v_model_yr,
|
modelYear: socket.JobData.v_model_yr,
|
||||||
@@ -854,19 +866,25 @@ async function UpdateDmsVehicle(socket) {
|
|||||||
...socket.DMSVeh.dealer,
|
...socket.DMSVeh.dealer,
|
||||||
...((socket.txEnvelope.inservicedate ||
|
...((socket.txEnvelope.inservicedate ||
|
||||||
socket.DMSVeh.dealer.inServiceDate) && {
|
socket.DMSVeh.dealer.inServiceDate) && {
|
||||||
inServiceDate: moment(
|
inServiceDate:
|
||||||
socket.DMSVeh.dealer.inServiceDate ||
|
socket.txEnvelope.dms_unsold === true
|
||||||
socket.txEnvelope.inservicedate
|
? ""
|
||||||
)
|
: moment(
|
||||||
// .tz(socket.JobData.bodyshop.timezone)
|
socket.DMSVeh.dealer.inServiceDate ||
|
||||||
.toISOString(),
|
socket.txEnvelope.inservicedate
|
||||||
|
)
|
||||||
|
// .tz(socket.JobData.bodyshop.timezone)
|
||||||
|
.toISOString(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
vehicle: {
|
vehicle: {
|
||||||
...socket.DMSVeh.vehicle,
|
...socket.DMSVeh.vehicle,
|
||||||
deliveryDate: moment(socket.DMSVeh.vehicle.deliveryDate)
|
deliveryDate:
|
||||||
//.tz(socket.JobData.bodyshop.timezone)
|
socket.txEnvelope.dms_unsold === true
|
||||||
.toISOString(),
|
? ""
|
||||||
|
: moment(socket.DMSVeh.vehicle.deliveryDate)
|
||||||
|
//.tz(socket.JobData.bodyshop.timezone)
|
||||||
|
.toISOString(),
|
||||||
},
|
},
|
||||||
owners: ids,
|
owners: ids,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ async function OpenSearchUpdateHandler(req, res) {
|
|||||||
"v_model_yr",
|
"v_model_yr",
|
||||||
"v_make_desc",
|
"v_make_desc",
|
||||||
"v_model_desc",
|
"v_model_desc",
|
||||||
|
"v_vin",
|
||||||
]);
|
]);
|
||||||
document.bodyshopid = req.body.event.data.new.shopid;
|
document.bodyshopid = req.body.event.data.new.shopid;
|
||||||
break;
|
break;
|
||||||
@@ -139,7 +140,7 @@ async function OpenSearchUpdateHandler(req, res) {
|
|||||||
"exported_at",
|
"exported_at",
|
||||||
"invoice_number",
|
"invoice_number",
|
||||||
"is_credit_memo",
|
"is_credit_memo",
|
||||||
"total"
|
"total",
|
||||||
]),
|
]),
|
||||||
...bill.bills_by_pk,
|
...bill.bills_by_pk,
|
||||||
bodyshopid: bill.bills_by_pk.job.shopid,
|
bodyshopid: bill.bills_by_pk.job.shopid,
|
||||||
@@ -244,17 +245,54 @@ async function OpensearchSearchHandler(req, res) {
|
|||||||
bool: {
|
bool: {
|
||||||
must: [
|
must: [
|
||||||
{
|
{
|
||||||
multi_match: {
|
match: {
|
||||||
query: search,
|
bodyshopid: assocs.associations[0].shopid,
|
||||||
type: "phrase_prefix",
|
|
||||||
//fields: ["*"],
|
|
||||||
// fuzziness: "5",
|
|
||||||
//prefix_length: 2,
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: {
|
bool: {
|
||||||
bodyshopid: assocs.associations[0].shopid,
|
should: [
|
||||||
|
{
|
||||||
|
multi_match: {
|
||||||
|
query: search,
|
||||||
|
type: "cross_fields",
|
||||||
|
fields: ["*ownr_fn", "*ownr_ln"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
multi_match: {
|
||||||
|
query: search,
|
||||||
|
type: "most_fields",
|
||||||
|
fields: [
|
||||||
|
"*v_model_yr",
|
||||||
|
"*v_make_desc^2",
|
||||||
|
"*v_model_desc^3",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
query_string: {
|
||||||
|
query: `*${search}*`,
|
||||||
|
|
||||||
|
fields: [
|
||||||
|
"*ro_number^20",
|
||||||
|
"*clm_no^14",
|
||||||
|
"*v_vin^12",
|
||||||
|
"*plate_no^12",
|
||||||
|
"*ownr_ln^10",
|
||||||
|
"transactionid^10",
|
||||||
|
"paymentnum^10",
|
||||||
|
"invoice_number^10",
|
||||||
|
"*ownr_fn^8",
|
||||||
|
"*ownr_co_nm^8",
|
||||||
|
"*ownr_ph1^8",
|
||||||
|
"*ownr_ph2^8",
|
||||||
|
"*",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
minimum_should_match: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user