Merge remote-tracking branch 'origin/release/2024-09-27' into feature/IO-2742-redis
This commit is contained in:
@@ -226,7 +226,9 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
||||||
hasura migrate apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura migrate apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
|
sleep 5
|
||||||
hasura metadata apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura metadata apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
|
sleep 10
|
||||||
hasura metadata reload --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura metadata reload --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
- jira/notify:
|
- jira/notify:
|
||||||
environment: Test (Rome) - Hasura
|
environment: Test (Rome) - Hasura
|
||||||
@@ -313,7 +315,9 @@ jobs:
|
|||||||
command: |
|
command: |
|
||||||
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
||||||
hasura migrate apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
hasura migrate apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
||||||
|
sleep 15
|
||||||
hasura metadata apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
hasura metadata apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
||||||
|
sleep 30
|
||||||
hasura metadata reload --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
hasura metadata reload --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
||||||
- jira/notify:
|
- jira/notify:
|
||||||
environment: Test (ImEX) - Hasura
|
environment: Test (ImEX) - Hasura
|
||||||
@@ -423,7 +427,7 @@ workflows:
|
|||||||
secret: ${HASURA_PROD_SECRET}
|
secret: ${HASURA_PROD_SECRET}
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
only: master-AIO
|
||||||
- rome-api-deploy:
|
- rome-api-deploy:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
@@ -433,7 +437,7 @@ workflows:
|
|||||||
branches:
|
branches:
|
||||||
only: master-AIO
|
only: master-AIO
|
||||||
- rome-hasura-migrate:
|
- rome-hasura-migrate:
|
||||||
secret: ${HASURA_PROD_SECRET}
|
secret: ${HASURA_ROME_PROD_SECRET}
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master-AIO
|
only: master-AIO
|
||||||
|
|||||||
59
_reference/prHelper.html
Normal file
59
_reference/prHelper.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>IMEX IO Extractor</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
.output-box {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
min-height: 40px;
|
||||||
|
}
|
||||||
|
.copy-button {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>IMEX IO Extractor</h1>
|
||||||
|
<textarea id="inputText" placeholder="Paste your text here..."></textarea>
|
||||||
|
<br>
|
||||||
|
<button onclick="extractIO()">Extract</button>
|
||||||
|
|
||||||
|
<div class="output-box" id="outputBox" contenteditable="true"></div>
|
||||||
|
<button class="copy-button" onclick="copyToClipboard()">Copy to Clipboard</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function extractIO() {
|
||||||
|
const inputText = document.getElementById('inputText').value;
|
||||||
|
const ioNumbers = [...new Set(inputText.match(/IO-\d{4}/g))] // Extract unique IO-#### matches
|
||||||
|
.map(io => ({ io, num: parseInt(io.split('-')[1]) })) // Extract number part for sorting
|
||||||
|
.sort((a, b) => a.num - b.num) // Sort by the number
|
||||||
|
.map(item => item.io); // Extract sorted IO-####
|
||||||
|
|
||||||
|
document.getElementById('outputBox').innerText = ioNumbers.join(', '); // Display horizontally
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyToClipboard() {
|
||||||
|
const outputBox = document.getElementById('outputBox');
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNodeContents(outputBox);
|
||||||
|
const selection = window.getSelection();
|
||||||
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(range);
|
||||||
|
document.execCommand('copy');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,9 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
|
<meta http-equiv="Expires" content="0">
|
||||||
<% if (env.VITE_APP_INSTANCE === 'IMEX') { %>
|
<% if (env.VITE_APP_INSTANCE === 'IMEX') { %>
|
||||||
<link rel="icon" href="/favicon.png"/>
|
<link rel="icon" href="/favicon.png"/>
|
||||||
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
|
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
|
||||||
@@ -14,7 +17,7 @@
|
|||||||
<meta name="theme-color" content="#1690ff"/>
|
<meta name="theme-color" content="#1690ff"/>
|
||||||
<!-- <link rel="apple-touch-icon" href="logo192.png" /> -->
|
<!-- <link rel="apple-touch-icon" href="logo192.png" /> -->
|
||||||
<!-- TODO:AIo Update the individual logos for each.-->
|
<!-- TODO:AIo Update the individual logos for each.-->
|
||||||
<link rel="apple-touch-icon" href="public/logo192.png"/>
|
<link rel="apple-touch-icon" href="/logo192.png"/>
|
||||||
<link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF">
|
<link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF">
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
@@ -46,77 +49,23 @@
|
|||||||
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
|
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
|
||||||
<meta name="description" content="Rome Online"/>
|
<meta name="description" content="Rome Online"/>
|
||||||
<title>Rome Online</title>
|
<title>Rome Online</title>
|
||||||
|
<script type="text/javascript" id="zsiqchat">
|
||||||
<!--Use the below code snippet to provide real time updates to the live chat plugin without the need of copying and paste each time to your website when changes are made via PBX-->
|
var $zoho = $zoho || {};
|
||||||
|
$zoho.salesiq = $zoho.salesiq || {
|
||||||
<call-us-selector phonesystem-url=https://rometech.east.3cx.us:5001
|
widgetcode: "siq01bb8ac617280bdacddfeb528f07734dadc64ef3f05efef9f769c1ec171af666",
|
||||||
party="LiveChat528346"></call-us-selector>
|
values: {},
|
||||||
|
ready: function () {
|
||||||
<!--Incase you don't want real time updates to the live chat plugin when options are changed, use the below code snippet. Please note that each time you change the settings you will need to copy and paste the snippet code to your website-->
|
}
|
||||||
|
};
|
||||||
<!--<call-us
|
var d = document;
|
||||||
|
s = d.createElement("script");
|
||||||
phonesystem-url=https://rometech.east.3cx.us:5001
|
s.type = "text/javascript";
|
||||||
|
s.id = "zsiqscript";
|
||||||
style="position:fixed;font-size:16px;line-height:17px;z-index: 99999;right: 20px; bottom: 20px;"
|
s.defer = true;
|
||||||
|
s.src = "https://salesiq.zohopublic.com/widget";
|
||||||
id="wp-live-chat-by-3CX"
|
t = d.getElementsByTagName("script")[0];
|
||||||
|
t.parentNode.insertBefore(s, t);
|
||||||
minimized="true"
|
</script>
|
||||||
|
|
||||||
animation-style="noanimation"
|
|
||||||
|
|
||||||
party="LiveChat528346"
|
|
||||||
|
|
||||||
minimized-style="bubbleright"
|
|
||||||
|
|
||||||
allow-call="true"
|
|
||||||
|
|
||||||
allow-video="false"
|
|
||||||
|
|
||||||
allow-soundnotifications="true"
|
|
||||||
|
|
||||||
enable-mute="true"
|
|
||||||
|
|
||||||
enable-onmobile="true"
|
|
||||||
|
|
||||||
offline-enabled="true"
|
|
||||||
|
|
||||||
enable="true"
|
|
||||||
|
|
||||||
ignore-queueownership="false"
|
|
||||||
|
|
||||||
authentication="both"
|
|
||||||
|
|
||||||
show-operator-actual-name="true"
|
|
||||||
|
|
||||||
aknowledge-received="true"
|
|
||||||
|
|
||||||
gdpr-enabled="false"
|
|
||||||
|
|
||||||
message-userinfo-format="name"
|
|
||||||
|
|
||||||
message-dateformat="both"
|
|
||||||
|
|
||||||
lang="browser"
|
|
||||||
|
|
||||||
button-icon-type="default"
|
|
||||||
|
|
||||||
greeting-visibility="none"
|
|
||||||
|
|
||||||
greeting-offline-visibility="none"
|
|
||||||
|
|
||||||
chat-delay="2000"
|
|
||||||
|
|
||||||
enable-direct-call="true"
|
|
||||||
|
|
||||||
enable-ga="false"
|
|
||||||
|
|
||||||
></call-us>-->
|
|
||||||
|
|
||||||
<script defer src=https://downloads-global.3cx.com/downloads/livechatandtalk/v1/callus.js
|
|
||||||
id="tcx-callus-js" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
<% } %> <% if (env.VITE_APP_INSTANCE === 'PROMANAGER') { %>
|
<% } %> <% if (env.VITE_APP_INSTANCE === 'PROMANAGER') { %>
|
||||||
<title>ProManager</title>
|
<title>ProManager</title>
|
||||||
|
|||||||
1
client/package-lock.json
generated
1
client/package-lock.json
generated
@@ -7,6 +7,7 @@
|
|||||||
"": {
|
"": {
|
||||||
"name": "bodyshop",
|
"name": "bodyshop",
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/pro-layout": "^7.20.0",
|
"@ant-design/pro-layout": "^7.20.0",
|
||||||
"@apollo/client": "^3.11.8",
|
"@apollo/client": "^3.11.8",
|
||||||
|
|||||||
@@ -84,6 +84,7 @@
|
|||||||
"web-vitals": "^3.5.2"
|
"web-vitals": "^3.5.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"postinstall": "echo 'when updating react-big-calendar, remember to check to localizer in the calendar wrapper'",
|
||||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
"build": "dotenvx run --env-file=.env.development.imex -- vite build",
|
"build": "dotenvx run --env-file=.env.development.imex -- vite build",
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ export function BillDetailEditcontainer({ setPartsOrderContext, insertAuditTrail
|
|||||||
});
|
});
|
||||||
|
|
||||||
billlines.forEach((billline) => {
|
billlines.forEach((billline) => {
|
||||||
const { deductedfromlbr, inventories, jobline, ...il } = billline;
|
const { deductedfromlbr, inventories, jobline, original_actual_price, create_ppc, ...il } = billline;
|
||||||
delete il.__typename;
|
delete il.__typename;
|
||||||
|
|
||||||
if (il.id) {
|
if (il.id) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { DeleteFilled } from "@ant-design/icons";
|
import { DeleteFilled, CopyFilled } from "@ant-design/icons";
|
||||||
import { useLazyQuery, useMutation } from "@apollo/client";
|
import { useLazyQuery, useMutation } from "@apollo/client";
|
||||||
import { Button, Card, Col, Form, Input, Row, Space, Spin, Statistic, notification } from "antd";
|
import { Button, Card, Col, Form, Input, Row, Space, Spin, Statistic, message, notification } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -14,10 +14,12 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
||||||
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
||||||
|
import { getCurrentUser } from "../../firebase/firebase.utils";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
cardPaymentModal: selectCardPayment,
|
cardPaymentModal: selectCardPayment,
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop,
|
||||||
|
currentUser: getCurrentUser
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
@@ -25,11 +27,17 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment"))
|
toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment"))
|
||||||
});
|
});
|
||||||
|
|
||||||
const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisible, insertAuditTrail }) => {
|
const CardPaymentModalComponent = ({
|
||||||
|
bodyshop,
|
||||||
|
currentUser,
|
||||||
|
cardPaymentModal,
|
||||||
|
toggleModalVisible,
|
||||||
|
insertAuditTrail
|
||||||
|
}) => {
|
||||||
const { context, actions } = cardPaymentModal;
|
const { context, actions } = cardPaymentModal;
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
const [paymentLink, setPaymentLink] = useState();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
// const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
|
// const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
|
||||||
const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE);
|
const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE);
|
||||||
@@ -37,7 +45,7 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
|
|
||||||
const [, { data, refetch, queryLoading }] = useLazyQuery(QUERY_RO_AND_OWNER_BY_JOB_PKS, {
|
const [, { data, refetch, queryLoading }] = useLazyQuery(QUERY_RO_AND_OWNER_BY_JOB_PKS, {
|
||||||
variables: { jobids: [context.jobid] },
|
variables: { jobids: [context.jobid] },
|
||||||
skip: true
|
skip: !context?.jobid
|
||||||
});
|
});
|
||||||
|
|
||||||
//Initialize the intellipay window.
|
//Initialize the intellipay window.
|
||||||
@@ -51,8 +59,7 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
//2024-04-25: Nothing is going to happen here anymore. We'll completely rely on the callback.
|
//2024-04-25: Nothing is going to happen here anymore. We'll completely rely on the callback.
|
||||||
//Add a slight delay to allow the refetch to properly get the data.
|
//Add a slight delay to allow the refetch to properly get the data.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (actions && actions.refetch && typeof actions.refetch === "function")
|
if (actions && actions.refetch && typeof actions.refetch === "function") actions.refetch();
|
||||||
actions.refetch();
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
toggleModalVisible();
|
toggleModalVisible();
|
||||||
}, 750);
|
}, 750);
|
||||||
@@ -86,7 +93,6 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleIntelliPayCharge = async () => {
|
const handleIntelliPayCharge = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
//Validate
|
//Validate
|
||||||
@@ -101,7 +107,7 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
const response = await axios.post("/intellipay/lightbox_credentials", {
|
const response = await axios.post("/intellipay/lightbox_credentials", {
|
||||||
bodyshop,
|
bodyshop,
|
||||||
refresh: !!window.intellipay,
|
refresh: !!window.intellipay,
|
||||||
paymentSplitMeta: form.getFieldsValue(),
|
paymentSplitMeta: form.getFieldsValue()
|
||||||
});
|
});
|
||||||
|
|
||||||
if (window.intellipay) {
|
if (window.intellipay) {
|
||||||
@@ -126,6 +132,42 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleIntelliPayChargeShortLink = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
//Validate
|
||||||
|
try {
|
||||||
|
await form.validateFields();
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { payments } = form.getFieldsValue();
|
||||||
|
const response = await axios.post("/intellipay/generate_payment_url", {
|
||||||
|
bodyshop,
|
||||||
|
amount: payments?.reduce((acc, val) => {
|
||||||
|
return acc + (val?.amount || 0);
|
||||||
|
}, 0),
|
||||||
|
account: payments && data && data.jobs.length > 0 ? data.jobs.map((j) => j.ro_number).join(", ") : null,
|
||||||
|
comment: btoa(JSON.stringify({ payments, userEmail: currentUser.email })),
|
||||||
|
paymentSplitMeta: form.getFieldsValue()
|
||||||
|
});
|
||||||
|
if (response.data) {
|
||||||
|
setPaymentLink(response.data?.shorUrl);
|
||||||
|
navigator.clipboard.writeText(response.data?.shorUrl);
|
||||||
|
message.success(t("general.actions.copied"));
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
notification.open({
|
||||||
|
type: "error",
|
||||||
|
message: t("job_payments.notifications.error.openingip")
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card title="Card Payment">
|
<Card title="Card Payment">
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
@@ -202,16 +244,14 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
shouldUpdate={(prevValues, curValues) =>
|
shouldUpdate={(prevValues, curValues) =>
|
||||||
prevValues.payments?.map((p) => p?.jobid).join() !== curValues.payments?.map((p) => p?.jobid).join()
|
prevValues.payments?.map((p) => p?.jobid + p?.amount).join() !==
|
||||||
|
curValues.payments?.map((p) => p?.jobid + p?.amount).join()
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{() => {
|
{() => {
|
||||||
//If all of the job ids have been fileld in, then query and update the IP field.
|
//If all of the job ids have been fileld in, then query and update the IP field.
|
||||||
const { payments } = form.getFieldsValue();
|
const { payments } = form.getFieldsValue();
|
||||||
if (
|
if (payments?.length > 0 && payments?.filter((p) => p?.jobid).length === payments?.length) {
|
||||||
payments?.length > 0 &&
|
|
||||||
payments?.filter((p) => p?.jobid).length === payments?.length
|
|
||||||
) {
|
|
||||||
refetch({ jobids: payments.map((p) => p.jobid) });
|
refetch({ jobids: payments.map((p) => p.jobid) });
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@@ -246,7 +286,6 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
const totalAmountToCharge = payments?.reduce((acc, val) => {
|
const totalAmountToCharge = payments?.reduce((acc, val) => {
|
||||||
return acc + (val?.amount || 0);
|
return acc + (val?.amount || 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space style={{ float: "right" }}>
|
<Space style={{ float: "right" }}>
|
||||||
<Statistic title="Amount To Charge" value={totalAmountToCharge} precision={2} />
|
<Statistic title="Amount To Charge" value={totalAmountToCharge} precision={2} />
|
||||||
@@ -273,11 +312,36 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
>
|
>
|
||||||
{t("job_payments.buttons.proceedtopayment")}
|
{t("job_payments.buttons.proceedtopayment")}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Space direction="vertical" align="center">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
// data-ipayname="submit"
|
||||||
|
className="ipayfield"
|
||||||
|
loading={queryLoading || loading}
|
||||||
|
disabled={!(totalAmountToCharge > 0)}
|
||||||
|
onClick={handleIntelliPayChargeShortLink}
|
||||||
|
>
|
||||||
|
{t("job_payments.buttons.create_short_link")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
{paymentLink && (
|
||||||
|
<Space
|
||||||
|
style={{ cursor: "pointer", float: "right" }}
|
||||||
|
align="end"
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(paymentLink);
|
||||||
|
message.success(t("general.actions.copied"));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>{paymentLink}</div>
|
||||||
|
<CopyFilled />
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
</Spin>
|
</Spin>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -141,10 +141,14 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
|||||||
key: t("jobs.fields.ded_amt"),
|
key: t("jobs.fields.ded_amt"),
|
||||||
total: job.job_totals.totals.custPayable.deductible
|
total: job.job_totals.totals.custPayable.deductible
|
||||||
},
|
},
|
||||||
// {
|
...(InstanceRenderManager({
|
||||||
// key: t("jobs.fields.federal_tax_payable"),
|
imex: [{
|
||||||
// total: job.job_totals.totals.custPayable.federal_tax,
|
key: t("jobs.fields.federal_tax_payable"),
|
||||||
// },
|
total: job.job_totals.totals.custPayable.federal_tax
|
||||||
|
}],
|
||||||
|
rome: [],
|
||||||
|
promanager: "USE_ROME"
|
||||||
|
})),
|
||||||
{
|
{
|
||||||
key: t("jobs.fields.other_amount_payable"),
|
key: t("jobs.fields.other_amount_payable"),
|
||||||
total: job.job_totals.totals.custPayable.other_customer_amount
|
total: job.job_totals.totals.custPayable.other_customer_amount
|
||||||
|
|||||||
@@ -250,8 +250,8 @@ export function JobsList({ bodyshop }) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.labels.estimator"),
|
title: t("jobs.labels.estimator"),
|
||||||
dataIndex: "jobs.labels.estimator",
|
dataIndex: "estimator",
|
||||||
key: "jobs.labels.estimator",
|
key: "estimator",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
responsive: ["xl"],
|
responsive: ["xl"],
|
||||||
sorter: (a, b) =>
|
sorter: (a, b) =>
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ export default function PartsOrderModalPriceChange({ form, field }) {
|
|||||||
key: "25",
|
key: "25",
|
||||||
label: t("parts_orders.labels.discount", { percent: "25%" })
|
label: t("parts_orders.labels.discount", { percent: "25%" })
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "40",
|
||||||
|
label: t("parts_orders.labels.discount", { percent: "40%" })
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "custom",
|
key: "custom",
|
||||||
label: (
|
label: (
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
|
import { openChatByPhone, setMessage } from "../../redux/messaging/messaging.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop,
|
||||||
|
currentUser: selectCurrentUser
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
|
openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
|
||||||
@@ -20,7 +21,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
});
|
});
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(PaymentsGenerateLink);
|
export default connect(mapStateToProps, mapDispatchToProps)(PaymentsGenerateLink);
|
||||||
|
|
||||||
export function PaymentsGenerateLink({ bodyshop, callback, job, openChatByPhone, setMessage }) {
|
export function PaymentsGenerateLink({ bodyshop, currentUser, callback, job, openChatByPhone, setMessage }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
@@ -30,29 +31,35 @@ export function PaymentsGenerateLink({ bodyshop, callback, job, openChatByPhone,
|
|||||||
|
|
||||||
const handleFinish = async ({ amount }) => {
|
const handleFinish = async ({ amount }) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
let p;
|
||||||
const p = parsePhoneNumber(job.ownr_ph1, "CA");
|
try {
|
||||||
|
p = parsePhoneNumber(job.ownr_ph1 || "", "CA");
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Unable to parse phone number");
|
||||||
|
}
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const response = await axios.post("/intellipay/generate_payment_url", {
|
const response = await axios.post("/intellipay/generate_payment_url", {
|
||||||
bodyshop,
|
bodyshop,
|
||||||
amount: amount,
|
amount: amount,
|
||||||
account: job.ro_number,
|
account: job.ro_number,
|
||||||
invoice: job.id
|
comment: btoa(JSON.stringify({ payments: [{ jobid: job.id, amount }], userEmail: currentUser.email }))
|
||||||
});
|
});
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setPaymentLink(response.data.shorUrl);
|
setPaymentLink(response.data.shorUrl);
|
||||||
|
|
||||||
openChatByPhone({
|
if (p) {
|
||||||
phone_num: p.formatInternational(),
|
openChatByPhone({
|
||||||
jobid: job.id
|
phone_num: p.formatInternational(),
|
||||||
});
|
jobid: job.id
|
||||||
setMessage(
|
});
|
||||||
t("payments.labels.smspaymentreminder", {
|
setMessage(
|
||||||
shopname: bodyshop.shopname,
|
t("payments.labels.smspaymentreminder", {
|
||||||
amount: amount,
|
shopname: bodyshop.shopname,
|
||||||
payment_link: response.data.shorUrl
|
amount: amount,
|
||||||
})
|
payment_link: response.data.shorUrl
|
||||||
);
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
//Add in confirmation & errors.
|
//Add in confirmation & errors.
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import React, { useEffect, useMemo } from "react";
|
import React, { useEffect, useMemo, useRef } from "react";
|
||||||
import { useQuery, useSubscription } from "@apollo/client";
|
import { useQuery, useSubscription } from "@apollo/client";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { QUERY_JOBS_IN_PRODUCTION, SUBSCRIPTION_JOBS_IN_PRODUCTION } from "../../graphql/jobs.queries";
|
import {
|
||||||
|
QUERY_JOBS_IN_PRODUCTION,
|
||||||
|
SUBSCRIPTION_JOBS_IN_PRODUCTION,
|
||||||
|
SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW
|
||||||
|
} from "../../graphql/jobs.queries";
|
||||||
import { QUERY_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
import { QUERY_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||||
import ProductionBoardKanbanComponent from "./production-board-kanban.component";
|
import ProductionBoardKanbanComponent from "./production-board-kanban.component";
|
||||||
@@ -12,7 +16,9 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
currentUser: selectCurrentUser
|
currentUser: selectCurrentUser
|
||||||
});
|
});
|
||||||
|
|
||||||
function ProductionBoardKanbanContainer({ bodyshop, currentUser }) {
|
function ProductionBoardKanbanContainer({ bodyshop, currentUser, subscriptionType = "direct" }) {
|
||||||
|
const fired = useRef(false); // useRef to keep track of whether the subscription fired
|
||||||
|
|
||||||
const combinedStatuses = useMemo(
|
const combinedStatuses = useMemo(
|
||||||
() => [
|
() => [
|
||||||
...bodyshop.md_ro_statuses.production_statuses,
|
...bodyshop.md_ro_statuses.production_statuses,
|
||||||
@@ -28,9 +34,12 @@ function ProductionBoardKanbanContainer({ bodyshop, currentUser }) {
|
|||||||
onError: (error) => console.error(`Error fetching jobs in production: ${error.message}`)
|
onError: (error) => console.error(`Error fetching jobs in production: ${error.message}`)
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: updatedJobs } = useSubscription(SUBSCRIPTION_JOBS_IN_PRODUCTION, {
|
const { data: updatedJobs } = useSubscription(
|
||||||
onError: (error) => console.error(`Error subscribing to jobs in production: ${error.message}`)
|
subscriptionType === "view" ? SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW : SUBSCRIPTION_JOBS_IN_PRODUCTION,
|
||||||
});
|
{
|
||||||
|
onError: (error) => console.error(`Error subscribing to jobs in production: ${error.message}`)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const { loading: associationSettingsLoading, data: associationSettings } = useQuery(QUERY_KANBAN_SETTINGS, {
|
const { loading: associationSettingsLoading, data: associationSettings } = useQuery(QUERY_KANBAN_SETTINGS, {
|
||||||
variables: { email: currentUser.email },
|
variables: { email: currentUser.email },
|
||||||
@@ -41,10 +50,15 @@ function ProductionBoardKanbanContainer({ bodyshop, currentUser }) {
|
|||||||
// const currentReducerData = useSelector((state) => (state.trello.lanes ? state.trello : {}));
|
// const currentReducerData = useSelector((state) => (state.trello.lanes ? state.trello : {}));
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (updatedJobs && data) {
|
if (!updatedJobs) {
|
||||||
refetch().catch((err) => console.error(`Error re-fetching jobs in production: ${err.message}`));
|
return;
|
||||||
}
|
}
|
||||||
}, [updatedJobs, data, refetch]);
|
if (!fired.current) {
|
||||||
|
fired.current = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
refetch().catch((err) => console.error(`Error re-fetching jobs in production: ${err.message}`));
|
||||||
|
}, [updatedJobs, refetch]);
|
||||||
|
|
||||||
const filteredAssociationSettings = useMemo(() => {
|
const filteredAssociationSettings = useMemo(() => {
|
||||||
return associationSettings?.associations[0] || null;
|
return associationSettings?.associations[0] || null;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
border-radius: 5px 5px 0 0;
|
border-radius: 5px 5px 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.production-alert {
|
.production-alert {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
@@ -70,3 +69,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clone.is-dragging .ant-card {
|
||||||
|
border: #1890ff 2px solid !important;
|
||||||
|
border-radius: 12px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ function getFurthestAway({ pageBorderBox, draggable, candidates }) {
|
|||||||
const axis = candidate.axis;
|
const axis = candidate.axis;
|
||||||
const target = patch(
|
const target = patch(
|
||||||
candidate.axis.line,
|
candidate.axis.line,
|
||||||
// use the current center of the dragging item on the main axis
|
// use the center of the list on the main axis
|
||||||
pageBorderBox.center[axis.line],
|
candidate.page.borderBox.center[axis.line],
|
||||||
// use the center of the list on the cross axis
|
// use the center of the list on the cross axis
|
||||||
candidate.page.borderBox.center[axis.crossAxisLine]
|
candidate.page.borderBox.center[axis.crossAxisLine]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import getBodyElement from "../get-body-element";
|
|||||||
const isEqual = (base) => (value) => base === value;
|
const isEqual = (base) => (value) => base === value;
|
||||||
const isScroll = isEqual("scroll");
|
const isScroll = isEqual("scroll");
|
||||||
const isAuto = isEqual("auto");
|
const isAuto = isEqual("auto");
|
||||||
|
const isOverlay = isEqual("overlay");
|
||||||
const isVisible = isEqual("visible");
|
const isVisible = isEqual("visible");
|
||||||
const isEither = (overflow, fn) => fn(overflow.overflowX) || fn(overflow.overflowY);
|
const isEither = (overflow, fn) => fn(overflow.overflowX) || fn(overflow.overflowY);
|
||||||
const isBoth = (overflow, fn) => fn(overflow.overflowX) && fn(overflow.overflowY);
|
const isBoth = (overflow, fn) => fn(overflow.overflowX) && fn(overflow.overflowY);
|
||||||
@@ -14,7 +15,7 @@ const isElementScrollable = (el) => {
|
|||||||
overflowX: style.overflowX,
|
overflowX: style.overflowX,
|
||||||
overflowY: style.overflowY
|
overflowY: style.overflowY
|
||||||
};
|
};
|
||||||
return isEither(overflow, isScroll) || isEither(overflow, isAuto);
|
return isEither(overflow, isScroll) || isEither(overflow, isAuto) || isEither(overflow, isOverlay);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Special case for a body element
|
// Special case for a body element
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ function getSelector(contextId) {
|
|||||||
return `[${attributes.dragHandle.contextId}="${contextId}"]`;
|
return `[${attributes.dragHandle.contextId}="${contextId}"]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function findClosestDragHandleFromEvent(contextId, event) {
|
export function findClosestDragHandleFromEvent(contextId, event) {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
if (!isElement(target)) {
|
if (!isElement(target)) {
|
||||||
warning("event.target must be a Element");
|
warning("event.target must be a Element");
|
||||||
|
|||||||
@@ -240,11 +240,14 @@ export default function useTouchSensor(api) {
|
|||||||
y: clientY
|
y: clientY
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handle = api.findClosestDragHandle(event);
|
||||||
|
invariant(handle, "Touch sensor unable to find drag handle");
|
||||||
|
|
||||||
// unbind this event handler
|
// unbind this event handler
|
||||||
unbindEventsRef.current();
|
unbindEventsRef.current();
|
||||||
|
|
||||||
// eslint-disable-next-line no-use-before-define
|
// eslint-disable-next-line no-use-before-define
|
||||||
startPendingDrag(actions, point);
|
startPendingDrag(actions, point, handle);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
// not including stop or startPendingDrag as it is not defined initially
|
// not including stop or startPendingDrag as it is not defined initially
|
||||||
@@ -288,7 +291,7 @@ export default function useTouchSensor(api) {
|
|||||||
}
|
}
|
||||||
}, [stop]);
|
}, [stop]);
|
||||||
const bindCapturingEvents = useCallback(
|
const bindCapturingEvents = useCallback(
|
||||||
function bindCapturingEvents() {
|
function bindCapturingEvents(target) {
|
||||||
const options = {
|
const options = {
|
||||||
capture: true,
|
capture: true,
|
||||||
passive: false
|
passive: false
|
||||||
@@ -307,7 +310,7 @@ export default function useTouchSensor(api) {
|
|||||||
// Old behaviour:
|
// Old behaviour:
|
||||||
// https://gist.github.com/parris/dda613e3ae78f14eb2dc9fa0f4bfce3d
|
// https://gist.github.com/parris/dda613e3ae78f14eb2dc9fa0f4bfce3d
|
||||||
// https://stackoverflow.com/questions/33298828/touch-move-event-dont-fire-after-touch-start-target-is-removed
|
// https://stackoverflow.com/questions/33298828/touch-move-event-dont-fire-after-touch-start-target-is-removed
|
||||||
const unbindTarget = bindEvents(window, getHandleBindings(args), options);
|
const unbindTarget = bindEvents(target, getHandleBindings(args), options);
|
||||||
const unbindWindow = bindEvents(window, getWindowBindings(args), options);
|
const unbindWindow = bindEvents(window, getWindowBindings(args), options);
|
||||||
unbindEventsRef.current = function unbindAll() {
|
unbindEventsRef.current = function unbindAll() {
|
||||||
unbindTarget();
|
unbindTarget();
|
||||||
@@ -330,7 +333,7 @@ export default function useTouchSensor(api) {
|
|||||||
[getPhase, setPhase]
|
[getPhase, setPhase]
|
||||||
);
|
);
|
||||||
const startPendingDrag = useCallback(
|
const startPendingDrag = useCallback(
|
||||||
function startPendingDrag(actions, point) {
|
function startPendingDrag(actions, point, target) {
|
||||||
invariant(getPhase().type === "IDLE", "Expected to move from IDLE to PENDING drag");
|
invariant(getPhase().type === "IDLE", "Expected to move from IDLE to PENDING drag");
|
||||||
const longPressTimerId = setTimeout(startDragging, timeForLongPress);
|
const longPressTimerId = setTimeout(startDragging, timeForLongPress);
|
||||||
setPhase({
|
setPhase({
|
||||||
@@ -339,7 +342,7 @@ export default function useTouchSensor(api) {
|
|||||||
actions,
|
actions,
|
||||||
longPressTimerId
|
longPressTimerId
|
||||||
});
|
});
|
||||||
bindCapturingEvents();
|
bindCapturingEvents(target);
|
||||||
},
|
},
|
||||||
[bindCapturingEvents, getPhase, setPhase, startDragging]
|
[bindCapturingEvents, getPhase, setPhase, startDragging]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,7 +23,9 @@ import getBorderBoxCenterPosition from "../get-border-box-center-position";
|
|||||||
import { warning } from "../../dev-warning";
|
import { warning } from "../../dev-warning";
|
||||||
import useLayoutEffect from "../use-isomorphic-layout-effect";
|
import useLayoutEffect from "../use-isomorphic-layout-effect";
|
||||||
import { noop } from "../../empty";
|
import { noop } from "../../empty";
|
||||||
import findClosestDraggableIdFromEvent from "./find-closest-draggable-id-from-event";
|
import findClosestDraggableIdFromEvent, {
|
||||||
|
findClosestDragHandleFromEvent
|
||||||
|
} from "./find-closest-draggable-id-from-event";
|
||||||
import findDraggable from "../get-elements/find-draggable";
|
import findDraggable from "../get-elements/find-draggable";
|
||||||
import bindEvents from "../event-bindings/bind-events";
|
import bindEvents from "../event-bindings/bind-events";
|
||||||
|
|
||||||
@@ -339,6 +341,9 @@ export default function useSensorMarshal({ contextId, store, registry, customSen
|
|||||||
}),
|
}),
|
||||||
[contextId, lockAPI, registry, store]
|
[contextId, lockAPI, registry, store]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const findClosestDragHandle = useCallback((event) => findClosestDragHandleFromEvent(contextId, event), [contextId]);
|
||||||
|
|
||||||
const findClosestDraggableId = useCallback((event) => findClosestDraggableIdFromEvent(contextId, event), [contextId]);
|
const findClosestDraggableId = useCallback((event) => findClosestDraggableIdFromEvent(contextId, event), [contextId]);
|
||||||
const findOptionsForDraggable = useCallback(
|
const findOptionsForDraggable = useCallback(
|
||||||
(id) => {
|
(id) => {
|
||||||
@@ -370,9 +375,18 @@ export default function useSensorMarshal({ contextId, store, registry, customSen
|
|||||||
findClosestDraggableId,
|
findClosestDraggableId,
|
||||||
findOptionsForDraggable,
|
findOptionsForDraggable,
|
||||||
tryReleaseLock,
|
tryReleaseLock,
|
||||||
isLockClaimed
|
isLockClaimed,
|
||||||
|
findClosestDragHandle
|
||||||
}),
|
}),
|
||||||
[canGetLock, tryGetLock, findClosestDraggableId, findOptionsForDraggable, tryReleaseLock, isLockClaimed]
|
[
|
||||||
|
canGetLock,
|
||||||
|
tryGetLock,
|
||||||
|
findClosestDraggableId,
|
||||||
|
findOptionsForDraggable,
|
||||||
|
tryReleaseLock,
|
||||||
|
isLockClaimed,
|
||||||
|
findClosestDragHandle
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
// Bad ass
|
// Bad ass
|
||||||
|
|||||||
@@ -83,7 +83,13 @@ const getFinalStyles = (contextId) => {
|
|||||||
return {
|
return {
|
||||||
selector: getSelector(attributes.draggable.contextId),
|
selector: getSelector(attributes.draggable.contextId),
|
||||||
styles: {
|
styles: {
|
||||||
dragging: transition,
|
dragging: `
|
||||||
|
${transition}
|
||||||
|
user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
`,
|
||||||
dropAnimating: transition,
|
dropAnimating: transition,
|
||||||
userCancel: transition
|
userCancel: transition
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ export default function useStyleMarshal(contextId, nonce) {
|
|||||||
const remove = (ref) => {
|
const remove = (ref) => {
|
||||||
const current = ref.current;
|
const current = ref.current;
|
||||||
invariant(current, "Cannot unmount ref as it is not set");
|
invariant(current, "Cannot unmount ref as it is not set");
|
||||||
getHead().removeChild(current);
|
if (getHead().contains(current)) {
|
||||||
|
getHead().removeChild(current);
|
||||||
|
}
|
||||||
ref.current = null;
|
ref.current = null;
|
||||||
};
|
};
|
||||||
remove(alwaysRef);
|
remove(alwaysRef);
|
||||||
|
|||||||
@@ -298,6 +298,16 @@ const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatme
|
|||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
sorter: (a, b) => statusSort(a.status, b.status, activeStatuses),
|
sorter: (a, b) => statusSort(a.status, b.status, activeStatuses),
|
||||||
sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
|
filters:
|
||||||
|
activeStatuses
|
||||||
|
?.map((s) => {
|
||||||
|
return {
|
||||||
|
text: s || "No Status*",
|
||||||
|
value: [s]
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.sort((a, b) => statusSort(a.text, b.text, activeStatuses)) || [],
|
||||||
|
onFilter: (value, record) => value.includes(record.status),
|
||||||
render: (text, record) => <ProductionListColumnStatus record={record} />
|
render: (text, record) => <ProductionListColumnStatus record={record} />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -4,12 +4,13 @@ import {
|
|||||||
QUERY_EXACT_JOB_IN_PRODUCTION,
|
QUERY_EXACT_JOB_IN_PRODUCTION,
|
||||||
QUERY_EXACT_JOBS_IN_PRODUCTION,
|
QUERY_EXACT_JOBS_IN_PRODUCTION,
|
||||||
QUERY_JOBS_IN_PRODUCTION,
|
QUERY_JOBS_IN_PRODUCTION,
|
||||||
SUBSCRIPTION_JOBS_IN_PRODUCTION
|
SUBSCRIPTION_JOBS_IN_PRODUCTION,
|
||||||
|
SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW
|
||||||
} from "../../graphql/jobs.queries";
|
} from "../../graphql/jobs.queries";
|
||||||
import ProductionListTable from "./production-list-table.component";
|
import ProductionListTable from "./production-list-table.component";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
|
||||||
export default function ProductionListTableContainer() {
|
export default function ProductionListTableContainer({ subscriptionType = "direct" }) {
|
||||||
const { refetch, loading, data } = useQuery(QUERY_JOBS_IN_PRODUCTION, {
|
const { refetch, loading, data } = useQuery(QUERY_JOBS_IN_PRODUCTION, {
|
||||||
pollInterval: 3600000,
|
pollInterval: 3600000,
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -17,7 +18,9 @@ export default function ProductionListTableContainer() {
|
|||||||
});
|
});
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
const [joblist, setJoblist] = useState([]);
|
const [joblist, setJoblist] = useState([]);
|
||||||
const { data: updatedJobs } = useSubscription(SUBSCRIPTION_JOBS_IN_PRODUCTION);
|
const { data: updatedJobs } = useSubscription(
|
||||||
|
subscriptionType === "view" ? SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW : SUBSCRIPTION_JOBS_IN_PRODUCTION
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!(data && data.jobs)) return;
|
if (!(data && data.jobs)) return;
|
||||||
|
|||||||
@@ -34,28 +34,34 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
|||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [search, setSearch] = useState("");
|
const [search, setSearch] = useState("");
|
||||||
const {
|
const {
|
||||||
treatments: { Enhanced_Payroll }
|
treatments: { Enhanced_Payroll, ADPPayroll }
|
||||||
} = useSplitTreatments({
|
} = useSplitTreatments({
|
||||||
attributes: {},
|
attributes: {},
|
||||||
names: ["Enhanced_Payroll"],
|
names: ["Enhanced_Payroll", "ADPPayroll"],
|
||||||
splitKey: bodyshop.imexshopid
|
splitKey: bodyshop.imexshopid
|
||||||
});
|
});
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const Templates = TemplateList("report_center");
|
const Templates = TemplateList("report_center");
|
||||||
const ReportsList =
|
const ReportsList = Object.keys(Templates)
|
||||||
Enhanced_Payroll.treatment === "on"
|
.map((key) => Templates[key])
|
||||||
? Object.keys(Templates)
|
.filter((temp) => {
|
||||||
.map((key) => {
|
const enhancedPayrollOn = Enhanced_Payroll.treatment === "on";
|
||||||
return Templates[key];
|
const adpPayrollOn = ADPPayroll.treatment === "on";
|
||||||
})
|
|
||||||
.filter((temp) => temp.enhanced_payroll === undefined || temp.enhanced_payroll === true)
|
if (enhancedPayrollOn && adpPayrollOn) {
|
||||||
: Object.keys(Templates)
|
return temp.enhanced_payroll !== false || temp.adp_payroll !== false;
|
||||||
.map((key) => {
|
}
|
||||||
return Templates[key];
|
if (enhancedPayrollOn) {
|
||||||
})
|
return temp.enhanced_payroll !== false && temp.adp_payroll !== true;
|
||||||
.filter((temp) => temp.enhanced_payroll === undefined || temp.enhanced_payroll === false);
|
}
|
||||||
|
if (adpPayrollOn) {
|
||||||
|
return temp.adp_payroll !== false && temp.enhanced_payroll !== true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return temp.enhanced_payroll !== true && temp.adp_payroll !== true;
|
||||||
|
});
|
||||||
|
|
||||||
const { open } = reportCenterModal;
|
const { open } = reportCenterModal;
|
||||||
|
|
||||||
@@ -104,7 +110,7 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
|||||||
to: values.to,
|
to: values.to,
|
||||||
subject: Templates[values.key]?.subject
|
subject: Templates[values.key]?.subject
|
||||||
},
|
},
|
||||||
values.sendbyexcel === "excel" ? "x" : values.sendby === "email" ? "e" : "p",
|
values.sendbytext === "text" ? values.sendbytext : values.sendbyexcel === "excel" ? "x" : values.sendby === "email" ? "e" : "p",
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
@@ -291,7 +297,15 @@ export function ReportCenterModalComponent({ reportCenterModal, bodyshop }) {
|
|||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
if (reporttype !== "excel")
|
if (reporttype === "text")
|
||||||
|
return (
|
||||||
|
<Form.Item label={t("general.labels.sendby")} name="sendbytext" initialValue="text">
|
||||||
|
<Radio.Group>
|
||||||
|
<Radio value="text">{t("general.labels.text")}</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
if (reporttype !== "excel" || reporttype !== "text")
|
||||||
return (
|
return (
|
||||||
<Form.Item label={t("general.labels.sendby")} name="sendby" initialValue="print">
|
<Form.Item label={t("general.labels.sendby")} name="sendby" initialValue="print">
|
||||||
<Radio.Group>
|
<Radio.Group>
|
||||||
|
|||||||
505
client/src/components/schedule-calendar-wrapper/localizer.js
Normal file
505
client/src/components/schedule-calendar-wrapper/localizer.js
Normal file
@@ -0,0 +1,505 @@
|
|||||||
|
import isBetween from "dayjs/plugin/isBetween";
|
||||||
|
import isSameOrAfter from "dayjs/plugin/isSameOrAfter";
|
||||||
|
import isSameOrBefore from "dayjs/plugin/isSameOrBefore";
|
||||||
|
import localeData from "dayjs/plugin/localeData";
|
||||||
|
import localizedFormat from "dayjs/plugin/localizedFormat";
|
||||||
|
import minMax from "dayjs/plugin/minMax";
|
||||||
|
import utc from "dayjs/plugin/utc";
|
||||||
|
import { DateLocalizer } from "react-big-calendar";
|
||||||
|
|
||||||
|
function arrayWithHoles(arr) {
|
||||||
|
if (Array.isArray(arr)) return arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function iterableToArrayLimit(arr, i) {
|
||||||
|
if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return;
|
||||||
|
var _arr = [];
|
||||||
|
var _n = true;
|
||||||
|
var _d = false;
|
||||||
|
var _e = undefined;
|
||||||
|
try {
|
||||||
|
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
||||||
|
_arr.push(_s.value);
|
||||||
|
if (i && _arr.length === i) break;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
_d = true;
|
||||||
|
_e = err;
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (!_n && _i["return"] != null) _i["return"]();
|
||||||
|
} finally {
|
||||||
|
if (_d) throw _e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _arr;
|
||||||
|
}
|
||||||
|
|
||||||
|
function unsupportedIterableToArray(o, minLen) {
|
||||||
|
if (!o) return;
|
||||||
|
if (typeof o === "string") return arrayLikeToArray(o, minLen);
|
||||||
|
var n = Object.prototype.toString.call(o).slice(8, -1);
|
||||||
|
if (n === "Object" && o.constructor) n = o.constructor.name;
|
||||||
|
if (n === "Map" || n === "Set") return Array.from(o);
|
||||||
|
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return arrayLikeToArray(o, minLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
function arrayLikeToArray(arr, len) {
|
||||||
|
if (len == null || len > arr.length) len = arr.length;
|
||||||
|
for (var i = 0, arr2 = new Array(len); i < len; i++) {
|
||||||
|
arr2[i] = arr[i];
|
||||||
|
}
|
||||||
|
return arr2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function nonIterableRest() {
|
||||||
|
throw new TypeError(
|
||||||
|
"Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function _slicedToArray(arr, i) {
|
||||||
|
return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || unsupportedIterableToArray(arr, i) || nonIterableRest();
|
||||||
|
}
|
||||||
|
|
||||||
|
function fixUnit(unit) {
|
||||||
|
var datePart = unit ? unit.toLowerCase() : unit;
|
||||||
|
if (datePart === "FullYear") {
|
||||||
|
datePart = "year";
|
||||||
|
} else if (!datePart) {
|
||||||
|
datePart = undefined;
|
||||||
|
}
|
||||||
|
return datePart;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeRangeFormat = function timeRangeFormat(_ref3, culture, local) {
|
||||||
|
var start = _ref3.start,
|
||||||
|
end = _ref3.end;
|
||||||
|
return local.format(start, "LT", culture) + " – " + local.format(end, "LT", culture);
|
||||||
|
};
|
||||||
|
var timeRangeStartFormat = function timeRangeStartFormat(_ref4, culture, local) {
|
||||||
|
var start = _ref4.start;
|
||||||
|
return local.format(start, "LT", culture) + " – ";
|
||||||
|
};
|
||||||
|
var timeRangeEndFormat = function timeRangeEndFormat(_ref5, culture, local) {
|
||||||
|
var end = _ref5.end;
|
||||||
|
return " – " + local.format(end, "LT", culture);
|
||||||
|
};
|
||||||
|
var weekRangeFormat = function weekRangeFormat(_ref, culture, local) {
|
||||||
|
var start = _ref.start,
|
||||||
|
end = _ref.end;
|
||||||
|
return (
|
||||||
|
local.format(start, "MMMM DD", culture) +
|
||||||
|
" – " +
|
||||||
|
// updated to use this localizer 'eq()' method
|
||||||
|
local.format(end, local.eq(start, end, "month") ? "DD" : "MMMM DD", culture)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
var dateRangeFormat = function dateRangeFormat(_ref2, culture, local) {
|
||||||
|
var start = _ref2.start,
|
||||||
|
end = _ref2.end;
|
||||||
|
return local.format(start, "L", culture) + " – " + local.format(end, "L", culture);
|
||||||
|
};
|
||||||
|
|
||||||
|
var formats = {
|
||||||
|
dateFormat: "DD",
|
||||||
|
dayFormat: "DD ddd",
|
||||||
|
weekdayFormat: "ddd",
|
||||||
|
selectRangeFormat: timeRangeFormat,
|
||||||
|
eventTimeRangeFormat: timeRangeFormat,
|
||||||
|
eventTimeRangeStartFormat: timeRangeStartFormat,
|
||||||
|
eventTimeRangeEndFormat: timeRangeEndFormat,
|
||||||
|
timeGutterFormat: "LT",
|
||||||
|
monthHeaderFormat: "MMMM YYYY",
|
||||||
|
dayHeaderFormat: "dddd MMM DD",
|
||||||
|
dayRangeHeaderFormat: weekRangeFormat,
|
||||||
|
agendaHeaderFormat: dateRangeFormat,
|
||||||
|
agendaDateFormat: "ddd MMM DD",
|
||||||
|
agendaTimeFormat: "LT",
|
||||||
|
agendaTimeRangeFormat: timeRangeFormat
|
||||||
|
};
|
||||||
|
|
||||||
|
const localizer = (dayjsLib) => {
|
||||||
|
// load dayjs plugins
|
||||||
|
dayjsLib.extend(isBetween);
|
||||||
|
dayjsLib.extend(isSameOrAfter);
|
||||||
|
dayjsLib.extend(isSameOrBefore);
|
||||||
|
dayjsLib.extend(localeData);
|
||||||
|
dayjsLib.extend(localizedFormat);
|
||||||
|
dayjsLib.extend(minMax);
|
||||||
|
dayjsLib.extend(utc);
|
||||||
|
var locale = function locale(dj, c) {
|
||||||
|
return c ? dj.locale(c) : dj;
|
||||||
|
};
|
||||||
|
|
||||||
|
// if the timezone plugin is loaded,
|
||||||
|
// then use the timezone aware version
|
||||||
|
|
||||||
|
//TODO This was the issue entirely...
|
||||||
|
// var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib;
|
||||||
|
var dayjs = dayjsLib;
|
||||||
|
|
||||||
|
function getTimezoneOffset(date) {
|
||||||
|
// ensures this gets cast to timezone
|
||||||
|
return dayjs(date).toDate().getTimezoneOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDstOffset(start, end) {
|
||||||
|
var _st$tz$$x$$timezone;
|
||||||
|
// convert to dayjs, in case
|
||||||
|
var st = dayjs(start);
|
||||||
|
var ed = dayjs(end);
|
||||||
|
// if not using the dayjs timezone plugin
|
||||||
|
if (!dayjs.tz) {
|
||||||
|
return st.toDate().getTimezoneOffset() - ed.toDate().getTimezoneOffset();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* If a default timezone has been applied, then
|
||||||
|
* use this to get the proper timezone offset, otherwise default
|
||||||
|
* the timezone to the browser local
|
||||||
|
*/
|
||||||
|
var tzName =
|
||||||
|
(_st$tz$$x$$timezone = st.tz().$x.$timezone) !== null && _st$tz$$x$$timezone !== void 0
|
||||||
|
? _st$tz$$x$$timezone
|
||||||
|
: dayjsLib.tz.guess();
|
||||||
|
// invert offsets to be inline with moment.js
|
||||||
|
var startOffset = -dayjs.tz(+st, tzName).utcOffset();
|
||||||
|
var endOffset = -dayjs.tz(+ed, tzName).utcOffset();
|
||||||
|
return startOffset - endOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDayStartDstOffset(start) {
|
||||||
|
var dayStart = dayjs(start).startOf("day");
|
||||||
|
return getDstOffset(dayStart, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** BEGIN localized date arithmetic methods with dayjs ***/
|
||||||
|
function defineComparators(a, b, unit) {
|
||||||
|
var datePart = fixUnit(unit);
|
||||||
|
var dtA = datePart ? dayjs(a).startOf(datePart) : dayjs(a);
|
||||||
|
var dtB = datePart ? dayjs(b).startOf(datePart) : dayjs(b);
|
||||||
|
return [dtA, dtB, datePart];
|
||||||
|
}
|
||||||
|
|
||||||
|
function startOf() {
|
||||||
|
var date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
||||||
|
var unit = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
var datePart = fixUnit(unit);
|
||||||
|
if (datePart) {
|
||||||
|
return dayjs(date).startOf(datePart).toDate();
|
||||||
|
}
|
||||||
|
return dayjs(date).toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function endOf() {
|
||||||
|
var date = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
|
||||||
|
var unit = arguments.length > 1 ? arguments[1] : undefined;
|
||||||
|
var datePart = fixUnit(unit);
|
||||||
|
if (datePart) {
|
||||||
|
return dayjs(date).endOf(datePart).toDate();
|
||||||
|
}
|
||||||
|
return dayjs(date).toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// dayjs comparison operations *always* convert both sides to dayjs objects
|
||||||
|
// prior to running the comparisons
|
||||||
|
function eq(a, b, unit) {
|
||||||
|
var _defineComparators = defineComparators(a, b, unit),
|
||||||
|
_defineComparators2 = _slicedToArray(_defineComparators, 3),
|
||||||
|
dtA = _defineComparators2[0],
|
||||||
|
dtB = _defineComparators2[1],
|
||||||
|
datePart = _defineComparators2[2];
|
||||||
|
return dtA.isSame(dtB, datePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
function neq(a, b, unit) {
|
||||||
|
return !eq(a, b, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gt(a, b, unit) {
|
||||||
|
var _defineComparators3 = defineComparators(a, b, unit),
|
||||||
|
_defineComparators4 = _slicedToArray(_defineComparators3, 3),
|
||||||
|
dtA = _defineComparators4[0],
|
||||||
|
dtB = _defineComparators4[1],
|
||||||
|
datePart = _defineComparators4[2];
|
||||||
|
return dtA.isAfter(dtB, datePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
function lt(a, b, unit) {
|
||||||
|
var _defineComparators5 = defineComparators(a, b, unit),
|
||||||
|
_defineComparators6 = _slicedToArray(_defineComparators5, 3),
|
||||||
|
dtA = _defineComparators6[0],
|
||||||
|
dtB = _defineComparators6[1],
|
||||||
|
datePart = _defineComparators6[2];
|
||||||
|
return dtA.isBefore(dtB, datePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
function gte(a, b, unit) {
|
||||||
|
var _defineComparators7 = defineComparators(a, b, unit),
|
||||||
|
_defineComparators8 = _slicedToArray(_defineComparators7, 3),
|
||||||
|
dtA = _defineComparators8[0],
|
||||||
|
dtB = _defineComparators8[1],
|
||||||
|
datePart = _defineComparators8[2];
|
||||||
|
return dtA.isSameOrBefore(dtB, datePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
function lte(a, b, unit) {
|
||||||
|
var _defineComparators9 = defineComparators(a, b, unit),
|
||||||
|
_defineComparators10 = _slicedToArray(_defineComparators9, 3),
|
||||||
|
dtA = _defineComparators10[0],
|
||||||
|
dtB = _defineComparators10[1],
|
||||||
|
datePart = _defineComparators10[2];
|
||||||
|
return dtA.isSameOrBefore(dtB, datePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inRange(day, min, max) {
|
||||||
|
var unit = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : "day";
|
||||||
|
var datePart = fixUnit(unit);
|
||||||
|
var djDay = dayjs(day);
|
||||||
|
var djMin = dayjs(min);
|
||||||
|
var djMax = dayjs(max);
|
||||||
|
return djDay.isBetween(djMin, djMax, datePart, "[]");
|
||||||
|
}
|
||||||
|
|
||||||
|
function min(dateA, dateB) {
|
||||||
|
var dtA = dayjs(dateA);
|
||||||
|
var dtB = dayjs(dateB);
|
||||||
|
var minDt = dayjsLib.min(dtA, dtB);
|
||||||
|
return minDt.toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function max(dateA, dateB) {
|
||||||
|
var dtA = dayjs(dateA);
|
||||||
|
var dtB = dayjs(dateB);
|
||||||
|
var maxDt = dayjsLib.max(dtA, dtB);
|
||||||
|
return maxDt.toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function merge(date, time) {
|
||||||
|
if (!date && !time) return null;
|
||||||
|
var tm = dayjs(time).format("HH:mm:ss");
|
||||||
|
var dt = dayjs(date).startOf("day").format("MM/DD/YYYY");
|
||||||
|
// We do it this way to avoid issues when timezone switching
|
||||||
|
return dayjsLib("".concat(dt, " ").concat(tm), "MM/DD/YYYY HH:mm:ss").toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function add(date, adder, unit) {
|
||||||
|
var datePart = fixUnit(unit);
|
||||||
|
return dayjs(date).add(adder, datePart).toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function range(start, end) {
|
||||||
|
var unit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "day";
|
||||||
|
var datePart = fixUnit(unit);
|
||||||
|
// because the add method will put these in tz, we have to start that way
|
||||||
|
var current = dayjs(start).toDate();
|
||||||
|
var days = [];
|
||||||
|
while (lte(current, end)) {
|
||||||
|
days.push(current);
|
||||||
|
current = add(current, 1, datePart);
|
||||||
|
}
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ceil(date, unit) {
|
||||||
|
var datePart = fixUnit(unit);
|
||||||
|
var floor = startOf(date, datePart);
|
||||||
|
return eq(floor, date) ? floor : add(floor, 1, datePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
function diff(a, b) {
|
||||||
|
var unit = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : "day";
|
||||||
|
var datePart = fixUnit(unit);
|
||||||
|
// don't use 'defineComparators' here, as we don't want to mutate the values
|
||||||
|
var dtA = dayjs(a);
|
||||||
|
var dtB = dayjs(b);
|
||||||
|
return dtB.diff(dtA, datePart);
|
||||||
|
}
|
||||||
|
|
||||||
|
function minutes(date) {
|
||||||
|
var dt = dayjs(date);
|
||||||
|
return dt.minutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstOfWeek(culture) {
|
||||||
|
var data = culture ? dayjsLib.localeData(culture) : dayjsLib.localeData();
|
||||||
|
return data ? data.firstDayOfWeek() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function firstVisibleDay(date) {
|
||||||
|
return dayjs(date).startOf("month").startOf("week").toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function lastVisibleDay(date) {
|
||||||
|
return dayjs(date).endOf("month").endOf("week").toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function visibleDays(date) {
|
||||||
|
var current = firstVisibleDay(date);
|
||||||
|
var last = lastVisibleDay(date);
|
||||||
|
var days = [];
|
||||||
|
while (lte(current, last)) {
|
||||||
|
days.push(current);
|
||||||
|
current = add(current, 1, "d");
|
||||||
|
}
|
||||||
|
return days;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*** END localized date arithmetic methods with dayjs ***/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moved from TimeSlots.js, this method overrides the method of the same name
|
||||||
|
* in the localizer.js, using dayjs to construct the js Date
|
||||||
|
* @param {Date} dt - date to start with
|
||||||
|
* @param {Number} minutesFromMidnight
|
||||||
|
* @param {Number} offset
|
||||||
|
* @returns {Date}
|
||||||
|
*/
|
||||||
|
function getSlotDate(dt, minutesFromMidnight, offset) {
|
||||||
|
return dayjs(dt)
|
||||||
|
.startOf("day")
|
||||||
|
.minute(minutesFromMidnight + offset)
|
||||||
|
.toDate();
|
||||||
|
}
|
||||||
|
|
||||||
|
// dayjs will automatically handle DST differences in it's calculations
|
||||||
|
function getTotalMin(start, end) {
|
||||||
|
return diff(start, end, "minutes");
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMinutesFromMidnight(start) {
|
||||||
|
var dayStart = dayjs(start).startOf("day");
|
||||||
|
var day = dayjs(start);
|
||||||
|
return day.diff(dayStart, "minutes") + getDayStartDstOffset(start);
|
||||||
|
}
|
||||||
|
|
||||||
|
// These two are used by DateSlotMetrics
|
||||||
|
function continuesPrior(start, first) {
|
||||||
|
var djStart = dayjs(start);
|
||||||
|
var djFirst = dayjs(first);
|
||||||
|
return djStart.isBefore(djFirst, "day");
|
||||||
|
}
|
||||||
|
|
||||||
|
function continuesAfter(start, end, last) {
|
||||||
|
var djEnd = dayjs(end);
|
||||||
|
var djLast = dayjs(last);
|
||||||
|
return djEnd.isSameOrAfter(djLast, "minutes");
|
||||||
|
}
|
||||||
|
|
||||||
|
function daySpan(start, end) {
|
||||||
|
var startDay = dayjs(start);
|
||||||
|
var endDay = dayjs(end);
|
||||||
|
return endDay.diff(startDay, "day");
|
||||||
|
}
|
||||||
|
|
||||||
|
// These two are used by eventLevels
|
||||||
|
function sortEvents(_ref6) {
|
||||||
|
var _ref6$evtA = _ref6.evtA,
|
||||||
|
aStart = _ref6$evtA.start,
|
||||||
|
aEnd = _ref6$evtA.end,
|
||||||
|
aAllDay = _ref6$evtA.allDay,
|
||||||
|
_ref6$evtB = _ref6.evtB,
|
||||||
|
bStart = _ref6$evtB.start,
|
||||||
|
bEnd = _ref6$evtB.end,
|
||||||
|
bAllDay = _ref6$evtB.allDay;
|
||||||
|
var startSort = +startOf(aStart, "day") - +startOf(bStart, "day");
|
||||||
|
var durA = daySpan(aStart, aEnd);
|
||||||
|
var durB = daySpan(bStart, bEnd);
|
||||||
|
return (
|
||||||
|
startSort ||
|
||||||
|
// sort by start Day first
|
||||||
|
durB - durA ||
|
||||||
|
// events spanning multiple days go first
|
||||||
|
!!bAllDay - !!aAllDay ||
|
||||||
|
// then allDay single day events
|
||||||
|
+aStart - +bStart ||
|
||||||
|
// then sort by start time *don't need dayjs conversion here
|
||||||
|
+aEnd - +bEnd // then sort by end time *don't need dayjs conversion here either
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function inEventRange(_ref7) {
|
||||||
|
var _ref7$event = _ref7.event,
|
||||||
|
start = _ref7$event.start,
|
||||||
|
end = _ref7$event.end,
|
||||||
|
_ref7$range = _ref7.range,
|
||||||
|
rangeStart = _ref7$range.start,
|
||||||
|
rangeEnd = _ref7$range.end;
|
||||||
|
var startOfDay = dayjs(start).startOf("day");
|
||||||
|
var eEnd = dayjs(end);
|
||||||
|
var rStart = dayjs(rangeStart);
|
||||||
|
var rEnd = dayjs(rangeEnd);
|
||||||
|
var startsBeforeEnd = startOfDay.isSameOrBefore(rEnd, "day");
|
||||||
|
// when the event is zero duration we need to handle a bit differently
|
||||||
|
var sameMin = !startOfDay.isSame(eEnd, "minutes");
|
||||||
|
var endsAfterStart = sameMin ? eEnd.isAfter(rStart, "minutes") : eEnd.isSameOrAfter(rStart, "minutes");
|
||||||
|
return startsBeforeEnd && endsAfterStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSameDate(date1, date2) {
|
||||||
|
var dt = dayjs(date1);
|
||||||
|
var dt2 = dayjs(date2);
|
||||||
|
return dt.isSame(dt2, "day");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method, called once in the localizer constructor, is used by eventLevels
|
||||||
|
* 'eventSegments()' to assist in determining the 'span' of the event in the display,
|
||||||
|
* specifically when using a timezone that is greater than the browser native timezone.
|
||||||
|
* @returns number
|
||||||
|
*/
|
||||||
|
function browserTZOffset() {
|
||||||
|
/**
|
||||||
|
* Date.prototype.getTimezoneOffset horrifically flips the positive/negative from
|
||||||
|
* what you see in it's string, so we have to jump through some hoops to get a value
|
||||||
|
* we can actually compare.
|
||||||
|
*/
|
||||||
|
var dt = new Date();
|
||||||
|
var neg = /-/.test(dt.toString()) ? "-" : "";
|
||||||
|
var dtOffset = dt.getTimezoneOffset();
|
||||||
|
var comparator = Number("".concat(neg).concat(Math.abs(dtOffset)));
|
||||||
|
// dayjs correctly provides positive/negative offset, as expected
|
||||||
|
var mtOffset = dayjs().utcOffset();
|
||||||
|
return mtOffset > comparator ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DateLocalizer({
|
||||||
|
formats: formats,
|
||||||
|
firstOfWeek: firstOfWeek,
|
||||||
|
firstVisibleDay: firstVisibleDay,
|
||||||
|
lastVisibleDay: lastVisibleDay,
|
||||||
|
visibleDays: visibleDays,
|
||||||
|
format: function format(value, _format, culture) {
|
||||||
|
return locale(dayjs(value), culture).format(_format);
|
||||||
|
},
|
||||||
|
lt: lt,
|
||||||
|
lte: lte,
|
||||||
|
gt: gt,
|
||||||
|
gte: gte,
|
||||||
|
eq: eq,
|
||||||
|
neq: neq,
|
||||||
|
merge: merge,
|
||||||
|
inRange: inRange,
|
||||||
|
startOf: startOf,
|
||||||
|
endOf: endOf,
|
||||||
|
range: range,
|
||||||
|
add: add,
|
||||||
|
diff: diff,
|
||||||
|
ceil: ceil,
|
||||||
|
min: min,
|
||||||
|
max: max,
|
||||||
|
minutes: minutes,
|
||||||
|
getSlotDate: getSlotDate,
|
||||||
|
getTimezoneOffset: getTimezoneOffset,
|
||||||
|
getDstOffset: getDstOffset,
|
||||||
|
getTotalMin: getTotalMin,
|
||||||
|
getMinutesFromMidnight: getMinutesFromMidnight,
|
||||||
|
continuesPrior: continuesPrior,
|
||||||
|
continuesAfter: continuesAfter,
|
||||||
|
sortEvents: sortEvents,
|
||||||
|
inEventRange: inEventRange,
|
||||||
|
isSameDate: isSameDate,
|
||||||
|
browserTZOffset: browserTZOffset
|
||||||
|
});
|
||||||
|
};
|
||||||
|
export default localizer;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { Calendar, dayjsLocalizer } from "react-big-calendar";
|
import { Calendar } from "react-big-calendar";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
@@ -14,12 +14,13 @@ import { selectProblemJobs } from "../../redux/application/application.selectors
|
|||||||
import { Alert, Collapse, Space } from "antd";
|
import { Alert, Collapse, Space } from "antd";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
import local from "./localizer";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
problemJobs: selectProblemJobs
|
problemJobs: selectProblemJobs
|
||||||
});
|
});
|
||||||
const localizer = dayjsLocalizer(dayjs);
|
const localizer = local(dayjs);
|
||||||
|
|
||||||
export function ScheduleCalendarWrapperComponent({
|
export function ScheduleCalendarWrapperComponent({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ export const CalculateWorkingDaysThisMonth = () => dayjs().endOf("month").busine
|
|||||||
|
|
||||||
export const CalculateWorkingDaysInPeriod = (start, end) => dayjs(end).businessDiff(dayjs(start));
|
export const CalculateWorkingDaysInPeriod = (start, end) => dayjs(end).businessDiff(dayjs(start));
|
||||||
|
|
||||||
export const CalculateWorkingDaysAsOfToday = () => dayjs().businessDaysInMonth().length;
|
export const CalculateWorkingDaysAsOfToday = () => dayjs().endOf("day").businessDiff(dayjs().startOf("month"));
|
||||||
|
|
||||||
export const CalculateWorkingDaysLastMonth = () =>
|
export const CalculateWorkingDaysLastMonth = () =>
|
||||||
dayjs().subtract(1, "month").endOf("month").businessDaysInMonth().length;
|
dayjs().subtract(1, "month").endOf("month").businessDaysInMonth().length;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import ShopInfoTaskPresets from "./shop-info.task-presets.component";
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import ShopInfoRoGuard from "./shop-info.roguard.component";
|
import ShopInfoRoGuard from "./shop-info.roguard.component";
|
||||||
|
import ShopInfoIntellipay from "./shop-intellipay-config.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
@@ -135,6 +136,17 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
|
|||||||
],
|
],
|
||||||
rome: "USE_IMEX",
|
rome: "USE_IMEX",
|
||||||
promanager: []
|
promanager: []
|
||||||
|
}),
|
||||||
|
...InstanceRenderManager({
|
||||||
|
imex: [],
|
||||||
|
rome: [
|
||||||
|
{
|
||||||
|
key: "intellipay",
|
||||||
|
label: t("bodyshop.labels.intellipay"),
|
||||||
|
children: <ShopInfoIntellipay form={form} />
|
||||||
|
}
|
||||||
|
],
|
||||||
|
promanager: []
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ 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 DatePickerRanges from "../../utils/DatePickerRanges";
|
import DatePickerRanges from "../../utils/DatePickerRanges";
|
||||||
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
import FeatureWrapper, { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||||
import PhoneFormItem, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
import PhoneFormItem, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
|
||||||
import FeatureWrapper, { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
|
||||||
// TODO: Client Update, this might break
|
// TODO: Client Update, this might break
|
||||||
const timeZonesList = Intl.supportedValuesOf("timeZone");
|
const timeZonesList = Intl.supportedValuesOf("timeZone");
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -28,10 +28,10 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
treatments: { ClosingPeriod }
|
treatments: { ClosingPeriod, ADPPayroll }
|
||||||
} = useSplitTreatments({
|
} = useSplitTreatments({
|
||||||
attributes: {},
|
attributes: {},
|
||||||
names: ["ClosingPeriod"],
|
names: ["ClosingPeriod", "ADPPayroll"],
|
||||||
splitKey: bodyshop && bodyshop.imexshopid
|
splitKey: bodyshop && bodyshop.imexshopid
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -98,7 +98,6 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
|||||||
<Form.Item label={t("bodyshop.fields.email")} name="email">
|
<Form.Item label={t("bodyshop.fields.email")} name="email">
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.fields.phone")}
|
label={t("bodyshop.fields.phone")}
|
||||||
name="phone"
|
name="phone"
|
||||||
@@ -356,14 +355,22 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
|||||||
<Select mode="tags" />
|
<Select mode="tags" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{ClosingPeriod.treatment === "on" && (
|
{ClosingPeriod.treatment === "on" && (
|
||||||
<>
|
<Form.Item
|
||||||
<Form.Item
|
name={["accountingconfig", "ClosingPeriod"]}
|
||||||
name={["accountingconfig", "ClosingPeriod"]}
|
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")}
|
||||||
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")}
|
>
|
||||||
>
|
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
|
||||||
<DatePicker.RangePicker format="MM/DD/YYYY" presets={DatePickerRanges} />
|
</Form.Item>
|
||||||
</Form.Item>
|
)}
|
||||||
</>
|
{ADPPayroll.treatment === "on" && (
|
||||||
|
<Form.Item name={["accountingconfig", "companyCode"]} label={t("bodyshop.fields.companycode")}>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
{ADPPayroll.treatment === "on" && (
|
||||||
|
<Form.Item name={["accountingconfig", "batchID"]} label={t("bodyshop.fields.batchid")}>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</FeatureWrapper>
|
</FeatureWrapper>
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { Alert, Form, InputNumber, Switch } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
|
});
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ShopInfoIntellipay);
|
||||||
|
|
||||||
|
export function ShopInfoIntellipay({ bodyshop, form }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item dependencies={[["intellipay_config", "enable_cash_discount"]]}>
|
||||||
|
{() => {
|
||||||
|
const { intellipay_config } = form.getFieldsValue();
|
||||||
|
|
||||||
|
if (intellipay_config?.enable_cash_discount)
|
||||||
|
return <Alert message={t("bodyshop.labels.intellipay_cash_discount")} />;
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<LayoutFormRow noDivider>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.intellipay_config.enable_cash_discount")}
|
||||||
|
valuePropName="checked"
|
||||||
|
name={["intellipay_config", "enable_cash_discount"]}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.intellipay_config.cash_discount_percentage")}
|
||||||
|
valuePropName="checked"
|
||||||
|
dependencies={[["intellipay_config", "enable_cash_discount"]]}
|
||||||
|
name={["intellipay_config", "cash_discount_percentage"]}
|
||||||
|
rules={[
|
||||||
|
({ getFieldsValue }) => ({ required: form.getFieldValue(["intellipay_config", "enable_cash_discount"]) })
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={1} suffix='%'/>
|
||||||
|
</Form.Item>
|
||||||
|
</LayoutFormRow>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import { AlertOutlined } from "@ant-design/icons";
|
import { AlertOutlined } from "@ant-design/icons";
|
||||||
import { Alert, Button, Col, Row, Space } from "antd";
|
import { Alert, Button, Col, notification, Row, Space } from "antd";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import React, { useEffect } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectUpdateAvailable } from "../../redux/application/application.selectors";
|
import { selectUpdateAvailable } from "../../redux/application/application.selectors";
|
||||||
import { useRegisterSW } from "virtual:pwa-register/react";
|
import { useRegisterSW } from "virtual:pwa-register/react";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
import useCountDown from "../../utils/countdownHook";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
updateAvailable: selectUpdateAvailable
|
updateAvailable: selectUpdateAvailable
|
||||||
@@ -19,6 +20,15 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
|
|
||||||
export function UpdateAlert({ updateAvailable }) {
|
export function UpdateAlert({ updateAvailable }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const [timerStarted, setTimerStarted] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [
|
||||||
|
timeLeft,
|
||||||
|
{
|
||||||
|
start //pause, resume, reset
|
||||||
|
}
|
||||||
|
] = useCountDown(180000, 1000);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
offlineReady: [offlineReady],
|
offlineReady: [offlineReady],
|
||||||
needRefresh: [needRefresh],
|
needRefresh: [needRefresh],
|
||||||
@@ -40,11 +50,43 @@ export function UpdateAlert({ updateAvailable }) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ReloadNewVersion = useCallback(() => {
|
||||||
|
setLoading(true);
|
||||||
|
updateServiceWorker(true);
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.reload(true);
|
||||||
|
}, 5000);
|
||||||
|
}, [updateServiceWorker]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (import.meta.env.DEV) {
|
if (needRefresh) {
|
||||||
console.log(`SW Status => Refresh? ${needRefresh} - offlineReady? ${offlineReady}`);
|
start();
|
||||||
|
setTimerStarted(true);
|
||||||
}
|
}
|
||||||
}, [needRefresh, offlineReady]);
|
}, [start, needRefresh, offlineReady]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (needRefresh && timerStarted && timeLeft < 60000) {
|
||||||
|
notification.open({
|
||||||
|
type: "warning",
|
||||||
|
closable: false,
|
||||||
|
duration: 65000,
|
||||||
|
key: "autoupdate",
|
||||||
|
message: t("general.actions.autoupdate", {
|
||||||
|
time: (timeLeft / 1000).toFixed(0),
|
||||||
|
app: InstanceRenderManager({
|
||||||
|
imex: "$t(titles.imexonline)",
|
||||||
|
rome: "$t(titles.romeonline)",
|
||||||
|
promanager: "$t(titles.promanager)"
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
placement: "bottomRight"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (needRefresh && timerStarted && timeLeft <= 0) {
|
||||||
|
ReloadNewVersion();
|
||||||
|
}
|
||||||
|
}, [timeLeft, t, needRefresh, ReloadNewVersion, timerStarted]);
|
||||||
|
|
||||||
if (!needRefresh) return null;
|
if (!needRefresh) return null;
|
||||||
|
|
||||||
@@ -75,9 +117,10 @@ export function UpdateAlert({ updateAvailable }) {
|
|||||||
<Button onClick={() => window.open("https://imex-online.noticeable.news/", "_blank")}>
|
<Button onClick={() => window.open("https://imex-online.noticeable.news/", "_blank")}>
|
||||||
{i18n.t("general.actions.viewreleasenotes")}
|
{i18n.t("general.actions.viewreleasenotes")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="primary" onClick={() => updateServiceWorker(true)}>
|
<Button loading={loading} type="primary" onClick={() => ReloadNewVersion()}>
|
||||||
{i18n.t("general.actions.refresh")}
|
{i18n.t("general.actions.refresh")} {`(${(timeLeft / 1000).toFixed(0)} s)`}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Button onClick={() => start(300000)}>{i18n.t("general.actions.delay")}</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ 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 = ({ value, onChange, options, onSelect, disabled, preferredMake, showPhone }, ref) => {
|
const VendorSearchSelect = ({ value, onChange, options, onSelect, disabled, preferredMake, showPhone }, ref) => {
|
||||||
const [option, setOption] = useState(value);
|
const [option, setOption] = useState(value);
|
||||||
@@ -33,9 +33,25 @@ const VendorSearchSelect = ({ value, onChange, options, onSelect, disabled, pref
|
|||||||
if (!value || !options) return label;
|
if (!value || !options) return label;
|
||||||
const discount = options?.find((o) => o.id === value)?.discount;
|
const discount = options?.find((o) => o.id === value)?.discount;
|
||||||
return (
|
return (
|
||||||
<div className="imex-flex-row" style={{ width: "100%" }}>
|
<div
|
||||||
<div style={{ flex: 1 }}>{label}</div>
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
flexWrap: "nowrap",
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 0,
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</div>
|
||||||
{discount && discount !== 0 ? <Tag color="green">{`${discount * 100}%`}</Tag> : null}
|
{discount && discount !== 0 ? <Tag color="green">{`${discount * 100}%`}</Tag> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -45,36 +61,67 @@ const VendorSearchSelect = ({ value, onChange, options, onSelect, disabled, pref
|
|||||||
optionFilterProp="name"
|
optionFilterProp="name"
|
||||||
onSelect={onSelect}
|
onSelect={onSelect}
|
||||||
disabled={disabled || false}
|
disabled={disabled || false}
|
||||||
optionLabelProp={"name"}
|
optionLabelProp="name"
|
||||||
>
|
>
|
||||||
{favorites
|
{favorites &&
|
||||||
? favorites.map((o) => (
|
favorites.map((o) => (
|
||||||
<Option key={`favorite-${o.id}`} value={o.id} name={o.name} discount={o.discount}>
|
<Option key={`favorite-${o.id}`} value={o.id} name={o.name} discount={o.discount}>
|
||||||
<div className="imex-flex-row">
|
<div
|
||||||
<div style={{ flex: 1 }}>{o.name}</div>
|
style={{
|
||||||
<Space style={{ marginLeft: "1rem" }}>
|
display: "flex",
|
||||||
<HeartOutlined style={{ color: "red" }} />
|
alignItems: "center",
|
||||||
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
flexWrap: "nowrap",
|
||||||
{o.discount && o.discount !== 0 ? <Tag color="green">{`${o.discount * 100}%`}</Tag> : null}
|
width: "100%"
|
||||||
</Space>
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 0,
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{o.name}
|
||||||
</div>
|
</div>
|
||||||
</Option>
|
<Space style={{ marginLeft: "1rem" }}>
|
||||||
))
|
<HeartOutlined style={{ color: "red" }} />
|
||||||
: null}
|
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||||
{options
|
{o.discount && o.discount !== 0 ? <Tag color="green">{`${o.discount * 100}%`}</Tag> : null}
|
||||||
? options.map((o) => (
|
</Space>
|
||||||
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
</div>
|
||||||
<div className="imex-flex-row" style={{ width: "100%" }}>
|
</Option>
|
||||||
<div style={{ flex: 1 }}>{o.name}</div>
|
))}
|
||||||
|
{options &&
|
||||||
<Space style={{ marginLeft: "1rem" }}>
|
options.map((o) => (
|
||||||
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
|
||||||
{o.discount && o.discount !== 0 ? <Tag color="green">{`${o.discount * 100}%`}</Tag> : null}
|
<div
|
||||||
</Space>
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
flexWrap: "nowrap",
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 0,
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "ellipsis",
|
||||||
|
whiteSpace: "nowrap"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{o.name}
|
||||||
</div>
|
</div>
|
||||||
</Option>
|
<Space style={{ marginLeft: "1rem" }}>
|
||||||
))
|
{o.phone && showPhone && <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>}
|
||||||
: null}
|
{o.discount && o.discount !== 0 ? <Tag color="green">{`${o.discount * 100}%`}</Tag> : null}
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
</Option>
|
||||||
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
|
|||||||
operationName: eventName,
|
operationName: eventName,
|
||||||
variables: additionalParams,
|
variables: additionalParams,
|
||||||
dbevent: false,
|
dbevent: false,
|
||||||
env: "master"
|
env: `master-AIO|${import.meta.env.VITE_APP_GIT_SHA_DATE}`
|
||||||
});
|
});
|
||||||
// console.log(
|
// console.log(
|
||||||
// "%c[Analytics]",
|
// "%c[Analytics]",
|
||||||
|
|||||||
@@ -138,7 +138,8 @@ export const QUERY_BODYSHOP = gql`
|
|||||||
tt_enforce_hours_for_tech_console
|
tt_enforce_hours_for_tech_console
|
||||||
md_tasks_presets
|
md_tasks_presets
|
||||||
use_paint_scale_data
|
use_paint_scale_data
|
||||||
md_ro_guard
|
intellipay_config
|
||||||
|
md_ro_guard
|
||||||
employee_teams(order_by: { name: asc }, where: { active: { _eq: true } }) {
|
employee_teams(order_by: { name: asc }, where: { active: { _eq: true } }) {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
@@ -266,7 +267,8 @@ export const UPDATE_SHOP = gql`
|
|||||||
enforce_conversion_category
|
enforce_conversion_category
|
||||||
tt_enforce_hours_for_tech_console
|
tt_enforce_hours_for_tech_console
|
||||||
md_tasks_presets
|
md_tasks_presets
|
||||||
md_ro_guard
|
intellipay_config
|
||||||
|
md_ro_guard
|
||||||
employee_teams(order_by: { name: asc }, where: { active: { _eq: true } }) {
|
employee_teams(order_by: { name: asc }, where: { active: { _eq: true } }) {
|
||||||
id
|
id
|
||||||
name
|
name
|
||||||
|
|||||||
@@ -2461,6 +2461,14 @@ export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
export const SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW = gql`
|
||||||
|
subscription SUBSCRIPTION_JOBS_IN_PRODUCTION_VIEW {
|
||||||
|
jobs: jobs_inproduction {
|
||||||
|
id
|
||||||
|
updated_at
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const QUERY_JOBS_IN_PRODUCTION = gql`
|
export const QUERY_JOBS_IN_PRODUCTION = gql`
|
||||||
query QUERY_JOBS_IN_PRODUCTION {
|
query QUERY_JOBS_IN_PRODUCTION {
|
||||||
|
|||||||
@@ -1,6 +1,26 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import ProductionBoardKanbanContainer from "../../components/production-board-kanban/production-board-kanban.container";
|
import ProductionBoardKanbanContainer from "../../components/production-board-kanban/production-board-kanban.container";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
//currentUser: selectCurrentUser
|
||||||
|
bodyshop: selectBodyshop
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
|
});
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ProductionBoardComponent);
|
||||||
|
|
||||||
export default function ProductionBoardComponent() {
|
export function ProductionBoardComponent({ bodyshop }) {
|
||||||
return <ProductionBoardKanbanContainer />;
|
const {
|
||||||
|
treatments: { Production_Use_View }
|
||||||
|
} = useSplitTreatments({
|
||||||
|
attributes: {},
|
||||||
|
names: ["Production_Use_View"],
|
||||||
|
splitKey: bodyshop && bodyshop.imexshopid
|
||||||
|
});
|
||||||
|
|
||||||
|
return <ProductionBoardKanbanContainer subscriptionType={Production_Use_View.treatment} />;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,31 @@ import React from "react";
|
|||||||
import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container";
|
import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container";
|
||||||
import ProductionListTable from "../../components/production-list-table/production-list-table.container";
|
import ProductionListTable from "../../components/production-list-table/production-list-table.container";
|
||||||
|
|
||||||
export default function ProductionListComponent() {
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
|
});
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ProductionListComponent);
|
||||||
|
|
||||||
|
export function ProductionListComponent({ bodyshop }) {
|
||||||
|
const {
|
||||||
|
treatments: { Production_Use_View }
|
||||||
|
} = useSplitTreatments({
|
||||||
|
attributes: {},
|
||||||
|
names: ["Production_Use_View"],
|
||||||
|
splitKey: bodyshop && bodyshop.imexshopid
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<NoteUpsertModal />
|
<NoteUpsertModal />
|
||||||
<ProductionListTable />
|
<ProductionListTable subscriptionType={Production_Use_View.treatment} />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import { Tabs } from "antd";
|
import { Tabs } from "antd";
|
||||||
import React, { useEffect } from "react";
|
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
|
import React, { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||||
|
import ShopCsiConfig from "../../components/shop-csi-config/shop-csi-config.component";
|
||||||
import ShopEmployeesContainer from "../../components/shop-employees/shop-employees.container";
|
import ShopEmployeesContainer from "../../components/shop-employees/shop-employees.container";
|
||||||
import ShopInfoContainer from "../../components/shop-info/shop-info.container";
|
import ShopInfoContainer from "../../components/shop-info/shop-info.container";
|
||||||
import ShopCsiConfig from "../../components/shop-csi-config/shop-csi-config.component";
|
import ShopInfoUsersComponent from "../../components/shop-users/shop-users.component";
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import ShopInfoUsersComponent from "../../components/shop-users/shop-users.component";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
|
||||||
import ShopTeamsContainer from "../../components/shop-teams/shop-teams.container";
|
|
||||||
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
|
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
|
||||||
|
import ShopTeamsContainer from "../../components/shop-teams/shop-teams.container";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
|
|||||||
@@ -36,7 +36,8 @@ export function* openChatByPhone({ payload }) {
|
|||||||
data: { conversations }
|
data: { conversations }
|
||||||
} = yield client.query({
|
} = yield client.query({
|
||||||
query: CONVERSATION_ID_BY_PHONE,
|
query: CONVERSATION_ID_BY_PHONE,
|
||||||
variables: { phone: p.number }
|
variables: { phone: p.number },
|
||||||
|
fetchPolicy: 'no-cache'
|
||||||
});
|
});
|
||||||
|
|
||||||
if (conversations.length === 0) {
|
if (conversations.length === 0) {
|
||||||
|
|||||||
@@ -230,7 +230,7 @@
|
|||||||
"markexported": "Mark Exported",
|
"markexported": "Mark Exported",
|
||||||
"markforreexport": "Mark for Re-export",
|
"markforreexport": "Mark for Re-export",
|
||||||
"new": "New Bill",
|
"new": "New Bill",
|
||||||
"nobilllines": "This part has not yet been recieved.",
|
"nobilllines": "",
|
||||||
"noneselected": "No bill selected.",
|
"noneselected": "No bill selected.",
|
||||||
"onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.",
|
"onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.",
|
||||||
"printlabels": "Print Labels",
|
"printlabels": "Print Labels",
|
||||||
@@ -270,9 +270,9 @@
|
|||||||
"testrender": "Test Render"
|
"testrender": "Test Render"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
"creatingdefaultview": "Error creating default view.",
|
||||||
"loading": "Unable to load shop details. Please call technical support.",
|
"loading": "Unable to load shop details. Please call technical support.",
|
||||||
"saving": "Error encountered while saving. {{message}}",
|
"saving": "Error encountered while saving. {{message}}"
|
||||||
"creatingdefaultview": "Error creating default view."
|
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
"ReceivableCustomField": "QBO Receivable Custom Field {{number}}",
|
"ReceivableCustomField": "QBO Receivable Custom Field {{number}}",
|
||||||
@@ -285,19 +285,21 @@
|
|||||||
},
|
},
|
||||||
"appt_length": "Default Appointment Length",
|
"appt_length": "Default Appointment Length",
|
||||||
"attach_pdf_to_email": "Attach PDF copy to sent emails?",
|
"attach_pdf_to_email": "Attach PDF copy to sent emails?",
|
||||||
|
"batchid": "ADP Batch ID",
|
||||||
"bill_allow_post_to_closed": "Allow Bills to be posted to Closed Jobs",
|
"bill_allow_post_to_closed": "Allow Bills to be posted to Closed Jobs",
|
||||||
"bill_federal_tax_rate": "Bills - Federal Tax Rate %",
|
"bill_federal_tax_rate": "Bills - Federal Tax Rate %",
|
||||||
"bill_local_tax_rate": "Bill - Local Tax Rate %",
|
"bill_local_tax_rate": "Bill - Local Tax Rate %",
|
||||||
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
|
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
|
||||||
"city": "City",
|
"city": "City",
|
||||||
"closingperiod": "Closing Period",
|
"closingperiod": "Closing Period",
|
||||||
|
"companycode": "ADP Company Code",
|
||||||
"country": "Country",
|
"country": "Country",
|
||||||
"dailybodytarget": "Scoreboard - Daily Body Target",
|
"dailybodytarget": "Scoreboard - Daily Body Target",
|
||||||
"dailypainttarget": "Scoreboard - Daily Paint Target",
|
"dailypainttarget": "Scoreboard - Daily Paint Target",
|
||||||
"default_adjustment_rate": "Default Labor Deduction Adjustment Rate",
|
"default_adjustment_rate": "Default Labor Deduction Adjustment Rate",
|
||||||
"deliver": {
|
"deliver": {
|
||||||
"templates": "Delivery Templates",
|
"require_actual_delivery_date": "Require Actual Delivery",
|
||||||
"require_actual_delivery_date": "Require Actual Delivery"
|
"templates": "Delivery Templates"
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
"apcontrol": "AP Control Number",
|
"apcontrol": "AP Control Number",
|
||||||
@@ -330,6 +332,10 @@
|
|||||||
"next_contact_hours": "Automatic Next Contact Date - Hours from Intake",
|
"next_contact_hours": "Automatic Next Contact Date - Hours from Intake",
|
||||||
"templates": "Intake Templates"
|
"templates": "Intake Templates"
|
||||||
},
|
},
|
||||||
|
"intellipay_config": {
|
||||||
|
"cash_discount_percentage": "Cash Discount %",
|
||||||
|
"enable_cash_discount": "Enable Cash Discounting"
|
||||||
|
},
|
||||||
"invoice_federal_tax_rate": "Invoices - Federal Tax Rate",
|
"invoice_federal_tax_rate": "Invoices - Federal Tax Rate",
|
||||||
"invoice_local_tax_rate": "Invoices - Local Tax Rate",
|
"invoice_local_tax_rate": "Invoices - Local Tax Rate",
|
||||||
"invoice_state_tax_rate": "Invoices - State Tax Rate",
|
"invoice_state_tax_rate": "Invoices - State Tax Rate",
|
||||||
@@ -661,6 +667,8 @@
|
|||||||
"filehandlers": "Adjusters",
|
"filehandlers": "Adjusters",
|
||||||
"insurancecos": "Insurance Companies",
|
"insurancecos": "Insurance Companies",
|
||||||
"intakechecklist": "Intake Checklist",
|
"intakechecklist": "Intake Checklist",
|
||||||
|
"intellipay": "IntelliPay",
|
||||||
|
"intellipay_cash_discount": "Please ensure that cash discounting has been enabled on your merchant account. Reach out to IntelliPay Support if you need assistance. ",
|
||||||
"jobstatuses": "Job Statuses",
|
"jobstatuses": "Job Statuses",
|
||||||
"laborrates": "Labor Rates",
|
"laborrates": "Labor Rates",
|
||||||
"licensing": "Licensing",
|
"licensing": "Licensing",
|
||||||
@@ -700,10 +708,10 @@
|
|||||||
"workingdays": "Working Days"
|
"workingdays": "Working Days"
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
"save": "Shop configuration saved successfully. ",
|
|
||||||
"unsavedchanges": "Unsaved changes will be lost. Are you sure you want to continue?",
|
|
||||||
"areyousure": "Are you sure you want to continue?",
|
"areyousure": "Are you sure you want to continue?",
|
||||||
"defaultviewcreated": "Default view created successfully."
|
"defaultviewcreated": "Default view created successfully.",
|
||||||
|
"save": "Shop configuration saved successfully. ",
|
||||||
|
"unsavedchanges": "Unsaved changes will be lost. Are you sure you want to continue?"
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
"centermustexist": "The chosen responsibility center does not exist.",
|
"centermustexist": "The chosen responsibility center does not exist.",
|
||||||
@@ -1133,8 +1141,8 @@
|
|||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"defaults": "Defaults",
|
|
||||||
"add": "Add",
|
"add": "Add",
|
||||||
|
"autoupdate": "{{app}} will automatically update in {{time}} seconds. Please save all changes.",
|
||||||
"calculate": "Calculate",
|
"calculate": "Calculate",
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
@@ -1142,6 +1150,8 @@
|
|||||||
"copied": "Copied!",
|
"copied": "Copied!",
|
||||||
"copylink": "Copy Link",
|
"copylink": "Copy Link",
|
||||||
"create": "Create",
|
"create": "Create",
|
||||||
|
"defaults": "Defaults",
|
||||||
|
"delay": "Delay Update (5 mins)",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
"deleteall": "Delete All",
|
"deleteall": "Delete All",
|
||||||
"deselectall": "Deselect All",
|
"deselectall": "Deselect All",
|
||||||
@@ -1153,10 +1163,12 @@
|
|||||||
"print": "Print",
|
"print": "Print",
|
||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
"remove": "Remove",
|
"remove": "Remove",
|
||||||
|
"remove_alert": "Are you sure you want to dismiss the alert?",
|
||||||
"reset": "Reset your changes.",
|
"reset": "Reset your changes.",
|
||||||
"resetpassword": "Reset Password",
|
"resetpassword": "Reset Password",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"saveandnew": "Save and New",
|
"saveandnew": "Save and New",
|
||||||
|
"saveas": "Save As",
|
||||||
"selectall": "Select All",
|
"selectall": "Select All",
|
||||||
"send": "Send",
|
"send": "Send",
|
||||||
"sendbysms": "Send by SMS",
|
"sendbysms": "Send by SMS",
|
||||||
@@ -1164,9 +1176,7 @@
|
|||||||
"submit": "Submit",
|
"submit": "Submit",
|
||||||
"tryagain": "Try Again",
|
"tryagain": "Try Again",
|
||||||
"view": "View",
|
"view": "View",
|
||||||
"viewreleasenotes": "See What's Changed",
|
"viewreleasenotes": "See What's Changed"
|
||||||
"remove_alert": "Are you sure you want to dismiss the alert?",
|
|
||||||
"saveas": "Save As"
|
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"fcm": "You must allow notification permissions to have real time messaging. Click to try again.",
|
"fcm": "You must allow notification permissions to have real time messaging. Click to try again.",
|
||||||
@@ -1181,7 +1191,6 @@
|
|||||||
"vehicle": "Vehicle"
|
"vehicle": "Vehicle"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"unsavedchanges": "Unsaved changes.",
|
|
||||||
"actions": "Actions",
|
"actions": "Actions",
|
||||||
"areyousure": "Are you sure?",
|
"areyousure": "Are you sure?",
|
||||||
"barcode": "Barcode",
|
"barcode": "Barcode",
|
||||||
@@ -1250,6 +1259,7 @@
|
|||||||
"tuesday": "Tuesday",
|
"tuesday": "Tuesday",
|
||||||
"tvmode": "TV Mode",
|
"tvmode": "TV Mode",
|
||||||
"unknown": "Unknown",
|
"unknown": "Unknown",
|
||||||
|
"unsavedchanges": "Unsaved changes.",
|
||||||
"username": "Username",
|
"username": "Username",
|
||||||
"view": "View",
|
"view": "View",
|
||||||
"wednesday": "Wednesday",
|
"wednesday": "Wednesday",
|
||||||
@@ -1363,6 +1373,7 @@
|
|||||||
},
|
},
|
||||||
"job_payments": {
|
"job_payments": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
|
"create_short_link": "Generate Short Link",
|
||||||
"goback": "Go Back",
|
"goback": "Go Back",
|
||||||
"proceedtopayment": "Proceed to Payment",
|
"proceedtopayment": "Proceed to Payment",
|
||||||
"refundpayment": "Refund Payment"
|
"refundpayment": "Refund Payment"
|
||||||
@@ -2739,41 +2750,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"constants": {
|
|
||||||
"main_profile": "Default"
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"small": "Small",
|
|
||||||
"medium": "Medium",
|
|
||||||
"large": "Large",
|
|
||||||
"vertical": "Vertical",
|
|
||||||
"horizontal": "Horizontal"
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"layout": "Layout",
|
|
||||||
"information": "Information",
|
|
||||||
"statistics_title": "Statistics",
|
|
||||||
"board_settings": "Board Settings",
|
|
||||||
"filters_title": "Filters",
|
|
||||||
"filters": {
|
|
||||||
"md_ins_cos": "Insurance Companies",
|
|
||||||
"md_estimators": "Estimators"
|
|
||||||
},
|
|
||||||
"statistics": {
|
|
||||||
"total_hours_in_production": "Hours in Production",
|
|
||||||
"total_lab_in_production": "Body Hours in Production",
|
|
||||||
"total_lar_in_production": "Refinish Hours in Production",
|
|
||||||
"total_amount_in_production": "Dollars in Production",
|
|
||||||
"jobs_in_production": "Jobs in Production",
|
|
||||||
"total_hours_on_board": "Hours on Board",
|
|
||||||
"total_lab_on_board": "Body Hours on Board",
|
|
||||||
"total_lar_on_board": "Refinish Hours on Board",
|
|
||||||
"total_amount_on_board": "Dollars on Board",
|
|
||||||
"total_jobs_on_board": "Jobs on Board",
|
|
||||||
"tasks_in_production": "Tasks in Production",
|
|
||||||
"tasks_on_board": "Tasks on Board"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"actions": {
|
"actions": {
|
||||||
"addcolumns": "Add Columns",
|
"addcolumns": "Add Columns",
|
||||||
"bodypriority-clear": "Clear Body Priority",
|
"bodypriority-clear": "Clear Body Priority",
|
||||||
@@ -2788,29 +2764,23 @@
|
|||||||
"suspend": "Suspend",
|
"suspend": "Suspend",
|
||||||
"unsuspend": "Unsuspend"
|
"unsuspend": "Unsuspend"
|
||||||
},
|
},
|
||||||
|
"constants": {
|
||||||
|
"main_profile": "Default"
|
||||||
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"boardupdate": "Error encountered updating Job. {{message}}",
|
"boardupdate": "Error encountered updating Job. {{message}}",
|
||||||
"removing": "Error removing from production board. {{error}}",
|
|
||||||
"settings": "Error saving board settings: {{error}}",
|
|
||||||
"name_exists": "A Profile with this name already exists. Please choose a different name.",
|
"name_exists": "A Profile with this name already exists. Please choose a different name.",
|
||||||
"name_required": "Profile name is required."
|
"name_required": "Profile name is required.",
|
||||||
|
"removing": "Error removing from production board. {{error}}",
|
||||||
|
"settings": "Error saving board settings: {{error}}"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"kiosk_mode": "Kiosk Mode",
|
|
||||||
"on": "On",
|
|
||||||
"off": "Off",
|
|
||||||
"wide": "Wide",
|
|
||||||
"tall": "Tall",
|
|
||||||
"vertical": "Vertical",
|
|
||||||
"horizontal": "Horizontal",
|
|
||||||
"orientation": "Board Orientation",
|
|
||||||
"card_size": "Card Size",
|
|
||||||
"model_info": "Vehicle Info",
|
|
||||||
"actual_in": "Actual In",
|
"actual_in": "Actual In",
|
||||||
|
"addnewprofile": "Add New Profile",
|
||||||
"alert": "Alert",
|
"alert": "Alert",
|
||||||
"tasks": "Tasks",
|
|
||||||
"alertoff": "Remove alert from Job",
|
"alertoff": "Remove alert from Job",
|
||||||
"alerton": "Add alert to Job",
|
"alerton": "Add alert to Job",
|
||||||
|
"alerts": "Alerts",
|
||||||
"ats": "Alternative Transportation",
|
"ats": "Alternative Transportation",
|
||||||
"bodyhours": "B",
|
"bodyhours": "B",
|
||||||
"bodypriority": "B/P",
|
"bodypriority": "B/P",
|
||||||
@@ -2820,6 +2790,7 @@
|
|||||||
"qbo_usa": "QBO USA"
|
"qbo_usa": "QBO USA"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"card_size": "Card Size",
|
||||||
"cardcolor": "Colored Cards",
|
"cardcolor": "Colored Cards",
|
||||||
"cardsettings": "Card Settings",
|
"cardsettings": "Card Settings",
|
||||||
"clm_no": "Claim Number",
|
"clm_no": "Claim Number",
|
||||||
@@ -2828,48 +2799,88 @@
|
|||||||
"detailpriority": "D/P",
|
"detailpriority": "D/P",
|
||||||
"employeeassignments": "Employee Assignments",
|
"employeeassignments": "Employee Assignments",
|
||||||
"employeesearch": "Employee Search",
|
"employeesearch": "Employee Search",
|
||||||
|
"estimator": "Estimator",
|
||||||
|
"horizontal": "Horizontal",
|
||||||
"ins_co_nm": "Insurance Company Name",
|
"ins_co_nm": "Insurance Company Name",
|
||||||
"jobdetail": "Job Details",
|
"jobdetail": "Job Details",
|
||||||
|
"kiosk_mode": "Kiosk Mode",
|
||||||
"laborhrs": "Labor Hours",
|
"laborhrs": "Labor Hours",
|
||||||
"legend": "Legend:",
|
"legend": "Legend:",
|
||||||
|
"model_info": "Vehicle Info",
|
||||||
"note": "Production Note",
|
"note": "Production Note",
|
||||||
|
"off": "Off",
|
||||||
|
"on": "On",
|
||||||
|
"orientation": "Board Orientation",
|
||||||
"ownr_nm": "Customer Name",
|
"ownr_nm": "Customer Name",
|
||||||
"paintpriority": "P/P",
|
"paintpriority": "P/P",
|
||||||
"partsstatus": "Parts Status",
|
"partsstatus": "Parts Status",
|
||||||
"estimator": "Estimator",
|
|
||||||
"subtotal": "Subtotal",
|
|
||||||
"production_note": "Production Note",
|
"production_note": "Production Note",
|
||||||
"refinishhours": "R",
|
"refinishhours": "R",
|
||||||
"scheduled_completion": "Scheduled Completion",
|
"scheduled_completion": "Scheduled Completion",
|
||||||
"selectview": "Select a View",
|
"selectview": "Select a View",
|
||||||
"stickyheader": "Sticky Header (BETA)",
|
"stickyheader": "Sticky Header (BETA)",
|
||||||
"sublets": "Sublets",
|
"sublets": "Sublets",
|
||||||
|
"subtotal": "Subtotal",
|
||||||
|
"tall": "Tall",
|
||||||
|
"tasks": "Tasks",
|
||||||
"totalhours": "Total Hrs ",
|
"totalhours": "Total Hrs ",
|
||||||
"touchtime": "T/T",
|
"touchtime": "T/T",
|
||||||
|
"vertical": "Vertical",
|
||||||
"viewname": "View Name",
|
"viewname": "View Name",
|
||||||
"alerts": "Alerts",
|
"wide": "Wide"
|
||||||
"addnewprofile": "Add New Profile"
|
},
|
||||||
|
"options": {
|
||||||
|
"horizontal": "Horizontal",
|
||||||
|
"large": "Large",
|
||||||
|
"medium": "Medium",
|
||||||
|
"small": "Small",
|
||||||
|
"vertical": "Vertical"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"board_settings": "Board Settings",
|
||||||
|
"filters": {
|
||||||
|
"md_estimators": "Estimators",
|
||||||
|
"md_ins_cos": "Insurance Companies"
|
||||||
|
},
|
||||||
|
"filters_title": "Filters",
|
||||||
|
"information": "Information",
|
||||||
|
"layout": "Layout",
|
||||||
|
"statistics": {
|
||||||
|
"jobs_in_production": "Jobs in Production",
|
||||||
|
"tasks_in_production": "Tasks in Production",
|
||||||
|
"tasks_on_board": "Tasks on Board",
|
||||||
|
"total_amount_in_production": "Dollars in Production",
|
||||||
|
"total_amount_on_board": "Dollars on Board",
|
||||||
|
"total_hours_in_production": "Hours in Production",
|
||||||
|
"total_hours_on_board": "Hours on Board",
|
||||||
|
"total_jobs_on_board": "Jobs on Board",
|
||||||
|
"total_lab_in_production": "Body Hours in Production",
|
||||||
|
"total_lab_on_board": "Body Hours on Board",
|
||||||
|
"total_lar_in_production": "Refinish Hours in Production",
|
||||||
|
"total_lar_on_board": "Refinish Hours on Board"
|
||||||
|
},
|
||||||
|
"statistics_title": "Statistics"
|
||||||
|
},
|
||||||
|
"statistics": {
|
||||||
|
"currency_symbol": "$",
|
||||||
|
"hours": "Hours",
|
||||||
|
"jobs": "Jobs",
|
||||||
|
"jobs_in_production": "Jobs in Production",
|
||||||
|
"tasks": "Tasks",
|
||||||
|
"tasks_in_production": "Tasks in Production",
|
||||||
|
"tasks_on_board": "Tasks on Board",
|
||||||
|
"total_amount_in_production": "Dollars in Production",
|
||||||
|
"total_amount_on_board": "Dollars on Board",
|
||||||
|
"total_hours_in_production": "Hours in Production",
|
||||||
|
"total_hours_on_board": "Hours on Board",
|
||||||
|
"total_jobs_on_board": "Jobs on Board",
|
||||||
|
"total_lab_in_production": "Body Hours in Production",
|
||||||
|
"total_lab_on_board": "Body Hours on Board",
|
||||||
|
"total_lar_in_production": "Refinish Hours in Production",
|
||||||
|
"total_lar_on_board": "Refinish Hours on Board"
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
"removed": "Job removed from production."
|
"removed": "Job removed from production."
|
||||||
},
|
|
||||||
"statistics": {
|
|
||||||
"total_hours_in_production": "Hours in Production",
|
|
||||||
"total_lab_in_production": "Body Hours in Production",
|
|
||||||
"total_lar_in_production": "Refinish Hours in Production",
|
|
||||||
"total_amount_in_production": "Dollars in Production",
|
|
||||||
"jobs_in_production": "Jobs in Production",
|
|
||||||
"total_hours_on_board": "Hours on Board",
|
|
||||||
"total_lab_on_board": "Body Hours on Board",
|
|
||||||
"total_lar_on_board": "Refinish Hours on Board",
|
|
||||||
"total_amount_on_board": "Dollars on Board",
|
|
||||||
"total_jobs_on_board": "Jobs on Board",
|
|
||||||
"tasks_in_production": "Tasks in Production",
|
|
||||||
"tasks_on_board": "Tasks on Board",
|
|
||||||
"tasks": "Tasks",
|
|
||||||
"hours": "Hours",
|
|
||||||
"currency_symbol": "$",
|
|
||||||
"jobs": "Jobs"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
@@ -2927,6 +2938,8 @@
|
|||||||
"vendor": "Vendor"
|
"vendor": "Vendor"
|
||||||
},
|
},
|
||||||
"templates": {
|
"templates": {
|
||||||
|
"adp_payroll_flat": "ADP Payroll - Flat Rate",
|
||||||
|
"adp_payroll_straight": "ADP Payroll - Straight Time",
|
||||||
"anticipated_revenue": "Anticipated Revenue",
|
"anticipated_revenue": "Anticipated Revenue",
|
||||||
"ar_aging": "AR Aging",
|
"ar_aging": "AR Aging",
|
||||||
"attendance_detail": "Attendance (All Employees)",
|
"attendance_detail": "Attendance (All Employees)",
|
||||||
@@ -3418,6 +3431,18 @@
|
|||||||
"vehicledetail": "Vehicle Details {{vehicle}} | {{app}}",
|
"vehicledetail": "Vehicle Details {{vehicle}} | {{app}}",
|
||||||
"vehicles": "All Vehicles | {{app}}"
|
"vehicles": "All Vehicles | {{app}}"
|
||||||
},
|
},
|
||||||
|
"trello": {
|
||||||
|
"labels": {
|
||||||
|
"add_card": "Add Card",
|
||||||
|
"add_lane": "Add Lane",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"delete_lane": "Delete Lane",
|
||||||
|
"description": "Description",
|
||||||
|
"label": "Label",
|
||||||
|
"lane_actions": "Lane Actions",
|
||||||
|
"title": "Title"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tt_approvals": {
|
"tt_approvals": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"approveselected": "Approve Selected"
|
"approveselected": "Approve Selected"
|
||||||
@@ -3556,18 +3581,6 @@
|
|||||||
"validation": {
|
"validation": {
|
||||||
"unique_vendor_name": "You must enter a unique vendor name."
|
"unique_vendor_name": "You must enter a unique vendor name."
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"trello": {
|
|
||||||
"labels": {
|
|
||||||
"add_card": "Add Card",
|
|
||||||
"add_lane": "Add Lane",
|
|
||||||
"delete_lane": "Delete Lane",
|
|
||||||
"lane_actions": "Lane Actions",
|
|
||||||
"title": "Title",
|
|
||||||
"description": "Description",
|
|
||||||
"label": "Label",
|
|
||||||
"cancel": "Cancel"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -270,9 +270,9 @@
|
|||||||
"testrender": ""
|
"testrender": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
|
"creatingdefaultview": "",
|
||||||
"loading": "No se pueden cargar los detalles de la tienda. Por favor llame al soporte técnico.",
|
"loading": "No se pueden cargar los detalles de la tienda. Por favor llame al soporte técnico.",
|
||||||
"saving": "",
|
"saving": ""
|
||||||
"creatingdefaultview": ""
|
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
"ReceivableCustomField": "",
|
"ReceivableCustomField": "",
|
||||||
@@ -285,19 +285,21 @@
|
|||||||
},
|
},
|
||||||
"appt_length": "",
|
"appt_length": "",
|
||||||
"attach_pdf_to_email": "",
|
"attach_pdf_to_email": "",
|
||||||
|
"batchid": "",
|
||||||
"bill_allow_post_to_closed": "",
|
"bill_allow_post_to_closed": "",
|
||||||
"bill_federal_tax_rate": "",
|
"bill_federal_tax_rate": "",
|
||||||
"bill_local_tax_rate": "",
|
"bill_local_tax_rate": "",
|
||||||
"bill_state_tax_rate": "",
|
"bill_state_tax_rate": "",
|
||||||
"city": "",
|
"city": "",
|
||||||
"closingperiod": "",
|
"closingperiod": "",
|
||||||
|
"companycode": "",
|
||||||
"country": "",
|
"country": "",
|
||||||
"dailybodytarget": "",
|
"dailybodytarget": "",
|
||||||
"dailypainttarget": "",
|
"dailypainttarget": "",
|
||||||
"default_adjustment_rate": "",
|
"default_adjustment_rate": "",
|
||||||
"deliver": {
|
"deliver": {
|
||||||
"templates": "",
|
"require_actual_delivery_date": "",
|
||||||
"require_actual_delivery_date": ""
|
"templates": ""
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
"apcontrol": "",
|
"apcontrol": "",
|
||||||
@@ -330,6 +332,10 @@
|
|||||||
"next_contact_hours": "",
|
"next_contact_hours": "",
|
||||||
"templates": ""
|
"templates": ""
|
||||||
},
|
},
|
||||||
|
"intellipay_config": {
|
||||||
|
"cash_discount_percentage": "",
|
||||||
|
"enable_cash_discount": ""
|
||||||
|
},
|
||||||
"invoice_federal_tax_rate": "",
|
"invoice_federal_tax_rate": "",
|
||||||
"invoice_local_tax_rate": "",
|
"invoice_local_tax_rate": "",
|
||||||
"invoice_state_tax_rate": "",
|
"invoice_state_tax_rate": "",
|
||||||
@@ -661,6 +667,8 @@
|
|||||||
"filehandlers": "",
|
"filehandlers": "",
|
||||||
"insurancecos": "",
|
"insurancecos": "",
|
||||||
"intakechecklist": "",
|
"intakechecklist": "",
|
||||||
|
"intellipay": "",
|
||||||
|
"intellipay_cash_discount": "",
|
||||||
"jobstatuses": "",
|
"jobstatuses": "",
|
||||||
"laborrates": "",
|
"laborrates": "",
|
||||||
"licensing": "",
|
"licensing": "",
|
||||||
@@ -700,10 +708,10 @@
|
|||||||
"workingdays": ""
|
"workingdays": ""
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
"save": "",
|
|
||||||
"unsavedchanges": "",
|
|
||||||
"areyousure": "",
|
"areyousure": "",
|
||||||
"defaultviewcreated": ""
|
"defaultviewcreated": "",
|
||||||
|
"save": "",
|
||||||
|
"unsavedchanges": ""
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
"centermustexist": "",
|
"centermustexist": "",
|
||||||
@@ -1133,8 +1141,8 @@
|
|||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"defaults": "defaults",
|
|
||||||
"add": "",
|
"add": "",
|
||||||
|
"autoupdate": "",
|
||||||
"calculate": "",
|
"calculate": "",
|
||||||
"cancel": "",
|
"cancel": "",
|
||||||
"clear": "",
|
"clear": "",
|
||||||
@@ -1142,6 +1150,8 @@
|
|||||||
"copied": "",
|
"copied": "",
|
||||||
"copylink": "",
|
"copylink": "",
|
||||||
"create": "",
|
"create": "",
|
||||||
|
"defaults": "defaults",
|
||||||
|
"delay": "",
|
||||||
"delete": "Borrar",
|
"delete": "Borrar",
|
||||||
"deleteall": "",
|
"deleteall": "",
|
||||||
"deselectall": "",
|
"deselectall": "",
|
||||||
@@ -1153,10 +1163,12 @@
|
|||||||
"print": "",
|
"print": "",
|
||||||
"refresh": "",
|
"refresh": "",
|
||||||
"remove": "",
|
"remove": "",
|
||||||
|
"remove_alert": "",
|
||||||
"reset": " Restablecer a original.",
|
"reset": " Restablecer a original.",
|
||||||
"resetpassword": "",
|
"resetpassword": "",
|
||||||
"save": "Salvar",
|
"save": "Salvar",
|
||||||
"saveandnew": "",
|
"saveandnew": "",
|
||||||
|
"saveas": "",
|
||||||
"selectall": "",
|
"selectall": "",
|
||||||
"send": "",
|
"send": "",
|
||||||
"sendbysms": "",
|
"sendbysms": "",
|
||||||
@@ -1164,9 +1176,7 @@
|
|||||||
"submit": "",
|
"submit": "",
|
||||||
"tryagain": "",
|
"tryagain": "",
|
||||||
"view": "",
|
"view": "",
|
||||||
"viewreleasenotes": "",
|
"viewreleasenotes": ""
|
||||||
"remove_alert": "",
|
|
||||||
"saveas": ""
|
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"fcm": "",
|
"fcm": "",
|
||||||
@@ -1181,7 +1191,6 @@
|
|||||||
"vehicle": ""
|
"vehicle": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"unsavedchanges": "",
|
|
||||||
"actions": "Comportamiento",
|
"actions": "Comportamiento",
|
||||||
"areyousure": "",
|
"areyousure": "",
|
||||||
"barcode": "código de barras",
|
"barcode": "código de barras",
|
||||||
@@ -1250,6 +1259,7 @@
|
|||||||
"tuesday": "",
|
"tuesday": "",
|
||||||
"tvmode": "",
|
"tvmode": "",
|
||||||
"unknown": "Desconocido",
|
"unknown": "Desconocido",
|
||||||
|
"unsavedchanges": "",
|
||||||
"username": "",
|
"username": "",
|
||||||
"view": "",
|
"view": "",
|
||||||
"wednesday": "",
|
"wednesday": "",
|
||||||
@@ -1363,6 +1373,7 @@
|
|||||||
},
|
},
|
||||||
"job_payments": {
|
"job_payments": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
|
"create_short_link": "",
|
||||||
"goback": "",
|
"goback": "",
|
||||||
"proceedtopayment": "",
|
"proceedtopayment": "",
|
||||||
"refundpayment": ""
|
"refundpayment": ""
|
||||||
@@ -2739,41 +2750,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"production": {
|
"production": {
|
||||||
"constants": {
|
|
||||||
"main_profile": ""
|
|
||||||
},
|
|
||||||
"options": {
|
|
||||||
"small": "",
|
|
||||||
"medium": "",
|
|
||||||
"large": "",
|
|
||||||
"vertical": "",
|
|
||||||
"horizontal": ""
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"layout": "",
|
|
||||||
"information": "",
|
|
||||||
"statistics_title": "",
|
|
||||||
"board_settings": "",
|
|
||||||
"filters_title": "",
|
|
||||||
"filters": {
|
|
||||||
"md_ins_cos": "",
|
|
||||||
"md_estimators": ""
|
|
||||||
},
|
|
||||||
"statistics": {
|
|
||||||
"total_hours_in_production": "",
|
|
||||||
"total_lab_in_production": "",
|
|
||||||
"total_lar_in_production": "",
|
|
||||||
"total_amount_in_production": "",
|
|
||||||
"jobs_in_production": "",
|
|
||||||
"total_hours_on_board": "",
|
|
||||||
"total_lab_on_board": "",
|
|
||||||
"total_lar_on_board": "",
|
|
||||||
"total_amount_on_board": "",
|
|
||||||
"total_jobs_on_board": "",
|
|
||||||
"tasks_in_production": "",
|
|
||||||
"tasks_on_board": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"actions": {
|
"actions": {
|
||||||
"addcolumns": "",
|
"addcolumns": "",
|
||||||
"bodypriority-clear": "",
|
"bodypriority-clear": "",
|
||||||
@@ -2788,29 +2764,23 @@
|
|||||||
"suspend": "",
|
"suspend": "",
|
||||||
"unsuspend": ""
|
"unsuspend": ""
|
||||||
},
|
},
|
||||||
|
"constants": {
|
||||||
|
"main_profile": ""
|
||||||
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"boardupdate": "",
|
"boardupdate": "",
|
||||||
"removing": "",
|
|
||||||
"settings": "",
|
|
||||||
"name_exists": "",
|
"name_exists": "",
|
||||||
"name_required": ""
|
"name_required": "",
|
||||||
|
"removing": "",
|
||||||
|
"settings": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"kiosk_mode": "",
|
|
||||||
"on": "",
|
|
||||||
"off": "",
|
|
||||||
"wide": "",
|
|
||||||
"tall": "",
|
|
||||||
"vertical": "",
|
|
||||||
"horizontal": "",
|
|
||||||
"orientation": "",
|
|
||||||
"card_size": "",
|
|
||||||
"model_info": "",
|
|
||||||
"actual_in": "",
|
"actual_in": "",
|
||||||
|
"addnewprofile": "",
|
||||||
"alert": "",
|
"alert": "",
|
||||||
"tasks": "",
|
|
||||||
"alertoff": "",
|
"alertoff": "",
|
||||||
"alerton": "",
|
"alerton": "",
|
||||||
|
"alerts": "",
|
||||||
"ats": "",
|
"ats": "",
|
||||||
"bodyhours": "",
|
"bodyhours": "",
|
||||||
"bodypriority": "",
|
"bodypriority": "",
|
||||||
@@ -2820,6 +2790,7 @@
|
|||||||
"qbo_usa": ""
|
"qbo_usa": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"card_size": "",
|
||||||
"cardcolor": "",
|
"cardcolor": "",
|
||||||
"cardsettings": "",
|
"cardsettings": "",
|
||||||
"clm_no": "",
|
"clm_no": "",
|
||||||
@@ -2828,48 +2799,88 @@
|
|||||||
"detailpriority": "",
|
"detailpriority": "",
|
||||||
"employeeassignments": "",
|
"employeeassignments": "",
|
||||||
"employeesearch": "",
|
"employeesearch": "",
|
||||||
|
"estimator": "",
|
||||||
|
"horizontal": "",
|
||||||
"ins_co_nm": "",
|
"ins_co_nm": "",
|
||||||
"jobdetail": "",
|
"jobdetail": "",
|
||||||
|
"kiosk_mode": "",
|
||||||
"laborhrs": "",
|
"laborhrs": "",
|
||||||
"legend": "",
|
"legend": "",
|
||||||
|
"model_info": "",
|
||||||
"note": "",
|
"note": "",
|
||||||
|
"off": "",
|
||||||
|
"on": "",
|
||||||
|
"orientation": "",
|
||||||
"ownr_nm": "",
|
"ownr_nm": "",
|
||||||
"paintpriority": "",
|
"paintpriority": "",
|
||||||
"partsstatus": "",
|
"partsstatus": "",
|
||||||
"estimator": "",
|
|
||||||
"subtotal": "",
|
|
||||||
"production_note": "",
|
"production_note": "",
|
||||||
"refinishhours": "",
|
"refinishhours": "",
|
||||||
"scheduled_completion": "",
|
"scheduled_completion": "",
|
||||||
"selectview": "",
|
"selectview": "",
|
||||||
"stickyheader": "",
|
"stickyheader": "",
|
||||||
"sublets": "",
|
"sublets": "",
|
||||||
|
"subtotal": "",
|
||||||
|
"tall": "",
|
||||||
|
"tasks": "",
|
||||||
"totalhours": "",
|
"totalhours": "",
|
||||||
"touchtime": "",
|
"touchtime": "",
|
||||||
|
"vertical": "",
|
||||||
"viewname": "",
|
"viewname": "",
|
||||||
"alerts": "",
|
"wide": ""
|
||||||
"addnewprofile": ""
|
},
|
||||||
|
"options": {
|
||||||
|
"horizontal": "",
|
||||||
|
"large": "",
|
||||||
|
"medium": "",
|
||||||
|
"small": "",
|
||||||
|
"vertical": ""
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"board_settings": "",
|
||||||
|
"filters": {
|
||||||
|
"md_estimators": "",
|
||||||
|
"md_ins_cos": ""
|
||||||
|
},
|
||||||
|
"filters_title": "",
|
||||||
|
"information": "",
|
||||||
|
"layout": "",
|
||||||
|
"statistics": {
|
||||||
|
"jobs_in_production": "",
|
||||||
|
"tasks_in_production": "",
|
||||||
|
"tasks_on_board": "",
|
||||||
|
"total_amount_in_production": "",
|
||||||
|
"total_amount_on_board": "",
|
||||||
|
"total_hours_in_production": "",
|
||||||
|
"total_hours_on_board": "",
|
||||||
|
"total_jobs_on_board": "",
|
||||||
|
"total_lab_in_production": "",
|
||||||
|
"total_lab_on_board": "",
|
||||||
|
"total_lar_in_production": "",
|
||||||
|
"total_lar_on_board": ""
|
||||||
|
},
|
||||||
|
"statistics_title": ""
|
||||||
|
},
|
||||||
|
"statistics": {
|
||||||
|
"currency_symbol": "",
|
||||||
|
"hours": "",
|
||||||
|
"jobs": "",
|
||||||
|
"jobs_in_production": "",
|
||||||
|
"tasks": "",
|
||||||
|
"tasks_in_production": "",
|
||||||
|
"tasks_on_board": "",
|
||||||
|
"total_amount_in_production": "",
|
||||||
|
"total_amount_on_board": "",
|
||||||
|
"total_hours_in_production": "",
|
||||||
|
"total_hours_on_board": "",
|
||||||
|
"total_jobs_on_board": "",
|
||||||
|
"total_lab_in_production": "",
|
||||||
|
"total_lab_on_board": "",
|
||||||
|
"total_lar_in_production": "",
|
||||||
|
"total_lar_on_board": ""
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
"removed": ""
|
"removed": ""
|
||||||
},
|
|
||||||
"statistics": {
|
|
||||||
"total_hours_in_production": "",
|
|
||||||
"total_lab_in_production": "",
|
|
||||||
"total_lar_in_production": "",
|
|
||||||
"total_amount_in_production": "",
|
|
||||||
"jobs_in_production": "",
|
|
||||||
"total_hours_on_board": "",
|
|
||||||
"total_lab_on_board": "",
|
|
||||||
"total_lar_on_board": "",
|
|
||||||
"total_amount_on_board": "",
|
|
||||||
"total_jobs_on_board": "",
|
|
||||||
"tasks_in_production": "",
|
|
||||||
"tasks_on_board": "",
|
|
||||||
"tasks": "",
|
|
||||||
"hours": "",
|
|
||||||
"currency_symbol": "",
|
|
||||||
"jobs": ""
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
@@ -2927,6 +2938,8 @@
|
|||||||
"vendor": ""
|
"vendor": ""
|
||||||
},
|
},
|
||||||
"templates": {
|
"templates": {
|
||||||
|
"adp_payroll_flat": "",
|
||||||
|
"adp_payroll_straight": "",
|
||||||
"anticipated_revenue": "",
|
"anticipated_revenue": "",
|
||||||
"ar_aging": "",
|
"ar_aging": "",
|
||||||
"attendance_detail": "",
|
"attendance_detail": "",
|
||||||
@@ -3418,6 +3431,18 @@
|
|||||||
"vehicledetail": "Detalles del vehículo {{vehicle}} | {{app}}",
|
"vehicledetail": "Detalles del vehículo {{vehicle}} | {{app}}",
|
||||||
"vehicles": "Todos los vehiculos | {{app}}"
|
"vehicles": "Todos los vehiculos | {{app}}"
|
||||||
},
|
},
|
||||||
|
"trello": {
|
||||||
|
"labels": {
|
||||||
|
"add_card": "",
|
||||||
|
"add_lane": "",
|
||||||
|
"cancel": "",
|
||||||
|
"delete_lane": "",
|
||||||
|
"description": "",
|
||||||
|
"label": "",
|
||||||
|
"lane_actions": "",
|
||||||
|
"title": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"tt_approvals": {
|
"tt_approvals": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"approveselected": ""
|
"approveselected": ""
|
||||||
@@ -3556,18 +3581,6 @@
|
|||||||
"validation": {
|
"validation": {
|
||||||
"unique_vendor_name": ""
|
"unique_vendor_name": ""
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"trello": {
|
|
||||||
"labels": {
|
|
||||||
"add_card": "",
|
|
||||||
"add_lane": "",
|
|
||||||
"delete_lane": "",
|
|
||||||
"lane_actions": "",
|
|
||||||
"title": "",
|
|
||||||
"description": "",
|
|
||||||
"label": "",
|
|
||||||
"cancel": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -2158,6 +2158,32 @@ export const TemplateList = (type, context) => {
|
|||||||
field: i18n.t("tasks.fields.created_at")
|
field: i18n.t("tasks.fields.created_at")
|
||||||
},
|
},
|
||||||
group: "jobs"
|
group: "jobs"
|
||||||
|
},
|
||||||
|
adp_payroll_flat: {
|
||||||
|
title: i18n.t("reportcenter.templates.adp_payroll_flat"),
|
||||||
|
subject: i18n.t("reportcenter.templates.adp_payroll_flat"),
|
||||||
|
key: "adp_payroll_flat",
|
||||||
|
reporttype: "text",
|
||||||
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.timetickets"),
|
||||||
|
field: i18n.t("timetickets.fields.committed_at")
|
||||||
|
},
|
||||||
|
group: "payroll",
|
||||||
|
adp_payroll: true
|
||||||
|
},
|
||||||
|
adp_payroll_straight: {
|
||||||
|
title: i18n.t("reportcenter.templates.adp_payroll_straight"),
|
||||||
|
subject: i18n.t("reportcenter.templates.adp_payroll_straight"),
|
||||||
|
key: "adp_payroll_straight",
|
||||||
|
reporttype: "text",
|
||||||
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.timetickets"),
|
||||||
|
field: i18n.t("timetickets.fields.date")
|
||||||
|
},
|
||||||
|
group: "payroll",
|
||||||
|
adp_payroll: true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
|||||||
84
client/src/utils/countdownHook.js
Normal file
84
client/src/utils/countdownHook.js
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
import React from "react";
|
||||||
|
|
||||||
|
const useCountDown = (timeToCount = 60 * 1000, interval = 1000) => {
|
||||||
|
const [timeLeft, setTimeLeft] = React.useState(0);
|
||||||
|
const timer = React.useRef({});
|
||||||
|
|
||||||
|
const run = (ts) => {
|
||||||
|
if (!timer.current.started) {
|
||||||
|
timer.current.started = ts;
|
||||||
|
timer.current.lastInterval = ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localInterval = Math.min(interval, timer.current.timeLeft || Infinity);
|
||||||
|
if (ts - timer.current.lastInterval >= localInterval) {
|
||||||
|
timer.current.lastInterval += localInterval;
|
||||||
|
setTimeLeft((timeLeft) => {
|
||||||
|
timer.current.timeLeft = timeLeft - localInterval;
|
||||||
|
return timer.current.timeLeft;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ts - timer.current.started < timer.current.timeToCount) {
|
||||||
|
timer.current.requestId = window.requestAnimationFrame(run);
|
||||||
|
} else {
|
||||||
|
timer.current = {};
|
||||||
|
setTimeLeft(0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const start = React.useCallback(
|
||||||
|
(ttc) => {
|
||||||
|
window.cancelAnimationFrame(timer.current.requestId);
|
||||||
|
|
||||||
|
const newTimeToCount = ttc !== undefined ? ttc : timeToCount;
|
||||||
|
timer.current.started = null;
|
||||||
|
timer.current.lastInterval = null;
|
||||||
|
timer.current.timeToCount = newTimeToCount;
|
||||||
|
timer.current.requestId = window.requestAnimationFrame(run);
|
||||||
|
|
||||||
|
setTimeLeft(newTimeToCount);
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const pause = React.useCallback(() => {
|
||||||
|
window.cancelAnimationFrame(timer.current.requestId);
|
||||||
|
timer.current.started = null;
|
||||||
|
timer.current.lastInterval = null;
|
||||||
|
timer.current.timeToCount = timer.current.timeLeft;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const resume = React.useCallback(
|
||||||
|
() => {
|
||||||
|
if (!timer.current.started && timer.current.timeLeft > 0) {
|
||||||
|
window.cancelAnimationFrame(timer.current.requestId);
|
||||||
|
timer.current.requestId = window.requestAnimationFrame(run);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const reset = React.useCallback(() => {
|
||||||
|
if (timer.current.timeLeft) {
|
||||||
|
window.cancelAnimationFrame(timer.current.requestId);
|
||||||
|
timer.current = {};
|
||||||
|
setTimeLeft(0);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const actions = React.useMemo(
|
||||||
|
() => ({ start, pause, resume, reset }), // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
return () => window.cancelAnimationFrame(timer.current.requestId);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return [timeLeft, actions];
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useCountDown;
|
||||||
@@ -918,6 +918,7 @@
|
|||||||
- bill_tax_rates
|
- bill_tax_rates
|
||||||
- cdk_configuration
|
- cdk_configuration
|
||||||
- cdk_dealerid
|
- cdk_dealerid
|
||||||
|
- chatterid
|
||||||
- city
|
- city
|
||||||
- claimscorpid
|
- claimscorpid
|
||||||
- convenient_company
|
- convenient_company
|
||||||
@@ -939,6 +940,7 @@
|
|||||||
- inhousevendorid
|
- inhousevendorid
|
||||||
- insurance_vendor_id
|
- insurance_vendor_id
|
||||||
- intakechecklist
|
- intakechecklist
|
||||||
|
- intellipay_config
|
||||||
- jc_hourly_rates
|
- jc_hourly_rates
|
||||||
- jobsizelimit
|
- jobsizelimit
|
||||||
- last_name_first
|
- last_name_first
|
||||||
@@ -1040,6 +1042,7 @@
|
|||||||
- inhousevendorid
|
- inhousevendorid
|
||||||
- insurance_vendor_id
|
- insurance_vendor_id
|
||||||
- intakechecklist
|
- intakechecklist
|
||||||
|
- intellipay_config
|
||||||
- jc_hourly_rates
|
- jc_hourly_rates
|
||||||
- last_name_first
|
- last_name_first
|
||||||
- localmediaserverhttp
|
- localmediaserverhttp
|
||||||
@@ -4240,6 +4243,63 @@
|
|||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
event_triggers:
|
event_triggers:
|
||||||
|
- name: job_modified
|
||||||
|
definition:
|
||||||
|
enable_manual: false
|
||||||
|
update:
|
||||||
|
columns:
|
||||||
|
- clm_no
|
||||||
|
- v_make_desc
|
||||||
|
- date_next_contact
|
||||||
|
- status
|
||||||
|
- employee_csr
|
||||||
|
- employee_prep
|
||||||
|
- clm_total
|
||||||
|
- suspended
|
||||||
|
- employee_body
|
||||||
|
- ro_number
|
||||||
|
- actual_in
|
||||||
|
- ownr_co_nm
|
||||||
|
- v_model_yr
|
||||||
|
- comment
|
||||||
|
- job_totals
|
||||||
|
- v_vin
|
||||||
|
- ownr_fn
|
||||||
|
- scheduled_completion
|
||||||
|
- special_coverage_policy
|
||||||
|
- v_color
|
||||||
|
- ca_gst_registrant
|
||||||
|
- scheduled_delivery
|
||||||
|
- actual_delivery
|
||||||
|
- actual_completion
|
||||||
|
- kanbanparent
|
||||||
|
- est_ct_fn
|
||||||
|
- employee_refinish
|
||||||
|
- ownr_ph1
|
||||||
|
- date_last_contacted
|
||||||
|
- alt_transport
|
||||||
|
- inproduction
|
||||||
|
- est_ct_ln
|
||||||
|
- production_vars
|
||||||
|
- category
|
||||||
|
- v_model_desc
|
||||||
|
- date_invoiced
|
||||||
|
- est_co_nm
|
||||||
|
- ownr_ln
|
||||||
|
retry_conf:
|
||||||
|
interval_sec: 10
|
||||||
|
num_retries: 0
|
||||||
|
timeout_sec: 60
|
||||||
|
webhook_from_env: HASURA_API_URL
|
||||||
|
headers:
|
||||||
|
- name: event-secret
|
||||||
|
value_from_env: EVENT_SECRET
|
||||||
|
request_transform:
|
||||||
|
method: POST
|
||||||
|
query_params: {}
|
||||||
|
template_engine: Kriti
|
||||||
|
url: '{{$base_url}}/job/job-updated'
|
||||||
|
version: 2
|
||||||
- name: job_status_transition
|
- name: job_status_transition
|
||||||
definition:
|
definition:
|
||||||
enable_manual: true
|
enable_manual: true
|
||||||
@@ -4299,6 +4359,35 @@
|
|||||||
template_engine: Kriti
|
template_engine: Kriti
|
||||||
url: '{{$base_url}}/opensearch'
|
url: '{{$base_url}}/opensearch'
|
||||||
version: 2
|
version: 2
|
||||||
|
- table:
|
||||||
|
name: jobs_inproduction
|
||||||
|
schema: public
|
||||||
|
object_relationships:
|
||||||
|
- name: bodyshop
|
||||||
|
using:
|
||||||
|
manual_configuration:
|
||||||
|
column_mapping:
|
||||||
|
shopid: id
|
||||||
|
insertion_order: null
|
||||||
|
remote_table:
|
||||||
|
name: bodyshops
|
||||||
|
schema: public
|
||||||
|
select_permissions:
|
||||||
|
- role: user
|
||||||
|
permission:
|
||||||
|
columns:
|
||||||
|
- id
|
||||||
|
- shopid
|
||||||
|
- updated_at
|
||||||
|
filter:
|
||||||
|
bodyshop:
|
||||||
|
associations:
|
||||||
|
_and:
|
||||||
|
- user:
|
||||||
|
authid:
|
||||||
|
_eq: X-Hasura-User-Id
|
||||||
|
- active:
|
||||||
|
_eq: true
|
||||||
- table:
|
- table:
|
||||||
name: masterdata
|
name: masterdata
|
||||||
schema: public
|
schema: public
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."bodyshops" add column "intellipay_config" jsonb
|
||||||
|
-- not null default jsonb_build_object();
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."bodyshops" add column "intellipay_config" jsonb
|
||||||
|
not null default jsonb_build_object();
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."bodyshops" add column "chatterid" text
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."bodyshops" add column "chatterid" text
|
||||||
|
null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "courtesycars_idx_fleet" on
|
||||||
|
"public"."courtesycars" using btree ("fleetnumber");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."courtesycars_idx_fleet";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_ownrfn" on
|
||||||
|
"public"."jobs" using gin ("ownr_fn");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_ownrfn";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_ownrln" on
|
||||||
|
"public"."jobs" using gin ("ownr_ln");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_ownrln";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "jobs_idx_iouparent" on
|
||||||
|
"public"."jobs" using btree ("iouparent");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."jobs_idx_iouparent";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_ronumber" on
|
||||||
|
"public"."jobs" using gin ("ro_number");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_ronumber";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_clmno" on
|
||||||
|
"public"."jobs" using gin ("clm_no");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_clmno";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_vmodeldesc" on
|
||||||
|
"public"."jobs" using gin ("v_model_desc");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_vmodeldesc";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_vmakedesc" on
|
||||||
|
"public"."jobs" using gin ("v_make_desc");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_vmakedesc";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_plateno" on
|
||||||
|
"public"."jobs" using gin ("plate_no");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_plateno";
|
||||||
11
hasura/migrations/1726773072213_run_sql_migration/down.sql
Normal file
11
hasura/migrations/1726773072213_run_sql_migration/down.sql
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE
|
||||||
|
-- OR REPLACE VIEW "public"."jobs_inproduction" AS
|
||||||
|
-- SELECT
|
||||||
|
-- j.id,
|
||||||
|
-- j.updated_at
|
||||||
|
-- FROM
|
||||||
|
-- jobs j
|
||||||
|
-- WHERE
|
||||||
|
-- j.inproduction=true;
|
||||||
9
hasura/migrations/1726773072213_run_sql_migration/up.sql
Normal file
9
hasura/migrations/1726773072213_run_sql_migration/up.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
CREATE
|
||||||
|
OR REPLACE VIEW "public"."jobs_inproduction" AS
|
||||||
|
SELECT
|
||||||
|
j.id,
|
||||||
|
j.updated_at
|
||||||
|
FROM
|
||||||
|
jobs j
|
||||||
|
WHERE
|
||||||
|
j.inproduction=true;
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE OR REPLACE VIEW "public"."jobs_inproduction" AS
|
||||||
|
-- SELECT j.id,
|
||||||
|
-- j.updated_at,
|
||||||
|
-- j.shopid
|
||||||
|
-- FROM jobs j
|
||||||
|
-- WHERE (j.inproduction = true);
|
||||||
6
hasura/migrations/1726773316245_run_sql_migration/up.sql
Normal file
6
hasura/migrations/1726773316245_run_sql_migration/up.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
CREATE OR REPLACE VIEW "public"."jobs_inproduction" AS
|
||||||
|
SELECT j.id,
|
||||||
|
j.updated_at,
|
||||||
|
j.shopid
|
||||||
|
FROM jobs j
|
||||||
|
WHERE (j.inproduction = true);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE OR REPLACE VIEW "public"."jobs_inproduction" AS
|
||||||
|
-- SELECT j.id,
|
||||||
|
-- j.updated_at,
|
||||||
|
-- j.shopid
|
||||||
|
-- FROM jobs j
|
||||||
|
-- WHERE (j.inproduction = true);
|
||||||
6
hasura/migrations/1726773326353_run_sql_migration/up.sql
Normal file
6
hasura/migrations/1726773326353_run_sql_migration/up.sql
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
CREATE OR REPLACE VIEW "public"."jobs_inproduction" AS
|
||||||
|
SELECT j.id,
|
||||||
|
j.updated_at,
|
||||||
|
j.shopid
|
||||||
|
FROM jobs j
|
||||||
|
WHERE (j.inproduction = true);
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE INDEX idx_jobs_inproduction_true_cast ON jobs(inproduction) WHERE inproduction = ('true') :: boolean;
|
||||||
1
hasura/migrations/1726775434726_run_sql_migration/up.sql
Normal file
1
hasura/migrations/1726775434726_run_sql_migration/up.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CREATE INDEX idx_jobs_inproduction_true_cast ON jobs(inproduction) WHERE inproduction = ('true') :: boolean;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_inproduction_true_cast" on
|
||||||
|
"public"."jobs" using btree ("inproduction");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_inproduction_true_cast";
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE INDEX idx_jobs_created_at_desc ON jobs (created_at DESC);
|
||||||
1
hasura/migrations/1726868398933_run_sql_migration/up.sql
Normal file
1
hasura/migrations/1726868398933_run_sql_migration/up.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CREATE INDEX idx_jobs_created_at_desc ON jobs (created_at DESC);
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_jobs_vehicleid";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_jobs_vehicleid" on
|
||||||
|
"public"."jobs" using btree ("vehicleid");
|
||||||
34
hasura/migrations/1726871373784_run_sql_migration/down.sql
Normal file
34
hasura/migrations/1726871373784_run_sql_migration/down.sql
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE OR REPLACE FUNCTION public.search_exportlog(search text)
|
||||||
|
-- RETURNS SETOF exportlog
|
||||||
|
-- LANGUAGE plpgsql
|
||||||
|
-- STABLE
|
||||||
|
-- AS $function$ BEGIN IF search = '' THEN RETURN query
|
||||||
|
-- SELECT
|
||||||
|
-- *
|
||||||
|
-- FROM
|
||||||
|
-- exportlog e;
|
||||||
|
-- ELSE RETURN query
|
||||||
|
-- SELECT
|
||||||
|
-- e.*
|
||||||
|
-- FROM
|
||||||
|
-- exportlog e
|
||||||
|
-- LEFT JOIN jobs j on j.id = e.jobid
|
||||||
|
-- LEFT JOIN payments p
|
||||||
|
-- ON p.id = e.paymentid
|
||||||
|
-- LEFT JOIN bills b
|
||||||
|
-- ON e.billid = b.id
|
||||||
|
-- WHERE
|
||||||
|
-- (
|
||||||
|
-- j.ro_number ILIKE '%' || search
|
||||||
|
-- OR b.invoice_number ILIKE '%' || search
|
||||||
|
-- OR p.paymentnum ILIKE '%' || search
|
||||||
|
-- OR e.useremail ILIKE '%' || search
|
||||||
|
-- )
|
||||||
|
-- AND (e.jobid = j.id
|
||||||
|
-- or e.paymentid = p.id
|
||||||
|
-- or e.billid = b.id)
|
||||||
|
-- ;
|
||||||
|
-- END IF;
|
||||||
|
-- END $function$;
|
||||||
32
hasura/migrations/1726871373784_run_sql_migration/up.sql
Normal file
32
hasura/migrations/1726871373784_run_sql_migration/up.sql
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
CREATE OR REPLACE FUNCTION public.search_exportlog(search text)
|
||||||
|
RETURNS SETOF exportlog
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
STABLE
|
||||||
|
AS $function$ BEGIN IF search = '' THEN RETURN query
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
exportlog e;
|
||||||
|
ELSE RETURN query
|
||||||
|
SELECT
|
||||||
|
e.*
|
||||||
|
FROM
|
||||||
|
exportlog e
|
||||||
|
LEFT JOIN jobs j on j.id = e.jobid
|
||||||
|
LEFT JOIN payments p
|
||||||
|
ON p.id = e.paymentid
|
||||||
|
LEFT JOIN bills b
|
||||||
|
ON e.billid = b.id
|
||||||
|
WHERE
|
||||||
|
(
|
||||||
|
j.ro_number ILIKE '%' || search
|
||||||
|
OR b.invoice_number ILIKE '%' || search
|
||||||
|
OR p.paymentnum ILIKE '%' || search
|
||||||
|
OR e.useremail ILIKE '%' || search
|
||||||
|
)
|
||||||
|
AND (e.jobid = j.id
|
||||||
|
or e.paymentid = p.id
|
||||||
|
or e.billid = b.id)
|
||||||
|
;
|
||||||
|
END IF;
|
||||||
|
END $function$;
|
||||||
34
hasura/migrations/1726871384601_run_sql_migration/down.sql
Normal file
34
hasura/migrations/1726871384601_run_sql_migration/down.sql
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE OR REPLACE FUNCTION public.search_exportlog(search text)
|
||||||
|
-- RETURNS SETOF exportlog
|
||||||
|
-- LANGUAGE plpgsql
|
||||||
|
-- STABLE
|
||||||
|
-- AS $function$ BEGIN IF search = '' THEN RETURN query
|
||||||
|
-- SELECT
|
||||||
|
-- *
|
||||||
|
-- FROM
|
||||||
|
-- exportlog e;
|
||||||
|
-- ELSE RETURN query
|
||||||
|
-- SELECT
|
||||||
|
-- e.*
|
||||||
|
-- FROM
|
||||||
|
-- exportlog e
|
||||||
|
-- LEFT JOIN jobs j on j.id = e.jobid
|
||||||
|
-- LEFT JOIN payments p
|
||||||
|
-- ON p.id = e.paymentid
|
||||||
|
-- LEFT JOIN bills b
|
||||||
|
-- ON e.billid = b.id
|
||||||
|
-- WHERE
|
||||||
|
-- (
|
||||||
|
-- j.ro_number ILIKE '%' || search
|
||||||
|
-- OR b.invoice_number ILIKE '%' || search
|
||||||
|
-- OR p.paymentnum ILIKE '%' || search
|
||||||
|
-- OR e.useremail ILIKE '%' || search
|
||||||
|
-- )
|
||||||
|
-- AND (e.jobid = j.id
|
||||||
|
-- or e.paymentid = p.id
|
||||||
|
-- or e.billid = b.id)
|
||||||
|
-- ;
|
||||||
|
-- END IF;
|
||||||
|
-- END $function$;
|
||||||
32
hasura/migrations/1726871384601_run_sql_migration/up.sql
Normal file
32
hasura/migrations/1726871384601_run_sql_migration/up.sql
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
CREATE OR REPLACE FUNCTION public.search_exportlog(search text)
|
||||||
|
RETURNS SETOF exportlog
|
||||||
|
LANGUAGE plpgsql
|
||||||
|
STABLE
|
||||||
|
AS $function$ BEGIN IF search = '' THEN RETURN query
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
exportlog e;
|
||||||
|
ELSE RETURN query
|
||||||
|
SELECT
|
||||||
|
e.*
|
||||||
|
FROM
|
||||||
|
exportlog e
|
||||||
|
LEFT JOIN jobs j on j.id = e.jobid
|
||||||
|
LEFT JOIN payments p
|
||||||
|
ON p.id = e.paymentid
|
||||||
|
LEFT JOIN bills b
|
||||||
|
ON e.billid = b.id
|
||||||
|
WHERE
|
||||||
|
(
|
||||||
|
j.ro_number ILIKE '%' || search
|
||||||
|
OR b.invoice_number ILIKE '%' || search
|
||||||
|
OR p.paymentnum ILIKE '%' || search
|
||||||
|
OR e.useremail ILIKE '%' || search
|
||||||
|
)
|
||||||
|
AND (e.jobid = j.id
|
||||||
|
or e.paymentid = p.id
|
||||||
|
or e.billid = b.id)
|
||||||
|
;
|
||||||
|
END IF;
|
||||||
|
END $function$;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_bill_invoice_number";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_bill_invoice_number" on
|
||||||
|
"public"."bills" using btree ("invoice_number");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."idx_payments_paymentnum";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "idx_payments_paymentnum" on
|
||||||
|
"public"."payments" using btree ("paymentnum");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."exportlog_useremail";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "exportlog_useremail" on
|
||||||
|
"public"."exportlog" using btree ("useremail");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."available_jobs_jobid";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "available_jobs_jobid" on
|
||||||
|
"public"."available_jobs" using btree ("jobid");
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE INDEX idx_jobslines_ordering ON joblines (jobid, removed, line_no asc) where removed=false;
|
||||||
1
hasura/migrations/1726872195945_run_sql_migration/up.sql
Normal file
1
hasura/migrations/1726872195945_run_sql_migration/up.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CREATE INDEX idx_jobslines_ordering ON joblines (jobid, removed, line_no asc) where removed=false;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE INDEX idx_joblines_types ON joblines (jobid, mod_lbr_ty, removed) where removed=false;
|
||||||
1
hasura/migrations/1726872572029_run_sql_migration/up.sql
Normal file
1
hasura/migrations/1726872572029_run_sql_migration/up.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CREATE INDEX idx_joblines_types ON joblines (jobid, mod_lbr_ty, removed) where removed=false;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- CREATE INDEX idx_exportlog_created_at_desc ON exportlog (created_at desc);
|
||||||
1
hasura/migrations/1726872872872_run_sql_migration/up.sql
Normal file
1
hasura/migrations/1726872872872_run_sql_migration/up.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
CREATE INDEX idx_exportlog_created_at_desc ON exportlog (created_at desc);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "joblines_idx_removed" on
|
||||||
|
"public"."joblines" using btree ("removed");
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user