Compare commits

...

482 Commits

Author SHA1 Message Date
Patrick Fic
5db43dd065 IO-70 Add basic functions of OEC. 2021-11-29 15:04:34 -08:00
Patrick Fic
53be0bbc1a IO-70 OEC WIP. 2021-11-29 08:57:44 -08:00
Patrick Fic
bfcc03850b IO-70 Add OEC Through Partner Call. 2021-11-23 00:30:11 -08:00
Patrick Fic
65402c1420 Clean up console log statements. 2021-11-22 23:20:13 -08:00
Patrick Fic
b462b2fa03 IO-1485 Auto CC on parts order. 2021-11-22 15:39:12 -08:00
Patrick Fic
0c26b90591 IO-1533 Resolve board rerender. 2021-11-21 21:59:33 -08:00
Patrick Fic
f8f2384c54 Merged in release/2021-11-19 (pull request #272)
release/2021-11-19

Approved-by: Patrick Fic
2021-11-19 20:08:53 +00:00
Patrick Fic
ef18cf0718 IO-233 CDK Updates. 2021-11-19 10:50:38 -08:00
Patrick Fic
9d35fc85ad Merged in release/2021-11-19 (pull request #271)
release/2021-11-19

Approved-by: Patrick Fic
2021-11-18 18:39:14 +00:00
Patrick Fic
e98f9763fd Resolve QB Payments Refund Issue. 2021-11-18 10:38:04 -08:00
Patrick Fic
95e5385cd1 Merged in release/2021-11-19 (pull request #270)
release/2021-11-19

Approved-by: Patrick Fic
2021-11-18 17:19:57 +00:00
Patrick Fic
46abf01366 IO-1533 Resolve defaults check issue for production board. 2021-11-18 09:19:34 -08:00
Patrick Fic
87f06425e1 Merged in release/2021-11-19 (pull request #269)
release/2021-11-19

Approved-by: Patrick Fic
2021-11-18 06:19:53 +00:00
Patrick Fic
45ab7543d5 Resolve CI Issues. 2021-11-17 22:18:09 -08:00
Patrick Fic
120e4fc94c Merged in release/2021-11-19 (pull request #268)
release/2021-11-19

Approved-by: Patrick Fic
2021-11-18 06:17:09 +00:00
Patrick Fic
fed16efd10 IO-1533 Added check for null settings on kanban. 2021-11-17 22:16:43 -08:00
Patrick Fic
ea6277c586 Merged in release/2021-11-19 (pull request #267)
release/2021-11-19

Approved-by: Patrick Fic
2021-11-18 06:08:21 +00:00
Patrick Fic
49bf461c36 IO-1533 Kanban Customizations 2021-11-17 22:07:50 -08:00
Patrick Fic
696781c857 IO-1533 Kanban Customizations 2021-11-17 21:47:05 -08:00
Patrick Fic
5540872f62 IO-1531 CC Contract add to production. 2021-11-17 20:18:21 -08:00
Patrick Fic
dac53a56c3 Merged in release/2021-11-19 (pull request #266)
release/2021-11-19

Approved-by: Patrick Fic
2021-11-18 01:30:23 +00:00
Patrick Fic
69690f0184 IO-1533 Kanban Customizations 2021-11-17 15:29:04 -08:00
Patrick Fic
f11a4c93ac IO-233 CDK Updates 2021-11-17 14:44:07 -08:00
Patrick Fic
d74870812e Merged in release/2021-11-19 (pull request #265)
release/2021-11-19

Approved-by: Patrick Fic
2021-11-16 01:17:31 +00:00
Patrick Fic
9eed33b5f2 Resolve CI issues with missing imports. 2021-11-15 17:15:51 -08:00
Patrick Fic
55b7715e1c IO-1529 Added gateway templates. 2021-11-15 17:14:12 -08:00
Patrick Fic
c129b5ba8c IO-1533 Kanban Customization 2021-11-15 13:53:54 -08:00
Patrick Fic
efc2844d99 IO-1530 Email individual note. 2021-11-15 11:06:10 -08:00
Patrick Fic
ab38f85d38 Package updates. 2021-11-15 10:36:41 -08:00
Patrick Fic
81eccba393 Merged in release/2021-11-12 (pull request #263)
release/2021-11-12

Approved-by: Patrick Fic
2021-11-12 21:46:33 +00:00
Patrick Fic
b3b49fd4ca Email test fix & Shop Config validation for resp centers. 2021-11-12 13:46:01 -08:00
Patrick Fic
b7a08db4e7 Merged in release/2021-11-12 (pull request #262)
IO-117 PBS WIP

Approved-by: Patrick Fic
2021-11-11 02:13:28 +00:00
Patrick Fic
2d63c3d576 IO-1528 Autohouse Updates. 2021-11-10 18:06:24 -08:00
Patrick Fic
5f4a2392af Costmetic updates & limit of conversations in subscription. 2021-11-10 17:09:09 -08:00
Patrick Fic
f6fe8be7c4 IO-1491 Simplify production query to use ignore employee relationships and match locally. 2021-11-10 16:54:02 -08:00
Patrick Fic
89af6d23e8 IO-1513 Added next contact date. 2021-11-10 16:22:52 -08:00
Patrick Fic
7e1431d65e IO-117 WIP PBS 2021-11-10 15:30:07 -08:00
Patrick Fic
d50e845ba0 IO-117 PBS WIP 2021-11-10 08:18:29 -08:00
Patrick Fic
6796c35e5b Merged in release/2021-11-12 (pull request #260)
release/2021-11-12

Approved-by: Patrick Fic
2021-11-10 01:06:57 +00:00
Patrick Fic
4a68a10005 IO-1486 Add dropdown for file handler. 2021-11-09 17:05:20 -08:00
Patrick Fic
17088b3025 IO-1188 Add AB proof of loss. 2021-11-09 16:33:20 -08:00
Patrick Fic
4e3c659b6d IO-1497 Ability to delete parts orders. 2021-11-09 16:31:57 -08:00
Patrick Fic
6afcf82cc4 IO-1505 Resolve PST exempt exporting to QBO. 2021-11-09 16:04:16 -08:00
Patrick Fic
f4ddb40bde IO-117 PBS WIP 2021-11-09 13:56:52 -08:00
Patrick Fic
6017e2172e IO-117 PBS WIP 2021-11-09 10:38:07 -08:00
Patrick Fic
bef9e64bf8 Resolve associations permissions to allow adjustments of RBAC. 2021-11-08 11:23:37 -08:00
Patrick Fic
e8d95bdb68 IO-1508 Add # of jobs in production. 2021-11-08 11:12:56 -08:00
Patrick Fic
10fb7d9d96 IO-1499 Reconciliation to consider quantity. 2021-11-08 10:50:21 -08:00
Patrick Fic
2ec196e664 IO-1510 Missing report templates 2021-11-08 10:29:16 -08:00
Patrick Fic
1f38b98bfd Package Updates 2021-11-08 10:27:38 -08:00
Patrick Fic
a7c76386bc Merged in release/2021-11-01 (pull request #258)
release/2021-11-01

Approved-by: Patrick Fic
2021-11-01 16:00:52 +00:00
Patrick Fic
042b67c531 IO-1438 Resolve issue with texting 2021-11-01 08:57:30 -07:00
Patrick Fic
2e72ed3698 IO-1438 Resolve Texting Issue 2021-11-01 08:40:53 -07:00
Patrick Fic
bc01f46388 Merge branch 'release/2021-10-29' into test 2021-10-29 13:48:27 -07:00
Patrick Fic
74f791541f IO-256 Resolve no invoice on CM QBO export. 2021-10-29 13:48:17 -07:00
Patrick Fic
84c7fdba5a Merge branch 'release/2021-10-29' into test 2021-10-29 11:30:53 -07:00
Patrick Fic
630fa23f6c Resolve uneeded import CI error. 2021-10-29 11:30:43 -07:00
Patrick Fic
8f58f09c8c Merge branch 'release/2021-10-29' into test 2021-10-29 11:19:36 -07:00
Patrick Fic
a0922f2944 IO-1476 Add Hrs to schedule modal. 2021-10-29 11:18:17 -07:00
Patrick Fic
b8f001625b IO-1502 PST on Adjustments for QBO 2021-10-29 10:55:35 -07:00
Patrick Fic
53394efebf IO-1503 QBO Credit Memos 2021-10-28 09:56:59 -07:00
Patrick Fic
d8296e1d01 Merge branch 'release/2021-10-29' into test 2021-10-27 11:37:04 -07:00
Patrick Fic
2c00e5ee79 IO-256 Resolve QBO Aposstroph Issues 2021-10-27 11:36:40 -07:00
Patrick Fic
34e220dcad IO-233 Update Regex for CDK. 2021-10-27 10:46:06 -07:00
Patrick Fic
fa1fffd8b9 Merge branch 'release/2021-10-29' into test 2021-10-27 08:39:20 -07:00
Patrick Fic
67eb430ff9 Add missing query field to CDK. 2021-10-27 08:39:05 -07:00
Patrick Fic
ff53355b4a Merge branch 'release/2021-10-29' into test 2021-10-27 08:30:03 -07:00
Patrick Fic
331b2c517b Update CDK Country Inclusion. 2021-10-27 08:29:43 -07:00
Patrick Fic
05d9f20a66 Mark Other RO field as Read Only 2021-10-26 15:38:05 -07:00
Patrick Fic
9e3a2e920d Merge branch 'release/2021-10-29' into test 2021-10-26 13:10:37 -07:00
Patrick Fic
1511b87959 IO-1487 MPI Totals Adjustments 2021-10-26 13:10:07 -07:00
Patrick Fic
9c3e4b7b83 IO-1489 Resolve payables memo for QBO. 2021-10-25 17:25:29 -07:00
Patrick Fic
b718f49071 IO-256 Resolve QBO Payable Vendor Insert. 2021-10-25 17:05:21 -07:00
Patrick Fic
e7157119ae Merged in release/2021-10-29 (pull request #256)
Release/2021 10 29
2021-10-25 21:58:53 +00:00
Patrick Fic
09187bdb7f Remove manual scheduling for CI. 2021-10-25 14:57:27 -07:00
Patrick Fic
2aed392fbe IO-658 IO-652 IO-657 add MPI Templates. 2021-10-25 14:46:24 -07:00
Patrick Fic
1a0054a911 IO-1438 Resolve inbound conversation creation. 2021-10-25 11:00:31 -07:00
Patrick Fic
6e6f3d3d3e Resolve user email naming if null. 2021-10-25 10:46:30 -07:00
Patrick Fic
29df140680 IO-1402 Respect blocked day today for scheduling. 2021-10-25 10:41:22 -07:00
Patrick Fic
f37c67a122 Merge branch 'master' into release/2021-10-29 2021-10-25 10:31:49 -07:00
Patrick Fic
e53c9aab72 IO-1379 CSI invite Key update. 2021-10-25 10:24:18 -07:00
Patrick Fic
385ad06adc IO-1375 Special characters in CDK 2021-10-25 10:12:43 -07:00
Patrick Fic
d1e2d943a9 Package updates. 2021-10-25 09:41:54 -07:00
Patrick Fic
90aa3557b7 Merged in release/2021-10-22 (pull request #255)
Change Nod Version.

Approved-by: Patrick Fic
2021-10-22 21:38:53 +00:00
Patrick Fic
8891167183 Merged in release/2021-10-22 (pull request #254)
release/2021-10-22

Approved-by: Patrick Fic
2021-10-22 21:38:35 +00:00
Patrick Fic
6631e645df Change Nod Version. 2021-10-22 14:38:05 -07:00
Patrick Fic
b7f202969b Merged in release/2021-10-22 (pull request #253)
release/2021-10-22

Approved-by: Patrick Fic
2021-10-22 21:29:49 +00:00
Patrick Fic
1dc3353ecc Merge branch 'release/2021-10-22' into test 2021-10-22 13:01:41 -07:00
Patrick Fic
b1a3f1a7b8 Finish revert stripe removal. 2021-10-22 13:01:26 -07:00
Patrick Fic
89f3a26635 Revert "Disable stripe promise."
This reverts commit 3ece5e0ba2.
2021-10-22 12:59:45 -07:00
Patrick Fic
506fe9b1af Merge branch 'release/2021-10-22' into test 2021-10-22 10:47:12 -07:00
Patrick Fic
37c898d3ce IO-256 Resolve QBO issues. 2021-10-22 10:46:03 -07:00
Patrick Fic
e4eac5714a Merge branch 'release/2021-10-22' into test 2021-10-22 10:00:42 -07:00
Patrick Fic
9d4a59ca16 IO-256 Remove credentials with Axios calls for QBO. 2021-10-22 10:00:23 -07:00
Patrick Fic
8ec524061a Merge branch 'release/2021-10-22' into test 2021-10-21 14:32:06 -07:00
Patrick Fic
434ed46b5a IO-1469 Add keep schedule details to job detail reschedule. 2021-10-21 14:30:50 -07:00
Patrick Fic
3ece5e0ba2 Disable stripe promise. 2021-10-21 14:16:18 -07:00
Patrick Fic
52a383ffb7 IO-1454 Disable production colors & add feature flags. 2021-10-21 14:03:48 -07:00
Patrick Fic
8ad1d5929a Reduce Sentry Logging. 2021-10-21 12:02:02 -07:00
Patrick Fic
445c01499b Merge branch 'release/2021-10-22' into test 2021-10-21 11:42:33 -07:00
Patrick Fic
0b05be841d Merge branch 'release/2021-10-22' of bitbucket.org:snaptsoft/bodyshop into release/2021-10-22 2021-10-21 11:42:10 -07:00
Patrick Fic
6bcb5f2af5 IO-1446 Smart Schedule Blocked Day Fixes 2021-10-21 11:42:05 -07:00
Patrick Fic
7482751c5b IO-1478 Make CC Contract RO lines editable. 2021-10-21 09:43:14 -07:00
Patrick Fic
7a025fff42 Merge branch 'release/2021-10-22' into test 2021-10-21 08:59:49 -07:00
Patrick Fic
602fe36638 QBO Cleanup. 2021-10-21 08:58:24 -07:00
Patrick Fic
da08fc74f1 IO-1475 Totals update for Mitchell Cloud discounts. 2021-10-21 08:53:15 -07:00
Patrick Fic
14af45baf0 IO-256 QBO SS Realm ID 2021-10-20 14:33:31 -07:00
Patrick Fic
420a88c505 Merged in release/2021-10-22 (pull request #252)
release/2021-10-22

Approved-by: Patrick Fic
2021-10-19 05:12:44 +00:00
Patrick Fic
f3c44f8dd1 Merge branch 'feature/pbs' into release/2021-10-22 2021-10-18 22:12:16 -07:00
Patrick Fic
c72111e18b Merged in release/2021-10-22 (pull request #251)
release/2021-10-22

Approved-by: Patrick Fic
2021-10-19 05:04:35 +00:00
Patrick Fic
1ca2870912 IO-1437 Add deductible Note 2021-10-18 22:02:45 -07:00
Patrick Fic
db9744e1e5 IO-1454 Production List Visual Indicators. 2021-10-18 21:54:24 -07:00
Patrick Fic
e700095551 IO-1492 Add estimator Presets 2021-10-18 20:26:57 -07:00
Patrick Fic
99196a77ed IO-1433 Add Loss of Use Field 2021-10-18 19:56:12 -07:00
Patrick Fic
289a8222a0 IO-223 ARM development 2021-10-18 19:37:27 -07:00
Patrick Fic
dc10f8d35b IO-1469 Retain event detals when rescheduling. 2021-10-18 13:56:48 -07:00
Patrick Fic
f448232fe7 IO-1435 Missed additional query. 2021-10-18 13:52:30 -07:00
Patrick Fic
4baf4b4afa IO-1435 Add scheduled time to job header if scheduled. 2021-10-18 13:48:23 -07:00
Patrick Fic
1785093023 IO-1449 Adjust display of time in schedulign setup. 2021-10-18 13:43:15 -07:00
Patrick Fic
0d65f8d894 IO-1407 Resolve bill not clearing on enter again 2021-10-18 13:40:31 -07:00
Patrick Fic
3d8c390291 IO-1408 Resolve bill form index issue. 2021-10-18 13:29:35 -07:00
Patrick Fic
f0a13856bc IO-1439 Trim QB name fields on export. 2021-10-18 12:16:12 -07:00
Patrick Fic
ad6394783d IO-1443 Expand Priority selection to 15. 2021-10-18 11:22:01 -07:00
Patrick Fic
16e9843298 Package Updates. 2021-10-18 11:21:51 -07:00
Patrick Fic
a4c949c376 Merged in release/2021-10-22 (pull request #250)
Release/2021 10 22
2021-10-18 17:01:18 +00:00
Patrick Fic
0e0d5316b7 Undo Quickbooks CORS to resolve prod error. 2021-10-18 07:55:36 -07:00
Patrick Fic
60cb6ee8fb IO-223 Begin ARMS Integration 2021-10-15 17:55:55 -07:00
Patrick Fic
7d3279d21a Merged in release/2021-10-15 (pull request #249)
Release/2021 10 15
2021-10-15 21:33:24 +00:00
Patrick Fic
402d13ad99 Merge branch 'test' into release/2021-10-15 2021-10-15 10:53:50 -07:00
Patrick Fic
e803f5a2d4 IO-1471 Total Hrs in produciton. 2021-10-15 10:53:24 -07:00
Patrick Fic
3989d0f1e2 Merge branch 'test' into feature/pbs 2021-10-14 17:20:15 -07:00
Patrick Fic
161d476ab3 IO-256 Export payments with no matching invoice & export cust data. 2021-10-14 15:07:31 -07:00
Patrick Fic
ce84a89cf3 Merge branch 'release/2021-10-15' into test 2021-10-14 11:22:14 -07:00
Patrick Fic
1d210a9e52 IO-1468 QB and CDK Updates for MCE Markup 2021-10-14 11:21:06 -07:00
Patrick Fic
660f463aea IO-1468 Resolve line markup for MCE. 2021-10-14 10:52:08 -07:00
Patrick Fic
ad9f01111c Merge branch 'release/2021-10-15' into test 2021-10-13 21:22:55 -07:00
Patrick Fic
1b885e4114 IO-256 Add description to receivables export. 2021-10-13 21:22:38 -07:00
Patrick Fic
b56742bcb2 IO-256 QBO Improvements. 2021-10-13 21:12:02 -07:00
Patrick Fic
40d4d69a9a Merge branch 'release/2021-10-15' into test 2021-10-13 17:03:00 -07:00
Patrick Fic
b54d5beb76 IO-256 Resolve Bill Center reference 2021-10-13 17:02:39 -07:00
Patrick Fic
5cbcd440f5 Merge branch 'feature/qbo' into test 2021-10-13 15:49:02 -07:00
Patrick Fic
1cdc34249a IO-256 Fix null handling for missing metadata. 2021-10-13 15:48:43 -07:00
Patrick Fic
8bbb218777 Merge branch 'feature/qbo' into test
# Conflicts:
#	server/accounting/qbo/qbo-payables.js
#	server/accounting/qbo/qbo-payments.js
#	server/accounting/qbo/qbo-receivables.js
2021-10-13 15:25:02 -07:00
Patrick Fic
755ac7f657 IO-256 Improved Logging 2021-10-13 15:24:14 -07:00
Patrick Fic
d7b884ff86 Revert "IO-256 Genericize email."
This reverts commit fda3620ed0.
2021-10-13 15:14:26 -07:00
Patrick Fic
fda3620ed0 IO-256 Genericize email. 2021-10-13 15:10:36 -07:00
Patrick Fic
61ad9f0d58 IO-256 Add CORS back for QBO. 2021-10-13 15:01:59 -07:00
Patrick Fic
804c8ad40a IO-256 Add cookie location 2021-10-13 14:49:47 -07:00
Patrick Fic
0ddf009f8f Reverse CORS & Fix Cookie Setting. 2021-10-13 14:35:39 -07:00
Patrick Fic
14309b5c96 QBO CORS Updates 2021-10-13 14:06:25 -07:00
Patrick Fic
57d9de469a Add CORS to Server. 2021-10-13 14:01:59 -07:00
Patrick Fic
404ade396c QB URL Updates. 2021-10-13 13:39:04 -07:00
Patrick Fic
bdad6da6d9 QB URL Fix. 2021-10-13 13:35:42 -07:00
Patrick Fic
e7ef3b94c1 QB Env update. 2021-10-13 13:34:56 -07:00
Patrick Fic
c19c92ab7e QBO port fix. 2021-10-13 13:25:15 -07:00
Patrick Fic
944229bae3 Update process env. 2021-10-13 13:22:56 -07:00
Patrick Fic
661b05d9e3 Merge branch 'feature/qbo' into test 2021-10-13 13:15:48 -07:00
Patrick Fic
4d1d471a66 Merge branch 'release/2021-10-15' into test 2021-10-13 13:15:35 -07:00
Patrick Fic
3e84fbbaf4 IO-1458 IO-1465 Sorting Fixes. 2021-10-13 11:52:11 -07:00
Patrick Fic
c4e59c1a5e IO-117 Begin PBS Structure. 2021-10-13 11:45:24 -07:00
Patrick Fic
9ee8e9007a IO-256 Add Payables Posting. 2021-10-12 20:18:06 -07:00
Patrick Fic
4d52a5c44a IO-256 Exporting of payments 2021-10-12 19:07:43 -07:00
Patrick Fic
fff9073f9d IO-256 Add vendor credits. 2021-10-12 16:54:28 -07:00
Patrick Fic
71f0b8a005 Merge branch 'release/2021-10-15' into test 2021-10-12 16:41:01 -07:00
Patrick Fic
d2b965f79e Resolve CI Issue. 2021-10-12 16:40:27 -07:00
Patrick Fic
a02aa71a95 Merged in release/2021-10-15 (pull request #248)
release/2021-10-15

Approved-by: Patrick Fic
2021-10-12 23:33:17 +00:00
Patrick Fic
7562bf5c95 IO-1418 Allow owner re-search on import. 2021-10-12 16:17:31 -07:00
Patrick Fic
f9521483e2 IO-1448 Disable negative deductible amounts. 2021-10-12 14:39:20 -07:00
Patrick Fic
ca85858885 IO-1453 Allow null scheduled completion dates on cehcklist view. 2021-10-12 14:27:22 -07:00
Patrick Fic
c7b3a94533 IO-1441 Conversion safety check. 2021-10-12 14:18:09 -07:00
Patrick Fic
b010c9ecb0 IO-1458 Production Board Sort ORder 2021-10-12 13:50:25 -07:00
Patrick Fic
0b98d04bac IO-1458 Production Board Sort Order 2021-10-12 13:49:32 -07:00
Patrick Fic
e25e388e59 Merged in release/2021-10-15 (pull request #247)
IO-233 Replace unknown CDK function.

Approved-by: Patrick Fic
2021-10-12 19:06:35 +00:00
Patrick Fic
10654b7916 IO-233 Replace unknown CDK function. 2021-10-12 12:04:50 -07:00
Patrick Fic
ff049ad3e8 Merged in release/2021-10-08 (pull request #246)
release/2021-10-08
2021-10-09 15:29:49 +00:00
Patrick Fic
3572fff2c1 Merged in release/2021-10-08 (pull request #245)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-07 23:38:03 +00:00
Patrick Fic
774e4cdf94 IO-1430 Add note on last contacted update. 2021-10-07 16:26:48 -07:00
Patrick Fic
65ade5cab8 IO-1428 add ph2 to global search. 2021-10-07 16:00:35 -07:00
Patrick Fic
bf21a073fb IO-1415 Update cache on line delete. 2021-10-07 15:48:29 -07:00
Patrick Fic
851f1c265f Merged in release/2021-10-08 (pull request #244)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-07 16:51:36 +00:00
Patrick Fic
51f3b5927b IO-1428 IO-1338 Add ownr_ph2. 2021-10-07 09:47:10 -07:00
Patrick Fic
42c779f368 IO-1415 Default tax part to true. 2021-10-07 09:19:37 -07:00
Patrick Fic
c104ee4fd9 Merged in release/2021-10-08 (pull request #243)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-06 20:37:34 +00:00
Patrick Fic
0b2efa31b5 IO-1375 IO-1383 CDK Tax Addition 2021-10-06 13:37:14 -07:00
Patrick Fic
17baa8fcb2 IO-1404 Rates in shop info minimums 2021-10-05 16:36:53 -07:00
Patrick Fic
e550baf59d Merged in release/2021-10-08 (pull request #242)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-05 23:20:08 +00:00
Patrick Fic
fd53eb92e6 Merge branch 'test' into release/2021-10-08 2021-10-05 16:19:41 -07:00
Patrick Fic
6521c0bfb8 IO-1413 Change color of kanban background 2021-10-05 14:22:45 -07:00
Patrick Fic
50489dd682 IO-1415 Add tax part & refresh line ticket on line edit 2021-10-05 14:15:21 -07:00
Patrick Fic
220afa5add IO-1405 resolve shift label issues. 2021-10-05 14:05:16 -07:00
Patrick Fic
9d549b02fe IO-1410 Remove ded from lbr lines on reconciliation. 2021-10-05 13:59:43 -07:00
Patrick Fic
ca2ded047b Merged in release/2021-10-08 (pull request #241)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-05 18:48:13 +00:00
Patrick Fic
c423e61ce8 IO-1422 Resolve send email with attachments. 2021-10-05 11:47:37 -07:00
Patrick Fic
65550c7bf4 IO-1436 App tax part fix to all regions. 2021-10-05 11:36:21 -07:00
Patrick Fic
cdb4da9e5f IO-1412 Resolve production list saving and loading. 2021-10-05 09:40:25 -07:00
Patrick Fic
b59a5303c6 IO-1430 add Last Contacted date to job. 2021-10-05 09:12:44 -07:00
Patrick Fic
9a72abbed0 IO-1426 Add time to date detail card. 2021-10-05 08:53:20 -07:00
Patrick Fic
762a5ff01b IO-1432 Add offset for speed print. 2021-10-05 08:49:38 -07:00
Patrick Fic
2f6571e703 Package updates. 2021-10-05 07:59:51 -07:00
Patrick Fic
80c90f1819 IO-1399 Parts Order Modal Updates 2021-10-04 16:13:33 -07:00
Patrick Fic
4b0c2c60a2 IO-1398 Parts Order Mark Duplication 2021-10-04 16:00:05 -07:00
Patrick Fic
ee7d7d2f6a IO-1397 Preview cards consistency updates. 2021-10-04 15:55:43 -07:00
Patrick Fic
0ad670013b IO-1395 Add missing info to job preview. 2021-10-04 15:48:28 -07:00
Patrick Fic
064a66aa66 IO-1329 Filtering on bill line posting 2021-10-04 14:37:37 -07:00
Patrick Fic
f46c19b152 Merged in release/2021-10-08 (pull request #239)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-04 20:35:21 +00:00
Patrick Fic
ea2c583b26 IO-1419 Resolve hsaura migration issues with new field. 2021-10-04 13:20:35 -07:00
Patrick Fic
7bd2a90141 Merged in release/2021-10-08 (pull request #238)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-04 19:11:34 +00:00
Patrick Fic
632549dd9d IO-1406 Parts Order label update 2021-10-04 12:08:47 -07:00
Patrick Fic
70ef274821 IO-1404 IO-1403 Remove negative value options for 2021-10-04 12:08:29 -07:00
Patrick Fic
7d9759fda4 IO-1419 Added comments to parts orders. 2021-10-04 11:59:33 -07:00
Patrick Fic
0fd06d5e4e IO-1421 Add day of week to smart scheduling buttons. 2021-10-04 11:48:55 -07:00
Patrick Fic
4995e44e06 IO-1424 Add other referral source 2021-10-04 11:43:33 -07:00
Patrick Fic
fd43d7d56d Merged in release/2021-10-08 (pull request #237)
JSR CHange

Approved-by: Patrick Fic
2021-10-04 14:57:42 +00:00
Patrick Fic
96f292f61c JSR CHange 2021-10-04 07:57:14 -07:00
Patrick Fic
e899e4545f Merged in release/2021-10-08 (pull request #236)
Release/2021 10 08
2021-10-02 06:19:45 +00:00
Patrick Fic
c62f5e3911 Merged in release/2021-10-08 (pull request #235)
Resolve CI.

Approved-by: Patrick Fic
2021-10-01 22:56:48 +00:00
Patrick Fic
9f1d184081 Resolve CI. 2021-10-01 15:56:24 -07:00
Patrick Fic
29e596eedb Merged in release/2021-10-08 (pull request #234)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-01 22:41:36 +00:00
Patrick Fic
6e28afda67 IO-1417 Resolve custom templates printing. 2021-10-01 15:41:17 -07:00
Patrick Fic
eca7e9fba1 Merged in release/2021-10-08 (pull request #233)
IO-1392 Add IOU Form to Print Center

Approved-by: Patrick Fic
2021-10-01 16:25:04 +00:00
Patrick Fic
aa2ac2b296 IO-1392 Add IOU Form to Print Center 2021-10-01 09:24:37 -07:00
Patrick Fic
ce57752b95 Merged in release/2021-10-08 (pull request #232)
release/2021-10-08

Approved-by: Patrick Fic
2021-10-01 00:49:16 +00:00
Patrick Fic
63163c6459 IO1387 Add tax part override for non-R&R lines & Package Updates 2021-09-30 17:48:31 -07:00
Patrick Fic
2712ee5c0b IO-1416 Add missing LAA to resp center setup. 2021-09-30 09:44:15 -07:00
Patrick Fic
2e28a4a790 Merged in release/2021-10-01 (pull request #231)
Release/2021 10 01
2021-09-30 01:50:34 +00:00
Patrick Fic
4179943df6 Merged in release/2021-10-01 (pull request #230)
Release/2021 10 01
2021-09-29 22:55:42 +00:00
Patrick Fic
8bb8eee384 Remove open replay tracker. 2021-09-29 14:38:40 -07:00
Patrick Fic
85d79a8d7f Remove extra console logs. 2021-09-29 12:03:21 -07:00
Patrick Fic
d38dd67c2f Merged in release/2021-10-01 (pull request #229)
release/2021-10-01

Approved-by: Patrick Fic
2021-09-29 15:50:34 +00:00
Patrick Fic
e73d082eab IO-1349 Resolve manual job creation. 2021-09-29 08:49:55 -07:00
Patrick Fic
2637538d9a IO-256 QBO Payables 2021-09-29 08:43:15 -07:00
Patrick Fic
0eacf9a840 Merged in release/2021-10-01 (pull request #228)
release/2021-10-01

Approved-by: Patrick Fic
2021-09-28 20:19:33 +00:00
Patrick Fic
eb58274f90 IO-1391 Scoreboard Improvements 2021-09-28 13:19:02 -07:00
Patrick Fic
aa410d6847 IO-1283 IO-1371 Updates to add to scoreboard button. 2021-09-28 11:45:12 -07:00
Patrick Fic
97f1be9d6f IO-1390 Resolve breaking import changes from Hasura. 2021-09-28 10:59:18 -07:00
Patrick Fic
a7c9dde5e3 Merged in release/2021-10-01 (pull request #227)
release/2021-10-01

Approved-by: Patrick Fic
2021-09-27 23:52:21 +00:00
Patrick Fic
8ec5bc049b Resolve Qb Export not separating for QBO. 2021-09-27 16:50:37 -07:00
Patrick Fic
1f2bec06ef IO-1381 Updates to mark up calculations process. 2021-09-27 16:34:11 -07:00
Patrick Fic
1cad57bec2 Merge branch 'release/2021-10-01' of https://bitbucket.org/snaptsoft/bodyshop into release/2021-10-01 2021-09-27 15:44:21 -07:00
Patrick Fic
10f3c01677 IO-1375 SGI Add Sublet Labor Lines Calculation 2021-09-27 15:44:17 -07:00
Patrick Fic
fc68b669db Add GST to PVRT on QBO. 2021-09-27 14:49:33 -07:00
Patrick Fic
6e22091b81 IO-1382 Add ownr_co_nm to queries that were missing it. 2021-09-27 11:38:48 -07:00
Patrick Fic
545db54c14 IO-653 IO-654 Add SGI documents & regions filtering on print center. 2021-09-27 10:36:12 -07:00
Patrick Fic
aa69fef9ba IO-1379 Updated CSI key for actions menu 2021-09-27 10:22:47 -07:00
Patrick Fic
1e30642d28 Package updates for Tracker. 2021-09-27 09:49:08 -07:00
Patrick Fic
c1dfba949e IO-1349 Update Hasura to 2.0.9. 2021-09-27 09:17:34 -07:00
Patrick Fic
dfa9592755 IO-256 Add PVRT handling for QBO. 2021-09-24 17:17:23 -07:00
Patrick Fic
8f2b1f0f78 IO-256 Export receivables for QBO 2021-09-24 16:43:57 -07:00
Patrick Fic
cf91ec14c0 Merge branch 'feature/qbo' into test 2021-09-24 14:33:07 -07:00
Patrick Fic
891aa649e8 Merged in release/2021-09-24 (pull request #226)
release/2021-09-24
2021-09-24 17:44:53 +00:00
Patrick Fic
dfe0f99bea Merged in release/2021-09-24 (pull request #225)
Revert Node Version

Approved-by: Patrick Fic
2021-09-24 17:44:20 +00:00
Patrick Fic
591022c097 Revert Node Version 2021-09-24 10:43:28 -07:00
Patrick Fic
a8a0167123 Merged in release/2021-09-24 (pull request #224)
Release/2021 09 24
2021-09-24 17:20:52 +00:00
Patrick Fic
c76da54b93 IO-256 First succesful basic post of receivables. 2021-09-23 16:53:41 -07:00
Patrick Fic
186f6101ff IO-256 Begin QBO Changes for Individual code mapping on receivables. 2021-09-23 16:22:59 -07:00
Patrick Fic
e95cf0a026 Merge branch 'test' into feature/qbo 2021-09-23 11:48:56 -07:00
Patrick Fic
3eaa3a0189 Merged in release/2021-09-24 (pull request #223)
release/2021-09-24

Approved-by: Patrick Fic
2021-09-23 17:42:34 +00:00
Patrick Fic
0ba445aad2 IO-1228 Report Center grouping change. 2021-09-23 10:38:22 -07:00
Patrick Fic
637c718b05 IO-1227 Add sold status to filter for CC 2021-09-23 10:36:27 -07:00
Patrick Fic
a01019b1b3 IO-1366 Additional Audit Trail Functionality 2021-09-23 10:29:35 -07:00
Patrick Fic
f6e2393a40 Merged in release/2021-09-24 (pull request #222)
release/2021-09-24

Approved-by: Patrick Fic
2021-09-22 23:11:31 +00:00
Patrick Fic
715857a587 IO-1370 Remove filtering on Other Part Type 2021-09-22 08:20:25 -07:00
Patrick Fic
186ad2d7a2 IO-1365 Update Messaging Issues. 2021-09-21 17:33:39 -07:00
Patrick Fic
c64c49ab6e IO-1103 Include removed lines for bill line select. 2021-09-21 15:56:07 -07:00
Patrick Fic
3e067e2103 Merged in release/2021-09-24 (pull request #221)
release/2021-09-24

Approved-by: Patrick Fic
2021-09-21 16:13:56 +00:00
Patrick Fic
4cc1f77b14 IO-1373 Resolve rounding issue on time tickets. 2021-09-21 08:29:16 -07:00
Patrick Fic
334dd5fe94 Merged in release/2021-09-24 (pull request #220)
release/2021-09-24

Approved-by: Patrick Fic
2021-09-21 00:22:47 +00:00
Patrick Fic
d73f37cacc IO-952 add confirm to bill enter with discrepancy. 2021-09-20 17:22:13 -07:00
Patrick Fic
c6a7e3dcb1 IO-1299 Resolve tax ratds not saving on bill enter save and new 2021-09-20 17:11:45 -07:00
Patrick Fic
4bdc02d22c IO-1358 IO-1372 Add Timestamp to report center. 2021-09-20 16:53:51 -07:00
Patrick Fic
afa8e04008 IO-1308 Remove pagination on job lines. 2021-09-20 16:41:59 -07:00
Patrick Fic
990c1bb2bf IO-1272 Improve reconciliation table UI 2021-09-20 16:39:17 -07:00
Patrick Fic
a5a59c526c IO-1369 Update jobs query to include name. 2021-09-20 16:18:39 -07:00
Patrick Fic
2d5bef4b7b IO-1370 Add glass to parts filter list. 2021-09-20 16:12:12 -07:00
Patrick Fic
5893b1e3b3 IO-1335 Add Subject with RO to Parts Order Email 2021-09-20 14:17:18 -07:00
Patrick Fic
0af452b8a4 IO-1292 Vendor Discount Step. 2021-09-20 14:09:27 -07:00
Patrick Fic
3d82198c90 IO-1227 Sold Courtesy Car Status. 2021-09-20 14:09:09 -07:00
Patrick Fic
01bca360c7 IO-1228 IO-1282 RC Categories & Searching 2021-09-20 12:48:37 -07:00
Patrick Fic
59e994ac29 IO-1367 Open Replay Tracking Improvements 2021-09-20 12:16:37 -07:00
Patrick Fic
d5f3105341 IO-1254 Add PO Number 2021-09-20 12:02:37 -07:00
Patrick Fic
92920f69d4 IO-1191 Add CSI to reports. 2021-09-20 11:34:05 -07:00
Patrick Fic
61ac520192 IO-1364 Update profile changes for new firebase package. 2021-09-20 11:31:13 -07:00
Patrick Fic
45176cc2e2 Merged in feature/cdk-cert (pull request #219)
IO-233 Add refetch.
2021-09-17 17:22:56 +00:00
Patrick Fic
6aacce5a58 IO-233 Add refetch. 2021-09-17 10:22:20 -07:00
Patrick Fic
7a515c35d2 Merge branch 'test' into feature/qbo 2021-09-16 17:04:57 -07:00
Patrick Fic
80dc04669c Merged in feature/cdk-cert (pull request #218)
feature/cdk-cert

Approved-by: Patrick Fic
2021-09-16 23:11:17 +00:00
Patrick Fic
a702c87986 io-233 Remote ITC Settings 2021-09-16 16:08:32 -07:00
Patrick Fic
1942103985 IO-256 Start add QBO Payables 2021-09-15 16:14:01 -07:00
Patrick Fic
fd161fa9eb IO-233 Add missing MAPA/MASH/Discount calulcations. 2021-09-15 08:28:54 -07:00
Patrick Fic
44a18f4ace Merged in feature/qbo (pull request #217)
feature/qbo

Approved-by: Patrick Fic
2021-09-14 21:10:15 +00:00
Patrick Fic
3269c4f602 Merged in feature/cdk-cert (pull request #216)
feature/cdk-cert

Approved-by: Patrick Fic
2021-09-14 21:09:10 +00:00
Patrick Fic
43cbf0084a Merged in release/2021-09-17 (pull request #215)
release/2021-09-17

Approved-by: Patrick Fic
2021-09-14 21:03:40 +00:00
Patrick Fic
28b1356f76 Merge branch 'release/2021-09-17' into feature/cdk-cert 2021-09-14 14:03:11 -07:00
Patrick Fic
38456cb213 Merge branch 'release/2021-09-17' into feature/qbo 2021-09-14 14:02:18 -07:00
Patrick Fic
8c826eaaed Update to latest node. 2021-09-14 14:01:55 -07:00
Patrick Fic
f047556ab5 Merge branch 'release/2021-09-17' into feature/qbo 2021-09-14 13:59:06 -07:00
Patrick Fic
057b335e82 Merge branch 'release/2021-09-17' into feature/cdk-cert 2021-09-14 13:58:48 -07:00
Patrick Fic
4b55719f86 Merged in hotfix-2021-09-14 (pull request #214)
hotfix-2021-09-14

Approved-by: Patrick Fic
2021-09-14 16:52:50 +00:00
Patrick Fic
30c7da2bf9 Merged in hotfix-2021-09-14 (pull request #213)
IO-43 Resolve issue when no vehicle associated.

Approved-by: Patrick Fic
2021-09-14 16:41:07 +00:00
Patrick Fic
82fb4fc74c IO-43 Resolve issue when no vehicle associated. 2021-09-14 09:40:08 -07:00
Patrick Fic
151f122b8c Package updates. 2021-09-14 09:12:58 -07:00
Patrick Fic
b198ca5051 IO-233 Revert ITC Calculations. 2021-09-13 14:56:54 -07:00
Patrick Fic
d9abe84949 Merge release & add time ticket calculations. 2021-09-13 14:47:09 -07:00
Patrick Fic
5387ff207c Merged in release/2021-09-10 (pull request #212)
Release/2021 09 10
2021-09-13 19:02:26 +00:00
Patrick Fic
17f4d69e30 Merged in release/2021-09-10 (pull request #211)
Resolve translation.

Approved-by: Patrick Fic
2021-09-13 17:09:49 +00:00
Patrick Fic
77d3fc359d Resolve translation. 2021-09-13 10:09:26 -07:00
Patrick Fic
86151f3337 Merge branch 'release/2021-09-10' into feature/cdk-cert 2021-09-13 10:08:15 -07:00
Patrick Fic
ae4b5bca33 Merged in release/2021-09-10 (pull request #210)
Add missing translations.

Approved-by: Patrick Fic
2021-09-13 16:50:13 +00:00
Patrick Fic
eb120a264e Add missing translations. 2021-09-13 09:49:38 -07:00
Patrick Fic
7e3f496ea1 IO-233 CDK WIP customer changes. 2021-09-13 09:43:41 -07:00
Patrick Fic
4d33f16f13 Merged in release/2021-09-10 (pull request #209)
release/2021-09-10

Approved-by: Patrick Fic
2021-09-13 15:09:19 +00:00
Patrick Fic
d7ebefe7ab Resolve missing query. 2021-09-13 08:08:43 -07:00
Patrick Fic
8dc2197677 IO-1353 Add missing default resp. centers. 2021-09-10 15:12:00 -07:00
Patrick Fic
e3804b103b Merged in release/2021-09-10 (pull request #208)
Release/2021 09 10
2021-09-10 22:08:15 +00:00
Patrick Fic
fe993cba73 IO-233 CDK Reformatting. First successful post. 2021-09-10 14:58:09 -07:00
Patrick Fic
ef6cdf07d8 IO-1352 Remove positive hrs check on receivables export. 2021-09-10 13:09:21 -07:00
Patrick Fic
cdbde6f5fa Merged in release/2021-09-10 (pull request #207)
IO-43 Updated related ROs approach.

Approved-by: Patrick Fic
2021-09-09 22:35:46 +00:00
Patrick Fic
4059aa9875 IO-43 Updated related ROs approach. 2021-09-09 15:35:24 -07:00
Patrick Fic
22e30ae5cb IO-233 WIP CDK 2021-09-09 15:18:43 -07:00
Patrick Fic
78c883743f Merged in release/2021-09-10 (pull request #206)
IO-1350 Audatex import issues.
2021-09-09 20:10:20 +00:00
Patrick Fic
e46307e715 IO-1350 Audatex import issues. 2021-09-09 13:09:05 -07:00
Patrick Fic
f3e078b481 IO-233 Additional CDK Posting 2021-09-08 15:11:24 -07:00
Patrick Fic
c03f54b3eb Merge branch 'release/2021-09-10' into feature/cdk-cert 2021-09-08 08:28:54 -07:00
Patrick Fic
bb0234fb7d Merge branch 'test' into feature/cdk-cert 2021-09-08 08:28:27 -07:00
Patrick Fic
03f25c8c0e Merged in release/2021-09-10 (pull request #205)
release/2021-09-10

Approved-by: Patrick Fic
2021-09-07 23:53:40 +00:00
Patrick Fic
8e5005daa0 IO-1345 IO-43 Related Job linking 2021-09-07 16:27:34 -07:00
Patrick Fic
259458eec3 IO-1343 Updated tax rate check on import. 2021-09-07 09:53:55 -07:00
Patrick Fic
59e57aa274 Package updates. 2021-09-07 09:12:35 -07:00
Patrick Fic
de33bcd72b IO-1342 Revert IO-554 and add validation on jobline upsert. 2021-09-07 09:12:31 -07:00
Patrick Fic
d72472ccc3 Merged in hotifx/2021-09-06 (pull request #203)
hotifx/2021-09-06

Approved-by: Patrick Fic
2021-09-06 22:50:14 +00:00
Patrick Fic
91efd170c8 Merged in hotifx/2021-09-06 (pull request #202)
IO-1346 Resolve delivery checklist freezing.

Approved-by: Patrick Fic
2021-09-06 22:43:24 +00:00
Patrick Fic
6f1ddd51fd IO-1346 Resolve delivery checklist freezing. 2021-09-06 15:42:25 -07:00
Patrick Fic
9f48a91a29 Merged in release/2021-09-03 (pull request #201)
Remove assist tracker again.

Approved-by: Patrick Fic
2021-09-03 20:01:07 +00:00
Patrick Fic
a7e2548e14 Merged in release/2021-09-03 (pull request #200)
Remove assist tracker again.

Approved-by: Patrick Fic
2021-09-03 20:00:43 +00:00
Patrick Fic
3294faaeaa Remove assist tracker again. 2021-09-03 13:00:02 -07:00
Patrick Fic
06480159e3 Merge branch 'release/2021-09-03' into feature/qbo 2021-09-03 11:24:42 -07:00
Patrick Fic
6ce06ed5c0 Merge branch 'release/2021-09-03' into feature/cdk-cert 2021-09-03 11:24:16 -07:00
Patrick Fic
71e535388a Merged in release/2021-09-03 (pull request #199)
Release/2021 09 03
2021-09-03 18:19:02 +00:00
Patrick Fic
dbd265d368 Merged in release/2021-09-03 (pull request #198)
IO-1342 Resolve negative parts discount for negatives.

Approved-by: Patrick Fic
2021-09-02 23:31:38 +00:00
Patrick Fic
c11f182f83 IO-1342 Resolve negative parts discount for negatives. 2021-09-02 16:25:07 -07:00
Patrick Fic
5f70cfd585 Merged in release/2021-09-03 (pull request #197)
release/2021-09-03

Approved-by: Patrick Fic
2021-09-02 22:50:50 +00:00
Patrick Fic
6e0675f28b IO-1342 Resolve negative parts discount crash on job totals. 2021-09-02 15:48:54 -07:00
Patrick Fic
96f45d2c80 IO-233 Begin Trans Headers 2021-09-02 15:30:03 -07:00
Patrick Fic
091e44f471 Merge branch 'release/2021-09-03' into feature/cdk-cert 2021-09-02 15:27:22 -07:00
Patrick Fic
00549d6a88 Revert "Remove assist tracker."
This reverts commit d940e0ee78.
2021-09-01 18:10:44 -07:00
Patrick Fic
d940e0ee78 Remove assist tracker. 2021-09-01 15:06:52 -07:00
Patrick Fic
39a38d46ee Merged in release/2021-09-03 (pull request #196)
release/2021-09-03

Approved-by: Patrick Fic
2021-09-01 21:14:34 +00:00
Patrick Fic
71435ed75a Added patch for peerjs. 2021-09-01 14:14:20 -07:00
Patrick Fic
e7ec408b98 Merged in release/2021-09-03 (pull request #195)
Openrelay tracking change.

Approved-by: Patrick Fic
2021-09-01 20:39:45 +00:00
Patrick Fic
9306064420 Openrelay tracking change. 2021-09-01 13:38:35 -07:00
Patrick Fic
37a16edfb4 IO-233 Updated translations. 2021-09-01 13:24:19 -07:00
Patrick Fic
9ad5b9547f Merged in release/2021-09-03 (pull request #194)
release/2021-09-03

Approved-by: Patrick Fic
2021-09-01 16:19:58 +00:00
Patrick Fic
47edb0bdf4 IO-1332 Resolve checklist prod note. 2021-09-01 09:19:11 -07:00
Patrick Fic
5db47e879c IO-1224 Adjust scoreboard Entry 2021-09-01 08:43:37 -07:00
Patrick Fic
54b46dd25e IO-256 WIP QBO. 2021-09-01 08:31:24 -07:00
Patrick Fic
4cb92c8508 Merged in release/2021-09-03 (pull request #193)
IO-1336 Resolve towing/storage missing on export.

Approved-by: Patrick Fic
2021-08-31 00:04:22 +00:00
Patrick Fic
cb76e2dcde IO-1336 Resolve issues with QB Export of towing. 2021-08-30 16:59:15 -07:00
Patrick Fic
901c64ed85 IO-1336 Resolve towing/storage missing on export. 2021-08-30 16:38:45 -07:00
Patrick Fic
f6f90d68fa Merged in release/2021-09-03 (pull request #192)
release/2021-09-03

Approved-by: Patrick Fic
2021-08-30 22:43:40 +00:00
Patrick Fic
05e295fcac IO-1334 Added shop info RBAC. 2021-08-30 15:43:10 -07:00
Patrick Fic
c97df6dc61 IO-1333 Resolve dashboard component name issue. 2021-08-30 15:34:19 -07:00
Patrick Fic
61406aafa6 IO-1302 Remove 2nd message on job close. 2021-08-30 15:28:22 -07:00
Patrick Fic
03210db711 IO-1332 Resolve production note save on intake. 2021-08-30 15:25:04 -07:00
Patrick Fic
b3a34c109a IO-539 Fix hanging confirmation. 2021-08-30 15:20:08 -07:00
Patrick Fic
81daad35d8 Package updates and firebase refactor to SDK 9. 2021-08-30 15:09:11 -07:00
Patrick Fic
529eb24d76 Merge branch 'feature/qbo' into release/2021-09-03 2021-08-30 12:57:38 -07:00
Patrick Fic
e81bf7b561 Merge in CDK Branches WIP. 2021-08-30 12:57:13 -07:00
Patrick Fic
7a35dc9b38 IO-233 Add Vehicle History 2021-08-30 12:54:43 -07:00
Patrick Fic
c72ef97b82 IO-256 Further work on QBO Receivables. 2021-08-30 10:50:56 -07:00
Patrick Fic
5284ee2ef9 IO-256 Authorization and Basic Calls 2021-08-27 15:42:32 -07:00
Patrick Fic
724c097d52 IO-256 QBO Authorization Flow. 2021-08-26 15:48:10 -07:00
Patrick Fic
3c3da178ba Merged in release/2021-08-27 (pull request #191)
Release/2021 08 27
2021-08-25 21:59:23 +00:00
Patrick Fic
db4e5d48af Merge branch 'feature/cdk-cert' into feature/qbo 2021-08-25 12:08:06 -07:00
Patrick Fic
a7cf081ed5 IO-233 Begin Wip Header Creation 2021-08-24 18:48:02 -07:00
Patrick Fic
db5b11f6d3 IO-233 Vehicle and Customer posting unit testing completed. 2021-08-24 18:14:41 -07:00
Patrick Fic
8d3d52485f Merged in release/2021-08-27 (pull request #190)
IO-1330 Resolve postal code on qb export.

Approved-by: Patrick Fic
2021-08-24 23:40:02 +00:00
Patrick Fic
edb58ebc81 IO-1330 Resolve postal code on qb export. 2021-08-24 16:39:42 -07:00
Patrick Fic
971b518e8f Merged in release/2021-08-27 (pull request #189)
IO-539 Resolve tax import for SGI.

Approved-by: Patrick Fic
2021-08-24 23:35:15 +00:00
Patrick Fic
8d9507dce1 IO-539 Resolve tax import for SGI. 2021-08-24 16:32:05 -07:00
Patrick Fic
748f8f472d IO-233 Insert DMS Vehicle 2021-08-24 15:56:10 -07:00
Patrick Fic
db2b4739c2 IO-233 Add insert Job. 2021-08-24 08:05:24 -07:00
Patrick Fic
6c12e5cb03 IO-233 Export Job Refactor 2021-08-23 19:02:05 -07:00
Patrick Fic
140e57a123 Merged in release/2021-08-27 (pull request #188)
IO-1330 Update QB Information

Approved-by: Patrick Fic
2021-08-23 21:17:06 +00:00
Patrick Fic
3ca6791939 IO-233 Added vehicle search & selection on form. 2021-08-23 10:40:10 -07:00
Patrick Fic
1c473c95a2 IO-1330 Update QB Information 2021-08-23 09:50:01 -07:00
Patrick Fic
7e145bdec7 Merged in release/2021-08-27 (pull request #187)
Remove tracker assist for CI.

Approved-by: Patrick Fic
2021-08-23 15:43:39 +00:00
Patrick Fic
44c17bd7a2 Remove tracker assist for CI. 2021-08-23 08:43:14 -07:00
Patrick Fic
c493f6e31e Merged in release/2021-08-27 (pull request #186)
Release/2021 08 27

Approved-by: Patrick Fic
2021-08-23 15:34:50 +00:00
Patrick Fic
5213b0b315 Merge branch 'test' into release/2021-08-27 2021-08-23 08:34:25 -07:00
Patrick Fic
8bfd0a1c16 IO-233 Insert DMS Vehicles 2021-08-23 08:30:30 -07:00
Patrick Fic
0541167cc5 Addition of Open Replay Tracker 2021-08-20 14:38:33 -07:00
Patrick Fic
834966ae96 Merged in release/2021-08-20 (pull request #185)
Release/2021 08 20
2021-08-20 21:01:17 +00:00
Patrick Fic
e7d813c3f3 Merged in test (pull request #184)
Merge WIP items back into CDK CErt.
2021-08-20 16:37:44 +00:00
Patrick Fic
26e47ff203 Merged in release/2021-08-20 (pull request #183)
IO-1327 Resolve dinero error on bill posting

Approved-by: Patrick Fic
2021-08-20 15:07:38 +00:00
Patrick Fic
d2b2a5399d IO-1327 Resolve dinero error on bill posting 2021-08-20 08:07:01 -07:00
Patrick Fic
5a4d6d3e8c IO-1269 2021-08-19 17:31:32 -07:00
Patrick Fic
61a5e180f4 IO-1323 Add unit number to contracts list. 2021-08-19 14:43:38 -07:00
Patrick Fic
d5b8ea3ac5 IO-1317 2021-08-19 14:24:12 -07:00
Patrick Fic
4e87ef179b Resolve craco configuration. 2021-08-19 13:45:37 -07:00
Patrick Fic
3b7c31626d IO-539 Adjust Threshold Totals 2021-08-19 08:48:30 -07:00
Patrick Fic
a57e35354d Add sentry error logging. 2021-08-18 15:57:29 -07:00
Patrick Fic
a269fd3ad8 IO-1316 Add flat_rate to time tickets & resolve issues in job costing calculations. 2021-08-18 15:39:37 -07:00
Patrick Fic
86bee9ad0d IO-1321 Mark PO Quantity as required. 2021-08-18 15:38:54 -07:00
Patrick Fic
f8b57ca9bd IO-1297 Adjust Job Costing after Invoicing 2021-08-18 14:13:11 -07:00
Patrick Fic
5f7b780195 Merged in release/2021-08-20 (pull request #182)
release/2021-08-20

Approved-by: Patrick Fic
2021-08-18 20:29:06 +00:00
Patrick Fic
ba5400d04a IO-1307 Resolve selection issues on export tables. 2021-08-18 13:18:30 -07:00
Patrick Fic
0190e737c1 IO-1297 resolve decimal issue on time ticket list. 2021-08-18 12:58:26 -07:00
Patrick Fic
db64d9b69f IO-233 WIP CDK 2021-08-17 16:22:10 -07:00
Patrick Fic
0d12ab36a9 Merged in release/2021-08-20 (pull request #181)
release/2021-08-20

Approved-by: Patrick Fic
2021-08-13 23:38:45 +00:00
Patrick Fic
8f52efbaca IO-1289 Resolve scoreboard UI issues. 2021-08-13 16:33:36 -07:00
Patrick Fic
d6dc5db185 IO-1296 Resolve missing translation. 2021-08-13 16:20:45 -07:00
Patrick Fic
58d1859640 IO-1306 Show Export Attempts on export screens. 2021-08-13 16:17:16 -07:00
Patrick Fic
dba648aea2 IO-1303 Adjust jobline status alignment. 2021-08-13 15:52:02 -07:00
Patrick Fic
12f6206f88 IO-1224 IO-1297 IO-1298 Adjust decimal place displays in various locations 2021-08-13 15:48:12 -07:00
Patrick Fic
7d9fd06b6d IO-233 CDK Get Makes & Taxes calculation. 2021-08-13 15:08:44 -07:00
Patrick Fic
d6fbf16272 Merged in feature/2021-08-13 (pull request #180)
Feature/2021 08 13
2021-08-13 19:09:00 +00:00
Patrick Fic
b68de683b0 Merged in hotfix/2021-08-12 (pull request #179)
Merged in hotfix/2021-08-12 (pull request #178)

Approved-by: Patrick Fic
2021-08-12 21:30:32 +00:00
Patrick Fic
2f9d025fbe Merged in hotfix/2021-08-12 (pull request #178)
hotfix/2021-08-12

Approved-by: Patrick Fic
2021-08-12 20:43:16 +00:00
Patrick Fic
9c1ffaba17 Merged in hotfix/2021-08-12 (pull request #177)
hotfix/2021-08-12
2021-08-12 20:42:55 +00:00
Patrick Fic
142df39cd2 Merged in hotfix/2021-08-12 (pull request #176)
Additional Checklist resolutions.

Approved-by: Patrick Fic
2021-08-12 20:21:34 +00:00
Patrick Fic
ef79ccc299 Additional Checklist resolutions. 2021-08-12 13:20:56 -07:00
Patrick Fic
6d2d96be5c Merged in hotfix/2021-08-12 (pull request #175)
Resolve delete checklist item.

Approved-by: Patrick Fic
2021-08-12 20:16:47 +00:00
Patrick Fic
8ff2a6e6c4 Resolve delete checklist item. 2021-08-12 13:16:26 -07:00
Patrick Fic
b793aa3394 Merged in hotfix/2021-08-12 (pull request #174)
hotfix/2021-08-12

Approved-by: Patrick Fic
2021-08-12 20:02:48 +00:00
Patrick Fic
be2cfb908a IO-1312 Resolve delivery checklist issue. 2021-08-12 13:01:20 -07:00
Patrick Fic
e34084b146 Merged in feature/2021-08-13 (pull request #173)
feature/2021-08-13

Approved-by: Patrick Fic
2021-08-12 16:53:13 +00:00
Patrick Fic
c1d7168260 Resolve CI issue. 2021-08-12 09:52:44 -07:00
Patrick Fic
b3a3709b72 Merged in feature/2021-08-13 (pull request #172)
IO-1286 Retry Supplement Importing fix.

Approved-by: Patrick Fic
2021-08-12 16:47:27 +00:00
Patrick Fic
dd59f3d026 IO-1286 Retry Supplement Importing fix. 2021-08-12 09:46:50 -07:00
Patrick Fic
ccb00ff391 Merged in feature/2021-08-13 (pull request #171)
feature/2021-08-13

Approved-by: Patrick Fic
2021-08-11 20:51:19 +00:00
Patrick Fic
b37970a6df IO-1300 Line Desc Null for Job costing 2021-08-11 13:50:37 -07:00
Patrick Fic
2cd7fcfbd8 Merged in hotfix/2021-08-11 (pull request #170)
hotfix/2021-08-11

Approved-by: Patrick Fic
2021-08-11 20:03:58 +00:00
Patrick Fic
77819b06fe Merged in hotfix/2021-08-11 (pull request #169)
hotfix/2021-08-11

Approved-by: Patrick Fic
2021-08-11 20:03:30 +00:00
Patrick Fic
4e936b4cff Merged in hotfix/2021-08-11 (pull request #168)
hotfix/2021-08-11

Approved-by: Patrick Fic
2021-08-11 20:03:10 +00:00
Patrick Fic
b2362a85fa Merged in hotfix/2021-08-11 (pull request #167)
hotfix/2021-08-11

Approved-by: Patrick Fic
2021-08-11 19:58:52 +00:00
Patrick Fic
f45f351678 IO-1310 resolve production list issue. 2021-08-11 12:57:46 -07:00
Patrick Fic
311171fa0a Merged in feature/2021-08-13 (pull request #166)
Merge into CDK Branch

Approved-by: Patrick Fic
2021-08-11 18:22:20 +00:00
Patrick Fic
7e05f03f4d Resolve merge conflicts. 2021-08-11 11:21:49 -07:00
Patrick Fic
76826c1e80 Merged in feature/2021-08-13 (pull request #165)
Include sentry username

Approved-by: Patrick Fic
2021-08-11 18:16:43 +00:00
Patrick Fic
18618efdc0 Include sentry username 2021-08-11 11:16:22 -07:00
Patrick Fic
d1952dfc25 Merged in feature/2021-08-13 (pull request #164)
IO-1300 Resolve null line desc.

Approved-by: Patrick Fic
2021-08-11 18:10:01 +00:00
Patrick Fic
fe5f4f2727 IO-1300 Resolve null line desc. 2021-08-11 11:09:16 -07:00
Patrick Fic
fd7c907b8f IO-233 Beging get vehicle makes 2021-08-11 11:08:03 -07:00
Patrick Fic
0273255c2c Merged in feature/2021-08-13 (pull request #163)
Feature/2021 08 13
2021-08-11 15:09:36 +00:00
Patrick Fic
e86160e530 IO-1307 Resolve table check error on export tables. 2021-08-11 08:06:51 -07:00
Patrick Fic
9f7e0d611a IO-1300 Resolve line desc to lower case error. 2021-08-11 07:59:32 -07:00
Patrick Fic
0b523efa95 IO-1304 Resolve ins co nm update on import. 2021-08-11 07:58:01 -07:00
Patrick Fic
6b64499e24 IO-233 Resolv merge issues & move allocations to ws 2021-08-10 14:30:08 -07:00
Patrick Fic
e78e628bec Merge branch 'feature/cdk' into feature/2021-08-13 2021-08-10 13:58:58 -07:00
Patrick Fic
ed8eb51c2f IO-233 CDK Allocations Summary 2021-08-10 13:42:53 -07:00
Patrick Fic
124d68ef68 IO-233 CDK Shop Config 2021-08-10 08:40:38 -07:00
Patrick Fic
3e802c1465 Merged in feature/2021-08-06 (pull request #162)
Feature/2021 08 06
2021-08-06 19:31:18 +00:00
Patrick Fic
ac18e78897 Merged in feature/2021-08-06 (pull request #161)
Resolve CI Error
2021-08-05 16:27:15 +00:00
Patrick Fic
e37ee39e88 Resolve CI Error 2021-08-05 09:25:59 -07:00
Patrick Fic
fed16a4aa3 Merged in feature/2021-08-06 (pull request #160)
Feature/2021 08 06
2021-08-05 16:18:03 +00:00
Patrick Fic
8c94dfce9e Time ticket sort update & remove io event logging. 2021-08-05 09:11:53 -07:00
Patrick Fic
69c13dd052 IO-1286 Resolve supplementing issues. 2021-08-05 09:10:09 -07:00
Patrick Fic
a5fe54164e IO-1285 Resolve production not saving sort order. 2021-08-04 09:30:53 -07:00
Patrick Fic
5ecd5a5a5c IO-1122 Add permission to text to intake checklist. 2021-08-04 09:10:23 -07:00
Patrick Fic
ed45347c23 Merged in feature/2021-07-30 (pull request #159)
feature/2021-07-30

Approved-by: Patrick Fic
2021-08-04 00:42:40 +00:00
Patrick Fic
8fb39f9ea4 Merged in feature/2021-07-30 (pull request #158)
feature/2021-07-30

Approved-by: Patrick Fic
2021-08-03 18:46:24 +00:00
Patrick Fic
7ac1fa5abf Merged in feature/2021-07-30 (pull request #157)
Feature/2021 07 30
2021-07-30 22:25:33 +00:00
Patrick Fic
a489ac1d26 Merged in feature/2021-07-30 (pull request #156)
Remove FCM token.

Approved-by: Patrick Fic
2021-07-30 22:21:27 +00:00
Patrick Fic
a19bce5a37 Merged in feature/2021-07-30 (pull request #155)
feature/2021-07-30

Approved-by: Patrick Fic
2021-07-30 22:11:48 +00:00
Patrick Fic
55c532f6e2 Merged in feature/2021-07-30 (pull request #154)
Resolve more Phone Lib issues.
2021-07-30 17:24:36 +00:00
Patrick Fic
cf09f98d7e Merged in feature/2021-07-30 (pull request #153)
Resolve break with Phone Package.
2021-07-30 16:46:38 +00:00
Patrick Fic
65210dea2f Merged in feature/2021-07-30 (pull request #152)
Add several reports to report center.

Approved-by: Patrick Fic
2021-07-29 21:06:18 +00:00
Patrick Fic
99486830b7 Merged in feature/2021-07-30 (pull request #151)
feature/2021-07-30

Approved-by: Patrick Fic
2021-07-29 20:24:45 +00:00
Patrick Fic
6ab1b9f787 Merged in feature/2021-07-30 (pull request #150)
feature/2021-07-30

Approved-by: Patrick Fic
2021-07-28 22:27:36 +00:00
Patrick Fic
c3c021774e Merged in feature/2021-07-30 (pull request #149)
feature/2021-07-30

Approved-by: Patrick Fic
2021-07-22 23:30:47 +00:00
Patrick Fic
c4fdef445e Merged in feature/2021-07-23 (pull request #148)
Feature/2021 07 23
2021-07-22 00:23:07 +00:00
Patrick Fic
11cfef904b Merged in feature/2021-07-16 (pull request #143)
Feature/2021 07 16
2021-07-16 21:51:15 +00:00
Patrick Fic
c9ed8a9360 Merged in feature/2021-07-16 (pull request #139)
Feature/2021 07 16
2021-07-16 15:32:01 +00:00
Patrick Fic
7999895323 Merged in feature/2021-07-09 (pull request #135)
Feature/2021 07 09
2021-07-09 20:52:55 +00:00
Patrick Fic
71ef3dadc5 Merged in feature/2021-07-09 (pull request #132)
Feature/2021 07 09
2021-07-08 01:06:58 +00:00
Patrick Fic
f0d6c5e1b1 IO-233 CDK WIP 2021-07-06 09:31:01 -07:00
Patrick Fic
991df9c48f Merged in hotfix/2021-07-02 (pull request #128)
hotfix/2021-07-02

Approved-by: Patrick Fic
2021-07-02 20:34:59 +00:00
Patrick Fic
84b39f3d2b IO-233 WIP CDK 2021-07-02 12:53:18 -07:00
Patrick Fic
4ab0947cc8 IO-233 Add customer insert actions. 2021-06-30 16:04:01 -07:00
Patrick Fic
8cbef14ea3 Merged in hotfix/2021-06-30 (pull request #126)
Hotfix/2021 06 30
2021-06-30 20:47:05 +00:00
Patrick Fic
105ecd4221 IO-233 CDK 2021-06-30 13:41:00 -07:00
Patrick Fic
3176cfcc56 Merged in hotfix/2021-06-30 (pull request #124)
Hotfix/2021 06 30
2021-06-30 20:17:34 +00:00
589 changed files with 96208 additions and 7089 deletions

1
.gitignore vendored
View File

@@ -112,3 +112,4 @@ firebase/.env
.elasticbeanstalk/*
!.elasticbeanstalk/*.cfg.yml
!.elasticbeanstalk/*.global.yml
logs/oAuthClient-log.log

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,25 @@
// craco.config.js
const TerserPlugin = require("terser-webpack-plugin");
const CracoLessPlugin = require("craco-less");
const SentryWebpackPlugin = require("@sentry/webpack-plugin");
module.exports = {
plugins: [
{
plugin: SentryWebpackPlugin,
options: {
// sentry-cli configuration
authToken:
"6b45b028a02342db97a9a2f92c0959058665443d379d4a3a876430009e744260",
org: "snapt-software",
project: "imexonline",
release: process.env.REACT_APP_GIT_SHA,
// webpack-specific configuration
include: ".",
ignore: ["node_modules", "webpack.config.js"],
},
},
{
plugin: CracoLessPlugin,
options: {
@@ -53,4 +69,5 @@ module.exports = {
},
}),
},
devtool: "source-map",
};

View File

@@ -2,83 +2,90 @@
"name": "bodyshop",
"version": "0.1.1",
"private": true,
"proxy": "http://localhost:5000",
"proxy": "http://localhost:4000",
"dependencies": {
"@apollo/client": "^3.3.21",
"@craco/craco": "^6.2.0",
"@fingerprintjs/fingerprintjs": "^3.2.0",
"@lourenci/react-kanban": "^2.1.0",
"@sentry/react": "^6.10.0",
"@sentry/tracing": "^6.10.0",
"@stripe/react-stripe-js": "^1.4.0",
"@stripe/stripe-js": "^1.16.0",
"@tanem/react-nprogress": "^3.0.74",
"antd": "^4.16.8",
"@apollo/client": "^3.4.17",
"@asseinfo/react-kanban": "^2.2.0",
"@craco/craco": "^6.4.0",
"@fingerprintjs/fingerprintjs": "^3.3.0",
"@openreplay/tracker": "^3.4.7",
"@openreplay/tracker-assist": "^3.4.4",
"@openreplay/tracker-graphql": "^3.0.0",
"@openreplay/tracker-redux": "^3.0.0",
"@sentry/react": "^6.14.3",
"@sentry/tracing": "^6.14.3",
"@splitsoftware/splitio-react": "^1.3.0",
"@stripe/react-stripe-js": "^1.6.0",
"@stripe/stripe-js": "^1.21.1",
"@tanem/react-nprogress": "^3.0.82",
"antd": "^4.16.13",
"apollo-link-logger": "^2.0.0",
"axios": "^0.21.1",
"craco-less": "^1.18.0",
"dinero.js": "^1.9.0",
"axios": "^0.24.0",
"craco-less": "^1.20.0",
"dinero.js": "^1.9.1",
"dotenv": "^10.0.0",
"enquire-js": "^0.2.1",
"env-cmd": "^10.1.0",
"exifr": "^7.1.2",
"firebase": "^8.7.1",
"graphql": "^15.5.1",
"i18next": "^20.3.4",
"exifr": "^7.1.3",
"firebase": "^9.4.1",
"graphql": "^16.0.1",
"i18next": "^21.4.2",
"i18next-browser-languagedetector": "^6.1.2",
"jsoneditor": "^9.5.2",
"jsoneditor": "^9.5.7",
"jsreport-browser-client-dist": "^1.3.0",
"libphonenumber-js": "^1.9.22",
"logrocket": "^1.2.0",
"markerjs2": "^2.9.0",
"libphonenumber-js": "^1.9.42",
"logrocket": "^2.1.1",
"markerjs2": "^2.17.0",
"moment-business-days": "^1.2.0",
"phone": "^3.1.2",
"phone": "^3.1.9",
"preval.macro": "^5.0.0",
"prop-types": "^15.7.2",
"query-string": "^7.0.1",
"rc-queue-anim": "^2.0.0",
"rc-scroll-anim": "^2.7.6",
"react": "^17.0.1",
"react-big-calendar": "^0.33.2",
"react-big-calendar": "^0.38.1",
"react-color": "^2.19.3",
"react-cookie": "^4.1.1",
"react-dom": "^17.0.1",
"react-drag-listview": "^0.1.8",
"react-grid-gallery": "^0.5.5",
"react-grid-layout": "^1.2.5",
"react-i18next": "^11.11.3",
"react-icons": "^4.2.0",
"react-number-format": "^4.6.4",
"react-redux": "^7.2.4",
"react-grid-layout": "^1.3.0",
"react-i18next": "^11.14.2",
"react-icons": "^4.3.1",
"react-number-format": "^4.8.0",
"react-redux": "^7.2.6",
"react-resizable": "^3.0.4",
"react-router-dom": "^5.2.0",
"react-router-dom": "^5.3.0",
"react-scripts": "^4.0.3",
"react-sublime-video": "^0.2.5",
"react-virtualized": "^9.22.3",
"recharts": "^2.0.10",
"redux": "^4.1.0",
"recharts": "^2.1.6",
"redux": "^4.1.2",
"redux-persist": "^6.0.0",
"redux-saga": "^1.1.3",
"redux-state-sync": "^3.1.2",
"reselect": "^4.0.0",
"sass": "^1.35.2",
"socket.io-client": "^4.1.3",
"styled-components": "^5.3.0",
"subscriptions-transport-ws": "^0.9.18",
"web-vitals": "^2.1.0",
"workbox-background-sync": "^6.1.5",
"workbox-broadcast-update": "^6.1.5",
"workbox-cacheable-response": "^6.1.5",
"workbox-core": "^6.1.5",
"workbox-expiration": "^6.1.5",
"workbox-google-analytics": "^6.1.5",
"workbox-navigation-preload": "^6.1.5",
"workbox-precaching": "^6.1.5",
"workbox-range-requests": "^6.1.5",
"workbox-routing": "^6.1.5",
"workbox-strategies": "^6.1.5",
"workbox-streams": "^6.1.5"
"reselect": "^4.1.2",
"sass": "^1.43.4",
"socket.io-client": "^4.3.2",
"styled-components": "^5.3.3",
"subscriptions-transport-ws": "^0.11.0",
"web-vitals": "^2.1.2",
"workbox-background-sync": "^6.3.0",
"workbox-broadcast-update": "^6.3.0",
"workbox-cacheable-response": "^6.3.0",
"workbox-core": "^6.3.0",
"workbox-expiration": "^6.3.0",
"workbox-google-analytics": "^6.3.0",
"workbox-navigation-preload": "^6.3.0",
"workbox-precaching": "^6.3.0",
"workbox-range-requests": "^6.3.0",
"workbox-routing": "^6.3.0",
"workbox-strategies": "^6.3.0",
"workbox-streams": "^6.3.0"
},
"scripts": {
"postinstall": "patch-package",
"analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "craco start",
"build": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build",
@@ -108,6 +115,8 @@
]
},
"devDependencies": {
"@sentry/webpack-plugin": "^1.18.3",
"patch-package": "^6.4.7",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.2"
}

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,8 @@
import { ApolloProvider } from "@apollo/client";
//import trackerRedux from "@openreplay/tracker-redux";
import Tracker from "@openreplay/tracker";
import trackerGraphQL from "@openreplay/tracker-graphql";
import { SplitFactory, SplitSdk } from "@splitsoftware/splitio-react";
import { ConfigProvider } from "antd";
import enLocale from "antd/es/locale/en_US";
import LogRocket from "logrocket";
@@ -6,12 +10,40 @@ import moment from "moment";
import React from "react";
import { useTranslation } from "react-i18next";
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
//import trackerAssist from "@openreplay/tracker-assist";
import { getCurrentUser } from "../firebase/firebase.utils";
import client from "../utils/GraphQLClient";
import App from "./App";
moment.locale("en-US");
export const tracker = new Tracker({
projectKey: "trDmOZlEXUpjGsMtHroA",
ingestPoint: "https://replay.imex.online/ingest",
...(process.env.NODE_ENV === null || process.env.NODE_ENV === "development"
? { __DISABLE_SECURE_MODE: true }
: {}),
// beaconSize: 10485760,
onStart: async ({ sessionID }) => {
const user = await getCurrentUser();
if (user) tracker.setUserID(user.email);
},
});
// tracker.use(
// trackerAssist({ confirmText: "Technical support is about to assist you." })
// ); // check the list of available options below
export const recordGraphQL = tracker.use(trackerGraphQL());
tracker.start();
if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp");
export const factory = SplitSdk({
core: {
authorizationKey: process.env.REACT_APP_SPLIT_API,
key: "anon",
},
});
export default function AppContainer() {
const { t } = useTranslation();
@@ -29,7 +61,9 @@ export default function AppContainer() {
}}
>
<GlobalLoadingBar />
<App />
<SplitFactory factory={factory}>
<App />
</SplitFactory>
</ConfigProvider>
</ApolloProvider>
);

View File

@@ -53,7 +53,6 @@ export function App({ checkUserSession, currentUser, online, setOnline }) {
const { t } = useTranslation();
window.addEventListener("offline", function (e) {
console.log("Internet connection lost.");
setOnline(false);
});

View File

@@ -124,3 +124,13 @@
z-index: 2 !important;
}
}
.react-kanban-column {
background-color: #ddd !important;
}
.production-list-table {
td.ant-table-column-sort {
background: unset;
}
}

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 51 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 51 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.6 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -1,25 +1,9 @@
import Axios from "axios";
import React from "react";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
export default function Test() {
const handleQbSignIn = async () => {
const result = await Axios.post("/qbo/authorize", { userId: "1234" });
console.log("handleQbSignIn -> result", result.data);
// window.open(result.data, "_blank", "toolbar=0,location=0,menubar=0");
var parameters = "location=1,width=800,height=650";
parameters +=
",left=" +
(window.screen.width - 800) / 2 +
",top=" +
(window.screen.height - 650) / 2;
// Launch Popup
window.open(result.data, "connectPopup", parameters);
};
return (
<div>
<button onClick={handleQbSignIn}>Sign Into Qb.</button>
<QboAuthorizeComponent />
</div>
);
}

View File

@@ -9,8 +9,25 @@ import PayableExportAll from "../payable-export-all-button/payable-export-all-bu
import { DateFormatter } from "../../utils/DateFormatter";
import queryString from "query-string";
import { logImEXEvent } from "../../firebase/firebase.utils";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
export default function AccountingPayablesTableComponent({ loading, bills }) {
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(AccountingPayablesTableComponent);
export function AccountingPayablesTableComponent({ bodyshop, loading, bills }) {
const { t } = useTranslation();
const [selectedBills, setSelectedBills] = useState([]);
const [transInProgress, setTransInProgress] = useState(false);
@@ -109,6 +126,17 @@ export default function AccountingPayablesTableComponent({ loading, bills }) {
<Checkbox disabled checked={record.is_credit_memo} />
),
},
{
title: t("exportlogs.labels.attempts"),
dataIndex: "attempts",
key: "attempts",
render: (text, record) => {
const success = record.exportlogs.filter((e) => e.successful).length;
const attempts = record.exportlogs.length;
return `${success}/${attempts}`;
},
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
@@ -121,6 +149,7 @@ export default function AccountingPayablesTableComponent({ loading, bills }) {
billId={record.id}
disabled={transInProgress || !!record.exported}
loadingCallback={setTransInProgress}
setSelectedBills={setSelectedBills}
/>
</div>
),
@@ -154,6 +183,9 @@ export default function AccountingPayablesTableComponent({ loading, bills }) {
loadingCallback={setTransInProgress}
completedCallback={setSelectedBills}
/>
{bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && (
<QboAuthorizeComponent />
)}
<Input
value={state.search}
onChange={handleSearch}

View File

@@ -8,8 +8,26 @@ import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
import { alphaSort, dateSort } from "../../utils/sorters";
import PaymentExportButton from "../payment-export-button/payment-export-button.component";
import PaymentsExportAllButton from "../payments-export-all-button/payments-export-all-button.component";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
export default function AccountingPayablesTableComponent({
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(AccountingPayablesTableComponent);
export function AccountingPayablesTableComponent({
bodyshop,
loading,
payments,
}) {
@@ -108,7 +126,17 @@ export default function AccountingPayablesTableComponent({
<DateTimeFormatter>{record.exportedat}</DateTimeFormatter>
),
},
{
title: t("exportlogs.labels.attempts"),
dataIndex: "attempts",
key: "attempts",
render: (text, record) => {
const success = record.exportlogs.filter((e) => e.successful).length;
const attempts = record.exportlogs.length;
return `${success}/${attempts}`;
},
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
@@ -120,6 +148,7 @@ export default function AccountingPayablesTableComponent({
paymentId={record.id}
disabled={transInProgress || !!record.exportedat}
loadingCallback={setTransInProgress}
setSelectedPayments={setSelectedPayments}
/>
),
},
@@ -152,6 +181,9 @@ export default function AccountingPayablesTableComponent({
loadingCallback={setTransInProgress}
completedCallback={setSelectedPayments}
/>
{bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && (
<QboAuthorizeComponent />
)}
<Input
value={state.search}
onChange={handleSearch}

View File

@@ -8,7 +8,26 @@ import { alphaSort } from "../../utils/sorters";
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
export default function AccountingReceivablesTableComponent({ loading, jobs }) {
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(AccountingReceivablesTableComponent);
export function AccountingReceivablesTableComponent({
bodyshop,
loading,
jobs,
}) {
const { t } = useTranslation();
const [selectedJobs, setSelectedJobs] = useState([]);
const [transInProgress, setTransInProgress] = useState(false);
@@ -114,17 +133,28 @@ export default function AccountingReceivablesTableComponent({ loading, jobs }) {
);
},
},
{
title: t("exportlogs.labels.attempts"),
dataIndex: "attempts",
key: "attempts",
render: (text, record) => {
const success = record.exportlogs.filter((e) => e.successful).length;
const attempts = record.exportlogs.length;
return `${success}/${attempts}`;
},
},
{
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
sorter: (a, b) => a.clm_total - b.clm_total,
render: (text, record) => (
<Space wrap>
<JobExportButton
jobId={record.id}
disabled={!!record.date_exported}
setSelectedJobs={setSelectedJobs}
/>
<Link to={`/manage/jobs/${record.id}/close`}>
<Button>{t("jobs.labels.viewallocations")}</Button>
@@ -169,12 +199,17 @@ export default function AccountingReceivablesTableComponent({ loading, jobs }) {
<Card
extra={
<Space wrap>
<JobsExportAllButton
jobIds={selectedJobs}
disabled={transInProgress || selectedJobs.length === 0}
loadingCallback={setTransInProgress}
completedCallback={setSelectedJobs}
/>
{!bodyshop.cdk_dealerid && !bodyshop.pbs_serialnumber && (
<JobsExportAllButton
jobIds={selectedJobs}
disabled={transInProgress || selectedJobs.length === 0}
loadingCallback={setTransInProgress}
completedCallback={setSelectedJobs}
/>
)}
{bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && (
<QboAuthorizeComponent />
)}
<Input.Search
value={state.search}
onChange={handleSearch}

View File

@@ -18,8 +18,10 @@ import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import confirmDialog from "../../utils/asyncConfirm";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import BillFormContainer from "../bill-form/bill-form.container";
import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility";
import { handleUpload } from "../documents-upload/documents-upload.utility";
const mapStateToProps = createStructuredSelector({
@@ -48,7 +50,31 @@ function BillEnterModalContainer({
const [loading, setLoading] = useState(false);
const client = useApolloClient();
const formValues = useMemo(() => {
return {
...billEnterModal.context.bill,
jobid:
(billEnterModal.context.job && billEnterModal.context.job.id) || null,
federal_tax_rate:
(bodyshop.bill_tax_rates && bodyshop.bill_tax_rates.federal_tax_rate) ||
0,
state_tax_rate:
(bodyshop.bill_tax_rates && bodyshop.bill_tax_rates.state_tax_rate) ||
0,
local_tax_rate:
(bodyshop.bill_tax_rates && bodyshop.bill_tax_rates.local_tax_rate) ||
0,
};
}, [billEnterModal, bodyshop]);
const handleFinish = async (values) => {
let totals = CalculateBillTotal(values);
if (totals.discrepancy.getAmount() !== 0) {
if (!(await confirmDialog(t("bills.labels.savewithdiscrepancy")))) {
return;
}
}
setLoading(true);
const { upload, location, ...remainingValues } = values;
@@ -190,7 +216,7 @@ function BillEnterModalContainer({
if (enterAgain) {
form.resetFields();
form.setFieldsValue({ billlines: [] });
form.setFieldsValue({ ...form.getFieldsValue(), billlines: [] });
} else {
toggleModalVisible();
}
@@ -208,23 +234,6 @@ function BillEnterModalContainer({
if (enterAgain) form.submit();
}, [enterAgain, form]);
const formValues = useMemo(() => {
return {
...billEnterModal.context.bill,
jobid:
(billEnterModal.context.job && billEnterModal.context.job.id) || null,
federal_tax_rate:
(bodyshop.bill_tax_rates && bodyshop.bill_tax_rates.federal_tax_rate) ||
0,
state_tax_rate:
(bodyshop.bill_tax_rates && bodyshop.bill_tax_rates.state_tax_rate) ||
0,
local_tax_rate:
(bodyshop.bill_tax_rates && bodyshop.bill_tax_rates.local_tax_rate) ||
0,
};
}, [billEnterModal, bodyshop]);
useEffect(() => {
if (billEnterModal.visible) {
form.setFieldsValue(formValues);

View File

@@ -72,9 +72,11 @@ export function BillEnterModalLinesComponent({
quantity: opt.part_qty || 1,
actual_price: opt.cost,
cost_center: opt.part_type
? responsibilityCenters.defaults.costs[
? responsibilityCenters.defaults &&
(responsibilityCenters.defaults.costs[
opt.part_type
] || null
] ||
null)
: null,
};
}
@@ -154,18 +156,7 @@ export function BillEnterModalLinesComponent({
setFieldsValue({
billlines: getFieldsValue("billlines").billlines.map(
(item, idx) => {
console.log("Checking", index, idx);
if (idx === index) {
console.log(
"Found and setting.",
!!item.actual_cost
? item.actual_cost
: Math.round(
(parseFloat(e.target.value) * (1 - discount) +
Number.EPSILON) *
100
) / 100
);
return {
...item,
actual_cost: !!item.actual_cost
@@ -500,9 +491,9 @@ const EditableCell = ({
labelCol={{ span: 0 }}
{...(formItemProps && formItemProps(record))}
>
{(formInput && formInput(record, record.key)) || children}
{(formInput && formInput(record, record.name)) || children}
</Form.Item>
{additional && additional(record, record.key)}
{additional && additional(record, record.name)}
</Space>
</td>
);
@@ -514,7 +505,7 @@ const EditableCell = ({
name={dataIndex}
{...(formItemProps && formItemProps(record))}
>
{(formInput && formInput(record, record.key)) || children}
{(formInput && formInput(record, record.name)) || children}
</Form.Item>
</td>
);

View File

@@ -1,13 +1,8 @@
import Dinero from "dinero.js";
export const CalculateBillTotal = (invoice) => {
const {
total,
billlines,
federal_tax_rate,
local_tax_rate,
state_tax_rate,
} = invoice;
const { total, billlines, federal_tax_rate, local_tax_rate, state_tax_rate } =
invoice;
//TODO Determine why this recalculates so many times.
let subtotal = Dinero({ amount: 0 });
@@ -20,8 +15,7 @@ export const CalculateBillTotal = (invoice) => {
billlines.forEach((i) => {
if (!!i) {
const itemTotal = Dinero({
amount:
Math.round(((i.actual_cost || 0) * 100 + Number.EPSILON) * 100) / 100,
amount: Math.round((i.actual_cost || 0) * 100),
}).multiply(i.quantity || 1);
subtotal = subtotal.add(itemTotal);

View File

@@ -12,7 +12,18 @@ const BillLineSearchSelect = ({ options, disabled, ...restProps }, ref) => {
disabled={disabled}
ref={ref}
showSearch
optionFilterProp="line_desc"
// optionFilterProp="line_desc"
filterOption={(inputValue, option) => {
return (
(option.line_desc &&
option.line_desc
.toLowerCase()
.includes(inputValue.toLowerCase())) ||
(option.oem_partno &&
option.oem_partno.toLowerCase().includes(inputValue.toLowerCase()))
);
}}
notFoundContent={"Removed."}
{...restProps}
>
<Select.Option key={null} value={"noline"} cost={0} line_desc={""}>
@@ -21,14 +32,19 @@ const BillLineSearchSelect = ({ options, disabled, ...restProps }, ref) => {
{options
? options.map((item) => (
<Option
disabled={item.removed}
key={item.id}
value={item.id}
cost={item.act_price ? item.act_price : 0}
part_type={item.part_type}
line_desc={item.line_desc}
part_qty={item.part_qty}
oem_partno={item.oem_partno}
style={{
...(item.removed ? { textDecoration: "line-through" } : {}),
}}
>
{`${item.line_desc}${
{`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
item.oem_partno ? ` - ${item.oem_partno}` : ""
}`}
</Option>

View File

@@ -8,6 +8,7 @@ import { selectSelectedConversation } from "../../redux/messaging/messaging.sele
import PhoneFormatter from "../../utils/PhoneFormatter";
import "./chat-conversation-list.styles.scss";
import { useTranslation } from "react-i18next";
import { TimeAgoFormatter } from "../../utils/DateFormatter";
const mapStateToProps = createStructuredSelector({
selectedConversation: selectSelectedConversation,
@@ -60,13 +61,18 @@ export function ChatConversationListComponent({
) : (
<PhoneFormatter>{item.phone_num}</PhoneFormatter>
)}
{item.job_conversations.length > 0
? item.job_conversations.map((j, idx) => (
<Tag key={idx} className="ro-number-tag">
{j.job.ro_number}
</Tag>
))
: null}
<div sryle={{ display: "inline-block" }}>
<div>
{item.job_conversations.length > 0
? item.job_conversations.map((j, idx) => (
<Tag key={idx} className="ro-number-tag">
{j.job.ro_number}
</Tag>
))
: null}
</div>
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>
</div>
<Badge count={item.messages_aggregate.aggregate.count || 0} />
</List.Item>
)}

View File

@@ -1,4 +1,5 @@
import Icon from "@ant-design/icons";
import { Tooltip } from "antd";
import i18n from "i18next";
import moment from "moment";
import React, { useEffect, useRef } from "react";
@@ -9,6 +10,7 @@ import {
CellMeasurerCache,
List,
} from "react-virtualized";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import "./chat-message-list.styles.scss";
export default function ChatMessageListComponent({ messages }) {
@@ -85,17 +87,22 @@ export default function ChatMessageListComponent({ messages }) {
const MessageRender = (message) => {
return (
<div>
{message.image_path &&
message.image_path.map((i, idx) => (
<div key={idx} style={{ display: "flex", justifyContent: "center" }}>
<a href={i} target="__blank">
<img alt="Received" className="message-img" src={i} />
</a>
</div>
))}
<div>{message.text}</div>
</div>
<Tooltip title={DateTimeFormatter({ children: message.created_at })}>
<div>
{message.image_path &&
message.image_path.map((i, idx) => (
<div
key={idx}
style={{ display: "flex", justifyContent: "center" }}
>
<a href={i} target="__blank">
<img alt="Received" className="message-img" src={i} />
</a>
</div>
))}
<div>{message.text}</div>
</div>
</Tooltip>
);
};

View File

@@ -20,7 +20,6 @@ export function ChatNewConversation({ openChatByPhone }) {
const { t } = useTranslation();
const [form] = Form.useForm();
const handleFinish = (values) => {
console.log("values :>> ", values);
openChatByPhone({ phone_num: values.phoneNumber });
form.resetFields();
};

View File

@@ -1,5 +1,5 @@
import { ShrinkOutlined } from "@ant-design/icons";
import { Col, Row, Typography } from "antd";
import { ShrinkOutlined, InfoCircleOutlined } from "@ant-design/icons";
import { Col, Row, Tooltip, Typography } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -31,6 +31,9 @@ export function ChatPopupComponent({
{t("messaging.labels.messaging")}
</Typography.Title>
<ChatNewConversation />
<Tooltip title={t("messaging.labels.recentonly")}>
<InfoCircleOutlined />
</Tooltip>
</div>
<ShrinkOutlined
onClick={() => toggleChatVisible()}

View File

@@ -53,6 +53,7 @@ export function ContractConvertToRo({
const billingLines = [];
if (contractLength > 0)
billingLines.push({
manual_line:true,
unq_seq: 1,
line_no: 1,
line_ref: 1,
@@ -70,6 +71,7 @@ export function ContractConvertToRo({
contract.kmend - contract.kmstart - contract.dailyfreekm * contractLength;
if (mileageDiff > 0) {
billingLines.push({
manual_line:true,
unq_seq: 2,
line_no: 2,
line_ref: 2,
@@ -86,6 +88,7 @@ export function ContractConvertToRo({
if (values.refuelqty > 0) {
billingLines.push({
manual_line:true,
unq_seq: 3,
line_no: 3,
line_ref: 3,
@@ -101,6 +104,7 @@ export function ContractConvertToRo({
}
if (values.applyCleanupCharge) {
billingLines.push({
manual_line:true,
unq_seq: 4,
line_no: 4,
line_ref: 4,
@@ -117,6 +121,7 @@ export function ContractConvertToRo({
if (contract.damagewaiver) {
//Add for cleanup fee.
billingLines.push({
manual_line:true,
unq_seq: 5,
line_no: 5,
line_ref: 5,

View File

@@ -42,7 +42,6 @@ export default function ContractFormComponent({
<ContractStatusSelector />
</Form.Item>
)}
<Form.Item
label={t("contracts.fields.start")}
name="start"

View File

@@ -83,8 +83,10 @@ export function ContractsList({
render: (text, record) => (
<Link to={`/manage/courtesycars/${record.courtesycar.id}`}>{`${
record.courtesycar.year
} ${record.courtesycar.make} ${record.courtesycar.model} ${
record.courtesycar.plate ? `(${record.courtesycar.plate})` : ""
} ${record.courtesycar.make} ${record.courtesycar.model}${
record.courtesycar.plate ? ` (${record.courtesycar.plate})` : ""
}${
record.courtesycar.fleetnumber ? ` (${record.courtesycar.fleetnumber})` : ""
}`}</Link>
),
},

View File

@@ -31,6 +31,9 @@ const CourtesyCarStatusComponent = ({ value, onChange }, ref) => {
<Option value="courtesycars.status.out">
{t("courtesycars.status.out")}
</Option>
<Option value="courtesycars.status.sold">
{t("courtesycars.status.sold")}
</Option>
</Select>
);
};

View File

@@ -45,6 +45,10 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
text: t("courtesycars.status.out"),
value: "courtesycars.status.out",
},
{
text: t("courtesycars.status.sold"),
value: "courtesycars.status.sold",
},
],
onFilter: (value, record) => value.includes(record.status),
sortOrder:

View File

@@ -86,10 +86,7 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
const handleRemoveComponent = (key) => {
logImEXEvent("dashboard_remove_component", { name: key });
const idxToRemove = state.items.findIndex((i) => i.i === key);
console.log(
"🚀 ~ file: dashboard-grid.component.jsx ~ line 81 ~ idxToRemove",
idxToRemove
);
const items = _.cloneDeep(state.items);
items.splice(idxToRemove, 1);
@@ -244,7 +241,7 @@ const componentList = {
h: 3,
},
MonthlyPartsSales: {
label: i18next.t("dashboard.titles.productiondollars"),
label: i18next.t("dashboard.titles.monthlypartssales"),
component: DashboardMonthlyPartsSales,
gqlFragment: null,
minW: 2,
@@ -253,7 +250,7 @@ const componentList = {
h: 2,
},
MonthlyLaborSales: {
label: i18next.t("dashboard.titles.monthlypartssales"),
label: i18next.t("dashboard.titles.monthlylaborsales"),
component: DashboardMonthlyLaborSales,
gqlFragment: null,
minW: 2,

View File

@@ -0,0 +1,135 @@
import { Button, Card, Table, Typography } from "antd";
import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import Dinero from "dinero.js";
import { SyncOutlined } from "@ant-design/icons";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(DmsAllocationsSummary);
export function DmsAllocationsSummary({ socket, bodyshop, jobId, title }) {
const { t } = useTranslation();
const [allocationsSummary, setAllocationsSummary] = useState([]);
useEffect(() => {
if (socket.connected) {
socket.emit("cdk-calculate-allocations", jobId, (ack) => {
setAllocationsSummary(ack);
socket.allocationsSummary = ack;
});
}
}, [socket, socket.connected, jobId]);
const columns = [
{
title: t("jobs.fields.dms.center"),
dataIndex: "center",
key: "center",
},
{
title: t("jobs.fields.dms.sale"),
dataIndex: "sale",
key: "sale",
render: (text, record) => Dinero(record.sale).toFormat(),
},
{
title: t("jobs.fields.dms.cost"),
dataIndex: "cost",
key: "cost",
render: (text, record) => Dinero(record.cost).toFormat(),
},
{
title: t("jobs.fields.dms.sale_dms_acctnumber"),
dataIndex: "sale_dms_acctnumber",
key: "sale_dms_acctnumber",
render: (text, record) =>
record.profitCenter && record.profitCenter.dms_acctnumber,
},
{
title: t("jobs.fields.dms.cost_dms_acctnumber"),
dataIndex: "cost_dms_acctnumber",
key: "cost_dms_acctnumber",
render: (text, record) =>
record.costCenter && record.costCenter.dms_acctnumber,
},
{
title: t("jobs.fields.dms.dms_wip_acctnumber"),
dataIndex: "dms_wip_acctnumber",
key: "dms_wip_acctnumber",
render: (text, record) =>
record.costCenter && record.costCenter.dms_wip_acctnumber,
},
];
return (
<Card
title={title}
extra={
<Button
onClick={() => {
socket.emit("cdk-calculate-allocations", jobId, (ack) =>
setAllocationsSummary(ack)
);
}}
>
<SyncOutlined />
</Button>
}
>
<Table
pagination={{ position: "top", defaultPageSize: 50 }}
columns={columns}
rowKey="center"
dataSource={allocationsSummary}
summary={() => {
const totals = allocationsSummary.reduce(
(acc, val) => {
return {
totalSale: acc.totalSale.add(Dinero(val.sale)),
totalCost: acc.totalCost.add(Dinero(val.cost)),
};
},
{
totalSale: Dinero(),
totalCost: Dinero(),
}
);
return (
<Table.Summary.Row>
<Table.Summary.Cell>
<Typography.Title level={4}>
{t("general.labels.totals")}
</Typography.Title>
</Table.Summary.Cell>
<Table.Summary.Cell>
{totals.totalSale.toFormat()}
</Table.Summary.Cell>
<Table.Summary.Cell>
{
// totals.totalCost.toFormat()
}
</Table.Summary.Cell>
<Table.Summary.Cell></Table.Summary.Cell>
<Table.Summary.Cell></Table.Summary.Cell>
</Table.Summary.Row>
);
}}
/>
</Card>
);
}

View File

@@ -0,0 +1,105 @@
import { useLazyQuery } from "@apollo/client";
import { Button, Input, Modal, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { SEARCH_DMS_VEHICLES } from "../../graphql/dms.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(DmsCdkVehicles);
export function DmsCdkVehicles({ bodyshop, form, socket, job }) {
const [visible, setVisible] = useState(false);
const [selectedModel, setSelectedModel] = useState(null);
const { t } = useTranslation();
const [callSearch, { loading, error, data }] =
useLazyQuery(SEARCH_DMS_VEHICLES);
const columns = [
{
title: t("vehicles.fields.v_make_desc"),
dataIndex: "make",
key: "make",
},
{
title: t("vehicles.fields.v_model_desc"),
dataIndex: "model",
key: "model",
},
{
title: t("jobs.fields.dms.dms_make"),
dataIndex: "makecode",
key: "makecode",
},
{
title: t("jobs.fields.dms.dms_model"),
dataIndex: "modelcode",
key: "modelcode",
},
];
return (
<div>
<Modal
width={"90%"}
visible={visible}
onCancel={() => setVisible(false)}
onOk={() => {
form.setFieldsValue({
dms_make: selectedModel.makecode,
dms_model: selectedModel.modelcode,
});
setVisible(false);
}}
>
{error && <AlertComponent error={error.message} />}
<Table
title={() => (
<Input.Search
onSearch={(val) => callSearch({ variables: { search: val } })}
placeholder={t("general.labels.search")}
/>
)}
columns={columns}
loading={loading}
rowKey="id"
dataSource={data ? data.search_dms_vehicles : []}
onRow={(record) => {
return {
onClick: () => setSelectedModel(record),
};
}}
rowSelection={{
onSelect: (record) => {
setSelectedModel(record);
},
type: "radio",
selectedRowKeys: [selectedModel && selectedModel.id],
}}
/>
</Modal>
<Button
onClick={() => {
setVisible(true);
callSearch({
variables: {
search: job && job.v_model_desc && job.v_model_desc.substr(0, 3),
},
});
}}
>
{t("jobs.actions.dms.findmakemodelcode")}
</Button>
</div>
);
}

View File

@@ -0,0 +1,34 @@
import { Button } from "antd";
import axios from "axios";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(DmsCdkMakesRefetch);
export function DmsCdkMakesRefetch({ bodyshop, form, socket }) {
const [loading, setLoading] = useState(false);
const { t } = useTranslation();
const handleRefetch = async () => {
setLoading(true);
await axios.post("/cdk/getvehicles", {
cdk_dealerid: bodyshop.cdk_dealerid,
bodyshopid: bodyshop.id,
});
setLoading(false);
};
return (
<Button loading={loading} onClick={handleRefetch}>
{t("jobs.actions.dms.refetchmakesmodels")}
</Button>
);
}

View File

@@ -0,0 +1,169 @@
import { Button, Table, Col, Checkbox } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { socket } from "../../pages/dms/dms.container";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { alphaSort } from "../../utils/sorters";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(DmsCustomerSelector);
export function DmsCustomerSelector({ bodyshop }) {
const { t } = useTranslation();
const [customerList, setcustomerList] = useState([]);
const [visible, setVisible] = useState(false);
const [selectedCustomer, setSelectedCustomer] = useState(null);
const [dmsType, setDmsType] = useState("cdk");
socket.on("cdk-select-customer", (customerList, callback) => {
setVisible(true);
setDmsType("cdk");
setcustomerList(customerList);
});
socket.on("pbs-select-customer", (customerList, callback) => {
setVisible(true);
setDmsType("pbs");
setcustomerList(customerList);
console.log(
"🚀 ~ file: dms-customer-selector.component.jsx ~ line 37 ~ socket.on ~ customerList",
customerList
);
});
const onUseSelected = () => {
setVisible(false);
socket.emit(`${dmsType}-selected-customer`, selectedCustomer);
setSelectedCustomer(null);
};
const onUseGeneric = () => {
setVisible(false);
socket.emit(
"cdk-selected-customer",
bodyshop.cdk_configuration.generic_customer_number
);
setSelectedCustomer(null);
};
const onCreateNew = () => {
setVisible(false);
socket.emit("cdk-selected-customer", null);
setSelectedCustomer(null);
};
const cdkColumns = [
{
title: t("jobs.fields.dms.id"),
dataIndex: ["id", "value"],
key: "id",
},
{
title: t("jobs.fields.dms.vinowner"),
dataIndex: "vinOwner",
key: "vinOwner",
render: (text, record) => <Checkbox disabled checked={record.vinOwner} />,
},
{
title: t("jobs.fields.dms.name1"),
dataIndex: ["name1", "fullName"],
key: "name1",
sorter: (a, b) =>
alphaSort(a.name1 && a.name1.fullName, b.name1 && b.name1.fullName),
},
{
title: t("jobs.fields.dms.address"),
//dataIndex: ["name2", "fullName"],
key: "address",
render: (record, value) =>
`${record.address && record.address.addressLine[0]}, ${
record.address && record.address.city
} ${record.address && record.address.stateOrProvince} ${
record.address && record.address.postalCode
}`,
},
];
const pbsColumns = [
{
title: t("jobs.fields.dms.id"),
dataIndex: "ContactId",
key: "ContactId",
},
{
title: t("jobs.fields.dms.vinowner"),
dataIndex: "vinOwner",
key: "vinOwner",
render: (text, record) => <Checkbox disabled checked={record.vinOwner} />,
},
{
title: t("jobs.fields.dms.name1"),
key: "name1",
sorter: (a, b) => alphaSort(a.LastName, b.LastName),
render: (text, record) =>
`${record.FirstName || ""} ${record.LastName || ""}`,
},
{
title: t("jobs.fields.dms.address"),
key: "address",
render: (record, value) =>
`${record.Address}, ${record.City} ${record.State} ${record.ZipCode}`,
},
];
if (!visible) return null;
return (
<Col span={24}>
<Table
title={() => (
<div>
<Button onClick={onUseSelected} disabled={!selectedCustomer}>
{t("jobs.actions.dms.useselected")}
</Button>
<Button
onClick={onUseGeneric}
disabled={
!(
bodyshop.cdk_configuration &&
bodyshop.cdk_configuration.generic_customer_number
)
}
>
{t("jobs.actions.dms.usegeneric")}
</Button>
<Button onClick={onCreateNew}>
{t("jobs.actions.dms.createnewcustomer")}
</Button>
</div>
)}
pagination={{ position: "top" }}
columns={dmsType === "cdk" ? cdkColumns : pbsColumns}
rowKey={(record) =>
dmsType === "cdk" ? record.id.value : record.ContactId
}
dataSource={customerList}
//onChange={handleTableChange}
rowSelection={{
onSelect: (record) => {
setSelectedCustomer(
dmsType === "cdk" ? record.id.value : record.ContactId
);
},
type: "radio",
selectedRowKeys: [selectedCustomer],
}}
/>
</Col>
);
}

View File

@@ -0,0 +1,55 @@
import { Divider, Space, Tag, Timeline } from "antd";
import moment from "moment";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
});
export default connect(mapStateToProps, mapDispatchToProps)(DmsLogEvents);
export function DmsLogEvents({ socket, logs, bodyshop }) {
return (
<Timeline pending reverse={true}>
{logs.map((log, idx) => (
<Timeline.Item key={idx} color={LogLevelHierarchy(log.level)}>
<Space wrap align="start" style={{}}>
<Tag color={LogLevelHierarchy(log.level)}>{log.level}</Tag>
<span>{moment(log.timestamp).format("MM/DD/YYYY HH:mm:ss")}</span>
<Divider type="vertical" />
<span>{log.message}</span>
</Space>
</Timeline.Item>
))}
</Timeline>
);
}
function LogLevelHierarchy(level) {
switch (level) {
case "TRACE":
return "pink";
case "DEBUG":
return "orange";
case "INFO":
return "blue";
case "WARNING":
return "yellow";
case "ERROR":
return "red";
default:
return 0;
}
}

View File

@@ -0,0 +1,342 @@
import { DeleteFilled } from "@ant-design/icons";
import {
Button,
Card,
Divider,
Form,
Input,
InputNumber,
Select,
Space,
Statistic,
Typography,
} from "antd";
import Dinero from "dinero.js";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { determineDmsType } from "../../pages/dms/dms.container";
import { selectBodyshop } from "../../redux/user/user.selectors";
import DmsCdkMakes from "../dms-cdk-makes/dms-cdk-makes.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import DmsCdkMakesRefetch from "../dms-cdk-makes/dms-cdk-makes.refetch.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(DmsPostForm);
export function DmsPostForm({ bodyshop, socket, job }) {
const [form] = Form.useForm();
const { t } = useTranslation();
const handlePayerSelect = (value, index) => {
form.setFieldsValue({
payers: form.getFieldValue("payers").map((payer, mapIndex) => {
if (index !== mapIndex) return payer;
const cdkPayer =
bodyshop.cdk_configuration.payers &&
bodyshop.cdk_configuration.payers.find((i) => i.name === value);
if (!cdkPayer) return payer;
return {
...cdkPayer,
dms_acctnumber: cdkPayer.dms_acctnumber,
controlnumber: job && job[cdkPayer.control_type],
};
}),
});
};
const handleFinish = (values) => {
socket.emit(`${determineDmsType(bodyshop)}-export-job`, {
jobid: job.id,
txEnvelope: values,
});
};
return (
<Card title={t("jobs.labels.dms.postingform")}>
<Form
form={form}
layout="vertical"
onFinish={handleFinish}
initialValues={{
story: t("jobs.labels.dms.defaultstory", {
ro_number: job.ro_number,
area_of_damage: job.area_of_damage && job.area_of_damage.impact1,
}).substr(0, 239),
}}
>
<LayoutFormRow grow>
<Form.Item
name="journal"
label={t("jobs.fields.dms.journal")}
initialValue={
bodyshop.cdk_configuration &&
bodyshop.cdk_configuration.default_journal
}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Input />
</Form.Item>
<Form.Item
name="kmin"
label={t("jobs.fields.kmin")}
initialValue={job && job.kmin}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber disabled />
</Form.Item>
<Form.Item
name="kmout"
label={t("jobs.fields.kmout")}
initialValue={job && job.kmout}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber disabled />
</Form.Item>
</LayoutFormRow>
{bodyshop.cdk_dealerid && (
<LayoutFormRow style={{ justifyContent: "center" }} grow>
<Form.Item
name="dms_make"
label={t("jobs.fields.dms.dms_make")}
rules={[
{
required: true,
},
]}
>
<Input disabled />
</Form.Item>
<Form.Item
name="dms_model"
label={t("jobs.fields.dms.dms_model")}
rules={[
{
required: true,
},
]}
>
<Input disabled />
</Form.Item>
<DmsCdkMakes form={form} socket={socket} job={job} />
<DmsCdkMakesRefetch />
</LayoutFormRow>
)}
<Form.Item
name="story"
label={t("jobs.fields.dms.story")}
rules={[
{
required: true,
},
]}
>
<Input.TextArea maxLength={240} />
</Form.Item>
<Divider />
<Form.List name={["payers"]}>
{(fields, { add, remove }) => {
return (
<div>
{fields.map((field, index) => (
<Form.Item key={field.key}>
<Space wrap>
<Form.Item
label={t("jobs.fields.dms.payer.name")}
key={`${index}name`}
name={[field.name, "name"]}
rules={[
{
required: true,
},
]}
>
<Select
style={{ minWidth: "15rem" }}
onSelect={(value) => handlePayerSelect(value, index)}
>
{bodyshop.cdk_configuration &&
bodyshop.cdk_configuration.payers &&
bodyshop.cdk_configuration.payers.map((payer) => (
<Select.Option key={payer.name}>
{payer.name}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("jobs.fields.dms.payer.dms_acctnumber")}
key={`${index}dms_acctnumber`}
name={[field.name, "dms_acctnumber"]}
rules={[
{
required: true,
},
]}
>
<Input disabled />
</Form.Item>
<Form.Item
label={t("jobs.fields.dms.payer.amount")}
key={`${index}amount`}
name={[field.name, "amount"]}
rules={[
{
required: true,
},
]}
>
<CurrencyInput min={0} />
</Form.Item>
<Form.Item
label={t("jobs.fields.dms.payer.controlnumber")}
key={`${index}controlnumber`}
name={[field.name, "controlnumber"]}
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
<Form.Item shouldUpdate>
{() => {
const payers = form.getFieldValue("payers");
const row = payers && payers[index];
const cdkPayer =
bodyshop.cdk_configuration.payers &&
bodyshop.cdk_configuration.payers.find(
(i) => i && row && i.name === row.name
);
return (
<div>
{cdkPayer &&
t(`jobs.fields.${cdkPayer.control_type}`)}
</div>
);
}}
</Form.Item>
<DeleteFilled
onClick={() => {
remove(field.name);
}}
/>
</Space>
</Form.Item>
))}
<Form.Item>
<Button
disabled={!(fields.length < 3)}
onClick={() => {
if (fields.length < 3) add();
}}
style={{ width: "100%" }}
>
{t("jobs.actions.dms.addpayer")}
</Button>
</Form.Item>
</div>
);
}}
</Form.List>
<Form.Item shouldUpdate>
{() => {
//Perform Calculation to determine discrepancy.
let totalAllocated = Dinero();
const payers = form.getFieldValue("payers");
payers &&
payers.forEach((payer) => {
totalAllocated = totalAllocated.add(
Dinero({ amount: Math.round((payer?.amount || 0) * 100) })
);
});
const totals =
socket.allocationsSummary &&
socket.allocationsSummary.reduce(
(acc, val) => {
return {
totalSale: acc.totalSale.add(Dinero(val.sale)),
totalCost: acc.totalCost.add(Dinero(val.cost)),
};
},
{
totalSale: Dinero(),
totalCost: Dinero(),
}
);
const discrep = totals
? totals.totalSale.subtract(totalAllocated)
: Dinero();
return (
<Space size="large" wrap align="center">
<Statistic
title={t("jobs.labels.subtotal")}
value={(totals ? totals.totalSale : Dinero()).toFormat()}
/>
<Typography.Title>-</Typography.Title>
<Statistic
title={t("jobs.labels.dms.totalallocated")}
value={totalAllocated.toFormat()}
/>
<Typography.Title>=</Typography.Title>
<Statistic
title={t("jobs.labels.dms.notallocated")}
valueStyle={{
color: discrep.getAmount() === 0 ? "green" : "red",
}}
value={discrep.toFormat()}
/>
<Button
disabled={
!socket.allocationsSummary || discrep.getAmount() !== 0
}
htmlType="submit"
>
{t("jobs.actions.dms.post")}
</Button>
</Space>
);
}}
</Form.Item>
</Form>
</Card>
);
}

View File

@@ -58,11 +58,9 @@ export function DocumentEditorComponent({ currentUser, bodyshop, document }) {
if (imgRef.current !== null) {
// create a marker.js MarkerArea
markerArea.current = new markerjs2.MarkerArea(imgRef.current);
console.log(`markerArea.current`, markerArea.current);
// attach an event handler to assign annotated image back to our image element
markerArea.current.addCloseEventListener((closeEvent) => {
console.log("Close Event", closeEvent);
});
markerArea.current.addCloseEventListener((closeEvent) => {});
markerArea.current.addRenderEventListener((dataUrl) => {
imgRef.current.src = dataUrl;

View File

@@ -14,8 +14,6 @@ var cleanAxios = axios.create();
cleanAxios.interceptors.request.eject(axiosAuthInterceptorId);
export const handleUpload = (ev, context) => {
console.log("Handling Upload", ev);
logImEXEvent("document_upload", { filetype: ev.file.type });
const { onError, onSuccess, onProgress } = ev;
@@ -61,7 +59,7 @@ export const uploadToCloudinary = async (
// let eager = process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS;
//Get the signed url.
console.log("fileType", fileType);
const upload_preset = fileType.startsWith("video")
? "incoming_upload_video"
: "incoming_upload";
@@ -74,7 +72,6 @@ export const uploadToCloudinary = async (
});
if (signedURLResponse.status !== 200) {
console.log("Error Getting Signed URL", signedURLResponse.statusText);
if (!!onError) onError(signedURLResponse.statusText);
notification["error"]({
message: i18n.t("documents.errors.getpresignurl", {
@@ -113,13 +110,8 @@ export const uploadToCloudinary = async (
...options,
}
);
console.log("Upload Response", cloudinaryUploadResponse.data);
if (cloudinaryUploadResponse.status !== 200) {
console.log(
"Error uploading to cloudinary.",
cloudinaryUploadResponse.statusText
);
if (!!onError) onError(cloudinaryUploadResponse.statusText);
notification["error"]({
message: i18n.t("documents.errors.insert", {

View File

@@ -35,10 +35,6 @@ export function EmailDocumentsComponent({
},
skip: !emailConfig.jobid,
});
console.log(
"🚀 ~ file: email-documents.component.jsx ~ line 38 ~ emailConfig",
emailConfig
);
return (
<div>

View File

@@ -1,15 +1,71 @@
import { UploadOutlined } from "@ant-design/icons";
import { Divider, Form, Input, Select, Tabs, Upload } from "antd";
import { UploadOutlined, UserAddOutlined } from "@ant-design/icons";
import {
Divider,
Form,
Input,
Select,
Tabs,
Upload,
Space,
Menu,
Dropdown,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import EmailDocumentsComponent from "../email-documents/email-documents.component";
import _ from "lodash";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(EmailOverlayComponent);
export default function EmailOverlayComponent({ form, selectedMediaState }) {
export function EmailOverlayComponent({ form, selectedMediaState, bodyshop }) {
const { t } = useTranslation();
const handleClick = ({ item, key, keyPath }) => {
const email = item.props.value;
form.setFieldsValue({ to: _.uniq([...form.getFieldValue("to"), email]) });
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.employees
.filter((e) => e.user_email)
.map((e, idx) => (
<Menu.Item value={e.user_email} key={idx}>
{`${e.first_name} ${e.last_name}`}
</Menu.Item>
))}
</Menu>
</div>
);
return (
<div>
<Form.Item
label={t("emails.fields.to")}
label={
<Space>
{t("emails.fields.to")}
<Dropdown overlay={menu}>
<a
className="ant-dropdown-link"
href=" #"
onClick={(e) => e.preventDefault()}
>
<UserAddOutlined />
</a>
</Dropdown>
</Space>
}
name="to"
rules={[
{

View File

@@ -51,7 +51,9 @@ export function EmailOverlayContainer({
const defaultEmailFrom = {
from: {
name: `${currentUser.displayName} @ ${bodyshop.shopname}`,
name: currentUser.displayName
? `${currentUser.displayName} @ ${bodyshop.shopname}`
: bodyshop.shopname,
address: EmailSettings.fromAddress,
},
ReplyTo: {
@@ -109,7 +111,6 @@ export function EmailOverlayContainer({
notification["success"]({ message: t("emails.successes.sent") });
toggleEmailOverlayVisible();
} catch (error) {
console.log(JSON.stringify(error));
notification["error"]({
message: t("emails.errors.notsent", { message: error.message }),
});
@@ -147,6 +148,18 @@ export function EmailOverlayContainer({
html: response.data,
fileList: [],
});
if (
bodyshop.md_email_cc[emailConfig.template.name] &&
bodyshop.md_email_cc[emailConfig.template.name].length > 0
) {
form.setFieldsValue({
cc: [
...(form.getFieldValue("cc") || []),
...bodyshop.md_email_cc[emailConfig.template.name],
],
});
}
setLoading(false);
};

View File

@@ -7,10 +7,12 @@ import { selectCurrentUser } from "../../redux/user/user.selectors";
import { GenerateDocument } from "../../utils/RenderTemplate";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import moment from "moment";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
});
@@ -19,14 +21,24 @@ export function EmailTestComponent({ currentUser, setEmailOptions }) {
const [form] = Form.useForm();
const handleFinish = (values) => {
console.log("values", values);
GenerateDocument(
{
name: values.key,
variables: {
...(values.start
? {
start: moment(values.start).startOf("day").format("YYYY-MM-DD"),
}
: {}),
...(values.end
? { end: moment(values.end).endOf("day").format("YYYY-MM-DD") }
: {}),
...(values.start
? { starttz: moment(values.start).startOf("day") }
: {}),
...(values.end ? { endtz: moment(values.end).endOf("day") } : {}),
...(values.id ? { id: values.id } : {}),
...(values.start ? { start: values.start } : {}),
...(values.end ? { end: values.end } : {}),
},
},
{

View File

@@ -9,6 +9,7 @@ import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { tracker } from "../../App/App.container";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
@@ -36,6 +37,7 @@ class ErrorBoundary extends React.Component {
componentDidCatch(error, info) {
console.log("Exception Caught by Error Boundary.", error, info);
this.setState({ ...this.state, error, info });
tracker.event("error_boundary", error, true);
}
handleErrorSubmit = () => {

View File

@@ -2,7 +2,7 @@ import { withApollo } from "@apollo/client/react/hoc";
import React, { Component } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { logImEXEvent, messaging } from "../../firebase/firebase.utils";
//import { logImEXEvent, messaging } from "../../firebase/firebase.utils";
import { selectCurrentUser } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
@@ -15,21 +15,20 @@ const mapDispatchToProps = (dispatch) => ({
class FcmNotificationComponent extends Component {
async componentDidMount() {
//const { client, currentUser } = this.props;
if (!!!messaging) return; //Skip all of the notification functionality if the firebase SDK could not start.
messaging
.requestPermission()
.then(async function () {
// const token = await messaging.getToken();
// client.mutate({
// mutation: UPDATE_FCM_TOKEN,
// variables: { authEmail: currentUser.email, token: { [token]: true } },
// });
})
.catch(function (err) {
console.log("Unable to get permission to notify.", err);
logImEXEvent("fcm_permission_denied", { message: err });
});
// if (!!!messaging) return; //Skip all of the notification functionality if the firebase SDK could not start.
// messaging
// .requestPermission()
// .then(async function () {
// // const token = await messaging.getToken();
// // client.mutate({
// // mutation: UPDATE_FCM_TOKEN,
// // variables: { authEmail: currentUser.email, token: { [token]: true } },
// // });
// })
// .catch(function (err) {
// console.log("Unable to get permission to notify.", err);
// logImEXEvent("fcm_permission_denied", { message: err });
// });
}
render() {

View File

@@ -21,7 +21,7 @@ export const PhoneItemFormatterValidation = (getFieldValue, name) => ({
return Promise.resolve();
} else {
const p = parsePhoneNumber(value, "CA");
if (p.isValid()) {
if (p && p.isValid()) {
return Promise.resolve();
} else {
return Promise.reject(i18n.t("general.validation.invalidphone"));

View File

@@ -62,13 +62,16 @@ export default function GlobalSearch() {
}`,
label: (
<Link to={`/manage/owners/${owner.id}`}>
<Space size="small" split={<Divider type="vertical" />}>
<Space size="small" split={<Divider type="vertical" />} wrap>
<span>{`${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
owner.ownr_co_nm || ""
}`}</span>
<PhoneNumberFormatter>
{owner.ownr_ph1}
</PhoneNumberFormatter>
<PhoneNumberFormatter>
{owner.ownr_ph2}
</PhoneNumberFormatter>
</Space>
</Link>
),
@@ -168,7 +171,6 @@ export default function GlobalSearch() {
<AutoComplete
options={options}
onSearch={handleSearch}
allowClear
placeholder={t("general.labels.globalsearch")}
>
<Input.Search loading={loading} />

View File

@@ -46,12 +46,16 @@ import {
} from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
import { signOutStart } from "../../redux/user/user.actions";
import { selectCurrentUser } from "../../redux/user/user.selectors";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
recentItems: selectRecentItems,
selectedHeader: selectSelectedHeader,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
@@ -69,6 +73,7 @@ const mapDispatchToProps = (dispatch) => ({
function Header({
handleMenuClick,
currentUser,
bodyshop,
selectedHeader,
signOutStart,
setBillEnterContext,
@@ -237,16 +242,26 @@ function Header({
{t("menus.header.accounting-receivables")}
</Link>
</Menu.Item>
<Menu.Item key="payables">
<Link to="/manage/accounting/payables">
{t("menus.header.accounting-payables")}
</Link>
</Menu.Item>
<Menu.Item key="payments">
<Link to="/manage/accounting/payments">
{t("menus.header.accounting-payments")}
</Link>
</Menu.Item>
{!(
(bodyshop && bodyshop.cdk_dealerid) ||
(bodyshop && bodyshop.pbs_serialnumber)
) && (
<Menu.Item key="payables">
<Link to="/manage/accounting/payables">
{t("menus.header.accounting-payables")}
</Link>
</Menu.Item>
)}
{!(
(bodyshop && bodyshop.cdk_dealerid) ||
(bodyshop && bodyshop.pbs_serialnumber)
) && (
<Menu.Item key="payments">
<Link to="/manage/accounting/payments">
{t("menus.header.accounting-payments")}
</Link>
</Menu.Item>
)}
<Menu.Item key="export-logs">
<Link to="/manage/accounting/exportlogs">
{t("menus.header.export-logs")}

View File

@@ -10,15 +10,11 @@ export default function HelpRescue() {
var bodyFormData = new FormData();
bodyFormData.append("Code", code);
bodyFormData.append("hostederrorhandling", 1);
const res1 = await fetch(
"https://secure.logmeinrescue.com/Customer/Code.aspx",
{
mode: "no-cors",
method: "POST",
body: bodyFormData,
}
);
console.log("handleClick -> res1", await res1.text());
await fetch("https://secure.logmeinrescue.com/Customer/Code.aspx", {
mode: "no-cors",
method: "POST",
body: bodyFormData,
});
};
return (
@@ -40,7 +36,6 @@ export default function HelpRescue() {
method="post"
id="logmeinsupport"
onSubmit={(...props) => {
console.log(`props`, props);
alert();
}}
>

View File

@@ -44,7 +44,7 @@ export function Jobd3RdPartyModal({ bodyshop, jobId }) {
};
const handleFinish = (values) => {
const { sendtype, ...restVals } = values;
console.log(restVals);
GenerateDocument(
{
name: TemplateList("job_special").thirdpartypayer.key,

View File

@@ -56,7 +56,7 @@ export function ScheduleEventColor({ bodyshop, event }) {
<Menu.Item key={"null"}>{t("general.actions.clear")}</Menu.Item>
</Menu>
);
console.log(`event`, event);
return (
<Dropdown overlay={menu}>
<a href=" #" onClick={(e) => e.preventDefault()}>

View File

@@ -106,6 +106,12 @@ export function ScheduleEventComponent({
jobid={event.job.id}
/>
</DataLabel>
<DataLabel label={t("jobs.fields.ownr_ph2")}>
<ChatOpenButton
phone={event.job && event.job.ownr_ph2}
jobid={event.job.id}
/>
</DataLabel>
<DataLabel label={t("jobs.fields.alt_transport")}>
{(event.job && event.job.alt_transport) || ""}
<ScheduleAtChange job={event && event.job} />
@@ -170,7 +176,7 @@ export function ScheduleEventComponent({
t("appointments.labels.reminder", {
shopname: bodyshop.shopname,
date: moment(event.start).format("MM/DD/YYYY"),
time: moment(event.start).format("HH:MM a"),
time: moment(event.start).format("HH:mm a"),
})
);
setVisible(false);
@@ -203,6 +209,9 @@ export function ScheduleEventComponent({
jobId: event.job.id,
job: event.job,
previousEvent: event.id,
color: event.color,
alt_transport: event.job && event.job.alt_transport,
note: event.note,
},
});
}}

View File

@@ -55,7 +55,6 @@ export default function JobBillsTotalComponent({
);
}
if (il.deductedfromlbr) {
console.log(i, "Deducting from labor.");
lbrAdjustments = lbrAdjustments.add(
Dinero({
amount: Math.round((il.actual_price || 0) * 100),

View File

@@ -18,6 +18,7 @@ import DateTimePicker from "../../../form-date-time-picker/form-date-time-picker
import moment from "moment-business-days";
import { insertAuditTrail } from "../../../../redux/application/application.actions";
import AuditTrailMapping from "../../../../utils/AuditTrailMappings";
import { UPDATE_OWNER } from "../../../../graphql/owners.queries";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -41,6 +42,8 @@ export function JobChecklistForm({
const [intakeJob] = useMutation(UPDATE_JOB);
const [loading, setLoading] = useState(false);
const [markAptArrived] = useMutation(MARK_LATEST_APPOINTMENT_AS_ARRIVED);
const [updateOwner] = useMutation(UPDATE_OWNER);
const { jobId } = useParams();
const history = useHistory();
const search = queryString.parse(useLocation().search);
@@ -61,14 +64,16 @@ export function JobChecklistForm({
...(type === "intake" && { actual_in: new Date() }),
...(type === "intake" && {
production_vars: {
...job.production_vars,
...values.production_vars,
...(job ? job.production_vars : {}),
note:
values.production_vars &&
values.production_vars.note &&
values.production_vars.note !== ""
? job.production_vars && values.production_vars.note
: job.production_vars && job.production_vars.note,
? values &&
values.production_vars &&
values.production_vars.note
: job && job.production_vars && job.production_vars.note,
},
}),
...(type === "intake" && {
@@ -114,6 +119,24 @@ export function JobChecklistForm({
});
}
}
if (type === "intake" && job.owner && job.owner.id) {
//Updae Owner Allow to Text
const updateOwnerResult = await updateOwner({
variables: {
ownerId: job.owner.id,
owner: { allow_text_message: values.allow_text_message },
},
});
if (!!updateOwnerResult.errors) {
notification["error"]({
message: t("checklist.errors.complete", {
error: JSON.stringify(result.errors),
}),
});
}
}
setLoading(false);
if (!!!result.errors) {
@@ -144,7 +167,11 @@ export function JobChecklistForm({
title={t("checklist.labels.checklist")}
extra={
!readOnly && (
<Button loading={loading} onClick={() => form.submit()}>
<Button
loading={loading}
type="primary"
onClick={() => form.submit()}
>
{t("general.actions.submit")}
</Button>
)
@@ -156,14 +183,17 @@ export function JobChecklistForm({
initialValues={{
...(type === "intake" && {
addToProduction: true,
allow_text_message: job.owner && job.owner.allow_text_message,
scheduled_completion:
(job && job.scheduled_completion) ||
moment().businessAdd(
(job.labhrs.aggregate.sum.mod_lb_hrs +
job.larhrs.aggregate.sum.mod_lb_hrs) /
bodyshop.target_touchtime,
"days"
),
(job.labbrs && job.larhrs
? moment().businessAdd(
(job.labhrs.aggregate.sum.mod_lb_hrs +
job.larhrs.aggregate.sum.mod_lb_hrs) /
bodyshop.target_touchtime,
"days"
)
: null),
scheduled_delivery: job && job.scheduled_delivery,
}),
...(type === "deliver" && {
@@ -191,6 +221,14 @@ export function JobChecklistForm({
>
<Switch disabled={readOnly} />
</Form.Item>
<Form.Item
name="allow_text_message"
valuePropName="checked"
label={t("checklist.labels.allow_text_message")}
disabled={readOnly}
>
<Switch disabled={readOnly} />
</Form.Item>
<Form.Item
name="scheduled_completion"
label={t("jobs.fields.scheduled_completion")}
@@ -215,6 +253,7 @@ export function JobChecklistForm({
name={["production_vars", "note"]}
label={t("jobs.fields.production_vars.note")}
disabled={readOnly}
trigger="onChange"
>
<Input.TextArea rows={3} disabled={readOnly} />
</Form.Item>

View File

@@ -34,7 +34,7 @@ export default function JobIntakeTemplateList({ templates }) {
const renderAllTemplates = async () => {
logImEXEvent("checklist_render_all_templates");
setLoading(true);
console.log("templates :>> ", templates);
await GenerateDocuments(
templates.map((key) => {
return { name: key, variables: { id: jobId } };

View File

@@ -35,7 +35,7 @@ export function JobCostingModalContainer({
async function getData() {
if (jobId && visible) {
const { data } = await axios.post("/job/costing", { jobid: jobId });
console.log(data);
setCostingData(data);
}
}

View File

@@ -77,7 +77,6 @@ export default function JobCostingPartsTable({ data, summaryData }) {
.includes(searchText.toLowerCase())
);
console.log("data :>> ", data);
return (
<div>
<Table

View File

@@ -112,60 +112,46 @@ export function JobDetailCards({ setPrintCenterContext }) {
<Divider type="horizontal" />
<Row gutter={[16, 16]}>
<Col {...span}>
<Card.Grid style={{ width: "100%", height: "100%" }}>
<JobDetailCardsInsuranceComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Card.Grid>
<JobDetailCardsInsuranceComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<Card.Grid style={{ width: "100%", height: "100%" }}>
<JobDetailCardsTotalsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Card.Grid>
<JobDetailCardsTotalsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<Card.Grid style={{ width: "100%", height: "100%" }}>
<JobDetailCardsDatesComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Card.Grid>
<JobDetailCardsDatesComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<Card.Grid style={{ width: "100%", height: "100%" }}>
<JobDetailCardsPartsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Card.Grid>
<JobDetailCardsPartsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<Card.Grid style={{ width: "100%", height: "100%" }}>
<JobDetailCardsNotesComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Card.Grid>
<JobDetailCardsNotesComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<Card.Grid style={{ width: "100%", height: "100%" }}>
<JobDetailCardsDocumentsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Card.Grid>
<JobDetailCardsDocumentsComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
<Col {...span}>
<Card.Grid style={{ width: "100%", height: "100%" }}>
<JobDetailCardsDamageComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Card.Grid>
<JobDetailCardsDamageComponent
loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</Col>
</Row>
</Card>

View File

@@ -1,7 +1,7 @@
import { Timeline } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { DateFormatter } from "../../utils/DateFormatter";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import CardTemplate from "./job-detail-cards.template.component";
export default function JobDetailCardsDatesComponent({ loading, data }) {
@@ -26,80 +26,86 @@ export default function JobDetailCardsDatesComponent({ loading, data }) {
) ? (
<div>{t("jobs.errors.nodates")}</div>
) : null}
{data.date_last_contacted ? (
<Timeline.Item>
<label>{t("jobs.fields.date_last_contacted")}: </label>
<DateTimeFormatter>{data.date_last_contacted}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_open ? (
<Timeline.Item>
<label>{t("jobs.fields.date_open")}: </label>
<DateFormatter>{data.date_open}</DateFormatter>
<DateTimeFormatter>{data.date_open}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_estimated ? (
<Timeline.Item>
<label>{t("jobs.fields.date_estimated")}: </label>
<DateFormatter>{data.date_estimated}</DateFormatter>
<DateTimeFormatter>{data.date_estimated}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_scheduled ? (
<Timeline.Item>
<label>{t("jobs.fields.date_scheduled")}: </label>
<DateFormatter>{data.date_scheduled}</DateFormatter>
<DateTimeFormatter>{data.date_scheduled}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.scheduled_in ? (
<Timeline.Item>
<label>{t("jobs.fields.scheduled_in")}: </label>
<DateFormatter>{data.scheduled_in}</DateFormatter>
<DateTimeFormatter>{data.scheduled_in}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.actual_in ? (
<Timeline.Item>
<label>{t("jobs.fields.actual_in")}: </label>
<DateFormatter>{data.actual_in}</DateFormatter>
<DateTimeFormatter>{data.actual_in}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.scheduled_completion ? (
<Timeline.Item>
<label>{t("jobs.fields.scheduled_completion")}: </label>
<DateFormatter>{data.scheduled_completion}</DateFormatter>
<DateTimeFormatter>{data.scheduled_completion}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.actual_completion ? (
<Timeline.Item>
<label>{t("jobs.fields.actual_completion")}: </label>
<DateFormatter>{data.actual_completion}</DateFormatter>
<DateTimeFormatter>{data.actual_completion}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.scheduled_delivery ? (
<Timeline.Item>
<label>{t("jobs.fields.scheduled_delivery")}: </label>
<DateFormatter>{data.scheduled_delivery}</DateFormatter>
<DateTimeFormatter>{data.scheduled_delivery}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.actual_delivery ? (
<Timeline.Item>
<label>{t("jobs.fields.actual_delivery")}: </label>
<DateFormatter>{data.actual_delivery}</DateFormatter>
<DateTimeFormatter>{data.actual_delivery}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_invoiced ? (
<Timeline.Item>
<label>{t("jobs.fields.date_invoiced")}: </label>
<DateFormatter>{data.date_invoiced}</DateFormatter>
<DateTimeFormatter>{data.date_invoiced}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_exported ? (
<Timeline.Item>
<label>{t("jobs.fields.date_exported")}: </label>
<DateFormatter>{data.date_exported}</DateFormatter>
<DateTimeFormatter>{data.date_exported}</DateTimeFormatter>
</Timeline.Item>
) : null}
</Timeline>

View File

@@ -1,8 +1,8 @@
import { Carousel } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { GenerateThumbUrl } from "../jobs-documents-gallery/job-documents.utility";
import CardTemplate from "./job-detail-cards.template.component";
import { DetermineFileType } from "../documents-upload/documents-upload.utility";
export default function JobDetailCardsDocumentsComponent({ loading, data }) {
const { t } = useTranslation();
@@ -22,15 +22,7 @@ export default function JobDetailCardsDocumentsComponent({ loading, data }) {
{data.documents.length > 0 ? (
<Carousel autoplay>
{data.documents.map((item) => (
<img
key={item.id}
src={`${
process.env.REACT_APP_CLOUDINARY_ENDPOINT
}/${DetermineFileType(item.type)}/upload/${
process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS
}/${item.key}`}
alt={item.name}
/>
<img key={item.id} src={GenerateThumbUrl(item)} alt={item.name} />
))}
</Carousel>
) : (

View File

@@ -12,11 +12,13 @@ export default function JobDetailCardTemplate({
if (extraLink) extra = { extra: <Link to={extraLink}>More</Link> };
return (
<Card
size='small'
className='job-card'
size="small"
className="job-card"
title={title}
loading={loading}
{...extra}>
style={{ height: "100%" }}
{...extra}
>
{otherProps.children}
</Card>
);

View File

@@ -36,6 +36,7 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re
// import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
import _ from "lodash";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -161,7 +162,11 @@ export function JobLinesComponent({
ellipsis: true,
render: (text, record) => (
<>
<CurrencyFormatter>{record.act_price}</CurrencyFormatter>
<CurrencyFormatter>
{record.db_ref === "900510" || record.db_ref === "900511"
? record.prt_dsmk_m
: record.act_price}
</CurrencyFormatter>
{record.prt_dsmk_p && record.prt_dsmk_p !== 0 ? (
<span
style={{ marginLeft: ".2rem" }}
@@ -295,18 +300,17 @@ export function JobLinesComponent({
onClick={async () => {
await deleteJobLine({
variables: { joblineId: record.id },
// update(cache) {
// cache.modify({
// id: cache.identify(job),
// fields: {
// joblines(existingJobLines, { readField }) {
// return existingJobLines.filter(
// (jlRef) => record.id !== readField("id", jlRef)
// );
// },
// },
// });
// },
update(cache) {
cache.modify({
fields: {
joblines(existingJobLines, { readField }) {
return existingJobLines.filter(
(jlRef) => record.id !== readField("id", jlRef)
);
},
},
});
},
});
await axios.post("/job/totalsssu", {
id: job.id,
@@ -334,10 +338,12 @@ export function JobLinesComponent({
const markedTypes = [e.key];
if (e.key === "PAN") markedTypes.push("PAP");
if (e.key === "PAS") markedTypes.push("PASL");
setSelectedLines([
...selectedLines,
...jobLines.filter((item) => markedTypes.includes(item.part_type)),
]);
setSelectedLines(
_.uniq([
...selectedLines,
...jobLines.filter((item) => markedTypes.includes(item.part_type)),
])
);
}
};
@@ -400,7 +406,7 @@ export function JobLinesComponent({
setState({
...state,
filteredInfo: {
part_type: ["PAN,PAC,PAR,PAL,PAA,PAM,PAP,PAS,PASL"],
part_type: ["PAN,PAC,PAR,PAL,PAA,PAM,PAP,PAS,PASL,PAG"],
},
});
}}
@@ -435,7 +441,7 @@ export function JobLinesComponent({
columns={columns}
rowKey="id"
loading={loading}
pagination={{ position: "top", defaultPageSize: 50 }}
pagination={false}
dataSource={jobLines}
onChange={handleTableChange}
scroll={{

View File

@@ -72,7 +72,7 @@ export function JobLineStatusPopup({ bodyshop, jobline, disabled }) {
);
return (
<div
style={{ width: "100%", minHeight: "2rem", cursor: "pointer" }}
style={{ width: "100%", minHeight: "1rem", cursor: "pointer" }}
onClick={() => !disabled && setEditing(true)}
>
{jobline.status}

View File

@@ -1,4 +1,4 @@
import { Form, Input, InputNumber, Modal, Select } from "antd";
import { Form, Input, InputNumber, Modal, Select, Switch } from "antd";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import InputCurrency from "../form-items-formatted/currency-form-item.component";
@@ -115,18 +115,18 @@ export default function JobLinesUpsertModalComponent({
<Form.Item
label={t("joblines.fields.mod_lb_hrs")}
name="mod_lb_hrs"
// rules={[
// ({ getFieldValue }) => ({
// validator(rule, value) {
// if (!!getFieldValue("mod_lbr_ty") === !!value) {
// return Promise.resolve();
// }
// return Promise.reject(
// t("joblines.validations.hrsrequirediflbrtyp")
// );
// },
// }),
// ]}
rules={[
({ getFieldValue }) => ({
validator(rule, value) {
if (!!getFieldValue("mod_lbr_ty") === !!value) {
return Promise.resolve();
}
return Promise.reject(
t("joblines.validations.hrsrequirediflbrtyp")
);
},
}),
]}
>
<InputNumber precision={1} />
</Form.Item>
@@ -169,49 +169,49 @@ export default function JobLinesUpsertModalComponent({
<Form.Item
label={t("joblines.fields.part_qty")}
name="part_qty"
// rules={[
// ({ getFieldValue }) => ({
// validator(rule, value) {
// if (!!getFieldValue("part_type") === !!value) {
// return Promise.resolve();
// }
// return Promise.reject(
// t("joblines.validations.requiredifparttype")
// );
// },
// }),
// ]}
rules={[
({ getFieldValue }) => ({
validator(rule, value) {
if (!!getFieldValue("part_type") === !!value) {
return Promise.resolve();
}
return Promise.reject(
t("joblines.validations.requiredifparttype")
);
},
}),
]}
>
<InputNumber precision={0} min={0} />
</Form.Item>
<Form.Item label={t("joblines.fields.db_price")} name="db_price">
{/* <Form.Item label={t("joblines.fields.db_price")} name="db_price">
<InputCurrency precision={2} min={0} />
</Form.Item>
</Form.Item> */}
<Form.Item
label={t("joblines.fields.act_price")}
name="act_price"
// rules={[
// ({ getFieldValue }) => ({
// validator(rule, value) {
// if (!value || getFieldValue("part_type") !== "PAE") {
// return Promise.resolve();
// }
// return Promise.reject(
// t("joblines.validations.zeropriceexistingpart")
// );
// },
// }),
// ({ getFieldValue }) => ({
// validator(rule, value) {
// if (!!getFieldValue("part_type") === !!value) {
// return Promise.resolve();
// }
// return Promise.reject(
// t("joblines.validations.requiredifparttype")
// );
// },
// }),
// ]}
rules={[
({ getFieldValue }) => ({
validator(rule, value) {
if (!value || getFieldValue("part_type") !== "PAE") {
return Promise.resolve();
}
return Promise.reject(
t("joblines.validations.zeropriceexistingpart")
);
},
}),
({ getFieldValue }) => ({
validator(rule, value) {
if (!!getFieldValue("part_type") === !!value) {
return Promise.resolve();
}
return Promise.reject(
t("joblines.validations.requiredifparttype")
);
},
}),
]}
>
<InputCurrency precision={2} min={0} />
</Form.Item>
@@ -222,6 +222,14 @@ export default function JobLinesUpsertModalComponent({
>
<InputNumber precision={0} min={0} max={100} />
</Form.Item>
<Form.Item
label={t("joblines.fields.tax_part")}
name="tax_part"
valuePropName="checked"
initialValue={true}
>
<Switch />
</Form.Item>
</LayoutFormRow>
</Form>
</Modal>

View File

@@ -44,6 +44,7 @@ function JobLinesUpsertModalContainer({
},
],
},
refetchQueries: ["GET_LINE_TICKET_BY_PK"],
});
if (!r.errors) {
await Axios.post("/job/totalsssu", {
@@ -69,6 +70,7 @@ function JobLinesUpsertModalContainer({
lineId: jobLineEditModal.context.id,
line: values,
},
refetchQueries: ["GET_LINE_TICKET_BY_PK"],
});
if (!r.errors) {
notification["success"]({

View File

@@ -21,7 +21,8 @@ export default function JobReconciliationBillsTable({
title: t("billlines.fields.line_desc"),
dataIndex: "line_desc",
key: "line_desc",
width: "35%",
ellipsis: true,
minWidth: "65rem",
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
sortOrder:
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
@@ -30,7 +31,7 @@ export default function JobReconciliationBillsTable({
title: t("billlines.labels.from"),
dataIndex: "from",
key: "from",
width: "20%",
ellipsis: true,
render: (text, record) =>
`${record.bill.vendor && record.bill.vendor.name} / ${
@@ -42,6 +43,7 @@ export default function JobReconciliationBillsTable({
dataIndex: "actual_price",
key: "actual_price",
sorter: (a, b) => a.actual_price - b.actual_price,
width: "7rem",
sortOrder:
state.sortedInfo.columnKey === "actual_price" && state.sortedInfo.order,
render: (text, record) => (
@@ -53,6 +55,7 @@ export default function JobReconciliationBillsTable({
dataIndex: "actual_cost",
key: "actual_cost",
sorter: (a, b) => a.actual_cost - b.actual_cost,
width: "7rem",
sortOrder:
state.sortedInfo.columnKey === "actual_cost" && state.sortedInfo.order,
render: (text, record) => (
@@ -64,6 +67,7 @@ export default function JobReconciliationBillsTable({
dataIndex: "quantity",
key: "quantity",
sorter: (a, b) => a.quantity - b.quantity,
width: "4rem",
sortOrder:
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
},
@@ -72,9 +76,11 @@ export default function JobReconciliationBillsTable({
dataIndex: "is_credit_memo",
key: "is_credit_memo",
sorter: (a, b) => a.bill.is_credit_memo - b.bill.is_credit_memo,
width: "8rem",
sortOrder:
state.sortedInfo.columnKey === "is_credit_memo" &&
state.sortedInfo.order,
render: (text, record) => (
<Checkbox disabled checked={record.bill.is_credit_memo} />
),
@@ -94,7 +100,7 @@ export default function JobReconciliationBillsTable({
<Table
pagination={false}
size="small"
scroll={{ y: "80vh", x: true }}
scroll={{ y: "60vh" }}
columns={columns}
rowKey="id"
dataSource={invoiceLineData}
@@ -102,6 +108,9 @@ export default function JobReconciliationBillsTable({
rowSelection={{
onChange: handleOnRowClick,
selectedRowKeys: selectedLines,
getCheckboxProps: (record) => {
return { disabled: record.deductedfromlbr };
},
}}
/>
</div>

View File

@@ -1,12 +1,12 @@
.imex-reconciliation-modal {
top: 20px;
.ant-modal-content {
height: 95vh;
display: flex;
flex-direction: column;
.ant-modal-body {
display: flex;
flex: 1;
}
}
// .ant-modal-content {
// height: 95vh;
// display: flex;
// flex-direction: column;
// .ant-modal-body {
// display: flex;
// flex: 1;
// }
// }
}

View File

@@ -23,6 +23,7 @@ export default function JobReconcilitionPartsTable({
dataIndex: "line_desc",
key: "line_desc",
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
ellipses: true,
sortOrder:
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
},
@@ -57,6 +58,7 @@ export default function JobReconcilitionPartsTable({
dataIndex: "act_price",
key: "act_price",
sorter: (a, b) => a.act_price - b.act_price,
width: "7rem",
sortOrder:
state.sortedInfo.columnKey === "act_price" && state.sortedInfo.order,
@@ -68,10 +70,12 @@ export default function JobReconcilitionPartsTable({
title: t("joblines.fields.part_qty"),
dataIndex: "part_qty",
key: "part_qty",
width: "4rem",
},
{
title: t("joblines.fields.total"),
dataIndex: "total",
width: "7rem",
key: "total",
sorter: (a, b) => a.act_price * a.part_qty - b.act_price * b.part_qty,
sortOrder:
@@ -89,6 +93,7 @@ export default function JobReconcilitionPartsTable({
dataIndex: "status",
key: "status",
sorter: (a, b) => alphaSort(a.status, b.status),
width: "6rem",
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
},
@@ -108,7 +113,7 @@ export default function JobReconcilitionPartsTable({
pagination={false}
columns={columns}
size="small"
scroll={{ y: "80vh", x: true }}
scroll={{ y: "60vh" }}
rowKey="id"
dataSource={jobLineData}
onChange={handleTableChange}

View File

@@ -11,7 +11,7 @@ export const reconcileByAssocLine = (
const [selectedJobLines, setSelectedJobLines] = jobLineState;
const allJoblinesFromBills = billLines
.filter((bl) => bl.joblineid && !(bl.jobline && bl.jobline.removed))
.filter((bl) => bl.joblineid && bl.jobline && !bl.jobline.removed)
.map((bl) => bl.joblineid);
const duplicatedJobLinesbyInvoiceId = _.filter(
@@ -73,7 +73,7 @@ export const reconcileByPrice = (
jobLines.forEach((jl) => {
const matchingBillLineIds = billLines
.filter((bl) => bl.actual_price === jl.act_price && !jl.removed)
.filter((bl) => bl.actual_price === jl.act_price && bl.quantity === jl.part_qty && !jl.removed)
.map((bl) => bl.id);
if (matchingBillLineIds.length > 1) {

View File

@@ -1,12 +1,24 @@
import { useMutation } from "@apollo/client";
import { Button, Card, Form, notification, Popover } from "antd";
import { useMutation, useLazyQuery } from "@apollo/client";
import {
Button,
Card,
Form,
InputNumber,
notification,
Popover,
Space,
} from "antd";
import moment from "moment";
import React, { useState } from "react";
import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { INSERT_SCOREBOARD_ENTRY } from "../../graphql/scoreboard.queries";
import {
INSERT_SCOREBOARD_ENTRY,
QUERY_SCOREBOARD_ENTRY,
UPDATE_SCOREBOARD_ENTRY,
} from "../../graphql/scoreboard.queries";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
import InputNumberCalculator from "../form-input-number-calculator/form-input-number-calculator.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
export default function ScoreboardAddButton({
job,
@@ -15,17 +27,44 @@ export default function ScoreboardAddButton({
}) {
const { t } = useTranslation();
const [insertScoreboardEntry] = useMutation(INSERT_SCOREBOARD_ENTRY);
const [updateScoreboardEntry] = useMutation(UPDATE_SCOREBOARD_ENTRY);
const [loading, setLoading] = useState(false);
const [form] = Form.useForm();
const [visibility, setVisibility] = useState(false);
const [callQuery, { loading: entryLoading, data: entryData }] = useLazyQuery(
QUERY_SCOREBOARD_ENTRY
);
useEffect(() => {
if (visibility) {
callQuery({ variables: { jobid: job.id } });
}
}, [visibility, job.id, callQuery]);
useEffect(() => {
if (entryData && entryData.scoreboard && entryData.scoreboard[0]) {
form.setFieldsValue(entryData.scoreboard[0]);
}
}, [entryData, form]);
const handleFinish = async (values) => {
logImEXEvent("job_close_add_to_scoreboard");
setLoading(true);
const result = await insertScoreboardEntry({
variables: { sbInput: [{ jobid: job.id, ...values }] },
});
let result;
if (entryData && entryData.scoreboard && entryData.scoreboard[0]) {
result = await updateScoreboardEntry({
variables: {
sbId: entryData.scoreboard[0].id,
sbInput: values,
},
});
} else {
result = await insertScoreboardEntry({
variables: { sbInput: [{ jobid: job.id, ...values }] },
});
}
if (!!result.errors) {
notification["error"]({
@@ -45,53 +84,62 @@ export default function ScoreboardAddButton({
const overlay = (
<Card>
<div>
<Form
form={form}
layout="vertical"
onFinish={handleFinish}
initialValues={{}}
>
<Form.Item
label={t("scoreboard.fields.date")}
name="date"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
{entryLoading ? (
<LoadingSpinner />
) : (
<Form
form={form}
layout="vertical"
onFinish={handleFinish}
initialValues={{}}
>
<FormDatePicker />
</Form.Item>
<Form.Item
label={t("scoreboard.fields.bodyhrs")}
name="bodyhrs"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumberCalculator precision={1} />
</Form.Item>
<Form.Item
label={t("scoreboard.fields.painthrs")}
name="painthrs"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumberCalculator precision={1} />
</Form.Item>
<Form.Item
label={t("scoreboard.fields.date")}
name="date"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<FormDatePicker />
</Form.Item>
<Form.Item
label={t("scoreboard.fields.bodyhrs")}
name="bodyhrs"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber precision={1} />
</Form.Item>
<Form.Item
label={t("scoreboard.fields.painthrs")}
name="painthrs"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<InputNumber precision={1} />
</Form.Item>
<Button type="primary" htmlType="submit">
{t("general.actions.save")}
</Button>
</Form>
<Space wrap>
<Button type="primary" htmlType="submit">
{t("general.actions.save")}
</Button>
<Button onClick={() => setVisibility(false)}>
{t("general.actions.cancel")}
</Button>
</Space>
</Form>
)}
</div>
</Card>
);
@@ -100,7 +148,7 @@ export default function ScoreboardAddButton({
setLoading(true);
const v = job.joblines.reduce(
(acc, val) => {
if (val.mod_lbr_ty === "LAB")
if (val.mod_lbr_ty !== "LAR")
acc = { ...acc, bodyhrs: acc.bodyhrs + val.mod_lb_hrs };
if (val.mod_lbr_ty === "LAR")
acc = { ...acc, painthrs: acc.painthrs + val.mod_lb_hrs };

View File

@@ -22,7 +22,6 @@ export function JobsAdminClass({ bodyshop, job }) {
const [updateJob] = useMutation(UPDATE_JOB);
const handleFinish = async (values) => {
console.log(values);
setLoading(true);
const result = await updateJob({
variables: { jobId: job.id, job: values },

View File

@@ -13,7 +13,6 @@ export default function JobsAdminDatesChange({ job }) {
const [updateJob] = useMutation(UPDATE_JOB);
const handleFinish = async (values) => {
console.log(values);
setLoading(true);
const result = await updateJob({
variables: { jobId: job.id, job: values },
@@ -74,7 +73,12 @@ export default function JobsAdminDatesChange({ job }) {
<Form.Item label={t("jobs.fields.actual_in")} name="actual_in">
<DateTimePicker />
</Form.Item>
<Form.Item
label={t("jobs.fields.date_last_contacted")}
name="date_last_contacted"
>
<DateTimePicker />
</Form.Item>
<Form.Item
label={t("jobs.fields.scheduled_completion")}
name="scheduled_completion"

View File

@@ -22,10 +22,10 @@ export default function JobAdminDeleteIntake({ job }) {
mutation DELETE_DELIVERY($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { deliverychecklist: null }
_set: { deliverchecklist: null }
) {
id
deliverychecklist
deliverchecklist
}
}
`);

View File

@@ -10,7 +10,6 @@ export default function JobAdminOwnerReassociate({ job }) {
const [form] = Form.useForm();
const [updateJob] = useMutation(UPDATE_JOB);
const handleFinish = async (values) => {
console.log(values);
setLoading(true);
const result = await updateJob({
variables: { jobId: job.id, job: { ownerid: values.ownerid } },

View File

@@ -10,7 +10,6 @@ export default function JobAdminOwnerReassociate({ job }) {
const [form] = Form.useForm();
const [updateJob] = useMutation(UPDATE_JOB);
const handleFinish = async (values) => {
console.log(values);
setLoading(true);
const result = await updateJob({
variables: { jobId: job.id, job: { vehicleid: values.vehicleid } },

View File

@@ -3,8 +3,6 @@ import { gql } from "@apollo/client";
import _ from "lodash";
export const GetSupplementDelta = async (client, jobId, newLines) => {
console.log("-----Begin Supplement-----");
const {
data: { joblines: existingLinesFromDb },
} = await client.query({

View File

@@ -8,7 +8,6 @@ import {
import { Col, notification, Row } from "antd";
import Axios from "axios";
import Dinero from "dinero.js";
import _ from "lodash";
import moment from "moment";
import queryString from "query-string";
import React, { useCallback, useEffect, useState } from "react";
@@ -30,6 +29,7 @@ import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import confirmDialog from "../../utils/asyncConfirm";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import AlertComponent from "../alert/alert.component";
import JobsAvailableScan from "../jobs-available-scan/jobs-available-scan.component";
@@ -75,7 +75,7 @@ export function JobsAvailableContainer({
const client = useApolloClient();
const estDataLazyLoad = useLazyQuery(QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK);
const [loadEstData, estData] = estDataLazyLoad;
const [loadEstData, estDataRaw] = estDataLazyLoad;
const importOptionsState = useState({ overrideHeaders: false });
const importOptions = importOptionsState[0];
@@ -88,13 +88,9 @@ export function JobsAvailableContainer({
setOwnerModalVisible(false);
setInsertLoading(true);
if (
!(
estData.data &&
estData.data.available_jobs_by_pk &&
estData.data.available_jobs_by_pk.est_data
)
) {
const estData = replaceEmpty(estDataRaw.data.available_jobs_by_pk);
if (!(estData && estData.est_data)) {
//We don't have the right data. Error!
setInsertLoading(false);
notification["error"]({
@@ -102,32 +98,31 @@ export function JobsAvailableContainer({
});
return;
}
//IO-539 Check for Parts Rate on PAL for SGI use case.
await CheckTaxRates(estData.est_data, bodyshop);
console.log(estData);
const newTotals = (
await Axios.post("/job/totals", {
job: {
...estData.data.available_jobs_by_pk.est_data,
joblines: estData.data.available_jobs_by_pk.est_data.joblines.data,
...estData.est_data,
joblines: estData.est_data.joblines.data,
},
})
).data;
let existingVehicles;
if (
estData.data.available_jobs_by_pk.est_data.vehicle &&
estData.data.available_jobs_by_pk.est_data.vin
) {
if (estData.est_data.vehicle && estData.est_data.vin) {
//There's vehicle data, need to double check the VIN.
existingVehicles = await client.query({
query: SEARCH_VEHICLE_BY_VIN,
variables: {
vin: estData.data.available_jobs_by_pk.est_data.vehicle.data.v_vin,
vin: estData.est_data.vehicle.data.v_vin,
},
});
}
const newJob = {
...estData.data.available_jobs_by_pk.est_data,
...estData.est_data,
clm_total: Dinero(newTotals.totals.total_repairs).toFormat("0.00"),
owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
job_totals: newTotals,
@@ -145,16 +140,17 @@ export function JobsAvailableContainer({
: {}),
};
if (selectedOwner) {
newJob.ownerid = selectedOwner;
delete newJob.owner;
}
if (newJob.vehicleid) {
delete newJob.vehicle;
}
insertNewJob({
variables: {
job: selectedOwner
? Object.assign(
{},
newJob,
{ owner: null },
{ ownerid: selectedOwner }
)
: newJob,
job: newJob,
},
})
.then((r) => {
@@ -172,7 +168,7 @@ export function JobsAvailableContainer({
});
deleteJob({
variables: { id: estData.data.available_jobs_by_pk.id },
variables: { id: estData.id },
}).then((r) => {
refetch();
setInsertLoading(false);
@@ -195,13 +191,9 @@ export function JobsAvailableContainer({
setJobModalVisible(false);
setInsertLoading(true);
if (
!(
estData.data &&
estData.data.available_jobs_by_pk &&
estData.data.available_jobs_by_pk.est_data
)
) {
const estData = estDataRaw.data.available_jobs_by_pk;
if (!(estData && estData.est_data)) {
//We don't have the right data. Error!
setInsertLoading(false);
notification["error"]({
@@ -209,18 +201,21 @@ export function JobsAvailableContainer({
});
} else {
//create upsert job
let supp = _.cloneDeep(estData.data.available_jobs_by_pk.est_data);
let supp = replaceEmpty({ ...estData.est_data });
//IO-539 Check for Parts Rate on PAL for SGI use case.
await CheckTaxRates(supp, bodyshop);
delete supp.owner;
delete supp.vehicle;
if (importOptions.overrideHeaders) {
delete supp.ins_co_nm;
if (!importOptions.overrideHeaders) {
HeaderFields.forEach((item) => delete supp[item]);
}
let suppDelta = await GetSupplementDelta(
client,
selectedJob,
estData.data.available_jobs_by_pk.est_data.joblines.data
supp.joblines.data
);
delete supp.joblines;
@@ -279,7 +274,7 @@ export function JobsAvailableContainer({
//Job has been inserted. Clean up the available jobs record.
deleteJob({
variables: { id: estData.data.available_jobs_by_pk.id },
variables: { id: estData.id },
}).then((r) => {
refetch();
setInsertLoading(false);
@@ -305,13 +300,13 @@ export function JobsAvailableContainer({
};
const owner =
estData.data &&
estData.data.available_jobs_by_pk &&
estData.data.available_jobs_by_pk.est_data &&
estData.data.available_jobs_by_pk.est_data.owner &&
estData.data.available_jobs_by_pk.est_data.owner.data &&
!estData.data.available_jobs_by_pk.issupplement
? estData.data.available_jobs_by_pk.est_data.owner.data
estDataRaw.data &&
estDataRaw.data.available_jobs_by_pk &&
estDataRaw.data.available_jobs_by_pk.est_data &&
estDataRaw.data.available_jobs_by_pk.est_data.owner &&
estDataRaw.data.available_jobs_by_pk.est_data.owner.data &&
!estDataRaw.data.available_jobs_by_pk.issupplement
? estDataRaw.data.available_jobs_by_pk.est_data.owner.data
: null;
const onOwnerModalCancel = () => {
@@ -349,8 +344,8 @@ export function JobsAvailableContainer({
message={t("jobs.labels.creating_new_job")}
>
<OwnerFindModalContainer
loading={estData.loading}
error={estData.error}
loading={estDataRaw.loading}
error={estDataRaw.error}
owner={owner}
selectedOwner={selectedOwner}
setSelectedOwner={setSelectedOwner}
@@ -359,8 +354,8 @@ export function JobsAvailableContainer({
onCancel={onOwnerModalCancel}
/>
<JobsFindModalContainer
loading={estData.loading}
error={estData.error}
loading={estDataRaw.loading}
error={estDataRaw.error}
selectedJob={selectedJob}
setSelectedJob={setSelectedJob}
importOptionsState={importOptionsState}
@@ -390,3 +385,125 @@ export default connect(
mapStateToProps,
mapDispatchToProps
)(JobsAvailableContainer);
function replaceEmpty(someObj, replaceValue = null) {
const replacer = (key, value) =>
value === "" ? replaceValue || null : value;
//^ because you seem to want to replace (strings) "null" or "undefined" too
const temp = JSON.stringify(someObj, replacer);
return JSON.parse(temp);
}
async function CheckTaxRates(estData, bodyshop) {
//LKQ Check
if (
!estData.parts_tax_rates?.PAL ||
estData.parts_tax_rates?.PAL?.prt_tax_rt === null ||
estData.parts_tax_rates?.PAL?.prt_tax_rt === 0
) {
const res = await confirmDialog(
`ImEX Online has detected that there is a missing tax rate for LKQ parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
);
if (res) {
if (!estData.parts_tax_rates.PAL) {
estData.parts_tax_rates.PAL = {
prt_discp: 0,
prt_mktyp: true,
prt_mkupp: 0,
prt_type: "PAL",
};
}
estData.parts_tax_rates.PAL.prt_tax_rt =
bodyshop.bill_tax_rates.state_tax_rate / 100;
estData.parts_tax_rates.PAL.prt_tax_in = true;
}
}
//PAC Check
if (
!estData.parts_tax_rates?.PAC ||
estData.parts_tax_rates?.PAC?.prt_tax_rt === null ||
estData.parts_tax_rates?.PAC?.prt_tax_rt === 0
) {
const res = await confirmDialog(
`ImEX Online has detected that there is a missing tax rate for rechromed parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
);
if (res) {
if (!estData.parts_tax_rates.PAC) {
estData.parts_tax_rates.PAC = {
prt_discp: 0,
prt_mktyp: true,
prt_mkupp: 0,
prt_type: "PAC",
};
}
estData.parts_tax_rates.PAC.prt_tax_rt =
bodyshop.bill_tax_rates.state_tax_rate / 100;
estData.parts_tax_rates.PAC.prt_tax_in = true;
}
}
//PAM Check
if (
!estData.parts_tax_rates?.PAM ||
estData.parts_tax_rates?.PAM?.prt_tax_rt === null ||
estData.parts_tax_rates?.PAM?.prt_tax_rt === 0
) {
const res = await confirmDialog(
`ImEX Online has detected that there is a missing tax rate for remanufactured parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
);
if (res) {
if (!estData.parts_tax_rates.PAM) {
estData.parts_tax_rates.PAM = {
prt_discp: 0,
prt_mktyp: true,
prt_mkupp: 0,
prt_type: "PAM",
};
}
estData.parts_tax_rates.PAM.prt_tax_rt =
bodyshop.bill_tax_rates.state_tax_rate / 100;
estData.parts_tax_rates.PAM.prt_tax_in = true;
}
}
if (
!estData.parts_tax_rates?.PAR ||
estData.parts_tax_rates?.PAR?.prt_tax_rt === null ||
estData.parts_tax_rates?.PAR?.prt_tax_rt === 0
) {
const res = await confirmDialog(
`ImEX Online has detected that there is a missing tax rate for recored parts. Pressing OK will set the tax rate to ${bodyshop.bill_tax_rates.state_tax_rate}% and enable the rate. Pressing cancel will keep the tax rate as is.`
);
if (res) {
if (!estData.parts_tax_rates.PAR) {
estData.parts_tax_rates.PAR = {
prt_discp: 0,
prt_mktyp: true,
prt_mkupp: 0,
prt_type: "PAR",
};
}
estData.parts_tax_rates.PAR.prt_tax_rt =
bodyshop.bill_tax_rates.state_tax_rate / 100;
estData.parts_tax_rates.PAR.prt_tax_in = true;
}
}
//IO-1387 If a sublet line is NOT R&R, use the labor tax. If it is, use the sublet tax rate.
//Currently limited to SK shops only.
//if (bodyshop.region_config === "CA_SK") {
estData.joblines.data.forEach((jl, index) => {
if (
(jl.part_type === "PASL" || jl.part_type === "PAS") &&
jl.lbr_op !== "OP11"
) {
estData.joblines.data[index].tax_part = jl.lbr_tax;
}
//Set markup lines and tax lines as taxable.
//900510 is a mark up. 900510 is a discount.
if (jl.db_ref === "900510") {
estData.joblines.data[index].tax_part = true;
}
});
//}
}

View File

@@ -1,4 +1,4 @@
import { Button } from "antd";
import { Button, Dropdown, Menu } from "antd";
import _ from "lodash";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -12,11 +12,8 @@ const mapStateToProps = createStructuredSelector({
export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
const { t } = useTranslation();
const handleAllocate = () => {
logImEXEvent("jobs_close_allocate_auto");
const { defaults } = bodyshop.md_responsibility_centers;
const handleAllocate = (defaults) => {
form.setFieldsValue({
joblines: joblines.map((jl) => {
const ret = _.cloneDeep(jl);
@@ -32,7 +29,7 @@ export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
}
//Verify that this is also manually updated in server/job-costing
if (!jl.part_type && !jl.mod_lbr_ty) {
const lineDesc = jl.line_desc.toLowerCase();
const lineDesc = jl.line_desc ? jl.line_desc.toLowerCase() : "";
if (lineDesc.includes("shop materials")) {
ret.profitcenter_part = defaults.profits["MASH"];
} else if (lineDesc.includes("paint/materials")) {
@@ -48,8 +45,36 @@ export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
});
};
return (
<Button onClick={handleAllocate} disabled={disabled}>
const handleAutoAllocateClick = () => {
logImEXEvent("jobs_close_allocate_auto");
const { defaults } = bodyshop.md_responsibility_centers;
handleAllocate(defaults);
};
const handleMenuClick = ({ item, key, keyPath, domEvent }) => {
logImEXEvent("jobs_close_allocate_auto_dms");
handleAllocate(
bodyshop.md_responsibility_centers.dms_defaults.find(
(x) => x.name === key
)
);
};
const overlay = (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
<Menu onClick={handleMenuClick}>
{bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => (
<Menu.Item key={mapping.name}>{mapping.name}</Menu.Item>
))}
</Menu>
);
return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? (
<Dropdown overlay={overlay}>
<Button disabled={disabled}>{t("jobs.actions.dmsautoallocate")}</Button>
</Dropdown>
) : (
<Button onClick={handleAutoAllocateClick} disabled={disabled}>
{t("jobs.actions.autoallocate")}
</Button>
);

View File

@@ -13,6 +13,8 @@ import {
} from "../../redux/user/user.selectors";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import { useHistory } from "react-router-dom";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -24,57 +26,78 @@ export function JobsCloseExportButton({
currentUser,
jobId,
disabled,
setSelectedJobs,
}) {
const history = useHistory();
const { t } = useTranslation();
const [updateJob] = useMutation(UPDATE_JOB);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const [loading, setLoading] = useState(false);
const handleQbxml = async () => {
//Check if it's a CDK setup.
if (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) {
history.push(`/manage/dms?jobId=${jobId}`);
return;
}
logImEXEvent("jobs_close_export");
setLoading(true);
let QbXmlResponse;
try {
QbXmlResponse = await axios.post(
"/accounting/qbxml/receivables",
{ jobIds: [jobId] },
{
headers: {
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
},
}
);
console.log("handle -> XML", QbXmlResponse);
} catch (error) {
console.log("Error getting QBXML from Server.", error);
notification["error"]({
message: t("jobs.errors.exporting", {
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
}),
});
setLoading(false);
return;
}
//Check if it's a QBO Setup.
let PartnerResponse;
try {
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
PartnerResponse = await axios.post(
"http://localhost:1337/qb/",
// "http://609feaeae986.ngrok.io/qb/",
QbXmlResponse.data,
`/qbo/receivables`,
{
headers: {
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
},
}
jobIds: [jobId],
},
);
} catch (error) {
console.log("Error connecting to quickbooks or partner.", error);
notification["error"]({
message: t("jobs.errors.exporting-partner"),
});
setLoading(false);
return;
} else {
//Default is QBD
let QbXmlResponse;
try {
QbXmlResponse = await axios.post(
"/accounting/qbxml/receivables",
{ jobIds: [jobId] },
{
headers: {
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
},
}
);
console.log("handle -> XML", QbXmlResponse);
} catch (error) {
console.log("Error getting QBXML from Server.", error);
notification["error"]({
message: t("jobs.errors.exporting", {
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
}),
});
setLoading(false);
return;
}
try {
PartnerResponse = await axios.post(
"http://localhost:1337/qb/",
// "http://609feaeae986.ngrok.io/qb/",
QbXmlResponse.data,
{
headers: {
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
},
}
);
} catch (error) {
console.log("Error connecting to quickbooks or partner.", error);
notification["error"]({
message: t("jobs.errors.exporting-partner"),
});
setLoading(false);
return;
}
}
console.log("PartnerResponse", PartnerResponse);
@@ -147,18 +170,18 @@ export function JobsCloseExportButton({
}),
});
}
if (setSelectedJobs) {
setSelectedJobs((selectedJobs) => {
return selectedJobs.filter((i) => i !== jobId);
});
}
}
setLoading(false);
};
return (
<Button
onClick={handleQbxml}
loading={loading}
disabled={disabled}
type="dashed"
>
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
{t("jobs.actions.export")}
</Button>
);

View File

@@ -31,6 +31,7 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) {
<th>{t("joblines.fields.line_desc")}</th>
<th>{t("joblines.fields.part_type")}</th>
<th>{t("joblines.fields.act_price")}</th>
<th>{t("joblines.fields.prt_dsmk_m")}</th>
<th>{t("joblines.fields.op_code_desc")}</th>
<th>{t("joblines.fields.mod_lbr_ty")}</th>
<th>{t("joblines.fields.mod_lb_hrs")}</th>
@@ -70,6 +71,16 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) {
<ReadOnlyFormItem type="currency" />
</Form.Item>
</td>
<td>
<Form.Item
span={2}
// label={t("joblines.fields.prt_dsmk_m")}
key={`${index}prt_dsmk_m`}
name={[field.name, "prt_dsmk_m"]}
>
<ReadOnlyFormItem type="currency" />
</Form.Item>
</td>
<td>
<Form.Item
span={2}
@@ -108,7 +119,9 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) {
labelCol={{ span: 0 }}
rules={[
{
required: !!job.joblines[index].act_price,
required:
!!job.joblines[index].act_price ||
!!job.joblines[index].prt_dsmk_m,
//message: t("general.validation.required"),
},
]}

View File

@@ -2,6 +2,7 @@ import { useMutation } from "@apollo/client";
import {
Button,
Form,
Input,
notification,
Popover,
Select,
@@ -34,6 +35,7 @@ export function JobsConvertButton({
refetch,
jobRO,
insertAuditTrail,
parentFormIsFieldsTouched,
}) {
const [visible, setVisible] = useState(false);
const [loading, setLoading] = useState(false);
@@ -42,6 +44,10 @@ export function JobsConvertButton({
const [form] = Form.useForm();
const handleConvert = async (values) => {
if (parentFormIsFieldsTouched()) {
alert(t("jobs.labels.savebeforeconversion"));
return;
}
setLoading(true);
const res = await mutationConvertJob({
variables: { jobId: job.id, ...values },
@@ -112,24 +118,32 @@ export function JobsConvertButton({
</Form.Item>
)}
{bodyshop.enforce_referral && (
<Form.Item
name={"referral_source"}
label={t("jobs.fields.referralsource")}
rules={[
{
required: bodyshop.enforce_referral,
//message: t("general.validation.required"),
},
]}
>
<Select>
{bodyshop.md_referral_sources.map((s) => (
<Select.Option key={s} value={s}>
{s}
</Select.Option>
))}
</Select>
</Form.Item>
<>
<Form.Item
name={"referral_source"}
label={t("jobs.fields.referralsource")}
rules={[
{
required: bodyshop.enforce_referral,
//message: t("general.validation.required"),
},
]}
>
<Select>
{bodyshop.md_referral_sources.map((s) => (
<Select.Option key={s} value={s}>
{s}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={t("jobs.fields.referral_source_extra")}
name="referral_source_extra"
>
<Input />
</Form.Item>
</>
)}
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}

View File

@@ -150,6 +150,9 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
<Form.Item label={t("jobs.fields.loss_desc")} name="loss_desc">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.loss_of_use")} name="loss_of_use">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ponumber")} name="po_number">
<Input />
</Form.Item>
@@ -181,6 +184,12 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t("jobs.fields.referral_source_extra")}
name="referral_source_extra"
>
<Input />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>
<Collapse.Panel
@@ -191,7 +200,7 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
<JobsMarkPstExempt form={form} />
<LayoutFormRow>
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
<CurrencyInput />
<CurrencyInput min={0} />
</Form.Item>
<Form.Item label={t("jobs.fields.ded_status")} name="ded_status">
<Select>

View File

@@ -129,6 +129,19 @@ export default function JobsCreateOwnerInfoNewComponent() {
>
<FormItemPhone disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_ph2")}
name={["owner", "data", "ownr_ph2"]}
rules={[
({ getFieldValue }) =>
PhoneItemFormatterValidation(
getFieldValue,
"owner.data.ownr_ph2"
),
]}
>
<FormItemPhone disabled={!state.owner.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item

View File

@@ -84,6 +84,18 @@ export default function JobsCreateOwnerInfoSearchComponent({
tableState.sortedInfo.columnKey === "ownr_ph1" &&
tableState.sortedInfo.order,
},
{
title: t("owners.fields.ownr_ph2"),
dataIndex: "ownr_ph2",
key: "ownr_ph2",
render: (text, record) => (
<PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>
),
sorter: (a, b) => alphaSort(a.ownr_ph2, b.ownr_ph2),
sortOrder:
tableState.sortedInfo.columnKey === "ownr_ph2" &&
tableState.sortedInfo.order,
},
];
const handleTableChange = (pagination, filters, sorter) => {

View File

@@ -0,0 +1,43 @@
import { DownOutlined } from "@ant-design/icons";
import { Dropdown, Menu } from "antd";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
export function JobsDetailChangeEstimator({ disabled, form, bodyshop }) {
const handleClick = ({ item, key, keyPath }) => {
const est = item.props.value;
form.setFieldsValue(est);
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.md_estimators.map((est, idx) => (
<Menu.Item value={est} key={idx}>
{`${est.est_ct_fn} ${est.est_ct_ln}`}
</Menu.Item>
))}
</Menu>
</div>
);
return (
<Dropdown overlay={menu} disabled={disabled}>
<a
className="ant-dropdown-link"
href=" #"
onClick={(e) => e.preventDefault()}
>
<DownOutlined />
</a>
</Dropdown>
);
}
export default connect(mapStateToProps, null)(JobsDetailChangeEstimator);

View File

@@ -0,0 +1,43 @@
import { DownOutlined } from "@ant-design/icons";
import { Dropdown, Menu } from "antd";
import React from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
export function JobsDetailChangeFilehandler({ disabled, form, bodyshop }) {
const handleClick = ({ item, key, keyPath }) => {
const est = item.props.value;
form.setFieldsValue(est);
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.md_filehandlers.map((est, idx) => (
<Menu.Item value={est} key={idx}>
{`${est.ins_ct_fn} ${est.ins_ct_ln}`}
</Menu.Item>
))}
</Menu>
</div>
);
return (
<Dropdown overlay={menu} disabled={disabled}>
<a
className="ant-dropdown-link"
href=" #"
onClick={(e) => e.preventDefault()}
>
<DownOutlined />
</a>
</Dropdown>
);
}
export default connect(mapStateToProps, null)(JobsDetailChangeFilehandler);

View File

@@ -69,6 +69,18 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
</Tooltip>
</FormRow>
<FormRow header={t("jobs.forms.repairdates")}>
<Form.Item
label={t("jobs.fields.date_last_contacted")}
name="date_last_contacted"
>
<DateTimePicker />
</Form.Item>
<Form.Item
label={t("jobs.fields.date_next_contact")}
name="date_next_contact"
>
<DateTimePicker />
</Form.Item>
<Form.Item
label={t("jobs.fields.scheduled_completion")}
name="scheduled_completion"
@@ -93,7 +105,6 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
);
}}
</Form.Item>
<Form.Item
label={t("jobs.fields.scheduled_delivery")}
name="scheduled_delivery"

View File

@@ -1,4 +1,14 @@
import { Col, Form, Input, InputNumber, Row, Select, Switch } from "antd";
import {
Col,
Divider,
Form,
Input,
InputNumber,
Row,
Select,
Space,
Switch,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -12,8 +22,9 @@ import FormItemPhone, {
PhoneItemFormatterValidation,
} from "../form-items-formatted/phone-form-item.component";
import Car from "../job-damage-visual/job-damage-visual.component";
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
import FormRow from "../layout-form-row/layout-form-row.component";
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
bodyshop: selectBodyshop,
@@ -44,7 +55,14 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
</Select>
</Form.Item>
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
<CurrencyInput disabled={jobRO} />
<CurrencyInput disabled={jobRO} min={0} />
</Form.Item>
<Form.Item label={t("jobs.fields.ded_note")} name="ded_note">
<Select disabled={jobRO}>
{bodyshop.md_ded_notes.map((n, index) => (
<Select.Option key={index}>{n}</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item label={t("jobs.fields.policy_no")} name="policy_no">
<Input disabled={jobRO} />
@@ -68,7 +86,15 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
<Form.Item label={t("jobs.fields.ins_city")} name="ins_city">
<Input disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_ct_ln")} name="ins_ct_ln">
<Form.Item
label={
<Space>
{t("jobs.fields.ins_ct_ln")}
<JobsDetailChangeFileHandler form={form} disabled={jobRO} />
</Space>
}
name="ins_ct_ln"
>
<Input disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_ct_fn")} name="ins_ct_fn">
@@ -114,6 +140,12 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
))}
</Select>
</Form.Item>
<Form.Item
label={t("jobs.fields.referral_source_extra")}
name="referral_source_extra"
>
<Input disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.alt_transport")} name="alt_transport">
<Select disabled={jobRO} allowClear>
{bodyshop.appt_alt_transport.map((s) => (
@@ -133,6 +165,9 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
<Form.Item label={t("jobs.fields.loss_date")} name="loss_date">
<FormDatePicker disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.loss_of_use")} name="loss_of_use">
<Input disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.kmin")} name="kmin">
<InputNumber precision={0} min={0} disabled={jobRO} />
</Form.Item>
@@ -185,12 +220,27 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
)}
</Col>
</Row>
<Divider
orientation="left"
type="horizontal"
style={{ marginTop: ".8rem", float: "right" }}
>
{t("jobs.forms.appraiserinfo")}
</Divider>
<FormRow header={t("jobs.forms.appraiserinfo")}>
<FormRow noDivider>
<Form.Item label={t("jobs.fields.est_co_nm")} name="est_co_nm">
<Input disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.est_ct_fn")} name="est_ct_fn">
<Form.Item
label={
<Space>
{t("jobs.fields.est_ct_fn")}
<JobsDetailChangeEstimator form={form} disabled={jobRO} />
</Space>
}
name="est_ct_fn"
>
<Input disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.est_ct_ln")} name="est_ct_ln">

View File

@@ -101,6 +101,7 @@ export function JobsDetailHeaderActions({
context: {
jobId: job.id,
job: job,
alt_transport: job.alt_transport,
},
});
}}

Some files were not shown because too many files have changed in this diff Show More