Merge branch 'master-AIO' into feature/IO-2458-RO-Closer
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
<babeledit_project version="1.2" be_version="2.7.1">
|
<babeledit_project be_version="2.7.1" version="1.2">
|
||||||
<!--
|
<!--
|
||||||
|
|
||||||
BabelEdit project file
|
BabelEdit project file
|
||||||
@@ -14791,6 +14791,27 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>titles</name>
|
<name>titles</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>joblifecycle</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>
|
<concept_node>
|
||||||
<name>labhours</name>
|
<name>labhours</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -37126,6 +37147,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>parts</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>
|
<concept_node>
|
||||||
<name>partssublet</name>
|
<name>partssublet</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
1613
client/package-lock.json
generated
1613
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -12,48 +12,34 @@
|
|||||||
"@ant-design/pro-layout": "^7.17.16",
|
"@ant-design/pro-layout": "^7.17.16",
|
||||||
"@apollo/client": "^3.8.10",
|
"@apollo/client": "^3.8.10",
|
||||||
"@asseinfo/react-kanban": "^2.2.0",
|
"@asseinfo/react-kanban": "^2.2.0",
|
||||||
"@craco/craco": "^7.1.0",
|
|
||||||
"@fingerprintjs/fingerprintjs": "^4.2.2",
|
"@fingerprintjs/fingerprintjs": "^4.2.2",
|
||||||
"@jsreport/browser-client": "^3.1.0",
|
"@jsreport/browser-client": "^3.1.0",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@reduxjs/toolkit": "^2.2.1",
|
||||||
"@sentry/cli": "^2.28.6",
|
"@sentry/cli": "^2.28.6",
|
||||||
"@sentry/react": "^7.104.0",
|
"@sentry/react": "^7.104.0",
|
||||||
"@sentry/tracing": "^7.104.0",
|
|
||||||
"@splitsoftware/splitio-react": "^1.11.0",
|
"@splitsoftware/splitio-react": "^1.11.0",
|
||||||
"@tanem/react-nprogress": "^5.0.51",
|
"@tanem/react-nprogress": "^5.0.51",
|
||||||
"@vitejs/plugin-legacy": "^5.3.0",
|
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.2.1",
|
||||||
"@vitejs/plugin-react-refresh": "^1.3.6",
|
"antd": "^5.15.3",
|
||||||
"@vitejs/plugin-react-swc": "^3.6.0",
|
|
||||||
"antd": "^5.14.2",
|
|
||||||
"apollo-link-logger": "^2.0.1",
|
"apollo-link-logger": "^2.0.1",
|
||||||
"apollo-link-sentry": "^3.3.0",
|
"apollo-link-sentry": "^3.3.0",
|
||||||
"axios": "^1.6.7",
|
"axios": "^1.6.7",
|
||||||
"consola": "^3.2.3",
|
|
||||||
"dayjs": "^1.11.10",
|
"dayjs": "^1.11.10",
|
||||||
"dayjs-business-days2": "^1.2.2",
|
"dayjs-business-days2": "^1.2.2",
|
||||||
"dinero.js": "^1.9.1",
|
"dinero.js": "^1.9.1",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"enquire-js": "^0.2.1",
|
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"esbuild": "^0.20.0",
|
|
||||||
"exifr": "^7.1.3",
|
"exifr": "^7.1.3",
|
||||||
"firebase": "^10.8.1",
|
"firebase": "^10.8.1",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"i18next": "^23.10.0",
|
"i18next": "^23.10.0",
|
||||||
"i18next-browser-languagedetector": "^7.0.2",
|
"i18next-browser-languagedetector": "^7.0.2",
|
||||||
"jsoneditor": "^10.0.1",
|
|
||||||
"jsreport-browser-client-dist": "^1.3.0",
|
|
||||||
"libphonenumber-js": "^1.10.57",
|
"libphonenumber-js": "^1.10.57",
|
||||||
"logrocket": "^8.0.1",
|
"logrocket": "^8.0.1",
|
||||||
"markerjs2": "^2.32.0",
|
"markerjs2": "^2.32.0",
|
||||||
"normalize-url": "^8.0.0",
|
"normalize-url": "^8.0.0",
|
||||||
"phone": "^3.1.42",
|
|
||||||
"preval.macro": "^5.0.0",
|
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"query-string": "^9.0.0",
|
"query-string": "^9.0.0",
|
||||||
"rc-queue-anim": "^2.0.0",
|
|
||||||
"rc-scroll-anim": "^2.7.6",
|
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-big-calendar": "^1.11.0",
|
"react-big-calendar": "^1.11.0",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
@@ -65,16 +51,15 @@
|
|||||||
"react-i18next": "^14.0.5",
|
"react-i18next": "^14.0.5",
|
||||||
"react-icons": "^5.0.1",
|
"react-icons": "^5.0.1",
|
||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
"react-intersection-observer": "^9.8.1",
|
|
||||||
"react-joyride": "^2.7.4",
|
"react-joyride": "^2.7.4",
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-number-format": "^5.3.3",
|
"react-number-format": "^5.3.3",
|
||||||
|
"react-product-fruits": "^2.2.6",
|
||||||
"react-redux": "^9.1.0",
|
"react-redux": "^9.1.0",
|
||||||
"react-resizable": "^3.0.5",
|
"react-resizable": "^3.0.5",
|
||||||
"react-router-dom": "^6.22.2",
|
"react-router-dom": "^6.22.2",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"react-sticky": "^6.0.3",
|
"react-sticky": "^6.0.3",
|
||||||
"react-sublime-video": "^0.2.5",
|
|
||||||
"react-virtualized": "^9.22.5",
|
"react-virtualized": "^9.22.5",
|
||||||
"recharts": "^2.12.2",
|
"recharts": "^2.12.2",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
@@ -87,17 +72,15 @@
|
|||||||
"styled-components": "^6.1.8",
|
"styled-components": "^6.1.8",
|
||||||
"subscriptions-transport-ws": "^0.11.0",
|
"subscriptions-transport-ws": "^0.11.0",
|
||||||
"terser-webpack-plugin": "^5.3.10",
|
"terser-webpack-plugin": "^5.3.10",
|
||||||
"vite-plugin-compression": "^0.5.1",
|
"userpilot": "^1.3.1",
|
||||||
"vite-plugin-ejs": "^1.7.0",
|
"vite-plugin-ejs": "^1.7.0",
|
||||||
"vite-plugin-svgr": "^4.2.0",
|
|
||||||
"web-vitals": "^3.5.2",
|
"web-vitals": "^3.5.2",
|
||||||
"workbox-core": "^7.0.0",
|
"workbox-core": "^7.0.0",
|
||||||
"workbox-expiration": "^7.0.0",
|
"workbox-expiration": "^7.0.0",
|
||||||
"workbox-navigation-preload": "^7.0.0",
|
"workbox-navigation-preload": "^7.0.0",
|
||||||
"workbox-precaching": "^7.0.0",
|
"workbox-precaching": "^7.0.0",
|
||||||
"workbox-routing": "^7.0.0",
|
"workbox-routing": "^7.0.0",
|
||||||
"workbox-strategies": "^7.0.0",
|
"workbox-strategies": "^7.0.0"
|
||||||
"yauzl": "^3.1.1"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||||
@@ -152,7 +135,6 @@
|
|||||||
"@testing-library/cypress": "^10.0.1",
|
"@testing-library/cypress": "^10.0.1",
|
||||||
"browserslist": "^4.22.3",
|
"browserslist": "^4.22.3",
|
||||||
"browserslist-to-esbuild": "^2.1.1",
|
"browserslist-to-esbuild": "^2.1.1",
|
||||||
"craco-less": "^3.0.1",
|
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"cypress": "^13.6.6",
|
"cypress": "^13.6.6",
|
||||||
"eslint-plugin-cypress": "^2.15.1",
|
"eslint-plugin-cypress": "^2.15.1",
|
||||||
|
|||||||
@@ -12,6 +12,12 @@ import App from "./App";
|
|||||||
import * as Sentry from "@sentry/react";
|
import * as Sentry from "@sentry/react";
|
||||||
|
|
||||||
import themeProvider from "./themeProvider";
|
import themeProvider from "./themeProvider";
|
||||||
|
import { Userpilot } from 'userpilot'
|
||||||
|
|
||||||
|
// Initialize Userpilot
|
||||||
|
if(import.meta.env.DEV){
|
||||||
|
Userpilot.initialize('NX-69145f08');
|
||||||
|
}
|
||||||
|
|
||||||
dayjs.locale("en");
|
dayjs.locale("en");
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ import "./App.styles.scss";
|
|||||||
import handleBeta from "../utils/betaHandler";
|
import handleBeta from "../utils/betaHandler";
|
||||||
import Eula from "../components/eula/eula.component";
|
import Eula from "../components/eula/eula.component";
|
||||||
import InstanceRenderMgr from "../utils/instanceRenderMgr";
|
import InstanceRenderMgr from "../utils/instanceRenderMgr";
|
||||||
|
import { ProductFruits } from 'react-product-fruits';
|
||||||
|
|
||||||
const ResetPassword = lazy(() =>
|
const ResetPassword = lazy(() =>
|
||||||
import("../pages/reset-password/reset-password.component")
|
import("../pages/reset-password/reset-password.component")
|
||||||
);
|
);
|
||||||
@@ -149,6 +151,7 @@ export function App({
|
|||||||
|
|
||||||
// Any route that is not assigned and matched will default to the Landing Page component
|
// Any route that is not assigned and matched will default to the Landing Page component
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<Suspense
|
<Suspense
|
||||||
fallback={
|
fallback={
|
||||||
<LoadingSpinner
|
<LoadingSpinner
|
||||||
@@ -160,6 +163,12 @@ export function App({
|
|||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
<ProductFruits //workspaceCode="aoJoEifvezYI0Z0P"
|
||||||
|
language="en" user={{
|
||||||
|
email: currentUser.email,
|
||||||
|
username: currentUser.email,
|
||||||
|
}} />
|
||||||
|
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
path="*"
|
path="*"
|
||||||
|
|||||||
BIN
client/src/assets/promanager/ProManagerLogo.gif
Normal file
BIN
client/src/assets/promanager/ProManagerLogo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 38 KiB |
@@ -1,5 +1,5 @@
|
|||||||
import {useMutation, useQuery} from "@apollo/client";
|
import {useMutation, useQuery} from "@apollo/client";
|
||||||
import {Button, Form, Popconfirm, Space} from "antd";
|
import {Button, Divider, Form, Popconfirm, Space} from "antd";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
@@ -203,7 +203,7 @@ export function BillDetailEditcontainer({setPartsOrderContext, insertAuditTrail,
|
|||||||
layout="vertical"
|
layout="vertical"
|
||||||
>
|
>
|
||||||
<BillFormContainer form={form} billEdit disabled={exported}/>
|
<BillFormContainer form={form} billEdit disabled={exported}/>
|
||||||
|
<Divider orientation="left">{t("general.labels.media")}</Divider>
|
||||||
{bodyshop.uselocalmediaserver ? (
|
{bodyshop.uselocalmediaserver ? (
|
||||||
<JobsDocumentsLocalGallery
|
<JobsDocumentsLocalGallery
|
||||||
job={{id: data ? data.bills_by_pk.jobid : null}}
|
job={{id: data ? data.bills_by_pk.jobid : null}}
|
||||||
|
|||||||
@@ -173,7 +173,11 @@ export function BillDetailEditReturn({
|
|||||||
</Form>
|
</Form>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Button
|
<Button
|
||||||
disabled={data.bills_by_pk.is_credit_memo || disabled}
|
disabled={
|
||||||
|
data.bills_by_pk.is_credit_memo ||
|
||||||
|
data.bills_by_pk.isinhouse ||
|
||||||
|
disabled
|
||||||
|
}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setOpen(true);
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -172,6 +172,7 @@ function BillEnterModalContainer({
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID", "GET_JOB_BY_PK"],
|
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID", "GET_JOB_BY_PK"],
|
||||||
|
awaitRefetchQueries: true
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
@@ -239,6 +240,7 @@ function BillEnterModalContainer({
|
|||||||
if (markPolReceived && markPolReceived.length > 0) {
|
if (markPolReceived && markPolReceived.length > 0) {
|
||||||
const r2 = await updatePartsOrderLines({
|
const r2 = await updatePartsOrderLines({
|
||||||
variables: {partsLineIds: markPolReceived.map((p) => p.id)},
|
variables: {partsLineIds: markPolReceived.map((p) => p.id)},
|
||||||
|
refetchQueries: ["QUERY_PARTS_BILLS_BY_JOBID" ],
|
||||||
});
|
});
|
||||||
if (!!r2.errors) {
|
if (!!r2.errors) {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -373,12 +375,13 @@ function BillEnterModalContainer({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (enterAgain) {
|
if (enterAgain) {
|
||||||
// form.resetFields();
|
form.resetFields();
|
||||||
form.setFieldsValue({
|
form.setFieldsValue({
|
||||||
...formValues,
|
...formValues,
|
||||||
billlines: [],
|
vendorid:values.vendorid,
|
||||||
});
|
billlines: [],
|
||||||
form.resetFields();
|
});
|
||||||
|
// form.resetFields();
|
||||||
} else {
|
} else {
|
||||||
toggleModalVisible();
|
toggleModalVisible();
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -689,14 +689,14 @@ export function BillEnterModalLinesComponent({
|
|||||||
|
|
||||||
formItemProps: (field) => {
|
formItemProps: (field) => {
|
||||||
return {
|
return {
|
||||||
key: `${field.index}fedtax`,
|
key: `${field.index}fedtax`,
|
||||||
valuePropName: "checked",
|
valuePropName: 'checked',
|
||||||
// initialValue: true,
|
initialValue: InstanceRenderManager({
|
||||||
name: [
|
imex: true,
|
||||||
field.name,
|
rome: false,
|
||||||
"applicable_taxes",
|
promanager: false,
|
||||||
"federal",
|
}),
|
||||||
],
|
name: [field.name, 'applicable_taxes', 'federal'],
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
formInput: (record, index) => (
|
formInput: (record, index) => (
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import "./chat-affix.styles.scss";
|
|||||||
export function ChatAffixContainer({bodyshop, chatVisible}) {
|
export function ChatAffixContainer({bodyshop, chatVisible}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!bodyshop || !bodyshop.messagingservicesid) return;
|
if (!bodyshop || !bodyshop.messagingservicesid) return;
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ export function ChatAffixContainer({bodyshop, chatVisible}) {
|
|||||||
error
|
error
|
||||||
);
|
);
|
||||||
notification.open({
|
notification.open({
|
||||||
|
key: 'fcm',
|
||||||
type: "warning",
|
type: "warning",
|
||||||
message: t("general.errors.fcm"),
|
message: t("general.errors.fcm"),
|
||||||
btn: (
|
btn: (
|
||||||
@@ -62,7 +64,7 @@ export function ChatAffixContainer({bodyshop, chatVisible}) {
|
|||||||
|
|
||||||
SubscribeToTopic();
|
SubscribeToTopic();
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, [bodyshop]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
function handleMessage(payload) {
|
function handleMessage(payload) {
|
||||||
|
|||||||
@@ -61,6 +61,10 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
|||||||
value: "courtesycars.status.in",
|
value: "courtesycars.status.in",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
text: t("courtesycars.status.inservice"),
|
||||||
|
value: "courtesycars.status.inservice",
|
||||||
|
},
|
||||||
|
{
|
||||||
text: t("courtesycars.status.out"),
|
text: t("courtesycars.status.out"),
|
||||||
value: "courtesycars.status.out",
|
value: "courtesycars.status.out",
|
||||||
},
|
},
|
||||||
@@ -73,7 +77,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
|||||||
value: "courtesycars.status.leasereturn",
|
value: "courtesycars.status.leasereturn",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
onFilter: (value, record) => value.includes(record.status),
|
onFilter: (value, record) => record.status === value,
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
@@ -176,7 +180,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
|||||||
title: t("courtesycars.fields.fuel"),
|
title: t("courtesycars.fields.fuel"),
|
||||||
dataIndex: "fuel",
|
dataIndex: "fuel",
|
||||||
key: "fuel",
|
key: "fuel",
|
||||||
sorter: (a, b) => alphaSort(a.fuel, b.fuel),
|
sorter: (a, b) => a.fuel - b.fuel,
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order,
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
@@ -185,12 +189,14 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
|||||||
return t("courtesycars.labels.fuel.full");
|
return t("courtesycars.labels.fuel.full");
|
||||||
case 88:
|
case 88:
|
||||||
return t("courtesycars.labels.fuel.78");
|
return t("courtesycars.labels.fuel.78");
|
||||||
case 63:
|
case 75:
|
||||||
|
return t("courtesycars.labels.fuel.34");
|
||||||
|
case 63:
|
||||||
return t("courtesycars.labels.fuel.58");
|
return t("courtesycars.labels.fuel.58");
|
||||||
case 50:
|
case 50:
|
||||||
return t("courtesycars.labels.fuel.12");
|
return t("courtesycars.labels.fuel.12");
|
||||||
case 38:
|
case 38:
|
||||||
return t("courtesycars.labels.fuel.34");
|
return t("courtesycars.labels.fuel.38");
|
||||||
case 25:
|
case 25:
|
||||||
return t("courtesycars.labels.fuel.14");
|
return t("courtesycars.labels.fuel.14");
|
||||||
case 13:
|
case 13:
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import axios from "axios";
|
|||||||
const fortyFiveDaysAgo = () => dayjs().subtract(45, 'day').toLocaleString();
|
const fortyFiveDaysAgo = () => dayjs().subtract(45, 'day').toLocaleString();
|
||||||
|
|
||||||
export default function JobLifecycleDashboardComponent({data, bodyshop, ...cardProps}) {
|
export default function JobLifecycleDashboardComponent({data, bodyshop, ...cardProps}) {
|
||||||
|
console.log("🚀 ~ JobLifecycleDashboardComponent ~ bodyshop:", bodyshop)
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [lifecycleData, setLifecycleData] = useState(null);
|
const [lifecycleData, setLifecycleData] = useState(null);
|
||||||
@@ -19,7 +20,7 @@ export default function JobLifecycleDashboardComponent({data, bodyshop, ...cardP
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await axios.post("/job/lifecycle", {
|
const response = await axios.post("/job/lifecycle", {
|
||||||
jobids: data.job_lifecycle.map(x => x.id),
|
jobids: data.job_lifecycle.map(x => x.id),
|
||||||
statuses: bodyshop.md_order_statuses
|
statuses: bodyshop.md_ro_statuses
|
||||||
});
|
});
|
||||||
setLifecycleData(response.data.durations);
|
setLifecycleData(response.data.durations);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|||||||
@@ -184,7 +184,7 @@ export function DashboardGridComponent({currentUser, bodyshop}) {
|
|||||||
}}
|
}}
|
||||||
onClick={() => handleRemoveComponent(item.i)}
|
onClick={() => handleRemoveComponent(item.i)}
|
||||||
/>
|
/>
|
||||||
<TheComponent className="dashboard-card" data={dashboarddata}/>
|
<TheComponent className="dashboard-card" bodyshop={bodyshop} data={dashboarddata}/>
|
||||||
</LoadingSkeleton>
|
</LoadingSkeleton>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
import dayjs from "../../utils/day";
|
import dayjs from '../../utils/day';
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from 'react-i18next';
|
||||||
import { connect } from "react-redux";
|
import { connect } from 'react-redux';
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from 'reselect';
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from '../../redux/user/user.selectors';
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from '../alert/alert.component';
|
||||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
function FeatureWrapper({
|
function FeatureWrapper({ bodyshop, featureName, noauth, children, ...restProps }) {
|
||||||
bodyshop,
|
|
||||||
featureName,
|
|
||||||
noauth,
|
|
||||||
children,
|
|
||||||
...restProps
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
if (HasFeatureAccess({ featureName, bodyshop })) return children;
|
if (HasFeatureAccess({ featureName, bodyshop })) return children;
|
||||||
@@ -25,7 +19,13 @@ function FeatureWrapper({
|
|||||||
return (
|
return (
|
||||||
noauth || (
|
noauth || (
|
||||||
<AlertComponent
|
<AlertComponent
|
||||||
message={t("general.messages.nofeatureaccess", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})})}
|
message={t('general.messages.nofeatureaccess', {
|
||||||
|
app: InstanceRenderManager({
|
||||||
|
imex: '$t(titles.imexonline)',
|
||||||
|
rome: '$t(titles.romeonline)',
|
||||||
|
promanager: '$t(titles.promanager)',
|
||||||
|
}),
|
||||||
|
})}
|
||||||
type="warning"
|
type="warning"
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
@@ -33,10 +33,7 @@ function FeatureWrapper({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function HasFeatureAccess({ featureName, bodyshop }) {
|
export function HasFeatureAccess({ featureName, bodyshop }) {
|
||||||
return (
|
return bodyshop?.features.allAccess || dayjs(bodyshop?.features[featureName]).isAfter(dayjs());
|
||||||
bodyshop?.features.allAccess ||
|
|
||||||
dayjs(bodyshop?.features[featureName]).isAfter(dayjs())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(FeatureWrapper);
|
export default connect(mapStateToProps, null)(FeatureWrapper);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {useTranslation} from "react-i18next";
|
|||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import "./job-bills-total.styles.scss";
|
import "./job-bills-total.styles.scss";
|
||||||
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
|
||||||
export default function JobBillsTotalComponent({
|
export default function JobBillsTotalComponent({
|
||||||
loading,
|
loading,
|
||||||
@@ -89,7 +90,7 @@ export default function JobBillsTotalComponent({
|
|||||||
.add(Dinero(totals.parts.sublets.total))
|
.add(Dinero(totals.parts.sublets.total))
|
||||||
.add(Dinero(totals.additional.shipping))
|
.add(Dinero(totals.additional.shipping))
|
||||||
.add(Dinero(totals.additional.towing))
|
.add(Dinero(totals.additional.towing))
|
||||||
.add(Dinero(totals.additional.additionalCosts)); //TODO:AIO Additional costs were captured for Rome, but not imex. This may need to be evaluated?
|
.add( InstanceRenderManager({imex: Dinero(), rome: Dinero(totals.additional.additionalCosts),promanager: "USE_ROME" })) ; // Additional costs were captured for Rome, but not imex.
|
||||||
|
|
||||||
const discrepancy = totalPartsSublet.subtract(billTotals);
|
const discrepancy = totalPartsSublet.subtract(billTotals);
|
||||||
|
|
||||||
|
|||||||
@@ -290,7 +290,7 @@ export function JobLinesComponent({
|
|||||||
key: 'location',
|
key: 'location',
|
||||||
render: (text, record) => <JobLineLocationPopup jobline={record} disabled={jobRO} />,
|
render: (text, record) => <JobLineLocationPopup jobline={record} disabled={jobRO} />,
|
||||||
},
|
},
|
||||||
...(HasFeatureAccess({ featureName: 'bills' })
|
...(HasFeatureAccess({ featureName: 'bills', bodyshop })
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
title: t('joblines.labels.billref'),
|
title: t('joblines.labels.billref'),
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ export function JobEmployeeAssignments({
|
|||||||
jobRO,
|
jobRO,
|
||||||
body,
|
body,
|
||||||
refinish,
|
refinish,
|
||||||
|
|
||||||
prep,
|
prep,
|
||||||
csr,
|
csr,
|
||||||
handleAdd,
|
handleAdd,
|
||||||
@@ -78,7 +77,7 @@ export function JobEmployeeAssignments({
|
|||||||
setVisibility(false);
|
setVisibility(false);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Assign
|
{t("allocations.actions.assign")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => setVisibility(false)}>Close</Button>
|
<Button onClick={() => setVisibility(false)}>Close</Button>
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -44,13 +44,13 @@ export function JobEmployeeAssignmentsContainer({
|
|||||||
});
|
});
|
||||||
if (refetch) refetch();
|
if (refetch) refetch();
|
||||||
|
|
||||||
insertAuditTrail({
|
if (!!!result.errors) {
|
||||||
jobid: job.id,
|
insertAuditTrail({
|
||||||
operation: AuditTrailMapping.jobassignmentchange(operation, name),
|
jobid: job.id,
|
||||||
type: "jobassignmentchange",
|
operation: AuditTrailMapping.jobassignmentchange(operation, name),
|
||||||
});
|
type: "jobassignmentchange",
|
||||||
|
});
|
||||||
if (!!result.errors) {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.assigning", {
|
message: t("jobs.errors.assigning", {
|
||||||
message: JSON.stringify(result.errors),
|
message: JSON.stringify(result.errors),
|
||||||
@@ -68,19 +68,21 @@ export function JobEmployeeAssignmentsContainer({
|
|||||||
variables: {jobId: job.id, job: {[empAssignment]: null}},
|
variables: {jobId: job.id, job: {[empAssignment]: null}},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!!result.errors) {
|
if (!!!result.errors) {
|
||||||
notification["error"]({
|
insertAuditTrail({
|
||||||
message: t("jobs.errors.assigning", {
|
jobid: job.id,
|
||||||
message: JSON.stringify(result.errors),
|
operation: AuditTrailMapping.jobassignmentremoved(operation),
|
||||||
}),
|
type: "jobassignmentremoved",
|
||||||
});
|
});
|
||||||
}
|
} else {
|
||||||
insertAuditTrail({
|
notification["error"]({
|
||||||
jobid: job.id,
|
message: t("jobs.errors.assigning", {
|
||||||
operation: AuditTrailMapping.jobassignmentremoved(operation),
|
message: JSON.stringify(result.errors),
|
||||||
type: "jobassignmentremoved",});
|
}),
|
||||||
setLoading(false);
|
});
|
||||||
};
|
}
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export default function JobReconciliationBillsTable({
|
|||||||
state.sortedInfo.order,
|
state.sortedInfo.order,
|
||||||
|
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Checkbox disabled checked={record.bill.is_credit_memo}/>
|
<Checkbox checked={record.bill.is_credit_memo}/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {useTranslation} from "react-i18next";
|
|||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
|
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -29,108 +30,130 @@ export function JobTotalsTableTotals({bodyshop, job}) {
|
|||||||
total: job.job_totals.totals.subtotal,
|
total: job.job_totals.totals.subtotal,
|
||||||
bold: true,
|
bold: true,
|
||||||
},
|
},
|
||||||
|
...InstanceRenderManager({imex: [ {
|
||||||
|
key: t("jobs.labels.local_tax_amt"),
|
||||||
|
total: job.job_totals.totals.local_tax,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: t("jobs.labels.state_tax_amt"),
|
||||||
|
total: job.job_totals.totals.state_tax,
|
||||||
|
},
|
||||||
|
...(bodyshop.region_config === "CA_BC"
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
key: t("jobs.fields.ca_bc_pvrt"),
|
||||||
|
total: job.job_totals.additional.pvrt,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: []),
|
||||||
|
{
|
||||||
|
key: t("jobs.labels.federal_tax_amt"),
|
||||||
|
total: job.job_totals.totals.federal_tax,
|
||||||
|
},],
|
||||||
|
promanager: "USE_ROME",
|
||||||
|
rome: [(job.job_totals.totals.us_sales_tax_breakdown
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
key: `${
|
||||||
|
bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
|
||||||
|
"T1"
|
||||||
|
} - ${[
|
||||||
|
job.cieca_pft.ty1_rate1,
|
||||||
|
job.cieca_pft.ty1_rate2,
|
||||||
|
job.cieca_pft.ty1_rate3,
|
||||||
|
job.cieca_pft.ty1_rate4,
|
||||||
|
job.cieca_pft.ty1_rate5,
|
||||||
|
]
|
||||||
|
.filter((i) => i > 0)
|
||||||
|
.join(", ")}%`,
|
||||||
|
total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${
|
||||||
|
bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
|
||||||
|
"T2"
|
||||||
|
} - ${[
|
||||||
|
job.cieca_pft.ty2_rate1,
|
||||||
|
job.cieca_pft.ty2_rate2,
|
||||||
|
job.cieca_pft.ty2_rate3,
|
||||||
|
job.cieca_pft.ty2_rate4,
|
||||||
|
job.cieca_pft.ty2_rate5,
|
||||||
|
]
|
||||||
|
.filter((i) => i > 0)
|
||||||
|
.join(", ")}%`,
|
||||||
|
total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${
|
||||||
|
bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
|
||||||
|
"T3"
|
||||||
|
} - ${[
|
||||||
|
job.cieca_pft.ty3_rate1,
|
||||||
|
job.cieca_pft.ty3_rate2,
|
||||||
|
job.cieca_pft.ty3_rate3,
|
||||||
|
job.cieca_pft.ty3_rate4,
|
||||||
|
job.cieca_pft.ty3_rate5,
|
||||||
|
]
|
||||||
|
.filter((i) => i > 0)
|
||||||
|
.join(", ")}%`,
|
||||||
|
total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${
|
||||||
|
bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
|
||||||
|
"T4"
|
||||||
|
} - ${[
|
||||||
|
job.cieca_pft.ty4_rate1,
|
||||||
|
job.cieca_pft.ty4_rate2,
|
||||||
|
job.cieca_pft.ty4_rate3,
|
||||||
|
job.cieca_pft.ty4_rate4,
|
||||||
|
job.cieca_pft.ty4_rate5,
|
||||||
|
]
|
||||||
|
.filter((i) => i > 0)
|
||||||
|
.join(", ")}%`,
|
||||||
|
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: `${
|
||||||
|
bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
|
||||||
|
"TT"
|
||||||
|
} - ${[
|
||||||
|
job.cieca_pft.ty5_rate1,
|
||||||
|
job.cieca_pft.ty5_rate2,
|
||||||
|
job.cieca_pft.ty5_rate3,
|
||||||
|
job.cieca_pft.ty5_rate4,
|
||||||
|
job.cieca_pft.ty5_rate5,
|
||||||
|
]
|
||||||
|
.filter((i) => i > 0)
|
||||||
|
.join(", ")}%`,
|
||||||
|
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: t("jobs.labels.total_sales_tax"),
|
||||||
|
bold: true,
|
||||||
|
total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
|
||||||
|
.add(
|
||||||
|
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
|
||||||
|
)
|
||||||
|
.add(
|
||||||
|
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
|
||||||
|
)
|
||||||
|
.add(
|
||||||
|
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
|
||||||
|
)
|
||||||
|
.add(
|
||||||
|
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
|
||||||
|
).toJSON(),
|
||||||
|
},
|
||||||
|
].filter((item) => item.total.amount !== 0)
|
||||||
|
: [
|
||||||
|
{
|
||||||
|
key: t("jobs.labels.state_tax_amt"),
|
||||||
|
total: job.job_totals.totals.state_tax,
|
||||||
|
},
|
||||||
|
])]
|
||||||
|
}),
|
||||||
|
|
||||||
...(job.job_totals.totals.us_sales_tax_breakdown
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
key: `${
|
|
||||||
bodyshop.md_responsibility_centers.taxes.tax_ty1?.tax_type1 ||
|
|
||||||
"T1"
|
|
||||||
} - ${[
|
|
||||||
job.cieca_pft.ty1_rate1,
|
|
||||||
job.cieca_pft.ty1_rate2,
|
|
||||||
job.cieca_pft.ty1_rate3,
|
|
||||||
job.cieca_pft.ty1_rate4,
|
|
||||||
job.cieca_pft.ty1_rate5,
|
|
||||||
]
|
|
||||||
.filter((i) => i > 0)
|
|
||||||
.join(", ")}%`,
|
|
||||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty1Tax,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${
|
|
||||||
bodyshop.md_responsibility_centers.taxes.tax_ty2?.tax_type2 ||
|
|
||||||
"T2"
|
|
||||||
} - ${[
|
|
||||||
job.cieca_pft.ty2_rate1,
|
|
||||||
job.cieca_pft.ty2_rate2,
|
|
||||||
job.cieca_pft.ty2_rate3,
|
|
||||||
job.cieca_pft.ty2_rate4,
|
|
||||||
job.cieca_pft.ty2_rate5,
|
|
||||||
]
|
|
||||||
.filter((i) => i > 0)
|
|
||||||
.join(", ")}%`,
|
|
||||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty2Tax,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${
|
|
||||||
bodyshop.md_responsibility_centers.taxes.tax_ty3?.tax_type3 ||
|
|
||||||
"T3"
|
|
||||||
} - ${[
|
|
||||||
job.cieca_pft.ty3_rate1,
|
|
||||||
job.cieca_pft.ty3_rate2,
|
|
||||||
job.cieca_pft.ty3_rate3,
|
|
||||||
job.cieca_pft.ty3_rate4,
|
|
||||||
job.cieca_pft.ty3_rate5,
|
|
||||||
]
|
|
||||||
.filter((i) => i > 0)
|
|
||||||
.join(", ")}%`,
|
|
||||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty3Tax,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${
|
|
||||||
bodyshop.md_responsibility_centers.taxes.tax_ty4?.tax_type4 ||
|
|
||||||
"T4"
|
|
||||||
} - ${[
|
|
||||||
job.cieca_pft.ty4_rate1,
|
|
||||||
job.cieca_pft.ty4_rate2,
|
|
||||||
job.cieca_pft.ty4_rate3,
|
|
||||||
job.cieca_pft.ty4_rate4,
|
|
||||||
job.cieca_pft.ty4_rate5,
|
|
||||||
]
|
|
||||||
.filter((i) => i > 0)
|
|
||||||
.join(", ")}%`,
|
|
||||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: `${
|
|
||||||
bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 ||
|
|
||||||
"TT"
|
|
||||||
} - ${[
|
|
||||||
job.cieca_pft.ty5_rate1,
|
|
||||||
job.cieca_pft.ty5_rate2,
|
|
||||||
job.cieca_pft.ty5_rate3,
|
|
||||||
job.cieca_pft.ty5_rate4,
|
|
||||||
job.cieca_pft.ty5_rate5,
|
|
||||||
]
|
|
||||||
.filter((i) => i > 0)
|
|
||||||
.join(", ")}%`,
|
|
||||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: t("jobs.labels.total_sales_tax"),
|
|
||||||
bold: true,
|
|
||||||
total: Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
|
|
||||||
.add(
|
|
||||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty2Tax)
|
|
||||||
)
|
|
||||||
.add(
|
|
||||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax)
|
|
||||||
)
|
|
||||||
.add(
|
|
||||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax)
|
|
||||||
)
|
|
||||||
.add(
|
|
||||||
Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax)
|
|
||||||
).toJSON(),
|
|
||||||
},
|
|
||||||
].filter((item) => item.total.amount !== 0)
|
|
||||||
: [
|
|
||||||
{
|
|
||||||
key: t("jobs.labels.state_tax_amt"),
|
|
||||||
total: job.job_totals.totals.state_tax,
|
|
||||||
},
|
|
||||||
]),
|
|
||||||
|
|
||||||
{
|
{
|
||||||
key: t("jobs.labels.total_repairs"),
|
key: t("jobs.labels.total_repairs"),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {connect} from "react-redux";
|
|||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {logImEXEvent} from "../../firebase/firebase.utils";
|
import {logImEXEvent} from "../../firebase/firebase.utils";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -29,19 +30,25 @@ export function JobsCloseAutoAllocate({bodyshop, joblines, form, disabled}) {
|
|||||||
ret.profitcenter_labor = null;
|
ret.profitcenter_labor = null;
|
||||||
}
|
}
|
||||||
//Verify that this is also manually updated in server/job-costing
|
//Verify that this is also manually updated in server/job-costing
|
||||||
if (!jl.part_type && !jl.mod_lbr_ty) {
|
if (
|
||||||
const lineDesc = jl.line_desc ? jl.line_desc.toLowerCase() : "";
|
InstanceRenderManager({
|
||||||
if (lineDesc.includes("shop materials")) {
|
imex: !jl.part_type && !jl.mod_lbr_ty,
|
||||||
ret.profitcenter_part = defaults.profits["MASH"];
|
rome: !ret.profitcenter_part,
|
||||||
} else if (lineDesc.includes("paint/materials")) {
|
promanager: 'USE_ROME',
|
||||||
ret.profitcenter_part = defaults.profits["MAPA"];
|
})
|
||||||
} else if (lineDesc.includes("ats amount")) {
|
) {
|
||||||
ret.profitcenter_part = defaults.profits["ATS"];
|
const lineDesc = jl.line_desc ? jl.line_desc.toLowerCase() : '';
|
||||||
} else if (jl.act_price > 0) {
|
if (lineDesc.includes('shop materials')) {
|
||||||
ret.profitcenter_part = defaults.profits["PAO"];
|
ret.profitcenter_part = defaults.profits['MASH'];
|
||||||
} else {
|
} else if (lineDesc.includes('paint/materials')) {
|
||||||
ret.profitcenter_part = null;
|
ret.profitcenter_part = defaults.profits['MAPA'];
|
||||||
}
|
} else if (lineDesc.includes('ats amount')) {
|
||||||
|
ret.profitcenter_part = defaults.profits['ATS'];
|
||||||
|
} else if (jl.act_price > 0) {
|
||||||
|
ret.profitcenter_part = defaults.profits['PAO'];
|
||||||
|
} else {
|
||||||
|
ret.profitcenter_part = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,261 +1,225 @@
|
|||||||
import {Divider, Form, Input, InputNumber, Select, Space, Switch, Tooltip,} from "antd";
|
import { Divider, Form, Input, InputNumber, Select, Space, Switch, Tooltip } from 'antd';
|
||||||
import React from "react";
|
import React from 'react';
|
||||||
import {useTranslation} from "react-i18next";
|
import { useTranslation } from 'react-i18next';
|
||||||
import {connect} from "react-redux";
|
import { connect } from 'react-redux';
|
||||||
import {createStructuredSelector} from "reselect";
|
import { createStructuredSelector } from 'reselect';
|
||||||
import {selectJobReadOnly} from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from '../../redux/application/application.selectors';
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import { selectBodyshop } from '../../redux/user/user.selectors';
|
||||||
import CABCpvrtCalculator from "../ca-bc-pvrt-calculator/ca-bc-pvrt-calculator.component";
|
import CABCpvrtCalculator from '../ca-bc-pvrt-calculator/ca-bc-pvrt-calculator.component';
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from '../form-items-formatted/currency-form-item.component';
|
||||||
import JobsDetailRatesChangeButton from "../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component";
|
import JobsDetailRatesChangeButton from '../jobs-detail-rates-change-button/jobs-detail-rates-change-button.component';
|
||||||
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
import JobsMarkPstExempt from '../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component';
|
||||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
import FormRow from '../layout-form-row/layout-form-row.component';
|
||||||
import JobsDetailRatesLabor from "./jobs-detail-rates.labor.component";
|
import JobsDetailRatesLabor from './jobs-detail-rates.labor.component';
|
||||||
import JobsDetailRatesMaterials from "./jobs-detail-rates.materials.component";
|
import JobsDetailRatesMaterials from './jobs-detail-rates.materials.component';
|
||||||
import JobsDetailRatesOther from "./jobs-detail-rates.other.component";
|
import JobsDetailRatesOther from './jobs-detail-rates.other.component';
|
||||||
import JobsDetailRatesParts from "./jobs-detail-rates.parts.component";
|
import JobsDetailRatesParts from './jobs-detail-rates.parts.component';
|
||||||
import JobsDetailRatesTaxes from "./jobs-detail-rates.taxes.component";
|
import JobsDetailRatesTaxes from './jobs-detail-rates.taxes.component';
|
||||||
import JobsDetailRatesProfileOVerride from "./jobs-detail-rates.profile-override.component";
|
import JobsDetailRatesProfileOVerride from './jobs-detail-rates.profile-override.component';
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function JobsDetailRates({jobRO, form, job, bodyshop}) {
|
export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||||
const {t} = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<FormRow>
|
<FormRow>
|
||||||
<Form.Item label={t("jobs.fields.class")} name="class">
|
<Form.Item label={t('jobs.fields.class')} name="class">
|
||||||
<Select disabled={true}/>
|
<Select disabled={true} />
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.depreciation_taxes")}
|
|
||||||
name="depreciation_taxes"
|
|
||||||
>
|
|
||||||
<CurrencyInput disabled={jobRO} min={0}/>
|
|
||||||
</Form.Item>
|
|
||||||
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
|
|
||||||
<Tooltip title={t("jobs.labels.ca_gst_all_if_null")}>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.ca_customer_gst")}
|
|
||||||
name="ca_customer_gst"
|
|
||||||
>
|
|
||||||
<CurrencyInput
|
|
||||||
disabled={jobRO}
|
|
||||||
min={0}
|
|
||||||
max={
|
|
||||||
Math.round(
|
|
||||||
(job.job_totals &&
|
|
||||||
job.job_totals.totals.federal_tax.amount) ||
|
|
||||||
0
|
|
||||||
) / 100
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</Tooltip>
|
|
||||||
)}
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.other_amount_payable")}
|
|
||||||
name="other_amount_payable"
|
|
||||||
>
|
|
||||||
<CurrencyInput disabled={jobRO} min={0}/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.towing_payable")}
|
|
||||||
name="towing_payable"
|
|
||||||
>
|
|
||||||
<CurrencyInput disabled={jobRO} min={0}/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.storage_payable")}
|
|
||||||
name="storage_payable"
|
|
||||||
>
|
|
||||||
<CurrencyInput disabled={jobRO} min={0}/>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.adjustment_bottom_line")}
|
|
||||||
name="adjustment_bottom_line"
|
|
||||||
>
|
|
||||||
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid}/>
|
|
||||||
</Form.Item>
|
|
||||||
{bodyshop.region_config === "CA_BC" && (
|
|
||||||
<Space align="center">
|
|
||||||
<Form.Item label={t("jobs.fields.ca_bc_pvrt")} name="ca_bc_pvrt">
|
|
||||||
<CurrencyInput disabled={jobRO} min={0}/>
|
|
||||||
</Form.Item>
|
|
||||||
<CABCpvrtCalculator form={form} disabled={jobRO}/>
|
|
||||||
</Space>
|
|
||||||
)}
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.auto_add_ats")}
|
|
||||||
name="auto_add_ats"
|
|
||||||
valuePropName="checked"
|
|
||||||
>
|
|
||||||
<Switch disabled={jobRO}/>
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
noStyle
|
|
||||||
shouldUpdate={(prev, cur) => prev.auto_add_ats !== cur.auto_add_ats}
|
|
||||||
>
|
|
||||||
{() => {
|
|
||||||
if (form.getFieldValue("auto_add_ats"))
|
|
||||||
return (
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.rate_ats")}
|
|
||||||
name="rate_ats"
|
|
||||||
initialValue={bodyshop.shoprates.rate_atp}
|
|
||||||
>
|
|
||||||
<CurrencyInput disabled={jobRO}/>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}}
|
|
||||||
</Form.Item>
|
|
||||||
</FormRow>
|
|
||||||
{
|
|
||||||
InstanceRenderManager({imex:
|
|
||||||
<FormRow>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.federal_tax_rate")}
|
|
||||||
name="federal_tax_rate"
|
|
||||||
>
|
|
||||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO}/>
|
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item label={t('jobs.fields.depreciation_taxes')} name="depreciation_taxes">
|
||||||
|
<CurrencyInput disabled={jobRO} min={0} />
|
||||||
|
</Form.Item>
|
||||||
|
{bodyshop.region_config.toLowerCase().startsWith('ca') && (
|
||||||
|
<Tooltip title={t('jobs.labels.ca_gst_all_if_null')}>
|
||||||
|
<Form.Item label={t('jobs.fields.ca_customer_gst')} name="ca_customer_gst">
|
||||||
|
<CurrencyInput
|
||||||
|
disabled={jobRO}
|
||||||
|
min={0}
|
||||||
|
max={
|
||||||
|
Math.round((job.job_totals && job.job_totals.totals.federal_tax.amount) || 0) /
|
||||||
|
100
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
<Form.Item label={t('jobs.fields.other_amount_payable')} name="other_amount_payable">
|
||||||
|
<CurrencyInput disabled={jobRO} min={0} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label={t('jobs.fields.towing_payable')} name="towing_payable">
|
||||||
|
<CurrencyInput disabled={jobRO} min={0} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label={t('jobs.fields.storage_payable')} name="storage_payable">
|
||||||
|
<CurrencyInput disabled={jobRO} min={0} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label={t('jobs.fields.adjustment_bottom_line')} name="adjustment_bottom_line">
|
||||||
|
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid} />
|
||||||
|
</Form.Item>
|
||||||
|
{bodyshop.region_config === 'CA_BC' && (
|
||||||
|
<Space align="center">
|
||||||
|
<Form.Item label={t('jobs.fields.ca_bc_pvrt')} name="ca_bc_pvrt">
|
||||||
|
<CurrencyInput disabled={jobRO} min={0} />
|
||||||
|
</Form.Item>
|
||||||
|
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.state_tax_rate")}
|
label={t('jobs.fields.auto_add_ats')}
|
||||||
name="state_tax_rate"
|
name="auto_add_ats"
|
||||||
|
valuePropName="checked"
|
||||||
>
|
>
|
||||||
<InputNumber
|
<Switch disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item noStyle shouldUpdate={(prev, cur) => prev.auto_add_ats !== cur.auto_add_ats}>
|
||||||
|
{() => {
|
||||||
|
if (form.getFieldValue('auto_add_ats'))
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t('jobs.fields.rate_ats')}
|
||||||
|
name="rate_ats"
|
||||||
|
initialValue={bodyshop.shoprates.rate_atp}
|
||||||
|
>
|
||||||
|
<CurrencyInput disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</FormRow>
|
||||||
|
{InstanceRenderManager({
|
||||||
|
imex: (
|
||||||
|
<FormRow>
|
||||||
|
<Form.Item label={t('jobs.fields.federal_tax_rate')} name="federal_tax_rate">
|
||||||
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label={t('jobs.fields.state_tax_rate')} name="state_tax_rate">
|
||||||
|
<InputNumber
|
||||||
min={0}
|
min={0}
|
||||||
max={1}
|
max={1}
|
||||||
precision={2}
|
precision={2}
|
||||||
disabled={jobRO}
|
disabled={jobRO}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item label={t('jobs.fields.local_tax_rate')} name="local_tax_rate">
|
||||||
label={t("jobs.fields.local_tax_rate")}
|
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||||
name="local_tax_rate"
|
</Form.Item>
|
||||||
>
|
{bodyshop.region_config.toLowerCase().startsWith('ca') && (
|
||||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO}/>
|
<Form.Item
|
||||||
</Form.Item>
|
label={t('jobs.fields.ca_gst_registrant')}
|
||||||
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.ca_gst_registrant")}
|
|
||||||
name="ca_gst_registrant"
|
name="ca_gst_registrant"
|
||||||
valuePropName="checked"
|
valuePropName="checked"
|
||||||
>
|
>
|
||||||
<Switch disabled={jobRO}/>
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</FormRow>})
|
</FormRow>
|
||||||
}
|
),
|
||||||
<Divider
|
})}
|
||||||
orientation="left"
|
<Divider orientation="left" type="horizontal" style={{ marginTop: '.8rem', float: 'right' }}>
|
||||||
type="horizontal"
|
{t('jobs.forms.laborrates')}
|
||||||
style={{marginTop: ".8rem", float: "right"}}
|
</Divider>
|
||||||
>
|
<Space>
|
||||||
{t("jobs.forms.laborrates")}
|
<JobsDetailRatesChangeButton form={form} disabled={jobRO} />
|
||||||
</Divider>
|
<JobsMarkPstExempt form={form} />
|
||||||
<Space>
|
</Space>
|
||||||
<JobsDetailRatesChangeButton form={form} disabled={jobRO}/>
|
<FormRow noDivider>
|
||||||
<JobsMarkPstExempt form={form}/>
|
<Form.Item label={t('jobs.fields.labor_rate_desc')} name="labor_rate_desc">
|
||||||
</Space>
|
<Input disabled={jobRO} />
|
||||||
<FormRow noDivider>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item label={t('jobs.fields.rate_laa')} name="rate_laa">
|
||||||
label={t("jobs.fields.labor_rate_desc")}
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
name="labor_rate_desc"
|
</Form.Item>
|
||||||
>
|
<Form.Item label={t('jobs.fields.rate_lab')} name="rate_lab">
|
||||||
<Input disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_laa")} name="rate_laa">
|
<Form.Item label={t('jobs.fields.rate_lad')} name="rate_lad">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
|
<Form.Item label={t('jobs.fields.rate_lae')} name="rate_lae">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_lad")} name="rate_lad">
|
<Form.Item label={t('jobs.fields.rate_lar')} name="rate_lar">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_lae")} name="rate_lae">
|
<Form.Item label={t('jobs.fields.rate_las')} name="rate_las">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_lar")} name="rate_lar">
|
<Form.Item label={t('jobs.fields.rate_laf')} name="rate_laf">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_las")} name="rate_las">
|
<Form.Item label={t('jobs.fields.rate_lam')} name="rate_lam">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_laf")} name="rate_laf">
|
<Form.Item label={t('jobs.fields.rate_lag')} name="rate_lag">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_lam")} name="rate_lam">
|
<Form.Item label={t('jobs.fields.rate_la1')} name="rate_la1">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_lag")} name="rate_lag">
|
<Form.Item label={t('jobs.fields.rate_la2')} name="rate_la2">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_la1")} name="rate_la1">
|
<Form.Item label={t('jobs.fields.rate_la3')} name="rate_la3">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_la2")} name="rate_la2">
|
<Form.Item label={t('jobs.fields.rate_la4')} name="rate_la4">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_la3")} name="rate_la3">
|
<Form.Item label={t('jobs.fields.rate_lau')} name="rate_lau">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_la4")} name="rate_la4">
|
<Form.Item label={t('jobs.fields.rate_mapa')} name="rate_mapa">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_lau")} name="rate_lau">
|
<Form.Item label={t('jobs.fields.rate_mash')} name="rate_mash">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_mapa")} name="rate_mapa">
|
<Form.Item label={t('jobs.fields.rate_mahw')} name="rate_mahw">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_mash")} name="rate_mash">
|
<Form.Item label={t('jobs.fields.rate_ma2s')} name="rate_ma2s">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_mahw")} name="rate_mahw">
|
<Form.Item label={t('jobs.fields.rate_ma3s')} name="rate_ma3s">
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.rate_ma2s")} name="rate_ma2s">
|
{
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
// <Form.Item label={t("jobs.fields.rate_mabl")} name="rate_mabl">
|
||||||
</Form.Item>
|
// <CurrencyInput min={0}disabled={jobRO} />
|
||||||
<Form.Item label={t("jobs.fields.rate_ma3s")} name="rate_ma3s">
|
// </Form.Item>
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
// <Form.Item label={t("jobs.fields.rate_macs")} name="rate_macs">
|
||||||
</Form.Item>
|
// <CurrencyInput min={0}disabled={jobRO} />
|
||||||
{
|
// </Form.Item>
|
||||||
// <Form.Item label={t("jobs.fields.rate_mabl")} name="rate_mabl">
|
}
|
||||||
// <CurrencyInput min={0}disabled={jobRO} />
|
<Form.Item label={t('jobs.fields.rate_matd')} name="rate_matd">
|
||||||
// </Form.Item>
|
<CurrencyInput min={0} disabled={jobRO} />
|
||||||
// <Form.Item label={t("jobs.fields.rate_macs")} name="rate_macs">
|
</Form.Item>
|
||||||
// <CurrencyInput min={0}disabled={jobRO} />
|
</FormRow>
|
||||||
// </Form.Item>
|
{InstanceRenderManager({
|
||||||
}
|
imex: <JobsDetailRatesParts form={form} />,
|
||||||
<Form.Item label={t("jobs.fields.rate_matd")} name="rate_matd">
|
rome: (
|
||||||
<CurrencyInput min={0} disabled={jobRO}/>
|
<>
|
||||||
</Form.Item>
|
<Divider orientation="left">Tax Profile</Divider>
|
||||||
</FormRow>
|
<JobsDetailRatesProfileOVerride form={form} />
|
||||||
{
|
<JobsDetailRatesParts form={form} />
|
||||||
InstanceRenderManager({rome: <>
|
<JobsDetailRatesLabor form={form} />
|
||||||
<Divider orientation="left">Tax Profile</Divider>
|
<JobsDetailRatesMaterials form={form} />
|
||||||
<JobsDetailRatesProfileOVerride form={form}/>
|
<JobsDetailRatesOther form={form} />
|
||||||
<JobsDetailRatesParts form={form}/>
|
<JobsDetailRatesTaxes form={form} />
|
||||||
<JobsDetailRatesLabor form={form}/>
|
</>
|
||||||
<JobsDetailRatesMaterials form={form}/>
|
),
|
||||||
<JobsDetailRatesOther form={form}/>
|
promanager: "USE_ROME"
|
||||||
<JobsDetailRatesTaxes form={form}/>
|
})}
|
||||||
|
</div>
|
||||||
</>})
|
);
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(JobsDetailRates);
|
export default connect(mapStateToProps, null)(JobsDetailRates);
|
||||||
|
|||||||
@@ -34,19 +34,20 @@ export function PartDispatchTableComponent({
|
|||||||
// const selectedBill = search.billid;
|
// const selectedBill = search.billid;
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
|
|
||||||
const Templates = TemplateList("job_special");
|
const Templates = TemplateList("job_special", job);
|
||||||
|
|
||||||
const {refetch} = billsQuery;
|
const {refetch} = billsQuery;
|
||||||
|
|
||||||
const recordActions = (record) => (
|
const recordActions = (record) => (
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
<PrintWrapperComponent
|
<PrintWrapperComponent
|
||||||
templateObject={{
|
templateObject={{
|
||||||
name: Templates.parts_dispatch.key,
|
name: Templates.parts_dispatch.key,
|
||||||
variables: {id: record.id},
|
variables: { id: record.id },
|
||||||
}}
|
}}
|
||||||
/>
|
messageObject={{ subject: Templates.parts_dispatch.subject }}
|
||||||
</Space>
|
/>
|
||||||
|
</Space>
|
||||||
);
|
);
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {connect} from "react-redux";
|
|||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
|
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -31,7 +32,13 @@ export function ProductionColumnsComponent({
|
|||||||
}) {
|
}) {
|
||||||
const [columns, setColumns] = columnState;
|
const [columns, setColumns] = columnState;
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
const {
|
||||||
|
treatments: { Enhanced_Payroll },
|
||||||
|
} = useSplitTreatments({
|
||||||
|
attributes: {},
|
||||||
|
names: ['Enhanced_Payroll'],
|
||||||
|
splitKey: bodyshop.imexshopid,
|
||||||
|
});
|
||||||
const handleAdd = (e) => {
|
const handleAdd = (e) => {
|
||||||
setColumns([
|
setColumns([
|
||||||
...columns,
|
...columns,
|
||||||
@@ -41,6 +48,7 @@ export function ProductionColumnsComponent({
|
|||||||
state: tableState,
|
state: tableState,
|
||||||
data,
|
data,
|
||||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||||
|
treatments:{Enhanced_Payroll}
|
||||||
}).filter((i) => i.key === e.key),
|
}).filter((i) => i.key === e.key),
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
@@ -52,6 +60,7 @@ export function ProductionColumnsComponent({
|
|||||||
state: tableState,
|
state: tableState,
|
||||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||||
refetch,
|
refetch,
|
||||||
|
treatments:{Enhanced_Payroll}
|
||||||
});
|
});
|
||||||
|
|
||||||
const menu = {
|
const menu = {
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.co
|
|||||||
import {store} from "../../redux/store";
|
import {store} from "../../redux/store";
|
||||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||||
|
|
||||||
const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
|
const r = ({technician, state, activeStatuses, data, bodyshop, refetch, treatments}) => {
|
||||||
|
const {Enhanced_Payroll} = treatments;
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
title: i18n.t("jobs.actions.viewdetail"),
|
title: i18n.t("jobs.actions.viewdetail"),
|
||||||
@@ -42,7 +43,7 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
|
|||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
...Enhanced_Payroll.treatment === "on" ? [ {
|
||||||
title: i18n.t("timetickets.actions.claimtasks"),
|
title: i18n.t("timetickets.actions.claimtasks"),
|
||||||
dataIndex: "claimtasks",
|
dataIndex: "claimtasks",
|
||||||
key: "claimtasks",
|
key: "claimtasks",
|
||||||
@@ -64,7 +65,7 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
|
|||||||
{i18n.t("timetickets.actions.claimtasks")}
|
{i18n.t("timetickets.actions.claimtasks")}
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
},
|
},] : [],
|
||||||
{
|
{
|
||||||
title: i18n.t("jobs.fields.ro_number"),
|
title: i18n.t("jobs.fields.ro_number"),
|
||||||
dataIndex: "ro_number",
|
dataIndex: "ro_number",
|
||||||
@@ -326,7 +327,7 @@ const r = ({technician, state, activeStatuses, data, bodyshop, refetch}) => {
|
|||||||
onFilter: (value, record) =>
|
onFilter: (value, record) =>
|
||||||
value.includes(record.special_coverage_policy),
|
value.includes(record.special_coverage_policy),
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Checkbox disabled checked={record.special_coverage_policy} />
|
<Checkbox checked={record.special_coverage_policy} />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {UPDATE_SHOP} from "../../graphql/bodyshop.queries";
|
|||||||
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
||||||
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
||||||
import ProductionListColumns from "../production-list-columns/production-list-columns.data";
|
import ProductionListColumns from "../production-list-columns/production-list-columns.data";
|
||||||
|
import {useSplitTreatments} from '@splitsoftware/splitio-react';
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -31,6 +32,12 @@ export function ProductionListTable({
|
|||||||
const [updateDefaultProdView] = useMutation(UPDATE_ACTIVE_PROD_LIST_VIEW);
|
const [updateDefaultProdView] = useMutation(UPDATE_ACTIVE_PROD_LIST_VIEW);
|
||||||
const [updateShop] = useMutation(UPDATE_SHOP);
|
const [updateShop] = useMutation(UPDATE_SHOP);
|
||||||
|
|
||||||
|
const {treatments: {Enhanced_Payroll}} = useSplitTreatments({
|
||||||
|
attributes: {},
|
||||||
|
names: ["Enhanced_Payroll"],
|
||||||
|
splitKey: bodyshop.imexshopid,
|
||||||
|
});
|
||||||
|
|
||||||
const handleSelect = async (value, option) => {
|
const handleSelect = async (value, option) => {
|
||||||
setColumns(
|
setColumns(
|
||||||
bodyshop.production_config
|
bodyshop.production_config
|
||||||
@@ -44,6 +51,7 @@ export function ProductionListTable({
|
|||||||
state,
|
state,
|
||||||
data: data,
|
data: data,
|
||||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||||
|
treatments:{Enhanced_Payroll}
|
||||||
}).find((e) => e.key === k.key),
|
}).find((e) => e.key === k.key),
|
||||||
width: k.width,
|
width: k.width,
|
||||||
};
|
};
|
||||||
@@ -100,6 +108,7 @@ export function ProductionListTable({
|
|||||||
refetch,
|
refetch,
|
||||||
data: data,
|
data: data,
|
||||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||||
|
treatments: {Enhanced_Payroll}
|
||||||
}).find((e) => e.key === k.key),
|
}).find((e) => e.key === k.key),
|
||||||
width: k.width,
|
width: k.width,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,13 +28,12 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
|
|||||||
|
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
|
|
||||||
const {treatments: {Production_List_Status_Colors}} = useSplitTreatments({
|
const {treatments: {Production_List_Status_Colors, Enhanced_Payroll}} = useSplitTreatments({
|
||||||
attributes: {},
|
attributes: {},
|
||||||
names: ["Production_List_Status_Colors"],
|
names: ["Production_List_Status_Colors","Enhanced_Payroll"],
|
||||||
splitKey: bodyshop.imexshopid,
|
splitKey: bodyshop.imexshopid,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const assoc = bodyshop.associations.find(
|
const assoc = bodyshop.associations.find(
|
||||||
(a) => a.useremail === currentUser.email
|
(a) => a.useremail === currentUser.email
|
||||||
);
|
);
|
||||||
@@ -69,6 +68,7 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
|
|||||||
state,
|
state,
|
||||||
data,
|
data,
|
||||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||||
|
treatments: {Production_List_Status_Colors, Enhanced_Payroll}
|
||||||
}).find((e) => e.key === k.key),
|
}).find((e) => e.key === k.key),
|
||||||
width: k.width ?? 100,
|
width: k.width ?? 100,
|
||||||
};
|
};
|
||||||
@@ -89,6 +89,7 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
|
|||||||
state,
|
state,
|
||||||
data: data,
|
data: data,
|
||||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||||
|
treatments: {Production_List_Status_Colors, Enhanced_Payroll}
|
||||||
}).find((e) => e.key === k.key),
|
}).find((e) => e.key === k.key),
|
||||||
width: k.width ?? 100,
|
width: k.width ?? 100,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -141,9 +141,10 @@ export function ReportCenterModalComponent({reportCenterModal, bodyshop}) {
|
|||||||
|
|
||||||
const grouped = _.groupBy(FilteredReportsList, "group");
|
const grouped = _.groupBy(FilteredReportsList, "group");
|
||||||
|
|
||||||
const groupExcludeKeyFilter = [...!HasFeatureAccess({featureName: 'bills'})? ["purchases"]:[],
|
const groupExcludeKeyFilter = [
|
||||||
...!HasFeatureAccess({featureName: 'timetickets'})? ["payroll"]:[],
|
...(!HasFeatureAccess({ featureName: 'bills', bodyshop }) ? ['purchases'] : []),
|
||||||
]
|
...(!HasFeatureAccess({ featureName: 'timetickets', bodyshop }) ? ['payroll'] : []),
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import ShopInfoSpeedPrint from "./shop-info.speedprint.component";
|
|||||||
import {useLocation, useNavigate} from "react-router-dom";
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
import ShopInfoTaskPresets from "./shop-info.task-presets.component";
|
import ShopInfoTaskPresets from "./shop-info.task-presets.component";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
|||||||
@@ -241,17 +241,17 @@ export function ShopInfoResponsibilityCenterComponent({bodyshop, form}) {
|
|||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Space align="center">
|
<Space align="center">
|
||||||
d
|
<DeleteFilled
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
remove(field.name);
|
remove(field.name);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormListMoveArrows
|
<FormListMoveArrows
|
||||||
move={move}
|
move={move}
|
||||||
index={index}
|
index={index}
|
||||||
total={fields.length}
|
total={fields.length}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import {Link, useLocation, useNavigate} from "react-router-dom";
|
|||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import RomeLogo from "../../assets/RomeOnlineBlue.png";
|
import RomeLogo from "../../assets/RomeOnlineBlue.png";
|
||||||
import ImEXOnlineLogo from "../../assets/logo192.png";
|
import ImEXOnlineLogo from "../../assets/logo192.png";
|
||||||
|
import ProManagerLogo from '../../assets/promanager/ProManagerLogo.gif';
|
||||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||||
import {emailSignInStart, sendPasswordReset,} from "../../redux/user/user.actions";
|
import {emailSignInStart, sendPasswordReset,} from "../../redux/user/user.actions";
|
||||||
import {selectCurrentUser, selectLoginLoading, selectSignInError,} from "../../redux/user/user.selectors";
|
import {selectCurrentUser, selectLoginLoading, selectSignInError,} from "../../redux/user/user.selectors";
|
||||||
@@ -53,9 +54,9 @@ export function SignInComponent({
|
|||||||
return (
|
return (
|
||||||
<div className="login-container">
|
<div className="login-container">
|
||||||
<div className="login-logo-container">
|
<div className="login-logo-container">
|
||||||
<img src={InstanceRenderManager({imex:ImEXOnlineLogo, rome:RomeLogo, promanager:'https://www.web-est.com/img/web_est_logo_software.gif'})} width={200} alt={InstanceRenderManager({imex:t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})}/>
|
<img src={InstanceRenderManager({imex:ImEXOnlineLogo, rome:RomeLogo, promanager:ProManagerLogo})} width={InstanceRenderManager({imex:200, rome:200,promanager:450})} alt={InstanceRenderManager({imex:t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})}/>
|
||||||
<Typography.Title>{
|
<Typography.Title>{
|
||||||
InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})
|
InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:null})
|
||||||
}</Typography.Title>
|
}</Typography.Title>
|
||||||
</div>
|
</div>
|
||||||
<Form onFinish={handleFinish} form={form} size="large">
|
<Form onFinish={handleFinish} form={form} size="large">
|
||||||
|
|||||||
@@ -65,14 +65,19 @@ export function TimeTicketList({
|
|||||||
}, [timetickets]);
|
}, [timetickets]);
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
...(Enhanced_Payroll.treatment === "on"
|
||||||
title: t("timetickets.fields.committed"),
|
? [{
|
||||||
dataIndex: "committed_at",
|
title: t("timetickets.fields.committed"),
|
||||||
key: "committed_at",
|
dataIndex: "committed_at",
|
||||||
render: (text, record) => (
|
key: "committed_at",
|
||||||
<Checkbox disabled checked={record.committed_at}/>
|
render: (text, record) => (
|
||||||
),
|
<Checkbox disabled checked={record.committed_at}/>
|
||||||
},
|
),
|
||||||
|
},]
|
||||||
|
: [
|
||||||
|
|
||||||
|
]),
|
||||||
|
|
||||||
{
|
{
|
||||||
title: t("timetickets.fields.date"),
|
title: t("timetickets.fields.date"),
|
||||||
dataIndex: "date",
|
dataIndex: "date",
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component";
|
import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
|
import TimeTicketList from "../time-ticket-list/time-ticket-list.component";
|
||||||
import TimeTicketCalculatorComponent from "../time-ticket-calculator/time-ticket-calculator.component";
|
|
||||||
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ export function TimeTicketModalContainer({
|
|||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
afterClose={() => form.resetFields()}
|
afterClose={() => form.resetFields()}
|
||||||
footer={
|
footer={
|
||||||
<span>
|
<Space>
|
||||||
<Button onClick={handleCancel}>{t("general.actions.cancel")}</Button>
|
<Button onClick={handleCancel}>{t("general.actions.cancel")}</Button>
|
||||||
<Button
|
<Button
|
||||||
loading={loading}
|
loading={loading}
|
||||||
@@ -198,7 +198,7 @@ export function TimeTicketModalContainer({
|
|||||||
{t("general.actions.saveandnew")}
|
{t("general.actions.saveandnew")}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</span>
|
</Space>
|
||||||
}
|
}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
>
|
>
|
||||||
@@ -229,9 +229,12 @@ export function TimeTicketModalContainer({
|
|||||||
<PageHeader
|
<PageHeader
|
||||||
extra={
|
extra={
|
||||||
<Space>
|
<Space>
|
||||||
|
{
|
||||||
|
Enhanced_Payroll.treatment === 'on' &&
|
||||||
<TimeTicketsCommitToggleComponent
|
<TimeTicketsCommitToggleComponent
|
||||||
timeticket={timeTicketModal.context?.timeticket}
|
timeticket={timeTicketModal.context?.timeticket}
|
||||||
/>
|
/>
|
||||||
|
}
|
||||||
<Button onClick={handleCancel}>
|
<Button onClick={handleCancel}>
|
||||||
{t("general.actions.cancel")}
|
{t("general.actions.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,92 +1,91 @@
|
|||||||
import {HeartOutlined} from "@ant-design/icons";
|
import { HeartOutlined } from '@ant-design/icons';
|
||||||
import {Select, Space, Tag} from "antd";
|
import { Select, Space, Tag } from 'antd';
|
||||||
import React, {forwardRef, useEffect, useState} from "react";
|
import React, { forwardRef, useEffect, useState } from 'react';
|
||||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
import PhoneNumberFormatter from '../../utils/PhoneFormatter';
|
||||||
|
|
||||||
const {Option} = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
//To be used as a form element only.
|
//To be used as a form element only.
|
||||||
|
|
||||||
const VendorSearchSelect = (
|
const VendorSearchSelect = (
|
||||||
{value, onChange, options, onSelect, disabled, preferredMake, showPhone},
|
{ value, onChange, options, onSelect, disabled, preferredMake, showPhone },
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const [option, setOption] = useState(value);
|
const [option, setOption] = useState(value);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (value !== option && onChange) {
|
if (value !== option && onChange) {
|
||||||
onChange(option);
|
onChange(option);
|
||||||
}
|
}
|
||||||
}, [value, option, onChange]);
|
}, [value, option, onChange]);
|
||||||
|
|
||||||
const favorites =
|
const favorites =
|
||||||
preferredMake && options
|
preferredMake && options
|
||||||
? options.filter(
|
? options.filter(
|
||||||
(o) =>
|
(o) =>
|
||||||
o.favorite.filter(
|
o.favorite.filter((f) => f.toLowerCase() === preferredMake.toLowerCase()).length > 0
|
||||||
(f) => f.toLowerCase() === preferredMake.toLowerCase()
|
)
|
||||||
).length > 0
|
: [];
|
||||||
)
|
|
||||||
: [];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Select
|
<Select
|
||||||
ref={ref}
|
ref={ref}
|
||||||
showSearch
|
showSearch
|
||||||
value={option}
|
value={option}
|
||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: '100%',
|
||||||
}}
|
}}
|
||||||
popupMatchSelectWidth={false}
|
labelRender={({ label, value, ...rest }) => {
|
||||||
onChange={setOption}
|
if (!value || !options) return label;
|
||||||
optionFilterProp="name"
|
const discount = options?.find((o) => o.id === value)?.discount;
|
||||||
onSelect={onSelect}
|
return (
|
||||||
disabled={disabled || false}
|
<div className="imex-flex-row" style={{ width: '100%' }}>
|
||||||
optionLabelProp={"name"}
|
<div style={{ flex: 1 }}>{label}</div>
|
||||||
>
|
|
||||||
{favorites
|
|
||||||
? favorites.map((o) => (
|
|
||||||
<Option
|
|
||||||
key={`favorite-${o.id}`}
|
|
||||||
value={o.id}
|
|
||||||
name={o.name}
|
|
||||||
discount={o.discount}
|
|
||||||
>
|
|
||||||
<div className="imex-flex-row">
|
|
||||||
<div style={{flex: 1}}>{o.name}</div>
|
|
||||||
<Space style={{marginLeft: "1rem"}}>
|
|
||||||
<HeartOutlined style={{color: "red"}}/>
|
|
||||||
{o.phone && showPhone && (
|
|
||||||
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
|
|
||||||
)}
|
|
||||||
{o.discount && o.discount !== 0 ? (
|
|
||||||
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
|
||||||
) : null}
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
</Option>
|
|
||||||
))
|
|
||||||
: null}
|
|
||||||
{options
|
|
||||||
? options.map((o) => (
|
|
||||||
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
|
||||||
<div className="imex-flex-row" style={{width: "100%"}}>
|
|
||||||
<div style={{flex: 1}}>{o.name}</div>
|
|
||||||
|
|
||||||
<Space style={{marginLeft: "1rem"}}>
|
{discount && discount !== 0 ? <Tag color="green">{`${discount * 100}%`}</Tag> : null}
|
||||||
{o.phone && showPhone && (
|
</div>
|
||||||
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
|
);
|
||||||
)}
|
}}
|
||||||
{o.discount && o.discount !== 0 ? (
|
popupMatchSelectWidth={false}
|
||||||
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
onChange={setOption}
|
||||||
) : null}
|
optionFilterProp="name"
|
||||||
</Space>
|
onSelect={onSelect}
|
||||||
</div>
|
disabled={disabled || false}
|
||||||
</Option>
|
optionLabelProp={'name'}
|
||||||
|
>
|
||||||
|
{favorites
|
||||||
|
? favorites.map((o) => (
|
||||||
|
<Option key={`favorite-${o.id}`} value={o.id} name={o.name} discount={o.discount}>
|
||||||
|
<div className="imex-flex-row">
|
||||||
|
<div style={{ flex: 1 }}>{o.name}</div>
|
||||||
|
<Space style={{ marginLeft: '1rem' }}>
|
||||||
|
<HeartOutlined style={{ color: 'red' }} />
|
||||||
|
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||||
|
{o.discount && o.discount !== 0 ? (
|
||||||
|
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
||||||
|
) : null}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
))
|
||||||
|
: null}
|
||||||
|
{options
|
||||||
|
? options.map((o) => (
|
||||||
|
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
||||||
|
<div className="imex-flex-row" style={{ width: '100%' }}>
|
||||||
|
<div style={{ flex: 1 }}>{o.name}</div>
|
||||||
|
|
||||||
))
|
<Space style={{ marginLeft: '1rem' }}>
|
||||||
: null}
|
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||||
</Select>
|
{o.discount && o.discount !== 0 ? (
|
||||||
);
|
<Tag color="green">{`${o.discount * 100}%`}</Tag>
|
||||||
|
) : null}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
))
|
||||||
|
: null}
|
||||||
|
</Select>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
export default forwardRef(VendorSearchSelect);
|
export default forwardRef(VendorSearchSelect);
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ export function BillsListPage({
|
|||||||
state.sortedInfo.columnKey === "is_credit_memo" &&
|
state.sortedInfo.columnKey === "is_credit_memo" &&
|
||||||
state.sortedInfo.order,
|
state.sortedInfo.order,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Checkbox disabled checked={record.is_credit_memo}/>
|
<Checkbox checked={record.is_credit_memo}/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -136,7 +136,7 @@ export function BillsListPage({
|
|||||||
sorter: (a, b) => a.exported - b.exported,
|
sorter: (a, b) => a.exported - b.exported,
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "exported" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "exported" && state.sortedInfo.order,
|
||||||
render: (text, record) => <Checkbox disabled checked={record.exported}/>,
|
render: (text, record) => <Checkbox checked={record.exported}/>,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("general.labels.actions"),
|
title: t("general.labels.actions"),
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
|
|||||||
export const socket = SocketIO(
|
export const socket = SocketIO(
|
||||||
import.meta.env.PROD
|
import.meta.env.PROD
|
||||||
? import.meta.env.VITE_APP_AXIOS_BASE_API_URL
|
? import.meta.env.VITE_APP_AXIOS_BASE_API_URL
|
||||||
: window.location.origin,
|
: "http://localhost:4000", // for dev testing,
|
||||||
// "http://localhost:4000", // for dev testing,
|
|
||||||
{
|
{
|
||||||
path: "/ws",
|
path: "/ws",
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
|
|||||||
@@ -162,26 +162,24 @@ sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
|||||||
{ text: "False", value: false },
|
{ text: "False", value: false },
|
||||||
],
|
],
|
||||||
onFilter: (value, record) => record.successful === value,
|
onFilter: (value, record) => record.successful === value,
|
||||||
render: (text, record) => (
|
render: (text, record) => <Checkbox checked={record.successful} />,
|
||||||
<Checkbox disabled checked={record.successful}/>
|
},
|
||||||
),
|
{
|
||||||
},
|
title: t("general.labels.message"),
|
||||||
{
|
dataIndex: "message",
|
||||||
title: t("general.labels.message"),
|
key: "message",
|
||||||
dataIndex: "message",
|
render: (text, record) =>
|
||||||
key: "message",
|
record.message && (
|
||||||
render: (text, record) =>
|
<div>
|
||||||
record.message && (
|
<ul>
|
||||||
<div>
|
{JSON.parse(record.message).map((m, idx) => (
|
||||||
<ul>
|
<li key={idx}>{m}</li>
|
||||||
{JSON.parse(record.message).map((m, idx) => (
|
))}
|
||||||
<li key={idx}>{m}</li>
|
</ul>
|
||||||
))}
|
</div>
|
||||||
</ul>
|
),
|
||||||
</div>
|
},
|
||||||
),
|
];
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
|
|||||||
@@ -372,8 +372,9 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<Divider>{t("jobs.labels.multipayers")}</Divider>
|
|
||||||
{Qb_Multi_Ar.treatment === "on" && (
|
{Qb_Multi_Ar.treatment === "on" && (
|
||||||
|
<><Divider>{t("jobs.labels.multipayers")}</Divider>
|
||||||
<Row gutter={[16, 16]}>
|
<Row gutter={[16, 16]}>
|
||||||
<Col lg={8} md={24}>
|
<Col lg={8} md={24}>
|
||||||
<Form.List
|
<Form.List
|
||||||
@@ -452,7 +453,9 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
|
|||||||
<DeleteFilled
|
<DeleteFilled
|
||||||
disabled={jobRO}
|
disabled={jobRO}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
if(!jobRO){
|
||||||
remove(field.name);
|
remove(field.name);
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
@@ -530,6 +533,7 @@ export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Divider/>
|
<Divider/>
|
||||||
<JobsCloseLines job={job}/>
|
<JobsCloseLines job={job}/>
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ export function JobsDetailPage({
|
|||||||
{
|
{
|
||||||
key: "partssublet",
|
key: "partssublet",
|
||||||
icon: <ToolFilled/>,
|
icon: <ToolFilled/>,
|
||||||
label: t("menus.jobsdetail.partssublet"),
|
label: HasFeatureAccess({featureName: "bills", bodyshop}) ? t("menus.jobsdetail.partssublet") : t("menus.jobsdetail.parts"),
|
||||||
children: <JobsDetailPliContainer job={job}/>,
|
children: <JobsDetailPliContainer job={job}/>,
|
||||||
},
|
},
|
||||||
...InstanceRenderManager({ imex: true, rome: true, promanager: HasFeatureAccess({ featureName: 'timetickets', bodyshop }) }) ? [ {
|
...InstanceRenderManager({ imex: true, rome: true, promanager: HasFeatureAccess({ featureName: 'timetickets', bodyshop }) }) ? [ {
|
||||||
|
|||||||
@@ -521,13 +521,12 @@ export function Manage({conflict, bodyshop,enableJoyRide,joyRideSteps,setJoyRide
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={{ display: 'flex' }}>
|
<div style={{ display: 'flex' }}>
|
||||||
{`Joy Ride Status: ${enableJoyRide}`}
|
|
||||||
<div>
|
<div>
|
||||||
{`${InstanceRenderManager({
|
{`${InstanceRenderManager({
|
||||||
imex: t('titles.imexonline'),
|
imex: t('titles.imexonline'),
|
||||||
rome: t('titles.romeonline'),
|
rome: t('titles.romeonline'),
|
||||||
promanager: t('titles.promanager'),
|
promanager: t('titles.promanager'),
|
||||||
})} ${import.meta.env.VITE_APP_GIT_SHA || 'Local Build'} - ${
|
})} - ${
|
||||||
import.meta.env.VITE_APP_GIT_SHA_DATE
|
import.meta.env.VITE_APP_GIT_SHA_DATE
|
||||||
}`}
|
}`}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export function ShopPage({bodyshop, setSelectedHeader, setBreadcrumbs}) {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
if(HasFeatureAccess("csi")){
|
if(HasFeatureAccess({featureName:"csi", bodyshop})){
|
||||||
items.push({
|
items.push({
|
||||||
key: "csiq",
|
key: "csiq",
|
||||||
label: t("bodyshop.labels.csiq"),
|
label: t("bodyshop.labels.csiq"),
|
||||||
|
|||||||
@@ -1,103 +1,110 @@
|
|||||||
import {useQuery} from "@apollo/client";
|
import { useQuery } from '@apollo/client';
|
||||||
import {Col, Row, Space} from "antd";
|
import { Col, Row, Space } from 'antd';
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from '../../utils/day';
|
||||||
import React, {useEffect} from "react";
|
import React, { useEffect } from 'react';
|
||||||
import {useTranslation} from "react-i18next";
|
import { useTranslation } from 'react-i18next';
|
||||||
import {connect} from "react-redux";
|
import { connect } from 'react-redux';
|
||||||
import {useSearchParams} from "react-router-dom";
|
import { useSearchParams } from 'react-router-dom';
|
||||||
import {createStructuredSelector} from "reselect";
|
import { createStructuredSelector } from 'reselect';
|
||||||
import AlertComponent from "../../components/alert/alert.component";
|
import AlertComponent from '../../components/alert/alert.component';
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from '../../components/rbac-wrapper/rbac-wrapper.component';
|
||||||
import TimeTicketsDatesSelector
|
import TimeTicketsDatesSelector from '../../components/ticket-tickets-dates-selector/time-tickets-dates-selector.component';
|
||||||
from "../../components/ticket-tickets-dates-selector/time-tickets-dates-selector.component";
|
import TimeTicketList from '../../components/time-ticket-list/time-ticket-list.component';
|
||||||
import TimeTicketList from "../../components/time-ticket-list/time-ticket-list.component";
|
import TimeTicketsPayrollTable from '../../components/time-tickets-payroll-table/time-tickets-payroll-table.component';
|
||||||
import TimeTicketsPayrollTable from "../../components/time-tickets-payroll-table/time-tickets-payroll-table.component";
|
import TimeTicketsSummaryEmployees from '../../components/time-tickets-summary-employees/time-tickets-summary-employees.component';
|
||||||
import TimeTicketsSummaryEmployees
|
import { QUERY_TIME_TICKETS_IN_RANGE } from '../../graphql/timetickets.queries';
|
||||||
from "../../components/time-tickets-summary-employees/time-tickets-summary-employees.component";
|
import TimeTicketsAttendanceTable from '../../components/time-tickets-attendance-table/time-tickets-attendance-table.component';
|
||||||
import {QUERY_TIME_TICKETS_IN_RANGE} from "../../graphql/timetickets.queries";
|
import { setBreadcrumbs, setSelectedHeader } from '../../redux/application/application.actions';
|
||||||
import TimeTicketsAttendanceTable
|
import TimeTicketsCommit from '../../components/time-tickets-commit/time-tickets-commit.component';
|
||||||
from "../../components/time-tickets-attendance-table/time-tickets-attendance-table.component";
|
import FeatureWrapperComponent from '../../components/feature-wrapper/feature-wrapper.component';
|
||||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
|
||||||
import TimeTicketsCommit from "../../components/time-tickets-commit/time-tickets-commit.component";
|
|
||||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
|
||||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||||
|
import { useSplitTreatments } from '@splitsoftware/splitio-react';
|
||||||
|
import { selectBodyshop } from '../../redux/user/user.selectors';
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({});
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop:selectBodyshop
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
|
||||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export function TimeTicketsContainer({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
bodyshop,
|
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||||
setBreadcrumbs,
|
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||||
setSelectedHeader,
|
});
|
||||||
}) {
|
|
||||||
const {t} = useTranslation();
|
|
||||||
const [searchParams] = useSearchParams();
|
|
||||||
const {start, end} = Object.fromEntries(searchParams);
|
|
||||||
|
|
||||||
const startDate = start
|
export function TimeTicketsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||||
? dayjs(start)
|
const {
|
||||||
: dayjs().startOf("week").subtract(7, "day");
|
treatments: { Enhanced_Payroll },
|
||||||
const endDate = end ? dayjs(end) : dayjs().endOf("week");
|
} = useSplitTreatments({
|
||||||
|
attributes: {},
|
||||||
|
names: ['Enhanced_Payroll'],
|
||||||
|
splitKey: bodyshop.imexshopid,
|
||||||
|
});
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [searchParams] = useSearchParams();
|
||||||
|
const { start, end } = Object.fromEntries(searchParams);
|
||||||
|
|
||||||
const {loading, error, data} = useQuery(QUERY_TIME_TICKETS_IN_RANGE, {
|
const startDate = start ? dayjs(start) : dayjs().startOf('week').subtract(7, 'day');
|
||||||
variables: {
|
const endDate = end ? dayjs(end) : dayjs().endOf('week');
|
||||||
start: startDate,
|
|
||||||
end: endDate,
|
const { loading, error, data } = useQuery(QUERY_TIME_TICKETS_IN_RANGE, {
|
||||||
},
|
variables: {
|
||||||
fetchPolicy: "network-only",
|
start: startDate,
|
||||||
nextFetchPolicy: "network-only",
|
end: endDate,
|
||||||
|
},
|
||||||
|
fetchPolicy: 'network-only',
|
||||||
|
nextFetchPolicy: 'network-only',
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = t('titles.timetickets', {
|
||||||
|
app: InstanceRenderManager({
|
||||||
|
imex: '$t(titles.imexonline)',
|
||||||
|
rome: '$t(titles.romeonline)',
|
||||||
|
promanager: '$t(titles.promanager)',
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
setSelectedHeader('timetickets');
|
||||||
|
setBreadcrumbs([
|
||||||
|
{
|
||||||
|
link: '/manage/timetickets',
|
||||||
|
label: t('titles.bc.timetickets'),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||||
|
|
||||||
useEffect(() => {
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
document.title = t("titles.timetickets",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
|
||||||
setSelectedHeader("timetickets");
|
|
||||||
setBreadcrumbs([
|
|
||||||
{
|
|
||||||
link: "/manage/timetickets",
|
|
||||||
label: t("titles.bc.timetickets"),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
return (
|
||||||
|
<FeatureWrapperComponent featureName="timetickets">
|
||||||
return (
|
<RbacWrapper action="timetickets:list">
|
||||||
<FeatureWrapperComponent featureName='timetickets'>
|
<Row gutter={[16, 16]}>
|
||||||
<RbacWrapper action="timetickets:list">
|
<Col span={24}>
|
||||||
<Row gutter={[16, 16]}>
|
<TimeTicketList
|
||||||
<Col span={24}>
|
loading={loading}
|
||||||
<TimeTicketList
|
timetickets={data ? data.timetickets : []}
|
||||||
loading={loading}
|
extra={
|
||||||
timetickets={data ? data.timetickets : []}
|
<Space wrap>
|
||||||
extra={
|
<TimeTicketsAttendanceTable />
|
||||||
<Space wrap>
|
<TimeTicketsPayrollTable />
|
||||||
<TimeTicketsAttendanceTable/>
|
{Enhanced_Payroll.treatment === 'on' && (
|
||||||
<TimeTicketsPayrollTable/>
|
<TimeTicketsCommit timetickets={data ? data.timetickets : []} />
|
||||||
<TimeTicketsCommit timetickets={data ? data.timetickets : []}/>
|
)}
|
||||||
<TimeTicketsDatesSelector/>
|
<TimeTicketsDatesSelector />
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<TimeTicketsSummaryEmployees
|
<TimeTicketsSummaryEmployees
|
||||||
loading={loading}
|
loading={loading}
|
||||||
timetickets={data ? data.timetickets : []}
|
timetickets={data ? data.timetickets : []}
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</RbacWrapper>
|
</RbacWrapper>
|
||||||
</FeatureWrapperComponent>
|
</FeatureWrapperComponent>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketsContainer);
|
||||||
mapStateToProps,
|
|
||||||
mapDispatchToProps
|
|
||||||
)(TimeTicketsContainer);
|
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ import client from "../../utils/GraphQLClient";
|
|||||||
import {QUERY_EULA} from "../../graphql/bodyshop.queries";
|
import {QUERY_EULA} from "../../graphql/bodyshop.queries";
|
||||||
import day from "../../utils/day";
|
import day from "../../utils/day";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
import { Userpilot } from "userpilot";
|
||||||
|
|
||||||
const fpPromise = FingerprintJS.load();
|
const fpPromise = FingerprintJS.load();
|
||||||
|
|
||||||
@@ -227,6 +228,15 @@ export function* signInSuccessSaga({payload}) {
|
|||||||
window.$crisp.push(['set', 'user:nickname', [payload.displayName || payload.email]]);
|
window.$crisp.push(['set', 'user:nickname', [payload.displayName || payload.email]]);
|
||||||
window.$crisp.push(['set', 'session:segments', [['user']]]);
|
window.$crisp.push(['set', 'session:segments', [['user']]]);
|
||||||
},
|
},
|
||||||
|
promanager: () =>{
|
||||||
|
Userpilot.identify(
|
||||||
|
payload.email,
|
||||||
|
{
|
||||||
|
email: payload.email,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
console.log("*** Userpilot identified.")
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -749,7 +749,7 @@
|
|||||||
"refuelcharge": "Refuel Charge (per liter/gallon)",
|
"refuelcharge": "Refuel Charge (per liter/gallon)",
|
||||||
"scheduledreturn": "Scheduled Return",
|
"scheduledreturn": "Scheduled Return",
|
||||||
"start": "Contract Start",
|
"start": "Contract Start",
|
||||||
"statetax": "State Taxes",
|
"statetax": "Provincial/State Taxes",
|
||||||
"status": "Status"
|
"status": "Status"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
@@ -899,6 +899,7 @@
|
|||||||
"refhrs": "Refinish Hrs"
|
"refhrs": "Refinish Hrs"
|
||||||
},
|
},
|
||||||
"titles": {
|
"titles": {
|
||||||
|
"joblifecycle": "Job Life Cycles",
|
||||||
"labhours": "Total Body Hours",
|
"labhours": "Total Body Hours",
|
||||||
"larhours": "Total Refinish Hours",
|
"larhours": "Total Refinish Hours",
|
||||||
"monthlyemployeeefficiency": "Monthly Employee Efficiency",
|
"monthlyemployeeefficiency": "Monthly Employee Efficiency",
|
||||||
@@ -1164,6 +1165,7 @@
|
|||||||
"loadingshop": "Loading shop data...",
|
"loadingshop": "Loading shop data...",
|
||||||
"loggingin": "Authorizing...",
|
"loggingin": "Authorizing...",
|
||||||
"markedexported": "Manually marked as exported.",
|
"markedexported": "Manually marked as exported.",
|
||||||
|
"media": "Media",
|
||||||
"message": "Message",
|
"message": "Message",
|
||||||
"monday": "Monday",
|
"monday": "Monday",
|
||||||
"na": "N/A",
|
"na": "N/A",
|
||||||
@@ -2002,7 +2004,7 @@
|
|||||||
"savebeforeconversion": "You have unsaved changes on the Job. Please save them before converting it. ",
|
"savebeforeconversion": "You have unsaved changes on the Job. Please save them before converting it. ",
|
||||||
"scheduledinchange": "The scheduled in is based off the latest appointment. To change this date, please schedule or reschedule the Job. ",
|
"scheduledinchange": "The scheduled in is based off the latest appointment. To change this date, please schedule or reschedule the Job. ",
|
||||||
"specialcoveragepolicy": "Special Coverage Policy Applies",
|
"specialcoveragepolicy": "Special Coverage Policy Applies",
|
||||||
"state_tax_amt": "State Taxes",
|
"state_tax_amt": "Provincial/State Taxes",
|
||||||
"subletstotal": "Sublets Total",
|
"subletstotal": "Sublets Total",
|
||||||
"subtotal": "Subtotal",
|
"subtotal": "Subtotal",
|
||||||
"supplementnote": "The Job had a supplement imported.",
|
"supplementnote": "The Job had a supplement imported.",
|
||||||
@@ -2174,6 +2176,7 @@
|
|||||||
"insurance": "Insurance Information",
|
"insurance": "Insurance Information",
|
||||||
"labor": "Labor",
|
"labor": "Labor",
|
||||||
"lifecycle": "Lifecycle",
|
"lifecycle": "Lifecycle",
|
||||||
|
"parts": "Parts",
|
||||||
"partssublet": "Parts & Bills",
|
"partssublet": "Parts & Bills",
|
||||||
"rates": "Rates",
|
"rates": "Rates",
|
||||||
"repairdata": "Repair Data",
|
"repairdata": "Repair Data",
|
||||||
@@ -2558,7 +2561,7 @@
|
|||||||
"invoice_total_payable": "Invoice (Total Payable)",
|
"invoice_total_payable": "Invoice (Total Payable)",
|
||||||
"iou_form": "IOU Form",
|
"iou_form": "IOU Form",
|
||||||
"job_costing_ro": "Job Costing",
|
"job_costing_ro": "Job Costing",
|
||||||
"job_lifecycle_ro": "",
|
"job_lifecycle_ro": "Job Lifecycle",
|
||||||
"job_notes": "Job Notes",
|
"job_notes": "Job Notes",
|
||||||
"key_tag": "Key Tag",
|
"key_tag": "Key Tag",
|
||||||
"labels": {
|
"labels": {
|
||||||
|
|||||||
@@ -899,6 +899,7 @@
|
|||||||
"refhrs": ""
|
"refhrs": ""
|
||||||
},
|
},
|
||||||
"titles": {
|
"titles": {
|
||||||
|
"joblifecycle": "",
|
||||||
"labhours": "",
|
"labhours": "",
|
||||||
"larhours": "",
|
"larhours": "",
|
||||||
"monthlyemployeeefficiency": "",
|
"monthlyemployeeefficiency": "",
|
||||||
@@ -2174,6 +2175,7 @@
|
|||||||
"insurance": "",
|
"insurance": "",
|
||||||
"labor": "Labor",
|
"labor": "Labor",
|
||||||
"lifecycle": "",
|
"lifecycle": "",
|
||||||
|
"parts": "",
|
||||||
"partssublet": "Piezas / Subarrendamiento",
|
"partssublet": "Piezas / Subarrendamiento",
|
||||||
"rates": "",
|
"rates": "",
|
||||||
"repairdata": "Datos de reparación",
|
"repairdata": "Datos de reparación",
|
||||||
|
|||||||
@@ -899,6 +899,7 @@
|
|||||||
"refhrs": ""
|
"refhrs": ""
|
||||||
},
|
},
|
||||||
"titles": {
|
"titles": {
|
||||||
|
"joblifecycle": "",
|
||||||
"labhours": "",
|
"labhours": "",
|
||||||
"larhours": "",
|
"larhours": "",
|
||||||
"monthlyemployeeefficiency": "",
|
"monthlyemployeeefficiency": "",
|
||||||
@@ -2174,6 +2175,7 @@
|
|||||||
"insurance": "",
|
"insurance": "",
|
||||||
"labor": "La main d'oeuvre",
|
"labor": "La main d'oeuvre",
|
||||||
"lifecycle": "",
|
"lifecycle": "",
|
||||||
|
"parts": "",
|
||||||
"partssublet": "Pièces / Sous-location",
|
"partssublet": "Pièces / Sous-location",
|
||||||
"rates": "",
|
"rates": "",
|
||||||
"repairdata": "Données de réparation",
|
"repairdata": "Données de réparation",
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { initReactI18next } from 'react-i18next';
|
|||||||
import en_Translation from './en_us/common.json';
|
import en_Translation from './en_us/common.json';
|
||||||
import es_Translation from './es/common.json';
|
import es_Translation from './es/common.json';
|
||||||
import fr_Translation from './fr/common.json';
|
import fr_Translation from './fr/common.json';
|
||||||
|
import { GenerateTemplates } from '../utils/RenderTemplate';
|
||||||
|
|
||||||
// the translations
|
// the translations
|
||||||
// (tip move them in a JSON file and import them)
|
// (tip move them in a JSON file and import them)
|
||||||
@@ -13,19 +14,27 @@ const resources = {
|
|||||||
'es-MX': es_Translation,
|
'es-MX': es_Translation,
|
||||||
};
|
};
|
||||||
i18n
|
i18n
|
||||||
.use(initReactI18next)
|
|
||||||
.use(LanguageDetector) // passes i18n down to react-i18next
|
.use(LanguageDetector) // passes i18n down to react-i18next
|
||||||
.init({
|
.use(initReactI18next)
|
||||||
resources,
|
.init(
|
||||||
//lng: "en",
|
{
|
||||||
detection: {},
|
resources,
|
||||||
fallbackLng: 'en-US',
|
//lng: "en",
|
||||||
debug: import.meta.env.DEV,
|
detection: {},
|
||||||
//keySeparator: false, // we do not use keys in form messages.welcome
|
fallbackLng: 'en-US',
|
||||||
interpolation: {
|
debug: import.meta.env.DEV,
|
||||||
escapeValue: false, // react already safes from xss
|
react: {
|
||||||
skipOnVariables: false,
|
useSuspense: true,
|
||||||
|
},
|
||||||
|
//keySeparator: false, // we do not use keys in form messages.welcome
|
||||||
|
interpolation: {
|
||||||
|
escapeValue: false, // react already safes from xss
|
||||||
|
skipOnVariables: false,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
(error) => {
|
||||||
|
GenerateTemplates();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
export default i18n;
|
export default i18n;
|
||||||
|
|||||||
@@ -14,7 +14,12 @@ const server = import.meta.env.VITE_APP_REPORTS_SERVER_URL;
|
|||||||
|
|
||||||
jsreport.serverUrl = server;
|
jsreport.serverUrl = server;
|
||||||
|
|
||||||
const Templates = TemplateList();
|
let Templates;
|
||||||
|
export function GenerateTemplates(){
|
||||||
|
//Required as a part of the transition to Vite.
|
||||||
|
//Previous method had the template hash generating before translations loaded, resulting in empty files.
|
||||||
|
Templates = TemplateList()
|
||||||
|
}
|
||||||
|
|
||||||
export default async function RenderTemplate(
|
export default async function RenderTemplate(
|
||||||
templateObject,
|
templateObject,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import * as path from 'path';
|
|||||||
import * as url from 'url';
|
import * as url from 'url';
|
||||||
import { defineConfig } from 'vite';
|
import { defineConfig } from 'vite';
|
||||||
import { ViteEjsPlugin } from 'vite-plugin-ejs';
|
import { ViteEjsPlugin } from 'vite-plugin-ejs';
|
||||||
import CompressionPlugin from 'vite-plugin-compression';
|
//import CompressionPlugin from 'vite-plugin-compression';
|
||||||
import { VitePWA } from 'vite-plugin-pwa';
|
import { VitePWA } from 'vite-plugin-pwa';
|
||||||
import InstanceRenderManager from './src/utils/instanceRenderMgr';
|
import InstanceRenderManager from './src/utils/instanceRenderMgr';
|
||||||
|
|
||||||
@@ -103,8 +103,11 @@ export default defineConfig({
|
|||||||
}),
|
}),
|
||||||
reactVirtualized(),
|
reactVirtualized(),
|
||||||
react(),
|
react(),
|
||||||
CompressionPlugin(),
|
// CompressionPlugin(), //Cloudfront already compresses assets, so not needed.
|
||||||
],
|
],
|
||||||
|
define:{
|
||||||
|
"APP_VERSION": JSON.stringify(process.env.npm_package_version)
|
||||||
|
},
|
||||||
server: {
|
server: {
|
||||||
host: true,
|
host: true,
|
||||||
port: 3000,
|
port: 3000,
|
||||||
|
|||||||
@@ -569,6 +569,13 @@
|
|||||||
table:
|
table:
|
||||||
name: parts_orders
|
name: parts_orders
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: tasks
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: billid
|
||||||
|
table:
|
||||||
|
name: tasks
|
||||||
|
schema: public
|
||||||
insert_permissions:
|
insert_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
@@ -818,6 +825,13 @@
|
|||||||
table:
|
table:
|
||||||
name: inventory
|
name: inventory
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: ioevents
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: bodyshopid
|
||||||
|
table:
|
||||||
|
name: ioevents
|
||||||
|
schema: public
|
||||||
- name: jobs
|
- name: jobs
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -846,6 +860,13 @@
|
|||||||
table:
|
table:
|
||||||
name: phonebook
|
name: phonebook
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: tasks
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: bodyshopid
|
||||||
|
table:
|
||||||
|
name: tasks
|
||||||
|
schema: public
|
||||||
- name: timetickets
|
- name: timetickets
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -2675,6 +2696,13 @@
|
|||||||
- table:
|
- table:
|
||||||
name: ioevents
|
name: ioevents
|
||||||
schema: public
|
schema: public
|
||||||
|
object_relationships:
|
||||||
|
- name: bodyshop
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: bodyshopid
|
||||||
|
- name: user
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: useremail
|
||||||
- table:
|
- table:
|
||||||
name: job_ar_schema
|
name: job_ar_schema
|
||||||
schema: public
|
schema: public
|
||||||
@@ -2824,6 +2852,13 @@
|
|||||||
table:
|
table:
|
||||||
name: parts_order_lines
|
name: parts_order_lines
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: tasks
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: joblineid
|
||||||
|
table:
|
||||||
|
name: tasks
|
||||||
|
schema: public
|
||||||
insert_permissions:
|
insert_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
@@ -3311,6 +3346,13 @@
|
|||||||
table:
|
table:
|
||||||
name: scoreboard
|
name: scoreboard
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: tasks
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: jobid
|
||||||
|
table:
|
||||||
|
name: tasks
|
||||||
|
schema: public
|
||||||
- name: timetickets
|
- name: timetickets
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -5008,6 +5050,13 @@
|
|||||||
table:
|
table:
|
||||||
name: parts_order_lines
|
name: parts_order_lines
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: tasks
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: partsorderid
|
||||||
|
table:
|
||||||
|
name: tasks
|
||||||
|
schema: public
|
||||||
insert_permissions:
|
insert_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
@@ -5623,6 +5672,128 @@
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
|
- table:
|
||||||
|
name: tasks
|
||||||
|
schema: public
|
||||||
|
object_relationships:
|
||||||
|
- name: bill
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: billid
|
||||||
|
- name: bodyshop
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: bodyshopid
|
||||||
|
- name: job
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: jobid
|
||||||
|
- name: jobline
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: joblineid
|
||||||
|
- name: parts_order
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: partsorderid
|
||||||
|
- name: user
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: assigned_to
|
||||||
|
- name: userByCreatedBy
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: created_by
|
||||||
|
insert_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
check:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
columns:
|
||||||
|
- completed
|
||||||
|
- deleted
|
||||||
|
- priority
|
||||||
|
- assigned_to
|
||||||
|
- created_by
|
||||||
|
- description
|
||||||
|
- title
|
||||||
|
- completed_at
|
||||||
|
- created_at
|
||||||
|
- deleted_at
|
||||||
|
- due_date
|
||||||
|
- remind_at
|
||||||
|
- updated_at
|
||||||
|
- billid
|
||||||
|
- bodyshopid
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
- joblineid
|
||||||
|
- partsorderid
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- completed
|
||||||
|
- deleted
|
||||||
|
- priority
|
||||||
|
- assigned_to
|
||||||
|
- created_by
|
||||||
|
- description
|
||||||
|
- title
|
||||||
|
- completed_at
|
||||||
|
- created_at
|
||||||
|
- deleted_at
|
||||||
|
- due_date
|
||||||
|
- remind_at
|
||||||
|
- updated_at
|
||||||
|
- billid
|
||||||
|
- bodyshopid
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
- joblineid
|
||||||
|
- partsorderid
|
||||||
|
filter:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
update_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- completed
|
||||||
|
- deleted
|
||||||
|
- priority
|
||||||
|
- assigned_to
|
||||||
|
- created_by
|
||||||
|
- description
|
||||||
|
- title
|
||||||
|
- completed_at
|
||||||
|
- created_at
|
||||||
|
- deleted_at
|
||||||
|
- due_date
|
||||||
|
- remind_at
|
||||||
|
- updated_at
|
||||||
|
- billid
|
||||||
|
- bodyshopid
|
||||||
|
- id
|
||||||
|
- jobid
|
||||||
|
- joblineid
|
||||||
|
- partsorderid
|
||||||
|
filter:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
|
check: null
|
||||||
- table:
|
- table:
|
||||||
name: timetickets
|
name: timetickets
|
||||||
schema: public
|
schema: public
|
||||||
@@ -6006,6 +6177,13 @@
|
|||||||
table:
|
table:
|
||||||
name: exportlog
|
name: exportlog
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: ioevents
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: useremail
|
||||||
|
table:
|
||||||
|
name: ioevents
|
||||||
|
schema: public
|
||||||
- name: messages
|
- name: messages
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
@@ -6034,6 +6212,20 @@
|
|||||||
table:
|
table:
|
||||||
name: parts_orders
|
name: parts_orders
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: tasks
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: assigned_to
|
||||||
|
table:
|
||||||
|
name: tasks
|
||||||
|
schema: public
|
||||||
|
- name: tasksByCreatedBy
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: created_by
|
||||||
|
table:
|
||||||
|
name: tasks
|
||||||
|
schema: public
|
||||||
- name: timetickets
|
- name: timetickets
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on:
|
foreign_key_constraint_on:
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP TABLE "public"."tasks";
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
CREATE TABLE "public"."tasks" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "title" text NOT NULL, "description" Text, "deleted" boolean NOT NULL DEFAULT false, "deleted_at" timestamptz, "due_date" timestamptz, "created_by" text NOT NULL, "assigned_to" Text, "completed" boolean NOT NULL DEFAULT false, "completed_at" timestamptz, "remind_at" timestamptz, "priority" numeric, "bodyshopid" UUID NOT NULL, "jobid" UUID NOT NULL, "joblineid" UUID, "partsorderid" UUID, "billid" UUID, PRIMARY KEY ("id") , FOREIGN KEY ("created_by") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("assigned_to") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("joblineid") REFERENCES "public"."joblines"("id") ON UPDATE set null ON DELETE set null, FOREIGN KEY ("partsorderid") REFERENCES "public"."parts_orders"("id") ON UPDATE set null ON DELETE set null, FOREIGN KEY ("billid") REFERENCES "public"."bills"("id") ON UPDATE set null ON DELETE set null);
|
||||||
|
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
||||||
|
RETURNS TRIGGER AS $$
|
||||||
|
DECLARE
|
||||||
|
_new record;
|
||||||
|
BEGIN
|
||||||
|
_new := NEW;
|
||||||
|
_new."updated_at" = NOW();
|
||||||
|
RETURN _new;
|
||||||
|
END;
|
||||||
|
$$ LANGUAGE plpgsql;
|
||||||
|
CREATE TRIGGER "set_public_tasks_updated_at"
|
||||||
|
BEFORE UPDATE ON "public"."tasks"
|
||||||
|
FOR EACH ROW
|
||||||
|
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
||||||
|
COMMENT ON TRIGGER "set_public_tasks_updated_at" ON "public"."tasks"
|
||||||
|
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
||||||
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||||
@@ -16,7 +16,7 @@ const CalculateAllocations =
|
|||||||
const CdkBase = require("../../web-sockets/web-socket");
|
const CdkBase = require("../../web-sockets/web-socket");
|
||||||
const moment = require("moment-timezone");
|
const moment = require("moment-timezone");
|
||||||
const Dinero = require("dinero.js");
|
const Dinero = require("dinero.js");
|
||||||
const { default: InstanceManager } = require("../../utils/instanceMgr");
|
const { default: InstanceManager } = require("../../utils/instanceMgr").default;
|
||||||
const axios = AxiosLib.create();
|
const axios = AxiosLib.create();
|
||||||
|
|
||||||
axios.interceptors.request.use((x) => {
|
axios.interceptors.request.use((x) => {
|
||||||
|
|||||||
@@ -605,9 +605,9 @@ exports.default = function ({
|
|||||||
const state_tax = Dinero(job_totals.totals.state_tax);
|
const state_tax = Dinero(job_totals.totals.state_tax);
|
||||||
const local_tax = Dinero(job_totals.totals.local_tax);
|
const local_tax = Dinero(job_totals.totals.local_tax);
|
||||||
|
|
||||||
const RulesetToUse = InstanceManager({imex:"CANADA",rome: "US"})
|
const RulesetToUse = InstanceManager({ imex: 'CANADA', rome: 'US', promanager: 'US' });
|
||||||
|
|
||||||
if(RulesetToUse = "CANADA"){
|
if(RulesetToUse === "CANADA"){
|
||||||
if (federal_tax.getAmount() > 0) {
|
if (federal_tax.getAmount() > 0) {
|
||||||
if (qbo) {
|
if (qbo) {
|
||||||
// do qbo
|
// do qbo
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const builder = require("xmlbuilder2");
|
|||||||
const QbXmlUtils = require("./qbxml-utils");
|
const QbXmlUtils = require("./qbxml-utils");
|
||||||
const moment = require("moment-timezone");
|
const moment = require("moment-timezone");
|
||||||
const logger = require('../../utils/logger');
|
const logger = require('../../utils/logger');
|
||||||
const InstanceManager = require("../../utils/instanceMgr");
|
const InstanceManager = require("../../utils/instanceMgr").default;
|
||||||
|
|
||||||
require("dotenv").config({
|
require("dotenv").config({
|
||||||
path: path.resolve(
|
path: path.resolve(
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const builder = require("xmlbuilder2");
|
|||||||
const QbXmlUtils = require("./qbxml-utils");
|
const QbXmlUtils = require("./qbxml-utils");
|
||||||
const CreateInvoiceLines = require("../qb-receivables-lines").default;
|
const CreateInvoiceLines = require("../qb-receivables-lines").default;
|
||||||
const logger = require('../../utils/logger');
|
const logger = require('../../utils/logger');
|
||||||
const InstanceManager = require('../../utils/instanceMgr');
|
const InstanceManager = require('../../utils/instanceMgr').default;
|
||||||
|
|
||||||
require("dotenv").config({
|
require("dotenv").config({
|
||||||
path: path.resolve(
|
path: path.resolve(
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const CdkBase = require("../web-sockets/web-socket");
|
|||||||
const Dinero = require("dinero.js");
|
const Dinero = require("dinero.js");
|
||||||
const _ = require("lodash");
|
const _ = require("lodash");
|
||||||
const {DiscountNotAlreadyCounted} = require("../job/job-totals");
|
const {DiscountNotAlreadyCounted} = require("../job/job-totals");
|
||||||
const InstanceManager = require('../utils/instanceMgr');
|
const InstanceManager = require('../utils/instanceMgr').default;
|
||||||
|
|
||||||
exports.default = async function (socket, jobid) {
|
exports.default = async function (socket, jobid) {
|
||||||
try {
|
try {
|
||||||
@@ -26,7 +26,11 @@ exports.default = async function (socket, jobid) {
|
|||||||
const {bodyshop} = job;
|
const {bodyshop} = job;
|
||||||
|
|
||||||
const taxAllocations =
|
const taxAllocations =
|
||||||
InstanceManager({imex: {
|
InstanceManager({
|
||||||
|
executeFunction:true,
|
||||||
|
deubg:true,
|
||||||
|
args: [],
|
||||||
|
imex: () => ({
|
||||||
local: {
|
local: {
|
||||||
center: bodyshop.md_responsibility_centers.taxes.local.name,
|
center: bodyshop.md_responsibility_centers.taxes.local.name,
|
||||||
sale: Dinero(job.job_totals.totals.local_tax),
|
sale: Dinero(job.job_totals.totals.local_tax),
|
||||||
@@ -48,7 +52,7 @@ exports.default = async function (socket, jobid) {
|
|||||||
profitCenter: bodyshop.md_responsibility_centers.taxes.federal,
|
profitCenter: bodyshop.md_responsibility_centers.taxes.federal,
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes.federal,
|
costCenter: bodyshop.md_responsibility_centers.taxes.federal,
|
||||||
},
|
},
|
||||||
}, rome:{
|
}), rome: () => ({
|
||||||
tax_ty1: {
|
tax_ty1: {
|
||||||
center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name,
|
center: bodyshop.md_responsibility_centers.taxes[`tax_ty1`].name,
|
||||||
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]),
|
sale: Dinero(job.job_totals.totals.us_sales_tax_breakdown[`ty1Tax`]),
|
||||||
@@ -84,7 +88,7 @@ exports.default = async function (socket, jobid) {
|
|||||||
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`],
|
profitCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`],
|
||||||
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`],
|
costCenter: bodyshop.md_responsibility_centers.taxes[`tax_ty5`],
|
||||||
},
|
},
|
||||||
} })
|
}) })
|
||||||
|
|
||||||
|
|
||||||
//Determine if there are MAPA and MASH lines already on the estimate.
|
//Determine if there are MAPA and MASH lines already on the estimate.
|
||||||
@@ -439,6 +443,7 @@ if(InstanceManager({rome:true})){
|
|||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
CdkBase.createLogEvent(
|
CdkBase.createLogEvent(
|
||||||
socket,
|
socket,
|
||||||
"ERROR",
|
"ERROR",
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const CdkBase = require("../web-sockets/web-socket");
|
|||||||
const CdkWsdl = require("./cdk-wsdl").default;
|
const CdkWsdl = require("./cdk-wsdl").default;
|
||||||
const {CDK_CREDENTIALS, CheckCdkResponseForError} = require("./cdk-wsdl");
|
const {CDK_CREDENTIALS, CheckCdkResponseForError} = require("./cdk-wsdl");
|
||||||
const CalcualteAllocations = require("./cdk-calculate-allocations").default;
|
const CalcualteAllocations = require("./cdk-calculate-allocations").default;
|
||||||
|
const InstanceMgr = require("../utils/instanceMgr").default;
|
||||||
|
|
||||||
const moment = require("moment-timezone");
|
const moment = require("moment-timezone");
|
||||||
|
|
||||||
@@ -599,12 +600,11 @@ async function InsertDmsCustomer(socket, newCustomerNumber) {
|
|||||||
country:
|
country:
|
||||||
socket.JobData.ownr_ctry &&
|
socket.JobData.ownr_ctry &&
|
||||||
socket.JobData.ownr_ctry.replace(replaceSpecialRegex, ""),
|
socket.JobData.ownr_ctry.replace(replaceSpecialRegex, ""),
|
||||||
postalCode:
|
postalCode: InstanceMgr({imex: socket.JobData.ownr_zip &&
|
||||||
socket.JobData.ownr_zip &&
|
socket.JobData.ownr_zip //TODO Need to remove for US Based customers.
|
||||||
socket.JobData.ownr_zip //TODO Need to remove for US Based customers.
|
.toUpperCase()
|
||||||
.toUpperCase()
|
.replace(/\W/g, "")
|
||||||
.replace(/\W/g, "")
|
.replace(/(...)/, "$1 "), rome: socket.JobData.ownr_zip }),
|
||||||
.replace(/(...)/, "$1 "),
|
|
||||||
stateOrProvince:
|
stateOrProvince:
|
||||||
socket.JobData.ownr_st &&
|
socket.JobData.ownr_st &&
|
||||||
socket.JobData.ownr_st.replace(replaceSpecialRegex, ""),
|
socket.JobData.ownr_st.replace(replaceSpecialRegex, ""),
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const queries = require("../graphql-client/queries");
|
|||||||
const {phone} = require("phone");
|
const {phone} = require("phone");
|
||||||
const {admin} = require("../firebase/firebase-handler");
|
const {admin} = require("../firebase/firebase-handler");
|
||||||
const logger = require("../utils/logger");
|
const logger = require("../utils/logger");
|
||||||
const InstanceManager = require("../utils/instanceMgr");
|
const InstanceManager = require("../utils/instanceMgr").default;
|
||||||
|
|
||||||
exports.receive = async (req, res) => {
|
exports.receive = async (req, res) => {
|
||||||
//Perform request validation
|
//Perform request validation
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
* @property { string | object | function } imex Return this prop if Rome.
|
* @property { string | object | function } imex Return this prop if Rome.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function InstanceManager({ instance, debug, executeFunction, rome, promanager, imex }) {
|
function InstanceManager({ args, instance, debug, executeFunction, rome, promanager, imex }) {
|
||||||
let propToReturn = null;
|
let propToReturn = null;
|
||||||
|
|
||||||
switch (instance || process.env.INSTANCE) {
|
switch (instance || process.env.INSTANCE) {
|
||||||
|
|||||||
Reference in New Issue
Block a user