Merge branch 'development' of https://bitbucket.org/snaptsoft/bodyshop into development

This commit is contained in:
Patrick Fic
2021-02-22 09:55:09 -08:00
78 changed files with 35978 additions and 134 deletions

View File

@@ -1,13 +1,12 @@
{
"env": {
"browser": true,
"commonjs": true,
"es2021": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
},
"rules": {
}
"env": {
"browser": false,
"commonjs": true,
"es2021": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
},
"rules": {}
}

View File

@@ -16,7 +16,7 @@ npx hasura migrate apply --endpoint https://db.imex.online/ --admin-secret 'Prod
NGROK TEsting:
./ngrok.exe http https://localhost:5000 -host-header="localhost:5000"
./ngrok.exe http http://localhost:5000 -host-header="localhost:5000"
Finding deadfiles - run from client directory
npx deadfile ./src/index.js --exclude build templates

View File

@@ -1,4 +1,4 @@
<babeledit_project be_version="2.7.1" version="1.2">
<babeledit_project version="1.2" be_version="2.7.1">
<!--
BabelEdit project file
@@ -3276,6 +3276,53 @@
</translation>
</translations>
</concept_node>
<folder_node>
<name>md_hour_split</name>
<children>
<concept_node>
<name>lab</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>lar</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<concept_node>
<name>md_ins_cos</name>
<definition_loaded>false</definition_loaded>
@@ -14324,6 +14371,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>voiding</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@@ -19792,6 +19860,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>voidjob</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@@ -20133,6 +20222,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>voided</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
</children>
@@ -21208,6 +21318,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>void</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@@ -21700,6 +21831,27 @@
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>maxtenimages</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>messaging</name>
<definition_loaded>false</definition_loaded>
@@ -21805,6 +21957,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>selectmedia</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>sentby</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>typeamessage</name>
<definition_loaded>false</definition_loaded>

26348
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,88 @@
import { PictureFilled } from "@ant-design/icons";
import { useQuery } from "@apollo/react-hooks";
import { Badge, Popover } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { GET_DOCUMENTS_BY_JOB } from "../../graphql/documents.queries";
import AlertComponent from "../alert/alert.component";
import JobDocumentsGalleryExternal from "../jobs-documents-gallery/jobs-documents-gallery.external.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(ChatMediaSelector);
export function ChatMediaSelector({
selectedMedia,
setSelectedMedia,
conversation,
}) {
const { t } = useTranslation();
console.log("conversation", conversation);
const { loading, error, data, refetch } = useQuery(GET_DOCUMENTS_BY_JOB, {
variables: {
jobId:
conversation.job_conversations[0] &&
conversation.job_conversations[0].jobid,
},
fetchPolicy: "network-only",
skip:
!conversation.job_conversations ||
conversation.job_conversations.length === 0,
});
const [visible, setVisible] = useState(false);
const handleVisibleChange = (visible) => {
setVisible(visible);
};
useEffect(() => {
setSelectedMedia([]);
}, [setSelectedMedia, conversation]);
const content = (
<div>
{loading && <LoadingSpinner />}
{error && <AlertComponent message={error.message} type="error" />}
{selectedMedia.filter((s) => s.isSelected).length >= 10 ? (
<div style={{ color: "red" }}>{t("messaging.labels.maxtenimages")}</div>
) : null}
{data && (
<JobDocumentsGalleryExternal
data={data ? data.documents : []}
externalMediaState={[selectedMedia, setSelectedMedia]}
/>
)}
</div>
);
return (
<Popover
content={
conversation.job_conversations.length === 0 ? (
<div>{t("messaging.errors.noattachedjobs")}</div>
) : (
content
)
}
title={t("messaging.labels.selectmedia")}
trigger="click"
visible={visible}
onVisibleChange={handleVisibleChange}
>
<Badge
size="small"
count={selectedMedia.filter((s) => s.isSelected).length}
>
<PictureFilled style={{ margin: "0 .5rem" }} />
</Badge>
</Popover>
);
}

View File

@@ -1,4 +1,6 @@
import Icon from "@ant-design/icons";
import i18n from "i18next";
import moment from "moment";
import React, { useEffect, useRef } from "react";
import { MdDone, MdDoneAll } from "react-icons/md";
import {
@@ -44,6 +46,16 @@ export default function ChatMessageListComponent({ messages }) {
{MessageRender(messages[index])}
{StatusRender(messages[index].status)}
</div>
{messages[index].isoutbound && (
<div style={{ fontSize: 10 }}>
{i18n.t("messaging.labels.sentby", {
by: messages[index].userid,
time: moment(messages[index].created_at).format(
"MM/DD/YYYY @ hh:mm a"
),
})}
</div>
)}
</div>
)}
</CellMeasurer>
@@ -72,15 +84,19 @@ export default function ChatMessageListComponent({ messages }) {
}
const MessageRender = (message) => {
if (message.image) {
return (
<a href={message.image_path} target="__blank">
<img alt="Received" className="message-img" src={message.image_path} />
</a>
);
} else {
return <span>{message.text}</span>;
}
return (
<div>
{message.image_path &&
message.image_path.map((i, idx) => (
<div key={idx} style={{ display: "flex", justifyContent: "center" }}>
<a href={i} target="__blank">
<img alt="Received" className="message-img" src={i} />
</a>
</div>
))}
<div>{message.text}</div>
</div>
);
};
const StatusRender = (status) => {

View File

@@ -34,9 +34,10 @@
//display: inline-block;
.message-img {
max-width: 3rem;
max-height: 3rem;
max-width: 10rem;
max-height: 10rem;
object-fit: contain;
margin: 0.2rem;
}
}

View File

