Compare commits
70 Commits
feature/AI
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
98bff6d8f6 | ||
|
|
7959dc67ce | ||
|
|
a4116b6c28 | ||
|
|
0d2cdec75c | ||
|
|
269ef25ece | ||
|
|
575fbd5357 | ||
|
|
2ad887fb82 | ||
|
|
40a1a86f72 | ||
|
|
95d43d936c | ||
|
|
9f56568680 | ||
|
|
3428940c72 | ||
|
|
ea604a5e64 | ||
|
|
5b76473cbc | ||
|
|
db5359e086 | ||
|
|
35046f11c2 | ||
|
|
69d8d27ad3 | ||
|
|
f4c4005a2a | ||
|
|
755acd24f0 | ||
|
|
079d6cfee6 | ||
|
|
3e3b3c269a | ||
|
|
39f1af7d4b | ||
|
|
1ea4d616d7 | ||
|
|
fdf0ecf6f6 | ||
|
|
e5f7285253 | ||
|
|
e46c304f7c | ||
|
|
1aa570db90 | ||
|
|
1c2be3c890 | ||
|
|
05e4eacf34 | ||
|
|
e1417b03f9 | ||
|
|
7b99de8046 | ||
|
|
6dc03d7f67 | ||
|
|
2a5e6a51aa | ||
|
|
885477fa68 | ||
|
|
c7db792793 | ||
|
|
31be51ef79 | ||
|
|
e4066c1570 | ||
|
|
ec480f2cb1 | ||
|
|
f5b30c9376 | ||
|
|
412508fbcf | ||
|
|
dbfd9bce54 | ||
|
|
52e0558c79 | ||
|
|
562d0b8641 | ||
|
|
d48d6cdd91 | ||
|
|
9363790541 | ||
|
|
2bceba948d | ||
|
|
168d4246af | ||
|
|
cdf6050ec2 | ||
|
|
f451155689 | ||
|
|
9f06e19346 | ||
|
|
f4be3e9668 | ||
|
|
ee613db0cb | ||
|
|
55b892a74e | ||
|
|
16754d9657 | ||
|
|
33db67122c | ||
|
|
b9b88b0e23 | ||
|
|
992ad71910 | ||
|
|
51d1f926c2 | ||
|
|
c70447f337 | ||
|
|
dc367e1a30 | ||
|
|
ee7997ffbc | ||
|
|
2dbb5adbbb | ||
|
|
d6e3c54b68 | ||
|
|
52809cc849 | ||
|
|
e78b114544 | ||
|
|
bcdd32f92f | ||
|
|
8e623c71a9 | ||
|
|
5f2a5e1025 | ||
|
|
f2af78f056 | ||
|
|
71f3dbbeb4 | ||
|
|
c9b63be29f |
@@ -1,7 +1,8 @@
|
||||
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
|
||||
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
|
||||
VITE_APP_GA_CODE=231099835
|
||||
VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
|
||||
# VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
|
||||
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
||||
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
|
||||
VITE_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test
|
||||
VITE_APP_CLOUDINARY_API_KEY=957865933348715
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
|
||||
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
|
||||
VITE_APP_GA_CODE=231099835
|
||||
VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
|
||||
# VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
|
||||
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
||||
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
|
||||
VITE_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test
|
||||
VITE_APP_CLOUDINARY_API_KEY=957865933348715
|
||||
|
||||
56
client/public/firebase-messaging-sw.js
Normal file
56
client/public/firebase-messaging-sw.js
Normal file
@@ -0,0 +1,56 @@
|
||||
// Scripts for firebase and firebase messaging
|
||||
importScripts("https://www.gstatic.com/firebasejs/8.2.0/firebase-app.js");
|
||||
importScripts("https://www.gstatic.com/firebasejs/8.2.0/firebase-messaging.js");
|
||||
|
||||
// Initialize the Firebase app in the service worker by passing the generated config
|
||||
let firebaseConfig;
|
||||
switch (this.location.hostname) {
|
||||
case "localhost":
|
||||
firebaseConfig = {
|
||||
apiKey: "AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc",
|
||||
authDomain: "imex-dev.firebaseapp.com",
|
||||
databaseURL: "https://imex-dev.firebaseio.com",
|
||||
projectId: "imex-dev",
|
||||
storageBucket: "imex-dev.appspot.com",
|
||||
messagingSenderId: "759548147434",
|
||||
appId: "1:759548147434:web:e8239868a48ceb36700993",
|
||||
measurementId: "G-K5XRBVVB4S",
|
||||
};
|
||||
break;
|
||||
case "test.imex.online":
|
||||
firebaseConfig = {
|
||||
apiKey: "AIzaSyBw7_GTy7GtQyfkIRPVrWHEGKfcqeyXw0c",
|
||||
authDomain: "imex-test.firebaseapp.com",
|
||||
projectId: "imex-test",
|
||||
storageBucket: "imex-test.appspot.com",
|
||||
messagingSenderId: "991923618608",
|
||||
appId: "1:991923618608:web:633437569cdad78299bef5",
|
||||
// measurementId: "${config.measurementId}",
|
||||
};
|
||||
break;
|
||||
case "imex.online":
|
||||
default:
|
||||
firebaseConfig = {
|
||||
apiKey: "AIzaSyDSezy-jGJreo7ulgpLdlpOwAOrgcaEkhU",
|
||||
authDomain: "imex-prod.firebaseapp.com",
|
||||
databaseURL: "https://imex-prod.firebaseio.com",
|
||||
projectId: "imex-prod",
|
||||
storageBucket: "imex-prod.appspot.com",
|
||||
messagingSenderId: "253497221485",
|
||||
appId: "1:253497221485:web:3c81c483b94db84b227a64",
|
||||
measurementId: "G-NTWBKG2L0M",
|
||||
};
|
||||
}
|
||||
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
|
||||
// Retrieve firebase messaging
|
||||
const messaging = firebase.messaging();
|
||||
|
||||
messaging.onBackgroundMessage(function (payload) {
|
||||
// Customize notification here
|
||||
const channel = new BroadcastChannel("imex-sw-messages");
|
||||
channel.postMessage(payload);
|
||||
|
||||
//self.registration.showNotification(notificationTitle, notificationOptions);
|
||||
});
|
||||
@@ -150,7 +150,7 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
|
||||
<ProductFruits
|
||||
workspaceCode={InstanceRenderMgr({
|
||||
imex: null,
|
||||
rome: null,
|
||||
rome: "9BkbEseqNqxw8jUH",
|
||||
promanager: "aoJoEifvezYI0Z0P"
|
||||
})}
|
||||
debug
|
||||
|
||||
@@ -25,31 +25,27 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps },
|
||||
);
|
||||
}}
|
||||
notFoundContent={"Removed."}
|
||||
{...restProps}
|
||||
>
|
||||
<Select.Option key={null} value={"noline"} cost={0} line_desc={""}>
|
||||
{t("billlines.labels.other")}
|
||||
</Select.Option>
|
||||
{options
|
||||
? options.map((item) => (
|
||||
<Option
|
||||
disabled={allowRemoved ? false : item.removed}
|
||||
key={item.id}
|
||||
value={item.id}
|
||||
cost={item.act_price ? item.act_price : 0}
|
||||
part_type={item.part_type}
|
||||
line_desc={item.line_desc}
|
||||
part_qty={item.part_qty}
|
||||
oem_partno={item.oem_partno}
|
||||
alt_partno={item.alt_partno}
|
||||
act_price={item.act_price}
|
||||
style={{
|
||||
...(item.removed ? { textDecoration: "line-through" } : {})
|
||||
}}
|
||||
name={`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
|
||||
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
||||
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim()}
|
||||
>
|
||||
options={[
|
||||
{ value: "noline", label: t("billlines.labels.other"), name: t("billlines.labels.other") },
|
||||
...options.map((item) => ({
|
||||
disabled: allowRemoved ? false : item.removed,
|
||||
key: item.id,
|
||||
value: item.id,
|
||||
cost: item.act_price ? item.act_price : 0,
|
||||
part_type: item.part_type,
|
||||
line_desc: item.line_desc,
|
||||
part_qty: item.part_qty,
|
||||
oem_partno: item.oem_partno,
|
||||
alt_partno: item.alt_partno,
|
||||
act_price: item.act_price,
|
||||
style: {
|
||||
...(item.removed ? { textDecoration: "line-through" } : {})
|
||||
},
|
||||
name: `${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
|
||||
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
||||
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim(),
|
||||
label: (
|
||||
<>
|
||||
<span>
|
||||
{`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
|
||||
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
||||
@@ -60,14 +56,15 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps },
|
||||
<span style={{ float: "right", paddingleft: "1rem" }}>{`${item.mod_lb_hrs} units`}</span>
|
||||
)
|
||||
})}
|
||||
|
||||
<span style={{ float: "right", paddingleft: "1rem" }}>
|
||||
{item.act_price ? `$${item.act_price && item.act_price.toFixed(2)}` : ``}
|
||||
</span>
|
||||
</Option>
|
||||
))
|
||||
: null}
|
||||
</Select>
|
||||
</>
|
||||
)
|
||||
}))
|
||||
]}
|
||||
{...restProps}
|
||||
></Select>
|
||||
);
|
||||
};
|
||||
export default forwardRef(BillLineSearchSelect);
|
||||
|
||||
@@ -3,14 +3,13 @@ import axios from "axios";
|
||||
import _ from "lodash";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { Link } from "react-router-dom";
|
||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
|
||||
|
||||
export default function GlobalSearchOs() {
|
||||
const { t } = useTranslation();
|
||||
const history = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [data, setData] = useState(false);
|
||||
|
||||
@@ -178,15 +177,7 @@ export default function GlobalSearchOs() {
|
||||
};
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
options={data}
|
||||
onSearch={handleSearch}
|
||||
defaultActiveFirstOption
|
||||
onSelect={(val, opt) => {
|
||||
history(opt.label.props.to);
|
||||
}}
|
||||
onClear={() => setData([])}
|
||||
>
|
||||
<AutoComplete options={data} onSearch={handleSearch} defaultActiveFirstOption onClear={() => setData([])}>
|
||||
<Input.Search
|
||||
size="large"
|
||||
placeholder={t("general.labels.globalsearch")}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { AutoComplete, Divider, Input, Space } from "antd";
|
||||
import _ from "lodash";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { Link } from "react-router-dom";
|
||||
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
@@ -12,7 +12,6 @@ import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.compon
|
||||
|
||||
export default function GlobalSearch() {
|
||||
const { t } = useTranslation();
|
||||
const history = useNavigate();
|
||||
const [callSearch, { loading, error, data }] = useLazyQuery(GLOBAL_SEARCH_QUERY);
|
||||
|
||||
const executeSearch = (v) => {
|
||||
@@ -157,14 +156,7 @@ export default function GlobalSearch() {
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
options={options}
|
||||
onSearch={handleSearch}
|
||||
defaultActiveFirstOption
|
||||
onSelect={(val, opt) => {
|
||||
history(opt.label.props.to);
|
||||
}}
|
||||
>
|
||||
<AutoComplete options={options} onSearch={handleSearch} defaultActiveFirstOption>
|
||||
<Input.Search
|
||||
size="large"
|
||||
placeholder={t("general.labels.globalsearch")}
|
||||
|
||||
@@ -32,6 +32,7 @@ import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { BsKanban } from "react-icons/bs";
|
||||
import { FaCalendarAlt, FaCarCrash, FaCreditCard, FaFileInvoiceDollar, FaTasks } from "react-icons/fa";
|
||||
import { FiLogOut } from "react-icons/fi";
|
||||
import { GiPayMoney, GiPlayerTime, GiSettingsKnobs } from "react-icons/gi";
|
||||
import { IoBusinessOutline } from "react-icons/io5";
|
||||
import { RiSurveyLine } from "react-icons/ri";
|
||||
@@ -42,7 +43,6 @@ import { selectRecentItems, selectSelectedHeader } from "../../redux/application
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { signOutStart } from "../../redux/user/user.actions";
|
||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { FiLogOut } from "react-icons/fi";
|
||||
import { checkBeta, handleBeta, setBeta } from "../../utils/betaHandler";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
@@ -141,11 +141,13 @@ function Header({
|
||||
accountingChildren.push(
|
||||
{
|
||||
key: "bills",
|
||||
id: "header-accounting-bills",
|
||||
icon: <Icon component={FaFileInvoiceDollar} />,
|
||||
label: <Link to="/manage/bills">{t("menus.header.bills")}</Link>
|
||||
},
|
||||
{
|
||||
key: "enterbills",
|
||||
id: "header-accounting-enterbills",
|
||||
icon: <Icon component={GiPayMoney} />,
|
||||
label: t("menus.header.enterbills"),
|
||||
onClick: () => {
|
||||
@@ -165,6 +167,7 @@ function Header({
|
||||
},
|
||||
{
|
||||
key: "inventory",
|
||||
id: "header-accounting-inventory",
|
||||
icon: <Icon component={FaFileInvoiceDollar} />,
|
||||
label: <Link to="/manage/inventory">{t("menus.header.inventory")}</Link>
|
||||
}
|
||||
@@ -183,11 +186,13 @@ function Header({
|
||||
},
|
||||
{
|
||||
key: "allpayments",
|
||||
id: "header-accounting-allpayments",
|
||||
icon: <BankFilled />,
|
||||
label: <Link to="/manage/payments">{t("menus.header.allpayments")}</Link>
|
||||
},
|
||||
{
|
||||
key: "enterpayments",
|
||||
id: "header-accounting-enterpayments",
|
||||
icon: <Icon component={FaCreditCard} />,
|
||||
label: t("menus.header.enterpayment"),
|
||||
onClick: () => {
|
||||
@@ -203,6 +208,7 @@ function Header({
|
||||
if (ImEXPay.treatment === "on") {
|
||||
accountingChildren.push({
|
||||
key: "entercardpayments",
|
||||
id: "header-accounting-entercardpayments",
|
||||
icon: <Icon component={FaCreditCard} />,
|
||||
label: t("menus.header.entercardpayment"),
|
||||
onClick: () => {
|
||||
@@ -227,6 +233,7 @@ function Header({
|
||||
},
|
||||
{
|
||||
key: "timetickets",
|
||||
id: "header-accounting-timetickets",
|
||||
icon: <FieldTimeOutlined />,
|
||||
label: <Link to="/manage/timetickets">{t("menus.header.timetickets")}</Link>
|
||||
}
|
||||
@@ -235,6 +242,7 @@ function Header({
|
||||
if (bodyshop?.md_tasks_presets?.use_approvals) {
|
||||
accountingChildren.push({
|
||||
key: "ttapprovals",
|
||||
id: "header-accounting-ttapprovals",
|
||||
icon: <FieldTimeOutlined />,
|
||||
label: <Link to="/manage/ttapprovals">{t("menus.header.ttapprovals")}</Link>
|
||||
});
|
||||
@@ -244,6 +252,7 @@ function Header({
|
||||
key: "entertimetickets",
|
||||
icon: <Icon component={GiPlayerTime} />,
|
||||
label: t("menus.header.entertimeticket"),
|
||||
id: "header-accounting-entertimetickets",
|
||||
onClick: () => {
|
||||
setTimeTicketContext({
|
||||
actions: {},
|
||||
@@ -264,6 +273,7 @@ function Header({
|
||||
const accountingExportChildren = [
|
||||
{
|
||||
key: "receivables",
|
||||
id: "header-accounting-receivables",
|
||||
label: <Link to="/manage/accounting/receivables">{t("menus.header.accounting-receivables")}</Link>
|
||||
}
|
||||
];
|
||||
@@ -271,6 +281,7 @@ function Header({
|
||||
if (!((bodyshop && bodyshop.cdk_dealerid) || (bodyshop && bodyshop.pbs_serialnumber)) || DmsAp.treatment === "on") {
|
||||
accountingExportChildren.push({
|
||||
key: "payables",
|
||||
id: "header-accounting-payables",
|
||||
label: <Link to="/manage/accounting/payables">{t("menus.header.accounting-payables")}</Link>
|
||||
});
|
||||
}
|
||||
@@ -278,6 +289,7 @@ function Header({
|
||||
if (!((bodyshop && bodyshop.cdk_dealerid) || (bodyshop && bodyshop.pbs_serialnumber))) {
|
||||
accountingExportChildren.push({
|
||||
key: "payments",
|
||||
id: "header-accounting-payments",
|
||||
label: <Link to="/manage/accounting/payments">{t("menus.header.accounting-payments")}</Link>
|
||||
});
|
||||
}
|
||||
@@ -288,6 +300,7 @@ function Header({
|
||||
},
|
||||
{
|
||||
key: "exportlogs",
|
||||
id: "header-accounting-exportlogs",
|
||||
label: <Link to="/manage/accounting/exportlogs">{t("menus.header.export-logs")}</Link>
|
||||
}
|
||||
);
|
||||
@@ -301,6 +314,7 @@ function Header({
|
||||
) {
|
||||
accountingChildren.push({
|
||||
key: "accountingexport",
|
||||
id: "header-accounting-export",
|
||||
icon: <ExportOutlined />,
|
||||
label: t("menus.header.export"),
|
||||
children: accountingExportChildren
|
||||
@@ -604,14 +618,22 @@ function Header({
|
||||
);
|
||||
}
|
||||
},
|
||||
// {
|
||||
// key: 'rescue',
|
||||
// icon: <Icon component={CarFilled}/>,
|
||||
// label: t("menus.header.rescueme"),
|
||||
// onClick: () => {
|
||||
// window.open("https://imexrescue.com/", "_blank");
|
||||
// }
|
||||
// },
|
||||
...(InstanceRenderManager({
|
||||
imex: true,
|
||||
rome: false,
|
||||
promanager: false
|
||||
})
|
||||
? [
|
||||
{
|
||||
key: "rescue",
|
||||
icon: <Icon component={CarFilled} />,
|
||||
label: t("menus.header.rescueme"),
|
||||
onClick: () => {
|
||||
window.open("https://imexrescue.com/", "_blank");
|
||||
}
|
||||
}
|
||||
]
|
||||
: []),
|
||||
|
||||
...(InstanceRenderManager({
|
||||
imex: true,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DownCircleFilled } from "@ant-design/icons";
|
||||
import { useApolloClient, useMutation } from "@apollo/client";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import { Button, Card, Dropdown, Form, Input, Modal, Popconfirm, Popover, Select, Space, notification } from "antd";
|
||||
import { Button, Card, Dropdown, Form, Input, Modal, notification, Popconfirm, Popover, Select, Space } from "antd";
|
||||
import axios from "axios";
|
||||
import parsePhoneNumber from "libphonenumber-js";
|
||||
import React, { useMemo, useState } from "react";
|
||||
@@ -641,6 +641,7 @@ export function JobsDetailHeaderActions({
|
||||
const menuItems = [
|
||||
{
|
||||
key: "schedule",
|
||||
id: "job-actions-schedule",
|
||||
disabled: !jobInPreProduction || !job.converted || jobRO,
|
||||
label: t("jobs.actions.schedule"),
|
||||
onClick: () => {
|
||||
@@ -657,6 +658,7 @@ export function JobsDetailHeaderActions({
|
||||
},
|
||||
{
|
||||
key: "cancelallappointments",
|
||||
id: "job-actions-cancelallappointments",
|
||||
onClick: () => {
|
||||
if (job.status !== bodyshop.md_ro_statuses.default_scheduled) {
|
||||
return;
|
||||
@@ -670,6 +672,7 @@ export function JobsDetailHeaderActions({
|
||||
imex: [
|
||||
{
|
||||
key: "intake",
|
||||
id: "job-actions-intake",
|
||||
disabled: !!job.intakechecklist || !jobInPreProduction || !job.converted || jobRO,
|
||||
label:
|
||||
!!job.intakechecklist || !jobInPreProduction || !job.converted || jobRO ? (
|
||||
@@ -680,6 +683,7 @@ export function JobsDetailHeaderActions({
|
||||
},
|
||||
{
|
||||
key: "deliver",
|
||||
id: "job-actions-deliver",
|
||||
disabled: !jobInProduction || jobRO,
|
||||
label: !jobInProduction ? (
|
||||
t("jobs.actions.deliver")
|
||||
@@ -689,6 +693,7 @@ export function JobsDetailHeaderActions({
|
||||
},
|
||||
{
|
||||
key: "checklist",
|
||||
id: "job-actions-checklist",
|
||||
disabled: !job.converted,
|
||||
label: <Link to={`/manage/jobs/${job.id}/checklist`}>{t("jobs.actions.viewchecklist")}</Link>
|
||||
}
|
||||
@@ -697,6 +702,7 @@ export function JobsDetailHeaderActions({
|
||||
promanager: [
|
||||
{
|
||||
key: "toggleproduction",
|
||||
id: "job-actions-toggleproduction",
|
||||
disabled: !job.converted || jobRO,
|
||||
label: <JobsDetailHeaderActionsToggleProduction job={job} refetch={refetch} />
|
||||
}
|
||||
@@ -710,6 +716,7 @@ export function JobsDetailHeaderActions({
|
||||
? [
|
||||
{
|
||||
key: "entertimetickets",
|
||||
id: "job-actions-entertimetickets",
|
||||
disabled: !job.converted || (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced),
|
||||
label: t("timetickets.actions.enter"),
|
||||
onClick: () => {
|
||||
@@ -733,6 +740,7 @@ export function JobsDetailHeaderActions({
|
||||
if (bodyshop.md_tasks_presets.enable_tasks) {
|
||||
menuItems.push({
|
||||
key: "claimtimetickettasks",
|
||||
id: "job-actions-claimtimetickettasks",
|
||||
disabled: !job.converted || (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced),
|
||||
onClick: () => {
|
||||
setTimeTicketTaskContext({
|
||||
@@ -746,6 +754,7 @@ export function JobsDetailHeaderActions({
|
||||
|
||||
menuItems.push({
|
||||
key: "enterpayments",
|
||||
id: "job-actions-enterpayments",
|
||||
disabled: !job.converted,
|
||||
label: t("menus.header.enterpayment"),
|
||||
onClick: () => {
|
||||
@@ -761,6 +770,7 @@ export function JobsDetailHeaderActions({
|
||||
if (ImEXPay.treatment === "on") {
|
||||
menuItems.push({
|
||||
key: "entercardpayments",
|
||||
id: "job-actions-entercardpayments",
|
||||
disabled: !job.converted,
|
||||
label: t("menus.header.entercardpayment"),
|
||||
onClick: () => {
|
||||
@@ -777,6 +787,7 @@ export function JobsDetailHeaderActions({
|
||||
if (HasFeatureAccess({ featureName: "courtesycars", bodyshop })) {
|
||||
menuItems.push({
|
||||
key: "cccontract",
|
||||
id: "job-actions-cccontract",
|
||||
disabled: jobRO || !job.converted,
|
||||
label: (
|
||||
<Link state={{ jobId: job.id }} to="/manage/courtesycars/contracts/new">
|
||||
@@ -788,6 +799,7 @@ export function JobsDetailHeaderActions({
|
||||
|
||||
menuItems.push({
|
||||
key: "createtask",
|
||||
id: "job-actions-createtask",
|
||||
label: t("menus.header.create_task"),
|
||||
onClick: () =>
|
||||
setTaskUpsertContext({
|
||||
@@ -800,12 +812,14 @@ export function JobsDetailHeaderActions({
|
||||
job.inproduction
|
||||
? {
|
||||
key: "removefromproduction",
|
||||
id: "job-actions-removefromproduction",
|
||||
disabled: !job.converted,
|
||||
label: t("jobs.actions.removefromproduction"),
|
||||
onClick: () => AddToProduction(client, job.id, refetch, true)
|
||||
}
|
||||
: {
|
||||
key: "addtoproduction",
|
||||
id: "job-actions-addtoproduction",
|
||||
disabled: !job.converted,
|
||||
label: t("jobs.actions.addtoproduction"),
|
||||
onClick: () => AddToProduction(client, job.id, refetch)
|
||||
@@ -815,12 +829,14 @@ export function JobsDetailHeaderActions({
|
||||
menuItems.push(
|
||||
{
|
||||
key: "togglesuspend",
|
||||
id: "job-actions-togglesuspend",
|
||||
onClick: handleSuspend,
|
||||
label: job.suspended ? t("production.actions.unsuspend") : t("production.actions.suspend")
|
||||
},
|
||||
{
|
||||
key: "toggleAlert",
|
||||
onClick: handleAlertToggle,
|
||||
id: "job-actions-togglealert",
|
||||
label:
|
||||
job.production_vars && job.production_vars.alert
|
||||
? t("production.labels.alertoff")
|
||||
@@ -832,6 +848,7 @@ export function JobsDetailHeaderActions({
|
||||
children: [
|
||||
{
|
||||
key: "duplicate",
|
||||
id: "job-actions-duplicate",
|
||||
label: (
|
||||
<Popconfirm
|
||||
title={t("jobs.labels.duplicateconfirm")}
|
||||
@@ -847,6 +864,7 @@ export function JobsDetailHeaderActions({
|
||||
},
|
||||
{
|
||||
key: "duplicatenolines",
|
||||
id: "job-actions-duplicatenolines",
|
||||
label: (
|
||||
<Popconfirm
|
||||
title={t("jobs.labels.duplicateconfirm")}
|
||||
@@ -870,6 +888,7 @@ export function JobsDetailHeaderActions({
|
||||
? [
|
||||
{
|
||||
key: "postbills",
|
||||
id: "job-actions-postbills",
|
||||
disabled: !job.converted,
|
||||
label: t("jobs.actions.postbills"),
|
||||
onClick: () => {
|
||||
@@ -888,6 +907,7 @@ export function JobsDetailHeaderActions({
|
||||
|
||||
{
|
||||
key: "addtopartsqueue",
|
||||
id: "job-actions-addtopartsqueue",
|
||||
disabled: !job.converted || !jobInProduction || jobRO,
|
||||
label: t("jobs.actions.addtopartsqueue"),
|
||||
onClick: async () => {
|
||||
@@ -913,6 +933,7 @@ export function JobsDetailHeaderActions({
|
||||
},
|
||||
{
|
||||
key: "closejob",
|
||||
id: "job-actions-closejob",
|
||||
disabled: !jobInPostProduction,
|
||||
label: !jobInPostProduction ? (
|
||||
t("menus.jobsactions.closejob")
|
||||
@@ -928,6 +949,7 @@ export function JobsDetailHeaderActions({
|
||||
},
|
||||
{
|
||||
key: "admin",
|
||||
id: "job-actions-admin",
|
||||
label: (
|
||||
<Link
|
||||
to={{
|
||||
@@ -949,6 +971,7 @@ export function JobsDetailHeaderActions({
|
||||
) {
|
||||
menuItems.push({
|
||||
key: "exportcustdata",
|
||||
id: "job-actions-exportcustdata",
|
||||
disabled: !job.converted,
|
||||
label: t("jobs.actions.exportcustdata"),
|
||||
onClick: handleExportCustData
|
||||
@@ -959,18 +982,21 @@ export function JobsDetailHeaderActions({
|
||||
const children = [
|
||||
{
|
||||
key: "email",
|
||||
id: "job-actions-email",
|
||||
disabled: !!!job.ownr_ea,
|
||||
label: t("general.labels.email"),
|
||||
onClick: handleCreateCsi
|
||||
},
|
||||
{
|
||||
key: "text",
|
||||
id: "job-actions-text",
|
||||
disabled: !!!job.ownr_ph1,
|
||||
label: t("general.labels.text"),
|
||||
onClick: handleCreateCsi
|
||||
},
|
||||
{
|
||||
key: "generate",
|
||||
id: "job-actions-generate",
|
||||
disabled: job.csiinvites && job.csiinvites.length > 0,
|
||||
label: t("jobs.actions.generatecsi"),
|
||||
onClick: handleCreateCsi
|
||||
@@ -1004,6 +1030,7 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
menuItems.push({
|
||||
key: "sendcsi",
|
||||
id: "job-actions-sendcsi",
|
||||
label: t("jobs.actions.sendcsi"),
|
||||
disabled: !job.converted,
|
||||
children
|
||||
@@ -1012,6 +1039,7 @@ export function JobsDetailHeaderActions({
|
||||
|
||||
menuItems.push({
|
||||
key: "jobcosting",
|
||||
id: "job-actions-jobcosting",
|
||||
disabled: !job.converted,
|
||||
label: t("jobs.labels.jobcosting"),
|
||||
onClick: () => {
|
||||
@@ -1029,6 +1057,7 @@ export function JobsDetailHeaderActions({
|
||||
if (job && !job.converted) {
|
||||
menuItems.push({
|
||||
key: "deletejob",
|
||||
id: "job-actions-deletejob",
|
||||
label: (
|
||||
<Popconfirm
|
||||
title={t("jobs.labels.deleteconfirm")}
|
||||
@@ -1045,6 +1074,7 @@ export function JobsDetailHeaderActions({
|
||||
|
||||
menuItems.push({
|
||||
key: "manualevent",
|
||||
id: "job-actions-manualevent",
|
||||
onClick: (e) => {
|
||||
setVisibility(true);
|
||||
},
|
||||
@@ -1054,6 +1084,7 @@ export function JobsDetailHeaderActions({
|
||||
if (!jobRO && job.converted) {
|
||||
menuItems.push({
|
||||
key: "voidjob",
|
||||
id: "job-actions-voidjob",
|
||||
label: (
|
||||
<RbacWrapper action="jobs:void" noauth>
|
||||
<Popconfirm
|
||||
|
||||
@@ -18,8 +18,6 @@ import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
import { setJoyRideSteps } from "../../redux/application/application.actions";
|
||||
import { OwnerNameDisplayFunction } from "./../owner-name-display/owner-name-display.component";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
@@ -101,7 +101,7 @@ export function PartsOrderListTableComponent({
|
||||
} else {
|
||||
const fetchData = async () => {
|
||||
const result = await billQuery({
|
||||
variables: { billid: returnfrombill },
|
||||
variables: { billid: returnfrombill }
|
||||
});
|
||||
setBillData(result.data);
|
||||
};
|
||||
@@ -203,7 +203,7 @@ export function PartsOrderListTableComponent({
|
||||
is_credit_memo: record.return,
|
||||
billlines: record.parts_order_lines.map((pol) => {
|
||||
return {
|
||||
joblineid: pol.job_line_id,
|
||||
joblineid: pol.job_line_id || "noline",
|
||||
line_desc: pol.line_desc,
|
||||
quantity: pol.quantity,
|
||||
|
||||
|
||||
@@ -30,227 +30,219 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
|
||||
return (
|
||||
<RbacWrapper action="shop:rbac">
|
||||
<LayoutFormRow>
|
||||
{HasFeatureAccess({ featureName: "export", bodyshop }) && (
|
||||
<>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.accounting.exportlog")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "accounting:exportlog"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.accounting.payables")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "accounting:payables"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.accounting.payments")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "accounting:payments"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.accounting.receivables")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "accounting:receivables"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{HasFeatureAccess({ featureName: "bills", bodyshop }) && (
|
||||
<>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.delete")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:delete"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.enter")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:enter"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.list")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:list"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.reexport")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:reexport"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.view")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:view"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{...HasFeatureAccess({ featureName: "export", bodyshop }) ? [
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.accounting.exportlog")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "accounting:exportlog"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.accounting.payables")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "accounting:payables"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.accounting.payments")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "accounting:payments"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.accounting.receivables")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "accounting:receivables"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
]:[]}
|
||||
{...HasFeatureAccess({ featureName: "bills", bodyshop }) ? [
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.delete")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:delete"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.enter")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:enter"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.list")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:list"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.reexport")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:reexport"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.bills.view")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "bills:view"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
]:[]}
|
||||
|
||||
{HasFeatureAccess({ featureName: "courtesycars", bodyshop }) && (
|
||||
<>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.contracts.create")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "contracts:create"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.contracts.detail")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "contracts:detail"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.contracts.list")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "contracts:list"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.courtesycar.create")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "courtesycar:create"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.courtesycar.detail")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "courtesycar:detail"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.courtesycar.list")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "courtesycar:list"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{HasFeatureAccess({ featureName: "csi", bodyshop }) && (
|
||||
<>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.csi.export")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "csi:export"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.csi.page")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "csi:page"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{...HasFeatureAccess({ featureName: "courtesycars", bodyshop }) ? [
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.contracts.create")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "contracts:create"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.contracts.detail")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "contracts:detail"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.contracts.list")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "contracts:list"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.courtesycar.create")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "courtesycar:create"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.courtesycar.detail")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "courtesycar:detail"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.courtesycar.list")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "courtesycar:list"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
]:[]}
|
||||
{...HasFeatureAccess({ featureName: "csi", bodyshop }) ? [
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.csi.export")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "csi:export"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.csi.page")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "csi:page"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
]:[]}
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.employees.page")}
|
||||
rules={[
|
||||
@@ -569,130 +561,128 @@ export function ShopInfoRbacComponent({ form, bodyshop }) {
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
)}
|
||||
{HasFeatureAccess({ featureName: "timetickets", bodyshop }) && (
|
||||
<>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.shiftclock.view")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "shiftclock:view"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.shop.config")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "shop:config"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.edit")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:edit"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:shiftedit"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.editcommitted")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:editcommitted"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.ttapprovals.view")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "ttapprovals:view"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.ttapprovals.approve")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "ttapprovals:approve"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.enter")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:enter"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.list")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:list"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:shiftedit"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
{...HasFeatureAccess({ featureName: "timetickets", bodyshop }) ? [
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.shiftclock.view")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "shiftclock:view"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.shop.config")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "shop:config"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.edit")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:edit"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:shiftedit"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.editcommitted")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:editcommitted"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.ttapprovals.view")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "ttapprovals:view"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.ttapprovals.approve")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "ttapprovals:approve"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.enter")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:enter"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.list")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:list"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>,
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.timetickets.shiftedit")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_rbac", "timetickets:shiftedit"]}
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
]:[]}
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.rbac.shop.vendors")}
|
||||
rules={[
|
||||
|
||||
@@ -291,6 +291,7 @@ export function JobsDetailPage({
|
||||
{
|
||||
key: "general",
|
||||
icon: <Icon component={FaShieldAlt} />,
|
||||
id: "job-details-general",
|
||||
label: t("menus.jobsdetail.general"),
|
||||
forceRender: true,
|
||||
children: <JobsDetailGeneral job={job} form={form} />
|
||||
@@ -298,6 +299,7 @@ export function JobsDetailPage({
|
||||
{
|
||||
key: "repairdata",
|
||||
icon: <BarsOutlined />,
|
||||
id: "job-details-repairdata",
|
||||
label: t("menus.jobsdetail.repairdata"),
|
||||
forceRender: true,
|
||||
children: <JobsLinesContainer job={job} joblines={job.joblines} refetch={refetch} form={form} />
|
||||
@@ -305,18 +307,21 @@ export function JobsDetailPage({
|
||||
{
|
||||
key: "rates",
|
||||
icon: <DollarCircleOutlined />,
|
||||
id: "job-details-rates",
|
||||
label: t("menus.jobsdetail.rates"),
|
||||
forceRender: true,
|
||||
children: <JobsDetailRates job={job} form={form} />
|
||||
},
|
||||
{
|
||||
key: "totals",
|
||||
id: "job-details-totals",
|
||||
icon: <DollarCircleOutlined />,
|
||||
label: t("menus.jobsdetail.totals"),
|
||||
children: <JobsDetailTotals job={job} refetch={refetch} />
|
||||
},
|
||||
{
|
||||
key: "partssublet",
|
||||
id: "job-details-partssublet",
|
||||
icon: <ToolFilled />,
|
||||
label: HasFeatureAccess({ featureName: "bills", bodyshop })
|
||||
? t("menus.jobsdetail.partssublet")
|
||||
@@ -331,6 +336,7 @@ export function JobsDetailPage({
|
||||
? [
|
||||
{
|
||||
key: "labor",
|
||||
id: "job-details-labor",
|
||||
icon: <Icon component={FaHardHat} />,
|
||||
label: t("menus.jobsdetail.labor"),
|
||||
children: <JobsDetailLaborContainer job={job} jobId={job.id} />
|
||||
@@ -340,11 +346,13 @@ export function JobsDetailPage({
|
||||
{
|
||||
key: "lifecycle",
|
||||
icon: <BarsOutlined />,
|
||||
id: "job-details-lifecycle",
|
||||
label: t("menus.jobsdetail.lifecycle"),
|
||||
children: <JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses} />
|
||||
},
|
||||
{
|
||||
key: "dates",
|
||||
id: "job-details-dates",
|
||||
icon: <CalendarFilled />,
|
||||
label: t("menus.jobsdetail.dates"),
|
||||
forceRender: true,
|
||||
@@ -358,6 +366,7 @@ export function JobsDetailPage({
|
||||
? [
|
||||
{
|
||||
key: "documents",
|
||||
id: "job-details-documents",
|
||||
icon: <FileImageFilled />,
|
||||
label: t("jobs.labels.documents"),
|
||||
children: bodyshop.uselocalmediaserver ? (
|
||||
@@ -370,6 +379,7 @@ export function JobsDetailPage({
|
||||
: []),
|
||||
{
|
||||
key: "notes",
|
||||
id: "job-details-notes",
|
||||
icon: <Icon component={FaRegStickyNote} />,
|
||||
label: t("jobs.labels.notes"),
|
||||
children: <JobNotesContainer jobId={job.id} />
|
||||
@@ -377,12 +387,14 @@ export function JobsDetailPage({
|
||||
{
|
||||
key: "audit",
|
||||
icon: <HistoryOutlined />,
|
||||
id: "job-details-audit",
|
||||
label: t("jobs.labels.audit"),
|
||||
children: <JobAuditTrail jobId={job.id} />
|
||||
},
|
||||
{
|
||||
key: "tasks",
|
||||
icon: <FaTasks />,
|
||||
id: "job-details-tasks",
|
||||
label: (
|
||||
<Space direction="horizontal">
|
||||
{t("jobs.labels.tasks")}
|
||||
|
||||
@@ -312,7 +312,14 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
|
||||
|
||||
const user = yield select((state) => state.user.currentUser);
|
||||
if (payload.features.singleDeviceOnly) {
|
||||
if (!(user.email.includes("@imex.") || user.email.includes("@rome.") || user.email.includes("@promanager.")))
|
||||
if (
|
||||
!(
|
||||
user.email.includes("@imex.") ||
|
||||
user.email.includes("@rome.") ||
|
||||
user.email.includes("@rometech.") ||
|
||||
user.email.includes("@promanager.")
|
||||
)
|
||||
)
|
||||
yield put(setInstanceId(user.uid));
|
||||
}
|
||||
|
||||
@@ -324,11 +331,17 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
|
||||
rome: () => {
|
||||
if (
|
||||
payload.imexshopid.toLowerCase().startsWith("pm_") &&
|
||||
!(user.email.includes("@imex.") || user.email.includes("@rome.") || user.email.includes("@promanager."))
|
||||
!(
|
||||
user.email.includes("@imex.") ||
|
||||
user.email.includes("@rome.") ||
|
||||
user.email.includes("@rometech.") ||
|
||||
user.email.includes("@promanager.")
|
||||
)
|
||||
) {
|
||||
throw new Error("You are not authorized to use this application.");
|
||||
}
|
||||
}
|
||||
},
|
||||
promanager: () => {}
|
||||
});
|
||||
} catch (error) {
|
||||
yield put(setInstanceConflict());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export default async function FcmHandler({ client, payload }) {
|
||||
console.log("FCM", payload);
|
||||
switch (payload.type) {
|
||||
case "messaging-inbound":
|
||||
client.cache.modify({
|
||||
|
||||
@@ -174,10 +174,7 @@ async function OpenSearchUpdateHandler(req, res) {
|
||||
const bulkOperation = [];
|
||||
slicedArray.forEach((bill) => {
|
||||
bulkOperation.push({ index: { _index: "bills", _id: bill.id } });
|
||||
bulkOperation.push({
|
||||
...omit(bill, ["job"]),
|
||||
bodyshopid: bill.job.bodyshopid
|
||||
});
|
||||
bulkOperation.push({ ...bill, bodyshopid: bill.job.bodyshopid });
|
||||
});
|
||||
promiseQueue.push(bulkOperation);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
"admin": "cd admin && npm start",
|
||||
"client": "cd client && npm start",
|
||||
"server": "nodemon server.js",
|
||||
"server:imex": "nodemon server.js imex",
|
||||
"server:rome": "nodemon server.js rome",
|
||||
"server:promanager": "nodemon server.js promanager",
|
||||
"build": "cd client && npm run build",
|
||||
"dev": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\"",
|
||||
"deva": "concurrently --kill-others-on-fail \"npm run server\" \"npm run client\" \"npm run admin\"",
|
||||
|
||||
@@ -8,9 +8,11 @@ const cookieParser = require("cookie-parser");
|
||||
const http = require("http");
|
||||
const { Server } = require("socket.io");
|
||||
|
||||
const instanceName = process.argv[2];
|
||||
|
||||
// Load environment variables
|
||||
require("dotenv").config({
|
||||
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
|
||||
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}${instanceName ? `.${instanceName}` : ''}`)
|
||||
});
|
||||
|
||||
// Import custom utilities and handlers
|
||||
|
||||
@@ -71,16 +71,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state:
|
||||
jobs_by_pk.state_tax_rate === 0
|
||||
? false
|
||||
: jobline.db_ref === "900511" ||
|
||||
jobline.db_ref === "900510" ||
|
||||
(jobline.mod_lb_hrs === 0 && //Extending IO-1375 as a part of IO-2023
|
||||
jobline.act_price > 0 &&
|
||||
jobline.lbr_op === "OP14")
|
||||
? true
|
||||
: jobline.tax_part
|
||||
state: checkStateTax(jobline, jobs_by_pk)
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -156,7 +147,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true
|
||||
state: jobs_by_pk.tax_lbr_rt === 0 ? false : true
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -224,7 +215,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true
|
||||
state: jobs_by_pk.tax_paint_mat_rt === 0 ? false : true
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -293,7 +284,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true
|
||||
state: jobs_by_pk.tax_shop_mat_rt === 0 ? false : true
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -379,7 +370,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true
|
||||
state: jobs_by_pk.tax_tow_rt === 0 ? false : true
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -439,7 +430,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true
|
||||
state: jobs_by_pk.tax_str_rt === 0 ? false : true
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -499,7 +490,7 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true
|
||||
state: jobs_by_pk.tax_lbr_rt === 0 ? false : true
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -879,6 +870,66 @@ exports.createMultiQbPayerLines = function ({ bodyshop, jobs_by_pk, qbo = false,
|
||||
return InvoiceLineAdd;
|
||||
};
|
||||
|
||||
function checkStateTax(jobline, jobs_by_pk) {
|
||||
const isPaintOrShopMat = jobline.db_ref === "936008" || jobline.db_ref === "936007";
|
||||
|
||||
if (isPaintOrShopMat) {
|
||||
if (jobline.db_ref === "936008") {
|
||||
if (jobs_by_pk.tax_paint_mat_rt === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (jobline.db_ref === "936007") {
|
||||
if (jobs_by_pk.tax_shop_mat_rt === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const isAdditionalCost =
|
||||
(jobline.lbr_op === "OP13" || (jobline.db_ref && jobline.db_ref.startsWith("9360"))) && !isPaintOrShopMat;
|
||||
|
||||
if (!jobline.part_type && isAdditionalCost) {
|
||||
if (jobs_by_pk.tax_lbr_rt === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
jobline.db_ref === "900511" ||
|
||||
jobline.db_ref === "900510" ||
|
||||
(jobline.mod_lb_hrs === 0 && jobline.act_price > 0 && jobline.lbr_op === "OP14")
|
||||
)
|
||||
return true; //Extending IO-1375 as a part of IO-2023
|
||||
|
||||
if (jobline.tax_part === false) {
|
||||
return false;
|
||||
} else {
|
||||
if (jobline.part_type) {
|
||||
if (
|
||||
jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_in === false ||
|
||||
jobs_by_pk.parts_tax_rates[`${jobline.part_type.toUpperCase()}`].prt_tax_rt === 0
|
||||
) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (jobs_by_pk.tax_lbr_rt === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CheckQBOUSATaxID({ jobline, job, type }) {
|
||||
//Replacing this to be all non-taxable items with the refactor of parts tax rates.
|
||||
return "NON";
|
||||
|
||||
@@ -206,8 +206,13 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
||||
adjustment_bottom_line
|
||||
state_tax_rate
|
||||
qb_multiple_payers
|
||||
parts_tax_rates
|
||||
tax_paint_mat_rt
|
||||
tax_lbr_rt
|
||||
tax_shop_mat_rt
|
||||
tax_sub_rt
|
||||
tax_tow_rt
|
||||
tax_str_rt
|
||||
owner {
|
||||
accountingid
|
||||
}
|
||||
@@ -1534,6 +1539,7 @@ exports.QUERY_JOB_COSTING_DETAILS = ` query QUERY_JOB_COSTING_DETAILS($id: uuid!
|
||||
op_code_desc
|
||||
profitcenter_part
|
||||
profitcenter_labor
|
||||
act_price_before_ppc
|
||||
}
|
||||
bills {
|
||||
id
|
||||
|
||||
@@ -6,6 +6,7 @@ const qs = require("query-string");
|
||||
const axios = require("axios");
|
||||
const moment = require("moment");
|
||||
const logger = require("../utils/logger");
|
||||
const InstanceManager = require("../utils/instanceMgr").default;
|
||||
|
||||
require("dotenv").config({
|
||||
path: path.resolve(process.cwd(), `.env.${process.env.NODE_ENV || "development"}`)
|
||||
@@ -16,7 +17,10 @@ const domain = process.env.NODE_ENV ? "secure" : "test";
|
||||
const { SecretsManagerClient, GetSecretValueCommand } = require("@aws-sdk/client-secrets-manager");
|
||||
|
||||
const client = new SecretsManagerClient({
|
||||
region: "ca-central-1" //TODO-AIO: instance manager required when merged to master-AIO
|
||||
region: InstanceManager({
|
||||
imex: "ca-central-1",
|
||||
rome: "us-east-2"
|
||||
})
|
||||
});
|
||||
|
||||
const gqlClient = require("../graphql-client/graphql-client").client;
|
||||
@@ -145,19 +149,19 @@ exports.generate_payment_url = async (req, res) => {
|
||||
};
|
||||
|
||||
exports.postback = async (req, res) => {
|
||||
logger.log("intellipay-postback", "DEBUG", req.user?.email, null, req.body);
|
||||
const { body: values } = req;
|
||||
|
||||
const comment = Buffer.from(values?.comment, "base64").toString();
|
||||
|
||||
if ((!values.invoice || values.invoice === "") && !comment) {
|
||||
//invoice is specified through the pay link. Comment by IO.
|
||||
logger.log("intellipay-postback-ignored", "DEBUG", req.user?.email, null, req.body);
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
logger.log("intellipay-postback", "DEBUG", req.user?.email, null, req.body);
|
||||
const { body: values } = req;
|
||||
|
||||
const comment = Buffer.from(values?.comment, "base64").toString();
|
||||
|
||||
if ((!values.invoice || values.invoice === "") && !comment) {
|
||||
//invoice is specified through the pay link. Comment by IO.
|
||||
logger.log("intellipay-postback-ignored", "DEBUG", req.user?.email, null, req.body);
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
}
|
||||
|
||||
if (values.invoice) {
|
||||
//This is a link email that's been sent out.
|
||||
const job = await gqlClient.request(queries.GET_JOB_BY_PK, {
|
||||
|
||||
@@ -269,7 +269,7 @@ function GenerateCostingData(job) {
|
||||
job &&
|
||||
job.joblines.reduce(
|
||||
(acc, val) => {
|
||||
//Parts Lines
|
||||
//Shop or Paint Material Flags
|
||||
if (val.db_ref === "936008") {
|
||||
//If either of these DB REFs change, they also need to change in job-totals/job-costing calculations.
|
||||
hasMapaLine = true;
|
||||
@@ -277,6 +277,8 @@ function GenerateCostingData(job) {
|
||||
if (val.db_ref === "936007") {
|
||||
hasMashLine = true;
|
||||
}
|
||||
|
||||
//Labor Profit Center
|
||||
if (val.mod_lbr_ty) {
|
||||
const laborProfitCenter = val.profitcenter_labor || defaultProfits[val.mod_lbr_ty] || "Unknown";
|
||||
|
||||
@@ -307,6 +309,7 @@ function GenerateCostingData(job) {
|
||||
}
|
||||
}
|
||||
|
||||
// Part Profit Center
|
||||
if (val.part_type && val.part_type !== "PAE" && val.part_type !== "PAS" && val.part_type !== "PASL") {
|
||||
const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
|
||||
|
||||
@@ -315,7 +318,7 @@ function GenerateCostingData(job) {
|
||||
if (!partsProfitCenter)
|
||||
console.log("Unknown cost/profit center mapping for parts.", val.line_desc, val.part_type);
|
||||
const partsAmount = Dinero({
|
||||
amount: Math.round((val.act_price || 0) * 100)
|
||||
amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) : Math.round(val.act_price * 100)
|
||||
})
|
||||
.multiply(val.part_qty || 1)
|
||||
.add(
|
||||
@@ -324,7 +327,7 @@ function GenerateCostingData(job) {
|
||||
? val.prt_dsmk_m
|
||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(val.act_price * 100)
|
||||
amount: val.act_price_before_ppc ? Math.round(val.act_price_before_ppc * 100) : Math.round(val.act_price * 100)
|
||||
})
|
||||
.multiply(val.part_qty || 0)
|
||||
.percentage(Math.abs(val.prt_dsmk_p || 0))
|
||||
@@ -334,6 +337,8 @@ function GenerateCostingData(job) {
|
||||
if (!acc.parts[partsProfitCenter]) acc.parts[partsProfitCenter] = Dinero();
|
||||
acc.parts[partsProfitCenter] = acc.parts[partsProfitCenter].add(partsAmount);
|
||||
}
|
||||
|
||||
//Sublet Profit Center
|
||||
if (val.part_type && val.part_type !== "PAE" && (val.part_type === "PAS" || val.part_type === "PASL")) {
|
||||
const partsProfitCenter = val.profitcenter_part || defaultProfits[val.part_type] || "Unknown";
|
||||
|
||||
@@ -362,8 +367,8 @@ function GenerateCostingData(job) {
|
||||
acc.sublet[partsProfitCenter] = acc.sublet[partsProfitCenter].add(partsAmount);
|
||||
}
|
||||
|
||||
//To deal with additional costs.
|
||||
if (!val.part_type && !val.mod_lbr_ty) {
|
||||
//Additional Profit Center
|
||||
if ((!val.part_type && !val.mod_lbr_ty) || (!val.part_type && val.mod_lbr_ty)) {
|
||||
//Does it already have a defined profit center?
|
||||
//If so, use it, otherwise try to use the same from the auto-allocate logic in IO app jobs-close-auto-allocate.
|
||||
const partsProfitCenter = val.profitcenter_part || getAdditionalCostCenter(val, defaultProfits) || "Unknown";
|
||||
|
||||
@@ -718,6 +718,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
|
||||
const taxableAmounts = {
|
||||
PAA: Dinero(),
|
||||
PAE: Dinero(),
|
||||
PAN: Dinero(),
|
||||
PAL: Dinero(),
|
||||
PAR: Dinero(),
|
||||
|
||||
Reference in New Issue
Block a user