Compare commits
32 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c8f5c7184 | ||
|
|
a06d3c9365 | ||
|
|
8a0916a47f | ||
|
|
3bc6504ae6 | ||
|
|
e2e5f3f885 | ||
|
|
7a88dd1aae | ||
|
|
521aa81591 | ||
|
|
d70fee6125 | ||
|
|
1a8fad26e5 | ||
|
|
d69050f006 | ||
|
|
abe1e80844 | ||
|
|
58e897db31 | ||
|
|
b7ed6734a0 | ||
|
|
7d5a866a5c | ||
|
|
23becf6494 | ||
|
|
64ee2c1526 | ||
|
|
c033c0fbc5 | ||
|
|
f8ddfeb7d0 | ||
|
|
c4f7c57c24 | ||
|
|
acc6633271 | ||
|
|
836e9b846a | ||
|
|
fd01746f7d | ||
|
|
4ec171d93b | ||
|
|
608988c67c | ||
|
|
8da4d0b0f1 | ||
|
|
a54668e030 | ||
|
|
2386457cf5 | ||
|
|
45944ae8c9 | ||
|
|
2c32a4891b | ||
|
|
2b9fe61d79 | ||
|
|
95751103a2 | ||
|
|
8ca4c5d7fa |
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -67,6 +67,7 @@
|
|||||||
*.rb text eol=lf
|
*.rb text eol=lf
|
||||||
*.java text eol=lf
|
*.java text eol=lf
|
||||||
*.php text eol=lf
|
*.php text eol=lf
|
||||||
|
*.sql text eol=lf
|
||||||
|
|
||||||
# Git configuration files
|
# Git configuration files
|
||||||
.gitattributes text eol=lf
|
.gitattributes text eol=lf
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { EditFilled, SyncOutlined } from "@ant-design/icons";
|
import { EditFilled, SyncOutlined } from "@ant-design/icons";
|
||||||
import { Button, Card, Checkbox, Input, Space, Table } from "antd";
|
import { Button, Card, Checkbox, Input, Space, Table } from "antd";
|
||||||
import React, { useRef, useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { FaTasks } from "react-icons/fa";
|
import { FaTasks } from "react-icons/fa";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -17,8 +17,7 @@ import BillDetailEditReturnComponent from "../bill-detail-edit/bill-detail-edit-
|
|||||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||||
import LockerWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
import LockerWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||||
import UpsellComponent from "../upsell/upsell.component";
|
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||||
import { upsellEnum } from "../upsell/upsell.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
@@ -61,7 +60,6 @@ export function BillsListTableComponent({
|
|||||||
// const search = queryString.parse(useLocation().search);
|
// const search = queryString.parse(useLocation().search);
|
||||||
// const selectedBill = search.billid;
|
// const selectedBill = search.billid;
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
const containerRef = useRef(null);
|
|
||||||
|
|
||||||
const Templates = TemplateList("bill");
|
const Templates = TemplateList("bill");
|
||||||
const bills = billsQuery.data ? billsQuery.data.bills : [];
|
const bills = billsQuery.data ? billsQuery.data.bills : [];
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ function Header({
|
|||||||
label: (
|
label: (
|
||||||
<Space>
|
<Space>
|
||||||
<LockWrapper featureName="bills" bodyshop={bodyshop}>
|
<LockWrapper featureName="bills" bodyshop={bodyshop}>
|
||||||
{t(t("menus.header.enterbills"))}
|
{t("menus.header.enterbills")}
|
||||||
</LockWrapper>
|
</LockWrapper>
|
||||||
</Space>
|
</Space>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -9,14 +9,25 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
import "./job-lifecycle.styles.scss";
|
import "./job-lifecycle.styles.scss";
|
||||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||||
|
|
||||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||||
|
|
||||||
|
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
|
});
|
||||||
// show text on bar if text can fit
|
// show text on bar if text can fit
|
||||||
export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
export function JobLifecycleComponent({ bodyshop, job, statuses, ...rest }) {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [lifecycleData, setLifecycleData] = useState(null);
|
const [lifecycleData, setLifecycleData] = useState(null);
|
||||||
const { t } = useTranslation(); // Used for tracking external state changes.
|
const { t } = useTranslation(); // Used for tracking external state changes.
|
||||||
|
const hasLifeCycleAccess = HasFeatureAccess({ bodyshop, featureName: "lifecycle" });
|
||||||
const { data } = useQuery(
|
const { data } = useQuery(
|
||||||
gql`
|
gql`
|
||||||
query get_job_test($id: uuid!) {
|
query get_job_test($id: uuid!) {
|
||||||
@@ -143,9 +154,11 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
|||||||
}
|
}
|
||||||
style={{ width: "100%" }}
|
style={{ width: "100%" }}
|
||||||
>
|
>
|
||||||
<Card type="inner" style={{ marginTop: "10px" }}>
|
{!hasLifeCycleAccess && (
|
||||||
<UpsellComponent upsell={upsellEnum().lifecycle.general} />
|
<Card type="inner" style={{ marginTop: "10px" }}>
|
||||||
</Card>
|
<UpsellComponent upsell={upsellEnum().lifecycle.general} />
|
||||||
|
</Card>
|
||||||
|
)}
|
||||||
<BlurWrapperComponent featureName="lifecycle" bypass>
|
<BlurWrapperComponent featureName="lifecycle" bypass>
|
||||||
<div
|
<div
|
||||||
id="bar-container"
|
id="bar-container"
|
||||||
@@ -302,5 +315,4 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(JobLifecycleComponent);
|
||||||
export default JobLifecycleComponent;
|
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import { selectScheduleLoad, selectScheduleLoadCalculating } from "../../redux/a
|
|||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
import { default as BlurWrapper, default as BlurWrapperComponent } from "../feature-wrapper/blur-wrapper.component";
|
import { default as BlurWrapper, default as BlurWrapperComponent } from "../feature-wrapper/blur-wrapper.component";
|
||||||
|
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
||||||
|
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||||
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
|
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
|
||||||
import UpsellComponent, { upsellEnum, UpsellMaskWrapper } from "../upsell/upsell.component";
|
|
||||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
|||||||
@@ -13,6 +13,9 @@ import { Button, Card, Result } from "antd";
|
|||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import React, { useEffect, useRef } from "react";
|
import React, { useEffect, useRef } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
import { store } from "../../redux/store.js";
|
||||||
|
import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
|
||||||
import "./upsell.styles.scss";
|
import "./upsell.styles.scss";
|
||||||
|
|
||||||
export default function UpsellComponent({ featureName, subFeatureName, upsell, disableMask }) {
|
export default function UpsellComponent({ featureName, subFeatureName, upsell, disableMask }) {
|
||||||
@@ -64,174 +67,275 @@ export function UpsellMaskWrapper({ children, upsell, featureName, subFeatureNam
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
//This is kept in this function as pulling it out into it's own util/enum prevents passing JSX as an `extra` prop
|
//This is kept in this function as pulling it out into it's own util/enum prevents passing JSX as an `extra` prop
|
||||||
export const upsellEnum = () => ({
|
export const upsellEnum = () => {
|
||||||
bills: {
|
const { currentUser, bodyshop } = store.getState().user;
|
||||||
autoreconcile: {
|
|
||||||
//icon: null,
|
const [first_name, ...last_name] = currentUser?.displayName ? currentUser.displayName.split(" ") : [];
|
||||||
title: i18n.t("upsell.messages.bills.autoreconcile.title"),
|
const LearnMoreLink = encodeURI(
|
||||||
subTitle: i18n.t("upsell.messages.bills.autoreconcile.subtitle"),
|
InstanceRenderManager({
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
imex: `https://imexsystems.ca/schedule-a-demo/`,
|
||||||
//status: null
|
rome: `https://forms.zohopublic.com/rometech/form/ROLearnMore/formperma/0G29z8LgLlvKK8nno-b7s-GHgNXwIFlrMeE0mC394L4?first_name=${first_name || ""}&last_name=${last_name.join(" ") || ""}&shop_name=${bodyshop?.shopname || ""}&email=${currentUser?.email || ""}&shop_phone=${bodyshop?.phone || ""}`
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
bills: {
|
||||||
|
autoreconcile: {
|
||||||
|
//icon: null,
|
||||||
|
title: i18n.t("upsell.messages.bills.autoreconcile.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.bills.autoreconcile.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
//status: null
|
||||||
|
},
|
||||||
|
general: {
|
||||||
|
//icon: null,
|
||||||
|
title: i18n.t("upsell.messages.bills.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.bills.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
//status: null
|
||||||
|
}
|
||||||
},
|
},
|
||||||
general: {
|
checklist: {
|
||||||
//icon: null,
|
general: {
|
||||||
title: i18n.t("upsell.messages.bills.general.title"),
|
//icon: null,
|
||||||
subTitle: i18n.t("upsell.messages.bills.general.subtitle"),
|
title: i18n.t("upsell.messages.checklist.general.title"),
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
subTitle: i18n.t("upsell.messages.checklist.general.subtitle"),
|
||||||
//status: null
|
extra: (
|
||||||
}
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
},
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
checklist: {
|
</Link>
|
||||||
general: {
|
)
|
||||||
//icon: null,
|
//status: null
|
||||||
title: i18n.t("upsell.messages.checklist.general.title"),
|
}
|
||||||
subTitle: i18n.t("upsell.messages.checklist.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
//status: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
payments: {
|
|
||||||
general: {
|
|
||||||
//icon: null,
|
|
||||||
title: i18n.t("upsell.messages.payments.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.payments.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
//status: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
audit: {
|
|
||||||
general: {
|
|
||||||
//icon: null,
|
|
||||||
title: i18n.t("upsell.messages.audit.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.audit.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
//status: null
|
|
||||||
}
|
|
||||||
},
|
|
||||||
lifecycle: {
|
|
||||||
general: {
|
|
||||||
//icon: null,
|
|
||||||
title: i18n.t("upsell.messages.lifecycle.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.lifecycle.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
//status: null }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
media: {
|
|
||||||
general: {
|
|
||||||
//icon: null,
|
|
||||||
title: i18n.t("upsell.messages.media.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.media.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
//status: null }
|
|
||||||
},
|
|
||||||
mobile: {
|
|
||||||
icon: <MobileOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.media.mobile.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.media.mobile.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
//status: null }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
timetickets: {
|
|
||||||
allocations: {
|
|
||||||
title: i18n.t("upsell.messages.timetickets.allocations.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.timetickets.allocations.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
},
|
|
||||||
general: {
|
|
||||||
title: i18n.t("upsell.messages.timetickets.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.timetickets.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
smartscheduling: {
|
|
||||||
general: {
|
|
||||||
icon: <CalendarOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.smartscheduling.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.smartscheduling.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
},
|
|
||||||
hrsdelta: {
|
|
||||||
icon: <CarOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.smartscheduling.hrsdelta.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.smartscheduling.hrsdelta.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
},
|
|
||||||
datepicker: {
|
|
||||||
icon: <CarOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.smartscheduling.datepicker.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.smartscheduling.datepicker.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
accounting: {
|
|
||||||
payables: {
|
|
||||||
icon: <DollarOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.accounting.payables.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.accounting.payables.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
},
|
|
||||||
receivables: {
|
|
||||||
icon: <DollarOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.accounting.receivables.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.accounting.receivables.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
},
|
},
|
||||||
payments: {
|
payments: {
|
||||||
icon: <DollarOutlined />,
|
general: {
|
||||||
title: i18n.t("upsell.messages.accounting.payments.title"),
|
//icon: null,
|
||||||
subTitle: i18n.t("upsell.messages.accounting.payments.subtitle"),
|
title: i18n.t("upsell.messages.payments.general.title"),
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
subTitle: i18n.t("upsell.messages.payments.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
//status: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
audit: {
|
||||||
|
general: {
|
||||||
|
//icon: null,
|
||||||
|
title: i18n.t("upsell.messages.audit.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.audit.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
//status: null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lifecycle: {
|
||||||
|
general: {
|
||||||
|
//icon: null,
|
||||||
|
title: i18n.t("upsell.messages.lifecycle.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.lifecycle.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
//status: null }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
media: {
|
||||||
|
general: {
|
||||||
|
//icon: null,
|
||||||
|
title: i18n.t("upsell.messages.media.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.media.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
//status: null }
|
||||||
|
},
|
||||||
|
mobile: {
|
||||||
|
icon: <MobileOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.media.mobile.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.media.mobile.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
//status: null }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
timetickets: {
|
||||||
|
allocations: {
|
||||||
|
title: i18n.t("upsell.messages.timetickets.allocations.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.timetickets.allocations.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
general: {
|
||||||
|
title: i18n.t("upsell.messages.timetickets.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.timetickets.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
smartscheduling: {
|
||||||
|
general: {
|
||||||
|
icon: <CalendarOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.smartscheduling.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.smartscheduling.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
hrsdelta: {
|
||||||
|
icon: <CarOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.smartscheduling.hrsdelta.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.smartscheduling.hrsdelta.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
datepicker: {
|
||||||
|
icon: <CarOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.smartscheduling.datepicker.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.smartscheduling.datepicker.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
accounting: {
|
||||||
|
payables: {
|
||||||
|
icon: <DollarOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.accounting.payables.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.accounting.payables.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
receivables: {
|
||||||
|
icon: <DollarOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.accounting.receivables.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.accounting.receivables.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
payments: {
|
||||||
|
icon: <DollarOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.accounting.payments.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.accounting.payments.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
courtesycars: {
|
||||||
|
general: {
|
||||||
|
icon: <CarOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.courtesycars.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.courtesycars.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dashboard: {
|
||||||
|
general: {
|
||||||
|
icon: <DashboardOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.dashboard.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.dashboard.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
visualboard: {
|
||||||
|
general: {
|
||||||
|
icon: <BuildOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.visualboard.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.visualboard.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
scoreboard: {
|
||||||
|
general: {
|
||||||
|
icon: <LineChartOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.scoreboard.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.scoreboard.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
techconsole: {
|
||||||
|
general: {
|
||||||
|
icon: <LineChartOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.techconsole.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.techconsole.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
csi: {
|
||||||
|
general: {
|
||||||
|
icon: <StarOutlined />,
|
||||||
|
title: i18n.t("upsell.messages.csi.general.title"),
|
||||||
|
subTitle: i18n.t("upsell.messages.csi.general.subtitle"),
|
||||||
|
extra: (
|
||||||
|
<Link to={LearnMoreLink} target="_blank">
|
||||||
|
<Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
};
|
||||||
courtesycars: {
|
};
|
||||||
general: {
|
|
||||||
icon: <CarOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.courtesycars.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.courtesycars.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
dashboard: {
|
|
||||||
general: {
|
|
||||||
icon: <DashboardOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.dashboard.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.dashboard.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
visualboard: {
|
|
||||||
general: {
|
|
||||||
icon: <BuildOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.visualboard.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.visualboard.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
scoreboard: {
|
|
||||||
general: {
|
|
||||||
icon: <LineChartOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.scoreboard.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.scoreboard.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
techconsole: {
|
|
||||||
general: {
|
|
||||||
icon: <LineChartOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.techconsole.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.techconsole.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
}
|
|
||||||
},
|
|
||||||
csi: {
|
|
||||||
general: {
|
|
||||||
icon: <StarOutlined />,
|
|
||||||
title: i18n.t("upsell.messages.csi.general.title"),
|
|
||||||
subTitle: i18n.t("upsell.messages.csi.general.subtitle"),
|
|
||||||
extra: <Button type="primary">{i18n.t("upsell.cta.learnmore")}</Button>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ import { FaHardHat, FaRegStickyNote, FaShieldAlt, FaTasks } from "react-icons/fa
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
|
|
||||||
import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
|
import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component";
|
import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component";
|
||||||
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
|
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
|
||||||
@@ -42,6 +41,7 @@ import JobsDetailTotals from "../../components/jobs-detail-totals/jobs-detail-to
|
|||||||
import JobsDocumentsGalleryContainer from "../../components/jobs-documents-gallery/jobs-documents-gallery.container";
|
import JobsDocumentsGalleryContainer from "../../components/jobs-documents-gallery/jobs-documents-gallery.container";
|
||||||
import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||||
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
|
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
|
||||||
|
import LockWrapperComponent from "../../components/lock-wrapper/lock-wrapper.component.jsx";
|
||||||
import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container";
|
import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container";
|
||||||
import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container";
|
import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container";
|
||||||
import TaskListContainer from "../../components/task-list/task-list.container.jsx";
|
import TaskListContainer from "../../components/task-list/task-list.container.jsx";
|
||||||
@@ -54,9 +54,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import { DateTimeFormat } from "../../utils/DateFormatter";
|
import { DateTimeFormat } from "../../utils/DateFormatter";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
|
||||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||||
import LockWrapperComponent from "../../components/lock-wrapper/lock-wrapper.component.jsx";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -403,7 +401,9 @@ export function JobsDetailPage({
|
|||||||
icon: <BarsOutlined />,
|
icon: <BarsOutlined />,
|
||||||
id: "job-details-lifecycle",
|
id: "job-details-lifecycle",
|
||||||
label: (
|
label: (
|
||||||
<LockWrapperComponent featureName="lifecycle" bypass>{t("menus.jobsdetail.lifecycle")}</LockWrapperComponent>
|
<LockWrapperComponent featureName="lifecycle" bypass>
|
||||||
|
{t("menus.jobsdetail.lifecycle")}
|
||||||
|
</LockWrapperComponent>
|
||||||
),
|
),
|
||||||
children: <JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses} />
|
children: <JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses} />
|
||||||
},
|
},
|
||||||
@@ -438,7 +438,11 @@ export function JobsDetailPage({
|
|||||||
key: "audit",
|
key: "audit",
|
||||||
icon: <HistoryOutlined />,
|
icon: <HistoryOutlined />,
|
||||||
id: "job-details-audit",
|
id: "job-details-audit",
|
||||||
label: <LockWrapperComponent featureName="audit" bypass>{t("jobs.labels.audit")}</LockWrapperComponent>,
|
label: (
|
||||||
|
<LockWrapperComponent featureName="audit" bypass>
|
||||||
|
{t("jobs.labels.audit")}
|
||||||
|
</LockWrapperComponent>
|
||||||
|
),
|
||||||
children: <JobAuditTrail jobId={job.id} />
|
children: <JobAuditTrail jobId={job.id} />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -207,6 +207,7 @@
|
|||||||
- default_prod_list_view
|
- default_prod_list_view
|
||||||
- id
|
- id
|
||||||
- kanban_settings
|
- kanban_settings
|
||||||
|
- notification_settings
|
||||||
- qbo_realmId
|
- qbo_realmId
|
||||||
- shopid
|
- shopid
|
||||||
- useremail
|
- useremail
|
||||||
@@ -222,6 +223,7 @@
|
|||||||
- authlevel
|
- authlevel
|
||||||
- default_prod_list_view
|
- default_prod_list_view
|
||||||
- kanban_settings
|
- kanban_settings
|
||||||
|
- notification_settings
|
||||||
- qbo_realmId
|
- qbo_realmId
|
||||||
filter:
|
filter:
|
||||||
user:
|
user:
|
||||||
@@ -681,6 +683,31 @@
|
|||||||
- exported:
|
- exported:
|
||||||
_eq: false
|
_eq: false
|
||||||
event_triggers:
|
event_triggers:
|
||||||
|
- name: notifications_bills
|
||||||
|
definition:
|
||||||
|
enable_manual: false
|
||||||
|
insert:
|
||||||
|
columns: '*'
|
||||||
|
retry_conf:
|
||||||
|
interval_sec: 10
|
||||||
|
num_retries: 0
|
||||||
|
timeout_sec: 60
|
||||||
|
webhook_from_env: HASURA_API_URL
|
||||||
|
headers:
|
||||||
|
- name: event-secret
|
||||||
|
value_from_env: EVENT_SECRET
|
||||||
|
request_transform:
|
||||||
|
body:
|
||||||
|
action: transform
|
||||||
|
template: |-
|
||||||
|
{
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
method: POST
|
||||||
|
query_params: {}
|
||||||
|
template_engine: Kriti
|
||||||
|
url: '{{$base_url}}/notifications/events/handleBillsChange'
|
||||||
|
version: 2
|
||||||
- name: os_bills
|
- name: os_bills
|
||||||
definition:
|
definition:
|
||||||
delete:
|
delete:
|
||||||
@@ -2805,6 +2832,80 @@
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
|
- table:
|
||||||
|
name: job_watchers
|
||||||
|
schema: public
|
||||||
|
object_relationships:
|
||||||
|
- name: job
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: jobid
|
||||||
|
- name: user
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: user_email
|
||||||
|
insert_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
check:
|
||||||
|
user:
|
||||||
|
_and:
|
||||||
|
- associations:
|
||||||
|
active:
|
||||||
|
_eq: true
|
||||||
|
- authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
columns:
|
||||||
|
- user_email
|
||||||
|
- created_at
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
comment: ""
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- user_email
|
||||||
|
- created_at
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
filter:
|
||||||
|
user:
|
||||||
|
_and:
|
||||||
|
- associations:
|
||||||
|
active:
|
||||||
|
_eq: true
|
||||||
|
- authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
comment: ""
|
||||||
|
update_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- user_email
|
||||||
|
- created_at
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
filter:
|
||||||
|
user:
|
||||||
|
_and:
|
||||||
|
- associations:
|
||||||
|
active:
|
||||||
|
_eq: true
|
||||||
|
- authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
check: null
|
||||||
|
comment: ""
|
||||||
|
delete_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
filter:
|
||||||
|
user:
|
||||||
|
_and:
|
||||||
|
- associations:
|
||||||
|
active:
|
||||||
|
_eq: true
|
||||||
|
- authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
comment: ""
|
||||||
- table:
|
- table:
|
||||||
name: joblines
|
name: joblines
|
||||||
schema: public
|
schema: public
|
||||||
@@ -4326,6 +4427,58 @@
|
|||||||
template_engine: Kriti
|
template_engine: Kriti
|
||||||
url: '{{$base_url}}/record-handler/arms'
|
url: '{{$base_url}}/record-handler/arms'
|
||||||
version: 2
|
version: 2
|
||||||
|
- name: notifications_jobs
|
||||||
|
definition:
|
||||||
|
enable_manual: false
|
||||||
|
insert:
|
||||||
|
columns: '*'
|
||||||
|
update:
|
||||||
|
columns:
|
||||||
|
- queued_for_parts
|
||||||
|
- employee_prep
|
||||||
|
- clm_total
|
||||||
|
- towin
|
||||||
|
- employee_body
|
||||||
|
- converted
|
||||||
|
- scheduled_in
|
||||||
|
- scheduled_completion
|
||||||
|
- scheduled_delivery
|
||||||
|
- actual_delivery
|
||||||
|
- actual_completion
|
||||||
|
- alt_transport
|
||||||
|
- date_exported
|
||||||
|
- status
|
||||||
|
- employee_csr
|
||||||
|
- actual_in
|
||||||
|
- deliverchecklist
|
||||||
|
- comment
|
||||||
|
- job_totals
|
||||||
|
- employee_refinish
|
||||||
|
- inproduction
|
||||||
|
- production_vars
|
||||||
|
- intakechecklist
|
||||||
|
- cieca_ttl
|
||||||
|
- date_invoiced
|
||||||
|
retry_conf:
|
||||||
|
interval_sec: 10
|
||||||
|
num_retries: 0
|
||||||
|
timeout_sec: 60
|
||||||
|
webhook_from_env: HASURA_API_URL
|
||||||
|
headers:
|
||||||
|
- name: event-secret
|
||||||
|
value_from_env: EVENT_SECRET
|
||||||
|
request_transform:
|
||||||
|
body:
|
||||||
|
action: transform
|
||||||
|
template: |-
|
||||||
|
{
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
method: POST
|
||||||
|
query_params: {}
|
||||||
|
template_engine: Kriti
|
||||||
|
url: '{{$base_url}}/notifications/events/handleJobsChange'
|
||||||
|
version: 2
|
||||||
- name: os_jobs
|
- name: os_jobs
|
||||||
definition:
|
definition:
|
||||||
delete:
|
delete:
|
||||||
@@ -4669,6 +4822,57 @@
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
|
- table:
|
||||||
|
name: notifications
|
||||||
|
schema: public
|
||||||
|
object_relationships:
|
||||||
|
- name: association
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: associationid
|
||||||
|
- name: job
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: jobid
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- associationid
|
||||||
|
- created_at
|
||||||
|
- fcm_data
|
||||||
|
- fcm_message
|
||||||
|
- fcm_title
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
- meta
|
||||||
|
- read
|
||||||
|
- ui_translation_meta
|
||||||
|
- ui_translation_string
|
||||||
|
- updated_at
|
||||||
|
filter:
|
||||||
|
association:
|
||||||
|
_and:
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
comment: ""
|
||||||
|
update_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- meta
|
||||||
|
- read
|
||||||
|
filter:
|
||||||
|
association:
|
||||||
|
_and:
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
check: null
|
||||||
|
comment: ""
|
||||||
- table:
|
- table:
|
||||||
name: owners
|
name: owners
|
||||||
schema: public
|
schema: public
|
||||||
@@ -4909,6 +5113,32 @@
|
|||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
check: null
|
check: null
|
||||||
|
event_triggers:
|
||||||
|
- name: notifications_parts_dispatch
|
||||||
|
definition:
|
||||||
|
enable_manual: false
|
||||||
|
insert:
|
||||||
|
columns: '*'
|
||||||
|
retry_conf:
|
||||||
|
interval_sec: 10
|
||||||
|
num_retries: 0
|
||||||
|
timeout_sec: 60
|
||||||
|
webhook_from_env: HASURA_API_URL
|
||||||
|
headers:
|
||||||
|
- name: event-secret
|
||||||
|
value_from_env: EVENT_SECRET
|
||||||
|
request_transform:
|
||||||
|
body:
|
||||||
|
action: transform
|
||||||
|
template: |-
|
||||||
|
{
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
method: POST
|
||||||
|
query_params: {}
|
||||||
|
template_engine: Kriti
|
||||||
|
url: '{{$base_url}}/notifications/events/handlePartsDispatchChange'
|
||||||
|
version: 2
|
||||||
- table:
|
- table:
|
||||||
name: parts_dispatch_lines
|
name: parts_dispatch_lines
|
||||||
schema: public
|
schema: public
|
||||||
@@ -5879,6 +6109,36 @@
|
|||||||
_eq: true
|
_eq: true
|
||||||
check: null
|
check: null
|
||||||
event_triggers:
|
event_triggers:
|
||||||
|
- name: notifications_tasks
|
||||||
|
definition:
|
||||||
|
enable_manual: false
|
||||||
|
insert:
|
||||||
|
columns: '*'
|
||||||
|
update:
|
||||||
|
columns:
|
||||||
|
- assigned_to
|
||||||
|
- completed
|
||||||
|
- description
|
||||||
|
retry_conf:
|
||||||
|
interval_sec: 10
|
||||||
|
num_retries: 0
|
||||||
|
timeout_sec: 60
|
||||||
|
webhook_from_env: HASURA_API_URL
|
||||||
|
headers:
|
||||||
|
- name: event-secret
|
||||||
|
value_from_env: EVENT_SECRET
|
||||||
|
request_transform:
|
||||||
|
body:
|
||||||
|
action: transform
|
||||||
|
template: |-
|
||||||
|
{
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
method: POST
|
||||||
|
query_params: {}
|
||||||
|
template_engine: Kriti
|
||||||
|
url: '{{$base_url}}/notifications/events/handleTasksChange'
|
||||||
|
version: 2
|
||||||
- name: tasks_assigned_changed
|
- name: tasks_assigned_changed
|
||||||
definition:
|
definition:
|
||||||
enable_manual: false
|
enable_manual: false
|
||||||
@@ -6035,6 +6295,32 @@
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
|
event_triggers:
|
||||||
|
- name: notifications_time_tickets
|
||||||
|
definition:
|
||||||
|
enable_manual: false
|
||||||
|
insert:
|
||||||
|
columns: '*'
|
||||||
|
retry_conf:
|
||||||
|
interval_sec: 10
|
||||||
|
num_retries: 0
|
||||||
|
timeout_sec: 60
|
||||||
|
webhook_from_env: HASURA_API_URL
|
||||||
|
headers:
|
||||||
|
- name: event-secret
|
||||||
|
value_from_env: EVENT_SECRET
|
||||||
|
request_transform:
|
||||||
|
body:
|
||||||
|
action: transform
|
||||||
|
template: |-
|
||||||
|
{
|
||||||
|
"success": true
|
||||||
|
}
|
||||||
|
method: POST
|
||||||
|
query_params: {}
|
||||||
|
template_engine: Kriti
|
||||||
|
url: '{{$base_url}}/notifications/events/handleTimeTicketsChange'
|
||||||
|
version: 2
|
||||||
- table:
|
- table:
|
||||||
name: transitions
|
name: transitions
|
||||||
schema: public
|
schema: public
|
||||||
|
|||||||
@@ -39,50 +39,50 @@ END;
|
|||||||
$$;
|
$$;
|
||||||
CREATE FUNCTION public.assign_ro_number() RETURNS trigger
|
CREATE FUNCTION public.assign_ro_number() RETURNS trigger
|
||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
AS $$
|
AS $$
|
||||||
begin
|
begin
|
||||||
IF NEW.converted = true and (new.ro_number is null or new.ro_number = '') THEN
|
IF NEW.converted = true and (new.ro_number is null or new.ro_number = '') THEN
|
||||||
UPDATE counters
|
UPDATE counters
|
||||||
SET count = count + 1 where shopid=new.shopid AND countertype = 'ronum'
|
SET count = count + 1 where shopid=new.shopid AND countertype = 'ronum'
|
||||||
RETURNING concat(prefix,count) into new.ro_number;
|
RETURNING concat(prefix,count) into new.ro_number;
|
||||||
END IF;
|
END IF;
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
CREATE FUNCTION public.audit_trigger() RETURNS trigger
|
CREATE FUNCTION public.audit_trigger() RETURNS trigger
|
||||||
LANGUAGE plpgsql SECURITY DEFINER
|
LANGUAGE plpgsql SECURITY DEFINER
|
||||||
AS $$
|
AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
shopid uuid ;
|
shopid uuid ;
|
||||||
email text;
|
email text;
|
||||||
BEGIN
|
BEGIN
|
||||||
select b.id, u.email INTO shopid, email from users u join associations a on u.email = a.useremail join bodyshops b on b.id = a.shopid where u.authid = current_setting('hasura.user', 't')::jsonb->>'x-hasura-user-id' and a.active = true;
|
select b.id, u.email INTO shopid, email from users u join associations a on u.email = a.useremail join bodyshops b on b.id = a.shopid where u.authid = current_setting('hasura.user', 't')::jsonb->>'x-hasura-user-id' and a.active = true;
|
||||||
IF TG_OP = 'INSERT'
|
IF TG_OP = 'INSERT'
|
||||||
THEN
|
THEN
|
||||||
INSERT INTO public.audit_trail (tabname, schemaname, operation, new_val, recordid, bodyshopid, useremail)
|
INSERT INTO public.audit_trail (tabname, schemaname, operation, new_val, recordid, bodyshopid, useremail)
|
||||||
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW), NEW.id, shopid, email);
|
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW), NEW.id, shopid, email);
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
ELSIF TG_OP = 'UPDATE'
|
ELSIF TG_OP = 'UPDATE'
|
||||||
THEN
|
THEN
|
||||||
INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, new_val, recordid, bodyshopid, useremail)
|
INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, new_val, recordid, bodyshopid, useremail)
|
||||||
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP,
|
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP,
|
||||||
json_diff(to_jsonb(OLD), to_jsonb(NEW)) , json_diff(to_jsonb(NEW), to_jsonb(OLD)), OLD.id, shopid, email);
|
json_diff(to_jsonb(OLD), to_jsonb(NEW)) , json_diff(to_jsonb(NEW), to_jsonb(OLD)), OLD.id, shopid, email);
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
ELSIF TG_OP = 'DELETE'
|
ELSIF TG_OP = 'DELETE'
|
||||||
THEN
|
THEN
|
||||||
INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, recordid, bodyshopid, useremail)
|
INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, recordid, bodyshopid, useremail)
|
||||||
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(OLD), OLD.ID, shopid, email);
|
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(OLD), OLD.ID, shopid, email);
|
||||||
RETURN OLD;
|
RETURN OLD;
|
||||||
END IF;
|
END IF;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
CREATE FUNCTION public.json_diff(l jsonb, r jsonb) RETURNS jsonb
|
CREATE FUNCTION public.json_diff(l jsonb, r jsonb) RETURNS jsonb
|
||||||
LANGUAGE sql
|
LANGUAGE sql
|
||||||
AS $$
|
AS $$
|
||||||
SELECT jsonb_object_agg(a.key, a.value) FROM
|
SELECT jsonb_object_agg(a.key, a.value) FROM
|
||||||
( SELECT key, value FROM jsonb_each(l) ) a LEFT OUTER JOIN
|
( SELECT key, value FROM jsonb_each(l) ) a LEFT OUTER JOIN
|
||||||
( SELECT key, value FROM jsonb_each(r) ) b ON a.key = b.key
|
( SELECT key, value FROM jsonb_each(r) ) b ON a.key = b.key
|
||||||
WHERE a.value != b.value OR b.key IS NULL;
|
WHERE a.value != b.value OR b.key IS NULL;
|
||||||
$$;
|
$$;
|
||||||
CREATE TABLE public.bills (
|
CREATE TABLE public.bills (
|
||||||
id uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
id uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
||||||
@@ -211,33 +211,33 @@ CREATE TABLE public.exportlog (
|
|||||||
);
|
);
|
||||||
CREATE FUNCTION public.search_exportlog(search text) RETURNS SETOF public.exportlog
|
CREATE FUNCTION public.search_exportlog(search text) RETURNS SETOF public.exportlog
|
||||||
LANGUAGE plpgsql STABLE
|
LANGUAGE plpgsql STABLE
|
||||||
AS $$ BEGIN IF search = '' THEN RETURN query
|
AS $$ BEGIN IF search = '' THEN RETURN query
|
||||||
SELECT
|
SELECT
|
||||||
*
|
*
|
||||||
FROM
|
FROM
|
||||||
exportlog e;
|
exportlog e;
|
||||||
ELSE RETURN query
|
ELSE RETURN query
|
||||||
SELECT
|
SELECT
|
||||||
e.*
|
e.*
|
||||||
FROM
|
FROM
|
||||||
exportlog e
|
exportlog e
|
||||||
LEFT JOIN jobs j on j.id = e.jobid
|
LEFT JOIN jobs j on j.id = e.jobid
|
||||||
LEFT JOIN payments p
|
LEFT JOIN payments p
|
||||||
ON p.id = e.paymentid
|
ON p.id = e.paymentid
|
||||||
LEFT JOIN bills b
|
LEFT JOIN bills b
|
||||||
ON e.billid = b.id
|
ON e.billid = b.id
|
||||||
WHERE
|
WHERE
|
||||||
(
|
(
|
||||||
j.ro_number ILIKE '%' || search || '%'
|
j.ro_number ILIKE '%' || search || '%'
|
||||||
OR b.invoice_number ILIKE '%' || search || '%'
|
OR b.invoice_number ILIKE '%' || search || '%'
|
||||||
OR p.paymentnum ILIKE '%' || search || '%'
|
OR p.paymentnum ILIKE '%' || search || '%'
|
||||||
OR e.useremail ILIKE '%' || search || '%'
|
OR e.useremail ILIKE '%' || search || '%'
|
||||||
)
|
)
|
||||||
AND (e.jobid = j.id
|
AND (e.jobid = j.id
|
||||||
or e.paymentid = p.id
|
or e.paymentid = p.id
|
||||||
or e.billid = b.id)
|
or e.billid = b.id)
|
||||||
;
|
;
|
||||||
END IF;
|
END IF;
|
||||||
END $$;
|
END $$;
|
||||||
CREATE TABLE public.jobs (
|
CREATE TABLE public.jobs (
|
||||||
id uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
id uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."associations" add column "notification_settings" jsonb
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."associations" add column "notification_settings" jsonb
|
||||||
|
null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."notifications";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE TABLE "public"."notifications" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "job_id" uuid NOT NULL, "association_id" uuid NOT NULL, "ui_translation_string" text NOT NULL, "ui_translation_meta" jsonb, "fcm_title" text NOT NULL, "fcm_message" text NOT NULL, "fcm_data" jsonb, "read" timestamptz, "meta" jsonb, "scenario" Integer NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("job_id") REFERENCES "public"."jobs"("id") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("association_id") REFERENCES "public"."associations"("id") ON UPDATE restrict ON DELETE restrict, UNIQUE ("id"));COMMENT ON TABLE "public"."notifications" IS E'Real Time Notifications System';
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
comment on column "public"."notifications"."scenario" is E'Real Time Notifications System';
|
||||||
|
alter table "public"."notifications" alter column "scenario" drop not null;
|
||||||
|
alter table "public"."notifications" add column "scenario" int4;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."notifications" drop column "scenario" 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"."notifications" add column "scenario" text
|
||||||
|
-- not null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."notifications" add column "scenario" text
|
||||||
|
not null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."job_watchers";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE TABLE "public"."job_watchers" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "job_id" uuid NOT NULL, "user_email" text NOT NULL, "created_at" timestamptz NOT NULL DEFAULT now(), PRIMARY KEY ("id") , FOREIGN KEY ("user_email") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("job_id") REFERENCES "public"."jobs"("id") ON UPDATE restrict ON DELETE restrict, UNIQUE ("id"));COMMENT ON TABLE "public"."job_watchers" IS E'Job Watchers';
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
comment on column "public"."notifications"."scenario" is E'Real Time Notifications System';
|
||||||
|
alter table "public"."notifications" alter column "scenario" drop not null;
|
||||||
|
alter table "public"."notifications" add column "scenario" text;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."notifications" drop column "scenario" cascade;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- update associations set notification_settings = '{}';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
update associations set notification_settings = '{}';
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."associations" alter column "notification_settings" drop not null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."associations" alter column "notification_settings" set not null;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- update notifications set meta = '{}';
|
||||||
|
-- update notifications set fcm_data = '{}';
|
||||||
|
-- update notifications set ui_translation_meta = '{}';
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
update notifications set meta = '{}';
|
||||||
|
update notifications set fcm_data = '{}';
|
||||||
|
update notifications set ui_translation_meta = '{}';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."notifications" alter column "meta" drop not null;
|
||||||
|
ALTER TABLE "public"."notifications" ALTER COLUMN "meta" drop default;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."notifications" alter column "meta" set default jsonb_build_object();
|
||||||
|
alter table "public"."notifications" alter column "meta" set not null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."notifications" alter column "fcm_data" drop not null;
|
||||||
|
ALTER TABLE "public"."notifications" ALTER COLUMN "fcm_data" drop default;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."notifications" alter column "fcm_data" set default jsonb_build_object();
|
||||||
|
alter table "public"."notifications" alter column "fcm_data" set not null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."notifications" alter column "ui_translation_meta" drop not null;
|
||||||
|
ALTER TABLE "public"."notifications" ALTER COLUMN "ui_translation_meta" drop default;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."notifications" alter column "ui_translation_meta" set default jsonb_build_object();
|
||||||
|
alter table "public"."notifications" alter column "ui_translation_meta" set not null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."notifications" rename column "jobid" to "job_id";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."notifications" rename column "job_id" to "jobid";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."notifications" rename column "associationid" to "association_id";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."notifications" rename column "association_id" to "associationid";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."job_watchers" rename column "jobid" to "job_id";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."job_watchers" rename column "job_id" to "jobid";
|
||||||
@@ -39,50 +39,50 @@ END;
|
|||||||
$$;
|
$$;
|
||||||
CREATE FUNCTION public.assign_ro_number() RETURNS trigger
|
CREATE FUNCTION public.assign_ro_number() RETURNS trigger
|
||||||
LANGUAGE plpgsql
|
LANGUAGE plpgsql
|
||||||
AS $$
|
AS $$
|
||||||
begin
|
begin
|
||||||
IF NEW.converted = true and (new.ro_number is null or new.ro_number = '') THEN
|
IF NEW.converted = true and (new.ro_number is null or new.ro_number = '') THEN
|
||||||
UPDATE counters
|
UPDATE counters
|
||||||
SET count = count + 1 where shopid=new.shopid AND countertype = 'ronum'
|
SET count = count + 1 where shopid=new.shopid AND countertype = 'ronum'
|
||||||
RETURNING concat(prefix,count) into new.ro_number;
|
RETURNING concat(prefix,count) into new.ro_number;
|
||||||
END IF;
|
END IF;
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
CREATE FUNCTION public.audit_trigger() RETURNS trigger
|
CREATE FUNCTION public.audit_trigger() RETURNS trigger
|
||||||
LANGUAGE plpgsql SECURITY DEFINER
|
LANGUAGE plpgsql SECURITY DEFINER
|
||||||
AS $$
|
AS $$
|
||||||
DECLARE
|
DECLARE
|
||||||
shopid uuid ;
|
shopid uuid ;
|
||||||
email text;
|
email text;
|
||||||
BEGIN
|
BEGIN
|
||||||
select b.id, u.email INTO shopid, email from users u join associations a on u.email = a.useremail join bodyshops b on b.id = a.shopid where u.authid = current_setting('hasura.user', 't')::jsonb->>'x-hasura-user-id' and a.active = true;
|
select b.id, u.email INTO shopid, email from users u join associations a on u.email = a.useremail join bodyshops b on b.id = a.shopid where u.authid = current_setting('hasura.user', 't')::jsonb->>'x-hasura-user-id' and a.active = true;
|
||||||
IF TG_OP = 'INSERT'
|
IF TG_OP = 'INSERT'
|
||||||
THEN
|
THEN
|
||||||
INSERT INTO public.audit_trail (tabname, schemaname, operation, new_val, recordid, bodyshopid, useremail)
|
INSERT INTO public.audit_trail (tabname, schemaname, operation, new_val, recordid, bodyshopid, useremail)
|
||||||
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW), NEW.id, shopid, email);
|
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(NEW), NEW.id, shopid, email);
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
ELSIF TG_OP = 'UPDATE'
|
ELSIF TG_OP = 'UPDATE'
|
||||||
THEN
|
THEN
|
||||||
INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, new_val, recordid, bodyshopid, useremail)
|
INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, new_val, recordid, bodyshopid, useremail)
|
||||||
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP,
|
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP,
|
||||||
json_diff(to_jsonb(OLD), to_jsonb(NEW)) , json_diff(to_jsonb(NEW), to_jsonb(OLD)), OLD.id, shopid, email);
|
json_diff(to_jsonb(OLD), to_jsonb(NEW)) , json_diff(to_jsonb(NEW), to_jsonb(OLD)), OLD.id, shopid, email);
|
||||||
RETURN NEW;
|
RETURN NEW;
|
||||||
ELSIF TG_OP = 'DELETE'
|
ELSIF TG_OP = 'DELETE'
|
||||||
THEN
|
THEN
|
||||||
INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, recordid, bodyshopid, useremail)
|
INSERT INTO public.audit_trail (tabname, schemaname, operation, old_val, recordid, bodyshopid, useremail)
|
||||||
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(OLD), OLD.ID, shopid, email);
|
VALUES (TG_RELNAME, TG_TABLE_SCHEMA, TG_OP, row_to_json(OLD), OLD.ID, shopid, email);
|
||||||
RETURN OLD;
|
RETURN OLD;
|
||||||
END IF;
|
END IF;
|
||||||
END;
|
END;
|
||||||
$$;
|
$$;
|
||||||
CREATE FUNCTION public.json_diff(l jsonb, r jsonb) RETURNS jsonb
|
CREATE FUNCTION public.json_diff(l jsonb, r jsonb) RETURNS jsonb
|
||||||
LANGUAGE sql
|
LANGUAGE sql
|
||||||
AS $$
|
AS $$
|
||||||
SELECT jsonb_object_agg(a.key, a.value) FROM
|
SELECT jsonb_object_agg(a.key, a.value) FROM
|
||||||
( SELECT key, value FROM jsonb_each(l) ) a LEFT OUTER JOIN
|
( SELECT key, value FROM jsonb_each(l) ) a LEFT OUTER JOIN
|
||||||
( SELECT key, value FROM jsonb_each(r) ) b ON a.key = b.key
|
( SELECT key, value FROM jsonb_each(r) ) b ON a.key = b.key
|
||||||
WHERE a.value != b.value OR b.key IS NULL;
|
WHERE a.value != b.value OR b.key IS NULL;
|
||||||
$$;
|
$$;
|
||||||
CREATE TABLE public.bills (
|
CREATE TABLE public.bills (
|
||||||
id uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
id uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
||||||
@@ -211,33 +211,33 @@ CREATE TABLE public.exportlog (
|
|||||||
);
|
);
|
||||||
CREATE FUNCTION public.search_exportlog(search text) RETURNS SETOF public.exportlog
|
CREATE FUNCTION public.search_exportlog(search text) RETURNS SETOF public.exportlog
|
||||||
LANGUAGE plpgsql STABLE
|
LANGUAGE plpgsql STABLE
|
||||||
AS $$ BEGIN IF search = '' THEN RETURN query
|
AS $$ BEGIN IF search = '' THEN RETURN query
|
||||||
SELECT
|
SELECT
|
||||||
*
|
*
|
||||||
FROM
|
FROM
|
||||||
exportlog e;
|
exportlog e;
|
||||||
ELSE RETURN query
|
ELSE RETURN query
|
||||||
SELECT
|
SELECT
|
||||||
e.*
|
e.*
|
||||||
FROM
|
FROM
|
||||||
exportlog e
|
exportlog e
|
||||||
LEFT JOIN jobs j on j.id = e.jobid
|
LEFT JOIN jobs j on j.id = e.jobid
|
||||||
LEFT JOIN payments p
|
LEFT JOIN payments p
|
||||||
ON p.id = e.paymentid
|
ON p.id = e.paymentid
|
||||||
LEFT JOIN bills b
|
LEFT JOIN bills b
|
||||||
ON e.billid = b.id
|
ON e.billid = b.id
|
||||||
WHERE
|
WHERE
|
||||||
(
|
(
|
||||||
j.ro_number ILIKE '%' || search || '%'
|
j.ro_number ILIKE '%' || search || '%'
|
||||||
OR b.invoice_number ILIKE '%' || search || '%'
|
OR b.invoice_number ILIKE '%' || search || '%'
|
||||||
OR p.paymentnum ILIKE '%' || search || '%'
|
OR p.paymentnum ILIKE '%' || search || '%'
|
||||||
OR e.useremail ILIKE '%' || search || '%'
|
OR e.useremail ILIKE '%' || search || '%'
|
||||||
)
|
)
|
||||||
AND (e.jobid = j.id
|
AND (e.jobid = j.id
|
||||||
or e.paymentid = p.id
|
or e.paymentid = p.id
|
||||||
or e.billid = b.id)
|
or e.billid = b.id)
|
||||||
;
|
;
|
||||||
END IF;
|
END IF;
|
||||||
END $$;
|
END $$;
|
||||||
CREATE TABLE public.jobs (
|
CREATE TABLE public.jobs (
|
||||||
id uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
id uuid DEFAULT public.gen_random_uuid() NOT NULL,
|
||||||
|
|||||||
5
server/notifications/eventHandlers/handeJobsChange.js
Normal file
5
server/notifications/eventHandlers/handeJobsChange.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const handleJobsChange = (req, res) => {
|
||||||
|
return res.status(200).json({ message: "Jobs change handled." });
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = handleJobsChange;
|
||||||
5
server/notifications/eventHandlers/handleBillsChange.js
Normal file
5
server/notifications/eventHandlers/handleBillsChange.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const handleBillsChange = (req, res) => {
|
||||||
|
return res.status(200).json({ message: "Bills change handled." });
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = handleBillsChange;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const handlePartsDispatchChange = (req, res) => {
|
||||||
|
return res.status(200).json({ message: "Parts Dispatch change handled." });
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = handlePartsDispatchChange;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const handlePartsOrderChange = (req, res) => {
|
||||||
|
return res.status(200).json({ message: "Parts Order change handled." });
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = handlePartsOrderChange;
|
||||||
5
server/notifications/eventHandlers/handleTasksChange.js
Normal file
5
server/notifications/eventHandlers/handleTasksChange.js
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const handleTasksChange = (req, res) => {
|
||||||
|
return res.status(200).json({ message: "Tasks change handled." });
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = handleTasksChange;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
const handleTimeTicketsChange = (req, res) => {
|
||||||
|
return res.status(200).json({ message: "Time Tickets change handled." });
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = handleTimeTicketsChange;
|
||||||
@@ -1,12 +1,28 @@
|
|||||||
const express = require("express");
|
const express = require("express");
|
||||||
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
||||||
const { subscribe, unsubscribe, sendNotification } = require("../firebase/firebase-handler");
|
const { subscribe, unsubscribe, sendNotification } = require("../firebase/firebase-handler");
|
||||||
|
const eventAuthorizationMiddleware = require("../middleware/eventAuthorizationMIddleware");
|
||||||
|
|
||||||
|
const handlePartsOrderChange = require("../notifications/eventHandlers/handlePartsOrderChange");
|
||||||
|
const handlePartsDispatchChange = require("../notifications/eventHandlers/handlePartsDispatchChange");
|
||||||
|
const handleTasksChange = require("../notifications/eventHandlers/handleTasksChange");
|
||||||
|
const handleTimeTicketsChange = require("../notifications/eventHandlers/handleTimeTicketsChange");
|
||||||
|
const handleJobsChange = require("../notifications/eventHandlers/handeJobsChange");
|
||||||
|
const handleBillsChange = require("../notifications/eventHandlers/handleBillsChange");
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.use(validateFirebaseIdTokenMiddleware);
|
// These are FCM handlers
|
||||||
|
router.post("/subscribe", validateFirebaseIdTokenMiddleware, subscribe);
|
||||||
|
router.post("/unsubscribe", validateFirebaseIdTokenMiddleware, unsubscribe);
|
||||||
|
router.post("/sendtestnotification", validateFirebaseIdTokenMiddleware, sendNotification);
|
||||||
|
|
||||||
router.post("/subscribe", subscribe);
|
// Hasura Entry points for creating notifications
|
||||||
router.post("/unsubscribe", unsubscribe);
|
router.post("/events/handleJobsChange", eventAuthorizationMiddleware, handleJobsChange);
|
||||||
router.post("/sendtestnotification", sendNotification);
|
router.post("/events/handleBillsChange", eventAuthorizationMiddleware, handleBillsChange);
|
||||||
|
router.post("/events/handlePartsOrderChange", eventAuthorizationMiddleware, handlePartsOrderChange);
|
||||||
|
router.post("/events/handlePartsDispatchChange", eventAuthorizationMiddleware, handlePartsDispatchChange);
|
||||||
|
router.post("/events/handleTasksChange", eventAuthorizationMiddleware, handleTasksChange);
|
||||||
|
router.post("/events/handleTimeTicketsChange", eventAuthorizationMiddleware, handleTimeTicketsChange);
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|||||||
Reference in New Issue
Block a user