@@ -1,6 +1,6 @@
import { LoadingOutlined, SendOutlined } from "@ant-design/icons";
import { Input, Spin } from "antd";
import React, { useEffect, useRef } from "react";
import React, { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -14,6 +14,7 @@ import {
selectMessage,
} from "../../redux/messaging/messaging.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import ChatMediaSelector from "../chat-media-selector/chat-media-selector.component";
import ChatPresetsComponent from "../chat-presets/chat-presets.component";
const mapStateToProps = createStructuredSelector({
@@ -36,6 +37,7 @@ function ChatSendMessageComponent({
setMessage,
}) {
const inputArea = useRef(null);
const [selectedMedia, setSelectedMedia] = useState([]);
useEffect(() => {
inputArea.current.focus();
}, [isSending, setMessage]);
@@ -43,36 +45,55 @@ function ChatSendMessageComponent({
const { t } = useTranslation();
const handleEnter = () => {
if (message === "" || !message) return;
logImEXEvent("messaging_send_message");
sendMessage({
to: conversation.phone_num,
body: message,
messagingServiceSid: bodyshop.messagingservicesid,
conversationid: conversation.id,
});
const selectedImages = selectedMedia.filter((i) => i.isSelected);
if (selectedImages < 11) {
sendMessage({
to: conversation.phone_num,
body: message,
messagingServiceSid: bodyshop.messagingservicesid,
conversationid: conversation.id,
selectedMedia: selectedImages,
});
setSelectedMedia(
selectedMedia.map((i) => {
return { ...i, isSelected: false };
})
);
}
};
return (
<div className="imex-flex-row" style={{ width: "100%" }}>
<ChatPresetsComponent className="imex-flex-row__margin" />
<Input.TextArea
className="imex-flex-row__margin imex-flex-row__grow"
allowClear
autoFocus
ref={inputArea}
autoSize={{ minRows: 1, maxRows: 4 }}
value={message}
disabled={isSending}
placeholder={t("messaging.labels.typeamessage")}
onChange={(e) => setMessage(e.target.value)}
onPressEnter={(event) => {
event.preventDefault();
if (!!!event.shiftKey) handleEnter();
}}
<ChatMediaSelector
conversation={conversation}
selectedMedia={selectedMedia}
setSelectedMedia={setSelectedMedia}
/>
<span style={{ flex: 1 }}>
<Input.TextArea
className="imex-flex-row__margin imex-flex-row__grow"
allowClear
autoFocus
ref={inputArea}
autoSize={{ minRows: 1, maxRows: 4 }}
value={message}
disabled={isSending}
placeholder={t("messaging.labels.typeamessage")}
onChange={(e) => setMessage(e.target.value)}
onPressEnter={(event) => {
event.preventDefault();
if (!!!event.shiftKey) handleEnter();
}}
/>
</span>
<SendOutlined
className="imex-flex-row__margin"
disabled={message === "" || !message}
onClick={handleEnter}
/>
<SendOutlined className="imex-flex-row__margin" onClick={handleEnter} />
<Spin
style={{ display: `${isSending ? "" : "none"}` }}
indicator={

View File

@@ -1,12 +1,13 @@
import { useLazyQuery } from "@apollo/react-hooks";
import { AutoComplete, Input } from "antd";
import _ from "lodash";
import React from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import AlertComponent from "../alert/alert.component";
export default function GlobalSearch() {
const { t } = useTranslation();
@@ -14,27 +15,18 @@ export default function GlobalSearch() {
GLOBAL_SEARCH_QUERY
);
const handleSearch = (searchTerm) => {
logImEXEvent("global_search", { term: searchTerm });
const executeSearch = (v) => {
callSearch(v);
};
const debouncedExecuteSearch = _.debounce(executeSearch, 500);
if (searchTerm.length > 0)
callSearch({ variables: { search: searchTerm } });
const handleSearch = (value) => {
if (value && value !== "")
debouncedExecuteSearch({ variables: { search: value } });
};
const renderTitle = (title) => {
return (
<span>
{title}
<a
style={{ float: "right" }}
href="https://www.google.com/search?q=antd"
target="_blank"
rel="noopener noreferrer"
>
more
</a>
</span>
);
return <span>{title}</span>;
};
const options = data
@@ -155,8 +147,9 @@ export default function GlobalSearch() {
dropdownMatchSelectWidth={false}
style={{ width: 200 }}
options={options}
onSearch={handleSearch}
>
<Input.Search loading={loading} onSearch={handleSearch} />
<Input.Search loading={loading} />
</AutoComplete>
</div>
);

View File

@@ -75,6 +75,7 @@ function Header({
className="header-main-menu"
selectedKeys={[selectedHeader]}
onClick={handleMenuClick}
subMenuCloseDelay={0.3}
>
<Menu.Item key="home">
<Link to="/manage">

View File

@@ -267,7 +267,6 @@ export function JobsDetailHeaderActions({
key="jobcosting"
onClick={() => {
logImEXEvent("job_header_job_costing");
setJobCostingContext({
actions: { refetch: refetch },
context: {
@@ -309,6 +308,45 @@ export function JobsDetailHeaderActions({
</Popconfirm>
</Menu.Item>
)}
{!jobRO && job.converted && (
<Menu.Item>
<Popconfirm
title={t("jobs.labels.voidjob")}
okText="Yes"
cancelText="No"
onClick={(e) => e.stopPropagation()}
onConfirm={async () => {
//delete the job.
const result = await updateJob({
variables: {
jobId: job.id,
job: {
status: bodyshop.md_ro_statuses.default_void,
voided: true,
},
},
});
if (!!!result.errors) {
notification["success"]({
message: t("jobs.successes.voided"),
});
//go back to jobs list.
history.push(`/manage/`);
} else {
notification["error"]({
message: t("jobs.errors.voiding", {
error: JSON.stringify(result.errors),
}),
});
}
}}
getPopupContainer={(trigger) => trigger.parentNode}
>
{t("menus.jobsactions.void")}
</Popconfirm>
</Menu.Item>
)}
</Menu>
);
return (

View File

@@ -1,5 +1,5 @@
import React from "react";
import { useQuery } from "@apollo/react-hooks";
import React from "react";
import { GET_DOCUMENTS_BY_JOB } from "../../graphql/documents.queries";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";

View File

@@ -0,0 +1,58 @@
import React, { useEffect } from "react";
import Gallery from "react-grid-gallery";
import { useTranslation } from "react-i18next";
import { DetermineFileType } from "../documents-upload/documents-upload.utility";
function JobsDocumentGalleryExternal({
data,
externalMediaState,
}) {
const [galleryImages, setgalleryImages] = externalMediaState;
const { t } = useTranslation();
useEffect(() => {
let documents = data.reduce((acc, value) => {
if (value.type.startsWith("image")) {
acc.push({
src: `${
process.env.REACT_APP_CLOUDINARY_ENDPOINT
}/${DetermineFileType(value.type)}/upload/${value.key}`,
thumbnail: `${
process.env.REACT_APP_CLOUDINARY_ENDPOINT
}/${DetermineFileType(value.type)}/upload/${
process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS
}/${value.key}`,
thumbnailHeight: 225,
thumbnailWidth: 225,
isSelected: false,
key: value.key,
extension: value.extension,
id: value.id,
type: value.type,
tags: [{ value: value.type, title: value.type }],
});
}
return acc;
}, []);
setgalleryImages(documents);
}, [data, setgalleryImages, t]);
return (
<div className="clearfix">
<Gallery
images={galleryImages}
backdropClosesModal={true}
onSelectImage={(index, image) => {
setgalleryImages(
galleryImages.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g
)
);
}}
/>
</div>
);
}
export default JobsDocumentGalleryExternal;

View File

@@ -1,5 +1,5 @@
import React from "react";
import { Dropdown, Button, Table } from "antd";
import { Dropdown, Button, Table, Space } from "antd";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import ScoreboardRemoveButton from "../scoreboard-remove-button/scorebard-remove-button.component";
@@ -42,10 +42,10 @@ export default function ScoreboardJobsList({ scoreBoardlist }) {
dataIndex: "actions",
key: "actions",
render: (text, record) => (
<div>
<Space>
<ScoreboardEntryEdit entry={record} style={{ zIndex: 15 }} />
<ScoreboardRemoveButton scoreboardId={record.id} />
</div>
</Space>
),
},
];

View File

@@ -648,6 +648,30 @@ export default function ShopInfoComponent({ form, saveLoading }) {
>
<Switch />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_hour_split.lab")}
name={["md_hour_split", "lab"]}
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<InputNumber min={0} max={1} precision={2} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.md_hour_split.lar")}
name={["md_hour_split", "lar"]}
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}
>
<InputNumber min={0} max={1} precision={2} />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>
<Collapse.Panel

View File

@@ -169,7 +169,9 @@ export default function ShopInfoROStatusComponent({ form }) {
>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
@@ -185,7 +187,9 @@ export default function ShopInfoROStatusComponent({ form }) {
>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
@@ -201,7 +205,9 @@ export default function ShopInfoROStatusComponent({ form }) {
>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
@@ -217,7 +223,9 @@ export default function ShopInfoROStatusComponent({ form }) {
>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
@@ -233,7 +241,9 @@ export default function ShopInfoROStatusComponent({ form }) {
>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
@@ -249,7 +259,9 @@ export default function ShopInfoROStatusComponent({ form }) {
>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
@@ -265,7 +277,9 @@ export default function ShopInfoROStatusComponent({ form }) {
>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>
@@ -281,7 +295,9 @@ export default function ShopInfoROStatusComponent({ form }) {
>
<Select>
{options.map((item, idx) => (
<Select.Option key={idx}>{item}</Select.Option>
<Select.Option key={idx} value={item}>
{item}
</Select.Option>
))}
</Select>
</Form.Item>

View File

@@ -79,6 +79,7 @@ export const QUERY_BODYSHOP = gql`
workingdays
use_fippa
md_payment_types
md_hour_split
employees {
id
first_name
@@ -156,6 +157,7 @@ export const UPDATE_SHOP = gql`
workingdays
use_fippa
md_payment_types
md_hour_split
employees {
id
first_name

View File

@@ -39,6 +39,8 @@ export const CONVERSATION_SUBSCRIPTION_BY_PK = gql`
isoutbound
image
image_path
userid
created_at
}
messages_aggregate(
where: { read: { _eq: false }, isoutbound: { _eq: false } }

View File

@@ -473,6 +473,7 @@ export const GET_JOB_BY_PK = gql`
class
category
deliverchecklist
voided
joblines(where: { jobid: { _eq: $id } }, order_by: { line_no: asc }) {
id
line_no
@@ -615,6 +616,7 @@ export const QUERY_JOB_CARD_DETAILS = gql`
updated_at
clm_total
ded_amt
voided
cccontracts {
id
agreementnumber
@@ -657,7 +659,7 @@ export const QUERY_TECH_JOB_DETAILS = gql`
date_invoiced
date_open
date_exported
voided
date_scheduled
date_estimated
employee_body

View File

@@ -2,6 +2,7 @@ import { useMutation, useQuery } from "@apollo/react-hooks";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component";
import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
import NotFound from "../../components/not-found/not-found.component";
@@ -13,9 +14,14 @@ import {
setJobReadOnly,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { CreateRecentItem } from "../../utils/create-recent-item";
import JobsDetailPage from "./jobs-detail.page.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
addRecentItem: (item) => dispatch(addRecentItem(item)),
@@ -24,6 +30,7 @@ const mapDispatchToProps = (dispatch) => ({
});
function JobsDetailPageContainer({
bodyshop,
match,
setBreadcrumbs,
addRecentItem,
@@ -64,7 +71,9 @@ function JobsDetailPageContainer({
if (data && data.jobs_by_pk) {
setJobReadOnly(
!!data.jobs_by_pk.date_exported || !!data.jobs_by_pk.date_invoiced
data.jobs_by_pk.date_exported ||
data.jobs_by_pk.date_invoiced ||
data.jobs_by_pk.voided
);
addRecentItem(
@@ -108,4 +117,7 @@ function JobsDetailPageContainer({
<AlertComponent message={t("jobs.errors.noaccess")} type="error" />
);
}
export default connect(null, mapDispatchToProps)(JobsDetailPageContainer);
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobsDetailPageContainer);

View File

@@ -215,6 +215,10 @@
"logo_img_path": "Shop Logo",
"md_categories": "Categories",
"md_classes": "Classes",
"md_hour_split": {
"lab": "Body Hour Split",
"lar": "Refinish Hour Split"
},
"md_ins_cos": "Insurance Companies",
"md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources",
@@ -909,9 +913,10 @@
"noowner": "No owner associated.",
"novehicle": "No vehicle associated.",
"saving": "Error encountered while saving record.",
"updating": "Error while updating job(s). {{error}}",
"updating": "Error while updating job(s). {{error}}",
"validation": "Please ensure all fields are entered correctly.",
"validationtitle": "Validation Error"
"validationtitle": "Validation Error",
"voiding": "Error voiding job. {{error}}"
},
"fields": {
"actual_completion": "Actual Completion",
@@ -1189,7 +1194,8 @@
"totals": "Totals",
"vehicle_info": "Vehicle",
"vehicleassociation": "Vehicle Association",
"viewallocations": "View Allocations"
"viewallocations": "View Allocations",
"voidjob": "Are you sure you want to void this job? This cannot be easily undone. "
},
"successes": {
"addedtoproduction": "Job added to production board.",
@@ -1207,7 +1213,8 @@
"save": "Job saved successfully.",
"savetitle": "Record saved successfully.",
"supplemented": "Job supplemented successfully. ",
"updated": "Job(s) updated successfully."
"updated": "Job(s) updated successfully.",
"voided": "Job voided successfully."
}
},
"menus": {
@@ -1267,7 +1274,8 @@
"deletejob": "Delete Job",
"duplicate": "Duplicate this Job",
"duplicatenolines": "Duplicate this Job without Repair Data",
"newcccontract": "Create Courtesy Car Contract"
"newcccontract": "Create Courtesy Car Contract",
"void": "Void Job"
},
"jobsdetail": {
"claimdetail": "Claim Details",
@@ -1302,11 +1310,14 @@
"new": "New Conversation"
},
"labels": {
"maxtenimages": "You can only select up to a maximum of 10 images at a time.",
"messaging": "Messaging",
"noallowtxt": "This customer has not indicated their permission to be messaged.",
"nojobs": "Not associated to any job.",
"phonenumber": "Phone #",
"presets": "Presets",
"selectmedia": "Select Media",
"sentby": "Sent by {{by}} at {{time}}",
"typeamessage": "Send a message..."
}
},

View File

@@ -215,6 +215,10 @@
"logo_img_path": "",
"md_categories": "",
"md_classes": "",
"md_hour_split": {
"lab": "",
"lar": ""
},
"md_ins_cos": "",
"md_payment_types": "",
"md_referral_sources": "",
@@ -911,7 +915,8 @@
"saving": "Se encontró un error al guardar el registro.",
"updating": "",
"validation": "Asegúrese de que todos los campos se ingresen correctamente.",
"validationtitle": "Error de validacion"
"validationtitle": "Error de validacion",
"voiding": ""
},
"fields": {
"actual_completion": "Realización real",
@@ -1189,7 +1194,8 @@
"totals": "",
"vehicle_info": "Vehículo",
"vehicleassociation": "",
"viewallocations": ""
"viewallocations": "",
"voidjob": ""
},
"successes": {
"addedtoproduction": "",
@@ -1207,7 +1213,8 @@
"save": "Trabajo guardado con éxito.",
"savetitle": "Registro guardado con éxito.",
"supplemented": "Trabajo complementado con éxito.",
"updated": ""
"updated": "",
"voided": ""
}
},
"menus": {
@@ -1267,7 +1274,8 @@
"deletejob": "",
"duplicate": "",
"duplicatenolines": "",
"newcccontract": ""
"newcccontract": "",
"void": ""
},
"jobsdetail": {
"claimdetail": "Detalles de la reclamación",
@@ -1302,11 +1310,14 @@
"new": ""
},
"labels": {
"maxtenimages": "",
"messaging": "Mensajería",
"noallowtxt": "",
"nojobs": "",
"phonenumber": "",
"presets": "",
"selectmedia": "",
"sentby": "",
"typeamessage": "Enviar un mensaje..."
}
},

View File

@@ -215,6 +215,10 @@
"logo_img_path": "",
"md_categories": "",
"md_classes": "",
"md_hour_split": {
"lab": "",
"lar": ""
},
"md_ins_cos": "",
"md_payment_types": "",
"md_referral_sources": "",
@@ -911,7 +915,8 @@
"saving": "Erreur rencontrée lors de la sauvegarde de l'enregistrement.",
"updating": "",
"validation": "Veuillez vous assurer que tous les champs sont correctement entrés.",
"validationtitle": "Erreur de validation"
"validationtitle": "Erreur de validation",
"voiding": ""
},
"fields": {
"actual_completion": "Achèvement réel",
@@ -1189,7 +1194,8 @@
"totals": "",
"vehicle_info": "Véhicule",
"vehicleassociation": "",
"viewallocations": ""
"viewallocations": "",
"voidjob": ""
},
"successes": {
"addedtoproduction": "",
@@ -1207,7 +1213,8 @@
"save": "Le travail a été enregistré avec succès.",
"savetitle": "Enregistrement enregistré avec succès.",
"supplemented": "Travail complété avec succès.",
"updated": ""
"updated": "",
"voided": ""
}
},
"menus": {
@@ -1267,7 +1274,8 @@
"deletejob": "",
"duplicate": "",
"duplicatenolines": "",
"newcccontract": ""
"newcccontract": "",
"void": ""
},
"jobsdetail": {
"claimdetail": "Détails de la réclamation",
@@ -1302,11 +1310,14 @@
"new": ""
},
"labels": {
"maxtenimages": "",
"messaging": "Messagerie",
"noallowtxt": "",
"nojobs": "",
"phonenumber": "",
"presets": "",
"selectmedia": "",
"sentby": "",
"typeamessage": "Envoyer un message..."
}
},

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,9 @@
- args:
cascade: false
read_only: false
sql: "CREATE OR REPLACE FUNCTION public.search_bills(search text)\n RETURNS SETOF
bills\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search = ''
then\n return query select * from bills ;\n else \n return query SELECT\n
\ *\nFROM\n bills, vendors\nWHERE\nbills.vendorid= vendors.id and \n (search
<% (invoice_number)\n OR\n search <% (name)\n )\n \n ;\n end if;\n\n\tEND\n$function$;"
type: run_sql

View File

@@ -0,0 +1 @@
[]

View File

@@ -0,0 +1,10 @@
- args:
cascade: false
read_only: false
sql: "CREATE OR REPLACE FUNCTION public.search_bills(search text)\n RETURNS SETOF
bills\n LANGUAGE plpgsql\n STABLE\nAS $function$\n\nBEGIN\n if search = ''
then\n return query select * from bills ;\n else \n return query SELECT\n
\ bills.*\nFROM\n bills, vendors\nWHERE\nbills.vendorid= vendors.id and \n
\ (search <% (invoice_number)\n OR\n search <% (name)\n )\n \n ;\n end
if;\n\n\tEND\n$function$;"
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."jobs" DROP COLUMN "voided";
type: run_sql

View File

@@ -0,0 +1,6 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."jobs" ADD COLUMN "voided" boolean NOT NULL DEFAULT
false;
type: run_sql

View File

@@ -0,0 +1,262 @@
- args:
role: user
table:
name: jobs
schema: public
type: drop_insert_permission
- args:
permission:
check:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- actual_completion
- actual_delivery
- actual_in
- adj_g_disc
- adj_strdis
- adj_towdis
- adjustment_bottom_line
- agt_addr1
- agt_addr2
- agt_city
- agt_co_id
- agt_co_nm
- agt_ct_fn
- agt_ct_ln
- agt_ct_ph
- agt_ct_phx
- agt_ctry
- agt_ea
- agt_fax
- agt_faxx
- agt_lic_no
- agt_ph1
- agt_ph1x
- agt_ph2
- agt_ph2x
- agt_st
- agt_zip
- alt_transport
- area_of_damage
- asgn_date
- asgn_no
- asgn_type
- ca_gst_registrant
- cat_no
- category
- cieca_stl
- cieca_ttl
- ciecaid
- class
- clm_addr1
- clm_addr2
- clm_city
- clm_ct_fn
- clm_ct_ln
- clm_ct_ph
- clm_ct_phx
- clm_ctry
- clm_ea
- clm_fax
- clm_faxx
- clm_no
- clm_ofc_id
- clm_ofc_nm
- clm_ph1
- clm_ph1x
- clm_ph2
- clm_ph2x
- clm_st
- clm_title
- clm_total
- clm_zip
- converted
- created_at
- csr
- cust_pr
- date_estimated
- date_exported
- date_invoiced
- date_open
- date_scheduled
- ded_amt
- ded_status
- deliverchecklist
- depreciation_taxes
- employee_body
- employee_prep
- employee_refinish
- est_addr1
- est_addr2
- est_city
- est_co_nm
- est_ct_fn
- est_ct_ln
- est_ctry
- est_ea
- est_ph1
- est_st
- est_zip
- federal_tax_rate
- g_bett_amt
- id
- inproduction
- ins_addr1
- ins_addr2
- ins_city
- ins_co_id
- ins_co_nm
- ins_ct_fn
- ins_ct_ln
- ins_ct_ph
- ins_ct_phx
- ins_ctry
- ins_ea
- ins_fax
- ins_faxx
- ins_memo
- ins_ph1
- ins_ph1x
- ins_ph2
- ins_ph2x
- ins_st
- ins_title
- ins_zip
- insd_addr1
- insd_addr2
- insd_city
- insd_co_nm
- insd_ctry
- insd_ea
- insd_fax
- insd_faxx
- insd_fn
- insd_ln
- insd_ph1
- insd_ph1x
- insd_ph2
- insd_ph2x
- insd_st
- insd_title
- insd_zip
- intakechecklist
- invoice_allocation
- invoice_date
- job_totals
- kanbanparent
- kmin
- kmout
- labor_rate_desc
- labor_rate_id
- lbr_adjustments
- local_tax_rate
- loss_cat
- loss_date
- loss_desc
- loss_type
- other_amount_payable
- owner_owing
- ownerid
- ownr_addr1
- ownr_addr2
- ownr_city
- ownr_co_nm
- ownr_ctry
- ownr_ea
- ownr_fax
- ownr_faxx
- ownr_fn
- ownr_ln
- ownr_ph1
- ownr_ph1x
- ownr_ph2
- ownr_ph2x
- ownr_st
- ownr_title
- ownr_zip
- parts_tax_rates
- pay_amt
- pay_chknm
- pay_date
- pay_type
- payee_nms
- plate_no
- plate_st
- po_number
- policy_no
- production_vars
- queued_for_parts
- rate_la1
- rate_la2
- rate_la3
- rate_la4
- rate_laa
- rate_lab
- rate_lad
- rate_lae
- rate_laf
- rate_lag
- rate_lam
- rate_lar
- rate_las
- rate_lau
- rate_ma2s
- rate_ma2t
- rate_ma3s
- rate_mabl
- rate_macs
- rate_mahw
- rate_mapa
- rate_mash
- rate_matd
- referral_source
- regie_number
- ro_number
- scheduled_completion
- scheduled_delivery
- scheduled_in
- selling_dealer
- selling_dealer_contact
- servicing_dealer
- servicing_dealer_contact
- shopid
- special_coverage_policy
- state_tax_rate
- status
- storage_payable
- tax_lbr_rt
- tax_levies_rt
- tax_paint_mat_rt
- tax_predis
- tax_prethr
- tax_pstthr
- tax_registration_number
- tax_shop_mat_rt
- tax_str_rt
- tax_sub_rt
- tax_thramt
- tax_tow_rt
- theft_ind
- tlos_ind
- towing_payable
- unit_number
- updated_at
- v_color
- v_make_desc
- v_model_desc
- v_model_yr
- v_vin
- vehicleid
set: {}
role: user
table:
name: jobs
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,263 @@
- args:
role: user
table:
name: jobs
schema: public
type: drop_insert_permission
- args:
permission:
check:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- actual_completion
- actual_delivery
- actual_in
- adj_g_disc
- adj_strdis
- adj_towdis
- adjustment_bottom_line
- agt_addr1
- agt_addr2
- agt_city
- agt_co_id
- agt_co_nm
- agt_ct_fn
- agt_ct_ln
- agt_ct_ph
- agt_ct_phx
- agt_ctry
- agt_ea
- agt_fax
- agt_faxx
- agt_lic_no
- agt_ph1
- agt_ph1x
- agt_ph2
- agt_ph2x
- agt_st
- agt_zip
- alt_transport
- area_of_damage
- asgn_date
- asgn_no
- asgn_type
- ca_gst_registrant
- cat_no
- category
- cieca_stl
- cieca_ttl
- ciecaid
- class
- clm_addr1
- clm_addr2
- clm_city
- clm_ct_fn
- clm_ct_ln
- clm_ct_ph
- clm_ct_phx
- clm_ctry
- clm_ea
- clm_fax
- clm_faxx
- clm_no
- clm_ofc_id
- clm_ofc_nm
- clm_ph1
- clm_ph1x
- clm_ph2
- clm_ph2x
- clm_st
- clm_title
- clm_total
- clm_zip
- converted
- created_at
- csr
- cust_pr
- date_estimated
- date_exported
- date_invoiced
- date_open
- date_scheduled
- ded_amt
- ded_status
- deliverchecklist
- depreciation_taxes
- employee_body
- employee_prep
- employee_refinish
- est_addr1
- est_addr2
- est_city
- est_co_nm
- est_ct_fn
- est_ct_ln
- est_ctry
- est_ea
- est_ph1
- est_st
- est_zip
- federal_tax_rate
- g_bett_amt
- id
- inproduction
- ins_addr1
- ins_addr2
- ins_city
- ins_co_id
- ins_co_nm
- ins_ct_fn
- ins_ct_ln
- ins_ct_ph
- ins_ct_phx
- ins_ctry
- ins_ea
- ins_fax
- ins_faxx
- ins_memo
- ins_ph1
- ins_ph1x
- ins_ph2
- ins_ph2x
- ins_st
- ins_title
- ins_zip
- insd_addr1
- insd_addr2
- insd_city
- insd_co_nm
- insd_ctry
- insd_ea
- insd_fax
- insd_faxx
- insd_fn
- insd_ln
- insd_ph1
- insd_ph1x
- insd_ph2
- insd_ph2x
- insd_st
- insd_title
- insd_zip
- intakechecklist
- invoice_allocation
- invoice_date
- job_totals
- kanbanparent
- kmin
- kmout
- labor_rate_desc
- labor_rate_id
- lbr_adjustments
- local_tax_rate
- loss_cat
- loss_date
- loss_desc
- loss_type
- other_amount_payable
- owner_owing
- ownerid
- ownr_addr1
- ownr_addr2
- ownr_city
- ownr_co_nm
- ownr_ctry
- ownr_ea
- ownr_fax
- ownr_faxx
- ownr_fn
- ownr_ln
- ownr_ph1
- ownr_ph1x
- ownr_ph2
- ownr_ph2x
- ownr_st
- ownr_title
- ownr_zip
- parts_tax_rates
- pay_amt
- pay_chknm
- pay_date
- pay_type
- payee_nms
- plate_no
- plate_st
- po_number
- policy_no
- production_vars
- queued_for_parts
- rate_la1
- rate_la2
- rate_la3
- rate_la4
- rate_laa
- rate_lab
- rate_lad
- rate_lae
- rate_laf
- rate_lag
- rate_lam
- rate_lar
- rate_las
- rate_lau
- rate_ma2s
- rate_ma2t
- rate_ma3s
- rate_mabl
- rate_macs
- rate_mahw
- rate_mapa
- rate_mash
- rate_matd
- referral_source
- regie_number
- ro_number
- scheduled_completion
- scheduled_delivery
- scheduled_in
- selling_dealer
- selling_dealer_contact
- servicing_dealer
- servicing_dealer_contact
- shopid
- special_coverage_policy
- state_tax_rate
- status
- storage_payable
- tax_lbr_rt
- tax_levies_rt
- tax_paint_mat_rt
- tax_predis
- tax_prethr
- tax_pstthr
- tax_registration_number
- tax_shop_mat_rt
- tax_str_rt
- tax_sub_rt
- tax_thramt
- tax_tow_rt
- theft_ind
- tlos_ind
- towing_payable
- unit_number
- updated_at
- v_color
- v_make_desc
- v_model_desc
- v_model_yr
- v_vin
- vehicleid
- voided
set: {}
role: user
table:
name: jobs
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,263 @@
- args:
role: user
table:
name: jobs
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- actual_completion
- actual_delivery
- actual_in
- adj_g_disc
- adj_strdis
- adj_towdis
- adjustment_bottom_line
- agt_addr1
- agt_addr2
- agt_city
- agt_co_id
- agt_co_nm
- agt_ct_fn
- agt_ct_ln
- agt_ct_ph
- agt_ct_phx
- agt_ctry
- agt_ea
- agt_fax
- agt_faxx
- agt_lic_no
- agt_ph1
- agt_ph1x
- agt_ph2
- agt_ph2x
- agt_st
- agt_zip
- alt_transport
- area_of_damage
- asgn_date
- asgn_no
- asgn_type
- ca_gst_registrant
- cat_no
- category
- cieca_stl
- cieca_ttl
- ciecaid
- class
- clm_addr1
- clm_addr2
- clm_city
- clm_ct_fn
- clm_ct_ln
- clm_ct_ph
- clm_ct_phx
- clm_ctry
- clm_ea
- clm_fax
- clm_faxx
- clm_no
- clm_ofc_id
- clm_ofc_nm
- clm_ph1
- clm_ph1x
- clm_ph2
- clm_ph2x
- clm_st
- clm_title
- clm_total
- clm_zip
- converted
- created_at
- csr
- cust_pr
- date_estimated
- date_exported
- date_invoiced
- date_open
- date_scheduled
- ded_amt
- ded_status
- deliverchecklist
- depreciation_taxes
- employee_body
- employee_prep
- employee_refinish
- est_addr1
- est_addr2
- est_city
- est_co_nm
- est_ct_fn
- est_ct_ln
- est_ctry
- est_ea
- est_ph1
- est_st
- est_zip
- federal_tax_rate
- g_bett_amt
- id
- inproduction
- ins_addr1
- ins_addr2
- ins_city
- ins_co_id
- ins_co_nm
- ins_ct_fn
- ins_ct_ln
- ins_ct_ph
- ins_ct_phx
- ins_ctry
- ins_ea
- ins_fax
- ins_faxx
- ins_memo
- ins_ph1
- ins_ph1x
- ins_ph2
- ins_ph2x
- ins_st
- ins_title
- ins_zip
- insd_addr1
- insd_addr2
- insd_city
- insd_co_nm
- insd_ctry
- insd_ea
- insd_fax
- insd_faxx
- insd_fn
- insd_ln
- insd_ph1
- insd_ph1x
- insd_ph2
- insd_ph2x
- insd_st
- insd_title
- insd_zip
- intakechecklist
- invoice_allocation
- invoice_date
- job_totals
- kanbanparent
- kmin
- kmout
- labor_rate_desc
- labor_rate_id
- lbr_adjustments
- local_tax_rate
- loss_cat
- loss_date
- loss_desc
- loss_type
- other_amount_payable
- owner_owing
- ownerid
- ownr_addr1
- ownr_addr2
- ownr_city
- ownr_co_nm
- ownr_ctry
- ownr_ea
- ownr_fax
- ownr_faxx
- ownr_fn
- ownr_ln
- ownr_ph1
- ownr_ph1x
- ownr_ph2
- ownr_ph2x
- ownr_st
- ownr_title
- ownr_zip
- parts_tax_rates
- pay_amt
- pay_chknm
- pay_date
- pay_type
- payee_nms
- plate_no
- plate_st
- po_number
- policy_no
- production_vars
- queued_for_parts
- rate_la1
- rate_la2
- rate_la3
- rate_la4
- rate_laa
- rate_lab
- rate_lad
- rate_lae
- rate_laf
- rate_lag
- rate_lam
- rate_lar
- rate_las
- rate_lau
- rate_ma2s
- rate_ma2t
- rate_ma3s
- rate_mabl
- rate_macs
- rate_mahw
- rate_mapa
- rate_mash
- rate_matd
- referral_source
- regie_number
- ro_number
- scheduled_completion
- scheduled_delivery
- scheduled_in
- selling_dealer
- selling_dealer_contact
- servicing_dealer
- servicing_dealer_contact
- shopid
- special_coverage_policy
- state_tax_rate
- status
- storage_payable
- tax_lbr_rt
- tax_levies_rt
- tax_paint_mat_rt
- tax_predis
- tax_prethr
- tax_pstthr
- tax_registration_number
- tax_shop_mat_rt
- tax_str_rt
- tax_sub_rt
- tax_thramt
- tax_tow_rt
- theft_ind
- tlos_ind
- towing_payable
- unit_number
- updated_at
- v_color
- v_make_desc
- v_model_desc
- v_model_yr
- v_vin
- vehicleid
computed_fields: []
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: jobs
schema: public
type: create_select_permission

View File

@@ -0,0 +1,264 @@
- args:
role: user
table:
name: jobs
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- actual_completion
- actual_delivery
- actual_in
- adj_g_disc
- adj_strdis
- adj_towdis
- adjustment_bottom_line
- agt_addr1
- agt_addr2
- agt_city
- agt_co_id
- agt_co_nm
- agt_ct_fn
- agt_ct_ln
- agt_ct_ph
- agt_ct_phx
- agt_ctry
- agt_ea
- agt_fax
- agt_faxx
- agt_lic_no
- agt_ph1
- agt_ph1x
- agt_ph2
- agt_ph2x
- agt_st
- agt_zip
- alt_transport
- area_of_damage
- asgn_date
- asgn_no
- asgn_type
- ca_gst_registrant
- cat_no
- category
- cieca_stl
- cieca_ttl
- ciecaid
- class
- clm_addr1
- clm_addr2
- clm_city
- clm_ct_fn
- clm_ct_ln
- clm_ct_ph
- clm_ct_phx
- clm_ctry
- clm_ea
- clm_fax
- clm_faxx
- clm_no
- clm_ofc_id
- clm_ofc_nm
- clm_ph1
- clm_ph1x
- clm_ph2
- clm_ph2x
- clm_st
- clm_title
- clm_total
- clm_zip
- converted
- created_at
- csr
- cust_pr
- date_estimated
- date_exported
- date_invoiced
- date_open
- date_scheduled
- ded_amt
- ded_status
- deliverchecklist
- depreciation_taxes
- employee_body
- employee_prep
- employee_refinish
- est_addr1
- est_addr2
- est_city
- est_co_nm
- est_ct_fn
- est_ct_ln
- est_ctry
- est_ea
- est_ph1
- est_st
- est_zip
- federal_tax_rate
- g_bett_amt
- id
- inproduction
- ins_addr1
- ins_addr2
- ins_city
- ins_co_id
- ins_co_nm
- ins_ct_fn
- ins_ct_ln
- ins_ct_ph
- ins_ct_phx
- ins_ctry
- ins_ea
- ins_fax
- ins_faxx
- ins_memo
- ins_ph1
- ins_ph1x
- ins_ph2
- ins_ph2x
- ins_st
- ins_title
- ins_zip
- insd_addr1
- insd_addr2
- insd_city
- insd_co_nm
- insd_ctry
- insd_ea
- insd_fax
- insd_faxx
- insd_fn
- insd_ln
- insd_ph1
- insd_ph1x
- insd_ph2
- insd_ph2x
- insd_st
- insd_title
- insd_zip
- intakechecklist
- invoice_allocation
- invoice_date
- job_totals
- kanbanparent
- kmin
- kmout
- labor_rate_desc
- labor_rate_id
- lbr_adjustments
- local_tax_rate
- loss_cat
- loss_date
- loss_desc
- loss_type
- other_amount_payable
- owner_owing
- ownerid
- ownr_addr1
- ownr_addr2
- ownr_city
- ownr_co_nm
- ownr_ctry
- ownr_ea
- ownr_fax
- ownr_faxx
- ownr_fn
- ownr_ln
- ownr_ph1
- ownr_ph1x
- ownr_ph2
- ownr_ph2x
- ownr_st
- ownr_title
- ownr_zip
- parts_tax_rates
- pay_amt
- pay_chknm
- pay_date
- pay_type
- payee_nms
- plate_no
- plate_st
- po_number
- policy_no
- production_vars
- queued_for_parts
- rate_la1
- rate_la2
- rate_la3
- rate_la4
- rate_laa
- rate_lab
- rate_lad
- rate_lae
- rate_laf
- rate_lag
- rate_lam
- rate_lar
- rate_las
- rate_lau
- rate_ma2s
- rate_ma2t
- rate_ma3s
- rate_mabl
- rate_macs
- rate_mahw
- rate_mapa
- rate_mash
- rate_matd
- referral_source
- regie_number
- ro_number
- scheduled_completion
- scheduled_delivery
- scheduled_in
- selling_dealer
- selling_dealer_contact
- servicing_dealer
- servicing_dealer_contact
- shopid
- special_coverage_policy
- state_tax_rate
- status
- storage_payable
- tax_lbr_rt
- tax_levies_rt
- tax_paint_mat_rt
- tax_predis
- tax_prethr
- tax_pstthr
- tax_registration_number
- tax_shop_mat_rt
- tax_str_rt
- tax_sub_rt
- tax_thramt
- tax_tow_rt
- theft_ind
- tlos_ind
- towing_payable
- unit_number
- updated_at
- v_color
- v_make_desc
- v_model_desc
- v_model_yr
- v_vin
- vehicleid
- voided
computed_fields: []
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: jobs
schema: public
type: create_select_permission

View File

@@ -0,0 +1,262 @@
- args:
role: user
table:
name: jobs
schema: public
type: drop_update_permission
- args:
permission:
columns:
- actual_completion
- actual_delivery
- actual_in
- adj_g_disc
- adj_strdis
- adj_towdis
- adjustment_bottom_line
- agt_addr1
- agt_addr2
- agt_city
- agt_co_id
- agt_co_nm
- agt_ct_fn
- agt_ct_ln
- agt_ct_ph
- agt_ct_phx
- agt_ctry
- agt_ea
- agt_fax
- agt_faxx
- agt_lic_no
- agt_ph1
- agt_ph1x
- agt_ph2
- agt_ph2x
- agt_st
- agt_zip
- alt_transport
- area_of_damage
- asgn_date
- asgn_no
- asgn_type
- ca_gst_registrant
- cat_no
- category
- cieca_stl
- cieca_ttl
- ciecaid
- class
- clm_addr1
- clm_addr2
- clm_city
- clm_ct_fn
- clm_ct_ln
- clm_ct_ph
- clm_ct_phx
- clm_ctry
- clm_ea
- clm_fax
- clm_faxx
- clm_no
- clm_ofc_id
- clm_ofc_nm
- clm_ph1
- clm_ph1x
- clm_ph2
- clm_ph2x
- clm_st
- clm_title
- clm_total
- clm_zip
- converted
- created_at
- csr
- cust_pr
- date_estimated
- date_exported
- date_invoiced
- date_open
- date_scheduled
- ded_amt
- ded_status
- deliverchecklist
- depreciation_taxes
- employee_body
- employee_prep
- employee_refinish
- est_addr1
- est_addr2
- est_city
- est_co_nm
- est_ct_fn
- est_ct_ln
- est_ctry
- est_ea
- est_ph1
- est_st
- est_zip
- federal_tax_rate
- g_bett_amt
- id
- inproduction
- ins_addr1
- ins_addr2
- ins_city
- ins_co_id
- ins_co_nm
- ins_ct_fn
- ins_ct_ln
- ins_ct_ph
- ins_ct_phx
- ins_ctry
- ins_ea
- ins_fax
- ins_faxx
- ins_memo
- ins_ph1
- ins_ph1x
- ins_ph2
- ins_ph2x
- ins_st
- ins_title
- ins_zip
- insd_addr1
- insd_addr2
- insd_city
- insd_co_nm
- insd_ctry
- insd_ea
- insd_fax
- insd_faxx
- insd_fn
- insd_ln
- insd_ph1
- insd_ph1x
- insd_ph2
- insd_ph2x
- insd_st
- insd_title
- insd_zip
- intakechecklist
- invoice_allocation
- invoice_date
- job_totals
- kanbanparent
- kmin
- kmout
- labor_rate_desc
- labor_rate_id
- lbr_adjustments
- local_tax_rate
- loss_cat
- loss_date
- loss_desc
- loss_type
- other_amount_payable
- owner_owing
- ownerid
- ownr_addr1
- ownr_addr2
- ownr_city
- ownr_co_nm
- ownr_ctry
- ownr_ea
- ownr_fax
- ownr_faxx
- ownr_fn
- ownr_ln
- ownr_ph1
- ownr_ph1x
- ownr_ph2
- ownr_ph2x
- ownr_st
- ownr_title
- ownr_zip
- parts_tax_rates
- pay_amt
- pay_chknm
- pay_date
- pay_type
- payee_nms
- plate_no
- plate_st
- po_number
- policy_no
- production_vars
- queued_for_parts
- rate_la1
- rate_la2
- rate_la3
- rate_la4
- rate_laa
- rate_lab
- rate_lad
- rate_lae
- rate_laf
- rate_lag
- rate_lam
- rate_lar
- rate_las
- rate_lau
- rate_ma2s
- rate_ma2t
- rate_ma3s
- rate_mabl
- rate_macs
- rate_mahw
- rate_mapa
- rate_mash
- rate_matd
- referral_source
- regie_number
- ro_number
- scheduled_completion
- scheduled_delivery
- scheduled_in
- selling_dealer
- selling_dealer_contact
- servicing_dealer
- servicing_dealer_contact
- shopid
- special_coverage_policy
- state_tax_rate
- status
- storage_payable
- tax_lbr_rt
- tax_levies_rt
- tax_paint_mat_rt
- tax_predis
- tax_prethr
- tax_pstthr
- tax_registration_number
- tax_shop_mat_rt
- tax_str_rt
- tax_sub_rt
- tax_thramt
- tax_tow_rt
- theft_ind
- tlos_ind
- towing_payable
- unit_number
- updated_at
- v_color
- v_make_desc
- v_model_desc
- v_model_yr
- v_vin
- vehicleid
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: jobs
schema: public
type: create_update_permission

View File

@@ -0,0 +1,263 @@
- args:
role: user
table:
name: jobs
schema: public
type: drop_update_permission
- args:
permission:
columns:
- actual_completion
- actual_delivery
- actual_in
- adj_g_disc
- adj_strdis
- adj_towdis
- adjustment_bottom_line
- agt_addr1
- agt_addr2
- agt_city
- agt_co_id
- agt_co_nm
- agt_ct_fn
- agt_ct_ln
- agt_ct_ph
- agt_ct_phx
- agt_ctry
- agt_ea
- agt_fax
- agt_faxx
- agt_lic_no
- agt_ph1
- agt_ph1x
- agt_ph2
- agt_ph2x
- agt_st
- agt_zip
- alt_transport
- area_of_damage
- asgn_date
- asgn_no
- asgn_type
- ca_gst_registrant
- cat_no
- category
- cieca_stl
- cieca_ttl
- ciecaid
- class
- clm_addr1
- clm_addr2
- clm_city
- clm_ct_fn
- clm_ct_ln
- clm_ct_ph
- clm_ct_phx
- clm_ctry
- clm_ea
- clm_fax
- clm_faxx
- clm_no
- clm_ofc_id
- clm_ofc_nm
- clm_ph1
- clm_ph1x
- clm_ph2
- clm_ph2x
- clm_st
- clm_title
- clm_total
- clm_zip
- converted
- created_at
- csr
- cust_pr
- date_estimated
- date_exported
- date_invoiced
- date_open
- date_scheduled
- ded_amt
- ded_status
- deliverchecklist
- depreciation_taxes
- employee_body
- employee_prep
- employee_refinish
- est_addr1
- est_addr2
- est_city
- est_co_nm
- est_ct_fn
- est_ct_ln
- est_ctry
- est_ea
- est_ph1
- est_st
- est_zip
- federal_tax_rate
- g_bett_amt
- id
- inproduction
- ins_addr1
- ins_addr2
- ins_city
- ins_co_id
- ins_co_nm
- ins_ct_fn
- ins_ct_ln
- ins_ct_ph
- ins_ct_phx
- ins_ctry
- ins_ea
- ins_fax
- ins_faxx
- ins_memo
- ins_ph1
- ins_ph1x
- ins_ph2
- ins_ph2x
- ins_st
- ins_title
- ins_zip
- insd_addr1
- insd_addr2
- insd_city
- insd_co_nm
- insd_ctry
- insd_ea
- insd_fax
- insd_faxx
- insd_fn
- insd_ln
- insd_ph1
- insd_ph1x
- insd_ph2
- insd_ph2x
- insd_st
- insd_title
- insd_zip
- intakechecklist
- invoice_allocation
- invoice_date
- job_totals
- kanbanparent
- kmin
- kmout
- labor_rate_desc
- labor_rate_id
- lbr_adjustments
- local_tax_rate
- loss_cat
- loss_date
- loss_desc
- loss_type
- other_amount_payable
- owner_owing
- ownerid
- ownr_addr1
- ownr_addr2
- ownr_city
- ownr_co_nm
- ownr_ctry
- ownr_ea
- ownr_fax
- ownr_faxx
- ownr_fn
- ownr_ln
- ownr_ph1
- ownr_ph1x
- ownr_ph2
- ownr_ph2x
- ownr_st
- ownr_title
- ownr_zip
- parts_tax_rates
- pay_amt
- pay_chknm
- pay_date
- pay_type
- payee_nms
- plate_no
- plate_st
- po_number
- policy_no
- production_vars
- queued_for_parts
- rate_la1
- rate_la2
- rate_la3
- rate_la4
- rate_laa
- rate_lab
- rate_lad
- rate_lae
- rate_laf
- rate_lag
- rate_lam
- rate_lar
- rate_las
- rate_lau
- rate_ma2s
- rate_ma2t
- rate_ma3s
- rate_mabl
- rate_macs
- rate_mahw
- rate_mapa
- rate_mash
- rate_matd
- referral_source
- regie_number
- ro_number
- scheduled_completion
- scheduled_delivery
- scheduled_in
- selling_dealer
- selling_dealer_contact
- servicing_dealer
- servicing_dealer_contact
- shopid
- special_coverage_policy
- state_tax_rate
- status
- storage_payable
- tax_lbr_rt
- tax_levies_rt
- tax_paint_mat_rt
- tax_predis
- tax_prethr
- tax_pstthr
- tax_registration_number
- tax_shop_mat_rt
- tax_str_rt
- tax_sub_rt
- tax_thramt
- tax_tow_rt
- theft_ind
- tlos_ind
- towing_payable
- unit_number
- updated_at
- v_color
- v_make_desc
- v_model_desc
- v_model_yr
- v_vin
- vehicleid
- voided
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: jobs
schema: public
type: create_update_permission

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "md_hour_split";
type: run_sql

View File

@@ -0,0 +1,6 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "md_hour_split" jsonb NOT NULL
DEFAULT jsonb_build_object();
type: run_sql

View File

@@ -0,0 +1,79 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- accountingconfig
- address1
- address2
- appt_alt_transport
- appt_colors
- appt_length
- bill_tax_rates
- city
- country
- created_at
- default_adjustment_rate
- deliverchecklist
- email
- enforce_class
- federal_tax_id
- id
- imexshopid
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- logo_img_path
- md_categories
- md_classes
- md_ins_cos
- md_labor_rates
- md_messaging_presets
- md_notes_presets
- md_order_statuses
- md_parts_locations
- md_payment_types
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- messagingservicesid
- phone
- prodtargethrs
- production_config
- region_config
- schedule_end_time
- schedule_start_time
- scoreboard_target
- shopname
- shoprates
- speedprint
- ssbuckets
- state
- state_tax_id
- stripe_acct_id
- target_touchtime
- template_header
- textid
- updated_at
- use_fippa
- workingdays
- zip_post
computed_fields: []
filter:
associations:
bodyshop:
associations:
user:
authid:
_eq: X-Hasura-User-Id
role: user
table:
name: bodyshops
schema: public
type: create_select_permission

View File

@@ -0,0 +1,80 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- accountingconfig
- address1
- address2
- appt_alt_transport
- appt_colors
- appt_length
- bill_tax_rates
- city
- country
- created_at
- default_adjustment_rate
- deliverchecklist
- email
- enforce_class
- federal_tax_id
- id
- imexshopid
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- logo_img_path
- md_categories
- md_classes
- md_hour_split
- md_ins_cos
- md_labor_rates
- md_messaging_presets
- md_notes_presets
- md_order_statuses
- md_parts_locations
- md_payment_types
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- messagingservicesid
- phone
- prodtargethrs
- production_config
- region_config
- schedule_end_time
- schedule_start_time
- scoreboard_target
- shopname
- shoprates
- speedprint
- ssbuckets
- state
- state_tax_id
- stripe_acct_id
- target_touchtime
- template_header
- textid
- updated_at
- use_fippa
- workingdays
- zip_post
computed_fields: []
filter:
associations:
bodyshop:
associations:
user:
authid:
_eq: X-Hasura-User-Id
role: user
table:
name: bodyshops
schema: public
type: create_select_permission

View File

@@ -0,0 +1,72 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_update_permission
- args:
permission:
columns:
- accountingconfig
- address1
- address2
- appt_alt_transport
- appt_colors
- appt_length
- bill_tax_rates
- city
- country
- created_at
- default_adjustment_rate
- deliverchecklist
- email
- enforce_class
- federal_tax_id
- id
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- logo_img_path
- md_categories
- md_classes
- md_ins_cos
- md_labor_rates
- md_messaging_presets
- md_notes_presets
- md_order_statuses
- md_parts_locations
- md_payment_types
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- phone
- prodtargethrs
- production_config
- schedule_end_time
- schedule_start_time
- scoreboard_target
- shopname
- shoprates
- speedprint
- ssbuckets
- state
- state_tax_id
- target_touchtime
- updated_at
- use_fippa
- workingdays
- zip_post
filter:
associations:
bodyshop:
associations:
user:
authid:
_eq: X-Hasura-User-Id
set: {}
role: user
table:
name: bodyshops
schema: public
type: create_update_permission

View File

@@ -0,0 +1,73 @@
- args:
role: user
table:
name: bodyshops
schema: public
type: drop_update_permission
- args:
permission:
columns:
- accountingconfig
- address1
- address2
- appt_alt_transport
- appt_colors
- appt_length
- bill_tax_rates
- city
- country
- created_at
- default_adjustment_rate
- deliverchecklist
- email
- enforce_class
- federal_tax_id
- id
- inhousevendorid
- insurance_vendor_id
- intakechecklist
- logo_img_path
- md_categories
- md_classes
- md_hour_split
- md_ins_cos
- md_labor_rates
- md_messaging_presets
- md_notes_presets
- md_order_statuses
- md_parts_locations
- md_payment_types
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- phone
- prodtargethrs
- production_config
- schedule_end_time
- schedule_start_time
- scoreboard_target
- shopname
- shoprates
- speedprint
- ssbuckets
- state
- state_tax_id
- target_touchtime
- updated_at
- use_fippa
- workingdays
- zip_post
filter:
associations:
bodyshop:
associations:
user:
authid:
_eq: X-Hasura-User-Id
set: {}
role: user
table:
name: bodyshops
schema: public
type: create_update_permission

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" DROP COLUMN "user";
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" ADD COLUMN "user" uuid NULL;
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: alter table "public"."messages" rename column "userid" to "user";
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: alter table "public"."messages" rename column "user" to "userid";
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" ALTER COLUMN "userid" TYPE uuid;
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" ALTER COLUMN "userid" TYPE text;
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: alter table "public"."messages" drop constraint "messages_userid_fkey";
type: run_sql

View File

@@ -0,0 +1,10 @@
- args:
cascade: false
read_only: false
sql: |-
alter table "public"."messages"
add constraint "messages_userid_fkey"
foreign key ("userid")
references "public"."users"
("email") on update set null on delete set null;
type: run_sql

View File

@@ -0,0 +1,36 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_insert_permission
- args:
permission:
check:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- id
- created_at
- updated_at
- msid
- conversationid
- text
- image
- image_path
- isoutbound
- status
- read
set: {}
role: user
table:
name: messages
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,37 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_insert_permission
- args:
permission:
check:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- conversationid
- created_at
- id
- image
- image_path
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
set: {}
role: user
table:
name: messages
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,37 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- image
- isoutbound
- read
- image_path
- msid
- status
- text
- created_at
- updated_at
- conversationid
- id
computed_fields: []
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: messages
schema: public
type: create_select_permission

View File

@@ -0,0 +1,38 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- conversationid
- created_at
- id
- image
- image_path
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
computed_fields: []
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: messages
schema: public
type: create_select_permission

View File

@@ -0,0 +1,37 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_insert_permission
- args:
permission:
check:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- conversationid
- created_at
- id
- image
- image_path
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
set: {}
role: user
table:
name: messages
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,36 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_insert_permission
- args:
permission:
check:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- conversationid
- created_at
- id
- image
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
set: {}
role: user
table:
name: messages
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,38 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- conversationid
- created_at
- id
- image
- image_path
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
computed_fields: []
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: messages
schema: public
type: create_select_permission

View File

@@ -0,0 +1,37 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- conversationid
- created_at
- id
- image
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
computed_fields: []
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: messages
schema: public
type: create_select_permission

View File

@@ -0,0 +1,36 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_update_permission
- args:
permission:
columns:
- image
- isoutbound
- read
- image_path
- msid
- status
- text
- created_at
- updated_at
- conversationid
- id
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: messages
schema: public
type: create_update_permission

View File

@@ -0,0 +1,35 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_update_permission
- args:
permission:
columns:
- conversationid
- created_at
- id
- image
- isoutbound
- msid
- read
- status
- text
- updated_at
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: messages
schema: public
type: create_update_permission

View File

@@ -0,0 +1,10 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" ADD COLUMN "image_path" text;
type: run_sql
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" ALTER COLUMN "image_path" DROP NOT NULL;
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" DROP COLUMN "image_path" CASCADE;
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" DROP COLUMN "image_path";
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."messages" ADD COLUMN "image_path" jsonb NULL;
type: run_sql

View File

@@ -0,0 +1,36 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_insert_permission
- args:
permission:
check:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- conversationid
- created_at
- id
- image
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
set: {}
role: user
table:
name: messages
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,37 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_insert_permission
- args:
permission:
check:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- conversationid
- created_at
- id
- image
- image_path
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
set: {}
role: user
table:
name: messages
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,37 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- conversationid
- created_at
- id
- image
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
computed_fields: []
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: messages
schema: public
type: create_select_permission

View File

@@ -0,0 +1,38 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: true
columns:
- conversationid
- created_at
- id
- image
- image_path
- isoutbound
- msid
- read
- status
- text
- updated_at
- userid
computed_fields: []
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: messages
schema: public
type: create_select_permission

View File

@@ -0,0 +1,35 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_update_permission
- args:
permission:
columns:
- conversationid
- created_at
- id
- image
- isoutbound
- msid
- read
- status
- text
- updated_at
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: messages
schema: public
type: create_update_permission

View File

@@ -0,0 +1,36 @@
- args:
role: user
table:
name: messages
schema: public
type: drop_update_permission
- args:
permission:
columns:
- conversationid
- created_at
- id
- image
- image_path
- isoutbound
- msid
- read
- status
- text
- updated_at
filter:
conversation:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
set: {}
role: user
table:
name: messages
schema: public
type: create_update_permission

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "autohouseid";
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "autohouseid" text NULL UNIQUE;
type: run_sql

5900
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -133,6 +133,9 @@ var qbo = require("./server/accounting/qbo/qbo");
app.post("/qbo/authorize", qbo.authorize);
app.get("/qbo/callback", qbo.callback);
var data = require("./server/data/data");
app.get("/data/ah", data.autohouse);
app.get("/", async function (req, res) {
res.status(200).send("Access Forbidden.");
});

399
server/data/autohouse.js Normal file
View File

@@ -0,0 +1,399 @@
const GraphQLClient = require("graphql-request").GraphQLClient;
const path = require("path");
const queries = require("../graphql-client/queries");
const Dinero = require("dinero.js");
const moment = require("moment");
var builder = require("xmlbuilder");
require("dotenv").config({
path: path.resolve(
process.cwd(),
`.env.${process.env.NODE_ENV || "development"}`
),
});
const client = require("../graphql-client/graphql-client").client;
const AhDateFormat = "MMDDYYYY";
exports.default = async (req, res) => {
//Get Client Dataset.
const { jobs } = await client.request(queries.AUTOHOUSE_QUERY);
const autoHouseObject = {
AutoHouseExport: { RepairOrder: jobs.map((j) => CreateRepairOrderTag(j)) },
};
var ret = builder
.create(autoHouseObject, {
version: "1.0",
encoding: "UTF-8",
headless: false,
})
.end({ pretty: true });
res.type("application/xml");
res.send(ret);
};
const CreateRepairOrderTag = (job) => {
//Level 2
const ret = {
RepairOrderInformation: {
ShopInternalName: job.bodyshop.autohouseid,
ID: job.id,
RO: job.ro_number,
Est: job.id, //We no longer use estimate id.
GUID: job.id,
TransType: StatusMapping(job.status, job.bodyshop.md_ro_statuses),
ShopName: job.bodyshop.shopname,
ShopAddress: job.bodyshop.address1,
ShopCity: job.bodyshop.city,
ShopState: job.bodyshop.state,
ShopZip: job.bodyshop.zip_post,
ShopPhone: job.bodyshop.phone,
EstimatorID: `${job.est_ct_fn} ${job.est_ct_ln}`,
EstimatorName: `${job.est_ct_fn} ${job.est_ct_ln}`,
},
CustomerInformation: {
FirstName: null,
LastName: null,
Street: null,
City: null,
State: null,
Zip: "N6G",
Phone1: null,
Phone2: null,
Phone2Extension: null,
Phone3: null,
Phone3Extension: null,
FileComments: null,
Source: null,
Email: null,
RetWhsl: null,
Cat: null,
InsuredorClaimantFlag: null,
},
VehicleInformation: {
Year: job.v_model_yr,
Make: job.v_make_desc,
Model: job.v_model_desc,
VIN: job.v_vin,
License: job.plate_no,
MileageIn: job.kmin,
Vehiclecolor: job.v_color,
VehicleProductionDate: null,
VehiclePaintCode: null,
VehicleTrimCode: null,
VehicleBodyStyle: null,
DriveableFlag: job.tlos_ind ? "Y" : "N",
},
InsuranceInformation: {
InsuranceCo: job.ins_co_nm,
CompanyName: job.ins_co_nm,
Address: job.ins_addr1,
City: job.ins_addr1,
State: job.ins_city,
Zip: job.ins_zip,
Phone: job.ins_ph1,
Fax: null,
ClaimType: null,
LossType: null,
Policy: null,
Claim: job.clm_no,
InsuredLastName: null,
InsuredFirstName: null,
ClaimantLastName: null,
ClaimantFirstName: null,
Assignment: null,
InsuranceAgentLastName: null,
InsuranceAgentFirstName: null,
InsAgentPhone: null,
InsideAdjuster: null,
OutsideAdjuster: null,
},
Dates: {
DateofLoss: job.loss_date && moment(job.loss_date).format(AhDateFormat),
InitialCustomerContactDate: null,
FirstFollowUpDate: null,
ReferralDate: null,
EstimateAppointmentDate: null,
SecondFollowUpDate: null,
AssignedDate: null,
EstComplete: null,
CustomerAuthorizationDate: null,
InsuranceAuthorizationDate: null,
DateOpened: job.date_open && moment(job.date_open).format(AhDateFormat),
ScheduledArrivalDate:
job.scheduled_in && moment(job.scheduled_in).format(AhDateFormat),
CarinShop: job.actual_in && moment(job.actual_in).format(AhDateFormat),
InsInspDate: null,
StartDate: null,
PartsOrder: null,
TeardownHold: null,
SupplementSubmittedDate: null,
SupplementApprovedDate: null,
AssntoBody: null,
AssntoMech: null,
AssntoPaint: null,
AssntoDetail: null,
PromiseDate:
job.scheduled_completion &&
moment(job.scheduled_completion).format(AhDateFormat),
InsuranceTargetOut: null,
CarComplete:
job.actual_completion &&
moment(job.actual_completion).format(AhDateFormat),
DeliveryAppointmentDate:
job.scheduled_delivery &&
moment(job.scheduled_delivery).format(AhDateFormat),
DateClosed:
job.date_invoiced && moment(job.date_invoiced).format(AhDateFormat),
CustomerPaidInFullDate: null,
InsurancePaidInFullDate: null,
CustPickup:
job.actual_delivery && moment(job.actual_delivery).format(AhDateFormat),
AccountPostedDate:
job.date_exported && moment(job.date_exported).format(AhDateFormat),
CSIProcessedDate: null,
ThankYouLetterSent: null,
AdditionalFollowUpDate: null,
},
Rates: {
BodyRate: job.rate_lab,
RefinishRate: job.rate_lar,
MechanicalRate: job.rate_lam,
StructuralRate: job.rate_las,
PMRate: job.rate_mapa,
BMRate: job.rate_mash,
TaxRate: null,
StorageRateperDay: null,
DaysStored: null,
},
EstimateTotals: {
BodyHours: null,
RefinishHours: null,
MechanicalHours: null,
StructuralHours: null,
PartsTotal: null,
PartsOEM: null,
PartsAM: null,
PartsReconditioned: null,
PartsRecycled: null,
PartsOther: null,
SubletTotal: null,
BodyLaborTotal: null,
RefinishLaborTotal: null,
MechanicalLaborTotal: null,
StructuralLaborTotal: null,
MiscellaneousChargeTotal: null,
PMTotal: null,
BMTotal: null,
MiscTotal: null,
TowingTotal: null,
StorageTotal: null,
DetailTotal: null,
SalesTaxTotal: null,
GrossTotal: null,
DeductibleTotal: null,
DepreciationTotal: null,
Discount: null,
CustomerPay: null,
InsurancePay: null,
Deposit: null,
AmountDue: null,
},
SupplementTotals: {
BodyHours: null,
RefinishHours: null,
MechanicalHours: null,
StructuralHours: null,
PartsTotal: null,
PartsOEM: null,
PartsAM: null,
PartsReconditioned: null,
PartsRecycled: null,
PartsOther: null,
SubletTotal: null,
BodyLaborTotal: null,
RefinishLaborTotal: null,
MechanicalLaborTotal: null,
StructuralLaborTotal: null,
MiscellaneousChargeTotal: null,
PMTotal: null,
BMTotal: null,
MiscTotal: null,
TowingTotal: null,
StorageTotal: null,
DetailTotal: null,
SalesTaxTotal: null,
GrossTotal: null,
DeductibleTotal: null,
DepreciationTotal: null,
Discount: null,
CustomerPay: null,
InsurancePay: null,
Deposit: null,
AmountDue: null,
},
RevisedTotals: {
BodyHours: "10.10",
RefinishHours: "4.70",
MechanicalHours: "2.90",
StructuralHours: null,
PartsTotal: "2630.24",
PartsTotalCost: "1655.67",
PartsOEM: "969.49",
PartsOEMCost: "761.91",
PartsAM: "1660.75",
PartsAMCost: "893.76",
PartsReconditioned: null,
PartsReconditionedCost: null,
PartsRecycled: null,
PartsRecycledCost: null,
PartsOther: null,
PartsOtherCost: null,
SubletTotal: "139.95",
SubletTotalCost: "0.00",
BodyLaborTotal: "642.46",
BodyLaborTotalCost: "0.00",
RefinishLaborTotal: "298.97",
RefinishLaborTotalCost: "0.00",
MechanicalLaborTotal: "276.69",
MechanicalLaborTotalCost: "0.00",
StructuralLaborTotal: null,
StructuralLaborTotalCost: null,
MiscellaneousChargeTotal: null,
MiscellaneousChargeTotalCost: null,
PMTotal: "159.42",
PMTotalCost: "0.00",
BMTotal: "40.30",
BMTotalCost: "36.27",
MiscTotal: "60.00",
MiscTotalCost: "9.00",
TowingTotal: null,
TowingTotalCost: null,
StorageTotal: null,
StorageTotalCost: null,
DetailTotal: null,
DetailTotalCost: null,
SalesTaxTotal: "552.24",
SalesTaxTotalCost: null,
GrossTotal: "4800.27",
DeductibleTotal: "500.00",
DepreciationTotal: "0.00",
Discount: "0",
CustomerPay: "500.00",
InsurancePay: "4300.27",
Deposit: null,
AmountDue: "4800.27",
},
Misc: {
ProductionStatus: null,
StatusDescription: null,
Hub50Comment: null,
DateofChange: null,
BodyTechName: null,
TotalLossYN: null,
InsScreenCommentsLine1: null,
InsScreenCommentsLine2: null,
AssignmentCaller: null,
AssignmentDivision: null,
LocationofPrimaryImpact: "12",
LocationofSecondaryImpact: null,
PaintTechID: null,
PaintTechName: null,
ImportType: null,
ImportFile: null,
GSTTax: null,
RepairDelayStatusCode: null,
RepairDelaycomment: null,
AgentMktgID: null,
AgentCity: null,
Picture1: null,
Picture2: null,
ExtNoteDate: null,
RentalOrdDate: null,
RentalPUDate: null,
RentalDueDate: null,
RentalActRetDate: null,
RentalCompanyID: null,
CSIID: null,
InsGroupCode: null,
},
DetailLines: {
DetailLine: job.joblines.map((jl) =>
GenerateDetailLines(jl, job.bodyshop.md_order_statuses)
),
},
};
return ret;
};
const StatusMapping = (status, md_ro_statuses) => {
//EST, SCH, ARR, IPR, RDY, DEL, CLO, CAN, UNDEFINED.
const {
default_imported,
default_open,
default_scheduled,
default_arrived,
default_completed,
default_delivered,
default_invoiced,
default_exported,
default_void,
} = md_ro_statuses;
if (status === default_open || status === default_imported) return "EST";
else if (status === default_scheduled) return "SCH";
else if (status === default_arrived) return "ARR";
else if (status === default_completed) return "RDY";
else if (status === default_delivered) return "DEL";
else if (status === default_invoiced || status === default_exported)
return "CLO";
else if (status === default_void) return "CLO";
else if (md_ro_statuses.production_statuses.include(status)) return "IPR";
else return "UNDEFINED";
// default: return "UNDEFINED"
};
const GenerateDetailLines = (line, statuses) => {
const ret = {
BackOrdered: line.status === statuses.default_bo ? "Y" : "N",
Cost:
line.billlines[0] &&
(line.billlines[0].actual_cost * line.billlines[0].quantity).toFixed(2),
Critical: null,
Description: line.desc,
DiscountMarkup: null,
InvoiceNumber: line.billlines[0] && line.billlines[0].bill.invoice_number,
IOUPart: null,
LineNumber: line.line_no,
MarkUp: null,
OrderedOn: null,
OriginalCost: null,
OriginalInvoiceNumber: null,
PriceEach: line.billlines[0] && line.billlines[0].actual_cost,
PartNumber: line.oem_partno,
ProfitPercent: null,
PurchaseOrderNumber: null,
Qty: line.part_qty,
Status: line.status,
SupplementNumber: null,
Type: line.part_type,
Vendor: line.billlines[0] && line.billlines[0].bill.vendor.name,
VendorPaid: null,
VendorPrice: line.billlines[0] && line.billlines[0].actual_price,
Deleted: null,
ExpectedOn: null,
ReceivedOn: null,
OrderedBy: null,
ShipVia: null,
VendorContact: null,
EstimateAmount: line.act_price,
};
return ret;
};

1
server/data/data.js Normal file
View File

@@ -0,0 +1 @@
exports.autohouse = require("./autohouse").default;

View File

@@ -256,3 +256,129 @@ exports.QUERY_EMPLOYEE_PIN = `query QUERY_EMPLOYEE_PIN($shopId: uuid!, $employee
pin
}
}`;
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
jobs(where: {_and: [{updated_at: {_gt: $start}}, {bodyshop: {autohouseid: {_is_null: false}}}]}) {
id
ro_number
status
est_ct_fn
est_ct_ln
ownr_zip
referral_source
v_model_yr
v_model_desc
v_make_desc
v_vin
plate_no
plate_st
kmin
v_color
tlos_ind
ins_co_nm
ins_addr1
ins_city
ins_st
ins_zip
ins_ph1
loss_type
policy_no
clm_no
loss_date
asgn_date
date_estimated
date_open
scheduled_in
actual_in
scheduled_completion
actual_completion
scheduled_delivery
actual_delivery
date_invoiced
date_exported
rate_la1
rate_la2
rate_la3
rate_la4
rate_laa
rate_lab
rate_lad
rate_lae
rate_laf
rate_lag
rate_lam
rate_lar
rate_las
rate_lau
rate_ma2s
rate_ma2t
rate_ma3s
rate_mabl
rate_macs
rate_mahw
rate_matd
rate_mapa
rate_mash
job_totals
bodyshop {
id
shopname
address1
city
state
zip_post
country
phone
md_ro_statuses
md_order_statuses
autohouseid
}
joblines (where:{removed: {_eq:false}}){
id
line_no
status
line_ind
db_price
act_price
mod_lb_hrs
mod_lbr_ty
line_desc
prt_dsmk_m
prt_dsmk_p
part_qty
part_type
oem_partno
billlines (order_by:{bill:{date:desc_nulls_last}}) {
actual_cost
actual_price
quantity
bill {
vendor{
name
}
invoice_number
}
}
}
area_of_damage
employee_prep_rel {
first_name
last_name
employee_number
id
}
employee_refinish_rel {
first_name
last_name
employee_number
id
}
employee_body_rel {
first_name
last_name
employee_number
id
}
}
}
`;

View File

@@ -29,11 +29,13 @@ exports.receive = (req, res) => {
phone: phone(req.body.From)[0],
})
.then((response) => {
console.log("re", req.body);
let newMessage = {
msid: req.body.SmsMessageSid,
text: req.body.Body,
image: !!req.body.MediaUrl0,
image_path: req.body.MediaUrl0 || null,
image_path: generateMediaArray(req.body),
};
if (response.bodyshops[0]) {
//Found a bodyshop - should always happen.
@@ -164,3 +166,17 @@ exports.receive = (req, res) => {
// [0] MediaContentType0: 'image/jpeg',
// MediaContentType0: 'video/3gpp',
const generateMediaArray = (body) => {
const { NumMedia } = body;
if (parseInt(NumMedia) > 0) {
//stuff
const ret = [];
for (var i = 0; i < parseInt(NumMedia); i++) {
ret.push(body[`MediaUrl${i}`]);
}
return ret;
} else {
return null;
}
};

View File

@@ -17,7 +17,13 @@ const client = twilio(
const gqlClient = require("../graphql-client/graphql-client").client;
exports.send = (req, res) => {
const { to, messagingServiceSid, body, conversationid } = req.body;
const {
to,
messagingServiceSid,
body,
conversationid,
selectedMedia,
} = req.body;
console.log("[Sending Sms] " + conversationid + " | " + body);
if (!!to && !!messagingServiceSid && !!body && !!conversationid) {
client.messages
@@ -25,6 +31,7 @@ exports.send = (req, res) => {
body: body,
messagingServiceSid: messagingServiceSid,
to: phone(to)[0],
mediaUrl: selectedMedia.map((i) => i.src),
})
.then((message) => {
let newMessage = {
@@ -32,6 +39,12 @@ exports.send = (req, res) => {
text: body,
conversationid,
isoutbound: true,
userid: req.user.email,
image: req.body.selectedMedia.length > 0,
image_path:
req.body.selectedMedia.length > 0
? selectedMedia.map((i) => i.src)
: [],
};
gqlClient
.request(queries.INSERT_MESSAGE, { msg: newMessage })
@@ -54,3 +67,23 @@ exports.send = (req, res) => {
.json({ success: false, message: "Missing required parameter(s)." });
}
};
// //Image
// acc.push({
// src: `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
// value.type
// )}/upload/${value.key}`,
// thumbnail: `${
// process.env.REACT_APP_CLOUDINARY_ENDPOINT
// }/${DetermineFileType(value.type)}/upload/${
// process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS
// }/${value.key}`,
// thumbnailHeight: 225,
// thumbnailWidth: 225,
// isSelected: false,
// key: value.key,
// extension: value.extension,
// id: value.id,
// type: value.type,
// tags: [{ value: value.type, title: value.type }],
// });