Compare commits
261 Commits
release/20
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d2c3c81c7 | ||
|
|
094160ebf3 | ||
|
|
c15e69f079 | ||
|
|
3c4902f71f | ||
|
|
209245187f | ||
|
|
8f91416623 | ||
|
|
a18dbbb6c4 | ||
|
|
57d8ca5829 | ||
|
|
4c6a2d6d63 | ||
|
|
5861d0e9b6 | ||
|
|
e36904794b | ||
|
|
1c89d12034 | ||
|
|
5e36a4ae89 | ||
|
|
f553307587 | ||
|
|
2c80c81197 | ||
|
|
9d865cf130 | ||
|
|
8e119ce0dd | ||
|
|
fe49161718 | ||
|
|
040e366335 | ||
|
|
4655663dd8 | ||
|
|
6e1fbda79b | ||
|
|
b2f616f1eb | ||
|
|
76eec7bebc | ||
|
|
aa5f405e1b | ||
|
|
ca9752d119 | ||
|
|
45b4af5225 | ||
|
|
d2d310cf57 | ||
|
|
5d1a7657a9 | ||
|
|
5cb17994cd | ||
|
|
dab78e3dc9 | ||
|
|
1232f28b3d | ||
|
|
8e8d40d4b0 | ||
|
|
7fae408454 | ||
|
|
1cdafaa2cc | ||
|
|
b9ca7ef2e3 | ||
|
|
60867ae4dc | ||
|
|
b0ddb62ac0 | ||
|
|
39a4646339 | ||
|
|
584322819f | ||
|
|
051ee347a9 | ||
|
|
acf1b387de | ||
|
|
d350515c90 | ||
|
|
121e579388 | ||
|
|
cf5ebb8130 | ||
|
|
2dabf3c811 | ||
|
|
04509fa587 | ||
|
|
56fef0f43c | ||
|
|
42702ef015 | ||
|
|
25bee3cfdf | ||
|
|
baf06fee6c | ||
|
|
a3557bbc86 | ||
|
|
3e00e7981d | ||
|
|
12fa270a1a | ||
|
|
de250b152a | ||
|
|
c45741257f | ||
|
|
3988386c79 | ||
|
|
492032c1e2 | ||
|
|
8222e56485 | ||
|
|
49a61e1564 | ||
|
|
eed18aa1c5 | ||
|
|
2de3f8b022 | ||
|
|
91476c7ad3 | ||
|
|
00eb7926f9 | ||
|
|
854ad21b20 | ||
|
|
3c3f9521f6 | ||
|
|
561bcf10d9 | ||
|
|
75d9faa05b | ||
|
|
ac72177fbb | ||
|
|
088faf152c | ||
|
|
90cba9ed24 | ||
|
|
a0702785c5 | ||
|
|
6898d609fe | ||
|
|
d70893e2ba | ||
|
|
6155b8bf24 | ||
|
|
239dc5c62d | ||
|
|
2586855f11 | ||
|
|
b3b3c4c737 | ||
|
|
abe5fadeea | ||
|
|
08e5543536 | ||
|
|
f1a10e0df4 | ||
|
|
7dc3c00628 | ||
|
|
1c5c403d65 | ||
|
|
7594f53e88 | ||
|
|
b861957342 | ||
|
|
2bf24ff5a1 | ||
|
|
6e5fcbfdbd | ||
|
|
759a8ac58c | ||
|
|
833baca9cc | ||
|
|
889ef61185 | ||
|
|
add1eddbc1 | ||
|
|
1c63aa39c4 | ||
|
|
0cabd80b94 | ||
|
|
7f756bab88 | ||
|
|
99b847822f | ||
|
|
f66d9b8c09 | ||
|
|
5660de42af | ||
|
|
ccbe92c275 | ||
|
|
b0ea8a71fb | ||
|
|
060871306f | ||
|
|
2eb4e142ff | ||
|
|
adf8cf9e8d | ||
|
|
852fd9c388 | ||
|
|
e921f28105 | ||
|
|
6db68b76db | ||
|
|
51ebfd86e7 | ||
|
|
79a90bb9ee | ||
|
|
1664f9c935 | ||
|
|
23fcdd6375 | ||
|
|
ea7c22daec | ||
|
|
10ffb33ec9 | ||
|
|
f9e023f922 | ||
|
|
c7832bdd82 | ||
|
|
329bdbe22d | ||
|
|
2df046c39d | ||
|
|
46065f1986 | ||
|
|
66b3fb6988 | ||
|
|
5eda224393 | ||
|
|
e387abcd14 | ||
|
|
4c2d4e20a6 | ||
|
|
3d26c2e94e | ||
|
|
d9e2ef9300 | ||
|
|
b00fdadc1b | ||
|
|
4d5e06b9fc | ||
|
|
ad42dd1295 | ||
|
|
1f4c1c9e92 | ||
|
|
2938b9c94c | ||
|
|
2227acab3a | ||
|
|
bde17446ad | ||
|
|
081165b6f5 | ||
|
|
7e717c0b1f | ||
|
|
e242aaa9f5 | ||
|
|
fe60538acf | ||
|
|
2db88f57df | ||
|
|
7461e58000 | ||
|
|
cd0b7a4e56 | ||
|
|
2a3b4e89ab | ||
|
|
1d77eda3e2 | ||
|
|
490e1f696a | ||
|
|
b96c618f54 | ||
|
|
1afda01d34 | ||
|
|
b9d11580d4 | ||
|
|
27fadb9ae2 | ||
|
|
4c5a2cefe9 | ||
|
|
175692559c | ||
|
|
57b27f73c3 | ||
|
|
7badb09ba1 | ||
|
|
c39f1d824a | ||
|
|
132cf98a37 | ||
|
|
59f71d53cd | ||
|
|
f4b3a990d7 | ||
|
|
20371ea00d | ||
|
|
3086a654a1 | ||
|
|
60768c8847 | ||
|
|
a68f8d6880 | ||
|
|
0cad64ff6d | ||
|
|
522665256e | ||
|
|
d3fe2c9d06 | ||
|
|
f080e84985 | ||
|
|
2a0ad46eea | ||
|
|
3a83160b33 | ||
|
|
7725080a11 | ||
|
|
701c532e48 | ||
|
|
1932795f55 | ||
|
|
cc7bd1c792 | ||
|
|
7799d93f3d | ||
|
|
a7cf36d5f8 | ||
|
|
54cc02068c | ||
|
|
f575870685 | ||
|
|
171b61b92f | ||
|
|
de44116940 | ||
|
|
3c0a883326 | ||
|
|
14d6cc94dd | ||
|
|
c0d9bacf1d | ||
|
|
d787821345 | ||
|
|
ed6eab4c38 | ||
|
|
b12c9407d9 | ||
|
|
300aee5b02 | ||
|
|
357f40bdc2 | ||
|
|
0a93551db4 | ||
|
|
8602ccbb8a | ||
|
|
d7b0e3046b | ||
|
|
30689a8ca6 | ||
|
|
0e06b449cb | ||
|
|
8e8208dd9a | ||
|
|
79e2fecb24 | ||
|
|
86e909e4e9 | ||
|
|
c7ff893397 | ||
|
|
3981b8684c | ||
|
|
1fb856f95f | ||
|
|
c62c3fa938 | ||
|
|
554ec37ace | ||
|
|
be4feca990 | ||
|
|
ec45454b3d | ||
|
|
0e78cb47f9 | ||
|
|
e5b8d003ec | ||
|
|
2eb81dde37 | ||
|
|
614549a545 | ||
|
|
5717727d2a | ||
|
|
f3714cea1e | ||
|
|
a3375e6152 | ||
|
|
f48fb7130e | ||
|
|
1460fa6fd7 | ||
|
|
3d9a07bd39 | ||
|
|
bd4aa4027a | ||
|
|
9fa995f002 | ||
|
|
3ed48b26f1 | ||
|
|
d585cacdfc | ||
|
|
55ddaca328 | ||
|
|
3fc7af9780 | ||
|
|
146bf95e51 | ||
|
|
58defad2ea | ||
|
|
9c40a03a06 | ||
|
|
a1b6ccc23d | ||
|
|
9b4247d6f6 | ||
|
|
8a6d94f193 | ||
|
|
6e7d1abd70 | ||
|
|
6bd74aae87 | ||
|
|
f21caa10fc | ||
|
|
dde6f17029 | ||
|
|
1aceef9153 | ||
|
|
678892d134 | ||
|
|
dc187bbf24 | ||
|
|
09aae78715 | ||
|
|
c42276ab3a | ||
|
|
41d25cbc52 | ||
|
|
085c27ad20 | ||
|
|
38e6b5010e | ||
|
|
242c275e7d | ||
|
|
1dc6130fdf | ||
|
|
910afbf48d | ||
|
|
9d9edfd674 | ||
|
|
62a5b49836 | ||
|
|
e93e138f78 | ||
|
|
4639e31e55 | ||
|
|
e8fde14f9b | ||
|
|
90e87adc34 | ||
|
|
81053b3cbf | ||
|
|
f4290bf20c | ||
|
|
5371657aa4 | ||
|
|
599f4e143c | ||
|
|
94440e5c48 | ||
|
|
aa5d6f2090 | ||
|
|
6bde1b1baf | ||
|
|
fc404b1f3b | ||
|
|
c6ba3fd8f0 | ||
|
|
119904ca2b | ||
|
|
f7e1b023df | ||
|
|
5855569194 | ||
|
|
4f852e7493 | ||
|
|
deec40a89c | ||
|
|
145dd9bec6 | ||
|
|
b8e5d4412f | ||
|
|
277fb8f839 | ||
|
|
d3d5485846 | ||
|
|
55091d61d6 | ||
|
|
5b5df8a3a1 | ||
|
|
ccf48cfcf1 | ||
|
|
c89342b6ef | ||
|
|
e97ceb7cbe | ||
|
|
de34cbd937 | ||
|
|
cf7a1b0168 |
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,4 @@
|
||||
GENERATE_SOURCEMAP=false
|
||||
REACT_APP_GRAPHQL_ENDPOINT=https://db.imex.online/v1/graphql
|
||||
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.imex.online/v1/graphql
|
||||
REACT_APP_GA_CODE=231103507
|
||||
|
||||
@@ -46,10 +46,11 @@
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-drag-listview": "^0.2.1",
|
||||
"react-grid-gallery": "^0.5.5",
|
||||
"react-grid-gallery": "^1.0.0",
|
||||
"react-grid-layout": "^1.3.4",
|
||||
"react-i18next": "^12.2.0",
|
||||
"react-icons": "^4.7.1",
|
||||
"react-image-lightbox": "^5.1.4",
|
||||
"react-number-format": "^5.1.3",
|
||||
"react-redux": "^8.0.5",
|
||||
"react-resizable": "^3.0.4",
|
||||
|
||||
@@ -143,13 +143,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Update row highlighting on production board.
|
||||
//Update row highlighting on production board.
|
||||
.ant-table-tbody > tr.ant-table-row:hover > td {
|
||||
background: #eaeaea !important;
|
||||
}
|
||||
|
||||
.job-line-manual{
|
||||
.job-line-manual {
|
||||
color: tomato;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
td.ant-table-column-sort {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { DELETE_BILL } from "../../graphql/bills.queries";
|
||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||
|
||||
export default function BillDeleteButton({ bill }) {
|
||||
export default function BillDeleteButton({ bill, callback }) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const [deleteBill] = useMutation(DELETE_BILL);
|
||||
@@ -36,6 +36,8 @@ export default function BillDeleteButton({ bill }) {
|
||||
|
||||
if (!!!result.errors) {
|
||||
notification["success"]({ message: t("bills.successes.deleted") });
|
||||
|
||||
if (callback && typeof callback === "function") callback(bill.id);
|
||||
} else {
|
||||
//Check if it's an fkey violation.
|
||||
const error = JSON.stringify(result.errors);
|
||||
|
||||
@@ -7,7 +7,9 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectBreadcrumbs } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import GlobalSearch from "../global-search/global-search.component";
|
||||
import GlobalSearchOs from "../global-search/global-search-os.component";
|
||||
import "./breadcrumbs.styles.scss";
|
||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
breadcrumbs: selectBreadcrumbs,
|
||||
@@ -15,6 +17,12 @@ const mapStateToProps = createStructuredSelector({
|
||||
});
|
||||
|
||||
export function BreadCrumbs({ breadcrumbs, bodyshop }) {
|
||||
const { OpenSearch } = useTreatments(
|
||||
["OpenSearch"],
|
||||
{},
|
||||
bodyshop && bodyshop.imexshopid
|
||||
);
|
||||
|
||||
return (
|
||||
<Row className="breadcrumb-container">
|
||||
<Col xs={24} sm={24} md={16}>
|
||||
@@ -38,7 +46,7 @@ export function BreadCrumbs({ breadcrumbs, bodyshop }) {
|
||||
</Breadcrumb>
|
||||
</Col>
|
||||
<Col xs={24} sm={24} md={8}>
|
||||
<GlobalSearch />
|
||||
{OpenSearch.treatment === "on" ? <GlobalSearchOs /> : <GlobalSearch />}
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
|
||||
@@ -10,7 +10,10 @@ export default function CABCpvrtCalculator({ disabled, form }) {
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("job_ca_bc_pvrt_calculate");
|
||||
form.setFieldsValue({ ca_bc_pvrt: ((values.rate||0) * (values.days||0)).toFixed(2) });
|
||||
form.setFieldsValue({
|
||||
ca_bc_pvrt: ((values.rate || 0) * (values.days || 0)).toFixed(2),
|
||||
});
|
||||
form.setFields([{ name: "ca_bc_pvrt", touched: true }]);
|
||||
setVisibility(false);
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,216 @@
|
||||
import { AutoComplete, Divider, Input, Space } from "antd";
|
||||
import axios from "axios";
|
||||
import _ from "lodash";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link, useHistory } from "react-router-dom";
|
||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||
import OwnerNameDisplay, {
|
||||
OwnerNameDisplayFunction,
|
||||
} from "../owner-name-display/owner-name-display.component";
|
||||
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
|
||||
|
||||
export default function GlobalSearchOs() {
|
||||
const { t } = useTranslation();
|
||||
const history = useHistory();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [data, setData] = useState(false);
|
||||
|
||||
const executeSearch = async (v) => {
|
||||
if (v && v && v !== "" && v.length >= 3) {
|
||||
try {
|
||||
setLoading(true);
|
||||
const searchData = await axios.post("/search", {
|
||||
search: v,
|
||||
});
|
||||
|
||||
const resultsByType = {
|
||||
payments: [],
|
||||
jobs: [],
|
||||
bills: [],
|
||||
owners: [],
|
||||
vehicles: [],
|
||||
};
|
||||
|
||||
searchData.data.hits.hits.forEach((hit) => {
|
||||
resultsByType[hit._index].push(hit._source);
|
||||
});
|
||||
setData([
|
||||
{
|
||||
label: renderTitle(t("menus.header.search.jobs")),
|
||||
options: resultsByType.jobs.map((job) => {
|
||||
return {
|
||||
key: job.id,
|
||||
value: job.ro_number || "N/A",
|
||||
label: (
|
||||
<Link to={`/manage/jobs/${job.id}`}>
|
||||
<Space size="small" split={<Divider type="vertical" />}>
|
||||
<strong>{job.ro_number || t("general.labels.na")}</strong>
|
||||
<span>{`${job.status || ""}`}</span>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={job} />
|
||||
</span>
|
||||
<span>{`${job.v_model_yr || ""} ${
|
||||
job.v_make_desc || ""
|
||||
} ${job.v_model_desc || ""}`}</span>
|
||||
<span>{`${job.clm_no || ""}`}</span>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: renderTitle(t("menus.header.search.owners")),
|
||||
options: resultsByType.owners.map((owner) => {
|
||||
return {
|
||||
key: owner.id,
|
||||
value: OwnerNameDisplayFunction(owner),
|
||||
label: (
|
||||
<Link to={`/manage/owners/${owner.id}`}>
|
||||
<Space
|
||||
size="small"
|
||||
split={<Divider type="vertical" />}
|
||||
wrap
|
||||
>
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={owner} />
|
||||
</span>
|
||||
<PhoneNumberFormatter>
|
||||
{owner.ownr_ph1}
|
||||
</PhoneNumberFormatter>
|
||||
<PhoneNumberFormatter>
|
||||
{owner.ownr_ph2}
|
||||
</PhoneNumberFormatter>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: renderTitle(t("menus.header.search.vehicles")),
|
||||
options: resultsByType.vehicles.map((vehicle) => {
|
||||
return {
|
||||
key: vehicle.id,
|
||||
value: `${vehicle.v_model_yr || ""} ${
|
||||
vehicle.v_make_desc || ""
|
||||
} ${vehicle.v_model_desc || ""}`,
|
||||
label: (
|
||||
<Link to={`/manage/vehicles/${vehicle.id}`}>
|
||||
<Space size="small" split={<Divider type="vertical" />}>
|
||||
<span>
|
||||
{`${vehicle.v_model_yr || ""} ${
|
||||
vehicle.v_make_desc || ""
|
||||
} ${vehicle.v_model_desc || ""}`}
|
||||
</span>
|
||||
<span>{vehicle.plate_no || ""}</span>
|
||||
<span>
|
||||
<VehicleVinDisplay>
|
||||
{vehicle.v_vin || ""}
|
||||
</VehicleVinDisplay>
|
||||
</span>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: renderTitle(t("menus.header.search.payments")),
|
||||
options: resultsByType.payments.map((payment) => {
|
||||
return {
|
||||
key: payment.id,
|
||||
value: `${payment.job?.ro_number} ${payment.amount}`,
|
||||
label: (
|
||||
<Link to={`/manage/jobs/${payment.job?.id}`}>
|
||||
<Space size="small" split={<Divider type="vertical" />}>
|
||||
<span>{payment.paymentnum}</span>
|
||||
<span>{payment.job?.ro_number}</span>
|
||||
<span>{payment.memo || ""}</span>
|
||||
<span>{payment.amount || ""}</span>
|
||||
<span>{payment.transactionid || ""}</span>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
};
|
||||
}),
|
||||
},
|
||||
{
|
||||
label: renderTitle(t("menus.header.search.bills")),
|
||||
options: resultsByType.bills.map((bill) => {
|
||||
return {
|
||||
key: bill.id,
|
||||
value: `${bill.invoice_number} - ${bill.vendor.name}`,
|
||||
label: (
|
||||
<Link to={`/manage/bills?billid=${bill.id}`}>
|
||||
<Space size="small" split={<Divider type="vertical" />}>
|
||||
<span>{bill.invoice_number}</span>
|
||||
<span>{bill.vendor.name}</span>
|
||||
<span>{bill.date}</span>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
};
|
||||
}),
|
||||
},
|
||||
// {
|
||||
// label: renderTitle(t("menus.header.search.phonebook")),
|
||||
// options: resultsByType.search_phonebook.map((pb) => {
|
||||
// return {
|
||||
// key: pb.id,
|
||||
// value: `${pb.firstname || ""} ${pb.lastname || ""} ${
|
||||
// pb.company || ""
|
||||
// }`,
|
||||
// label: (
|
||||
// <Link to={`/manage/phonebook?phonebookentry=${pb.id}`}>
|
||||
// <Space size="small" split={<Divider type="vertical" />}>
|
||||
// <span>{`${pb.firstname || ""} ${pb.lastname || ""} ${
|
||||
// pb.company || ""
|
||||
// }`}</span>
|
||||
// <PhoneNumberFormatter>{pb.phone1}</PhoneNumberFormatter>
|
||||
// <span>{pb.email}</span>
|
||||
// </Space>
|
||||
// </Link>
|
||||
// ),
|
||||
// };
|
||||
// }),
|
||||
// },
|
||||
]);
|
||||
} catch (error) {
|
||||
console.log("Error while fetching search results", error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
const debouncedExecuteSearch = _.debounce(executeSearch, 750);
|
||||
|
||||
const handleSearch = (value) => {
|
||||
debouncedExecuteSearch(value);
|
||||
};
|
||||
|
||||
const renderTitle = (title) => {
|
||||
return <span>{title}</span>;
|
||||
};
|
||||
|
||||
return (
|
||||
<AutoComplete
|
||||
options={data}
|
||||
onSearch={handleSearch}
|
||||
defaultActiveFirstOption
|
||||
onSelect={(val, opt) => {
|
||||
history.push(opt.label.props.to);
|
||||
}}
|
||||
onClear={() => setData([])}
|
||||
>
|
||||
<Input.Search
|
||||
size="large"
|
||||
placeholder={t("general.labels.globalsearch")}
|
||||
enterButton
|
||||
allowClear
|
||||
loading={loading}
|
||||
/>
|
||||
</AutoComplete>
|
||||
);
|
||||
}
|
||||
@@ -8,7 +8,7 @@ import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import OwnerNameDisplay, {
|
||||
OwnerNameDisplayFunction
|
||||
OwnerNameDisplayFunction,
|
||||
} from "../owner-name-display/owner-name-display.component";
|
||||
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
|
||||
export default function GlobalSearch() {
|
||||
@@ -18,11 +18,18 @@ export default function GlobalSearch() {
|
||||
useLazyQuery(GLOBAL_SEARCH_QUERY);
|
||||
|
||||
const executeSearch = (v) => {
|
||||
if (v && v.variables.search && v.variables.search !== "") callSearch(v);
|
||||
if (
|
||||
v &&
|
||||
v.variables.search &&
|
||||
v.variables.search !== "" &&
|
||||
v.variables.search.length >= 3
|
||||
)
|
||||
callSearch(v);
|
||||
};
|
||||
const debouncedExecuteSearch = _.debounce(executeSearch, 750);
|
||||
|
||||
const handleSearch = (value) => {
|
||||
console.log("Handle Search");
|
||||
debouncedExecuteSearch({ variables: { search: value } });
|
||||
};
|
||||
|
||||
@@ -37,7 +44,7 @@ export default function GlobalSearch() {
|
||||
options: data.search_jobs.map((job) => {
|
||||
return {
|
||||
key: job.id,
|
||||
value: job.ro_number,
|
||||
value: job.ro_number || "N/A",
|
||||
label: (
|
||||
<Link to={`/manage/jobs/${job.id}`}>
|
||||
<Space size="small" split={<Divider type="vertical" />}>
|
||||
|
||||
@@ -99,7 +99,7 @@ export function JobPayments({
|
||||
render: (text, record) => (
|
||||
<Space wrap>
|
||||
<Button
|
||||
disabled={record.exportedat}
|
||||
// disabled={record.exportedat}
|
||||
onClick={() => {
|
||||
setPaymentContext({
|
||||
actions: { refetch: refetch },
|
||||
|
||||
@@ -109,8 +109,8 @@ export function JobsConvertButton({
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{bodyshop.md_ins_cos.map((s) => (
|
||||
<Select.Option key={s.name} value={s.name}>
|
||||
{bodyshop.md_ins_cos.map((s, i) => (
|
||||
<Select.Option key={i} value={s.name}>
|
||||
{s.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
@@ -219,13 +219,15 @@ export function JobsConvertButton({
|
||||
</Select>
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_gst_registrant")}
|
||||
name="ca_gst_registrant"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_gst_registrant")}
|
||||
name="ca_gst_registrant"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.driveable")}
|
||||
name="driveable"
|
||||
|
||||
@@ -224,13 +224,15 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
||||
>
|
||||
<CurrencyInput />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_gst_registrant")}
|
||||
name="ca_gst_registrant"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_gst_registrant")}
|
||||
name="ca_gst_registrant"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.other_amount_payable")}
|
||||
name="other_amount_payable"
|
||||
|
||||
@@ -40,24 +40,26 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Tooltip title={t("jobs.labels.ca_gst_all_if_null")}>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_customer_gst")}
|
||||
name="ca_customer_gst"
|
||||
>
|
||||
<CurrencyInput
|
||||
disabled={jobRO}
|
||||
min={0}
|
||||
max={
|
||||
Math.round(
|
||||
(job.job_totals &&
|
||||
job.job_totals.totals.federal_tax.amount) ||
|
||||
0
|
||||
) / 100
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Tooltip>
|
||||
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
|
||||
<Tooltip title={t("jobs.labels.ca_gst_all_if_null")}>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_customer_gst")}
|
||||
name="ca_customer_gst"
|
||||
>
|
||||
<CurrencyInput
|
||||
disabled={jobRO}
|
||||
min={0}
|
||||
max={
|
||||
Math.round(
|
||||
(job.job_totals &&
|
||||
job.job_totals.totals.federal_tax.amount) ||
|
||||
0
|
||||
) / 100
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.other_amount_payable")}
|
||||
name="other_amount_payable"
|
||||
@@ -82,12 +84,14 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
>
|
||||
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid} />
|
||||
</Form.Item>
|
||||
<Space align="end">
|
||||
<Form.Item label={t("jobs.fields.ca_bc_pvrt")} name="ca_bc_pvrt">
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
||||
</Space>
|
||||
{bodyshop.region_config === "CA_BC" && (
|
||||
<Space align="center">
|
||||
<Form.Item label={t("jobs.fields.ca_bc_pvrt")} name="ca_bc_pvrt">
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
||||
</Space>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.auto_add_ats")}
|
||||
name="auto_add_ats"
|
||||
@@ -141,13 +145,15 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
>
|
||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_gst_registrant")}
|
||||
name="ca_gst_registrant"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch disabled={jobRO} />
|
||||
</Form.Item>
|
||||
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_gst_registrant")}
|
||||
name="ca_gst_registrant"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch disabled={jobRO} />
|
||||
</Form.Item>
|
||||
)}
|
||||
</FormRow>
|
||||
<Divider
|
||||
orientation="left"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { EditFilled, FileExcelFilled, SyncOutlined } from "@ant-design/icons";
|
||||
import { Button, Card, Col, Row, Space } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Gallery from "react-grid-gallery";
|
||||
import { Gallery } from "react-grid-gallery";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import DocumentsUploadComponent from "../documents-upload/documents-upload.component";
|
||||
import { DetermineFileType } from "../documents-upload/documents-upload.utility";
|
||||
@@ -11,6 +11,9 @@ import JobsDocumentsGalleryReassign from "./jobs-document-gallery.reassign.compo
|
||||
import JobsDocumentsDeleteButton from "./jobs-documents-gallery.delete.component";
|
||||
import JobsDocumentsGallerySelectAllComponent from "./jobs-documents-gallery.selectall.component";
|
||||
|
||||
import Lightbox from "react-image-lightbox";
|
||||
import "react-image-lightbox/style.css";
|
||||
|
||||
function JobsDocumentsComponent({
|
||||
data,
|
||||
jobId,
|
||||
@@ -23,11 +26,7 @@ function JobsDocumentsComponent({
|
||||
}) {
|
||||
const [galleryImages, setgalleryImages] = useState({ images: [], other: [] });
|
||||
const { t } = useTranslation();
|
||||
const [index, setIndex] = useState(0);
|
||||
|
||||
const onCurrentImageChange = (index) => {
|
||||
setIndex(index);
|
||||
};
|
||||
const [modalState, setModalState] = useState({ open: false, index: 0 });
|
||||
|
||||
useEffect(() => {
|
||||
let documents = data.reduce(
|
||||
@@ -35,14 +34,16 @@ function JobsDocumentsComponent({
|
||||
const fileType = DetermineFileType(value.type);
|
||||
if (value.type.startsWith("image")) {
|
||||
acc.images.push({
|
||||
src: GenerateSrcUrl(value),
|
||||
thumbnail: GenerateThumbUrl(value),
|
||||
thumbnailHeight: 225,
|
||||
thumbnailWidth: 225,
|
||||
// src: GenerateSrcUrl(value),
|
||||
src: GenerateThumbUrl(value),
|
||||
// src: GenerateSrcUrl(value),
|
||||
// thumbnail: GenerateThumbUrl(value),
|
||||
fullsize: GenerateSrcUrl(value),
|
||||
height: 225,
|
||||
width: 225,
|
||||
isSelected: false,
|
||||
key: value.key,
|
||||
extension: value.extension,
|
||||
|
||||
id: value.id,
|
||||
type: value.type,
|
||||
size: value.size,
|
||||
@@ -62,7 +63,7 @@ function JobsDocumentsComponent({
|
||||
const fileName = value.key.split("/").pop();
|
||||
acc.other.push({
|
||||
source: GenerateSrcUrl(value),
|
||||
src: "",
|
||||
src: thumb,
|
||||
thumbnail: thumb,
|
||||
tags: [
|
||||
{
|
||||
@@ -85,10 +86,9 @@ function JobsDocumentsComponent({
|
||||
]
|
||||
: []),
|
||||
],
|
||||
thumbnailHeight: 225,
|
||||
thumbnailWidth: 225,
|
||||
height: 225,
|
||||
width: 225,
|
||||
isSelected: false,
|
||||
|
||||
extension: value.extension,
|
||||
key: value.key,
|
||||
id: value.id,
|
||||
@@ -148,35 +148,15 @@ function JobsDocumentsComponent({
|
||||
<Card title={t("jobs.labels.documents-images")}>
|
||||
<Gallery
|
||||
images={galleryImages.images}
|
||||
backdropClosesModal={true}
|
||||
currentImageWillChange={onCurrentImageChange}
|
||||
customControls={[
|
||||
<Button
|
||||
key="edit-button"
|
||||
style={{
|
||||
float: "right",
|
||||
zIndex: "5",
|
||||
}}
|
||||
onClick={() => {
|
||||
const newWindow = window.open(
|
||||
`${window.location.protocol}//${window.location.host}/edit?documentId=${galleryImages.images[index].id}`,
|
||||
"_blank",
|
||||
"noopener,noreferrer"
|
||||
);
|
||||
if (newWindow) newWindow.opener = null;
|
||||
}}
|
||||
>
|
||||
<EditFilled />
|
||||
</Button>,
|
||||
]}
|
||||
onClickImage={(props) => {
|
||||
window.open(
|
||||
props.target.src,
|
||||
"_blank",
|
||||
"toolbar=0,location=0,menubar=0"
|
||||
);
|
||||
onClick={(index, item) => {
|
||||
setModalState({ open: true, index: index });
|
||||
// window.open(
|
||||
// item.fullsize,
|
||||
// "_blank",
|
||||
// "toolbar=0,location=0,menubar=0"
|
||||
// );
|
||||
}}
|
||||
onSelectImage={(index, image) => {
|
||||
onSelect={(index, image) => {
|
||||
setgalleryImages({
|
||||
...galleryImages,
|
||||
images: galleryImages.images.map((g, idx) =>
|
||||
@@ -191,8 +171,6 @@ function JobsDocumentsComponent({
|
||||
<Card title={t("jobs.labels.documents-other")}>
|
||||
<Gallery
|
||||
images={galleryImages.other}
|
||||
backdropClosesModal={true}
|
||||
enableLightbox={false}
|
||||
thumbnailStyle={() => {
|
||||
return {
|
||||
backgroundImage: <FileExcelFilled />,
|
||||
@@ -201,14 +179,14 @@ function JobsDocumentsComponent({
|
||||
cursor: "pointer",
|
||||
};
|
||||
}}
|
||||
onClickThumbnail={(index) => {
|
||||
onClick={(index) => {
|
||||
window.open(
|
||||
galleryImages.other[index].source,
|
||||
"_blank",
|
||||
"toolbar=0,location=0,menubar=0"
|
||||
);
|
||||
}}
|
||||
onSelectImage={(index) => {
|
||||
onSelect={(index) => {
|
||||
setgalleryImages({
|
||||
...galleryImages,
|
||||
other: galleryImages.other.map((g, idx) =>
|
||||
@@ -219,6 +197,53 @@ function JobsDocumentsComponent({
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
{modalState.open && (
|
||||
<Lightbox
|
||||
toolbarButtons={[
|
||||
<EditFilled
|
||||
onClick={() => {
|
||||
const newWindow = window.open(
|
||||
`${window.location.protocol}//${
|
||||
window.location.host
|
||||
}/edit?documentId=${
|
||||
galleryImages.images[modalState.index].id
|
||||
}`,
|
||||
"_blank",
|
||||
"noopener,noreferrer"
|
||||
);
|
||||
if (newWindow) newWindow.opener = null;
|
||||
}}
|
||||
/>,
|
||||
]}
|
||||
mainSrc={galleryImages.images[modalState.index].fullsize}
|
||||
nextSrc={
|
||||
galleryImages.images[
|
||||
(modalState.index + 1) % galleryImages.images.length
|
||||
].fullsize
|
||||
}
|
||||
prevSrc={
|
||||
galleryImages.images[
|
||||
(modalState.index + galleryImages.images.length - 1) %
|
||||
galleryImages.images.length
|
||||
].fullsize
|
||||
}
|
||||
onCloseRequest={() => setModalState({ open: false, index: 0 })}
|
||||
onMovePrevRequest={() =>
|
||||
setModalState({
|
||||
...modalState,
|
||||
index:
|
||||
(modalState.index + galleryImages.images.length - 1) %
|
||||
galleryImages.images.length,
|
||||
})
|
||||
}
|
||||
onMoveNextRequest={() =>
|
||||
setModalState({
|
||||
...modalState,
|
||||
index: (modalState.index + 1) % galleryImages.images.length,
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect } from "react";
|
||||
import Gallery from "react-grid-gallery";
|
||||
import { Gallery } from "react-grid-gallery";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { GenerateSrcUrl, GenerateThumbUrl } from "./job-documents.utility";
|
||||
import { GenerateThumbUrl } from "./job-documents.utility";
|
||||
|
||||
function JobsDocumentGalleryExternal({
|
||||
data,
|
||||
@@ -15,8 +15,8 @@ function JobsDocumentGalleryExternal({
|
||||
let documents = data.reduce((acc, value) => {
|
||||
if (value.type.startsWith("image")) {
|
||||
acc.push({
|
||||
src: GenerateSrcUrl(value),
|
||||
thumbnail: GenerateThumbUrl(value),
|
||||
//src: GenerateSrcUrl(value),
|
||||
src: GenerateThumbUrl(value),
|
||||
thumbnailHeight: 225,
|
||||
thumbnailWidth: 225,
|
||||
isSelected: false,
|
||||
@@ -39,7 +39,7 @@ function JobsDocumentGalleryExternal({
|
||||
<Gallery
|
||||
images={galleryImages}
|
||||
backdropClosesModal={true}
|
||||
onSelectImage={(index, image) => {
|
||||
onSelect={(index, image) => {
|
||||
setgalleryImages(
|
||||
galleryImages.map((g, idx) =>
|
||||
index === idx ? { ...g, isSelected: !g.isSelected } : g
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SyncOutlined, FileExcelFilled } from "@ant-design/icons";
|
||||
import { Alert, Button, Card, Space } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import Gallery from "react-grid-gallery";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Gallery } from "react-grid-gallery";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -19,6 +19,9 @@ import JobsLocalGalleryDownloadButton from "./jobs-documents-local-gallery.downl
|
||||
import JobsDocumentsLocalGalleryReassign from "./jobs-documents-local-gallery.reassign.component";
|
||||
import JobsDocumentsLocalGallerySelectAllComponent from "./jobs-documents-local-gallery.selectall.component";
|
||||
|
||||
import Lightbox from "react-image-lightbox";
|
||||
import "react-image-lightbox/style.css";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
allMedia: selectAllMedia,
|
||||
@@ -49,6 +52,7 @@ export function JobsDocumentsLocalGallery({
|
||||
vendorid,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [modalState, setModalState] = useState({ open: false, index: 0 });
|
||||
useEffect(() => {
|
||||
if (job) {
|
||||
if (invoice_number) {
|
||||
@@ -70,12 +74,20 @@ export function JobsDocumentsLocalGallery({
|
||||
) {
|
||||
acc.images.push({
|
||||
...val,
|
||||
fullsize: val.src,
|
||||
src: val.thumbnail,
|
||||
height: val.thumbnailHeight,
|
||||
width: val.thumbnailWidth,
|
||||
...(val.optimized && { src: val.optimized, fullsize: val.src }),
|
||||
});
|
||||
if (val.optimized) optimized = true;
|
||||
} else {
|
||||
acc.other.push({
|
||||
...val,
|
||||
fullsize: val.src,
|
||||
src: val.thumbnail,
|
||||
height: val.thumbnailHeight,
|
||||
width: val.thumbnailWidth,
|
||||
tags: [{ value: val.filename, title: val.filename }],
|
||||
});
|
||||
}
|
||||
@@ -120,8 +132,7 @@ export function JobsDocumentsLocalGallery({
|
||||
<Card title={t("jobs.labels.documents-images")}>
|
||||
<Gallery
|
||||
images={jobMedia.images}
|
||||
backdropClosesModal={true}
|
||||
onSelectImage={(index, image) => {
|
||||
onSelect={(index, image) => {
|
||||
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||
}}
|
||||
{...(optimized && {
|
||||
@@ -133,24 +144,23 @@ export function JobsDocumentsLocalGallery({
|
||||
/>,
|
||||
],
|
||||
})}
|
||||
onClickImage={(props) => {
|
||||
const media = allMedia[job.id].find(
|
||||
(m) => m.optimized === props.target.src
|
||||
);
|
||||
onClick={(index) => {
|
||||
setModalState({ open: true, index: index });
|
||||
// const media = allMedia[job.id].find(
|
||||
// (m) => m.optimized === item.src
|
||||
// );
|
||||
|
||||
window.open(
|
||||
media ? media.src : props.target.src,
|
||||
"_blank",
|
||||
"toolbar=0,location=0,menubar=0"
|
||||
);
|
||||
// window.open(
|
||||
// media ? media.fullsize : item.fullsize,
|
||||
// "_blank",
|
||||
// "toolbar=0,location=0,menubar=0"
|
||||
// );
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
<Card title={t("jobs.labels.documents-other")}>
|
||||
<Gallery
|
||||
images={jobMedia.other}
|
||||
backdropClosesModal={true}
|
||||
enableLightbox={false}
|
||||
thumbnailStyle={() => {
|
||||
return {
|
||||
backgroundImage: <FileExcelFilled />,
|
||||
@@ -159,18 +169,48 @@ export function JobsDocumentsLocalGallery({
|
||||
cursor: "pointer",
|
||||
};
|
||||
}}
|
||||
onClickThumbnail={(index) => {
|
||||
onClick={(index) => {
|
||||
window.open(
|
||||
jobMedia.other[index].src,
|
||||
jobMedia.other[index].fullsize,
|
||||
"_blank",
|
||||
"toolbar=0,location=0,menubar=0"
|
||||
);
|
||||
}}
|
||||
onSelectImage={(index, image) => {
|
||||
onSelect={(index, image) => {
|
||||
toggleMediaSelected({ jobid: job.id, filename: image.filename });
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
{modalState.open && (
|
||||
<Lightbox
|
||||
mainSrc={jobMedia.images[modalState.index].fullsize}
|
||||
nextSrc={
|
||||
jobMedia.images[(modalState.index + 1) % jobMedia.images.length]
|
||||
.fullsize
|
||||
}
|
||||
prevSrc={
|
||||
jobMedia.images[
|
||||
(modalState.index + jobMedia.images.length - 1) %
|
||||
jobMedia.images.length
|
||||
].fullsize
|
||||
}
|
||||
onCloseRequest={() => setModalState({ open: false, index: 0 })}
|
||||
onMovePrevRequest={() =>
|
||||
setModalState({
|
||||
...modalState,
|
||||
index:
|
||||
(modalState.index + jobMedia.images.length - 1) %
|
||||
jobMedia.images.length,
|
||||
})
|
||||
}
|
||||
onMoveNextRequest={() =>
|
||||
setModalState({
|
||||
...modalState,
|
||||
index: (modalState.index + 1) % jobMedia.images.length,
|
||||
})
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import React, { useEffect } from "react";
|
||||
import Gallery from "react-grid-gallery";
|
||||
import { Gallery } from "react-grid-gallery";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -38,7 +38,7 @@ function JobDocumentsLocalGalleryExternal({
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if ( jobId) {
|
||||
if (jobId) {
|
||||
getJobMedia(jobId);
|
||||
}
|
||||
}, [jobId, getJobMedia]);
|
||||
@@ -52,11 +52,15 @@ function JobDocumentsLocalGalleryExternal({
|
||||
val.type.mime &&
|
||||
val.type.mime.startsWith("image")
|
||||
) {
|
||||
acc.push(val);
|
||||
acc.push({ ...val, src: val.thumbnail });
|
||||
}
|
||||
return acc;
|
||||
}, [])
|
||||
: [];
|
||||
console.log(
|
||||
"🚀 ~ file: jobs-documents-local-gallery.external.component.jsx:48 ~ useEffect ~ documents:",
|
||||
documents
|
||||
);
|
||||
|
||||
setgalleryImages(documents);
|
||||
}, [allMedia, jobId, setgalleryImages, t]);
|
||||
@@ -65,8 +69,7 @@ function JobDocumentsLocalGalleryExternal({
|
||||
<div className="clearfix">
|
||||
<Gallery
|
||||
images={galleryImages}
|
||||
backdropClosesModal={true}
|
||||
onSelectImage={(index, image) => {
|
||||
onSelect={(index, image) => {
|
||||
setgalleryImages(
|
||||
galleryImages.map((g, idx) =>
|
||||
index === idx ? { ...g, isSelected: !g.isSelected } : g
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { Button, Card, Input, Space, Table, Typography } from "antd";
|
||||
import axios from "axios";
|
||||
import _ from "lodash";
|
||||
import queryString from "query-string";
|
||||
import React from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||
@@ -21,6 +22,8 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const [openSearchResults, setOpenSearchResults] = useState([]);
|
||||
const [searchLoading, setSearchLoading] = useState(false);
|
||||
const { page, sortcolumn, sortorder } = search;
|
||||
const history = useHistory();
|
||||
|
||||
@@ -193,6 +196,28 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (search.search && search.search.trim() !== "") {
|
||||
searchJobs();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function searchJobs(value) {
|
||||
try {
|
||||
setSearchLoading(true);
|
||||
const searchData = await axios.post("/search", {
|
||||
search: value || search.search,
|
||||
index: "jobs",
|
||||
});
|
||||
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
|
||||
} catch (error) {
|
||||
console.log("Error while fetching search results", error);
|
||||
} finally {
|
||||
setSearchLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
@@ -205,6 +230,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete search.search;
|
||||
delete search.page;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
}}
|
||||
>
|
||||
@@ -220,24 +246,32 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
||||
onSearch={(value) => {
|
||||
search.search = value;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
searchJobs(value);
|
||||
}}
|
||||
loading={loading || searchLoading}
|
||||
enterButton
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
total: total,
|
||||
showSizeChanger: false,
|
||||
}}
|
||||
loading={loading || searchLoading}
|
||||
pagination={
|
||||
search?.search
|
||||
? {
|
||||
pageSize: 25,
|
||||
showSizeChanger: false,
|
||||
}
|
||||
: {
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
total: total,
|
||||
showSizeChanger: false,
|
||||
}
|
||||
}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={jobs}
|
||||
dataSource={search?.search ? openSearchResults : jobs}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -75,6 +75,27 @@ export function JobNotesComponent({
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("notes.fields.type"),
|
||||
dataIndex: "type",
|
||||
key: "type",
|
||||
width: 120,
|
||||
filteredValue: filter?.type || null,
|
||||
filters: [
|
||||
{ value: "general", text: t("notes.fields.types.general") },
|
||||
{ value: "customer", text: t("notes.fields.types.customer") },
|
||||
{ value: "shop", text: t("notes.fields.types.shop") },
|
||||
{ value: "office", text: t("notes.fields.types.office") },
|
||||
{ value: "parts", text: t("notes.fields.types.parts") },
|
||||
{ value: "paint", text: t("notes.fields.types.paint") },
|
||||
{
|
||||
value: "supplement",
|
||||
text: t("notes.fields.types.supplement"),
|
||||
},
|
||||
],
|
||||
onFilter: (value, record) => value.includes(record.type),
|
||||
render: (text, record) => t(`notes.fields.types.${record.type}`),
|
||||
},
|
||||
{
|
||||
title: t("notes.fields.text"),
|
||||
dataIndex: "text",
|
||||
@@ -106,7 +127,7 @@ export function JobNotesComponent({
|
||||
title: t("notes.actions.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
width: 150,
|
||||
width: 200,
|
||||
render: (text, record) => (
|
||||
<Space wrap>
|
||||
<Button
|
||||
|
||||
@@ -207,7 +207,7 @@ export function LaborAllocationsTable({
|
||||
<Card title={t("jobs.labels.laborallocations")}>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="cost_center"
|
||||
rowKey={(record) => `${record.cost_center} ${record.mod_lbr_ty}`}
|
||||
pagination={false}
|
||||
onChange={handleTableChange}
|
||||
dataSource={totals}
|
||||
|
||||
@@ -6,10 +6,6 @@ export const CalculateAllocationsTotals = (
|
||||
timetickets,
|
||||
adjustments = []
|
||||
) => {
|
||||
console.log(
|
||||
"🚀 ~ file: labor-allocations-table.utility.js ~ line 9 ~ adjustments",
|
||||
adjustments
|
||||
);
|
||||
const responsibilitycenters = bodyshop.md_responsibility_centers;
|
||||
const jobCodes = joblines.map((item) => item.mod_lbr_ty);
|
||||
//.filter((value, index, self) => self.indexOf(value) === index && !!value);
|
||||
|
||||
@@ -1,4 +1,14 @@
|
||||
import { Checkbox, Col, Form, Input, Row, Space, Switch, Tag } from "antd";
|
||||
import {
|
||||
Checkbox,
|
||||
Col,
|
||||
Form,
|
||||
Input,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Switch,
|
||||
Tag,
|
||||
} from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -46,6 +56,28 @@ export function NoteUpsertModalComponent({ form, noteUpsertModal }) {
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Form.Item
|
||||
label={t("notes.fields.type")}
|
||||
name="type"
|
||||
initialValue="general"
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
{ value: "general", label: t("notes.fields.types.general") },
|
||||
{ value: "customer", label: t("notes.fields.types.customer") },
|
||||
{ value: "shop", label: t("notes.fields.types.shop") },
|
||||
{ value: "office", label: t("notes.fields.types.office") },
|
||||
{ value: "parts", label: t("notes.fields.types.parts") },
|
||||
{ value: "paint", label: t("notes.fields.types.paint") },
|
||||
{
|
||||
value: "supplement",
|
||||
label: t("notes.fields.types.supplement"),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<NotesPresetButton form={form} />
|
||||
</Col>
|
||||
|
||||
@@ -34,7 +34,7 @@ export function NoteUpsertModalContainer({
|
||||
const [updateNote] = useMutation(UPDATE_NOTE);
|
||||
|
||||
const { visible, context, actions } = noteUpsertModal;
|
||||
const { jobId, existingNote } = context;
|
||||
const { jobId, existingNote, text } = context;
|
||||
const { refetch } = actions;
|
||||
|
||||
const [form] = Form.useForm();
|
||||
@@ -45,8 +45,12 @@ export function NoteUpsertModalContainer({
|
||||
form.setFieldsValue(existingNote);
|
||||
} else if (!existingNote && visible) {
|
||||
form.resetFields();
|
||||
|
||||
if (text) {
|
||||
form.setFieldValue("text", text);
|
||||
}
|
||||
}
|
||||
}, [existingNote, form, visible]);
|
||||
}, [existingNote, form, visible, text]);
|
||||
|
||||
const handleFinish = async (formValues) => {
|
||||
const { relatedros, ...values } = formValues;
|
||||
@@ -82,6 +86,7 @@ export function NoteUpsertModalContainer({
|
||||
{ ...values, jobid: jobId, created_by: currentUser.email },
|
||||
],
|
||||
},
|
||||
refetchQueries: ["QUERY_NOTES_BY_JOB_PK"],
|
||||
});
|
||||
|
||||
if (AdditionalNoteInserts.length > 0) {
|
||||
|
||||
@@ -201,6 +201,7 @@ export function PartsOrderListTableComponent({
|
||||
subject: record.return
|
||||
? Templates.parts_return_slip.subject
|
||||
: Templates.parts_order.subject,
|
||||
to: record.vendor.email,
|
||||
}}
|
||||
id={job.id}
|
||||
/>
|
||||
@@ -296,7 +297,6 @@ export function PartsOrderListTableComponent({
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
|
||||
},
|
||||
|
||||
{
|
||||
title: t("parts_orders.fields.act_price"),
|
||||
dataIndex: "act_price",
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
import React from "react";
|
||||
import { Button, notification } from "antd";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { connect } from "react-redux";
|
||||
import { UPDATE_PAYMENT } from "../../graphql/payments.queries";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPaymentContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "payment" })),
|
||||
});
|
||||
|
||||
const PaymentMarkForExportButton = ({
|
||||
bodyshop,
|
||||
payment,
|
||||
refetch,
|
||||
setPaymentContext,
|
||||
currentUser,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const [insertExportLog, { loading: exportLogLoading }] =
|
||||
useMutation(INSERT_EXPORT_LOG);
|
||||
const [updatePayment, { loading: updatePaymentLoading }] =
|
||||
useMutation(UPDATE_PAYMENT);
|
||||
|
||||
const handleClick = async () => {
|
||||
const today = new Date();
|
||||
|
||||
await insertExportLog({
|
||||
variables: {
|
||||
logs: [
|
||||
{
|
||||
bodyshopid: bodyshop.id,
|
||||
paymentid: payment.id,
|
||||
successful: true,
|
||||
useremail: currentUser.email,
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const paymentUpdateResponse = await updatePayment({
|
||||
variables: {
|
||||
paymentId: payment.id,
|
||||
payment: {
|
||||
exportedat: today,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!!!paymentUpdateResponse.errors) {
|
||||
notification.open({
|
||||
type: "success",
|
||||
key: "paymentsuccessmarkforexport",
|
||||
message: t("payments.successes.markexported"),
|
||||
});
|
||||
|
||||
if (refetch) refetch();
|
||||
|
||||
setPaymentContext({
|
||||
actions: {
|
||||
refetch,
|
||||
},
|
||||
context: {
|
||||
...payment,
|
||||
exportedat: today,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting", {
|
||||
error: JSON.stringify(paymentUpdateResponse.error),
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
loading={exportLogLoading || updatePaymentLoading}
|
||||
disabled={!!payment.exportedat}
|
||||
>
|
||||
{t("payments.labels.markexported")}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(PaymentMarkForExportButton);
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
|
||||
import { Button, Form, Modal, notification } from "antd";
|
||||
import { Button, Form, Modal, notification, Space } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -19,6 +19,8 @@ import {
|
||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import PaymentForm from "../payment-form/payment-form.component";
|
||||
import PaymentReexportButton from "../payment-reexport-button/payment-reexport-button.component";
|
||||
import PaymentMarkForExportButton from "../payment-mark-export-button/payment-mark-export-button-component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
paymentModal: selectPayment,
|
||||
@@ -52,7 +54,7 @@ function PaymentModalContainer({
|
||||
const { useStripe, sendby, ...paymentObj } = values;
|
||||
|
||||
setLoading(true);
|
||||
|
||||
let updatedPayment; //Moved up from if statement for greater scope.
|
||||
try {
|
||||
if (!context || (context && !context.id)) {
|
||||
const newPayment = await insertPayment({
|
||||
@@ -87,7 +89,7 @@ function PaymentModalContainer({
|
||||
);
|
||||
}
|
||||
} else {
|
||||
const updatedPayment = await updatePayment({
|
||||
updatedPayment = await updatePayment({
|
||||
variables: {
|
||||
paymentId: context.id,
|
||||
payment: paymentObj,
|
||||
@@ -101,7 +103,11 @@ function PaymentModalContainer({
|
||||
}
|
||||
}
|
||||
|
||||
if (actions.refetch) actions.refetch();
|
||||
if (actions.refetch)
|
||||
actions.refetch(
|
||||
updatedPayment && updatedPayment.data.update_payments.returning[0]
|
||||
);
|
||||
|
||||
if (enterAgain) {
|
||||
const prev = form.getFieldsValue(["date"]);
|
||||
|
||||
@@ -172,12 +178,24 @@ function PaymentModalContainer({
|
||||
</span>
|
||||
}
|
||||
>
|
||||
{!context || (context && !context.id) ? null : (
|
||||
<Space>
|
||||
<PaymentReexportButton payment={context} refetch={actions.refetch} />
|
||||
<PaymentMarkForExportButton
|
||||
bodyshop={bodyshop}
|
||||
payment={context}
|
||||
refetch={actions.refetch}
|
||||
/>
|
||||
</Space>
|
||||
)}
|
||||
|
||||
<Form
|
||||
onFinish={handleFinish}
|
||||
autoComplete={"off"}
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={context || {}}
|
||||
disabled={context?.exportedat}
|
||||
>
|
||||
<PaymentForm form={form} />
|
||||
</Form>
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import React from "react";
|
||||
import { Button, notification } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_PAYMENT } from "../../graphql/payments.queries";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPaymentContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "payment" })),
|
||||
});
|
||||
|
||||
const PaymentReexportButton = ({ payment, refetch, setPaymentContext }) => {
|
||||
const { t } = useTranslation();
|
||||
const [updatePayment, { loading }] = useMutation(UPDATE_PAYMENT);
|
||||
|
||||
const handleClick = async () => {
|
||||
const paymentUpdateResponse = await updatePayment({
|
||||
variables: {
|
||||
paymentId: payment.id,
|
||||
payment: {
|
||||
exportedat: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!!!paymentUpdateResponse.errors) {
|
||||
notification.open({
|
||||
type: "success",
|
||||
key: "paymentsuccessexport",
|
||||
message: t("payments.successes.markreexported"),
|
||||
});
|
||||
|
||||
if (refetch) refetch();
|
||||
|
||||
setPaymentContext({
|
||||
actions: {
|
||||
refetch,
|
||||
},
|
||||
context: {
|
||||
...payment,
|
||||
exportedat: null,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting", {
|
||||
error: JSON.stringify(paymentUpdateResponse.error),
|
||||
}),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleClick}
|
||||
loading={loading}
|
||||
disabled={!payment.exportedat}
|
||||
>
|
||||
{t("payments.labels.markforreexport")}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(PaymentReexportButton);
|
||||
@@ -1,20 +1,23 @@
|
||||
import { EditFilled, SyncOutlined } from "@ant-design/icons";
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import { Button, Card, Input, Space, Table, Typography } from "antd";
|
||||
import axios from "axios";
|
||||
import queryString from "query-string";
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { QUERY_PAYMENT_BY_ID } from "../../graphql/payments.queries";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import CaBcEtfTableModalContainer from "../ca-bc-etf-table-modal/ca-bc-etf-table-modal.container";
|
||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -39,7 +42,10 @@ export function PaymentsListPaginated({
|
||||
bodyshop,
|
||||
}) {
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const [openSearchResults, setOpenSearchResults] = useState([]);
|
||||
const [searchLoading, setSearchLoading] = useState(false);
|
||||
const { page, sortcolumn, sortorder } = search;
|
||||
const client = useApolloClient();
|
||||
const history = useHistory();
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
@@ -52,13 +58,17 @@ export function PaymentsListPaginated({
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
|
||||
sortOrder: sortcolumn === "ro_number" && sortorder,
|
||||
render: (text, record) => (
|
||||
<Link to={"/manage/jobs/" + record.job.id}>
|
||||
{record.job.ro_number || t("general.labels.na")}
|
||||
</Link>
|
||||
),
|
||||
// sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
|
||||
// sortOrder: sortcolumn === "ro_number" && sortorder,
|
||||
render: (text, record) => {
|
||||
return record.job ? (
|
||||
<Link to={"/manage/jobs/" + record.job.id}>
|
||||
{record.job.ro_number || t("general.labels.na")}
|
||||
</Link>
|
||||
) : (
|
||||
<span>{t("general.labels.na")}</span>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("payments.fields.paymentnum"),
|
||||
@@ -72,16 +82,16 @@ export function PaymentsListPaginated({
|
||||
dataIndex: "owner",
|
||||
key: "owner",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln),
|
||||
sortOrder: sortcolumn === "owner" && sortorder,
|
||||
// sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln),
|
||||
// sortOrder: sortcolumn === "owner" && sortorder,
|
||||
render: (text, record) => {
|
||||
return record.job.owner ? (
|
||||
<Link to={"/manage/owners/" + record.job.owner.id}>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
return record.job?.owner ? (
|
||||
<Link to={"/manage/owners/" + record.job?.owner?.id}>
|
||||
<OwnerNameDisplay ownerObject={record.job} />
|
||||
</Link>
|
||||
) : (
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
<OwnerNameDisplay ownerObject={record.job} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
@@ -146,11 +156,34 @@ export function PaymentsListPaginated({
|
||||
render: (text, record) => (
|
||||
<Space>
|
||||
<Button
|
||||
disabled={record.exportedat}
|
||||
onClick={() => {
|
||||
// disabled={record.exportedat}
|
||||
onClick={async () => {
|
||||
let apolloResults;
|
||||
if (search.search) {
|
||||
const { data } = await client.query({
|
||||
query: QUERY_PAYMENT_BY_ID,
|
||||
variables: {
|
||||
paymentId: record.id,
|
||||
},
|
||||
});
|
||||
apolloResults = data.payments_by_pk;
|
||||
}
|
||||
setPaymentContext({
|
||||
actions: { refetch: refetch },
|
||||
context: record,
|
||||
actions: {
|
||||
refetch: apolloResults
|
||||
? (updatedRecord) => {
|
||||
setOpenSearchResults((results) =>
|
||||
results.map((result) => {
|
||||
if (result.id !== record.id) {
|
||||
return result;
|
||||
}
|
||||
return updatedRecord;
|
||||
})
|
||||
);
|
||||
}
|
||||
: refetch,
|
||||
},
|
||||
context: apolloResults ? apolloResults : record,
|
||||
});
|
||||
}}
|
||||
>
|
||||
@@ -177,6 +210,28 @@ export function PaymentsListPaginated({
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (search.search && search.search.trim() !== "") {
|
||||
searchPayments();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function searchPayments(value) {
|
||||
try {
|
||||
setSearchLoading(true);
|
||||
const searchData = await axios.post("/search", {
|
||||
search: value || search.search,
|
||||
index: "payments",
|
||||
});
|
||||
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
|
||||
} catch (error) {
|
||||
console.log("Error while fetching search results", error);
|
||||
} finally {
|
||||
setSearchLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
@@ -189,6 +244,7 @@ export function PaymentsListPaginated({
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete search.search;
|
||||
delete search.page;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
}}
|
||||
>
|
||||
@@ -212,24 +268,33 @@ export function PaymentsListPaginated({
|
||||
onSearch={(value) => {
|
||||
search.search = value;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
searchPayments(value);
|
||||
}}
|
||||
loading={loading || searchLoading}
|
||||
enterButton
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
loading={loading || searchLoading}
|
||||
scroll={{ x: true }}
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
total: total,
|
||||
}}
|
||||
pagination={
|
||||
search?.search
|
||||
? {
|
||||
pageSize: 25,
|
||||
showSizeChanger: false,
|
||||
}
|
||||
: {
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
total: total,
|
||||
showSizeChanger: false,
|
||||
}
|
||||
}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={payments}
|
||||
dataSource={search?.search ? openSearchResults : payments}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -29,7 +29,10 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
|
||||
})
|
||||
.filter(
|
||||
(temp) =>
|
||||
!temp.regions || (temp.regions && temp.regions[bodyshop.region_config])
|
||||
!temp.regions ||
|
||||
(temp.regions && temp.regions[bodyshop.region_config]) ||
|
||||
(temp.regions &&
|
||||
bodyshop.region_config.includes(Object.keys(temp.regions)) === true)
|
||||
);
|
||||
|
||||
const filteredJobsReportsList =
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { Col, List, Space, Typography } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const CardColorLegend = ({ bodyshop }) => {
|
||||
const { t } = useTranslation();
|
||||
const data = bodyshop.ssbuckets.map((bucket) => {
|
||||
let color = { r: 255, g: 255, b: 255 };
|
||||
|
||||
if (bucket.color) {
|
||||
color = bucket.color;
|
||||
|
||||
if (bucket.color.rgb) {
|
||||
color = bucket.color.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
label: bucket.label,
|
||||
color,
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Col>
|
||||
<Typography>{t("production.labels.legend")}</Typography>
|
||||
<List
|
||||
grid={{
|
||||
gutter: 16,
|
||||
}}
|
||||
dataSource={data}
|
||||
renderItem={(item) => (
|
||||
<List.Item>
|
||||
<Space>
|
||||
<div
|
||||
style={{
|
||||
width: "1.5rem",
|
||||
aspectRatio: "1/1",
|
||||
backgroundColor: `rgba(${item.color.r},${item.color.g},${item.color.b},${item.color.a})`,
|
||||
}}
|
||||
></div>
|
||||
<div>{item.label}</div>
|
||||
</Space>
|
||||
</List.Item>
|
||||
)}
|
||||
/>
|
||||
</Col>
|
||||
);
|
||||
};
|
||||
|
||||
export default CardColorLegend;
|
||||
@@ -18,6 +18,31 @@ import moment from "moment";
|
||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
|
||||
|
||||
const cardColor = (ssbuckets, totalHrs) => {
|
||||
const bucket = ssbuckets.filter(
|
||||
(bucket) =>
|
||||
bucket.gte <= totalHrs && (!!bucket.lt ? bucket.lt > totalHrs : true)
|
||||
)[0];
|
||||
|
||||
let color = { r: 255, g: 255, b: 255 };
|
||||
|
||||
if (bucket && bucket.color) {
|
||||
color = bucket.color;
|
||||
|
||||
if (bucket.color.rgb) {
|
||||
color = bucket.color.rgb;
|
||||
}
|
||||
}
|
||||
|
||||
return color;
|
||||
};
|
||||
|
||||
function getContrastYIQ(bgColor) {
|
||||
const yiq = (bgColor.r * 299 + bgColor.g * 587 + bgColor.b * 114) / 1000;
|
||||
|
||||
return yiq >= 128 ? "black" : "white";
|
||||
}
|
||||
|
||||
export default function ProductionBoardCard(
|
||||
technician,
|
||||
card,
|
||||
@@ -54,10 +79,22 @@ export default function ProductionBoardCard(
|
||||
.isSame(moment(card.scheduled_completion), "day") &&
|
||||
"production-completion-soon"));
|
||||
|
||||
const totalHrs =
|
||||
card.labhrs.aggregate.sum.mod_lb_hrs + card.larhrs.aggregate.sum.mod_lb_hrs;
|
||||
const bgColor = cardColor(bodyshop.ssbuckets, totalHrs);
|
||||
|
||||
return (
|
||||
<Card
|
||||
className="react-kanban-card imex-kanban-card"
|
||||
size="small"
|
||||
style={{
|
||||
backgroundColor:
|
||||
cardSettings &&
|
||||
cardSettings.cardcolor &&
|
||||
`rgba(${bgColor.r},${bgColor.g},${bgColor.b},${bgColor.a})`,
|
||||
color:
|
||||
cardSettings && cardSettings.cardcolor && getContrastYIQ(bgColor),
|
||||
}}
|
||||
title={
|
||||
<Space>
|
||||
<ProductionAlert record={card} key="alert" />
|
||||
|
||||
@@ -104,6 +104,13 @@ export default function ProductionBoardKanbanCardSettings({
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.cardcolor")}
|
||||
name="cardcolor"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
@@ -166,7 +173,7 @@ export default function ProductionBoardKanbanCardSettings({
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Popover content={overlay} visible={visible}>
|
||||
<Popover content={overlay} visible={visible} placement="topRight">
|
||||
<Button loading={loading} onClick={() => setVisible(true)}>
|
||||
{t("production.labels.cardsettings")}
|
||||
</Button>
|
||||
|
||||
@@ -22,6 +22,7 @@ import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-se
|
||||
//import "@asseinfo/react-kanban/dist/styles.css";
|
||||
import "./production-board-kanban.styles.scss";
|
||||
import { createBoardData } from "./production-board-kanban.utils.js";
|
||||
import CardColorLegend from "../production-board-kanban-card/production-board-kanban-card-color-legend.component";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
technician: selectTechnician,
|
||||
@@ -221,6 +222,7 @@ export function ProductionBoardKanbanComponent({
|
||||
employeeassignments: true,
|
||||
scheduled_completion: true,
|
||||
stickyheader: false,
|
||||
cardcolor: false,
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -256,6 +258,11 @@ export function ProductionBoardKanbanComponent({
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
{cardSettings.cardcolor && (
|
||||
<CardColorLegend cardSettings={cardSettings} bodyshop={bodyshop} />
|
||||
)}
|
||||
|
||||
<ProductionListDetailComponent jobs={data} />
|
||||
<StickyContainer>
|
||||
<Board
|
||||
|
||||
@@ -91,11 +91,13 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||
b.v_make_desc + b.v_model_desc
|
||||
),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
|
||||
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||
record.v_model_desc || ""
|
||||
} ${record.v_color || ""} ${record.plate_no || ""}`}</span>
|
||||
<Link to={`/manage/vehicles/${record.vehicleid}`}>{`${
|
||||
record.v_model_yr || ""
|
||||
} ${record.v_make_desc || ""} ${record.v_model_desc || ""} ${
|
||||
record.v_color || ""
|
||||
} ${record.plate_no || ""}`}</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,12 +1,23 @@
|
||||
import Icon from "@ant-design/icons";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Button, Input, Popover } from "antd";
|
||||
import { Button, Input, Popover, Space } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FaRegStickyNote } from "react-icons/fa";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
export default function ProductionListColumnProductionNote({ record }) {
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setNoteUpsertContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "noteUpsert" })),
|
||||
});
|
||||
|
||||
function ProductionListColumnProductionNote({ record, setNoteUpsertContext }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [note, setNote] = useState(
|
||||
@@ -60,12 +71,26 @@ export default function ProductionListColumnProductionNote({ record }) {
|
||||
// onPressEnter={handleSaveNote}
|
||||
autoFocus
|
||||
allowClear
|
||||
style={{ marginBottom: "1em" }}
|
||||
/>
|
||||
<div>
|
||||
<Button onClick={handleSaveNote}>
|
||||
<Space>
|
||||
<Button onClick={handleSaveNote} type="primary">
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setVisible(false);
|
||||
setNoteUpsertContext({
|
||||
context: {
|
||||
jobId: record.id,
|
||||
text: note,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("notes.actions.savetojobnotes")}
|
||||
</Button>
|
||||
</Space>
|
||||
</div>
|
||||
}
|
||||
trigger={["click"]}
|
||||
@@ -85,3 +110,8 @@ export default function ProductionListColumnProductionNote({ record }) {
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ProductionListColumnProductionNote);
|
||||
|
||||
@@ -81,7 +81,7 @@ export function ProductionListTable({
|
||||
state,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
}).find((e) => e.key === k.key),
|
||||
width: k.width,
|
||||
width: k.width ?? 100,
|
||||
};
|
||||
})) ||
|
||||
[]
|
||||
@@ -267,6 +267,8 @@ export function ProductionListTable({
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === c.key && state.sortedInfo.order,
|
||||
title: headerItem(c),
|
||||
ellipsis: true,
|
||||
width: c.width ?? 100,
|
||||
onHeaderCell: (column) => ({
|
||||
width: column.width,
|
||||
onResize: handleResize(index),
|
||||
@@ -276,11 +278,12 @@ export function ProductionListTable({
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
dataSource={dataSource}
|
||||
// scroll={{ x: true }}
|
||||
scroll={{ x: 1000 }}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</ReactDragListView.DragColumn>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(ProductionListTable);
|
||||
|
||||
@@ -3,8 +3,26 @@ import { Resizable } from "react-resizable";
|
||||
|
||||
export default function ResizableComponent(props) {
|
||||
const { onResize, width, ...restProps } = props;
|
||||
|
||||
if (!width) {
|
||||
return <th {...restProps} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<Resizable width={width || 200} height={0} onResize={onResize}>
|
||||
<Resizable
|
||||
width={width || 200}
|
||||
height={0}
|
||||
onResize={onResize}
|
||||
draggableOpts={{ enableUserSelectHack: false }}
|
||||
handle={
|
||||
<span
|
||||
className="react-resizable-handle"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<th {...restProps} />
|
||||
</Resizable>
|
||||
);
|
||||
|
||||
@@ -92,7 +92,11 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
|
||||
to: values.to,
|
||||
subject: Templates[values.key]?.subject,
|
||||
},
|
||||
values.sendby === "email" ? "e" : "p",
|
||||
values.sendbyexcel === "excel"
|
||||
? "x"
|
||||
: values.sendby === "email"
|
||||
? "e"
|
||||
: "p",
|
||||
id
|
||||
);
|
||||
setLoading(false);
|
||||
@@ -250,15 +254,38 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
|
||||
ranges={DatePIckerRanges}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("general.labels.sendby")}
|
||||
name="sendby"
|
||||
initialValue="print"
|
||||
>
|
||||
<Radio.Group>
|
||||
<Radio value="email">{t("general.labels.email")}</Radio>
|
||||
<Radio value="print">{t("general.labels.print")}</Radio>
|
||||
</Radio.Group>
|
||||
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
|
||||
{() => {
|
||||
const key = form.getFieldValue("key");
|
||||
//Kind of Id
|
||||
const reporttype = Templates[key] && Templates[key].reporttype;
|
||||
|
||||
if (reporttype === "excel")
|
||||
return (
|
||||
<Form.Item
|
||||
label={t("general.labels.sendby")}
|
||||
name="sendbyexcel"
|
||||
initialValue="excel"
|
||||
>
|
||||
<Radio.Group>
|
||||
<Radio value="excel">{t("general.labels.excel")}</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
);
|
||||
if (reporttype !== "excel")
|
||||
return (
|
||||
<Form.Item
|
||||
label={t("general.labels.sendby")}
|
||||
name="sendby"
|
||||
initialValue="print"
|
||||
>
|
||||
<Radio.Group>
|
||||
<Radio value="email">{t("general.labels.email")}</Radio>
|
||||
<Radio value="print">{t("general.labels.print")}</Radio>
|
||||
</Radio.Group>
|
||||
</Form.Item>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
|
||||
<div
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
import Dinero from "dinero.js";
|
||||
|
||||
const CustomTooltip = ({ active, payload, label }) => {
|
||||
if (active && payload && payload.length) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
backgroundColor: "white",
|
||||
border: "1px solid gray",
|
||||
padding: "0.5rem",
|
||||
}}
|
||||
>
|
||||
<p style={{ margin: "0" }}>{label}</p>
|
||||
{payload.map((data, index) => {
|
||||
if (data.dataKey === "sales" || data.dataKey === "accSales")
|
||||
return (
|
||||
<p
|
||||
style={{ margin: "10px 0", color: data.color }}
|
||||
key={index}
|
||||
>{`${data.name} : ${Dinero({
|
||||
amount: Math.round(data.value * 100),
|
||||
}).toFormat()}`}</p>
|
||||
);
|
||||
|
||||
return (
|
||||
<p
|
||||
style={{ margin: "10px 0", color: data.color }}
|
||||
key={index}
|
||||
>{`${data.name} : ${data.value}`}</p>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export default CustomTooltip;
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Card } from "antd";
|
||||
import Dinero from "dinero.js";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
@@ -17,7 +19,7 @@ import {
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
|
||||
import _ from "lodash";
|
||||
import CustomTooltip from "./chart-custom-tooltip";
|
||||
|
||||
const graphProps = {
|
||||
strokeWidth: 3,
|
||||
@@ -44,14 +46,19 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
|
||||
return {
|
||||
bodyhrs: dayAcc.bodyhrs + dayVal.bodyhrs,
|
||||
painthrs: dayAcc.painthrs + dayVal.painthrs,
|
||||
sales:
|
||||
dayAcc.painthrs +
|
||||
dayVal.job.job_totals.totals.subtotal.amount / 100 +
|
||||
2500,
|
||||
};
|
||||
},
|
||||
{ bodyhrs: 0, painthrs: 0 }
|
||||
{ bodyhrs: 0, painthrs: 0, sales: 0 }
|
||||
);
|
||||
} else {
|
||||
dayhrs = {
|
||||
bodyhrs: 0,
|
||||
painthrs: 0,
|
||||
sales: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -64,7 +71,9 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
|
||||
bodyshop.scoreboard_target.dailyBodyTarget +
|
||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||
val
|
||||
),
|
||||
) +
|
||||
bodyshop.scoreboard_target.dailyBodyTarget +
|
||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||
1
|
||||
),
|
||||
accHrs: _.round(
|
||||
@@ -73,6 +82,13 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
|
||||
: dayhrs.painthrs + dayhrs.bodyhrs,
|
||||
1
|
||||
),
|
||||
sales: _.round(dayhrs.sales, 2),
|
||||
accSales: _.round(
|
||||
acc.length > 0
|
||||
? acc[acc.length - 1].accSales + dayhrs.sales
|
||||
: dayhrs.sales,
|
||||
2
|
||||
),
|
||||
};
|
||||
|
||||
return [...acc, theValue];
|
||||
@@ -87,22 +103,27 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
|
||||
>
|
||||
<CartesianGrid stroke="#f5f5f5" />
|
||||
<XAxis dataKey="date" strokeWidth={graphProps.strokeWidth} />
|
||||
<YAxis strokeWidth={graphProps.strokeWidth} />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Area
|
||||
type="monotone"
|
||||
name="Accumulated Hours"
|
||||
dataKey="accHrs"
|
||||
fill="lightgreen"
|
||||
stroke="green"
|
||||
<YAxis
|
||||
strokeWidth={graphProps.strokeWidth}
|
||||
// allowDataOverflow
|
||||
dataKey="sales"
|
||||
yAxisId="right"
|
||||
tickFormatter={(value) =>
|
||||
Dinero({ amount: Math.round(value * 100) }).toFormat()
|
||||
}
|
||||
orientation="right"
|
||||
/>
|
||||
<YAxis yAxisId="left" strokeWidth={graphProps.strokeWidth} />
|
||||
<Tooltip content={<CustomTooltip />} />
|
||||
<Legend />
|
||||
|
||||
<Bar
|
||||
name="Body Hours"
|
||||
dataKey="bodyHrs"
|
||||
stackId="day"
|
||||
barSize={20}
|
||||
fill="darkblue"
|
||||
yAxisId="left"
|
||||
/>
|
||||
<Bar
|
||||
name="Paint Hours"
|
||||
@@ -110,12 +131,42 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
|
||||
stackId="day"
|
||||
barSize={20}
|
||||
fill="darkred"
|
||||
yAxisId="left"
|
||||
/>
|
||||
<Line
|
||||
name="Target Hours"
|
||||
type="monotone"
|
||||
dataKey="accTargetHrs"
|
||||
stroke="#ff7300"
|
||||
yAxisId="left"
|
||||
strokeWidth={graphProps.strokeWidth}
|
||||
/>
|
||||
|
||||
<Area
|
||||
type="monotone"
|
||||
name="MTD Hours"
|
||||
dataKey="accHrs"
|
||||
fill="lightblue"
|
||||
stroke="blue"
|
||||
yAxisId="left"
|
||||
/>
|
||||
{
|
||||
// <Area
|
||||
// type="monotone"
|
||||
// name="MTD Sales"
|
||||
// dataKey="accSales"
|
||||
// fill="lightgreen"
|
||||
// stroke="green"
|
||||
// yAxisId="right"
|
||||
// />
|
||||
}
|
||||
<Bar
|
||||
name="Sales"
|
||||
dataKey="sales"
|
||||
stackId="day"
|
||||
barSize={20}
|
||||
fill="darkgreen"
|
||||
yAxisId="right"
|
||||
strokeWidth={graphProps.strokeWidth}
|
||||
/>
|
||||
</ComposedChart>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Card, Statistic } from "antd";
|
||||
import { Card, Divider, Statistic } from "antd";
|
||||
import moment from "moment";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
@@ -41,6 +41,9 @@ export function ScoreboardDayStats({ bodyshop, date, entries }) {
|
||||
label="P"
|
||||
value={paintHrs.toFixed(1)}
|
||||
/>
|
||||
<Divider style={{ margin: 0 }} />
|
||||
|
||||
<Statistic value={(bodyHrs + paintHrs).toFixed(1)} />
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { CalendarOutlined } from "@ant-design/icons";
|
||||
import { Card, Col, Row, Statistic } from "antd";
|
||||
import { Card, Col, Divider, Row, Statistic } from "antd";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import React, { useMemo } from "react";
|
||||
@@ -177,6 +177,9 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
|
||||
<Statistic value={values.toDatePaint.toFixed(1)} />
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Divider style={{ margin: 5 }} />
|
||||
</Row>
|
||||
<Row>
|
||||
<Col {...statSpans}></Col>
|
||||
<Col {...statSpans}>
|
||||
@@ -184,14 +187,53 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
|
||||
value={(values.todayPaint + values.todayBody).toFixed(1)}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}></Col>
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={(
|
||||
Util.WeeklyTargetHrs(
|
||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||
bodyshop
|
||||
) +
|
||||
Util.WeeklyTargetHrs(
|
||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||
bodyshop
|
||||
)
|
||||
).toFixed(1)}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={(values.weeklyPaint + values.weeklyBody).toFixed(1)}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}></Col>
|
||||
<Col {...statSpans}></Col>
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={(
|
||||
Util.MonthlyTargetHrs(
|
||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||
bodyshop
|
||||
) +
|
||||
Util.MonthlyTargetHrs(
|
||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||
bodyshop
|
||||
)
|
||||
).toFixed(1)}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={(
|
||||
Util.AsOfTodayTargetHrs(
|
||||
bodyshop.scoreboard_target.dailyBodyTarget,
|
||||
bodyshop
|
||||
) +
|
||||
Util.AsOfTodayTargetHrs(
|
||||
bodyshop.scoreboard_target.dailyPaintTarget,
|
||||
bodyshop
|
||||
)
|
||||
).toFixed(1)}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...statSpans}>
|
||||
<Statistic
|
||||
value={(values.toDatePaint + values.toDateBody).toFixed(1)}
|
||||
|
||||
@@ -81,6 +81,7 @@ export default function ScoreboardTimeTickets() {
|
||||
totalLastMonth: 0,
|
||||
totalOverPeriod: 0,
|
||||
actualTotalOverPeriod: 0,
|
||||
totalEffieciencyOverPeriod: 0,
|
||||
employees: {},
|
||||
};
|
||||
data.fixedperiod.forEach((ticket) => {
|
||||
@@ -94,6 +95,7 @@ export default function ScoreboardTimeTickets() {
|
||||
totalLastMonth: 0,
|
||||
totalOverPeriod: 0,
|
||||
actualTotalOverPeriod: 0,
|
||||
totalEffieciencyOverPeriod: 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -221,6 +223,30 @@ export default function ScoreboardTimeTickets() {
|
||||
|
||||
ret2.push(r);
|
||||
});
|
||||
|
||||
// Add total efficiency of employees
|
||||
const totalActualAndProductive = Object.keys(ret.employees)
|
||||
.map((key) => {
|
||||
return { employee_number: key, ...ret.employees[key] };
|
||||
})
|
||||
.reduce(
|
||||
(acc, e) => {
|
||||
return {
|
||||
totalOverPeriod: acc.totalOverPeriod + e.totalOverPeriod,
|
||||
actualTotalOverPeriod:
|
||||
acc.actualTotalOverPeriod + e.actualTotalOverPeriod,
|
||||
};
|
||||
},
|
||||
{ totalOverPeriod: 0, actualTotalOverPeriod: 0 }
|
||||
);
|
||||
|
||||
ret.totalEffieciencyOverPeriod =
|
||||
totalActualAndProductive.actualTotalOverPeriod
|
||||
? (totalActualAndProductive.totalOverPeriod /
|
||||
totalActualAndProductive.actualTotalOverPeriod) *
|
||||
100
|
||||
: 0;
|
||||
|
||||
roundObject(ret);
|
||||
roundObject(totals);
|
||||
roundObject(ret2);
|
||||
|
||||
@@ -62,7 +62,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
|
||||
key: "efficiencyoverperiod",
|
||||
render: (text, record) =>
|
||||
`${(
|
||||
(record.totalOverPeriod / (record.actualTotalOverPeriod || .1)) *
|
||||
(record.totalOverPeriod / (record.actualTotalOverPeriod || 0.1)) *
|
||||
100
|
||||
).toFixed(1)} %`,
|
||||
},
|
||||
@@ -113,6 +113,12 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
|
||||
value={data.totalOverPeriod}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Statistic
|
||||
title={t("scoreboard.labels.efficiencyoverperiod")}
|
||||
value={`${data.totalEffieciencyOverPeriod || 0}%`}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
<Typography.Text type="secondary">
|
||||
{t("scoreboard.labels.calendarperiod")}
|
||||
@@ -121,7 +127,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
|
||||
<Col md={24} lg={20}>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey='employee_number'
|
||||
rowKey="employee_number"
|
||||
dataSource={tableData}
|
||||
id="employee_number"
|
||||
scroll={{ y: "300px" }}
|
||||
|
||||
@@ -11,13 +11,13 @@ import {
|
||||
} from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CurrencyInput from "../form-items-formatted/currency-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 FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||
|
||||
import momentTZ from "moment-timezone";
|
||||
const timeZonesList = momentTZ.tz.names();
|
||||
@@ -551,6 +551,13 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<CurrencyInput />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["use_paint_scale_data"]}
|
||||
label={t("bodyshop.fields.use_paint_scale_data")}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["attach_pdf_to_email"]}
|
||||
label={t("bodyshop.fields.attach_pdf_to_email")}
|
||||
@@ -589,6 +596,13 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["tt_enforce_hours_for_tech_console"]}
|
||||
label={t("bodyshop.fields.tt_enforce_hours_for_tech_console")}
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["bill_allow_post_to_closed"]}
|
||||
label={t("bodyshop.fields.bill_allow_post_to_closed")}
|
||||
|
||||
@@ -396,7 +396,7 @@ export function ShopInfoROStatusComponent({ bodyshop, form }) {
|
||||
);
|
||||
}
|
||||
|
||||
const ColorPicker = ({ value, onChange, style, ...restProps }) => {
|
||||
export const ColorPicker = ({ value, onChange, style, ...restProps }) => {
|
||||
const handleChange = (color) => {
|
||||
if (onChange) onChange(color.rgb);
|
||||
};
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useTranslation } from "react-i18next";
|
||||
import ColorpickerFormItemComponent from "../form-items-formatted/colorpicker-form-item.component";
|
||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import { ColorPicker } from "./shop-info.rostatus.component";
|
||||
|
||||
export default function ShopInfoSchedulingComponent({ form }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -277,17 +278,50 @@ export default function ShopInfoSchedulingComponent({ form }) {
|
||||
>
|
||||
<InputNumber />
|
||||
</Form.Item>
|
||||
<Space wrap>
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
<FormListMoveArrows
|
||||
move={move}
|
||||
index={index}
|
||||
total={fields.length}
|
||||
/>
|
||||
|
||||
<Space direction="horizontal">
|
||||
<Form.Item
|
||||
label={
|
||||
<Space>
|
||||
{t("bodyshop.fields.ssbuckets.color")}
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() => {
|
||||
form.setFieldValue([
|
||||
"ssbuckets",
|
||||
field.name,
|
||||
"color",
|
||||
]);
|
||||
|
||||
form.setFields([
|
||||
{
|
||||
name: ["ssbuckets", field.name, "color"],
|
||||
touched: true,
|
||||
},
|
||||
]);
|
||||
}}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
key={`${index}color`}
|
||||
name={[field.name, "color"]}
|
||||
>
|
||||
<ColorPicker />
|
||||
</Form.Item>
|
||||
<Space wrap>
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
<FormListMoveArrows
|
||||
move={move}
|
||||
index={index}
|
||||
total={fields.length}
|
||||
/>
|
||||
</Space>
|
||||
</Space>
|
||||
</LayoutFormRow>
|
||||
</Form.Item>
|
||||
|
||||
@@ -26,6 +26,10 @@ export function TechClockInContainer({
|
||||
technician,
|
||||
bodyshop,
|
||||
}) {
|
||||
console.log(
|
||||
"🚀 ~ file: tech-job-clock-in-form.container.jsx:29 ~ technician:",
|
||||
technician
|
||||
);
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET, {
|
||||
@@ -33,6 +37,10 @@ export function TechClockInContainer({
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
const emps = bodyshop.employees.filter(
|
||||
(e) => e.id === (technician && technician.id)
|
||||
)[0];
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
const theTime = (await axios.post("/utils/time")).data;
|
||||
@@ -87,7 +95,12 @@ export function TechClockInContainer({
|
||||
onClick={() => {
|
||||
setTimeTicketContext({
|
||||
actions: {},
|
||||
context: { timeticket: { employeeid: technician.id } },
|
||||
context: {
|
||||
timeticket: {
|
||||
employeeid: technician.id,
|
||||
flat_rate: emps.flat_rate,
|
||||
},
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
@@ -21,6 +21,8 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
|
||||
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
|
||||
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
|
||||
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -39,7 +41,17 @@ export function TechClockOffButton({
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const { queryLoading, data: lineTicketData } = useQuery(
|
||||
GET_LINE_TICKET_BY_PK,
|
||||
{
|
||||
variables: {
|
||||
id: jobId,
|
||||
},
|
||||
skip: !jobId,
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
}
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
const emps = bodyshop.employees.filter(
|
||||
(e) => e.id === (technician && technician.id)
|
||||
@@ -59,6 +71,7 @@ export function TechClockOffButton({
|
||||
emps &&
|
||||
emps.rates.filter((r) => r.cost_center === values.cost_center)[0]
|
||||
?.rate,
|
||||
flat_rate: emps && emps.flat_rate,
|
||||
ciecacode:
|
||||
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||
? values.cost_center
|
||||
@@ -128,6 +141,54 @@ export function TechClockOffButton({
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
validator(rule, value) {
|
||||
console.log(
|
||||
bodyshop.tt_enforce_hours_for_tech_console
|
||||
);
|
||||
if (!bodyshop.tt_enforce_hours_for_tech_console) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (
|
||||
!value ||
|
||||
getFieldValue("cost_center") === null ||
|
||||
!lineTicketData
|
||||
)
|
||||
return Promise.resolve();
|
||||
|
||||
//Check the cost center,
|
||||
const totals = CalculateAllocationsTotals(
|
||||
bodyshop,
|
||||
lineTicketData.joblines,
|
||||
lineTicketData.timetickets,
|
||||
lineTicketData.jobs_by_pk.lbr_adjustments
|
||||
);
|
||||
|
||||
const fieldTypeToCheck =
|
||||
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||
? "mod_lbr_ty"
|
||||
: "cost_center";
|
||||
|
||||
const costCenterDiff =
|
||||
Math.round(
|
||||
totals.find(
|
||||
(total) =>
|
||||
total[fieldTypeToCheck] ===
|
||||
getFieldValue("cost_center")
|
||||
)?.difference * 10
|
||||
) / 10;
|
||||
|
||||
if (value > costCenterDiff)
|
||||
return Promise.reject(
|
||||
t(
|
||||
"timetickets.validation.hoursenteredmorethanavailable"
|
||||
)
|
||||
);
|
||||
else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<InputNumber min={0} precision={1} />
|
||||
@@ -177,7 +238,11 @@ export function TechClockOffButton({
|
||||
</Col>
|
||||
{!isShiftTicket && (
|
||||
<Col span={16}>
|
||||
<LaborAllocationContainer jobid={jobId} />
|
||||
<LaborAllocationContainer
|
||||
jobid={jobId || null}
|
||||
loading={queryLoading}
|
||||
lineTicketData={lineTicketData}
|
||||
/>
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Card, Col, Space, Statistic, Typography } from "antd";
|
||||
import moment from "moment";
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE } from "../../graphql/timetickets.queries";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
const { Title } = Typography;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
const TechJobStatistics = ({ technician }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const startDate = moment().startOf("week");
|
||||
const endDate = moment().endOf("week");
|
||||
|
||||
const { loading, error, data } = useQuery(
|
||||
QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE,
|
||||
{
|
||||
variables: {
|
||||
start: startDate.format("YYYY-MM-DD"),
|
||||
end: endDate.format("YYYY-MM-DD"),
|
||||
fixedStart: moment().startOf("month").format("YYYY-MM-DD"),
|
||||
fixedEnd: moment().endOf("month").format("YYYY-MM-DD"),
|
||||
employeeid: technician.id,
|
||||
},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
}
|
||||
);
|
||||
|
||||
const totals = useMemo(() => {
|
||||
if (data && data.timetickets && data.fixedperiod) {
|
||||
const week = data.timetickets.reduce(
|
||||
(acc, val) => {
|
||||
acc.productivehrs = acc.productivehrs + val.productivehrs;
|
||||
acc.actualhrs = acc.actualhrs + val.actualhrs;
|
||||
return acc;
|
||||
},
|
||||
{ productivehrs: 0, actualhrs: 0 }
|
||||
);
|
||||
|
||||
const month = data.fixedperiod.reduce(
|
||||
(acc, val) => {
|
||||
acc.productivehrs = acc.productivehrs + val.productivehrs;
|
||||
acc.actualhrs = acc.actualhrs + val.actualhrs;
|
||||
return acc;
|
||||
},
|
||||
{ productivehrs: 0, actualhrs: 0 }
|
||||
);
|
||||
|
||||
return {
|
||||
week,
|
||||
month,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
week: { productivehrs: 0, actualhrs: 0 },
|
||||
month: { productivehrs: 0, actualhrs: 0 },
|
||||
};
|
||||
}, [data]);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
return (
|
||||
<Card title={t("scoreboard.labels.productivestatistics")}>
|
||||
<Space size={100}>
|
||||
<Col>
|
||||
<Title level={5}>{t("scoreboard.labels.thisweek")}</Title>
|
||||
<Space size={20}>
|
||||
<Statistic
|
||||
title={t("timetickets.fields.productivehrs")}
|
||||
value={totals.week.productivehrs.toFixed(2)}
|
||||
/>
|
||||
<Statistic
|
||||
title={t("timetickets.fields.actualhrs")}
|
||||
value={totals.week.actualhrs.toFixed(2)}
|
||||
/>
|
||||
<Statistic
|
||||
title={t("timetickets.labels.efficiency")}
|
||||
value={
|
||||
totals.week.actualhrs
|
||||
? `${(
|
||||
(totals.week.productivehrs / totals.week.actualhrs) *
|
||||
100
|
||||
).toFixed(2)}%`
|
||||
: "0%"
|
||||
}
|
||||
/>
|
||||
</Space>
|
||||
</Col>
|
||||
<Col>
|
||||
<Title level={5}>{t("scoreboard.labels.thismonth")}</Title>
|
||||
<Space size={20}>
|
||||
<Statistic
|
||||
title={t("timetickets.fields.productivehrs")}
|
||||
value={totals.month.productivehrs.toFixed(2)}
|
||||
/>
|
||||
<Statistic
|
||||
title={t("timetickets.fields.actualhrs")}
|
||||
value={totals.month.actualhrs.toFixed(2)}
|
||||
/>
|
||||
<Statistic
|
||||
title={t("timetickets.labels.efficiency")}
|
||||
value={
|
||||
totals.month.actualhrs
|
||||
? `${(
|
||||
(totals.month.productivehrs / totals.month.actualhrs) *
|
||||
100
|
||||
).toFixed(2)}%`
|
||||
: "0%"
|
||||
}
|
||||
/>
|
||||
</Space>
|
||||
</Col>
|
||||
</Space>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TechJobStatistics);
|
||||
@@ -29,7 +29,17 @@ export function TechSider({ technician, techLogout }) {
|
||||
};
|
||||
|
||||
return (
|
||||
<Sider collapsible collapsed={collapsed} onCollapse={onCollapse}>
|
||||
<Sider
|
||||
style={{
|
||||
height: "100vh",
|
||||
position: "sticky",
|
||||
top: 0,
|
||||
left: 0,
|
||||
}}
|
||||
collapsible
|
||||
collapsed={collapsed}
|
||||
onCollapse={onCollapse}
|
||||
>
|
||||
<Menu theme="dark" defaultSelectedKeys={["1"]} mode="inline">
|
||||
<Menu.Item
|
||||
key="1"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { useLazyQuery } from "@apollo/client";
|
||||
import { Form, Input, InputNumber, Select, Switch } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -14,6 +14,7 @@ import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||
import FormDateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
||||
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
||||
import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component";
|
||||
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
|
||||
@@ -38,7 +39,11 @@ export function TimeTicketModalComponent({
|
||||
employeeSelectDisabled,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [loadLineTicketData, { called, loading, data: lineTicketData }] =
|
||||
useLazyQuery(GET_LINE_TICKET_BY_PK, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
});
|
||||
const CostCenterSelect = ({ emps, value, ...props }) => {
|
||||
return (
|
||||
<Select
|
||||
@@ -176,6 +181,51 @@ export function TimeTicketModalComponent({
|
||||
label={t("timetickets.fields.productivehrs")}
|
||||
name="productivehrs"
|
||||
rules={[
|
||||
({ getFieldValue }) => ({
|
||||
validator(rule, value) {
|
||||
if (!bodyshop.tt_enforce_hours_for_tech_console) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
if (
|
||||
!value ||
|
||||
getFieldValue("cost_center") === null ||
|
||||
!lineTicketData
|
||||
)
|
||||
return Promise.resolve();
|
||||
|
||||
//Check the cost center,
|
||||
const totals = CalculateAllocationsTotals(
|
||||
bodyshop,
|
||||
lineTicketData.joblines,
|
||||
lineTicketData.timetickets,
|
||||
lineTicketData.jobs_by_pk.lbr_adjustments
|
||||
);
|
||||
|
||||
const fieldTypeToCheck =
|
||||
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
|
||||
? "mod_lbr_ty"
|
||||
: "cost_center";
|
||||
|
||||
const costCenterDiff =
|
||||
Math.round(
|
||||
totals.find(
|
||||
(total) =>
|
||||
total[fieldTypeToCheck] ===
|
||||
getFieldValue("cost_center")
|
||||
)?.difference * 10
|
||||
) / 10;
|
||||
|
||||
if (value > costCenterDiff)
|
||||
return Promise.reject(
|
||||
t(
|
||||
"timetickets.validation.hoursenteredmorethanavailable"
|
||||
)
|
||||
);
|
||||
else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
}),
|
||||
{
|
||||
required:
|
||||
form.getFieldValue("cost_center") !==
|
||||
@@ -291,23 +341,28 @@ export function TimeTicketModalComponent({
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<Form.Item dependencies={["jobid"]}>
|
||||
{() => (
|
||||
<LaborAllocationContainer
|
||||
jobid={form.getFieldValue("jobid") || null}
|
||||
/>
|
||||
)}
|
||||
{() => {
|
||||
const jobid = form.getFieldValue("jobid");
|
||||
if (
|
||||
(!called && jobid) ||
|
||||
(jobid && lineTicketData?.jobs_by_pk?.id !== jobid && !loading)
|
||||
) {
|
||||
loadLineTicketData({ variables: { id: jobid } });
|
||||
}
|
||||
return (
|
||||
<LaborAllocationContainer
|
||||
jobid={jobid || null}
|
||||
loading={loading}
|
||||
lineTicketData={lineTicketData}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function LaborAllocationContainer({ jobid }) {
|
||||
const { loading, data: lineTicketData } = useQuery(GET_LINE_TICKET_BY_PK, {
|
||||
variables: { id: jobid },
|
||||
skip: !jobid,
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
});
|
||||
export function LaborAllocationContainer({ jobid, loading, lineTicketData }) {
|
||||
if (loading) return <LoadingSkeleton />;
|
||||
if (!lineTicketData) return null;
|
||||
return (
|
||||
|
||||
@@ -20,13 +20,11 @@ export const DELETE_BILL = gql`
|
||||
|
||||
export const QUERY_ALL_BILLS_PAGINATED = gql`
|
||||
query QUERY_ALL_BILLS_PAGINATED(
|
||||
$search: String
|
||||
$offset: Int
|
||||
$limit: Int
|
||||
$order: [bills_order_by!]!
|
||||
) {
|
||||
search_bills(
|
||||
args: { search: $search }
|
||||
bills(
|
||||
offset: $offset
|
||||
limit: $limit
|
||||
order_by: $order
|
||||
@@ -51,7 +49,7 @@ export const QUERY_ALL_BILLS_PAGINATED = gql`
|
||||
ro_number
|
||||
}
|
||||
}
|
||||
search_bills_aggregate(args: { search: $search }) {
|
||||
bills_aggregate {
|
||||
aggregate {
|
||||
count(distinct: true)
|
||||
}
|
||||
@@ -69,6 +67,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
|
||||
vendor {
|
||||
id
|
||||
name
|
||||
email
|
||||
}
|
||||
order_date
|
||||
deliver_by
|
||||
@@ -104,6 +103,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
|
||||
vendor {
|
||||
id
|
||||
name
|
||||
email
|
||||
}
|
||||
total
|
||||
invoice_number
|
||||
|
||||
@@ -116,6 +116,8 @@ export const QUERY_BODYSHOP = gql`
|
||||
md_lost_sale_reasons
|
||||
md_parts_scan
|
||||
enforce_conversion_category
|
||||
tt_enforce_hours_for_tech_console
|
||||
use_paint_scale_data
|
||||
employees {
|
||||
user_email
|
||||
id
|
||||
@@ -125,6 +127,7 @@ export const QUERY_BODYSHOP = gql`
|
||||
employee_number
|
||||
rates
|
||||
external_id
|
||||
flat_rate
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,6 +232,7 @@ export const UPDATE_SHOP = gql`
|
||||
md_lost_sale_reasons
|
||||
md_parts_scan
|
||||
enforce_conversion_category
|
||||
tt_enforce_hours_for_tech_console
|
||||
employees {
|
||||
id
|
||||
first_name
|
||||
|
||||
@@ -284,6 +284,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
|
||||
clm_no
|
||||
v_make_desc
|
||||
v_color
|
||||
vehicleid
|
||||
plate_no
|
||||
actual_in
|
||||
scheduled_completion
|
||||
@@ -1277,7 +1278,7 @@ export const SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE = gql`
|
||||
|
||||
export const SEARCH_FOR_JOBS = gql`
|
||||
query SEARCH_FOR_JOBS($search: String!) {
|
||||
search_jobs(args: { search: $search }) {
|
||||
search_jobs(args: { search: $search }, limit: 25) {
|
||||
id
|
||||
ro_number
|
||||
ownr_fn
|
||||
@@ -1780,14 +1781,12 @@ export const QUERY_ALL_JOB_FIELDS = gql`
|
||||
|
||||
export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
|
||||
query QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED(
|
||||
$search: String
|
||||
$offset: Int
|
||||
$limit: Int
|
||||
$order: [jobs_order_by!]
|
||||
$statusList: [String!]
|
||||
) {
|
||||
search_jobs(
|
||||
args: { search: $search }
|
||||
jobs(
|
||||
offset: $offset
|
||||
limit: $limit
|
||||
order_by: $order
|
||||
@@ -1818,10 +1817,7 @@ export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
|
||||
updated_at
|
||||
ded_amt
|
||||
}
|
||||
search_jobs_aggregate(
|
||||
args: { search: $search }
|
||||
where: { status: { _in: $statusList } }
|
||||
) {
|
||||
jobs_aggregate(where: { status: { _in: $statusList } }) {
|
||||
aggregate {
|
||||
count(distinct: true)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,16 @@ export const INSERT_NEW_NOTE = gql`
|
||||
mutation INSERT_NEW_NOTE($noteInput: [notes_insert_input!]!) {
|
||||
insert_notes(objects: $noteInput) {
|
||||
returning {
|
||||
created_at
|
||||
created_by
|
||||
critical
|
||||
id
|
||||
jobid
|
||||
private
|
||||
text
|
||||
updated_at
|
||||
audit
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,8 +24,8 @@ export const QUERY_NOTES_BY_JOB_PK = gql`
|
||||
jobs_by_pk(id: $id) {
|
||||
id
|
||||
ro_number
|
||||
vehicle{
|
||||
jobs{
|
||||
vehicle {
|
||||
jobs {
|
||||
id
|
||||
ro_number
|
||||
status
|
||||
@@ -33,6 +42,7 @@ export const QUERY_NOTES_BY_JOB_PK = gql`
|
||||
text
|
||||
updated_at
|
||||
audit
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -52,6 +62,7 @@ export const UPDATE_NOTE = gql`
|
||||
text
|
||||
updated_at
|
||||
audit
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,39 +12,39 @@ export const INSERT_NEW_PAYMENT = gql`
|
||||
|
||||
export const QUERY_ALL_PAYMENTS_PAGINATED = gql`
|
||||
query QUERY_ALL_PAYMENTS_PAGINATED(
|
||||
$search: String
|
||||
$offset: Int
|
||||
$limit: Int
|
||||
$order: [payments_order_by!]!
|
||||
) {
|
||||
search_payments(
|
||||
args: { search: $search }
|
||||
offset: $offset
|
||||
limit: $limit
|
||||
order_by: $order
|
||||
) {
|
||||
payments(offset: $offset, limit: $limit, order_by: $order) {
|
||||
id
|
||||
amount
|
||||
created_at
|
||||
jobid
|
||||
paymentnum
|
||||
date
|
||||
exportedat
|
||||
jobid
|
||||
job {
|
||||
id
|
||||
ro_number
|
||||
ownerid
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
owner {
|
||||
id
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
}
|
||||
ro_number
|
||||
}
|
||||
transactionid
|
||||
memo
|
||||
type
|
||||
amount
|
||||
stripeid
|
||||
exportedat
|
||||
stripeid
|
||||
payer
|
||||
paymentnum
|
||||
stripeid
|
||||
transactionid
|
||||
type
|
||||
}
|
||||
search_payments_aggregate(args: { search: $search }) {
|
||||
payments_aggregate {
|
||||
aggregate {
|
||||
count(distinct: true)
|
||||
}
|
||||
@@ -57,16 +57,31 @@ export const UPDATE_PAYMENT = gql`
|
||||
update_payments(where: { id: { _eq: $paymentId } }, _set: $payment) {
|
||||
returning {
|
||||
id
|
||||
transactionid
|
||||
memo
|
||||
type
|
||||
amount
|
||||
stripeid
|
||||
created_at
|
||||
date
|
||||
exportedat
|
||||
stripeid
|
||||
jobid
|
||||
job {
|
||||
id
|
||||
ownerid
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
owner {
|
||||
id
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
}
|
||||
ro_number
|
||||
}
|
||||
memo
|
||||
payer
|
||||
paymentnum
|
||||
date
|
||||
stripeid
|
||||
transactionid
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,17 +95,31 @@ export const UPDATE_PAYMENTS = gql`
|
||||
update_payments(where: { id: { _in: $paymentIdList } }, _set: $payment) {
|
||||
returning {
|
||||
id
|
||||
exportedat
|
||||
transactionid
|
||||
memo
|
||||
type
|
||||
amount
|
||||
stripeid
|
||||
created_at
|
||||
date
|
||||
exportedat
|
||||
stripeid
|
||||
jobid
|
||||
job {
|
||||
id
|
||||
ownerid
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
owner {
|
||||
id
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
}
|
||||
ro_number
|
||||
}
|
||||
memo
|
||||
payer
|
||||
paymentnum
|
||||
date
|
||||
stripeid
|
||||
transactionid
|
||||
type
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -109,3 +138,36 @@ export const QUERY_JOB_PAYMENT_TOTALS = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_PAYMENT_BY_ID = gql`
|
||||
query QUERY_PAYMENT_BY_ID($paymentId: uuid!) {
|
||||
payments_by_pk(id: $paymentId) {
|
||||
id
|
||||
amount
|
||||
created_at
|
||||
exportedat
|
||||
date
|
||||
jobid
|
||||
job {
|
||||
id
|
||||
ownerid
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
owner {
|
||||
id
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
}
|
||||
ro_number
|
||||
}
|
||||
memo
|
||||
payer
|
||||
paymentnum
|
||||
stripeid
|
||||
transactionid
|
||||
type
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -19,6 +19,7 @@ export const QUERY_SCOREBOARD = gql`
|
||||
v_make_desc
|
||||
v_model_desc
|
||||
v_model_yr
|
||||
job_totals
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,22 +2,20 @@ import { gql } from "@apollo/client";
|
||||
|
||||
export const GLOBAL_SEARCH_QUERY = gql`
|
||||
query GLOBAL_SEARCH_QUERY($search: String) {
|
||||
search_jobs(args: { search: $search }) {
|
||||
search_jobs(args: { search: $search }, limit: 25) {
|
||||
id
|
||||
ro_number
|
||||
status
|
||||
|
||||
clm_no
|
||||
v_model_yr
|
||||
v_model_desc
|
||||
v_make_desc
|
||||
v_color
|
||||
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
}
|
||||
search_owners(args: { search: $search }) {
|
||||
search_owners(args: { search: $search }, limit: 25) {
|
||||
id
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
@@ -25,7 +23,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
}
|
||||
search_vehicles(args: { search: $search }) {
|
||||
search_vehicles(args: { search: $search }, limit: 25) {
|
||||
id
|
||||
v_model_yr
|
||||
v_model_desc
|
||||
@@ -34,7 +32,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
|
||||
v_vin
|
||||
plate_no
|
||||
}
|
||||
search_payments(args: { search: $search }) {
|
||||
search_payments(args: { search: $search }, limit: 25) {
|
||||
id
|
||||
amount
|
||||
paymentnum
|
||||
@@ -45,7 +43,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
|
||||
memo
|
||||
transactionid
|
||||
}
|
||||
search_bills(args: { search: $search }) {
|
||||
search_bills(args: { search: $search }, limit: 25) {
|
||||
id
|
||||
date
|
||||
invoice_number
|
||||
@@ -54,7 +52,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
|
||||
name
|
||||
}
|
||||
}
|
||||
search_phonebook(args: { search: $search }) {
|
||||
search_phonebook(args: { search: $search }, limit: 25) {
|
||||
id
|
||||
firstname
|
||||
lastname
|
||||
|
||||
@@ -59,6 +59,81 @@ export const QUERY_TIME_TICKETS_IN_RANGE = gql`
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
|
||||
query QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE(
|
||||
$employeeid: uuid!
|
||||
$start: date!
|
||||
$end: date!
|
||||
$fixedStart: date!
|
||||
$fixedEnd: date!
|
||||
) {
|
||||
timetickets(
|
||||
where: {
|
||||
date: { _gte: $start, _lte: $end }
|
||||
employeeid: { _eq: $employeeid }
|
||||
}
|
||||
order_by: { date: desc_nulls_first }
|
||||
) {
|
||||
actualhrs
|
||||
ciecacode
|
||||
clockoff
|
||||
clockon
|
||||
cost_center
|
||||
created_at
|
||||
date
|
||||
id
|
||||
rate
|
||||
productivehrs
|
||||
memo
|
||||
jobid
|
||||
flat_rate
|
||||
job {
|
||||
id
|
||||
ro_number
|
||||
}
|
||||
employeeid
|
||||
employee {
|
||||
id
|
||||
employee_number
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
}
|
||||
fixedperiod: timetickets(
|
||||
where: {
|
||||
date: { _gte: $fixedStart, _lte: $fixedEnd }
|
||||
employeeid: { _eq: $employeeid }
|
||||
}
|
||||
order_by: { date: desc_nulls_first }
|
||||
) {
|
||||
actualhrs
|
||||
ciecacode
|
||||
clockoff
|
||||
clockon
|
||||
cost_center
|
||||
created_at
|
||||
date
|
||||
id
|
||||
rate
|
||||
productivehrs
|
||||
memo
|
||||
jobid
|
||||
flat_rate
|
||||
job {
|
||||
id
|
||||
ro_number
|
||||
}
|
||||
employeeid
|
||||
employee {
|
||||
id
|
||||
employee_number
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
|
||||
query QUERY_TIME_TICKETS_IN_RANGE_SB(
|
||||
$start: date!
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { SyncOutlined, EditFilled } from "@ant-design/icons";
|
||||
import { EditFilled, SyncOutlined } from "@ant-design/icons";
|
||||
import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd";
|
||||
import axios from "axios";
|
||||
import queryString from "query-string";
|
||||
import React, { useState } from "react";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||
@@ -11,8 +12,8 @@ import PrintWrapperComponent from "../../components/print-wrapper/print-wrapper.
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPartsOrderContext: (context) =>
|
||||
@@ -29,34 +30,36 @@ export function BillsListPage({
|
||||
setPartsOrderContext,
|
||||
setBillEnterContext,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const [openSearchResults, setOpenSearchResults] = useState([]);
|
||||
const [searchLoading, setSearchLoading] = useState(false);
|
||||
const { page } = search;
|
||||
const history = useHistory();
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
filteredInfo: { text: "" },
|
||||
});
|
||||
const history = useHistory();
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const { page } = search;
|
||||
const Templates = TemplateList("bill");
|
||||
|
||||
const { t } = useTranslation();
|
||||
const columns = [
|
||||
{
|
||||
title: t("bills.fields.vendorname"),
|
||||
dataIndex: "vendorname",
|
||||
key: "vendorname",
|
||||
sortObject: (direction) => {
|
||||
return {
|
||||
vendor: {
|
||||
name: direction
|
||||
? direction === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
},
|
||||
};
|
||||
},
|
||||
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
|
||||
// sortObject: (direction) => {
|
||||
// return {
|
||||
// vendor: {
|
||||
// name: direction
|
||||
// ? direction === "descend"
|
||||
// ? "desc"
|
||||
// : "asc"
|
||||
// : "desc",
|
||||
// },
|
||||
// };
|
||||
// },
|
||||
// sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||
// sortOrder:
|
||||
// state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
|
||||
render: (text, record) => <span>{record.vendor.name}</span>,
|
||||
},
|
||||
{
|
||||
@@ -72,20 +75,20 @@ export function BillsListPage({
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
sortObject: (direction) => {
|
||||
return {
|
||||
job: {
|
||||
ro_number: direction
|
||||
? direction === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
},
|
||||
};
|
||||
},
|
||||
sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||
// sortObject: (direction) => {
|
||||
// return {
|
||||
// job: {
|
||||
// ro_number: direction
|
||||
// ? direction === "descend"
|
||||
// ? "desc"
|
||||
// : "asc"
|
||||
// : "desc",
|
||||
// },
|
||||
// };
|
||||
// },
|
||||
// sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
|
||||
// sortOrder:
|
||||
// state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||
render: (text, record) =>
|
||||
record.job && (
|
||||
<Link to={`/manage/jobs/${record.job.id}`}>
|
||||
@@ -174,7 +177,15 @@ export function BillsListPage({
|
||||
// {t("bills.actions.return")}
|
||||
// </Button>
|
||||
}
|
||||
<BillDeleteButton bill={record} />
|
||||
<BillDeleteButton
|
||||
bill={record}
|
||||
callback={(deletedBillid) => {
|
||||
//Filter out the state and set it again.
|
||||
setOpenSearchResults((currentResults) =>
|
||||
currentResults.filter((bill) => bill.id !== deletedBillid)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{record.isinhouse && (
|
||||
<PrintWrapperComponent
|
||||
templateObject={{
|
||||
@@ -199,11 +210,32 @@ export function BillsListPage({
|
||||
search.sortcolumn = sorter.order ? sorter.columnKey : null;
|
||||
search.sortorder = sorter.order;
|
||||
}
|
||||
|
||||
search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order });
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (search.search && search.search.trim() !== "") {
|
||||
searchBills();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function searchBills(value) {
|
||||
try {
|
||||
setSearchLoading(true);
|
||||
const searchData = await axios.post("/search", {
|
||||
search: value || search.search,
|
||||
index: "bills",
|
||||
});
|
||||
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
|
||||
} catch (error) {
|
||||
console.log("Error while fetching search results", error);
|
||||
} finally {
|
||||
setSearchLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={t("bills.labels.bills")}
|
||||
@@ -217,6 +249,7 @@ export function BillsListPage({
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete search.search;
|
||||
delete search.page;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
}}
|
||||
>
|
||||
@@ -243,7 +276,10 @@ export function BillsListPage({
|
||||
onSearch={(value) => {
|
||||
search.search = value;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
searchBills(value);
|
||||
}}
|
||||
loading={loading || searchLoading}
|
||||
enterButton
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
@@ -251,19 +287,27 @@ export function BillsListPage({
|
||||
<PartsOrderModalContainer />
|
||||
|
||||
<Table
|
||||
loading={loading}
|
||||
scroll={{
|
||||
x: "50%", // y: "40rem"
|
||||
}}
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
total: total,
|
||||
}}
|
||||
loading={loading || searchLoading}
|
||||
// scroll={{
|
||||
// x: "50%", // y: "40rem"
|
||||
// }}
|
||||
scroll={{ x: true }}
|
||||
pagination={
|
||||
search?.search
|
||||
? {
|
||||
pageSize: 25,
|
||||
showSizeChanger: false,
|
||||
}
|
||||
: {
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
total: total,
|
||||
showSizeChanger: false,
|
||||
}
|
||||
}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={data}
|
||||
dataSource={search?.search ? openSearchResults : data}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import queryString from "query-string";
|
||||
import React, { useEffect } from "react";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
@@ -22,7 +22,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, search, searchObj } = searchParams;
|
||||
const { page, sortcolumn, sortorder, searchObj } = searchParams;
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.bills-list");
|
||||
@@ -38,7 +38,6 @@ export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * 25 : 0,
|
||||
limit: 25,
|
||||
order: [
|
||||
@@ -61,10 +60,10 @@ export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
<RbacWrapper action="bills:list">
|
||||
<div>
|
||||
<BillsPageComponent
|
||||
data={data ? data.search_bills : []}
|
||||
data={data ? data.bills : []}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
total={data ? data.search_bills_aggregate.aggregate.count : 0}
|
||||
total={data ? data.bills_aggregate.aggregate.count : 0}
|
||||
/>
|
||||
|
||||
<BillDetailEditContainer />
|
||||
|
||||
@@ -25,7 +25,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, search, statusFilters } = searchParams;
|
||||
const { page, sortcolumn, sortorder, statusFilters } = searchParams;
|
||||
|
||||
const { loading, error, data, refetch } = useQuery(
|
||||
QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED,
|
||||
@@ -33,13 +33,12 @@ export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * 25 : 0,
|
||||
limit: 25,
|
||||
...(statusFilters ? { statusList: JSON.parse(statusFilters) } : {}),
|
||||
order: [
|
||||
{
|
||||
[sortcolumn || "created_at"]:
|
||||
[sortcolumn || "ro_number"]:
|
||||
sortorder && sortorder !== "false"
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
@@ -67,8 +66,8 @@ export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
|
||||
refetch={refetch}
|
||||
loading={loading}
|
||||
searchParams={searchParams}
|
||||
total={data ? data.search_jobs_aggregate.aggregate.count : 0}
|
||||
jobs={data ? data.search_jobs : []}
|
||||
total={data ? data.jobs_aggregate.aggregate.count : 0}
|
||||
jobs={data ? data.jobs : []}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
|
||||
@@ -52,6 +52,7 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||
import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -97,7 +98,11 @@ export function JobsDetailPage({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
...UndefinedToNull(values, ["alt_transport", "category", "referral_source"]),
|
||||
...UndefinedToNull(values, [
|
||||
"alt_transport",
|
||||
"category",
|
||||
"referral_source",
|
||||
]),
|
||||
parts_tax_rates: {
|
||||
...job.parts_tax_rates,
|
||||
...values.parts_tax_rates,
|
||||
@@ -231,6 +236,7 @@ export function JobsDetailPage({
|
||||
<ScheduleJobModalContainer />
|
||||
<JobReconciliationModal />
|
||||
<JobLineUpsertModalContainer />
|
||||
<NoteUpsertModalComponent />
|
||||
<Form
|
||||
form={form}
|
||||
name="JobDetailForm"
|
||||
|
||||
@@ -26,7 +26,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, search } = searchParams;
|
||||
const { page, sortcolumn, sortorder, searchObj } = searchParams;
|
||||
|
||||
const { loading, error, data, refetch } = useQuery(
|
||||
QUERY_ALL_PAYMENTS_PAGINATED,
|
||||
@@ -34,11 +34,12 @@ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * 25 : 0,
|
||||
limit: 25,
|
||||
order: [
|
||||
{
|
||||
searchObj
|
||||
? JSON.parse(searchObj)
|
||||
: {
|
||||
[sortcolumn || "date"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
@@ -66,8 +67,8 @@ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
refetch={refetch}
|
||||
loading={loading}
|
||||
searchParams={searchParams}
|
||||
total={data ? data.search_payments_aggregate.aggregate.count : 0}
|
||||
payments={data ? data.search_payments : []}
|
||||
total={data ? data.payments_aggregate.aggregate.count : 0}
|
||||
payments={data ? data.payments : []}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
|
||||
@@ -2,10 +2,12 @@ import { Divider } from "antd";
|
||||
import React from "react";
|
||||
import TechClockInFormContainer from "../../components/tech-job-clock-in-form/tech-job-clock-in-form.container";
|
||||
import TechClockedInList from "../../components/tech-job-clocked-in-list/tech-job-clocked-in-list.component";
|
||||
import TechJobStatistics from "../../components/tech-job-statistics/tech-job-statistics.component";
|
||||
|
||||
export default function TechClockComponent() {
|
||||
return (
|
||||
<div>
|
||||
<TechJobStatistics />
|
||||
<TechClockInFormContainer />
|
||||
<Divider />
|
||||
<TechClockedInList />
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
.tech-content-container {
|
||||
overflow-y: auto;
|
||||
overflow-y: visible;
|
||||
padding: 1rem;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.tech-layout-container {
|
||||
height: 100vh;
|
||||
position: relative;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"scheduledfor": "Scheduled appointment for: ",
|
||||
"severalerrorsfound": "Several jobs have issues which may prevent accurate smart scheduling. Click to expand.",
|
||||
"smartscheduling": "Smart Scheduling",
|
||||
"smspaymentreminder": "",
|
||||
"suggesteddates": "Suggested Dates"
|
||||
},
|
||||
"successes": {
|
||||
@@ -103,6 +104,7 @@
|
||||
"admin_jobunvoid": "ADMIN: Job has been unvoided.",
|
||||
"billposted": "Bill with invoice number {{invoice_number}} posted.",
|
||||
"billupdated": "Bill with invoice number {{invoice_number}} updated.",
|
||||
"failedpayment": "",
|
||||
"jobassignmentchange": "Employee {{name}} assigned to {{operation}}",
|
||||
"jobassignmentremoved": "Employee assignment removed for {{operation}}",
|
||||
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
|
||||
@@ -227,6 +229,7 @@
|
||||
},
|
||||
"bodyshop": {
|
||||
"actions": {
|
||||
"add_task_preset": "",
|
||||
"addapptcolor": "Add Appointment Color",
|
||||
"addbucket": "Add Definition",
|
||||
"addpartslocation": "Add Parts Location",
|
||||
@@ -339,6 +342,12 @@
|
||||
},
|
||||
"md_payment_types": "Payment Types",
|
||||
"md_referral_sources": "Referral Sources",
|
||||
"md_tasks_presets": {
|
||||
"hourstype": "",
|
||||
"memo": "",
|
||||
"name": "",
|
||||
"percent": ""
|
||||
},
|
||||
"messaginglabel": "Messaging Preset Label",
|
||||
"messagingtext": "Messaging Preset Text",
|
||||
"noteslabel": "Note Label",
|
||||
@@ -374,6 +383,9 @@
|
||||
"export": "CSI -> Export",
|
||||
"page": "CSI -> Page"
|
||||
},
|
||||
"employee_teams": {
|
||||
"page": ""
|
||||
},
|
||||
"employees": {
|
||||
"page": "Employees -> List"
|
||||
},
|
||||
@@ -432,10 +444,15 @@
|
||||
},
|
||||
"timetickets": {
|
||||
"edit": "Time Tickets -> Edit",
|
||||
"editcommitted": "",
|
||||
"enter": "Time Tickets -> Enter",
|
||||
"list": "Time Tickets -> List",
|
||||
"shiftedit": "Time Tickets -> Shift Edit"
|
||||
},
|
||||
"ttapprovals": {
|
||||
"approve": "",
|
||||
"view": ""
|
||||
},
|
||||
"users": {
|
||||
"editaccess": "Users -> Edit access"
|
||||
}
|
||||
@@ -453,6 +470,8 @@
|
||||
"federal_tax": "Federal Tax",
|
||||
"federal_tax_itc": "Federal Tax Credit",
|
||||
"gst_override": "GST Override Account #",
|
||||
"invoiceexemptcode": "",
|
||||
"itemexemptcode": "",
|
||||
"la1": "LA1",
|
||||
"la2": "LA2",
|
||||
"la3": "LA3",
|
||||
@@ -504,6 +523,7 @@
|
||||
"dailyhrslimit": "Daily Incoming Hours Limit"
|
||||
},
|
||||
"ssbuckets": {
|
||||
"color": "Job Color",
|
||||
"gte": "Greater Than/Equal to (hrs)",
|
||||
"id": "ID",
|
||||
"label": "Label",
|
||||
@@ -541,7 +561,9 @@
|
||||
"target_touchtime": "Target Touch Time",
|
||||
"timezone": "Timezone",
|
||||
"tt_allow_post_to_invoiced": "Allow Time Tickets to be posted to Invoiced & Exported Jobs",
|
||||
"tt_enforce_hours_for_tech_console": "Restrict Claimable hours from Tech Console",
|
||||
"use_fippa": "Use FIPPA for Names on Generated Documents?",
|
||||
"use_paint_scale_data": "Use Paint Scale Data for Job Costing?",
|
||||
"uselocalmediaserver": "Use Local Media Server?",
|
||||
"website": "Website",
|
||||
"zip_post": "Zip/Postal Code"
|
||||
@@ -572,6 +594,7 @@
|
||||
"title": "DMS"
|
||||
},
|
||||
"emaillater": "Email Later",
|
||||
"employee_teams": "",
|
||||
"employees": "Employees",
|
||||
"estimators": "Estimators",
|
||||
"filehandlers": "File Handlers",
|
||||
@@ -580,6 +603,7 @@
|
||||
"jobstatuses": "Job Statuses",
|
||||
"laborrates": "Labor Rates",
|
||||
"licensing": "Licensing",
|
||||
"md_tasks_presets": "",
|
||||
"md_to_emails": "Preset To Emails",
|
||||
"md_to_emails_emails": "Emails",
|
||||
"messagingpresets": "Messaging Presets",
|
||||
@@ -606,6 +630,7 @@
|
||||
"speedprint": "Speed Print Configuration",
|
||||
"ssbuckets": "Job Size Definitions",
|
||||
"systemsettings": "System Settings",
|
||||
"task-presets": "",
|
||||
"workingdays": "Working Days"
|
||||
},
|
||||
"successes": {
|
||||
@@ -905,6 +930,18 @@
|
||||
"sent": "Email sent successfully."
|
||||
}
|
||||
},
|
||||
"employee_teams": {
|
||||
"actions": {
|
||||
"new": "",
|
||||
"newmember": ""
|
||||
},
|
||||
"fields": {
|
||||
"active": "",
|
||||
"employeeid": "",
|
||||
"name": "",
|
||||
"percentage": ""
|
||||
}
|
||||
},
|
||||
"employees": {
|
||||
"actions": {
|
||||
"addvacation": "Add Vacation",
|
||||
@@ -1014,6 +1051,7 @@
|
||||
"created_at": "Created At",
|
||||
"email": "Email",
|
||||
"errors": "Errors",
|
||||
"excel": "Excel",
|
||||
"exceptiontitle": "An error has occurred.",
|
||||
"friday": "Friday",
|
||||
"globalsearch": "Global Search",
|
||||
@@ -1063,6 +1101,7 @@
|
||||
"sunday": "Sunday",
|
||||
"text": "Text",
|
||||
"thursday": "Thursday",
|
||||
"total": "Total",
|
||||
"totals": "Totals",
|
||||
"tuesday": "Tuesday",
|
||||
"unknown": "Unknown",
|
||||
@@ -1142,6 +1181,30 @@
|
||||
"updated": "Inventory line updated."
|
||||
}
|
||||
},
|
||||
"job_payments": {
|
||||
"buttons": {
|
||||
"goback": "",
|
||||
"proceedtopayment": "",
|
||||
"refundpayment": ""
|
||||
},
|
||||
"notifications": {
|
||||
"error": {
|
||||
"description": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"amount": "",
|
||||
"dateOfPayment": "",
|
||||
"descriptions": "",
|
||||
"payer": "",
|
||||
"payername": "",
|
||||
"paymentid": "",
|
||||
"paymenttype": "",
|
||||
"refundamount": "",
|
||||
"transactionid": ""
|
||||
}
|
||||
},
|
||||
"joblines": {
|
||||
"actions": {
|
||||
"converttolabor": "Convert amount to Labor.",
|
||||
@@ -1374,7 +1437,7 @@
|
||||
"ded_amt": "Deductible",
|
||||
"ded_note": "Deductible Note",
|
||||
"ded_status": "Deductible Status",
|
||||
"depreciation_taxes": "Depreciation/Taxes",
|
||||
"depreciation_taxes": "Betterment/Depreciation/Taxes",
|
||||
"dms": {
|
||||
"address": "Customer Address",
|
||||
"amount": "Amount",
|
||||
@@ -1574,6 +1637,7 @@
|
||||
"scheddates": "Schedule Dates"
|
||||
},
|
||||
"labels": {
|
||||
"act_price_ppc": "",
|
||||
"actual_completion_inferred": "$t(jobs.fields.actual_completion) inferred using $t(jobs.fields.scheduled_completion).",
|
||||
"actual_delivery_inferred": "$t(jobs.fields.actual_delivery) inferred using $t(jobs.fields.scheduled_delivery).",
|
||||
"actual_in_inferred": "$t(jobs.fields.actual_in) inferred using $t(jobs.fields.scheduled_in).",
|
||||
@@ -1710,6 +1774,7 @@
|
||||
"partstotal": "This is the total of all parts and sublet amounts on the vehicle (some of these may require an in-house invoice).<br/>\nItems such as shop and paint materials, labor online lines, etc. are not included in this total.",
|
||||
"totalreturns": "The total <b>retail</b> amount of returns created for this job."
|
||||
},
|
||||
"ppc": "",
|
||||
"profileadjustments": "",
|
||||
"prt_dsmk_total": "Line Item Adjustment",
|
||||
"rates": "Rates",
|
||||
@@ -1850,6 +1915,7 @@
|
||||
"customers": "Customers",
|
||||
"dashboard": "Dashboard",
|
||||
"enterbills": "Enter Bills",
|
||||
"entercardpayment": "",
|
||||
"enterpayment": "Enter Payments",
|
||||
"entertimeticket": "Enter Time Tickets",
|
||||
"export": "Export",
|
||||
@@ -1861,6 +1927,7 @@
|
||||
"newjob": "Create New Job",
|
||||
"owners": "Owners",
|
||||
"parts-queue": "Parts Queue",
|
||||
"paymentremindersms": "",
|
||||
"phonebook": "Phonebook",
|
||||
"productionboard": "Production Board - Visual",
|
||||
"productionlist": "Production Board - List",
|
||||
@@ -1886,6 +1953,7 @@
|
||||
"shop_vendors": "Vendors",
|
||||
"temporarydocs": "Temporary Documents",
|
||||
"timetickets": "Time Tickets",
|
||||
"ttapprovals": "",
|
||||
"vehicles": "Vehicles"
|
||||
},
|
||||
"jobsactions": {
|
||||
@@ -1958,7 +2026,8 @@
|
||||
"actions": "Actions",
|
||||
"deletenote": "Delete Note",
|
||||
"edit": "Edit Note",
|
||||
"new": "New Note"
|
||||
"new": "New Note",
|
||||
"savetojobnotes": "Save to Job Notes"
|
||||
},
|
||||
"errors": {
|
||||
"inserting": "Error inserting note. {{error}}"
|
||||
@@ -1968,6 +2037,16 @@
|
||||
"critical": "Critical",
|
||||
"private": "Private",
|
||||
"text": "Contents",
|
||||
"type": "Type",
|
||||
"types": {
|
||||
"customer": "Customer",
|
||||
"general": "General",
|
||||
"office": "Office",
|
||||
"paint": "Paint",
|
||||
"parts": "Parts",
|
||||
"shop": "Shop",
|
||||
"supplement": "Supplement"
|
||||
},
|
||||
"updatedat": "Updated At"
|
||||
},
|
||||
"labels": {
|
||||
@@ -2138,10 +2217,13 @@
|
||||
"new": "New Payment",
|
||||
"signup": "Please contact support to sign up for electronic payments.",
|
||||
"title": "Payments",
|
||||
"totalpayments": "Total Payments"
|
||||
"totalpayments": "Total Payments",
|
||||
"markexported": "Mark Exported",
|
||||
"markforreexport": "Mark for Re-export"
|
||||
},
|
||||
"successes": {
|
||||
"exported": "Payment(s) exported successfully.",
|
||||
"markreexported": "Payment marked for re-export successfully",
|
||||
"markexported": "Payment(s) marked exported.",
|
||||
"payment": "Payment created successfully. ",
|
||||
"stripe": "Credit card transaction charged successfully."
|
||||
@@ -2224,6 +2306,7 @@
|
||||
"csi_invitation": "CSI Invitation",
|
||||
"csi_invitation_action": "CSI Invite",
|
||||
"diagnostic_authorization": "Diagnostic Authorization",
|
||||
"dms_posting_sheet": "DMS Posting Sheet",
|
||||
"envelope_return_address": "#10 Envelope Return Address Label",
|
||||
"estimate": "Estimate Only",
|
||||
"estimate_detail": "Estimate Details",
|
||||
@@ -2357,6 +2440,7 @@
|
||||
"qbo_usa": "QBO USA"
|
||||
}
|
||||
},
|
||||
"cardcolor": "Card Colors",
|
||||
"cardsettings": "Card Settings",
|
||||
"clm_no": "Claim Number",
|
||||
"comment": "Comment",
|
||||
@@ -2367,6 +2451,7 @@
|
||||
"ins_co_nm": "Insurance Company Name",
|
||||
"jobdetail": "Job Details",
|
||||
"laborhrs": "Labor Hours",
|
||||
"legend": "Legend:",
|
||||
"note": "Production Note",
|
||||
"ownr_nm": "Owner Name",
|
||||
"paintpriority": "P/P",
|
||||
@@ -2442,6 +2527,8 @@
|
||||
"export_payables": "Export Log - Payables",
|
||||
"export_payments": "Export Log - Payments",
|
||||
"export_receivables": "Export Log - Receivables",
|
||||
"exported_gsr_by_ro": "Exported Gross Sales - Excel",
|
||||
"exported_gsr_by_ro_labor": "Exported Gross Sales (Labor) - Excel",
|
||||
"gsr_by_atp": "",
|
||||
"gsr_by_ats": "Gross Sales by ATS",
|
||||
"gsr_by_category": "Gross Sales by Category",
|
||||
@@ -2603,6 +2690,7 @@
|
||||
},
|
||||
"timetickets": {
|
||||
"actions": {
|
||||
"claimtasks": "",
|
||||
"clockin": "Clock In",
|
||||
"clockout": "Clock Out",
|
||||
"enter": "Enter New Time Ticket",
|
||||
@@ -2623,10 +2711,12 @@
|
||||
"clockhours": "Clock Hours",
|
||||
"clockoff": "Clock Off",
|
||||
"clockon": "Clocked In",
|
||||
"committed": "",
|
||||
"cost_center": "Cost Center",
|
||||
"date": "Ticket Date",
|
||||
"efficiency": "Efficiency",
|
||||
"employee": "Employee",
|
||||
"employee_team": "",
|
||||
"flat_rate": "Flat Rate?",
|
||||
"memo": "Memo",
|
||||
"productivehrs": "Productive Hours",
|
||||
@@ -2661,7 +2751,8 @@
|
||||
},
|
||||
"validation": {
|
||||
"clockoffmustbeafterclockon": "Clock off time must be the same or after clock in time.",
|
||||
"clockoffwithoutclockon": "Clock off time cannot be set without a clock in time."
|
||||
"clockoffwithoutclockon": "Clock off time cannot be set without a clock in time.",
|
||||
"hoursenteredmorethanavailable": "The number of hours entered is more than what is available for this cost center."
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
@@ -2712,6 +2803,7 @@
|
||||
"shop-vendors": "Vendors",
|
||||
"temporarydocs": "Temporary Documents",
|
||||
"timetickets": "Time Tickets",
|
||||
"ttapprovals": "",
|
||||
"vehicle-details": "Vehicle: {{vehicle}}",
|
||||
"vehicles": "Vehicles"
|
||||
},
|
||||
@@ -2757,9 +2849,15 @@
|
||||
"shop_vendors": "Vendors | $t(titles.app)",
|
||||
"temporarydocs": "Temporary Documents | $t(titles.app)",
|
||||
"timetickets": "Time Tickets | $t(titles.app)",
|
||||
"ttapprovals": "",
|
||||
"vehicledetail": "Vehicle Details {{vehicle}} | $t(titles.app)",
|
||||
"vehicles": "All Vehicles | $t(titles.app)"
|
||||
},
|
||||
"tt_approvals": {
|
||||
"actions": {
|
||||
"approveselected": ""
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"actions": {
|
||||
"changepassword": "Change Password",
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"scheduledfor": "Cita programada para:",
|
||||
"severalerrorsfound": "",
|
||||
"smartscheduling": "",
|
||||
"smspaymentreminder": "",
|
||||
"suggesteddates": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -103,6 +104,7 @@
|
||||
"admin_jobunvoid": "",
|
||||
"billposted": "",
|
||||
"billupdated": "",
|
||||
"failedpayment": "",
|
||||
"jobassignmentchange": "",
|
||||
"jobassignmentremoved": "",
|
||||
"jobchecklist": "",
|
||||
@@ -227,6 +229,7 @@
|
||||
},
|
||||
"bodyshop": {
|
||||
"actions": {
|
||||
"add_task_preset": "",
|
||||
"addapptcolor": "",
|
||||
"addbucket": "",
|
||||
"addpartslocation": "",
|
||||
@@ -339,6 +342,12 @@
|
||||
},
|
||||
"md_payment_types": "",
|
||||
"md_referral_sources": "",
|
||||
"md_tasks_presets": {
|
||||
"hourstype": "",
|
||||
"memo": "",
|
||||
"name": "",
|
||||
"percent": ""
|
||||
},
|
||||
"messaginglabel": "",
|
||||
"messagingtext": "",
|
||||
"noteslabel": "",
|
||||
@@ -374,6 +383,9 @@
|
||||
"export": "",
|
||||
"page": ""
|
||||
},
|
||||
"employee_teams": {
|
||||
"page": ""
|
||||
},
|
||||
"employees": {
|
||||
"page": ""
|
||||
},
|
||||
@@ -432,10 +444,15 @@
|
||||
},
|
||||
"timetickets": {
|
||||
"edit": "",
|
||||
"editcommitted": "",
|
||||
"enter": "",
|
||||
"list": "",
|
||||
"shiftedit": ""
|
||||
},
|
||||
"ttapprovals": {
|
||||
"approve": "",
|
||||
"view": ""
|
||||
},
|
||||
"users": {
|
||||
"editaccess": ""
|
||||
}
|
||||
@@ -453,6 +470,8 @@
|
||||
"federal_tax": "",
|
||||
"federal_tax_itc": "",
|
||||
"gst_override": "",
|
||||
"invoiceexemptcode": "",
|
||||
"itemexemptcode": "",
|
||||
"la1": "",
|
||||
"la2": "",
|
||||
"la3": "",
|
||||
@@ -504,6 +523,7 @@
|
||||
"dailyhrslimit": ""
|
||||
},
|
||||
"ssbuckets": {
|
||||
"color": "",
|
||||
"gte": "",
|
||||
"id": "",
|
||||
"label": "",
|
||||
@@ -541,7 +561,9 @@
|
||||
"target_touchtime": "",
|
||||
"timezone": "",
|
||||
"tt_allow_post_to_invoiced": "",
|
||||
"tt_enforce_hours_for_tech_console": "",
|
||||
"use_fippa": "",
|
||||
"use_paint_scale_data": "",
|
||||
"uselocalmediaserver": "",
|
||||
"website": "",
|
||||
"zip_post": ""
|
||||
@@ -572,6 +594,7 @@
|
||||
"title": ""
|
||||
},
|
||||
"emaillater": "",
|
||||
"employee_teams": "",
|
||||
"employees": "",
|
||||
"estimators": "",
|
||||
"filehandlers": "",
|
||||
@@ -580,6 +603,7 @@
|
||||
"jobstatuses": "",
|
||||
"laborrates": "",
|
||||
"licensing": "",
|
||||
"md_tasks_presets": "",
|
||||
"md_to_emails": "",
|
||||
"md_to_emails_emails": "",
|
||||
"messagingpresets": "",
|
||||
@@ -606,6 +630,7 @@
|
||||
"speedprint": "",
|
||||
"ssbuckets": "",
|
||||
"systemsettings": "",
|
||||
"task-presets": "",
|
||||
"workingdays": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -905,6 +930,18 @@
|
||||
"sent": "Correo electrónico enviado con éxito."
|
||||
}
|
||||
},
|
||||
"employee_teams": {
|
||||
"actions": {
|
||||
"new": "",
|
||||
"newmember": ""
|
||||
},
|
||||
"fields": {
|
||||
"active": "",
|
||||
"employeeid": "",
|
||||
"name": "",
|
||||
"percentage": ""
|
||||
}
|
||||
},
|
||||
"employees": {
|
||||
"actions": {
|
||||
"addvacation": "",
|
||||
@@ -1014,6 +1051,7 @@
|
||||
"created_at": "",
|
||||
"email": "",
|
||||
"errors": "",
|
||||
"excel": "",
|
||||
"exceptiontitle": "",
|
||||
"friday": "",
|
||||
"globalsearch": "",
|
||||
@@ -1063,6 +1101,7 @@
|
||||
"sunday": "",
|
||||
"text": "",
|
||||
"thursday": "",
|
||||
"total": "",
|
||||
"totals": "",
|
||||
"tuesday": "",
|
||||
"unknown": "Desconocido",
|
||||
@@ -1142,6 +1181,30 @@
|
||||
"updated": ""
|
||||
}
|
||||
},
|
||||
"job_payments": {
|
||||
"buttons": {
|
||||
"goback": "",
|
||||
"proceedtopayment": "",
|
||||
"refundpayment": ""
|
||||
},
|
||||
"notifications": {
|
||||
"error": {
|
||||
"description": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"amount": "",
|
||||
"dateOfPayment": "",
|
||||
"descriptions": "",
|
||||
"payer": "",
|
||||
"payername": "",
|
||||
"paymentid": "",
|
||||
"paymenttype": "",
|
||||
"refundamount": "",
|
||||
"transactionid": ""
|
||||
}
|
||||
},
|
||||
"joblines": {
|
||||
"actions": {
|
||||
"converttolabor": "",
|
||||
@@ -1574,6 +1637,7 @@
|
||||
"scheddates": ""
|
||||
},
|
||||
"labels": {
|
||||
"act_price_ppc": "",
|
||||
"actual_completion_inferred": "",
|
||||
"actual_delivery_inferred": "",
|
||||
"actual_in_inferred": "",
|
||||
@@ -1710,6 +1774,7 @@
|
||||
"partstotal": "",
|
||||
"totalreturns": ""
|
||||
},
|
||||
"ppc": "",
|
||||
"profileadjustments": "",
|
||||
"prt_dsmk_total": "",
|
||||
"rates": "Tarifas",
|
||||
@@ -1850,6 +1915,7 @@
|
||||
"customers": "Clientes",
|
||||
"dashboard": "",
|
||||
"enterbills": "",
|
||||
"entercardpayment": "",
|
||||
"enterpayment": "",
|
||||
"entertimeticket": "",
|
||||
"export": "",
|
||||
@@ -1861,6 +1927,7 @@
|
||||
"newjob": "",
|
||||
"owners": "propietarios",
|
||||
"parts-queue": "",
|
||||
"paymentremindersms": "",
|
||||
"phonebook": "",
|
||||
"productionboard": "",
|
||||
"productionlist": "",
|
||||
@@ -1886,6 +1953,7 @@
|
||||
"shop_vendors": "Vendedores",
|
||||
"temporarydocs": "",
|
||||
"timetickets": "",
|
||||
"ttapprovals": "",
|
||||
"vehicles": "Vehículos"
|
||||
},
|
||||
"jobsactions": {
|
||||
@@ -1958,7 +2026,8 @@
|
||||
"actions": "Comportamiento",
|
||||
"deletenote": "Borrar nota",
|
||||
"edit": "Editar nota",
|
||||
"new": "Nueva nota"
|
||||
"new": "Nueva nota",
|
||||
"savetojobnotes": ""
|
||||
},
|
||||
"errors": {
|
||||
"inserting": ""
|
||||
@@ -1968,6 +2037,16 @@
|
||||
"critical": "Crítico",
|
||||
"private": "Privado",
|
||||
"text": "Contenido",
|
||||
"type": "",
|
||||
"types": {
|
||||
"customer": "",
|
||||
"general": "",
|
||||
"office": "",
|
||||
"paint": "",
|
||||
"parts": "",
|
||||
"shop": "",
|
||||
"supplement": ""
|
||||
},
|
||||
"updatedat": "Actualizado en"
|
||||
},
|
||||
"labels": {
|
||||
@@ -2224,6 +2303,7 @@
|
||||
"csi_invitation": "",
|
||||
"csi_invitation_action": "",
|
||||
"diagnostic_authorization": "",
|
||||
"dms_posting_sheet": "",
|
||||
"envelope_return_address": "",
|
||||
"estimate": "",
|
||||
"estimate_detail": "",
|
||||
@@ -2357,6 +2437,7 @@
|
||||
"qbo_usa": ""
|
||||
}
|
||||
},
|
||||
"cardcolor": "",
|
||||
"cardsettings": "",
|
||||
"clm_no": "",
|
||||
"comment": "",
|
||||
@@ -2367,6 +2448,7 @@
|
||||
"ins_co_nm": "",
|
||||
"jobdetail": "",
|
||||
"laborhrs": "",
|
||||
"legend": "",
|
||||
"note": "",
|
||||
"ownr_nm": "",
|
||||
"paintpriority": "",
|
||||
@@ -2442,6 +2524,8 @@
|
||||
"export_payables": "",
|
||||
"export_payments": "",
|
||||
"export_receivables": "",
|
||||
"exported_gsr_by_ro": "",
|
||||
"exported_gsr_by_ro_labor": "",
|
||||
"gsr_by_atp": "",
|
||||
"gsr_by_ats": "",
|
||||
"gsr_by_category": "",
|
||||
@@ -2603,6 +2687,7 @@
|
||||
},
|
||||
"timetickets": {
|
||||
"actions": {
|
||||
"claimtasks": "",
|
||||
"clockin": "",
|
||||
"clockout": "",
|
||||
"enter": "",
|
||||
@@ -2623,10 +2708,12 @@
|
||||
"clockhours": "",
|
||||
"clockoff": "",
|
||||
"clockon": "",
|
||||
"committed": "",
|
||||
"cost_center": "",
|
||||
"date": "",
|
||||
"efficiency": "",
|
||||
"employee": "",
|
||||
"employee_team": "",
|
||||
"flat_rate": "",
|
||||
"memo": "",
|
||||
"productivehrs": "",
|
||||
@@ -2661,7 +2748,8 @@
|
||||
},
|
||||
"validation": {
|
||||
"clockoffmustbeafterclockon": "",
|
||||
"clockoffwithoutclockon": ""
|
||||
"clockoffwithoutclockon": "",
|
||||
"hoursenteredmorethanavailable": ""
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
@@ -2712,6 +2800,7 @@
|
||||
"shop-vendors": "",
|
||||
"temporarydocs": "",
|
||||
"timetickets": "",
|
||||
"ttapprovals": "",
|
||||
"vehicle-details": "",
|
||||
"vehicles": ""
|
||||
},
|
||||
@@ -2757,9 +2846,15 @@
|
||||
"shop_vendors": "Vendedores | $t(titles.app)",
|
||||
"temporarydocs": "",
|
||||
"timetickets": "",
|
||||
"ttapprovals": "",
|
||||
"vehicledetail": "Detalles del vehículo {{vehicle}} | $t(titles.app)",
|
||||
"vehicles": "Todos los vehiculos | $t(titles.app)"
|
||||
},
|
||||
"tt_approvals": {
|
||||
"actions": {
|
||||
"approveselected": ""
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"actions": {
|
||||
"changepassword": "",
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"scheduledfor": "Rendez-vous prévu pour:",
|
||||
"severalerrorsfound": "",
|
||||
"smartscheduling": "",
|
||||
"smspaymentreminder": "",
|
||||
"suggesteddates": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -103,6 +104,7 @@
|
||||
"admin_jobunvoid": "",
|
||||
"billposted": "",
|
||||
"billupdated": "",
|
||||
"failedpayment": "",
|
||||
"jobassignmentchange": "",
|
||||
"jobassignmentremoved": "",
|
||||
"jobchecklist": "",
|
||||
@@ -227,6 +229,7 @@
|
||||
},
|
||||
"bodyshop": {
|
||||
"actions": {
|
||||
"add_task_preset": "",
|
||||
"addapptcolor": "",
|
||||
"addbucket": "",
|
||||
"addpartslocation": "",
|
||||
@@ -339,6 +342,12 @@
|
||||
},
|
||||
"md_payment_types": "",
|
||||
"md_referral_sources": "",
|
||||
"md_tasks_presets": {
|
||||
"hourstype": "",
|
||||
"memo": "",
|
||||
"name": "",
|
||||
"percent": ""
|
||||
},
|
||||
"messaginglabel": "",
|
||||
"messagingtext": "",
|
||||
"noteslabel": "",
|
||||
@@ -374,6 +383,9 @@
|
||||
"export": "",
|
||||
"page": ""
|
||||
},
|
||||
"employee_teams": {
|
||||
"page": ""
|
||||
},
|
||||
"employees": {
|
||||
"page": ""
|
||||
},
|
||||
@@ -432,10 +444,15 @@
|
||||
},
|
||||
"timetickets": {
|
||||
"edit": "",
|
||||
"editcommitted": "",
|
||||
"enter": "",
|
||||
"list": "",
|
||||
"shiftedit": ""
|
||||
},
|
||||
"ttapprovals": {
|
||||
"approve": "",
|
||||
"view": ""
|
||||
},
|
||||
"users": {
|
||||
"editaccess": ""
|
||||
}
|
||||
@@ -453,6 +470,8 @@
|
||||
"federal_tax": "",
|
||||
"federal_tax_itc": "",
|
||||
"gst_override": "",
|
||||
"invoiceexemptcode": "",
|
||||
"itemexemptcode": "",
|
||||
"la1": "",
|
||||
"la2": "",
|
||||
"la3": "",
|
||||
@@ -504,6 +523,7 @@
|
||||
"dailyhrslimit": ""
|
||||
},
|
||||
"ssbuckets": {
|
||||
"color": "",
|
||||
"gte": "",
|
||||
"id": "",
|
||||
"label": "",
|
||||
@@ -541,7 +561,9 @@
|
||||
"target_touchtime": "",
|
||||
"timezone": "",
|
||||
"tt_allow_post_to_invoiced": "",
|
||||
"tt_enforce_hours_for_tech_console": "",
|
||||
"use_fippa": "",
|
||||
"use_paint_scale_data": "",
|
||||
"uselocalmediaserver": "",
|
||||
"website": "",
|
||||
"zip_post": ""
|
||||
@@ -572,6 +594,7 @@
|
||||
"title": ""
|
||||
},
|
||||
"emaillater": "",
|
||||
"employee_teams": "",
|
||||
"employees": "",
|
||||
"estimators": "",
|
||||
"filehandlers": "",
|
||||
@@ -580,6 +603,7 @@
|
||||
"jobstatuses": "",
|
||||
"laborrates": "",
|
||||
"licensing": "",
|
||||
"md_tasks_presets": "",
|
||||
"md_to_emails": "",
|
||||
"md_to_emails_emails": "",
|
||||
"messagingpresets": "",
|
||||
@@ -606,6 +630,7 @@
|
||||
"speedprint": "",
|
||||
"ssbuckets": "",
|
||||
"systemsettings": "",
|
||||
"task-presets": "",
|
||||
"workingdays": ""
|
||||
},
|
||||
"successes": {
|
||||
@@ -905,6 +930,18 @@
|
||||
"sent": "E-mail envoyé avec succès."
|
||||
}
|
||||
},
|
||||
"employee_teams": {
|
||||
"actions": {
|
||||
"new": "",
|
||||
"newmember": ""
|
||||
},
|
||||
"fields": {
|
||||
"active": "",
|
||||
"employeeid": "",
|
||||
"name": "",
|
||||
"percentage": ""
|
||||
}
|
||||
},
|
||||
"employees": {
|
||||
"actions": {
|
||||
"addvacation": "",
|
||||
@@ -1014,6 +1051,7 @@
|
||||
"created_at": "",
|
||||
"email": "",
|
||||
"errors": "",
|
||||
"excel": "",
|
||||
"exceptiontitle": "",
|
||||
"friday": "",
|
||||
"globalsearch": "",
|
||||
@@ -1063,6 +1101,7 @@
|
||||
"sunday": "",
|
||||
"text": "",
|
||||
"thursday": "",
|
||||
"total": "",
|
||||
"totals": "",
|
||||
"tuesday": "",
|
||||
"unknown": "Inconnu",
|
||||
@@ -1142,6 +1181,30 @@
|
||||
"updated": ""
|
||||
}
|
||||
},
|
||||
"job_payments": {
|
||||
"buttons": {
|
||||
"goback": "",
|
||||
"proceedtopayment": "",
|
||||
"refundpayment": ""
|
||||
},
|
||||
"notifications": {
|
||||
"error": {
|
||||
"description": "",
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
"amount": "",
|
||||
"dateOfPayment": "",
|
||||
"descriptions": "",
|
||||
"payer": "",
|
||||
"payername": "",
|
||||
"paymentid": "",
|
||||
"paymenttype": "",
|
||||
"refundamount": "",
|
||||
"transactionid": ""
|
||||
}
|
||||
},
|
||||
"joblines": {
|
||||
"actions": {
|
||||
"converttolabor": "",
|
||||
@@ -1574,6 +1637,7 @@
|
||||
"scheddates": ""
|
||||
},
|
||||
"labels": {
|
||||
"act_price_ppc": "",
|
||||
"actual_completion_inferred": "",
|
||||
"actual_delivery_inferred": "",
|
||||
"actual_in_inferred": "",
|
||||
@@ -1710,6 +1774,7 @@
|
||||
"partstotal": "",
|
||||
"totalreturns": ""
|
||||
},
|
||||
"ppc": "",
|
||||
"profileadjustments": "",
|
||||
"prt_dsmk_total": "",
|
||||
"rates": "Les taux",
|
||||
@@ -1850,6 +1915,7 @@
|
||||
"customers": "Les clients",
|
||||
"dashboard": "",
|
||||
"enterbills": "",
|
||||
"entercardpayment": "",
|
||||
"enterpayment": "",
|
||||
"entertimeticket": "",
|
||||
"export": "",
|
||||
@@ -1861,6 +1927,7 @@
|
||||
"newjob": "",
|
||||
"owners": "Propriétaires",
|
||||
"parts-queue": "",
|
||||
"paymentremindersms": "",
|
||||
"phonebook": "",
|
||||
"productionboard": "",
|
||||
"productionlist": "",
|
||||
@@ -1886,6 +1953,7 @@
|
||||
"shop_vendors": "Vendeurs",
|
||||
"temporarydocs": "",
|
||||
"timetickets": "",
|
||||
"ttapprovals": "",
|
||||
"vehicles": "Véhicules"
|
||||
},
|
||||
"jobsactions": {
|
||||
@@ -1958,7 +2026,8 @@
|
||||
"actions": "actes",
|
||||
"deletenote": "Supprimer la note",
|
||||
"edit": "Note éditée",
|
||||
"new": "Nouvelle note"
|
||||
"new": "Nouvelle note",
|
||||
"savetojobnotes": ""
|
||||
},
|
||||
"errors": {
|
||||
"inserting": ""
|
||||
@@ -1968,6 +2037,16 @@
|
||||
"critical": "Critique",
|
||||
"private": "privé",
|
||||
"text": "Contenu",
|
||||
"type": "",
|
||||
"types": {
|
||||
"customer": "",
|
||||
"general": "",
|
||||
"office": "",
|
||||
"paint": "",
|
||||
"parts": "",
|
||||
"shop": "",
|
||||
"supplement": ""
|
||||
},
|
||||
"updatedat": "Mis à jour à"
|
||||
},
|
||||
"labels": {
|
||||
@@ -2224,6 +2303,7 @@
|
||||
"csi_invitation": "",
|
||||
"csi_invitation_action": "",
|
||||
"diagnostic_authorization": "",
|
||||
"dms_posting_sheet": "",
|
||||
"envelope_return_address": "",
|
||||
"estimate": "",
|
||||
"estimate_detail": "",
|
||||
@@ -2357,6 +2437,7 @@
|
||||
"qbo_usa": ""
|
||||
}
|
||||
},
|
||||
"cardcolor": "",
|
||||
"cardsettings": "",
|
||||
"clm_no": "",
|
||||
"comment": "",
|
||||
@@ -2367,6 +2448,7 @@
|
||||
"ins_co_nm": "",
|
||||
"jobdetail": "",
|
||||
"laborhrs": "",
|
||||
"legend": "",
|
||||
"note": "",
|
||||
"ownr_nm": "",
|
||||
"paintpriority": "",
|
||||
@@ -2442,6 +2524,8 @@
|
||||
"export_payables": "",
|
||||
"export_payments": "",
|
||||
"export_receivables": "",
|
||||
"exported_gsr_by_ro": "",
|
||||
"exported_gsr_by_ro_labor": "",
|
||||
"gsr_by_atp": "",
|
||||
"gsr_by_ats": "",
|
||||
"gsr_by_category": "",
|
||||
@@ -2603,6 +2687,7 @@
|
||||
},
|
||||
"timetickets": {
|
||||
"actions": {
|
||||
"claimtasks": "",
|
||||
"clockin": "",
|
||||
"clockout": "",
|
||||
"enter": "",
|
||||
@@ -2623,10 +2708,12 @@
|
||||
"clockhours": "",
|
||||
"clockoff": "",
|
||||
"clockon": "",
|
||||
"committed": "",
|
||||
"cost_center": "",
|
||||
"date": "",
|
||||
"efficiency": "",
|
||||
"employee": "",
|
||||
"employee_team": "",
|
||||
"flat_rate": "",
|
||||
"memo": "",
|
||||
"productivehrs": "",
|
||||
@@ -2661,7 +2748,8 @@
|
||||
},
|
||||
"validation": {
|
||||
"clockoffmustbeafterclockon": "",
|
||||
"clockoffwithoutclockon": ""
|
||||
"clockoffwithoutclockon": "",
|
||||
"hoursenteredmorethanavailable": ""
|
||||
}
|
||||
},
|
||||
"titles": {
|
||||
@@ -2712,6 +2800,7 @@
|
||||
"shop-vendors": "",
|
||||
"temporarydocs": "",
|
||||
"timetickets": "",
|
||||
"ttapprovals": "",
|
||||
"vehicle-details": "",
|
||||
"vehicles": ""
|
||||
},
|
||||
@@ -2757,9 +2846,15 @@
|
||||
"shop_vendors": "Vendeurs | $t(titles.app)",
|
||||
"temporarydocs": "",
|
||||
"timetickets": "",
|
||||
"ttapprovals": "",
|
||||
"vehicledetail": "Détails du véhicule {{vehicle} | $t(titles.app)",
|
||||
"vehicles": "Tous les véhicules | $t(titles.app)"
|
||||
},
|
||||
"tt_approvals": {
|
||||
"actions": {
|
||||
"approveselected": ""
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"actions": {
|
||||
"changepassword": "",
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { gql } from "@apollo/client";
|
||||
import { notification } from "antd";
|
||||
import axios from "axios";
|
||||
import jsreport from "@jsreport/browser-client";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
@@ -9,7 +8,8 @@ import { setEmailOptions } from "../redux/email/email.actions";
|
||||
import { store } from "../redux/store";
|
||||
import client from "../utils/GraphQLClient";
|
||||
import { TemplateList } from "./TemplateConstants";
|
||||
|
||||
import cleanAxios from "./CleanAxios";
|
||||
import axios from "axios";
|
||||
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
||||
|
||||
jsreport.serverUrl = server;
|
||||
@@ -26,10 +26,14 @@ export default async function RenderTemplate(
|
||||
if (window.jsr3) {
|
||||
jsreport.serverUrl = "https://reports3.test.imex.online/";
|
||||
}
|
||||
const jsrAuth = (await axios.post("/utils/jsr")).data;
|
||||
|
||||
jsreport.headers["Authorization"] = jsrAuth;
|
||||
|
||||
//Query assets that match the template name. Must be in format <<templateName>>.query
|
||||
let { contextData, useShopSpecificTemplate } = await fetchContextData(
|
||||
templateObject
|
||||
templateObject,
|
||||
jsrAuth
|
||||
);
|
||||
|
||||
const { ignoreCustomMargins } = Templates[templateObject.name];
|
||||
@@ -137,11 +141,15 @@ export async function RenderTemplates(
|
||||
//Query assets that match the template name. Must be in format <<templateName>>.query
|
||||
let unsortedTemplatesAndData = [];
|
||||
let proms = [];
|
||||
const jsrAuth = (await axios.post("/utils/jsr")).data;
|
||||
jsreport.headers["Authorization"] = jsrAuth;
|
||||
|
||||
templateObjects.forEach((template) => {
|
||||
proms.push(
|
||||
(async () => {
|
||||
let { contextData, useShopSpecificTemplate } = await fetchContextData(
|
||||
template
|
||||
template,
|
||||
jsrAuth
|
||||
);
|
||||
unsortedTemplatesAndData.push({
|
||||
templateObject: template,
|
||||
@@ -298,19 +306,22 @@ export const GenerateDocuments = async (templates) => {
|
||||
await RenderTemplates(templates, bodyshop);
|
||||
};
|
||||
|
||||
const fetchContextData = async (templateObject) => {
|
||||
const fetchContextData = async (templateObject, jsrAuth) => {
|
||||
const bodyshop = store.getState().user.bodyshop;
|
||||
|
||||
jsreport.headers["Authorization"] =
|
||||
jsreport.headers["FirebaseAuthorization"] =
|
||||
"Bearer " + (await auth.currentUser.getIdToken());
|
||||
|
||||
const folders = await axios.get(`${server}/odata/folders`);
|
||||
const folders = await cleanAxios.get(`${server}/odata/folders`, {
|
||||
headers: { Authorization: jsrAuth },
|
||||
});
|
||||
const shopSpecificFolder = folders.data.value.find(
|
||||
(f) => f.name === bodyshop.imexshopid
|
||||
);
|
||||
|
||||
const jsReportQueries = await axios.get(
|
||||
`${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`
|
||||
const jsReportQueries = await cleanAxios.get(
|
||||
`${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`,
|
||||
{ headers: { Authorization: jsrAuth } }
|
||||
);
|
||||
|
||||
let templateQueryToExecute;
|
||||
|
||||
@@ -7,23 +7,24 @@ export const EmailSettings = {
|
||||
|
||||
export const TemplateList = (type, context) => {
|
||||
//const { bodyshop } = store.getState().user;
|
||||
|
||||
return {
|
||||
//If there's no type or the type is job, send it back.
|
||||
...(!type || type === "job"
|
||||
? {
|
||||
casl_authorization: {
|
||||
title: i18n.t("printcenter.jobs.casl_authorization"),
|
||||
description: "CASL Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.casl_authorization"),
|
||||
key: "casl_authorization",
|
||||
disabled: false,
|
||||
group: "authorization",
|
||||
regions: {
|
||||
CA: true,
|
||||
},
|
||||
},
|
||||
|
||||
fippa_authorization: {
|
||||
title: i18n.t("printcenter.jobs.fippa_authorization"),
|
||||
description: "CASL Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.fippa_authorization"),
|
||||
key: "fippa_authorization",
|
||||
disabled: false,
|
||||
@@ -31,7 +32,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
diagnostic_authorization: {
|
||||
title: i18n.t("printcenter.jobs.diagnostic_authorization"),
|
||||
description: "Diagnostic Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.diagnostic_authorization"),
|
||||
key: "diagnostic_authorization",
|
||||
disabled: false,
|
||||
@@ -39,7 +40,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
mechanical_authorization: {
|
||||
title: i18n.t("printcenter.jobs.mechanical_authorization"),
|
||||
description: "Diagnostic Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.mechanical_authorization"),
|
||||
key: "mechanical_authorization",
|
||||
disabled: false,
|
||||
@@ -47,7 +48,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
appointment_reminder: {
|
||||
title: i18n.t("printcenter.jobs.appointment_reminder"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.appointment_reminder"),
|
||||
key: "appointment_reminder",
|
||||
disabled: false,
|
||||
@@ -55,7 +56,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
estimate_followup: {
|
||||
title: i18n.t("printcenter.jobs.estimate_followup"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.estimate_followup"),
|
||||
key: "estimate_followup",
|
||||
disabled: false,
|
||||
@@ -63,7 +64,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
express_repair_checklist: {
|
||||
title: i18n.t("printcenter.jobs.express_repair_checklist"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.express_repair_checklist"),
|
||||
key: "express_repair_checklist",
|
||||
disabled: false,
|
||||
@@ -71,7 +72,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
glass_express_checklist: {
|
||||
title: i18n.t("printcenter.jobs.glass_express_checklist"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.glass_express_checklist"),
|
||||
key: "glass_express_checklist",
|
||||
disabled: false,
|
||||
@@ -79,7 +80,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
stolen_recovery_checklist: {
|
||||
title: i18n.t("printcenter.jobs.stolen_recovery_checklist"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.stolen_recovery_checklist"),
|
||||
key: "stolen_recovery_checklist",
|
||||
disabled: false,
|
||||
@@ -87,7 +88,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
vehicle_check_in: {
|
||||
title: i18n.t("printcenter.jobs.vehicle_check_in"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.vehicle_check_in"),
|
||||
key: "vehicle_check_in",
|
||||
disabled: false,
|
||||
@@ -95,16 +96,15 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
parts_order_history: {
|
||||
title: i18n.t("printcenter.jobs.parts_order_history"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.parts_order_history"),
|
||||
key: "parts_order_history",
|
||||
disabled: false,
|
||||
group: "ro",
|
||||
},
|
||||
|
||||
job_notes: {
|
||||
title: i18n.t("printcenter.jobs.job_notes"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.job_notes"),
|
||||
key: "job_notes",
|
||||
disabled: false,
|
||||
@@ -112,7 +112,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
ro_with_description: {
|
||||
title: i18n.t("printcenter.jobs.ro_with_description"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.ro_with_description"),
|
||||
key: "ro_with_description",
|
||||
disabled: false,
|
||||
@@ -120,7 +120,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
window_tag: {
|
||||
title: i18n.t("printcenter.jobs.window_tag"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.window_tag"),
|
||||
key: "window_tag",
|
||||
disabled: false,
|
||||
@@ -128,7 +128,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
supplement_request: {
|
||||
title: i18n.t("printcenter.jobs.supplement_request"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.supplement_request"),
|
||||
key: "supplement_request",
|
||||
disabled: false,
|
||||
@@ -136,7 +136,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
estimate: {
|
||||
title: i18n.t("printcenter.jobs.estimate"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.estimate"),
|
||||
key: "estimate",
|
||||
disabled: false,
|
||||
@@ -144,7 +144,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
parts_list: {
|
||||
title: i18n.t("printcenter.jobs.parts_list"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.parts_list"),
|
||||
key: "parts_list",
|
||||
disabled: false,
|
||||
@@ -152,7 +152,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
coversheet_portrait: {
|
||||
title: i18n.t("printcenter.jobs.coversheet_portrait"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.coversheet_portrait"),
|
||||
key: "coversheet_portrait",
|
||||
disabled: false,
|
||||
@@ -160,7 +160,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
coversheet_landscape: {
|
||||
title: i18n.t("printcenter.jobs.coversheet_landscape"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.coversheet_landscape"),
|
||||
key: "coversheet_landscape",
|
||||
disabled: false,
|
||||
@@ -168,7 +168,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
key_tag: {
|
||||
title: i18n.t("printcenter.jobs.key_tag"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.key_tag"),
|
||||
key: "key_tag",
|
||||
disabled: false,
|
||||
@@ -176,7 +176,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
paint_grid: {
|
||||
title: i18n.t("printcenter.jobs.paint_grid"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.paint_grid"),
|
||||
key: "paint_grid",
|
||||
disabled: false,
|
||||
@@ -184,7 +184,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
worksheet_by_line_number: {
|
||||
title: i18n.t("printcenter.jobs.worksheet_by_line_number"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.worksheet_by_line_number"),
|
||||
key: "worksheet_by_line_number",
|
||||
disabled: false,
|
||||
@@ -194,7 +194,7 @@ export const TemplateList = (type, context) => {
|
||||
title: i18n.t(
|
||||
"printcenter.jobs.worksheet_sorted_by_operation_type"
|
||||
),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"printcenter.jobs.worksheet_sorted_by_operation_type"
|
||||
),
|
||||
@@ -204,7 +204,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
worksheet_sorted_by_operation: {
|
||||
title: i18n.t("printcenter.jobs.worksheet_sorted_by_operation"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.worksheet_sorted_by_operation"),
|
||||
key: "worksheet_sorted_by_operation",
|
||||
disabled: false,
|
||||
@@ -214,7 +214,7 @@ export const TemplateList = (type, context) => {
|
||||
title: i18n.t(
|
||||
"printcenter.jobs.worksheet_sorted_by_operation_no_hours"
|
||||
),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"printcenter.jobs.worksheet_sorted_by_operation_no_hours"
|
||||
),
|
||||
@@ -226,7 +226,7 @@ export const TemplateList = (type, context) => {
|
||||
title: i18n.t(
|
||||
"printcenter.jobs.worksheet_sorted_by_operation_part_type"
|
||||
),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"printcenter.jobs.worksheet_sorted_by_operation_part_type"
|
||||
),
|
||||
@@ -236,7 +236,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
payments_by_job: {
|
||||
title: i18n.t("printcenter.jobs.payments_by_job"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.payments_by_job"),
|
||||
key: "payments_by_job",
|
||||
disabled: false,
|
||||
@@ -244,7 +244,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
final_invoice: {
|
||||
title: i18n.t("printcenter.jobs.final_invoice"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.final_invoice"),
|
||||
key: "final_invoice",
|
||||
disabled: false,
|
||||
@@ -252,7 +252,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
payment_request: {
|
||||
title: i18n.t("printcenter.jobs.payment_request"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.payment_request"),
|
||||
key: "payment_request",
|
||||
disabled: false,
|
||||
@@ -260,7 +260,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
invoice_total_payable: {
|
||||
title: i18n.t("printcenter.jobs.invoice_total_payable"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.invoice_total_payable"),
|
||||
key: "invoice_total_payable",
|
||||
disabled: false,
|
||||
@@ -268,7 +268,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
invoice_customer_payable: {
|
||||
title: i18n.t("printcenter.jobs.invoice_customer_payable"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.invoice_customer_payable"),
|
||||
key: "invoice_customer_payable",
|
||||
disabled: false,
|
||||
@@ -276,7 +276,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
ro_totals: {
|
||||
title: i18n.t("printcenter.jobs.ro_totals"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.ro_totals"),
|
||||
key: "ro_totals",
|
||||
disabled: false,
|
||||
@@ -284,7 +284,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
job_costing_ro: {
|
||||
title: i18n.t("printcenter.jobs.job_costing_ro"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.job_costing_ro"),
|
||||
key: "job_costing_ro",
|
||||
disabled: false,
|
||||
@@ -292,7 +292,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
purchases_by_ro_detail: {
|
||||
title: i18n.t("printcenter.jobs.purchases_by_ro_detail"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.purchases_by_ro_detail"),
|
||||
key: "purchases_by_ro_detail",
|
||||
disabled: false,
|
||||
@@ -300,7 +300,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
purchases_by_ro_summary: {
|
||||
title: i18n.t("printcenter.jobs.purchases_by_ro_summary"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.purchases_by_ro_summary"),
|
||||
key: "purchases_by_ro_summary",
|
||||
disabled: false,
|
||||
@@ -308,7 +308,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
filing_coversheet_portrait: {
|
||||
title: i18n.t("printcenter.jobs.filing_coversheet_portrait"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.filing_coversheet_portrait"),
|
||||
key: "filing_coversheet_portrait",
|
||||
disabled: false,
|
||||
@@ -316,7 +316,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
filing_coversheet_landscape: {
|
||||
title: i18n.t("printcenter.jobs.filing_coversheet_landscape"),
|
||||
description: "CASL Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.filing_coversheet_landscape"),
|
||||
key: "filing_coversheet_landscape",
|
||||
disabled: false,
|
||||
@@ -324,25 +324,23 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
qc_sheet: {
|
||||
title: i18n.t("printcenter.jobs.qc_sheet"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.qc_sheet"),
|
||||
key: "qc_sheet",
|
||||
disabled: false,
|
||||
group: "post",
|
||||
},
|
||||
|
||||
vehicle_delivery_check: {
|
||||
title: i18n.t("printcenter.jobs.vehicle_delivery_check"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.vehicle_delivery_check"),
|
||||
key: "vehicle_delivery_check",
|
||||
disabled: false,
|
||||
group: "post",
|
||||
},
|
||||
|
||||
guarantee: {
|
||||
title: i18n.t("printcenter.jobs.guarantee"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.guarantee"),
|
||||
key: "guarantee",
|
||||
disabled: false,
|
||||
@@ -350,7 +348,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
csi_invitation: {
|
||||
title: i18n.t("printcenter.jobs.csi_invitation"),
|
||||
description: "CSI invite",
|
||||
description: "",
|
||||
key: "csi_invitation",
|
||||
subject: i18n.t("printcenter.jobs.csi_invitation"),
|
||||
disabled: false,
|
||||
@@ -358,7 +356,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
window_tag_sublet: {
|
||||
title: i18n.t("printcenter.jobs.window_tag_sublet"),
|
||||
description: "Window Tag Sublet",
|
||||
description: "",
|
||||
key: "window_tag_sublet",
|
||||
subject: i18n.t("printcenter.jobs.window_tag_sublet"),
|
||||
disabled: false,
|
||||
@@ -366,7 +364,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
thank_you_ro: {
|
||||
title: i18n.t("printcenter.jobs.thank_you_ro"),
|
||||
description: "Thank You Letter by RO",
|
||||
description: "",
|
||||
key: "thank_you_ro",
|
||||
subject: i18n.t("printcenter.jobs.thank_you_ro"),
|
||||
disabled: false,
|
||||
@@ -374,7 +372,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
parts_label_single: {
|
||||
title: i18n.t("printcenter.jobs.parts_label_single"),
|
||||
description: "Thank You Letter by RO",
|
||||
description: "",
|
||||
key: "parts_label_single",
|
||||
subject: i18n.t("printcenter.jobs.parts_label_single"),
|
||||
disabled: false,
|
||||
@@ -383,7 +381,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
envelope_return_address: {
|
||||
title: i18n.t("printcenter.jobs.envelope_return_address"),
|
||||
description: "All Jobs Notes",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.envelope_return_address"),
|
||||
key: "envelope_return_address",
|
||||
disabled: false,
|
||||
@@ -392,7 +390,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
sgi_certificate_of_repairs: {
|
||||
title: i18n.t("printcenter.jobs.sgi_certificate_of_repairs"),
|
||||
description: "Thank You Letter by RO",
|
||||
description: "",
|
||||
key: "sgi_certificate_of_repairs",
|
||||
subject: i18n.t("printcenter.jobs.sgi_certificate_of_repairs"),
|
||||
disabled: false,
|
||||
@@ -403,7 +401,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
sgi_windshield_auth: {
|
||||
title: i18n.t("printcenter.jobs.sgi_windshield_auth"),
|
||||
description: "Thank You Letter by RO",
|
||||
description: "",
|
||||
key: "sgi_windshield_auth",
|
||||
subject: i18n.t("printcenter.jobs.sgi_windshield_auth"),
|
||||
disabled: false,
|
||||
@@ -414,7 +412,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
mpi_final_acct_sheet: {
|
||||
title: i18n.t("printcenter.jobs.mpi_final_acct_sheet"),
|
||||
description: "Thank You Letter by RO",
|
||||
description: "",
|
||||
key: "mpi_final_acct_sheet",
|
||||
subject: i18n.t("printcenter.jobs.mpi_final_acct_sheet"),
|
||||
disabled: false,
|
||||
@@ -425,7 +423,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
mpi_eglass_auth: {
|
||||
title: i18n.t("printcenter.jobs.mpi_eglass_auth"),
|
||||
description: "Thank You Letter by RO",
|
||||
description: "",
|
||||
key: "mpi_eglass_auth",
|
||||
subject: i18n.t("printcenter.jobs.mpi_eglass_auth"),
|
||||
disabled: false,
|
||||
@@ -436,7 +434,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
mpi_animal_checklist: {
|
||||
title: i18n.t("printcenter.jobs.mpi_animal_checklist"),
|
||||
description: "Thank You Letter by RO",
|
||||
description: "",
|
||||
key: "mpi_animal_checklist",
|
||||
subject: i18n.t("printcenter.jobs.mpi_animal_checklist"),
|
||||
disabled: false,
|
||||
@@ -447,7 +445,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
ab_proof_of_loss: {
|
||||
title: i18n.t("printcenter.jobs.ab_proof_of_loss"),
|
||||
description: "Thank You Letter by RO",
|
||||
description: "",
|
||||
key: "ab_proof_of_loss",
|
||||
subject: i18n.t("printcenter.jobs.ab_proof_of_loss"),
|
||||
disabled: false,
|
||||
@@ -458,7 +456,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
// parts_label_multi: {
|
||||
// title: i18n.t("printcenter.jobs.parts_label_multi"),
|
||||
// description: "Thank You Letter by RO",
|
||||
// description: "",
|
||||
// key: "parts_label_multi",
|
||||
// subject: i18n.t("printcenter.jobs.parts_label_multi"),
|
||||
// disabled: false,
|
||||
@@ -466,7 +464,7 @@ export const TemplateList = (type, context) => {
|
||||
// },
|
||||
iou_form: {
|
||||
title: i18n.t("printcenter.jobs.iou_form"),
|
||||
description: "CASL Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.iou_form"),
|
||||
key: "iou_form",
|
||||
disabled: false,
|
||||
@@ -474,7 +472,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
lag_time_ro: {
|
||||
title: i18n.t("printcenter.jobs.lag_time_ro"),
|
||||
description: "CASL Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.lag_time_ro"),
|
||||
key: "lag_time_ro",
|
||||
disabled: false,
|
||||
@@ -482,7 +480,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
rental_reservation: {
|
||||
title: i18n.t("printcenter.jobs.rental_reservation"),
|
||||
description: "CASL Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.rental_reservation"),
|
||||
key: "rental_reservation",
|
||||
disabled: false,
|
||||
@@ -490,51 +488,59 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
timetickets_ro: {
|
||||
title: i18n.t("printcenter.jobs.timetickets_ro"),
|
||||
description: "CASL Authorization",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.timetickets_ro"),
|
||||
key: "timetickets_ro",
|
||||
disabled: false,
|
||||
group: "financial",
|
||||
},
|
||||
dms_posting_sheet: {
|
||||
title: i18n.t("printcenter.jobs.dms_posting_sheet"),
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.dms_posting_sheet"),
|
||||
key: "dms_posting_sheet",
|
||||
disabled: false,
|
||||
group: "financial",
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(!type || type === "job_special"
|
||||
? {
|
||||
special_thirdpartypayer: {
|
||||
title: i18n.t("printcenter.jobs.thirdpartypayer"),
|
||||
description: "CSI invite",
|
||||
description: "",
|
||||
key: "special_thirdpartypayer",
|
||||
disabled: false,
|
||||
},
|
||||
folder_label_multiple: {
|
||||
title: i18n.t("printcenter.jobs.folder_label_multiple"),
|
||||
description: "Folder Label Multiple",
|
||||
description: "",
|
||||
key: "folder_label_multiple",
|
||||
disabled: false,
|
||||
},
|
||||
parts_label_multiple: {
|
||||
title: i18n.t("printcenter.jobs.parts_label_multiple"),
|
||||
description: "Parts Label Multiple",
|
||||
description: "",
|
||||
key: "parts_label_multiple",
|
||||
disabled: false,
|
||||
},
|
||||
parts_invoice_label_single: {
|
||||
title: i18n.t("printcenter.jobs.parts_invoice_label_single"),
|
||||
description: "Parts Label Multiple",
|
||||
description: "",
|
||||
key: "parts_invoice_label_single",
|
||||
disabled: false,
|
||||
ignoreCustomMargins: true,
|
||||
},
|
||||
csi_invitation_action: {
|
||||
title: i18n.t("printcenter.jobs.csi_invitation_action"),
|
||||
description: "CSI invite",
|
||||
description: "",
|
||||
key: "csi_invitation_action",
|
||||
subject: i18n.t("printcenter.jobs.csi_invitation_action"),
|
||||
disabled: false,
|
||||
},
|
||||
individual_job_note: {
|
||||
title: i18n.t("printcenter.jobs.individual_job_note"),
|
||||
description: "CSI invite",
|
||||
description: "",
|
||||
key: "individual_job_note",
|
||||
subject: i18n.t("printcenter.jobs.individual_job_note", {
|
||||
ro_number: (context && context.ro_number) || "",
|
||||
@@ -547,7 +553,7 @@ export const TemplateList = (type, context) => {
|
||||
? {
|
||||
appointment_confirmation: {
|
||||
title: i18n.t("printcenter.appointments.appointment_confirmation"),
|
||||
description: "Appointment Confirmation",
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"printcenter.appointments.appointment_confirmation"
|
||||
),
|
||||
@@ -560,7 +566,7 @@ export const TemplateList = (type, context) => {
|
||||
? {
|
||||
parts_order: {
|
||||
title: i18n.t("printcenter.jobs.parts_order"),
|
||||
description: "Parts Order",
|
||||
description: "",
|
||||
key: "parts_order",
|
||||
subject: i18n.t("printcenter.subjects.jobs.parts_order", {
|
||||
ro_number: context && context.job && context.job.ro_number,
|
||||
@@ -574,7 +580,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
sublet_order: {
|
||||
title: i18n.t("printcenter.jobs.sublet_order"),
|
||||
description: "Parts Order",
|
||||
description: "",
|
||||
key: "sublet_order",
|
||||
subject: i18n.t("printcenter.subjects.jobs.sublet_order", {
|
||||
ro_number: context && context.job && context.job.ro_number,
|
||||
@@ -589,7 +595,7 @@ export const TemplateList = (type, context) => {
|
||||
parts_return_slip: {
|
||||
title: i18n.t("printcenter.jobs.parts_return_slip"),
|
||||
subject: i18n.t("printcenter.jobs.parts_return_slip"),
|
||||
description: "Parts Return",
|
||||
description: "",
|
||||
key: "parts_return_slip",
|
||||
disabled: false,
|
||||
},
|
||||
@@ -599,7 +605,7 @@ export const TemplateList = (type, context) => {
|
||||
? {
|
||||
payment_receipt: {
|
||||
title: i18n.t("printcenter.jobs.payment_receipt"),
|
||||
description: "Payment Receipt",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.jobs.payment_receipt"),
|
||||
key: "payment_receipt",
|
||||
disabled: false,
|
||||
@@ -622,7 +628,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
hours_sold_detail_closed_ins_co: {
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.hours_sold_detail_closed_ins_co"
|
||||
@@ -640,7 +645,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
hours_sold_summary_closed: {
|
||||
title: i18n.t("reportcenter.templates.hours_sold_summary_closed"),
|
||||
description: "",
|
||||
@@ -654,7 +658,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
hours_sold_summary_closed_ins_co: {
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.hours_sold_summary_closed_ins_co"
|
||||
@@ -672,7 +675,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
hours_sold_detail_open: {
|
||||
title: i18n.t("reportcenter.templates.hours_sold_detail_open"),
|
||||
description: "",
|
||||
@@ -686,7 +688,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
hours_sold_detail_open_ins_co: {
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.hours_sold_detail_open_ins_co"
|
||||
@@ -704,7 +705,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
hours_sold_summary_open: {
|
||||
title: i18n.t("reportcenter.templates.hours_sold_summary_open"),
|
||||
description: "",
|
||||
@@ -718,7 +718,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
hours_sold_summary_open_ins_co: {
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.hours_sold_summary_open_ins_co"
|
||||
@@ -736,7 +735,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
hours_sold_detail_closed_csr: {
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.hours_sold_detail_closed_csr"
|
||||
@@ -1090,7 +1088,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "customers",
|
||||
},
|
||||
|
||||
schedule: {
|
||||
title: i18n.t("reportcenter.templates.schedule"),
|
||||
subject: i18n.t("reportcenter.templates.schedule"),
|
||||
@@ -1102,7 +1099,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "customers",
|
||||
},
|
||||
|
||||
timetickets: {
|
||||
title: i18n.t("reportcenter.templates.timetickets"),
|
||||
subject: i18n.t("reportcenter.templates.timetickets"),
|
||||
@@ -1126,7 +1122,6 @@ export const TemplateList = (type, context) => {
|
||||
title: i18n.t("reportcenter.templates.attendance_detail"),
|
||||
subject: i18n.t("reportcenter.templates.attendance_detail"),
|
||||
key: "attendance_detail",
|
||||
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.timetickets"),
|
||||
@@ -1138,7 +1133,6 @@ export const TemplateList = (type, context) => {
|
||||
title: i18n.t("reportcenter.templates.attendance_summary"),
|
||||
subject: i18n.t("reportcenter.templates.attendance_summary"),
|
||||
key: "attendance_summary",
|
||||
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.timetickets"),
|
||||
@@ -1158,7 +1152,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "payroll",
|
||||
},
|
||||
|
||||
timetickets_summary: {
|
||||
title: i18n.t("reportcenter.templates.timetickets_summary"),
|
||||
subject: i18n.t("reportcenter.templates.timetickets_summary"),
|
||||
@@ -1171,7 +1164,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "payroll",
|
||||
},
|
||||
|
||||
estimator_detail: {
|
||||
title: i18n.t("reportcenter.templates.estimator_detail"),
|
||||
description: "",
|
||||
@@ -1224,7 +1216,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "purchases",
|
||||
},
|
||||
|
||||
void_ros: {
|
||||
title: i18n.t("reportcenter.templates.void_ros"),
|
||||
description: "",
|
||||
@@ -1329,7 +1320,6 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
|
||||
gsr_by_estimator: {
|
||||
title: i18n.t("reportcenter.templates.gsr_by_estimator"),
|
||||
description: "",
|
||||
@@ -1814,7 +1804,9 @@ export const TemplateList = (type, context) => {
|
||||
group: "jobs",
|
||||
},
|
||||
purchase_return_ratio_grouped_by_vendor_detail: {
|
||||
title: i18n.t("reportcenter.templates.purchase_return_ratio_grouped_by_vendor_detail"),
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.purchase_return_ratio_grouped_by_vendor_detail"
|
||||
),
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.purchase_return_ratio_grouped_by_vendor_detail"
|
||||
),
|
||||
@@ -1828,7 +1820,9 @@ export const TemplateList = (type, context) => {
|
||||
group: "purchases",
|
||||
},
|
||||
purchase_return_ratio_grouped_by_vendor_summary: {
|
||||
title: i18n.t("reportcenter.templates.purchase_return_ratio_grouped_by_vendor_summary"),
|
||||
title: i18n.t(
|
||||
"reportcenter.templates.purchase_return_ratio_grouped_by_vendor_summary"
|
||||
),
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.purchase_return_ratio_grouped_by_vendor_summary"
|
||||
),
|
||||
@@ -1843,9 +1837,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
production_over_time: {
|
||||
title: i18n.t("reportcenter.templates.production_over_time"),
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.production_over_time"
|
||||
),
|
||||
subject: i18n.t("reportcenter.templates.production_over_time"),
|
||||
key: "production_over_time",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
@@ -1857,9 +1849,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
customer_list: {
|
||||
title: i18n.t("reportcenter.templates.customer_list"),
|
||||
subject: i18n.t(
|
||||
"reportcenter.templates.customer_list"
|
||||
),
|
||||
subject: i18n.t("reportcenter.templates.customer_list"),
|
||||
key: "customer_list",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
@@ -1869,6 +1859,32 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "customers",
|
||||
},
|
||||
exported_gsr_by_ro: {
|
||||
title: i18n.t("reportcenter.templates.exported_gsr_by_ro"),
|
||||
subject: i18n.t("reportcenter.templates.exported_gsr_by_ro"),
|
||||
key: "exported_gsr_by_ro",
|
||||
//idtype: "vendor",
|
||||
reporttype: "excel",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_exported"),
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
exported_gsr_by_ro_labor: {
|
||||
title: i18n.t("reportcenter.templates.exported_gsr_by_ro_labor"),
|
||||
subject: i18n.t("reportcenter.templates.exported_gsr_by_ro_labor"),
|
||||
key: "exported_gsr_by_ro_labor",
|
||||
//idtype: "vendor",
|
||||
reporttype: "excel",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_exported"),
|
||||
},
|
||||
group: "sales",
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(!type || type === "courtesycarcontract"
|
||||
@@ -1877,7 +1893,7 @@ export const TemplateList = (type, context) => {
|
||||
title: i18n.t(
|
||||
"printcenter.courtesycarcontract.courtesy_car_contract"
|
||||
),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"printcenter.courtesycarcontract.courtesy_car_contract"
|
||||
),
|
||||
@@ -1886,7 +1902,7 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
courtesy_car_terms: {
|
||||
title: i18n.t("printcenter.courtesycarcontract.courtesy_car_terms"),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"printcenter.courtesycarcontract.courtesy_car_terms"
|
||||
),
|
||||
@@ -1897,7 +1913,7 @@ export const TemplateList = (type, context) => {
|
||||
title: i18n.t(
|
||||
"printcenter.courtesycarcontract.courtesy_car_impound"
|
||||
),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"printcenter.courtesycarcontract.courtesy_car_impound"
|
||||
),
|
||||
@@ -1912,7 +1928,7 @@ export const TemplateList = (type, context) => {
|
||||
title: i18n.t(
|
||||
"printcenter.courtesycarcontract.courtesy_car_inventory"
|
||||
),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t(
|
||||
"printcenter.courtesycarcontract.courtesy_car_inventory"
|
||||
),
|
||||
@@ -1925,7 +1941,7 @@ export const TemplateList = (type, context) => {
|
||||
? {
|
||||
inhouse_invoice: {
|
||||
title: i18n.t("printcenter.bills.inhouse_invoice"),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.bills.inhouse_invoice"),
|
||||
key: "inhouse_invoice",
|
||||
disabled: false,
|
||||
@@ -1936,7 +1952,7 @@ export const TemplateList = (type, context) => {
|
||||
? {
|
||||
// timetickets: {
|
||||
// title: i18n.t("printcenter.timetickets.timetickets"),
|
||||
// description: "Est Detail",
|
||||
// description: "",
|
||||
// subject: `${i18n.t("printcenter.timetickets.timetickets")} - ${
|
||||
// context && context.job && context.job.ro_number
|
||||
// }`,
|
||||
@@ -1949,21 +1965,20 @@ export const TemplateList = (type, context) => {
|
||||
? {
|
||||
purchases_by_vendor_detailed: {
|
||||
title: i18n.t("printcenter.vendors.purchases_by_vendor_detailed"),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.vendors.purchases_by_vendor_detailed"),
|
||||
key: "purchases_by_vendor_detailed",
|
||||
disabled: false,
|
||||
},
|
||||
purchases_by_vendor_summary: {
|
||||
title: i18n.t("printcenter.vendors.purchases_by_vendor_summary"),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.vendors.purchases_by_vendor_summary"),
|
||||
key: "purchases_by_vendor_summary",
|
||||
disabled: false,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
|
||||
...(!type || type === "production"
|
||||
? {
|
||||
production_by_last_name: {
|
||||
@@ -2030,21 +2045,21 @@ export const TemplateList = (type, context) => {
|
||||
? {
|
||||
ca_bc_etf_table: {
|
||||
title: i18n.t("printcenter.payments.ca_bc_etf_table"),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.payments.ca_bc_etf_table"),
|
||||
key: "ca_bc_etf_table",
|
||||
disabled: false,
|
||||
},
|
||||
exported_payroll: {
|
||||
title: i18n.t("printcenter.payments.exported_payroll"),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.payments.exported_payroll"),
|
||||
key: "exported_payroll",
|
||||
disabled: false,
|
||||
},
|
||||
attendance_detail_csv: {
|
||||
title: i18n.t("printcenter.special.attendance_detail_csv"),
|
||||
description: "Est Detail",
|
||||
description: "",
|
||||
subject: i18n.t("printcenter.special.attendance_detail_csv"),
|
||||
key: "attendance_detail_csv",
|
||||
disabled: false,
|
||||
|
||||
@@ -3924,14 +3924,6 @@ anymatch@^3.0.3, anymatch@~3.1.2:
|
||||
normalize-path "^3.0.0"
|
||||
picomatch "^2.0.4"
|
||||
|
||||
aphrodite@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/aphrodite/-/aphrodite-0.5.0.tgz#a4b9a8902662395d2702e70ac7a2b4ca66f25703"
|
||||
integrity sha512-bPcR/68OdLg+16XDYAaKnlGJufxrbOw86ucElS7qHm7Y6ZNvMT/D/VDEEfodjFgfyRyoTeKmSaikULG92kSYvQ==
|
||||
dependencies:
|
||||
asap "^2.0.3"
|
||||
inline-style-prefixer "^2.0.0"
|
||||
|
||||
apollo-link-logger@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/apollo-link-logger/-/apollo-link-logger-2.0.1.tgz#63d86b4fe550c147c5a52108710075675694905c"
|
||||
@@ -4073,7 +4065,7 @@ array.prototype.tosorted@^1.1.1:
|
||||
es-shim-unscopables "^1.0.0"
|
||||
get-intrinsic "^1.1.3"
|
||||
|
||||
asap@^2.0.3, asap@~2.0.6:
|
||||
asap@~2.0.6:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
|
||||
integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
|
||||
@@ -4484,11 +4476,6 @@ boolbase@^1.0.0, boolbase@~1.0.0:
|
||||
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
|
||||
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
|
||||
|
||||
bowser@^1.0.0:
|
||||
version "1.9.4"
|
||||
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a"
|
||||
integrity sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==
|
||||
|
||||
brace-expansion@^1.1.7:
|
||||
version "1.1.11"
|
||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
|
||||
@@ -6504,7 +6491,7 @@ executable@^4.1.1:
|
||||
dependencies:
|
||||
pify "^2.2.0"
|
||||
|
||||
exenv@^1.2.2:
|
||||
exenv@^1.2.0:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
|
||||
integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==
|
||||
@@ -7404,11 +7391,6 @@ human-signals@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
|
||||
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
|
||||
|
||||
hyphenate-style-name@^1.0.1:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
|
||||
integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
|
||||
|
||||
i18next-browser-languagedetector@^7.0.1:
|
||||
version "7.0.1"
|
||||
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz#ead34592edc96c6c3a618a51cb57ad027c5b5d87"
|
||||
@@ -7543,14 +7525,6 @@ ini@^1.3.5:
|
||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
|
||||
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
|
||||
|
||||
inline-style-prefixer@^2.0.0:
|
||||
version "2.0.5"
|
||||
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
|
||||
integrity sha512-rlgoApaAAv66JeDFqGYaXwglnlxjyIr7RMaFZqJw4opT0WKnZVXhXMC9SAfuMpN7NELPaImUhJmOO3hAamSlfw==
|
||||
dependencies:
|
||||
bowser "^1.0.0"
|
||||
hyphenate-style-name "^1.0.1"
|
||||
|
||||
internal-slot@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
|
||||
@@ -11157,13 +11131,10 @@ react-error-overlay@6.0.9, react-error-overlay@^6.0.11:
|
||||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
|
||||
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
|
||||
|
||||
react-grid-gallery@^0.5.5:
|
||||
version "0.5.5"
|
||||
resolved "https://registry.yarnpkg.com/react-grid-gallery/-/react-grid-gallery-0.5.5.tgz#1b3f3c23a190834e587ab613c96d53ec3af4f0a2"
|
||||
integrity sha512-DkKg2/Am+VZPDG39fazelTcsZSQrfM/YllnIcWToyUEfOZcrzHxUoqCziCkuTPmCuMbHnrjidBFuDbAFgvSnvQ==
|
||||
dependencies:
|
||||
prop-types "^15.5.8"
|
||||
react-images "^0.5.16"
|
||||
react-grid-gallery@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/react-grid-gallery/-/react-grid-gallery-1.0.0.tgz#31604b9488dfa75a899aa39bc8884138f0409a12"
|
||||
integrity sha512-S1gr6WXBlPFVrE0x2BHuu7jhyaB61mabcMQyx+8KCgAyKzGza0WF67AfAnS9Q00aurFEq4IP8eqb2Bk5F4RAmQ==
|
||||
|
||||
react-grid-layout@^1.3.4:
|
||||
version "1.3.4"
|
||||
@@ -11189,15 +11160,13 @@ react-icons@^4.7.1:
|
||||
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.7.1.tgz#0f4b25a5694e6972677cb189d2a72eabea7a8345"
|
||||
integrity sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==
|
||||
|
||||
react-images@^0.5.16:
|
||||
version "0.5.19"
|
||||
resolved "https://registry.yarnpkg.com/react-images/-/react-images-0.5.19.tgz#9339570029e065f9f28a19f03fdb5d9d5aa109d3"
|
||||
integrity sha512-B3d4W1uFJj+m17K8S65iAyEJShKGBjPk7n7N1YsPiAydEm8mIq9a6CoeQFMY1d7N2QMs6FBCjT9vELyc5jP5JA==
|
||||
react-image-lightbox@^5.1.4:
|
||||
version "5.1.4"
|
||||
resolved "https://registry.yarnpkg.com/react-image-lightbox/-/react-image-lightbox-5.1.4.tgz#5b847dcb79e9efdf9d7cd5621a92e0f156d2cf30"
|
||||
integrity sha512-kTiAODz091bgT7SlWNHab0LSMZAPJtlNWDGKv7pLlLY1krmf7FuG1zxE0wyPpeA8gPdwfr3cu6sPwZRqWsc3Eg==
|
||||
dependencies:
|
||||
aphrodite "^0.5.0"
|
||||
prop-types "^15.6.0"
|
||||
react-scrolllock "^2.0.1"
|
||||
react-transition-group "2"
|
||||
prop-types "^15.7.2"
|
||||
react-modal "^3.11.1"
|
||||
|
||||
react-is@^16.10.2, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
@@ -11214,11 +11183,21 @@ react-is@^18.0.0:
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-lifecycles-compat@^3.0.4:
|
||||
react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
|
||||
|
||||
react-modal@^3.11.1:
|
||||
version "3.16.1"
|
||||
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.1.tgz#34018528fc206561b1a5467fc3beeaddafb39b2b"
|
||||
integrity sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==
|
||||
dependencies:
|
||||
exenv "^1.2.0"
|
||||
prop-types "^15.7.2"
|
||||
react-lifecycles-compat "^3.0.0"
|
||||
warning "^4.0.3"
|
||||
|
||||
react-number-format@^5.1.3:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-5.1.3.tgz#5534f5141cea29e0fe889f76c73dfad11ddf2e17"
|
||||
@@ -11240,11 +11219,6 @@ react-overlays@^5.2.1:
|
||||
uncontrollable "^7.2.1"
|
||||
warning "^4.0.3"
|
||||
|
||||
react-prop-toggle@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/react-prop-toggle/-/react-prop-toggle-1.0.2.tgz#8b0b7e74653606b1427cfcf6c4eaa9198330568e"
|
||||
integrity sha512-JmerjAXs7qJ959+d0Ygt7Cb2+4fG+n3I2VXO6JO0AcAY1vkRN/JpZKAN67CMXY889xEJcfylmMPhzvf6nWO68Q==
|
||||
|
||||
react-redux@^7.2.0:
|
||||
version "7.2.8"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.8.tgz#a894068315e65de5b1b68899f9c6ee0923dd28de"
|
||||
@@ -11373,14 +11347,6 @@ react-scripts@^5.0.1:
|
||||
optionalDependencies:
|
||||
fsevents "^2.3.2"
|
||||
|
||||
react-scrolllock@^2.0.1:
|
||||
version "2.0.7"
|
||||
resolved "https://registry.yarnpkg.com/react-scrolllock/-/react-scrolllock-2.0.7.tgz#3b879e1fe308fc900ab76e226e9be594c41226fd"
|
||||
integrity sha512-Gzpu8+ulxdYcybAgJOFTXc70xs7SBZDQbZNpKzchZUgLCJKjz6lrgESx6LHHZgfELx1xYL4yHu3kYQGQPFas/g==
|
||||
dependencies:
|
||||
exenv "^1.2.2"
|
||||
react-prop-toggle "^1.0.2"
|
||||
|
||||
react-smooth@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-2.0.1.tgz#74c7309916d6ccca182c4b30c8992f179e6c5a05"
|
||||
@@ -11405,7 +11371,7 @@ react-sublime-video@^0.2.5:
|
||||
prop-types "^15.5.10"
|
||||
rc-tween-one "^1.2.5"
|
||||
|
||||
react-transition-group@2, react-transition-group@2.9.0:
|
||||
react-transition-group@2.9.0:
|
||||
version "2.9.0"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==
|
||||
|
||||
@@ -673,6 +673,30 @@
|
||||
_eq: true
|
||||
- exported:
|
||||
_eq: false
|
||||
event_triggers:
|
||||
- name: os_bills
|
||||
definition:
|
||||
delete:
|
||||
columns: '*'
|
||||
enable_manual: false
|
||||
insert:
|
||||
columns: '*'
|
||||
update:
|
||||
columns: '*'
|
||||
retry_conf:
|
||||
interval_sec: 10
|
||||
num_retries: 3
|
||||
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}}/opensearch'
|
||||
version: 2
|
||||
- table:
|
||||
name: bodyshops
|
||||
schema: public
|
||||
@@ -761,6 +785,13 @@
|
||||
table:
|
||||
name: email_audit_trail
|
||||
schema: public
|
||||
- name: employee_teams
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bodyshopid
|
||||
table:
|
||||
name: employee_teams
|
||||
schema: public
|
||||
- name: employees
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
@@ -824,6 +855,13 @@
|
||||
table:
|
||||
name: transitions
|
||||
schema: public
|
||||
- name: tt_approval_queues
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: bodyshopid
|
||||
table:
|
||||
name: tt_approval_queue
|
||||
schema: public
|
||||
- name: vehicles
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
@@ -903,6 +941,7 @@
|
||||
- md_referral_sources
|
||||
- md_responsibility_centers
|
||||
- md_ro_statuses
|
||||
- md_tasks_presets
|
||||
- md_to_emails
|
||||
- messagingservicesid
|
||||
- pbs_configuration
|
||||
@@ -928,8 +967,10 @@
|
||||
- textid
|
||||
- timezone
|
||||
- tt_allow_post_to_invoiced
|
||||
- tt_enforce_hours_for_tech_console
|
||||
- updated_at
|
||||
- use_fippa
|
||||
- use_paint_scale_data
|
||||
- uselocalmediaserver
|
||||
- website
|
||||
- workingdays
|
||||
@@ -998,6 +1039,7 @@
|
||||
- md_referral_sources
|
||||
- md_responsibility_centers
|
||||
- md_ro_statuses
|
||||
- md_tasks_presets
|
||||
- md_to_emails
|
||||
- pbs_configuration
|
||||
- phone
|
||||
@@ -1016,8 +1058,10 @@
|
||||
- target_touchtime
|
||||
- timezone
|
||||
- tt_allow_post_to_invoiced
|
||||
- tt_enforce_hours_for_tech_console
|
||||
- updated_at
|
||||
- use_fippa
|
||||
- use_paint_scale_data
|
||||
- uselocalmediaserver
|
||||
- website
|
||||
- workingdays
|
||||
@@ -1945,6 +1989,165 @@
|
||||
- active:
|
||||
_eq: true
|
||||
check: null
|
||||
- table:
|
||||
name: employee_team_members
|
||||
schema: public
|
||||
object_relationships:
|
||||
- name: employee
|
||||
using:
|
||||
foreign_key_constraint_on: employeeid
|
||||
- name: employee_team
|
||||
using:
|
||||
foreign_key_constraint_on: teamid
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
check:
|
||||
employee_team:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
columns:
|
||||
- labor_rates
|
||||
- percentage
|
||||
- created_at
|
||||
- updated_at
|
||||
- employeeid
|
||||
- id
|
||||
- teamid
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- labor_rates
|
||||
- percentage
|
||||
- created_at
|
||||
- updated_at
|
||||
- employeeid
|
||||
- id
|
||||
- teamid
|
||||
filter:
|
||||
employee_team:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- labor_rates
|
||||
- percentage
|
||||
- created_at
|
||||
- updated_at
|
||||
- employeeid
|
||||
- id
|
||||
- teamid
|
||||
filter:
|
||||
employee_team:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
check: null
|
||||
delete_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
backend_only: false
|
||||
filter:
|
||||
employee_team:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
- table:
|
||||
name: employee_teams
|
||||
schema: public
|
||||
object_relationships:
|
||||
- name: bodyshop
|
||||
using:
|
||||
foreign_key_constraint_on: bodyshopid
|
||||
array_relationships:
|
||||
- name: employee_team_members
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: teamid
|
||||
table:
|
||||
name: employee_team_members
|
||||
schema: public
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
check:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
columns:
|
||||
- active
|
||||
- name
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- active
|
||||
- name
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- active
|
||||
- bodyshopid
|
||||
- name
|
||||
- updated_at
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
check: null
|
||||
- table:
|
||||
name: employee_vacation
|
||||
schema: public
|
||||
@@ -2045,6 +2248,13 @@
|
||||
table:
|
||||
name: allocations
|
||||
schema: public
|
||||
- name: employee_team_members
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: employeeid
|
||||
table:
|
||||
name: employee_team_members
|
||||
schema: public
|
||||
- name: employee_vacations
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
@@ -2087,6 +2297,13 @@
|
||||
table:
|
||||
name: timetickets
|
||||
schema: public
|
||||
- name: tt_approval_queues
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: employeeid
|
||||
table:
|
||||
name: tt_approval_queue
|
||||
schema: public
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
@@ -2218,30 +2435,32 @@
|
||||
- active:
|
||||
_eq: true
|
||||
columns:
|
||||
- id
|
||||
- created_at
|
||||
- updated_at
|
||||
- jobid
|
||||
- billid
|
||||
- bodyshopid
|
||||
- created_at
|
||||
- id
|
||||
- jobid
|
||||
- message
|
||||
- metadata
|
||||
- paymentid
|
||||
- successful
|
||||
- message
|
||||
- bodyshopid
|
||||
- updated_at
|
||||
- useremail
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- successful
|
||||
- message
|
||||
- useremail
|
||||
- created_at
|
||||
- updated_at
|
||||
- billid
|
||||
- bodyshopid
|
||||
- created_at
|
||||
- id
|
||||
- jobid
|
||||
- message
|
||||
- metadata
|
||||
- paymentid
|
||||
- successful
|
||||
- updated_at
|
||||
- useremail
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
@@ -2493,6 +2712,7 @@
|
||||
_eq: true
|
||||
columns:
|
||||
- act_price
|
||||
- act_price_before_ppc
|
||||
- ah_detail_line
|
||||
- alt_co_id
|
||||
- alt_overrd
|
||||
@@ -2559,6 +2779,7 @@
|
||||
permission:
|
||||
columns:
|
||||
- act_price
|
||||
- act_price_before_ppc
|
||||
- ah_detail_line
|
||||
- alt_co_id
|
||||
- alt_overrd
|
||||
@@ -2637,6 +2858,7 @@
|
||||
permission:
|
||||
columns:
|
||||
- act_price
|
||||
- act_price_before_ppc
|
||||
- ah_detail_line
|
||||
- alt_co_id
|
||||
- alt_overrd
|
||||
@@ -2965,6 +3187,13 @@
|
||||
table:
|
||||
name: transitions
|
||||
schema: public
|
||||
- name: tt_approval_queues
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: jobid
|
||||
table:
|
||||
name: tt_approval_queue
|
||||
schema: public
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
@@ -3853,6 +4082,29 @@
|
||||
template_engine: Kriti
|
||||
url: '{{$base_url}}/record-handler/arms'
|
||||
version: 2
|
||||
- name: os_jobs
|
||||
definition:
|
||||
delete:
|
||||
columns: '*'
|
||||
enable_manual: false
|
||||
insert:
|
||||
columns: '*'
|
||||
update:
|
||||
columns: '*'
|
||||
retry_conf:
|
||||
interval_sec: 10
|
||||
num_retries: 3
|
||||
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}}/opensearch'
|
||||
version: 2
|
||||
- table:
|
||||
name: masterdata
|
||||
schema: public
|
||||
@@ -4081,6 +4333,7 @@
|
||||
- jobid
|
||||
- private
|
||||
- text
|
||||
- type
|
||||
- updated_at
|
||||
select_permissions:
|
||||
- role: user
|
||||
@@ -4094,6 +4347,7 @@
|
||||
- jobid
|
||||
- private
|
||||
- text
|
||||
- type
|
||||
- updated_at
|
||||
filter:
|
||||
job:
|
||||
@@ -4117,6 +4371,7 @@
|
||||
- jobid
|
||||
- private
|
||||
- text
|
||||
- type
|
||||
- updated_at
|
||||
filter:
|
||||
job:
|
||||
@@ -4277,6 +4532,30 @@
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
event_triggers:
|
||||
- name: os_owners
|
||||
definition:
|
||||
delete:
|
||||
columns: '*'
|
||||
enable_manual: false
|
||||
insert:
|
||||
columns: '*'
|
||||
update:
|
||||
columns: '*'
|
||||
retry_conf:
|
||||
interval_sec: 10
|
||||
num_retries: 3
|
||||
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}}/opensearch'
|
||||
version: 2
|
||||
- table:
|
||||
name: parts_order_lines
|
||||
schema: public
|
||||
@@ -4700,6 +4979,30 @@
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
event_triggers:
|
||||
- name: os_payments
|
||||
definition:
|
||||
delete:
|
||||
columns: '*'
|
||||
enable_manual: false
|
||||
insert:
|
||||
columns: '*'
|
||||
update:
|
||||
columns: '*'
|
||||
retry_conf:
|
||||
interval_sec: 10
|
||||
num_retries: 3
|
||||
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}}/opensearch'
|
||||
version: 2
|
||||
- table:
|
||||
name: phonebook
|
||||
schema: public
|
||||
@@ -5030,6 +5333,12 @@
|
||||
- name: job
|
||||
using:
|
||||
foreign_key_constraint_on: jobid
|
||||
- name: tt_approval_queue
|
||||
using:
|
||||
foreign_key_constraint_on: ttapprovalqueueid
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: commited_by
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
@@ -5048,6 +5357,8 @@
|
||||
- ciecacode
|
||||
- clockoff
|
||||
- clockon
|
||||
- commited_by
|
||||
- committed_at
|
||||
- cost_center
|
||||
- created_at
|
||||
- date
|
||||
@@ -5058,6 +5369,7 @@
|
||||
- memo
|
||||
- productivehrs
|
||||
- rate
|
||||
- ttapprovalqueueid
|
||||
- updated_at
|
||||
select_permissions:
|
||||
- role: user
|
||||
@@ -5068,6 +5380,8 @@
|
||||
- ciecacode
|
||||
- clockoff
|
||||
- clockon
|
||||
- commited_by
|
||||
- committed_at
|
||||
- cost_center
|
||||
- created_at
|
||||
- date
|
||||
@@ -5078,6 +5392,7 @@
|
||||
- memo
|
||||
- productivehrs
|
||||
- rate
|
||||
- ttapprovalqueueid
|
||||
- updated_at
|
||||
filter:
|
||||
bodyshop:
|
||||
@@ -5097,6 +5412,8 @@
|
||||
- ciecacode
|
||||
- clockoff
|
||||
- clockon
|
||||
- commited_by
|
||||
- committed_at
|
||||
- cost_center
|
||||
- created_at
|
||||
- date
|
||||
@@ -5107,6 +5424,7 @@
|
||||
- memo
|
||||
- productivehrs
|
||||
- rate
|
||||
- ttapprovalqueueid
|
||||
- updated_at
|
||||
filter:
|
||||
bodyshop:
|
||||
@@ -5217,6 +5535,119 @@
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
check: {}
|
||||
- table:
|
||||
name: tt_approval_queue
|
||||
schema: public
|
||||
object_relationships:
|
||||
- name: bodyshop
|
||||
using:
|
||||
foreign_key_constraint_on: bodyshopid
|
||||
- name: employee
|
||||
using:
|
||||
foreign_key_constraint_on: employeeid
|
||||
- name: job
|
||||
using:
|
||||
foreign_key_constraint_on: jobid
|
||||
- name: user
|
||||
using:
|
||||
foreign_key_constraint_on: approved_by
|
||||
array_relationships:
|
||||
- name: timetickets
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: ttapprovalqueueid
|
||||
table:
|
||||
name: timetickets
|
||||
schema: public
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
check:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- active:
|
||||
_eq: true
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
columns:
|
||||
- actualhrs
|
||||
- approved_at
|
||||
- approved_by
|
||||
- bodyshopid
|
||||
- ciecacode
|
||||
- cost_center
|
||||
- created_at
|
||||
- date
|
||||
- employeeid
|
||||
- flat_rate
|
||||
- id
|
||||
- jobid
|
||||
- memo
|
||||
- productivehrs
|
||||
- rate
|
||||
- updated_at
|
||||
select_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- actualhrs
|
||||
- approved_at
|
||||
- approved_by
|
||||
- bodyshopid
|
||||
- ciecacode
|
||||
- cost_center
|
||||
- created_at
|
||||
- date
|
||||
- employeeid
|
||||
- flat_rate
|
||||
- id
|
||||
- jobid
|
||||
- memo
|
||||
- productivehrs
|
||||
- rate
|
||||
- updated_at
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- active:
|
||||
_eq: true
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
allow_aggregations: true
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
columns:
|
||||
- actualhrs
|
||||
- approved_at
|
||||
- approved_by
|
||||
- bodyshopid
|
||||
- ciecacode
|
||||
- cost_center
|
||||
- created_at
|
||||
- date
|
||||
- employeeid
|
||||
- flat_rate
|
||||
- id
|
||||
- jobid
|
||||
- memo
|
||||
- productivehrs
|
||||
- rate
|
||||
- updated_at
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
_and:
|
||||
- active:
|
||||
_eq: true
|
||||
- user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
check: null
|
||||
- table:
|
||||
name: users
|
||||
schema: public
|
||||
@@ -5287,6 +5718,20 @@
|
||||
table:
|
||||
name: parts_orders
|
||||
schema: public
|
||||
- name: timetickets
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: commited_by
|
||||
table:
|
||||
name: timetickets
|
||||
schema: public
|
||||
- name: tt_approval_queues
|
||||
using:
|
||||
foreign_key_constraint_on:
|
||||
column: approved_by
|
||||
table:
|
||||
name: tt_approval_queue
|
||||
schema: public
|
||||
insert_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
@@ -5472,6 +5917,30 @@
|
||||
_eq: X-Hasura-User-Id
|
||||
- active:
|
||||
_eq: true
|
||||
event_triggers:
|
||||
- name: os_vehicles
|
||||
definition:
|
||||
delete:
|
||||
columns: '*'
|
||||
enable_manual: false
|
||||
insert:
|
||||
columns: '*'
|
||||
update:
|
||||
columns: '*'
|
||||
retry_conf:
|
||||
interval_sec: 10
|
||||
num_retries: 3
|
||||
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}}/opensearch'
|
||||
version: 2
|
||||
- table:
|
||||
name: vendors
|
||||
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"."joblines" add column "act_price_before_ppc" numeric
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."joblines" add column "act_price_before_ppc" numeric
|
||||
null;
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE "public"."employee_teams";
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE "public"."employee_teams" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "bodyshopid" uuid NOT NULL, "name" text NOT NULL, "active" boolean NOT NULL DEFAULT true, PRIMARY KEY ("id") , FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE cascade ON DELETE cascade);
|
||||
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
_new record;
|
||||
BEGIN
|
||||
_new := NEW;
|
||||
_new."updated_at" = NOW();
|
||||
RETURN _new;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
CREATE TRIGGER "set_public_employee_teams_updated_at"
|
||||
BEFORE UPDATE ON "public"."employee_teams"
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
||||
COMMENT ON TRIGGER "set_public_employee_teams_updated_at" ON "public"."employee_teams"
|
||||
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE "public"."employee_team_members";
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE "public"."employee_team_members" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "teamid" uuid NOT NULL, "employeeid" uuid NOT NULL, "labor_rates" jsonb NOT NULL DEFAULT jsonb_build_object(), "percentage" numeric NOT NULL DEFAULT 0, PRIMARY KEY ("id") , FOREIGN KEY ("teamid") REFERENCES "public"."employee_teams"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("employeeid") REFERENCES "public"."employees"("id") ON UPDATE cascade ON DELETE cascade);
|
||||
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
_new record;
|
||||
BEGIN
|
||||
_new := NEW;
|
||||
_new."updated_at" = NOW();
|
||||
RETURN _new;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
CREATE TRIGGER "set_public_employee_team_members_updated_at"
|
||||
BEFORE UPDATE ON "public"."employee_team_members"
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
||||
COMMENT ON TRIGGER "set_public_employee_team_members_updated_at" ON "public"."employee_team_members"
|
||||
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."exportlog" add column "metadata" jsonb
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."exportlog" add column "metadata" jsonb
|
||||
null;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."bodyshops" add column "tt_enforce_hours_for_tech_console" boolean
|
||||
-- not null default 'false';
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."bodyshops" add column "tt_enforce_hours_for_tech_console" boolean
|
||||
not null default 'false';
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."timetickets" add column "committed_at" timestamptz
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."timetickets" add column "committed_at" timestamptz
|
||||
null;
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE "public"."tt_approval_queue";
|
||||
@@ -0,0 +1,18 @@
|
||||
CREATE TABLE "public"."tt_approval_queue" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "bodyshopid" uuid NOT NULL, "jobid" uuid NOT NULL, "employeeid" uuid NOT NULL, "timeticketid" uuid, "approved_by" text, "approved_at" timestamptz NOT NULL, "actualhrs" numeric NOT NULL DEFAULT 0, "productivehrs" numeric NOT NULL DEFAULT 0, "rate" numeric NOT NULL DEFAULT 0, "flat_rate" boolean NOT NULL DEFAULT true, "ciecacode" text, "cost_center" text NOT NULL, "date" date NOT NULL DEFAULT now(), "memo" text NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("employeeid") REFERENCES "public"."employees"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("timeticketid") REFERENCES "public"."timetickets"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("approved_by") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict);
|
||||
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
|
||||
RETURNS TRIGGER AS $$
|
||||
DECLARE
|
||||
_new record;
|
||||
BEGIN
|
||||
_new := NEW;
|
||||
_new."updated_at" = NOW();
|
||||
RETURN _new;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql;
|
||||
CREATE TRIGGER "set_public_tt_approval_queue_updated_at"
|
||||
BEFORE UPDATE ON "public"."tt_approval_queue"
|
||||
FOR EACH ROW
|
||||
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
|
||||
COMMENT ON TRIGGER "set_public_tt_approval_queue_updated_at" ON "public"."tt_approval_queue"
|
||||
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
|
||||
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."tt_approval_queue" alter column "approved_at" set not null;
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."tt_approval_queue" alter column "approved_at" drop not null;
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."tt_approval_queue" alter column "memo" set not null;
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."tt_approval_queue" alter column "memo" drop not null;
|
||||
@@ -0,0 +1,5 @@
|
||||
alter table "public"."tt_approval_queue"
|
||||
add constraint "tt_approval_queue_timeticketid_fkey"
|
||||
foreign key ("timeticketid")
|
||||
references "public"."timetickets"
|
||||
("id") on update cascade on delete cascade;
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."tt_approval_queue" drop constraint "tt_approval_queue_timeticketid_fkey";
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."tt_approval_queue" alter column "timeticketid" drop not null;
|
||||
alter table "public"."tt_approval_queue" add column "timeticketid" uuid;
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."tt_approval_queue" drop column "timeticketid" cascade;
|
||||
@@ -0,0 +1,4 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- alter table "public"."timetickets" add column "ttapprovalqueueid" uuid
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."timetickets" add column "ttapprovalqueueid" uuid
|
||||
null;
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."timetickets" drop constraint "timetickets_ttapprovalqueueid_fkey";
|
||||
@@ -0,0 +1,5 @@
|
||||
alter table "public"."timetickets"
|
||||
add constraint "timetickets_ttapprovalqueueid_fkey"
|
||||
foreign key ("ttapprovalqueueid")
|
||||
references "public"."tt_approval_queue"
|
||||
("id") on update cascade on delete set null;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user