Compare commits

...

81 Commits

Author SHA1 Message Date
Dave Richer
c98a48ea14 - Add Additional tags (prettier also fixed some double spaced imports)
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-19 12:57:45 -04:00
Patrick Fic
cdf02a8eac Merged in release/AIO/2024-04-19 (pull request #1420)
Resolve CCC supplement with UNQ_SEQ.
2024-04-18 20:49:45 +00:00
Dave Richer
7822e3f90e Merged in feature/IO-2760-IDS-for-headers (pull request #1424)
Add Header IDS

Approved-by: Patrick Fic
2024-04-18 17:25:15 +00:00
Dave Richer
a4a612fbe4 - adjust moment import
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-18 13:17:13 -04:00
Patrick Fic
2d9412e4e8 Merge branch 'release/2024-04-19' into release/AIO/2024-04-19 2024-04-16 16:10:33 -07:00
Patrick Fic
069d508528 Update cron trigger timing. 2024-04-16 16:09:54 -07:00
Patrick Fic
a9d38e743f Merge branch 'release/2024-04-19' into release/AIO/2024-04-19 2024-04-16 16:03:06 -07:00
Patrick Fic
878e81dc8f Hasura schema changes for tasks. 2024-04-16 16:02:25 -07:00
Patrick Fic
de35155ffe Resolve CCC supplement with UNQ_SEQ. 2024-04-16 15:15:25 -07:00
Dave Richer
a1f7e7b755 Merged in feature/IO-2667-Migrations-For-Remind-At-Sent (pull request #1416)
- Migrations for remind_at_sent
2024-04-16 19:52:13 +00:00
Dave Richer
c8f8a86a98 - Migrations for remind_at_sent
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-16 15:45:56 -04:00
Patrick Fic
443c6046f9 Merged in release/2024-04-19 (pull request #1415)
Resolve schedule header display.
2024-04-15 21:02:39 +00:00
Patrick Fic
1620b94a7b Merged in release/2024-04-19 (pull request #1414)
Resolve schedule header display.
2024-04-15 20:47:48 +00:00
Patrick Fic
81f94eac6c Resolve schedule header display. 2024-04-15 13:47:19 -07:00
Patrick Fic
ffada75d9e Merged in test-AIO (pull request #1412)
Test AIO

Approved-by: Dave Richer
2024-04-12 18:05:35 +00:00
Allan Carr
ec7509670d Merged in release/2024-04-12 (pull request #1413)
Release/2024 04 12

Approved-by: Dave Richer
2024-04-12 17:08:21 +00:00
Patrick Fic
25a49473f9 Merge branch 'release/AIO/2024-04-12' into test-AIO 2024-04-11 15:22:26 -07:00
Patrick Fic
8e86e7fba5 Resolve linting errors from merge. 2024-04-11 15:22:05 -07:00
Patrick Fic
f9b380a0d4 Merged in release/AIO/2024-04-12 (pull request #1411)
Release/AIO/2024 04 12
2024-04-11 22:16:32 +00:00
Patrick Fic
f664a56b16 Merge branch 'release/2024-04-12' into release/AIO/2024-04-12 2024-04-11 15:15:54 -07:00
Allan Carr
0acfd3c4b1 Merged in feature/IO-2609-Calendar-BPT-HRS (pull request #1409)
IO-2609 Fix Spelling Mistake in object name
2024-04-11 21:39:06 +00:00
Allan Carr
bfc4cb1ad9 IO-2609 Fix Spelling Mistake in object name
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-11 14:38:08 -07:00
Patrick Fic
66dd1a9a2b Merge branch 'feature/AIO/promanager' into test-AIO 2024-04-11 14:29:09 -07:00
Allan Carr
1f42be2e54 Merged in feature/IO-2753-Qty-Parts-Order-Modal (pull request #1405)
IO-2753 Parts Order/Return Quantity restrict to above 0
2024-04-11 21:22:37 +00:00
Allan Carr
30d344af6b Merged in feature/IO-2752-BO-ETA-Jobline-Expander (pull request #1404)
IO-2752 BO ETA Jobline Expander
2024-04-11 21:22:19 +00:00
Allan Carr
3ca989fd8c Merged in release/2024-04-05 (pull request #1401)
Release/2024 04 05

Approved-by: Dave Richer
2024-04-11 21:22:03 +00:00
Patrick Fic
73c38b3ae4 Merged in feature/IO-2458-RO-Closer (pull request #1406)
Feature/IO-2458 RO Closer
2024-04-11 20:25:25 +00:00
Allan Carr
ce2086a480 IO-2753 Parts Order/Return Quantity restrict to above 0
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-11 12:43:14 -07:00
Allan Carr
63f7106d2b IO-2752 BO ETA Jobline Expander
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-11 11:55:55 -07:00
Patrick Fic
e991586254 Merged in feature/IO-2458-RO-Closer (pull request #1403)
Bug fixes and formatting for RO guard.
2024-04-11 16:54:35 +00:00
Allan Carr
e75d8d1874 Merged in feature/IO-2609-Calendar-BPT-HRS (pull request #1402)
IO-2609 Body & Refinish Times included in Calendar View

Approved-by: Dave Richer
2024-04-11 16:27:02 +00:00
Patrick Fic
719fa6a67d ProMan totals changes. 2024-04-11 09:23:20 -07:00
Patrick Fic
512cd70d13 Merge branch 'feature/IO-2458-RO-Closer' into test-AIO 2024-04-09 12:23:49 -07:00
Allan Carr
07bf84ed69 IO-2609 Body & Refinish Times included in Calendar View
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-09 11:55:20 -07:00
Patrick Fic
f5b8bf1d74 Resolve unnecessary import. 2024-04-08 14:32:02 -07:00
Patrick Fic
61766017ea Resolve supplement import for CCC. 2024-04-08 14:28:58 -07:00
Patrick Fic
706984a53b Resolve CCC supplement import. 2024-04-08 14:27:33 -07:00
Patrick Fic
e137feca20 Resolve ESLint Warnings 2024-04-08 14:20:34 -07:00
Patrick Fic
9e66d7c929 Merge branch 'release/AIO/2024-04-05' into test-AIO 2024-04-08 13:56:10 -07:00
Patrick Fic
9605bf5c21 Merge branch 'release/2024-04-05' into release/AIO/2024-04-05 2024-04-08 13:55:43 -07:00
Allan Carr
c2cc7b1e9e Merged in feature/IO-2731-Payment-Edit (pull request #1399)
IO-2731 Payment Edit
2024-04-08 19:56:43 +00:00
Allan Carr
fe55eccbf9 Merged in feature/IO-2749-Parts-Return-Pass-Jobs-Data (pull request #1398)
IO-2749 Pass Jobs data from Parts Return to Parts Order Modal
2024-04-08 19:55:49 +00:00
Patrick Fic
47e17dc78a Merge branch 'feature/IO-2727-resolve-payment-refetch' into release/AIO/2024-04-05 2024-04-08 12:43:15 -07:00
Allan Carr
88a71dd647 IO-2731 Payment Edit
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-08 12:23:04 -07:00
Patrick Fic
ce0b3a8635 Merge branch 'feature/IO-2727-resolve-payment-refetch' into test-AIO 2024-04-08 11:08:57 -07:00
Patrick Fic
b8e4520366 Resolve ES Lint error. 2024-04-08 11:05:12 -07:00
Allan Carr
c3b395c99e IO-2749 Pass Jobs data from Parts Return to Parts Order Modal
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-08 09:53:20 -07:00
Patrick Fic
a2a7c1c58c Add contextRefect to payment export buttons. 2024-04-08 09:48:39 -07:00
Patrick Fic
1469960643 Resolve payment refetch. 2024-04-05 12:52:26 -07:00
Allan Carr
19a03ec080 Merge branch 'release/2024-04-05' into test-AIO
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>

# Conflicts:
#	client/src/components/print-center-jobs-labels/print-center-jobs-labels.component.jsx
2024-04-05 12:21:35 -07:00
Allan Carr
33d5d9b462 Merged in feature/IO-2568-Payment-Modal-Button-Spacing (pull request #1396)
IO-2568 Button Padding in Print Center Label Modal
2024-04-05 19:03:09 +00:00
Allan Carr
b5a371d0cf IO-2568 Button Padding in Print Center Label Modal
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-05 12:01:26 -07:00
Dave Richer
b61fd17879 - add smart refetch to mark-export and reexport
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-05 14:54:16 -04:00
Dave Richer
6722f8b1e5 - reversion
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-05 13:41:37 -04:00
Dave Richer
69ff75157d - reversion
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-05 13:35:44 -04:00
Allan Carr
7c619f5439 Merged in release/2024-04-05 (pull request #1395)
IO-2750 Missing Mutation return fields
2024-04-05 16:00:52 +00:00
Allan Carr
3b35f38ad5 Merged in feature/IO-2750-Missing-Jobline-Fields (pull request #1393)
IO-2750 Missing Mutation return fields
2024-04-05 15:55:13 +00:00
Dave Richer
4ff2ab1bc8 - Remove actions params in Payment modal, which was causing issues.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-05 11:20:16 -04:00
Dave Richer
83a976e98f - Add ESLint back to Vite
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-04-05 09:59:30 -04:00
Patrick Fic
d7caaecaf7 Merge branch 'feature/IO-2458-RO-Closer' into test-AIO 2024-04-04 20:42:17 -07:00
Patrick Fic
7ece1256f2 Uncomment ProManager calculations. 2024-04-04 20:01:47 -07:00
Allan Carr
1f5c1b9658 IO-2750 Missing Mutation return fields
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-04 17:00:30 -07:00
Patrick Fic
a43134511b Merge branch 'release/2024-04-05' into test-AIO 2024-04-04 12:56:09 -07:00
Patrick Fic
b188cce3ea Merge branch 'test-AIO' of bitbucket.org:snaptsoft/bodyshop into test-AIO 2024-04-04 12:52:02 -07:00
Patrick Fic
56dfd174dd Merge branch 'hotfix/AIO/2024-04-04' into master-AIO 2024-04-04 11:32:09 -07:00
Patrick Fic
39d4f56812 Merge branch 'hotfix/AIO/2024-04-04' into test-AIO 2024-04-04 11:32:01 -07:00
Patrick Fic
f85e3d8d60 Resolve job costing. 2024-04-04 11:31:37 -07:00
Patrick Fic
c33eaa6c68 Merged in feature/IO-2458-RO-Closer (pull request #1390)
Feature/IO-2458 RO Closer
2024-04-04 18:14:11 +00:00
Patrick Fic
532cd4937b Merge branch 'hotfix/AIO/2024-04-04' into master-AIO 2024-04-04 10:51:57 -07:00
Patrick Fic
37196e65c3 Add schema changes for RO Guard to bodyshop table. 2024-04-03 09:46:52 -07:00
Allan Carr
b20c605c85 Merged in feature/IO-2568-Payment-Modal-Button-Spacing (pull request #1384)
IO-2568 Payment Modal Button Spacing

Approved-by: Dave Richer
2024-04-02 19:03:49 +00:00
Allan Carr
d8ac708536 Merged in feature/IO-2552-PVRT-Button-Spacing (pull request #1386)
IO-2552 PVRT Button Spacing and Alignment

Approved-by: Dave Richer
2024-04-02 19:03:36 +00:00
Allan Carr
8a32fe50f3 Merged in feature/IO-2730-Bill-Search-Result-Align (pull request #1383)
IO-2730 Bill Search Result Align

Approved-by: Dave Richer
2024-04-02 19:03:06 +00:00
Allan Carr
7897a490bd Merged in feature/IO-2563-Repair-Line-Expander-Bills-Transaltion (pull request #1385)
IO-2563 Repair LIne Expander Bills Translation

Approved-by: Dave Richer
2024-04-02 19:02:50 +00:00
Allan Carr
17d73fc6d7 Merged in feature/IO-2553-Edit-CC-Unsaved-Changes (pull request #1388)
IO-2553 Unsaved Changes on Edit CC

Approved-by: Dave Richer
2024-04-02 19:02:28 +00:00
Allan Carr
7d1910086e IO-2553 Unsaved Changes on Edit CC
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-02 10:39:41 -07:00
Allan Carr
817c41afb9 IO-2552 PVRT Button Spacing and Alignment
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-01 14:27:25 -07:00
Allan Carr
04315a9045 IO-2563 Repair LIne Expander Bills Translation
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-01 14:07:58 -07:00
Allan Carr
d0871ffe21 IO-2568 Payment Modal Button Spacing
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-01 13:52:25 -07:00
Allan Carr
dca587d6e0 IO-2730 Bill Search Result Align
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-04-01 13:20:30 -07:00
Allan Carr
19ec4cb021 Merged in release/2024-03-28 (pull request #1382)
Release/2024 03 28
2024-03-28 21:15:25 +00:00
39 changed files with 539 additions and 247 deletions

5
client/.eslintrc Normal file
View File

@@ -0,0 +1,5 @@
{
"extends": [
"react-app"
]
}

View File

@@ -96,6 +96,8 @@
"browserslist-to-esbuild": "^2.1.1",
"cross-env": "^7.0.3",
"cypress": "^13.6.6",
"eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-cypress": "^2.15.1",
"memfs": "^4.6.0",
"os-browserify": "^0.3.0",
@@ -104,6 +106,7 @@
"source-map-explorer": "^2.5.3",
"vite": "^5.0.11",
"vite-plugin-babel": "^1.2.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-legacy": "^2.1.0",
"vite-plugin-node-polyfills": "^0.19.0",
"vite-plugin-pwa": "^0.19.0",
@@ -11934,7 +11937,8 @@
},
"node_modules/eslint": {
"version": "8.57.0",
"license": "MIT",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
"integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -11987,7 +11991,8 @@
},
"node_modules/eslint-config-react-app": {
"version": "7.0.1",
"license": "MIT",
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-7.0.1.tgz",
"integrity": "sha512-K6rNzvkIeHaTd8m/QEh1Zko0KI7BACWkkneSs6s9cKZC/J27X3eZR6Upt1jkmZ/4FK+XUOPPxMEN7+lbUXfSlA==",
"dependencies": {
"@babel/core": "^7.16.0",
"@babel/eslint-parser": "^7.16.3",
@@ -26439,6 +26444,36 @@
"vite": ">=5.0.0"
}
},
"node_modules/vite-plugin-eslint": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/vite-plugin-eslint/-/vite-plugin-eslint-1.8.1.tgz",
"integrity": "sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang==",
"dev": true,
"dependencies": {
"@rollup/pluginutils": "^4.2.1",
"@types/eslint": "^8.4.5",
"rollup": "^2.77.2"
},
"peerDependencies": {
"eslint": ">=7",
"vite": ">=2"
}
},
"node_modules/vite-plugin-eslint/node_modules/rollup": {
"version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
"integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
"dev": true,
"bin": {
"rollup": "dist/bin/rollup"
},
"engines": {
"node": ">=10.0.0"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/vite-plugin-legacy": {
"version": "2.1.0",
"dev": true,

View File

@@ -140,6 +140,8 @@
"browserslist-to-esbuild": "^2.1.1",
"cross-env": "^7.0.3",
"cypress": "^13.6.6",
"eslint": "^8.57.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-cypress": "^2.15.1",
"memfs": "^4.6.0",
"os-browserify": "^0.3.0",
@@ -148,6 +150,7 @@
"source-map-explorer": "^2.5.3",
"vite": "^5.0.11",
"vite-plugin-babel": "^1.2.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-legacy": "^2.1.0",
"vite-plugin-node-polyfills": "^0.19.0",
"vite-plugin-pwa": "^0.19.0",

View File

@@ -34,6 +34,7 @@ export function BillDetailEditReturn({ setPartsOrderContext, insertAuditTrail, b
actions: {},
context: {
jobId: data.bills_by_pk.jobid,
job: data.bills_by_pk.job,
vendorId: data.bills_by_pk.vendorid,
returnFromBill: data.bills_by_pk.id,
invoiceNumber: data.bills_by_pk.invoice_number,

View File

@@ -57,7 +57,7 @@ export function BillsListTableComponent({
)}
<BillDeleteButton bill={record} jobid={job.id} />
<BillDetailEditReturnComponent
data={{ bills_by_pk: { ...record, jobid: job.id } }}
data={{ bills_by_pk: { ...record, jobid: job.id, job: job } }}
disabled={record.is_credit_memo || record.vendorid === bodyshop.inhousevendorid || jobRO}
/>

View File

@@ -1,9 +1,8 @@
import React, { useState } from "react";
import { Button, Form, InputNumber, Popover } from "antd";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { useTranslation } from "react-i18next";
import { CalculatorFilled } from "@ant-design/icons";
import { Button, Form, InputNumber, Popover, Space } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils";
export default function CABCpvrtCalculator({ disabled, form }) {
const [visibility, setVisibility] = useState(false);
@@ -27,10 +26,14 @@ export default function CABCpvrtCalculator({ disabled, form }) {
<Form.Item name="days" label={t("jobs.labels.ca_bc_pvrt.days")}>
<InputNumber precision={0} min={0} />
</Form.Item>
<Button type="primary" htmlType="submit">
{t("general.actions.calculate")}
</Button>
<Button onClick={() => setVisibility(false)}>Close</Button>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<Space>
<Button type="primary" htmlType="submit">
{t("general.actions.calculate")}
</Button>
<Button onClick={() => setVisibility(false)}>Close</Button>
</Space>
</div>
</Form>
</div>
);

View File

@@ -11,11 +11,15 @@ import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel
import CourtesyCarReadiness from "../courtesy-car-readiness-select/courtesy-car-readiness-select.component";
import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
//import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
export default function CourtesyCarCreateFormComponent({
form,
saveLoading,
newCC,
}) {
const { t } = useTranslation();
const client = useApolloClient();
@@ -30,7 +34,7 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
}
/>
{/* <FormFieldsChanged form={form} /> */}
{newCC ? null : <FormFieldsChanged form={form} />}
<LayoutFormRow header={t("courtesycars.labels.vehicle")}>
<Form.Item
label={t("courtesycars.fields.year")}

View File

@@ -278,10 +278,12 @@ function Header({
{
key: "home",
icon: <HomeFilled />,
id: "header-home",
label: <Link to="/manage/">{t("menus.header.home")}</Link>
},
{
key: "schedule",
id: "header-schedule",
icon: <Icon component={FaCalendarAlt} />,
label: <Link to="/manage/schedule">{t("menus.header.schedule")}</Link>
},
@@ -293,16 +295,19 @@ function Header({
children: [
{
key: "activejobs",
id: "header-active-jobs",
icon: <FileFilled />,
label: <Link to="/manage/jobs">{t("menus.header.activejobs")}</Link>
},
{
key: "readyjobs",
id: "header-ready-jobs",
icon: <CheckCircleOutlined />,
label: <Link to="/manage/jobs/ready">{t("menus.header.readyjobs")}</Link>
},
{
key: "parts-queue",
id: "header-parts-queue",
icon: <ToolFilled />,
label: <Link to="/manage/partsqueue">{t("menus.header.parts-queue")}</Link>
},
@@ -314,6 +319,7 @@ function Header({
},
{
key: "newjob",
id: "header-new-job",
icon: <FileAddOutlined />,
label: <Link to="/manage/jobs/new">{t("menus.header.newjob")}</Link>
},
@@ -322,6 +328,7 @@ function Header({
},
{
key: "alljobs",
id: "header-all-jobs",
icon: <UnorderedListOutlined />,
label: <Link to="/manage/jobs/all">{t("menus.header.alljobs")}</Link>
},
@@ -330,6 +337,7 @@ function Header({
},
{
key: "productionlist",
id: "header-production-list",
icon: <ScheduleOutlined />,
label: <Link to="/manage/production/list">{t("menus.header.productionlist")}</Link>
},
@@ -341,6 +349,7 @@ function Header({
? [
{
key: "productionboard",
id: "header-production-board",
icon: <Icon component={BsKanban} />,
label: <Link to="/manage/production/board">{t("menus.header.productionboard")}</Link>
}
@@ -358,6 +367,7 @@ function Header({
},
{
key: "scoreboard",
id: "header-scoreboard",
icon: <LineChartOutlined />,
label: <Link to="/manage/scoreboard">{t("menus.header.scoreboard")}</Link>
}
@@ -368,15 +378,18 @@ function Header({
{
key: "customers",
icon: <UserOutlined />,
id: "header-customers",
label: t("menus.header.customers"),
children: [
{
key: "owners",
id: "header-owners",
icon: <TeamOutlined />,
label: <Link to="/manage/owners">{t("menus.header.owners")}</Link>
},
{
key: "vehicles",
id: "header-vehicles",
icon: <CarFilled />,
label: <Link to="/manage/vehicles">{t("menus.header.vehicles")}</Link>
}
@@ -390,21 +403,25 @@ function Header({
? [
{
key: "ccs",
id: "header-css",
icon: <CarFilled />,
label: t("menus.header.courtesycars"),
children: [
{
key: "courtesycarsall",
id: "header-courtesycars-all",
icon: <CarFilled />,
label: <Link to="/manage/courtesycars">{t("menus.header.courtesycars-all")}</Link>
},
{
key: "contracts",
id: "header-contracts",
icon: <FileFilled />,
label: <Link to="/manage/courtesycars/contracts">{t("menus.header.courtesycars-contracts")}</Link>
},
{
key: "newcontract",
id: "header-newcontract",
icon: <FileAddFilled />,
label: <Link to="/manage/courtesycars/contracts/new">{t("menus.header.courtesycars-newcontract")}</Link>
}
@@ -417,6 +434,7 @@ function Header({
? [
{
key: "accounting",
id: "header-accounting",
icon: <DollarCircleFilled />,
label: t("menus.header.accounting"),
children: accountingChildren
@@ -425,6 +443,7 @@ function Header({
: []),
{
key: "phonebook",
id: "header-phonebook",
icon: <PhoneOutlined />,
label: <Link to="/manage/phonebook">{t("menus.header.phonebook")}</Link>
},
@@ -436,6 +455,7 @@ function Header({
? [
{
key: "temporarydocs",
id: "header-temporarydocs",
icon: <PaperClipOutlined />,
label: <Link to="/manage/temporarydocs">{t("menus.header.temporarydocs")}</Link>
}
@@ -443,21 +463,25 @@ function Header({
: []),
{
key: "shopsubmenu",
id: "header-shopsubmenu",
icon: <SettingOutlined />,
label: t("menus.header.shop"),
children: [
{
key: "shop",
id: "header-shop",
icon: <Icon component={GiSettingsKnobs} />,
label: <Link to="/manage/shop?tab=info">{t("menus.header.shop_config")}</Link>
},
{
key: "dashboard",
id: "header-dashboard",
icon: <DashboardFilled />,
label: <Link to="/manage/dashboard">{t("menus.header.dashboard")}</Link>
},
{
key: "reportcenter",
id: "header-reportcenter",
icon: <BarChartOutlined />,
label: t("menus.header.reportcenter"),
onClick: () => {
@@ -469,6 +493,7 @@ function Header({
},
{
key: "shop-vendors",
id: "header-shop-vendors",
icon: <Icon component={IoBusinessOutline} />,
label: <Link to="/manage/shop/vendors">{t("menus.header.shop_vendors")}</Link>
},
@@ -480,6 +505,7 @@ function Header({
? [
{
key: "shop-csi",
id: "header-shop-csi",
icon: <Icon component={RiSurveyLine} />,
label: <Link to="/manage/shop/csi">{t("menus.header.shop_csi")}</Link>
}
@@ -493,6 +519,7 @@ function Header({
children: [
{
key: "signout",
id: "header-signout",
icon: <Icon component={FiLogOut} />,
danger: true,
label: t("user.actions.signout"),
@@ -500,6 +527,7 @@ function Header({
},
{
key: "help",
id: "header-help",
icon: <Icon component={QuestionCircleFilled} />,
label: t("menus.header.help"),
onClick: () => {
@@ -531,6 +559,7 @@ function Header({
? [
{
key: "shiftclock",
id: "header-shiftclock",
icon: <Icon component={GiPlayerTime} />,
label: <Link to="/manage/shiftclock">{t("menus.header.shiftclock")}</Link>
}
@@ -538,6 +567,7 @@ function Header({
: []),
{
key: "profile",
id: "header-profile",
icon: <UserOutlined />,
label: <Link to="/manage/profile">{t("menus.currentuser.profile")}</Link>
}
@@ -573,6 +603,7 @@ function Header({
{
key: "recent",
icon: <ClockCircleFilled />,
id: "header-recent",
children: recentItems.map((i, idx) => ({
key: idx,
label: <Link to={i.url}>{i.label}</Link>
@@ -586,6 +617,7 @@ function Header({
imex: () => {
menuItems.push({
key: "beta-switch",
id: "header-beta-switch",
style: { marginLeft: "auto" },
label: (
<Tooltip

View File

@@ -1,5 +1,5 @@
import { useQuery } from "@apollo/client";
import { Col, Divider, Row, Skeleton, Space, Timeline, Typography } from "antd";
import { Col, Row, Skeleton, Space, Timeline, Typography } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
@@ -43,13 +43,25 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
? data.parts_order_lines.map((line) => ({
key: line.id,
children: (
<Space split={<Divider type="vertical" />} wrap>
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.parts_order.id}`}>
{line.parts_order.order_number}
</Link>
<DateFormatter>{line.parts_order.order_date}</DateFormatter>
{line.parts_order.vendor.name}
</Space>
<Row wrap>
<Col span={4}>
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.parts_order.id}`}>
{line.parts_order.order_number}
</Link>
</Col>
<Col span={4}>
<DateFormatter>{line.parts_order.order_date}</DateFormatter>
</Col>
<Col span={4}>{line.parts_order.vendor.name}</Col>
{line.backordered_eta ? (
<Col span={4}>
<span>
{`${t("parts_orders.fields.backordered_eta")}: `}
<DateFormatter>{line.backordered_eta}</DateFormatter>
</span>
</Col>
) : null}
</Row>
)
}))
: [
@@ -61,6 +73,37 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
}
/>{" "}
</Col>
<Col md={24} lg={8}>
<Typography.Title level={4}>{t("parts_dispatch.labels.parts_dispatch")}</Typography.Title>
<Timeline
items={
data.parts_dispatch_lines.length > 0
? data.parts_dispatch_lines.map((line) => ({
key: line.id,
children: (
<Row>
<Col span={8}>
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.id}`}>{line.parts_dispatch.number}</Link>
</Col>
<Col span={8}>
{bodyshop.employees.find((e) => e.id === line.parts_dispatch.employeeid)?.first_name}
</Col>
<Col span={8}>
<Space>
{t("parts_dispatch_lines.fields.accepted_at")}
<DateFormatter>{line.accepted_at}</DateFormatter>
</Space>
</Col>
</Row>
)
}))
: {
key: "dispatch-lines",
children: t("parts_orders.labels.notyetordered")
}
}
/>
</Col>
<Col md={24} lg={8}>
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
<Timeline
@@ -97,37 +140,12 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
: [
{
key: "no-orders",
children: t("parts_orders.labels.notyetordered")
children: t("bills.labels.nobilllines")
}
]
}
/>
</Col>
<Col md={24} lg={8}>
<Typography.Title level={4}>{t("parts_dispatch.labels.parts_dispatch")}</Typography.Title>
<Timeline
items={
data.parts_dispatch_lines.length > 0
? data.parts_dispatch_lines.map((line) => ({
key: line.id,
children: (
<Space split={<Divider type="vertical" />} wrap>
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.id}`}>{line.parts_dispatch.number}</Link>
{bodyshop.employees.find((e) => e.id === line.parts_dispatch.employeeid)?.first_name}
<Space>
{t("parts_dispatch_lines.fields.accepted_at")}
<DateFormatter>{line.accepted_at}</DateFormatter>
</Space>
</Space>
)
}))
: {
key: "dispatch-lines",
children: t("parts_orders.labels.notyetordered")
}
}
/>
</Col>
</Row>
);
}

View File

@@ -1,3 +1,4 @@
import { LoadingOutlined } from "@ant-design/icons";
import { useLazyQuery } from "@apollo/client";
import { Select, Space, Spin, Tag } from "antd";
import _ from "lodash";
@@ -6,8 +7,6 @@ import { useTranslation } from "react-i18next";
import { SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE, SEARCH_JOBS_FOR_AUTOCOMPLETE } from "../../graphql/jobs.queries";
import AlertComponent from "../alert/alert.component";
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
import { SearchOutlined } from "@ant-design/icons";
import { LoadingOutlined } from "@ant-design/icons";
const { Option } = Select;
@@ -19,9 +18,14 @@ const JobSearchSelect = (
const [theOptions, setTheOptions] = useState([]);
const [callSearch, { loading, error, data }] = useLazyQuery(SEARCH_JOBS_FOR_AUTOCOMPLETE, {});
const [callIdSearch, { loading: idLoading, error: idError, data: idData }] = useLazyQuery(
SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE
);
const [
callIdSearch,
{
//loading: idLoading,
error: idError,
data: idData
}
] = useLazyQuery(SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE);
const executeSearch = (v) => {
if (v && v.variables?.search !== "" && v.variables.search.length >= 2) callSearch(v);
@@ -86,9 +90,9 @@ const JobSearchSelect = (
<span>
{`${clm_no && o.clm_no ? `${o.clm_no} | ` : ""}${
o.ro_number || t("general.labels.na")
} | ${OwnerNameDisplayFunction(o)} | ${
o.v_model_yr || ""
} ${o.v_make_desc || ""} ${o.v_model_desc || ""}`}
} | ${OwnerNameDisplayFunction(o)} | ${o.v_model_yr || ""} ${o.v_make_desc || ""} ${
o.v_model_desc || ""
}`}
</span>
<Tag>
<strong>{o.status}</strong>

View File

@@ -15,23 +15,43 @@ export const GetSupplementDelta = async (client, jobId, newLines) => {
const linesToUpdate = [];
newLines.forEach((newLine) => {
const matchingIndex = existingLines.findIndex((eL) => eL.unq_seq === newLine.unq_seq);
const matchingIndexLines = [];
existingLines.forEach((eL, index) => {
if (eL.unq_seq === newLine.unq_seq) {
matchingIndexLines.push({ index, record: eL });
}
});
//Should do a check to make sure there is only 1 matching unq sequence number.
if (matchingIndex >= 0) {
//Found a relevant matching line. Add it to lines to update.
linesToUpdate.push({
id: existingLines[matchingIndex].id,
newData: { ...newLine, removed: false, act_price_before_ppc: null }
});
//Splice out item we found for performance.
existingLines.splice(matchingIndex, 1);
} else {
if (matchingIndexLines.length === 0) {
//Didn't find a match. Must be a new line.
linesToInsert.push(newLine);
}
//If we find only 1, we can use the old logic.
else if (matchingIndexLines.length === 1) {
//Found a relevant matching line. Add it to lines to update.
linesToUpdate.push({
id: matchingIndexLines[0].record.id,
newData: { ...newLine, removed: false, act_price_before_ppc: null }
});
//Splice out item we found for performance.
existingLines.splice(matchingIndexLines[0].index, 1);
} else if (matchingIndexLines.length === 2) {
//if we find 2, we need to separate it out by the non-refinish lines and splice one out.
//Find the mathcing one depending on whether this is the refiniish one or not.
const matchingLine = matchingIndexLines.find((i) =>
newLine.mod_lbr_ty === "LAR" ? i.record.mod_lbr_ty === "LAR" : i.record.mod_lbr_ty !== "LAR"
);
linesToUpdate.push({
id: matchingLine.record.id,
newData: { ...newLine, removed: false, act_price_before_ppc: null }
});
//Splice out item we found for performance.
existingLines.splice(matchingLine.index, 1);
} else {
//We found more than 2 matching lines. We should never get here. Throw a warning and back out!
throw new Error("Too many matching lines found. Ensure EMS file is valid.");
}
});
//Wahtever is left in the existing lines, are lines that should be removed.

View File

@@ -237,7 +237,7 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail
executeFunction: true,
rome: ResolveCCCLineIssues,
promanager: ResolveCCCLineIssues,
args: [(supp, bodyshop)]
args: [supp, bodyshop]
});
await InstanceRenderManager({
@@ -592,32 +592,34 @@ function ResolveCCCLineIssues(estData, bodyshop) {
//Group by line no
// For everything but the first one, strip out the price number in
// InstanceRenderManager({executeFunction:true, args:[], promanager: () => {
// const groupedByLineRef = _.groupBy(estData.joblines.data, "line_ref");
// Object.keys(groupedByLineRef).forEach((lineRef) => {
// let index0ActPrice;
// groupedByLineRef[lineRef].forEach((line, index) => {
// //Let the first one keep it
// if (index === 0){
// index0ActPrice = line.act_price;
// return;}
// //Web Est seems to have additional costs with UNQ_SEQ 0. Keep them all?
// if (line.unq_seq === 0) return;
// if(index0ActPrice !== line.act_price){
// line.notes += ` | Price override.`;
// return;
// }
// const indexInEstData = estData.joblines.data.findIndex(
// (l) => l.unq_seq === line.unq_seq
// );
// estData.joblines.data[
// indexInEstData
// ].notes += ` | Scrubbed due to the line_ref issue. (prev act price = ${estData.joblines.data[indexInEstData].act_price})`;
// estData.joblines.data[indexInEstData].act_price = 0;
// estData.joblines.data[indexInEstData].db_price = 0;
// });
// })
// }})
InstanceRenderManager({
executeFunction: true,
args: [],
promanager: () => {
const groupedByLineRef = _.groupBy(estData.joblines.data, "line_ref");
Object.keys(groupedByLineRef).forEach((lineRef) => {
let index0ActPrice;
groupedByLineRef[lineRef].forEach((line, index) => {
//Let the first one keep it
if (index === 0) {
index0ActPrice = line.act_price;
return;
}
//Web Est seems to have additional costs with UNQ_SEQ 0. Keep them all?
if (line.unq_seq === 0) return;
if (index0ActPrice !== line.act_price) {
// line.notes += ` | Price override.`;
return;
}
const indexInEstData = estData.joblines.data.findIndex((l) => l.unq_seq === line.unq_seq);
//estData.joblines.data[indexInEstData].notes +=
// ` | Act Price delete. (prev act price = ${estData.joblines.data[indexInEstData].act_price})`;
estData.joblines.data[indexInEstData].act_price = 0;
estData.joblines.data[indexInEstData].db_price = 0;
});
});
}
});
InstanceRenderManager({
executeFunction: true,

View File

@@ -182,7 +182,7 @@ export function PartsOrderModalComponent({ bodyshop, vendorList, sendTypeState,
}
]}
>
<InputNumber />
<InputNumber min={1} />
</Form.Item>
<Form.Item
label={t("parts_orders.fields.act_price")}

View File

@@ -7,17 +7,19 @@ import { createStructuredSelector } from "reselect";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import { UPDATE_PAYMENT } from "../../graphql/payments.queries";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectPayment } from "../../redux/modals/modals.selectors";
import { selectCurrentUser } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser
currentUser: selectCurrentUser,
paymentModal: selectPayment
});
const mapDispatchToProps = (dispatch) => ({
setPaymentContext: (context) => dispatch(setModalContext({ context: context, modal: "payment" }))
});
const PaymentMarkForExportButton = ({ bodyshop, payment, refetch, setPaymentContext, currentUser }) => {
const PaymentMarkForExportButton = ({ bodyshop, payment, refetch, setPaymentContext, currentUser, paymentModal }) => {
const { t } = useTranslation();
const [insertExportLog, { loading: exportLogLoading }] = useMutation(INSERT_EXPORT_LOG);
const [updatePayment, { loading: updatePaymentLoading }] = useMutation(UPDATE_PAYMENT);
@@ -56,16 +58,21 @@ const PaymentMarkForExportButton = ({ bodyshop, payment, refetch, setPaymentCont
refetch
},
context: {
...paymentModal.context,
...paymentModal.context,
...payment,
smartRefetch: true,
exportedat: today
}
});
if (refetch)
refetch(
paymentUpdateResponse &&
paymentUpdateResponse.data.update_payments.returning[0]
);
if (refetch) {
if (paymentModal.context.refetchRequiresContext) {
refetch(paymentUpdateResponse && paymentUpdateResponse.data.update_payments.returning[0]);
} else {
refetch();
}
}
} else {
notification["error"]({
message: t("payments.errors.exporting", {

View File

@@ -1,33 +1,30 @@
import { useMutation } from "@apollo/client";
import { Button, Form, Modal, notification, Space } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { INSERT_NEW_PAYMENT, UPDATE_PAYMENT } from "../../graphql/payments.queries";
import { setEmailOptions } from "../../redux/email/email.actions";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectPayment } from "../../redux/modals/modals.selectors";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
import {useMutation} from "@apollo/client";
import {Button, Form, Modal, notification, Space} from "antd";
import React, {useEffect, useState} from "react";
import {useTranslation} from "react-i18next";
import {connect} from "react-redux";
import {createStructuredSelector} from "reselect";
import {INSERT_NEW_PAYMENT, UPDATE_PAYMENT} from "../../graphql/payments.queries";
import {toggleModalVisible} from "../../redux/modals/modals.actions";
import {selectPayment} from "../../redux/modals/modals.selectors";
import {selectBodyshop} from "../../redux/user/user.selectors";
import {GenerateDocument} from "../../utils/RenderTemplate";
import {TemplateList} from "../../utils/TemplateConstants";
import PaymentForm from "../payment-form/payment-form.component";
import PaymentMarkForExportButton from "../payment-mark-export-button/payment-mark-export-button-component";
import PaymentMarkForExportButton
from "../payment-mark-export-button/payment-mark-export-button-component";
import PaymentReexportButton from "../payment-reexport-button/payment-reexport-button.component";
const mapStateToProps = createStructuredSelector({
paymentModal: selectPayment,
bodyshop: selectBodyshop,
currentUser: selectCurrentUser
});
const mapDispatchToProps = (dispatch) => ({
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
toggleModalVisible: () => dispatch(toggleModalVisible("payment"))
});
function PaymentModalContainer({ paymentModal, toggleModalVisible, bodyshop, currentUser, setEmailOptions }) {
function PaymentModalContainer({paymentModal, toggleModalVisible, bodyshop }) {
const [form] = Form.useForm();
const [enterAgain, setEnterAgain] = useState(false);
const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
@@ -35,7 +32,6 @@ function PaymentModalContainer({ paymentModal, toggleModalVisible, bodyshop, cur
const { t } = useTranslation();
const { context, actions, open } = paymentModal;
const [loading, setLoading] = useState(false);
const handleFinish = async (values) => {
@@ -85,13 +81,19 @@ function PaymentModalContainer({ paymentModal, toggleModalVisible, bodyshop, cur
});
if (!!!updatedPayment.errors) {
notification["success"]({ message: t("payments.successes.payment") });
notification["success"]({ message: t("payments.successes.paymentupdate") });
} else {
notification["error"]({ message: t("payments.errors.payment") });
notification["error"]({ message: t("payments.errors.paymentupdate") });
}
}
if (actions.refetch) actions.refetch(updatedPayment && updatedPayment.data.update_payments.returning[0]);
if (actions.refetch) {
if (context.refetchRequiresContext) {
actions.refetch(updatedPayment && updatedPayment.data.update_payments.returning[0]);
} else {
actions.refetch();
}
}
if (enterAgain) {
const prev = form.getFieldsValue(["date"]);
@@ -166,13 +168,7 @@ function PaymentModalContainer({ paymentModal, toggleModalVisible, bodyshop, cur
</Space>
)}
<Form
onFinish={handleFinish}
autoComplete={"off"}
form={form}
layout="vertical"
disabled={context?.exportedat}
>
<Form onFinish={handleFinish} autoComplete={"off"} form={form} layout="vertical" disabled={context?.exportedat}>
<PaymentForm form={form} />
</Form>
</Modal>

View File

@@ -3,14 +3,20 @@ import { Button, notification } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { UPDATE_PAYMENT } from "../../graphql/payments.queries";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectPayment } from "../../redux/modals/modals.selectors";
const mapStateToProps = createStructuredSelector({
paymentModal: selectPayment
});
const mapDispatchToProps = (dispatch) => ({
setPaymentContext: (context) => dispatch(setModalContext({ context: context, modal: "payment" }))
});
const PaymentReexportButton = ({ payment, refetch, setPaymentContext }) => {
const PaymentReexportButton = ({ paymentModal, payment, refetch, setPaymentContext }) => {
const { t } = useTranslation();
const [updatePayment, { loading }] = useMutation(UPDATE_PAYMENT);
@@ -34,15 +40,20 @@ const PaymentReexportButton = ({ payment, refetch, setPaymentContext }) => {
refetch
},
context: {
...paymentModal.context,
...paymentModal.context,
...payment,
exportedat: null
}
});
if (refetch)
refetch(
paymentUpdateResponse &&
paymentUpdateResponse.data.update_payments.returning[0]
);
if (refetch) {
if (paymentModal.context.refetchRequiresContext) {
refetch(paymentUpdateResponse && paymentUpdateResponse.data.update_payments.returning[0]);
} else {
refetch();
}
}
} else {
notification["error"]({
message: t("payments.errors.exporting", {
@@ -59,4 +70,4 @@ const PaymentReexportButton = ({ payment, refetch, setPaymentContext }) => {
);
};
export default connect(null, mapDispatchToProps)(PaymentReexportButton);
export default connect(mapStateToProps, mapDispatchToProps)(PaymentReexportButton);

View File

@@ -14,11 +14,11 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
import { TemplateList } from "../../utils/TemplateConstants";
import { pageLimit } from "../../utils/config";
import { alphaSort } from "../../utils/sorters";
import CaBcEtfTableModalContainer from "../ca-bc-etf-table-modal/ca-bc-etf-table-modal.container";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
import { pageLimit } from "../../utils/config";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -171,7 +171,7 @@ export function PaymentsListPaginated({
}
: refetch
},
context: apolloResults ? apolloResults : record
context: { ...(apolloResults ? apolloResults : record), refetchRequiresContext: true }
});
}}
>

View File

@@ -1,4 +1,13 @@
import { Button, Card, Form, InputNumber, notification, Popover, Radio } from "antd";
import {
Button,
Card,
Form,
InputNumber,
notification,
Popover,
Radio,
Space,
} from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -95,10 +104,16 @@ export function PrintCenterJobsLabels({ bodyshop, jobId }) {
>
<InputNumber min={1} precision={0} max={99} />
</Form.Item>
<Button type="primary" loading={loading} onClick={handleOk}>
{t("general.actions.print")}
</Button>
<Button onClick={handleCancel}>{t("general.actions.cancel")}</Button>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<Space>
<Button type="primary" loading={loading} onClick={handleOk}>
{t("general.actions.print")}
</Button>
<Button onClick={handleCancel}>
{t("general.actions.cancel")}
</Button>
</Space>
</div>
</Form>
</Card>
);

View File

@@ -59,25 +59,33 @@ export function ScheduleCalendarHeaderComponent({
{loadData && loadData.allJobsOut ? (
loadData.allJobsOut.map((j) => (
<tr key={j.id}>
<td>
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
<td style={{ padding: "2.5px" }}>
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link> (
{j.status})
</td>
<td>
<td style={{ padding: "2.5px" }}>
<OwnerNameDisplay ownerObject={j} />
</td>
<td>
{`(${(j.labhrs.aggregate.sum.mod_lb_hrs + j.larhrs.aggregate.sum.mod_lb_hrs).toFixed(
1
)} ${t("general.labels.hours")})`}
<td style={{ padding: "2.5px" }}>
{`(${j.labhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0}/${
j.larhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0
}/${(
j.labhrs.aggregate?.sum?.mod_lb_hrs +
j.larhrs.aggregate?.sum?.mod_lb_hrs
).toFixed(1)} ${t("general.labels.hours")})`}
</td>
<td>
<DateTimeFormatter>{j.scheduled_completion}</DateTimeFormatter>
<td style={{ padding: "2.5px" }}>
<DateTimeFormatter>
{j.scheduled_completion}
</DateTimeFormatter>
</td>
</tr>
))
) : (
<tr>
<td>{t("appointments.labels.nocompletingjobs")}</td>
<td style={{ padding: "2.5px" }}>
{t("appointments.labels.nocompletingjobs")}
</td>
</tr>
)}
</tbody>
@@ -92,26 +100,30 @@ export function ScheduleCalendarHeaderComponent({
{loadData && loadData.allJobsIn ? (
loadData.allJobsIn.map((j) => (
<tr key={j.id}>
<td>
<td style={{ padding: "2.5px" }}>
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
{j.status}
</td>
<td>
<td style={{ padding: "2.5px" }}>
<OwnerNameDisplay ownerObject={j} />
</td>
<td>
{`(${(j.labhrs.aggregate.sum.mod_lb_hrs + j.larhrs.aggregate.sum.mod_lb_hrs).toFixed(
1
)} ${t("general.labels.hours")})`}
<td style={{ padding: "2.5px" }}>
{`(${j.labhrs?.aggregate?.sum.mod_lb_hrs?.toFixed(1) || 0}/${
j.larhrs?.aggregate?.sum?.mod_lb_hrs?.toFixed(1) || 0
}/${(
j.labhrs?.aggregate?.sum?.mod_lb_hrs +
j.larhrs?.aggregate?.sum?.mod_lb_hrs
).toFixed(1)} ${t("general.labels.hours")})`}
</td>
<td>
<td style={{ padding: "2.5px" }}>
<DateTimeFormatter>{j.scheduled_in}</DateTimeFormatter>
</td>
</tr>
))
) : (
<tr>
<td>{t("appointments.labels.noarrivingjobs")}</td>
<td style={{ padding: "2.5px" }}>
{t("appointments.labels.noarrivingjobs")}
</td>
</tr>
)}
</tbody>
@@ -121,27 +133,33 @@ export function ScheduleCalendarHeaderComponent({
const LoadComponent = loadData ? (
<div>
<Space align="center">
<Popover
placement={"bottom"}
content={jobsInPopup}
trigger="hover"
title={t("appointments.labels.arrivingjobs")}
>
<Icon component={MdFileDownload} style={{ color: "green" }} />
{(loadData.allHoursIn || 0) && loadData.allHoursIn.toFixed(2)}
</Popover>
<Popover
placement={"bottom"}
content={jobsOutPopup}
trigger="hover"
title={t("appointments.labels.completingjobs")}
>
<Icon component={MdFileUpload} style={{ color: "red" }} />
{(loadData.allHoursOut || 0) && loadData.allHoursOut.toFixed(2)}
</Popover>
<ScheduleCalendarHeaderGraph loadData={loadData} />
</Space>
<Space align="center">
<Popover
placement={"bottom"}
content={jobsInPopup}
trigger="hover"
title={t("appointments.labels.arrivingjobs")}
>
<Icon component={MdFileDownload} style={{ color: "green" }} />
{(loadData.allHoursInBody || 0) &&
loadData.allHoursInBody.toFixed(1)}
/
{(loadData.allHoursInRefinish || 0) &&
loadData.allHoursInRefinish.toFixed(1)}
/{(loadData.allHoursIn || 0) && loadData.allHoursIn.toFixed(1)}
</Popover>
<Popover
placement={"bottom"}
content={jobsOutPopup}
trigger="hover"
title={t("appointments.labels.completingjobs")}
>
<Icon component={MdFileUpload} style={{ color: "red" }} />
{(loadData.allHoursOut || 0) && loadData.allHoursOut.toFixed(1)}
</Popover>
<ScheduleCalendarHeaderGraph loadData={loadData} />
</Space>
<div>
<ul style={{ listStyleType: "none", columns: "2 auto", padding: 0 }}>
{Object.keys(ATSToday).map((key, idx) => (

View File

@@ -1,25 +1,25 @@
import { useSplitTreatments } from '@splitsoftware/splitio-react';
import { Button, Card, Tabs } from 'antd';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { selectBodyshop } from '../../redux/user/user.selectors';
import ShopInfoGeneral from './shop-info.general.component';
import ShopInfoIntakeChecklistComponent from './shop-info.intake.component';
import ShopInfoLaborRates from './shop-info.laborrates.component';
import ShopInfoOrderStatusComponent from './shop-info.orderstatus.component';
import ShopInfoPartsScan from './shop-info.parts-scan';
import ShopInfoRbacComponent from './shop-info.rbac.component';
import ShopInfoResponsibilityCenterComponent from './shop-info.responsibilitycenters.component';
import ShopInfoROStatusComponent from './shop-info.rostatus.component';
import ShopInfoSchedulingComponent from './shop-info.scheduling.component';
import ShopInfoSpeedPrint from './shop-info.speedprint.component';
import { useLocation, useNavigate } from 'react-router-dom';
import ShopInfoTaskPresets from './shop-info.task-presets.component';
import queryString from 'query-string';
import InstanceRenderManager from '../../utils/instanceRenderMgr';
import ShopInfoRoGuard from './shop-info.roguard.component';
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { Button, Card, Tabs } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import ShopInfoGeneral from "./shop-info.general.component";
import ShopInfoIntakeChecklistComponent from "./shop-info.intake.component";
import ShopInfoLaborRates from "./shop-info.laborrates.component";
import ShopInfoOrderStatusComponent from "./shop-info.orderstatus.component";
import ShopInfoPartsScan from "./shop-info.parts-scan";
import ShopInfoRbacComponent from "./shop-info.rbac.component";
import ShopInfoResponsibilityCenterComponent from "./shop-info.responsibilitycenters.component";
import ShopInfoROStatusComponent from "./shop-info.rostatus.component";
import ShopInfoSchedulingComponent from "./shop-info.scheduling.component";
import ShopInfoSpeedPrint from "./shop-info.speedprint.component";
import { useLocation, useNavigate } from "react-router-dom";
import ShopInfoTaskPresets from "./shop-info.task-presets.component";
import queryString from "query-string";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import ShopInfoRoGuard from "./shop-info.roguard.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
@@ -47,44 +47,52 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
{
key: "general",
label: t("bodyshop.labels.shopinfo"),
children: <ShopInfoGeneral form={form} />
children: <ShopInfoGeneral form={form} />,
id: "tab-shop-general"
},
{
key: "speedprint",
label: t("bodyshop.labels.speedprint"),
children: <ShopInfoSpeedPrint form={form} />
children: <ShopInfoSpeedPrint form={form} />,
id: "tab-shop-speedprint"
},
{
key: "rbac",
label: t("bodyshop.labels.rbac"),
children: <ShopInfoRbacComponent form={form} />
children: <ShopInfoRbacComponent form={form} />,
id: "tab-shop-rbac"
},
{
key: "roStatus",
label: t("bodyshop.labels.jobstatuses"),
children: <ShopInfoROStatusComponent form={form} />
children: <ShopInfoROStatusComponent form={form} />,
id: "tab-shop-rostatus"
},
{
key: "scheduling",
label: t("bodyshop.labels.scheduling"),
children: <ShopInfoSchedulingComponent form={form} />
children: <ShopInfoSchedulingComponent form={form} />,
id: "tab-shop-scheduling"
},
{
key: "orderStatus",
label: t("bodyshop.labels.orderstatuses"),
children: <ShopInfoOrderStatusComponent form={form} />
children: <ShopInfoOrderStatusComponent form={form} />,
id: "tab-shop-orderstatus"
},
{
key: "responsibilityCenters",
label: t("bodyshop.labels.responsibilitycenters.title"),
children: <ShopInfoResponsibilityCenterComponent form={form} />
children: <ShopInfoResponsibilityCenterComponent form={form} />,
id: "tab-shop-responsibilitycenters"
},
...InstanceRenderManager({
imex: [
{
key: "checklists",
label: t("bodyshop.labels.checklists"),
children: <ShopInfoIntakeChecklistComponent form={form} />
children: <ShopInfoIntakeChecklistComponent form={form} />,
id: "tab-shop-checklists"
}
],
rome: "USE_IMEX",
@@ -93,14 +101,16 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
{
key: "laborrates",
label: t("bodyshop.labels.laborrates"),
children: <ShopInfoLaborRates form={form} />
children: <ShopInfoLaborRates form={form} />,
id: "tab-shop-laborrates"
},
...(CriticalPartsScanning.treatment === "on"
? [
{
key: "partsscan",
label: t("bodyshop.labels.partsscan"),
children: <ShopInfoPartsScan form={form} />
children: <ShopInfoPartsScan form={form} />,
id: "tab-shop-partsscan"
}
]
: []),
@@ -109,21 +119,23 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
{
key: "task-presets",
label: t("bodyshop.labels.task-presets"),
children: <ShopInfoTaskPresets form={form} />
children: <ShopInfoTaskPresets form={form} />,
id: "tab-shop-task-presets"
}
]
: []),
...InstanceRenderManager({
imex: [
{
key: 'roguard',
label: t('bodyshop.labels.roguard.title'),
children: <ShopInfoRoGuard form={form} />,
},
],
rome: 'USE_IMEX',
promanager: [],
}),
...InstanceRenderManager({
imex: [
{
key: "roguard",
label: t("bodyshop.labels.roguard.title"),
children: <ShopInfoRoGuard form={form} />,
id: "tab-shop-roguard"
}
],
rome: "USE_IMEX",
promanager: []
})
];
return (
<Card

View File

@@ -41,7 +41,7 @@ export const QUERY_AVAILABLE_CC = gql`
`;
export const CHECK_CC_FLEET_NUMBER = gql`
query CHECK_VENDOR_NAME($name: String!) {
query CHECK_CC_FLEET_NUMBER($name: String!) {
courtesycars_aggregate(where: { fleetnumber: { _ilike: $name } }) {
aggregate {
count

View File

@@ -219,6 +219,12 @@ export const UPDATE_JOB_LINE = gql`
id
notes
mod_lbr_ty
mod_lb_hrs
part_type
op_code_desc
prt_dsmk_m
prt_dsmk_p
tax_part
part_qty
db_price
act_price

View File

@@ -2238,6 +2238,8 @@ export const GET_JOB_LINE_ORDERS = gql`
parts_order_lines(where: { job_line_id: { _eq: $joblineid } }) {
id
act_price
backordered_eta
backordered_on
parts_order {
id
order_date

View File

@@ -216,7 +216,7 @@ export function BillsListPage({ loading, data, refetch, total, setPartsOrderCont
extra={
<Space wrap>
{search.search && (
<>
<Space align="center">
<Typography.Title level={4}>
{t("general.labels.searchresults", { search: search.search })}
</Typography.Title>
@@ -229,7 +229,7 @@ export function BillsListPage({ loading, data, refetch, total, setPartsOrderCont
>
{t("general.actions.clear")}
</Button>
</>
</Space>
)}
<Button onClick={() => refetch()}>
<SyncOutlined />

View File

@@ -72,7 +72,11 @@ export function CourtesyCarCreateContainer({ bodyshop, setBreadcrumbs, setSelect
<RbacWrapper action="courtesycar:create">
<FeatureWrapperComponent featureName="courtesycars">
<Form form={form} autoComplete="new-password" onFinish={handleFinish} layout="vertical">
<CourtesyCarFormComponent form={form} saveLoading={loading} />
<CourtesyCarFormComponent
form={form}
saveLoading={loading}
newCC={true}
/>
</Form>
</FeatureWrapperComponent>
</RbacWrapper>

View File

@@ -20,18 +20,21 @@ export default function JobsCreateComponent({ form }) {
const steps = [
{
title: t("jobs.labels.create.vehicleinfo"),
id: "step-job-vehicleinfo",
content: <JobsCreateVehicleInfoContainer form={form} />,
validation: !!state.vehicle.new || !!state.vehicle.selectedid || !!state.vehicle.none,
error: t("vehicles.errors.selectexistingornew")
},
{
title: t("jobs.labels.create.ownerinfo"),
id: "step-job-ownerinfo",
content: <JobsCreateOwnerInfoContainer />,
validation: !!state.owner.new || !!state.owner.selectedid,
error: t("owners.errors.selectexistingornew")
},
{
title: t("jobs.labels.create.jobinfo"),
id: "step-job-jobinfo",
content: <JobsCreateJobsInfo form={form} selected={pageIndex === 2} />
}
];

View File

@@ -111,7 +111,12 @@ export function* calculateScheduleLoad({ payload: end }) {
(load[itemDate].allHoursIn || 0) +
item.labhrs.aggregate.sum.mod_lb_hrs +
item.larhrs.aggregate.sum.mod_lb_hrs;
load[itemDate].allHoursInBody =
(load[itemDate].allHoursInBody || 0) +
item.labhrs.aggregate.sum.mod_lb_hrs;
load[itemDate].allHoursInRefinish =
(load[itemDate].allHoursInRefinish || 0) +
item.larhrs.aggregate.sum.mod_lb_hrs;
//If the job hasn't already arrived, add it to the jobs in list.
// Make sure it also hasn't already been completed, or isn't an in and out job.
//This prevents the duplicate counting.
@@ -119,7 +124,15 @@ export function* calculateScheduleLoad({ payload: end }) {
if (AddJobForSchedulingCalc) {
load[itemDate].jobsIn.push(item);
load[itemDate].hoursIn =
(load[itemDate].hoursIn || 0) + item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs;
(load[itemDate].hoursIn || 0) +
item.labhrs.aggregate.sum.mod_lb_hrs +
item.larhrs.aggregate.sum.mod_lb_hrs;
load[itemDate].hoursInBody =
(load[itemDate].hoursInBody || 0) +
item.labhrs.aggregate.sum.mod_lb_hrs;
load[itemDate].hoursInRefinish =
(load[itemDate].hoursInRefinish || 0) +
item.larhrs.aggregate.sum.mod_lb_hrs;
}
} else {
load[itemDate] = {
@@ -127,10 +140,21 @@ export function* calculateScheduleLoad({ payload: end }) {
jobsIn: AddJobForSchedulingCalc ? [item] : [], //Same as above, only add it if it isn't already in production.
jobsOut: [],
allJobsOut: [],
allHoursIn: item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs,
allHoursIn:
item.labhrs.aggregate.sum.mod_lb_hrs +
item.larhrs.aggregate.sum.mod_lb_hrs,
allHoursInBody: item.labhrs.aggregate.sum.mod_lb_hrs,
allHoursInRefinish: item.larhrs.aggregate.sum.mod_lb_hrs,
hoursIn: AddJobForSchedulingCalc
? item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs
: 0
? item.labhrs.aggregate.sum.mod_lb_hrs +
item.larhrs.aggregate.sum.mod_lb_hrs
: 0,
hoursInBody: AddJobForSchedulingCalc
? item.labhrs.aggregate.sum.mod_lb_hrs
: 0,
hoursInRefinish: AddJobForSchedulingCalc
? item.larhrs.aggregate.sum.mod_lb_hrs
: 0,
};
}
});
@@ -151,6 +175,12 @@ export function* calculateScheduleLoad({ payload: end }) {
(load[itemDate].allHoursOut || 0) +
item.labhrs.aggregate.sum.mod_lb_hrs +
item.larhrs.aggregate.sum.mod_lb_hrs;
load[itemDate].allHoursOutBody =
(load[itemDate].allHoursOutBody || 0) +
item.labhrs.aggregate.sum.mod_lb_hrs;
load[itemDate].allHoursOutRefinish =
(load[itemDate].allHoursOutRefinish || 0) +
item.larhrs.aggregate.sum.mod_lb_hrs;
//Add only the jobs that are still in production to get rid of.
//If it's not in production, we'd subtract unnecessarily.
load[itemDate].allJobsOut.push(item);
@@ -161,6 +191,12 @@ export function* calculateScheduleLoad({ payload: end }) {
(load[itemDate].hoursOut || 0) +
item.labhrs.aggregate.sum.mod_lb_hrs +
item.larhrs.aggregate.sum.mod_lb_hrs;
load[itemDate].hoursOutBody =
(load[itemDate].hoursOutBody || 0) +
item.labhrs.aggregate.sum.mod_lb_hrs;
load[itemDate].hoursOutRefinish =
(load[itemDate].hoursOutRefinish || 0) +
item.larhrs.aggregate.sum.mod_lb_hrs;
}
} else {
load[itemDate] = {
@@ -169,7 +205,11 @@ export function* calculateScheduleLoad({ payload: end }) {
hoursOut: AddJobForSchedulingCalc
? item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs
: 0,
allHoursOut: item.labhrs.aggregate.sum.mod_lb_hrs + item.larhrs.aggregate.sum.mod_lb_hrs
allHoursOut:
item.labhrs.aggregate.sum.mod_lb_hrs +
item.larhrs.aggregate.sum.mod_lb_hrs,
allHoursOutBody: item.labhrs.aggregate.sum.mod_lb_hrs,
allHoursOutRefinish: item.larhrs.aggregate.sum.mod_lb_hrs,
};
}
});

View File

@@ -224,8 +224,9 @@
"markexported": "Mark Exported",
"markforreexport": "Mark for Re-export",
"new": "New Bill",
"nobilllines": "This part has not yet been recieved.",
"noneselected": "No bill selected.",
"onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.",
"onlycmforinvoiced": "Only credit memos can be entered for any Job that has been invoiced, exported, or voided.",
"printlabels": "Print Labels",
"retailtotal": "Bills Retail Total",
"savewithdiscrepancy": "You are about to save this bill with a discrepancy. The system will continue to use the calculated amount using the bill lines. Press cancel to return to the bill.",
@@ -2506,6 +2507,7 @@
"markexported": "Payment(s) marked exported.",
"markreexported": "Payment marked for re-export successfully",
"payment": "Payment created successfully. ",
"paymentupdate": "Payment updated successfully. ",
"stripe": "Credit card transaction charged successfully."
}
},

View File

@@ -2506,6 +2506,7 @@
"markexported": "",
"markreexported": "",
"payment": "",
"paymentupdate": "",
"stripe": ""
}
},

View File

@@ -2506,6 +2506,7 @@
"markexported": "",
"markreexported": "",
"payment": "",
"paymentupdate": "",
"stripe": ""
}
},

View File

@@ -5,6 +5,8 @@ import * as path from "path";
import * as url from "url";
import { defineConfig } from "vite";
import { ViteEjsPlugin } from "vite-plugin-ejs";
import eslint from 'vite-plugin-eslint';
//import CompressionPlugin from 'vite-plugin-compression';
import { VitePWA } from "vite-plugin-pwa";
import InstanceRenderManager from "./src/utils/instanceRenderMgr";
@@ -100,7 +102,8 @@ export default defineConfig({
}
}),
reactVirtualized(),
react()
react(),
eslint(),
// CompressionPlugin(), //Cloudfront already compresses assets, so not needed.
],
define: {

View File

@@ -1 +1,8 @@
[ ]
- name: Task Reminders
webhook: '{{HASURA_API_URL}}/tasks-remind-handler'
schedule: '*/15 * * * *'
include_in_metadata: true
payload: {}
headers:
- name: event-secret
value_from_env: EVENT_SECRET

View File

@@ -969,6 +969,7 @@
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_guard
- md_ro_statuses
- md_tasks_presets
- md_to_emails
@@ -1068,6 +1069,7 @@
- md_rbac
- md_referral_sources
- md_responsibility_centers
- md_ro_guard
- md_ro_statuses
- md_tasks_presets
- md_to_emails
@@ -5795,6 +5797,29 @@
- active:
_eq: true
check: null
event_triggers:
- name: tasks_assigned_changed
definition:
enable_manual: false
insert:
columns: '*'
update:
columns:
- assigned_to
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}}/tasks-assigned-handler'
version: 2
- table:
name: timetickets
schema: public

View File

@@ -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 "md_ro_guard" jsonb
-- null default jsonb_build_object();

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "md_ro_guard" jsonb
null default jsonb_build_object();

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."tasks" add column "remind_at_sent" timestamptz
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."tasks" add column "remind_at_sent" timestamptz
null;

View File

@@ -770,7 +770,7 @@ const getAdditionalCostCenter = (jl, profitCenters) => {
return profitCenters["TOW"];
} else if (jl.act_price > 0) {
//TODO:AIO Ensure that this is tested.
ret.profitcenter_part = defaults.profits["PAO"];
return profitCenters["PAO"];
} else {
return null;
}

View File

@@ -925,7 +925,7 @@ function CalculateTaxesTotals(job, otherTotals) {
thresholdAmount === 9999.99 ||
InstanceMgr({
imex: false,
rome: false,
rome: thresholdAmount === 0 && parseInt(tyCounter) === 1,
promanager: thresholdAmount === 0 && parseInt(tyCounter) === 1
})
) {