Compare commits

...

257 Commits

Author SHA1 Message Date
Allan Carr
44f2287b07 IO-2295 Individual Note Print File Name contained {{ro_number}} 2023-05-23 13:38:55 -07:00
Patrick Fic
8f91416623 Merged in release/2023-05-19 (pull request #796)
Release/2023 05 19
2023-05-19 17:17:47 +00:00
Allan Carr
a18dbbb6c4 Merged in feature/IO-2293-Autohouse-Job-Cost-Dinero-Type-Cast (pull request #794)
IO-2293 Autohouse & Job Costing Dinero Type Casting

Approved-by: Patrick Fic
2023-05-19 17:02:05 +00:00
Allan Carr
57d8ca5829 IO-2293 Autohouse & Job Costing Dinero Type Casting
All type cast to Dinero round to integer to prevent cast errors
2023-05-19 09:39:37 -07:00
Patrick Fic
4c6a2d6d63 Merged in release/2023-05-19 (pull request #793)
Release/2023 05 19
2023-05-18 22:05:08 +00:00
Patrick Fic
5861d0e9b6 IO-2289 Add betterment description to translation 2023-05-17 13:46:37 -07:00
Patrick Fic
e36904794b IO-2274 Add typing to notes. 2023-05-17 13:31:15 -07:00
Patrick Fic
1c89d12034 IO-2286 Resolve duplication of cost centers when sorting labor allocations. 2023-05-17 12:36:15 -07:00
Patrick Fic
5e36a4ae89 IO-2275 Remove PVRT and GST References in USA App. 2023-05-17 12:09:21 -07:00
Patrick Fic
f553307587 Added rounding to job costing for adjustments. 2023-05-17 10:11:27 -07:00
Patrick Fic
2c80c81197 Added tasks presets to database schema. 2023-05-17 07:39:23 -07:00
Patrick Fic
9d865cf130 Merged in release/2023-05-19 (pull request #789)
IO-2258 Scoreboard Chart
2023-05-16 18:34:13 +00:00
Allan Carr
8e119ce0dd Merged in feature/IO-2258-Scoreboard-Chart-Inconsistencies (pull request #788)
IO-2258 Scoreboard Chart

Approved-by: Patrick Fic
2023-05-16 18:33:34 +00:00
Allan Carr
fe49161718 IO-2258 Scoreboard Chart
Add in target paint and body to the overall calculation to bump the start value up to the target instead of zero.
2023-05-15 15:18:24 -07:00
Patrick Fic
040e366335 Merged in release/2023-05-12 (pull request #786)
Release/2023 05 12
2023-05-12 18:18:04 +00:00
Patrick Fic
4655663dd8 Merged in release/2023-05-12 (pull request #785)
Release/2023 05 12
2023-05-12 17:14:31 +00:00
Allan Carr
6e1fbda79b Merged in feature/IO-2261-opensearch-replacements (pull request #784)
IO-2261 Add missing fields to return querys

Approved-by: Patrick Fic
2023-05-12 17:14:04 +00:00
Allan Carr
b2f616f1eb IO-2261 Add missing fields to return querys
Customer info missing on return
2023-05-12 10:12:49 -07:00
Patrick Fic
76eec7bebc Merged in release/2023-05-12 (pull request #783)
IO-2261 Remove duplicate fields and add created_at into return querys
2023-05-12 16:32:51 +00:00
Allan Carr
aa5f405e1b Merged in feature/IO-2261-opensearch-replacements (pull request #782)
IO-2261 Remove duplicate fields and add created_at into return querys

Approved-by: Patrick Fic
2023-05-12 15:26:05 +00:00
Allan Carr
ca9752d119 IO-2261 Remove duplicate fields and add created_at into return querys 2023-05-12 08:23:16 -07:00
Patrick Fic
45b4af5225 Merged in release/2023-05-12 (pull request #781)
Release/2023 05 12
2023-05-11 23:39:04 +00:00
Allan Carr
d2d310cf57 Merged in feature/IO-2190-Autohouse (pull request #780)
IO-2190 Paint Costs for JC if Cost/Hr is 0

Approved-by: Patrick Fic
2023-05-11 23:38:42 +00:00
Allan Carr
5d1a7657a9 Merged in feature/IO-2265-Autohouse-Extract (pull request #779)
IO-2190 Allow for 0 in JC/Hr rate

Approved-by: Patrick Fic
2023-05-11 23:38:25 +00:00
Allan Carr
5cb17994cd IO-2190 Allow for 0 in JC/Hr rate 2023-05-11 16:09:30 -07:00
Allan Carr
dab78e3dc9 IO-2190 Paint Costs for JC if Cost/Hr is 0 2023-05-11 16:07:28 -07:00
Patrick Fic
1232f28b3d Merged in release/2023-05-12 (pull request #778)
IO-2261 Modify Opensearch Data after payment update
2023-05-11 21:42:57 +00:00
Allan Carr
8e8d40d4b0 Merged in feature/IO-2261-opensearch-replacements (pull request #777)
IO-2261 Modify Opensearch Data after payment update

Approved-by: Patrick Fic
2023-05-11 21:42:24 +00:00
Allan Carr
7fae408454 IO-2261 Modify Opensearch Data after payment update 2023-05-11 14:38:09 -07:00
Patrick Fic
1cdafaa2cc Merged in release/2023-05-12 (pull request #776)
Release/2023 05 12
2023-05-11 14:50:33 +00:00
Allan Carr
b9ca7ef2e3 Merged in feature/IO-2271-Country-Region (pull request #775)
Feature/IO-2271 Country Region

Approved-by: Patrick Fic
2023-05-11 14:50:07 +00:00
Allan Carr
60867ae4dc IO-2271 Country Region Print Center Modification
Allow items to be hidden by Country Code only from region
2023-05-10 18:03:42 -07:00
Allan Carr
b0ddb62ac0 Merged in feature/IO-2265-Autohouse-Extract (pull request #773)
IO-2265 Autohouse Extract Remove Customer Info

Approved-by: Patrick Fic
2023-05-10 15:24:27 +00:00
Allan Carr
39a4646339 IO-2271 Country Region for Print Center
Hide reports based on Country Code for Region
2023-05-09 18:11:06 -07:00
Allan Carr
584322819f IO-2265 Autohouse Extract Remove Customer Info 2023-05-09 16:51:55 -07:00
Patrick Fic
051ee347a9 Merged in release/2023-05-05 (pull request #768)
Release/2023 05 05
2023-05-05 22:51:16 +00:00
Patrick Fic
acf1b387de Merged in release/2023-05-05 (pull request #767)
Release/2023 05 05
2023-05-05 22:03:21 +00:00
John Allen Delos Reyes
d350515c90 Merged in feature/IO-1722-job-size-color (pull request #763)
Feature/IO-1722 job size color

Approved-by: Patrick Fic
2023-05-05 22:02:55 +00:00
Allan Carr
121e579388 Merged in feature/IO-2261-opensearch-replacements (pull request #766)
IO-2261 Missing loader handler for owner_owing, correct payment

Approved-by: Patrick Fic
2023-05-05 22:02:03 +00:00
Allan Carr
cf5ebb8130 IO-2261 Missing loader for owner_owing 2023-05-05 14:24:00 -07:00
Allan Carr
2dabf3c811 IO-2261 Missing loader handler for owner_owing, correct payment 2023-05-05 14:03:05 -07:00
swtmply
04509fa587 IO-1722 adjusted logic for card color 2023-05-06 04:56:03 +08:00
swtmply
56fef0f43c IO-1722 Added reset button 2023-05-06 04:55:21 +08:00
Patrick Fic
42702ef015 Merged in release/2023-05-05 (pull request #765)
Release/2023 05 05
2023-05-05 20:19:03 +00:00
Allan Carr
25bee3cfdf Merged in feature/IO-2261-opensearch-replacements (pull request #764)
Feature/IO-2261 opensearch replacements

Approved-by: Patrick Fic
2023-05-05 20:14:02 +00:00
Allan Carr
baf06fee6c Merge branch 'feature/IO-2261-opensearch-replacements' of https://bitbucket.org/snaptsoft/bodyshop into feature/IO-2261-opensearch-replacements 2023-05-05 13:10:39 -07:00
Allan Carr
a3557bbc86 IO-2261 Add Delete function, Correct Payment edit, add Totals to Bills handler 2023-05-05 13:10:07 -07:00
swtmply
3e00e7981d IO-1722 added placement to popover 2023-05-06 03:34:55 +08:00
swtmply
12fa270a1a IO-1722 adjusted background colors 2023-05-06 03:34:22 +08:00
Patrick Fic
de250b152a Change all open search events to trigger on all fields. 2023-05-05 12:20:25 -07:00
Patrick Fic
c45741257f Add export trigger for os_bills event. 2023-05-05 12:16:39 -07:00
swtmply
3988386c79 IO-1722 replaced hex to rgba 2023-05-06 02:56:02 +08:00
Patrick Fic
492032c1e2 Merged in release/2023-05-05 (pull request #762)
Release/2023 05 05
2023-05-05 17:56:36 +00:00
Allan Carr
8222e56485 Merged in feature/IO-2261-opensearch-replacements (pull request #761)
IO-2261 Add in missing field "date" for Payments

Approved-by: Patrick Fic
2023-05-05 17:56:14 +00:00
Patrick Fic
49a61e1564 Merge branch 'feature/IO-2261-opensearch-replacements' of https://bitbucket.org/snaptsoft/bodyshop into feature/IO-2261-opensearch-replacements 2023-05-05 10:55:59 -07:00
Patrick Fic
eed18aa1c5 Add event triggers on export fields 2023-05-05 10:55:42 -07:00
Allan Carr
2de3f8b022 IO-2261 Add in missing field "date" for Payments 2023-05-05 10:54:41 -07:00
Patrick Fic
91476c7ad3 Merged in release/2023-05-05 (pull request #760)
Release/2023 05 05
2023-05-05 17:44:50 +00:00
John Allen Delos Reyes
00eb7926f9 Merged in feature/IO-2266-duplicate-option (pull request #759)
IO-2266 fixed key issue causing option to duplicate

Approved-by: Patrick Fic
2023-05-05 17:44:19 +00:00
Patrick Fic
854ad21b20 Update autohouse header auth. 2023-05-05 10:16:41 -07:00
swtmply
3c3f9521f6 IO-2266 fixed key issue causing option to duplicate 2023-05-05 23:43:48 +08:00
Patrick Fic
561bcf10d9 Merged in release/2023-05-05 (pull request #758)
IO-2261 All Jobs, Bills, Payments
2023-05-05 14:49:55 +00:00
Allan Carr
75d9faa05b Merged in feature/IO-2261-opensearch-replacements (pull request #757)
IO-2261 All Jobs, Bills, Payments

Approved-by: Patrick Fic
2023-05-05 14:49:23 +00:00
Allan Carr
ac72177fbb IO-2261 All Jobs, Bills, Payments
Adjust Pagination settings and on clear delete search.page to reset. Adjust payments for bodyshopid as it was pointed at bill instead of payment
2023-05-04 18:27:47 -07:00
Allan Carr
088faf152c Merged in release/2023-05-05 (pull request #756)
Release/2023 05 05

Approved-by: Patrick Fic
2023-05-04 22:33:12 +00:00
Patrick Fic
90cba9ed24 Merge branch 'feature/IO-1722-job-size-color' into release/2023-05-05 2023-05-04 15:32:30 -07:00
Patrick Fic
a0702785c5 Revert "Revert "Merged in feature/IO-1722-job-size-color (pull request #746)""
This reverts commit 7dc3c00628.
2023-05-04 15:32:21 -07:00
Allan Carr
6898d609fe IO-2261 Add Loading effect 2023-05-04 15:17:37 -07:00
Allan Carr
d70893e2ba Merged in feature/IO-2261-opensearch-replacements (pull request #748)
Feature/IO-2261 opensearch replacements
2023-05-04 22:16:49 +00:00
Patrick Fic
6155b8bf24 Merged in release/2023-05-05 (pull request #754)
Add firebase auth to JSR call.
2023-05-04 21:04:16 +00:00
Patrick Fic
239dc5c62d Merged in release/2023-05-05 (pull request #753)
Release/2023 05 05
2023-05-04 20:36:18 +00:00
Patrick Fic
2586855f11 Add firebase auth to JSR call. 2023-05-04 13:33:16 -07:00
Patrick Fic
b3b3c4c737 Merged in release/2023-05-05 (pull request #752)
Resolve health check
2023-05-04 20:26:04 +00:00
Patrick Fic
abe5fadeea Resolve health check 2023-05-04 13:25:45 -07:00
swtmply
08e5543536 IO-1722 adjusted condition for text color 2023-05-05 04:00:44 +08:00
Patrick Fic
f1a10e0df4 Merged in release/2023-05-05 (pull request #750)
Release/2023 05 05
2023-05-04 19:57:22 +00:00
Patrick Fic
7dc3c00628 Revert "Merged in feature/IO-1722-job-size-color (pull request #746)"
This reverts commit 7594f53e88, reversing
changes made to b861957342.
2023-05-04 12:50:28 -07:00
Patrick Fic
1c5c403d65 Merged in release/2023-05-05 (pull request #749)
Release/2023 05 05
2023-05-04 19:34:56 +00:00
John Allen Delos Reyes
7594f53e88 Merged in feature/IO-1722-job-size-color (pull request #746)
Feature/IO-1722 job size color

Approved-by: Patrick Fic
2023-05-04 19:03:30 +00:00
Patrick Fic
b861957342 Additional security hardening. 2023-05-04 11:59:39 -07:00
swtmply
2bf24ff5a1 IO-1722 refactor color function 2023-05-04 23:00:37 +08:00
Allan Carr
6e5fcbfdbd IO-2267 Remove Sort for Linked Table fields 2023-05-03 16:30:48 -07:00
Allan Carr
759a8ac58c IO-2261 Opensearch for Payments, Bills and All Jobs 2023-05-03 16:29:01 -07:00
swtmply
833baca9cc Merge branch 'feature/IO-1722-job-size-color' of https://bitbucket.org/snaptsoft/bodyshop into feature/IO-1722-job-size-color 2023-05-04 01:27:24 +08:00
swtmply
889ef61185 IO-1722 fixed spacing on translations 2023-05-04 01:25:17 +08:00
swtmply
add1eddbc1 IO-1722 added translations 2023-05-04 01:18:16 +08:00
Allan Carr
1c63aa39c4 Merged in release/2023-05-05 (pull request #744)
Release/2023 05 05
2023-05-03 17:10:48 +00:00
swtmply
0cabd80b94 IO-1722 job size color in production card 2023-05-04 00:39:50 +08:00
Patrick Fic
7f756bab88 Merged in feature/IO-2190-Autohouse (pull request #743)
IO-2190 Autohouse & Job Costing
2023-05-02 21:53:40 +00:00
Allan Carr
99b847822f Merged in feature/IO-2190-Autohouse (pull request #742)
IO-2190 Autohouse & Job Costing

Approved-by: Patrick Fic
2023-05-02 21:52:50 +00:00
Allan Carr
f66d9b8c09 IO-2190 Autohouse & Job Costing
Insure that amount going into Dinero is Integer
2023-05-02 14:51:47 -07:00
Patrick Fic
5660de42af Add support email to server side emails. 2023-05-02 12:31:18 -07:00
Patrick Fic
ccbe92c275 Merged in feature/IO-2190-Autohouse (pull request #741)
IO-2190 Correct lookup location for MAPA Hrs
2023-05-02 17:06:12 +00:00
Allan Carr
b0ea8a71fb Merged in feature/IO-2190-Autohouse (pull request #738)
IO-2190 Correct lookup location for MAPA Hrs

Approved-by: Patrick Fic
2023-05-01 22:30:13 +00:00
Allan Carr
060871306f Merged in feature/IO-2257-PBS-EXPORT-CREDIT (pull request #737)
IO-2257 PBS Export of Credits

Approved-by: Patrick Fic
2023-05-01 22:30:00 +00:00
Allan Carr
2eb4e142ff IO-2190 Correct lookup location for MAPA Hrs 2023-05-01 13:48:18 -07:00
Patrick Fic
adf8cf9e8d Additional hasura indexes. 2023-05-01 13:05:59 -07:00
Patrick Fic
852fd9c388 IO-2261 Sample open search replacement. 2023-05-01 13:04:10 -07:00
Patrick Fic
e921f28105 Merged in release/2023-04-28 (pull request #736)
Additional database indexing.
2023-04-28 16:51:46 +00:00
Patrick Fic
6db68b76db Merged in release/2023-04-28 (pull request #735)
Additional database indexing.
2023-04-28 16:51:31 +00:00
Patrick Fic
51ebfd86e7 Additional database indexing. 2023-04-28 09:37:49 -07:00
Allan Carr
79a90bb9ee IO-2257 PBS Export of Credits
Amounts less then 0 (ie all credits) would not get pushed to transactionObject. Expand to be both sides of zero to allow for credits within transactionObject
2023-04-27 17:13:37 -07:00
Patrick Fic
1664f9c935 Merged in release/2023-04-28 (pull request #733)
Resolve Loader script issue.
2023-04-27 22:21:15 +00:00
Patrick Fic
23fcdd6375 Merged in release/2023-04-28 (pull request #732)
Release/2023 04 28
2023-04-27 22:21:03 +00:00
Patrick Fic
ea7c22daec Resolve Loader script issue. 2023-04-27 15:20:41 -07:00
Patrick Fic
10ffb33ec9 Merged in release/2023-04-28 (pull request #731)
Remove unneeded imports.
2023-04-27 21:33:39 +00:00
Patrick Fic
f9e023f922 Remove unneeded imports. 2023-04-27 14:19:27 -07:00
Patrick Fic
c7832bdd82 Merged in release/2023-04-28 (pull request #730)
Release/2023 04 28
2023-04-27 21:13:54 +00:00
Patrick Fic
329bdbe22d Merged in release/2023-04-28 (pull request #729)
Release/2023 04 28
2023-04-27 20:54:32 +00:00
Patrick Fic
2df046c39d IO-1053 Fix issues with scoreboard updates. 2023-04-27 13:52:01 -07:00
Patrick Fic
46065f1986 IO-1933 Resolve tech efficency component. 2023-04-27 13:13:16 -07:00
Allan Carr
66b3fb6988 Merged in release/2023-04-28 (pull request #728)
IO-2190 Factor Paint Costs from Scale over to Job Costing & Autohouse

Approved-by: Patrick Fic
2023-04-27 19:47:13 +00:00
swtmply
5eda224393 IO-1053 Added Job Total to graph 2023-04-28 01:42:22 +08:00
Patrick Fic
e387abcd14 IO-1741 IO-2147 IO-1933 Bug fixes for multiple tickets. 2023-04-27 10:20:46 -07:00
Allan Carr
4c2d4e20a6 IO-2190 Factor Paint Costs from Scale over to Job Costing & Autohouse
Add use_paint_scale_data to bodyshop query
2023-04-27 09:40:12 -07:00
Patrick Fic
3d26c2e94e Merged in release/2023-04-28 (pull request #727)
Release/2023 04 28
2023-04-27 16:32:43 +00:00
swtmply
d9e2ef9300 IO-1933 Added statistics on tech page 2023-04-27 22:19:32 +08:00
swtmply
b00fdadc1b IO-1741 Added touched property on calculate button 2023-04-27 22:19:00 +08:00
swtmply
4d5e06b9fc IO-2157 Added save to job notes button 2023-04-27 22:18:45 +08:00
Patrick Fic
ad42dd1295 Merged in release/2023-04-28 (pull request #726)
IO-2210 Remove unused state.
2023-04-26 23:52:34 +00:00
Patrick Fic
1f4c1c9e92 IO-2210 Remove unused state. 2023-04-26 16:51:53 -07:00
Patrick Fic
2938b9c94c Merged in release/2023-04-28 (pull request #725)
IO-2210 Search Improvements
2023-04-26 23:45:43 +00:00
Patrick Fic
2227acab3a IO-2210 Search Improvements 2023-04-26 16:45:20 -07:00
Patrick Fic
bde17446ad Merged in release/2023-04-28 (pull request #724)
Release/2023 04 28
2023-04-26 19:49:54 +00:00
Patrick Fic
081165b6f5 Resolve missing items from merge conflicts. 2023-04-26 12:46:41 -07:00
Allan Carr
7e717c0b1f Merge branch 'release/2023-04-28' of https://bitbucket.org/snaptsoft/bodyshop into release/2023-04-28
# Conflicts:
#	yarn.lock
2023-04-26 12:23:50 -07:00
Allan Carr
e242aaa9f5 IO-2190 Factor Paint Costs from Scale over to Job Costing & Autohouse
If Paint Scale Data exist in MixData then use the LiquidCost is use_paint_scale_data is set to true else fall back to cost calculations
2023-04-26 12:05:14 -07:00
Patrick Fic
fe60538acf Merged in release/2023-04-28 (pull request #723)
Resolve missing items from merge conflicts.
2023-04-26 17:21:20 +00:00
Patrick Fic
2db88f57df Resolve missing items from merge conflicts. 2023-04-26 10:20:24 -07:00
Patrick Fic
7461e58000 Merged in release/2023-04-28 (pull request #722)
Release/2023 04 28
2023-04-26 16:44:29 +00:00
Patrick Fic
cd0b7a4e56 Add additional indexes. 2023-04-26 09:42:43 -07:00
Allan Carr
2a3b4e89ab Merge branch 'release/2023-04-28' of https://bitbucket.org/snaptsoft/bodyshop into release/2023-04-28
# Conflicts:
#	hasura/metadata/tables.yaml
2023-04-26 09:13:34 -07:00
Allan Carr
1d77eda3e2 IO-2190 Add extra field in for this item 2023-04-26 09:02:36 -07:00
swtmply
490e1f696a IO-1741 Added touched property on calculate button 2023-04-26 22:33:30 +08:00
swtmply
b96c618f54 IO-2157 Added save to job notes button 2023-04-26 22:32:46 +08:00
Patrick Fic
1afda01d34 Merged in release/2023-04-28 (pull request #721)
Release/2023 04 28
2023-04-26 02:22:48 +00:00
Patrick Fic
b9d11580d4 IO-2210 Opensearch implementation. 2023-04-25 18:47:11 -07:00
Patrick Fic
27fadb9ae2 Additional payroll schema tracking. 2023-04-25 10:16:56 -07:00
Patrick Fic
4c5a2cefe9 Payroll schema updates. 2023-04-25 09:33:17 -07:00
Patrick Fic
175692559c Merged in release/2023-04-28 (pull request #720)
Release/2023 04 28
2023-04-24 21:45:57 +00:00
Patrick Fic
57b27f73c3 Added a search filter for greater than 3 characters. 2023-04-24 14:45:08 -07:00
Patrick Fic
7badb09ba1 Timeticket Approval Queue schema updates for payroll updates. 2023-04-24 13:39:59 -07:00
Patrick Fic
c39f1d824a Merged in release/2023-04-21 (pull request #719)
Release/2023 04 21
2023-04-21 20:18:25 +00:00
Patrick Fic
132cf98a37 IO-2086 Resolve local media server pulling full size image for thumbnail. 2023-04-21 12:21:28 -07:00
Patrick Fic
59f71d53cd Merged in release/2023-04-21 (pull request #718)
Release/2023 04 21
2023-04-21 18:42:34 +00:00
Patrick Fic
f4b3a990d7 Additional schema changes for payroll. 2023-04-21 08:42:47 -07:00
swtmply
20371ea00d Merge branch 'release/2023-04-21' of https://bitbucket.org/snaptsoft/bodyshop into release/2023-04-21 2023-04-21 22:28:00 +08:00
swtmply
3086a654a1 IO-1461 made the sider sticky 2023-04-21 22:27:48 +08:00
Patrick Fic
60768c8847 Timeticket approval queue aggregation permissions. 2023-04-20 15:28:14 -07:00
Patrick Fic
a68f8d6880 Payroll schema changes. 2023-04-20 15:05:23 -07:00
Allan Carr
0cad64ff6d Merged in release/2023-04-21 (pull request #717)
IO-2335 Exported GSR to Excel

Approved-by: Patrick Fic
2023-04-20 19:58:58 +00:00
Allan Carr
522665256e IO-2335 Exported GSR to Excel
Change idtype to reporttype to prevent issues later on down the road if we extend more reports to excel format
2023-04-20 12:43:06 -07:00
swtmply
d3fe2c9d06 IO-2011 removed column background color 2023-04-21 03:37:36 +08:00
swtmply
f080e84985 IO-2242 added email on vendor query 2023-04-21 02:56:11 +08:00
Allan Carr
2a0ad46eea IO-2235
Changes in Prettier
2023-04-20 09:46:21 -07:00
Allan Carr
3a83160b33 Merged in release/2023-04-21 (pull request #716)
IO-2235 Exported GSR to Excel

Approved-by: Patrick Fic
2023-04-20 16:45:28 +00:00
Allan Carr
7725080a11 IO-2235 Exported GSR to Excel
For Morrey Body Shop
2023-04-20 09:33:22 -07:00
Allan Carr
701c532e48 Merged in release/2023-04-21 (pull request #715)
Release/2023 04 21

Approved-by: Patrick Fic
2023-04-19 23:14:52 +00:00
Allan Carr
1932795f55 Merge branch 'release/2023-04-21' of https://bitbucket.org/snaptsoft/bodyshop into release/2023-04-21 2023-04-19 15:44:41 -07:00
Allan Carr
cc7bd1c792 IO-2243 DMS Posting Sheet Report
Requested by Morrey Auto Body
2023-04-19 15:44:09 -07:00
Patrick Fic
7799d93f3d Merged in release/2023-04-21 (pull request #714)
Disable job status transition tracking.
2023-04-19 21:26:37 +00:00
Patrick Fic
a7cf36d5f8 Disable job status transition tracking. 2023-04-19 14:26:12 -07:00
Patrick Fic
54cc02068c Merged in release/2023-04-21 (pull request #713)
Release/2023 04 21
2023-04-19 21:11:45 +00:00
Patrick Fic
f575870685 Added missed limit on global search. 2023-04-19 14:10:33 -07:00
Patrick Fic
171b61b92f Included a limit on global search query to limit performance impact. 2023-04-19 14:08:57 -07:00
Patrick Fic
de44116940 Merged in release/2023-04-21 (pull request #712)
Resolve status transition error message.
2023-04-19 20:08:39 +00:00
Patrick Fic
3c0a883326 Resolve status transition error message. 2023-04-19 13:08:18 -07:00
Patrick Fic
14d6cc94dd Merged in release/2023-04-21 (pull request #711)
IO-2086 Resolve cloudinary based thumbnail retrieval.
2023-04-19 18:45:22 +00:00
Patrick Fic
c0d9bacf1d Merged in release/2023-04-21 (pull request #710)
Release/2023 04 21
2023-04-19 18:44:50 +00:00
Patrick Fic
d787821345 IO-2086 Resolve cloudinary based thumbnail retrieval. 2023-04-19 11:43:24 -07:00
Patrick Fic
ed6eab4c38 Merged in release/2023-04-14 (pull request #708)
Remove erroneous console log.
2023-04-14 20:05:43 +00:00
Patrick Fic
b12c9407d9 Remove erroneous console log. 2023-04-14 13:05:09 -07:00
Patrick Fic
300aee5b02 Merged in release/2023-04-14 (pull request #707)
Release/2023 04 14
2023-04-14 20:04:15 +00:00
Patrick Fic
357f40bdc2 Merged in release/2023-04-14 (pull request #706)
Release/2023 04 14
2023-04-14 20:03:58 +00:00
Patrick Fic
0a93551db4 Merge branch 'release/2023-04-14' of https://bitbucket.org/snaptsoft/bodyshop into release/2023-04-14
# Conflicts:
#	client/src/components/scoreboard-timetickets/scoreboard-timetickets.component.jsx
2023-04-14 12:30:22 -07:00
Patrick Fic
8602ccbb8a IO-2240 Resolve efficiency calculation issue. 2023-04-14 12:29:11 -07:00
swtmply
d7b0e3046b IO-2240 Adjusted calculation for total efficiency 2023-04-15 03:26:56 +08:00
Patrick Fic
30689a8ca6 Merged in release/2023-04-14 (pull request #705)
Release/2023 04 14
2023-04-14 18:39:19 +00:00
swtmply
0e06b449cb IO-2240 Adjusted the location of the calculation 2023-04-15 01:18:29 +08:00
swtmply
8e8208dd9a IO-2240 Moved the calculation within the function 2023-04-15 01:11:44 +08:00
swtmply
79e2fecb24 IO-2239 Removed total title 2023-04-14 23:33:14 +08:00
swtmply
86e909e4e9 Merge branch 'release/2023-04-14' of https://bitbucket.org/snaptsoft/bodyshop into release/2023-04-14 2023-04-14 02:53:14 +08:00
swtmply
c7ff893397 IO-1412 Fixed column resize drag speed 2023-04-14 02:53:04 +08:00
Patrick Fic
3981b8684c IO-2244 Round difference calculation to 1 decimal point for productive hours claiming enforcement. 2023-04-13 10:11:15 -07:00
swtmply
1fb856f95f Merge branch 'release/2023-04-14' of https://bitbucket.org/snaptsoft/bodyshop into release/2023-04-14 2023-04-14 00:41:00 +08:00
swtmply
c62c3fa938 IO-2240 total for productive hours in summary 2023-04-14 00:40:50 +08:00
Patrick Fic
554ec37ace Merged in release/2023-04-14 (pull request #704)
Release/2023 04 14
2023-04-13 16:36:16 +00:00
Patrick Fic
be4feca990 Clean up unneeded import. 2023-04-13 09:26:24 -07:00
Patrick Fic
ec45454b3d IO-2244 Restrict claimable productive hours based on remaining hours 2023-04-13 09:25:52 -07:00
swtmply
0e78cb47f9 Merge branch 'release/2023-04-14' of https://bitbucket.org/snaptsoft/bodyshop into release/2023-04-14 2023-04-13 22:04:01 +08:00
Patrick Fic
e5b8d003ec IO-2137 Adjust PBS company name logic for posting. 2023-04-13 22:03:35 +08:00
Patrick Fic
2eb81dde37 Add ppc field to job lines. 2023-04-13 22:03:35 +08:00
Patrick Fic
614549a545 Include employee team changes from Payroll Based Changes. 2023-04-13 22:03:35 +08:00
Patrick Fic
5717727d2a IO-2243 Capture successful CDK posting details. 2023-04-13 22:03:35 +08:00
swtmply
f3714cea1e IO-2239 Added totals on cards in job scoreboards 2023-04-13 22:03:35 +08:00
swtmply
a3375e6152 IO-2238 Changed vehicle column to be a hyperlink 2023-04-13 22:03:24 +08:00
Patrick Fic
f48fb7130e IO-2137 Adjust PBS company name logic for posting. 2023-04-12 13:16:18 -07:00
Patrick Fic
1460fa6fd7 Add ppc field to job lines. 2023-04-12 13:13:51 -07:00
Patrick Fic
3d9a07bd39 Include employee team changes from Payroll Based Changes. 2023-04-12 13:08:39 -07:00
Patrick Fic
bd4aa4027a IO-2243 Capture successful CDK posting details. 2023-04-12 13:02:45 -07:00
swtmply
9fa995f002 IO-2239 Added totals on cards in job scoreboards 2023-04-12 03:13:19 +08:00
swtmply
3ed48b26f1 IO-2338 Changed vehicle column to be a hyperlink 2023-04-12 01:44:45 +08:00
swtmply
d585cacdfc IO-1412 Fixed column resize 2023-04-12 00:57:13 +08:00
Patrick Fic
55ddaca328 Merged in release/2023-04-07 (pull request #703)
Release/2023 04 07
2023-04-06 00:22:52 +00:00
Patrick Fic
3fc7af9780 Merged in release/2023-04-07 (pull request #702)
Release/2023 04 07
2023-04-06 00:22:37 +00:00
Patrick Fic
146bf95e51 IO-2086 Resolve additional gallery import issue & tech login issue. 2023-04-05 17:22:18 -07:00
Patrick Fic
58defad2ea IO-2086 Resolve imports for additional classes with gallery. 2023-04-05 17:21:47 -07:00
Patrick Fic
9c40a03a06 Merged in release/2023-04-07 (pull request #701)
Release/2023 04 07
2023-04-05 22:09:28 +00:00
John Allen Delos Reyes
a1b6ccc23d Merged in release/2023-04-07 (pull request #700)
Release/2023 04 07

Approved-by: Patrick Fic
2023-04-05 21:21:39 +00:00
Patrick Fic
9b4247d6f6 Revert "fixed column resize"
This reverts commit 6e7d1abd70.
2023-04-05 14:20:15 -07:00
Patrick Fic
8a6d94f193 Resolve time ticket posting issue. 2023-04-05 14:02:34 -07:00
swtmply
6e7d1abd70 fixed column resize 2023-04-05 02:35:07 +08:00
swtmply
6bd74aae87 document galleries 2023-04-01 03:26:08 +08:00
Patrick Fic
f21caa10fc Merged in release/2023-03-21 (pull request #697)
IO-2213 Resolve issue with filtering on schedule screen.
2023-03-21 16:10:03 +00:00
Patrick Fic
dde6f17029 Merged in release/2023-03-17 (pull request #694)
Language updates & default for lost sale reason.
2023-03-17 18:43:52 +00:00
Allan Carr
1aceef9153 Merged in release/2023-03-17 (pull request #693)
IO-2193 Delete Owner & Vehicle

Approved-by: Patrick Fic
2023-03-17 01:06:10 +00:00
Patrick Fic
678892d134 Merged in release/2023-03-17 (pull request #692)
IO-2177 Add enforce category on conversion.
2023-03-16 21:51:01 +00:00
Allan Carr
dc187bbf24 Merged in release/2023-03-17 (pull request #691)
Release/2023 03 17

Approved-by: Patrick Fic
2023-03-16 18:51:11 +00:00
Patrick Fic
09aae78715 Merged in release/2023-03-17 (pull request #690)
Release/2023 03 17
2023-03-15 18:53:49 +00:00
Patrick Fic
c42276ab3a Merged in release/2023-03-10 (pull request #688)
Release/2023 03 10
2023-03-10 18:51:03 +00:00
Patrick Fic
41d25cbc52 Merged in release/2023-03-03 (pull request #686)
release/2023-03-03

Approved-by: Patrick Fic
2023-03-03 17:28:32 +00:00
Patrick Fic
085c27ad20 Merged in release/2023-03-03 (pull request #685)
release/2023-03-03

Approved-by: Patrick Fic
2023-03-03 17:08:45 +00:00
Patrick Fic
38e6b5010e Merged in release/2023-03-03 (pull request #684)
release/2023-03-03

Approved-by: Patrick Fic
2023-03-03 04:05:30 +00:00
Allan Carr
242c275e7d Merged in release/2023-02-24 (pull request #680)
Release/2023 02 24

Approved-by: Patrick Fic
2023-02-23 19:44:40 +00:00
Allan Carr
1dc6130fdf Merged in release/2023-02-17 (pull request #678)
Release/2023 02 17

Approved-by: Patrick Fic
2023-02-17 18:37:20 +00:00
Allan Carr
910afbf48d Merged in release/2023-02-17 (pull request #676)
Release/2023 02 17

Approved-by: Patrick Fic
2023-02-14 22:03:01 +00:00
Patrick Fic
9d9edfd674 Merged in release/2023-02-10 (pull request #674)
Improve display of job lines preset display.
2023-02-10 23:22:47 +00:00
Allan Carr
62a5b49836 Merged in release/2023-02-10 (pull request #673)
Release/2023 02 10

Approved-by: Patrick Fic
2023-02-09 17:56:24 +00:00
Patrick Fic
e93e138f78 Merged in release/2023-02-03 (pull request #671)
release/2023-02-03

Approved-by: Patrick Fic
2023-02-06 18:09:03 +00:00
Patrick Fic
4639e31e55 Merged in release/2023-02-03 (pull request #669)
release/2023-02-03

Approved-by: Patrick Fic
2023-02-04 01:19:46 +00:00
Patrick Fic
e8fde14f9b Merged in release/2023-02-03 (pull request #668)
release/2023-02-03

Approved-by: Patrick Fic
2023-02-03 22:58:21 +00:00
Patrick Fic
90e87adc34 Merged in release/2023-02-03 (pull request #667)
release/2023-02-03

Approved-by: Patrick Fic
2023-02-03 20:34:27 +00:00
Patrick Fic
81053b3cbf Merged in release/2023-02-03 (pull request #666)
release/2023-02-03

Approved-by: Patrick Fic
2023-02-02 21:47:46 +00:00
Patrick Fic
f4290bf20c Merged in release/2023-02-03 (pull request #665)
release/2023-02-03

Approved-by: Patrick Fic
2023-02-02 19:06:20 +00:00
Patrick Fic
5371657aa4 Merged in release/2023-02-03 (pull request #664)
release/2023-02-03

Approved-by: Patrick Fic
2023-02-02 18:42:40 +00:00
Patrick Fic
599f4e143c Merged in release/2023-02-03 (pull request #663)
release/2023-02-03

Approved-by: Patrick Fic
2023-02-02 18:10:12 +00:00
Patrick Fic
94440e5c48 Merged in master (pull request #662)
Merged in release/2023-01-27 (pull request #661)
2023-01-27 23:14:44 +00:00
Patrick Fic
aa5d6f2090 Merged in release/2023-01-27 (pull request #660)
IO-2156 Resolve AH detail line validation issue.
2023-01-27 21:21:21 +00:00
Patrick Fic
6bde1b1baf Merged in release/2023-01-27 (pull request #659)
Release/2023 01 27
2023-01-27 17:02:10 +00:00
Patrick Fic
fc404b1f3b Merged in release/2022-01-20 (pull request #655)
Release/2022 01 20
2023-01-19 21:11:58 +00:00
Patrick Fic
c6ba3fd8f0 Merged in release/2022-01-13 (pull request #653)
Release/2022 01 13
2023-01-09 17:36:25 +00:00
Patrick Fic
119904ca2b Merged in release/2023-01-06 (pull request #651)
Updates to Sentry & removal of Stripe.
2023-01-04 16:33:10 +00:00
Patrick Fic
f7e1b023df Merged in release/2023-01-06 (pull request #650)
Release/2023 01 06
2023-01-02 22:56:05 +00:00
Patrick Fic
5855569194 Merged in release/2022-12-30 (pull request #648)
IO-2133 Manual Line Highlighting
2022-12-28 18:05:20 +00:00
Patrick Fic
4f852e7493 Merged in release/2022-12-30 (pull request #647)
release/2022-12-30

Approved-by: Patrick Fic
2022-12-26 18:34:28 +00:00
Patrick Fic
deec40a89c Merged in release/2022-12-16 (pull request #642)
Remove unneeded import to fix CI.
2022-12-16 01:09:42 +00:00
Patrick Fic
145dd9bec6 Merged in release/2022-12-16 (pull request #641)
IO-2131 Resolve job search select filtering issue.
2022-12-16 01:02:45 +00:00
Patrick Fic
b8e5d4412f Merged in release/2022-12-16 (pull request #640)
Release/2022 12 16
2022-12-15 18:20:28 +00:00
Patrick Fic
277fb8f839 Merged in release/2022-12-09 (pull request #637)
IO-2123 Add cc inventory print.
2022-12-09 19:35:49 +00:00
Patrick Fic
d3d5485846 Merged in release/2022-12-09 (pull request #636)
Release/2022 12 09
2022-12-09 16:19:58 +00:00
Patrick Fic
55091d61d6 Merged in release/2022-12-02 (pull request #634)
Release/2022 12 02
2022-11-30 18:26:32 +00:00
Patrick Fic
5b5df8a3a1 Merged in release/2022-11-25 (pull request #630)
Release/2022 11 25
2022-11-25 16:42:19 +00:00
Patrick Fic
ccf48cfcf1 Merged in release/2022-11-10 (pull request #624)
release/2022-11-10

Approved-by: Patrick Fic
2022-11-10 18:47:48 +00:00
Patrick Fic
c89342b6ef Merge branch 'release/2022-11-10' into test
* release/2022-11-10:
  CI Test
2022-11-09 16:35:48 -08:00
Patrick Fic
e97ceb7cbe Merged in release/2022-11-10 (pull request #623)
CI Test
2022-11-10 00:30:20 +00:00
Patrick Fic
de34cbd937 Merged in release/2022-11-10 (pull request #622)
Release/2022 11 10
2022-11-10 00:23:10 +00:00
Patrick Fic
cf7a1b0168 Merged in release/2022-11-10 (pull request #621)
Add .circleci/config.yml
2022-11-08 19:10:04 +00:00
153 changed files with 6713 additions and 1436 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,4 @@
GENERATE_SOURCEMAP=false
REACT_APP_GRAPHQL_ENDPOINT=https://db.imex.online/v1/graphql
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.imex.online/v1/graphql
REACT_APP_GA_CODE=231103507

View File

@@ -46,10 +46,11 @@
"react-cookie": "^4.1.1",
"react-dom": "^17.0.2",
"react-drag-listview": "^0.2.1",
"react-grid-gallery": "^0.5.5",
"react-grid-gallery": "^1.0.0",
"react-grid-layout": "^1.3.4",
"react-i18next": "^12.2.0",
"react-icons": "^4.7.1",
"react-image-lightbox": "^5.1.4",
"react-number-format": "^5.1.3",
"react-redux": "^8.0.5",
"react-resizable": "^3.0.4",

View File

@@ -143,13 +143,16 @@
}
}
//Update row highlighting on production board.
//Update row highlighting on production board.
.ant-table-tbody > tr.ant-table-row:hover > td {
background: #eaeaea !important;
}
.job-line-manual{
.job-line-manual {
color: tomato;
font-style: italic;
}
td.ant-table-column-sort {
background-color: transparent;
}

View File

@@ -6,7 +6,7 @@ import { useTranslation } from "react-i18next";
import { DELETE_BILL } from "../../graphql/bills.queries";
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
export default function BillDeleteButton({ bill }) {
export default function BillDeleteButton({ bill, callback }) {
const [loading, setLoading] = useState(false);
const { t } = useTranslation();
const [deleteBill] = useMutation(DELETE_BILL);
@@ -36,6 +36,8 @@ export default function BillDeleteButton({ bill }) {
if (!!!result.errors) {
notification["success"]({ message: t("bills.successes.deleted") });
if (callback && typeof callback === "function") callback(bill.id);
} else {
//Check if it's an fkey violation.
const error = JSON.stringify(result.errors);

View File

@@ -7,7 +7,9 @@ import { createStructuredSelector } from "reselect";
import { selectBreadcrumbs } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import GlobalSearch from "../global-search/global-search.component";
import GlobalSearchOs from "../global-search/global-search-os.component";
import "./breadcrumbs.styles.scss";
import { useTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
breadcrumbs: selectBreadcrumbs,
@@ -15,6 +17,12 @@ const mapStateToProps = createStructuredSelector({
});
export function BreadCrumbs({ breadcrumbs, bodyshop }) {
const { OpenSearch } = useTreatments(
["OpenSearch"],
{},
bodyshop && bodyshop.imexshopid
);
return (
<Row className="breadcrumb-container">
<Col xs={24} sm={24} md={16}>
@@ -38,7 +46,7 @@ export function BreadCrumbs({ breadcrumbs, bodyshop }) {
</Breadcrumb>
</Col>
<Col xs={24} sm={24} md={8}>
<GlobalSearch />
{OpenSearch.treatment === "on" ? <GlobalSearchOs /> : <GlobalSearch />}
</Col>
</Row>
);

View File

@@ -10,7 +10,10 @@ export default function CABCpvrtCalculator({ disabled, form }) {
const handleFinish = async (values) => {
logImEXEvent("job_ca_bc_pvrt_calculate");
form.setFieldsValue({ ca_bc_pvrt: ((values.rate||0) * (values.days||0)).toFixed(2) });
form.setFieldsValue({
ca_bc_pvrt: ((values.rate || 0) * (values.days || 0)).toFixed(2),
});
form.setFields([{ name: "ca_bc_pvrt", touched: true }]);
setVisibility(false);
};

View File

@@ -0,0 +1,216 @@
import { AutoComplete, Divider, Input, Space } from "antd";
import axios from "axios";
import _ from "lodash";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link, useHistory } from "react-router-dom";
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import OwnerNameDisplay, {
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
export default function GlobalSearchOs() {
const { t } = useTranslation();
const history = useHistory();
const [loading, setLoading] = useState(false);
const [data, setData] = useState(false);
const executeSearch = async (v) => {
if (v && v && v !== "" && v.length >= 3) {
try {
setLoading(true);
const searchData = await axios.post("/search", {
search: v,
});
const resultsByType = {
payments: [],
jobs: [],
bills: [],
owners: [],
vehicles: [],
};
searchData.data.hits.hits.forEach((hit) => {
resultsByType[hit._index].push(hit._source);
});
setData([
{
label: renderTitle(t("menus.header.search.jobs")),
options: resultsByType.jobs.map((job) => {
return {
key: job.id,
value: job.ro_number || "N/A",
label: (
<Link to={`/manage/jobs/${job.id}`}>
<Space size="small" split={<Divider type="vertical" />}>
<strong>{job.ro_number || t("general.labels.na")}</strong>
<span>{`${job.status || ""}`}</span>
<span>
<OwnerNameDisplay ownerObject={job} />
</span>
<span>{`${job.v_model_yr || ""} ${
job.v_make_desc || ""
} ${job.v_model_desc || ""}`}</span>
<span>{`${job.clm_no || ""}`}</span>
</Space>
</Link>
),
};
}),
},
{
label: renderTitle(t("menus.header.search.owners")),
options: resultsByType.owners.map((owner) => {
return {
key: owner.id,
value: OwnerNameDisplayFunction(owner),
label: (
<Link to={`/manage/owners/${owner.id}`}>
<Space
size="small"
split={<Divider type="vertical" />}
wrap
>
<span>
<OwnerNameDisplay ownerObject={owner} />
</span>
<PhoneNumberFormatter>
{owner.ownr_ph1}
</PhoneNumberFormatter>
<PhoneNumberFormatter>
{owner.ownr_ph2}
</PhoneNumberFormatter>
</Space>
</Link>
),
};
}),
},
{
label: renderTitle(t("menus.header.search.vehicles")),
options: resultsByType.vehicles.map((vehicle) => {
return {
key: vehicle.id,
value: `${vehicle.v_model_yr || ""} ${
vehicle.v_make_desc || ""
} ${vehicle.v_model_desc || ""}`,
label: (
<Link to={`/manage/vehicles/${vehicle.id}`}>
<Space size="small" split={<Divider type="vertical" />}>
<span>
{`${vehicle.v_model_yr || ""} ${
vehicle.v_make_desc || ""
} ${vehicle.v_model_desc || ""}`}
</span>
<span>{vehicle.plate_no || ""}</span>
<span>
<VehicleVinDisplay>
{vehicle.v_vin || ""}
</VehicleVinDisplay>
</span>
</Space>
</Link>
),
};
}),
},
{
label: renderTitle(t("menus.header.search.payments")),
options: resultsByType.payments.map((payment) => {
return {
key: payment.id,
value: `${payment.job?.ro_number} ${payment.amount}`,
label: (
<Link to={`/manage/jobs/${payment.job?.id}`}>
<Space size="small" split={<Divider type="vertical" />}>
<span>{payment.paymentnum}</span>
<span>{payment.job?.ro_number}</span>
<span>{payment.memo || ""}</span>
<span>{payment.amount || ""}</span>
<span>{payment.transactionid || ""}</span>
</Space>
</Link>
),
};
}),
},
{
label: renderTitle(t("menus.header.search.bills")),
options: resultsByType.bills.map((bill) => {
return {
key: bill.id,
value: `${bill.invoice_number} - ${bill.vendor.name}`,
label: (
<Link to={`/manage/bills?billid=${bill.id}`}>
<Space size="small" split={<Divider type="vertical" />}>
<span>{bill.invoice_number}</span>
<span>{bill.vendor.name}</span>
<span>{bill.date}</span>
</Space>
</Link>
),
};
}),
},
// {
// label: renderTitle(t("menus.header.search.phonebook")),
// options: resultsByType.search_phonebook.map((pb) => {
// return {
// key: pb.id,
// value: `${pb.firstname || ""} ${pb.lastname || ""} ${
// pb.company || ""
// }`,
// label: (
// <Link to={`/manage/phonebook?phonebookentry=${pb.id}`}>
// <Space size="small" split={<Divider type="vertical" />}>
// <span>{`${pb.firstname || ""} ${pb.lastname || ""} ${
// pb.company || ""
// }`}</span>
// <PhoneNumberFormatter>{pb.phone1}</PhoneNumberFormatter>
// <span>{pb.email}</span>
// </Space>
// </Link>
// ),
// };
// }),
// },
]);
} catch (error) {
console.log("Error while fetching search results", error);
} finally {
setLoading(false);
}
}
};
const debouncedExecuteSearch = _.debounce(executeSearch, 750);
const handleSearch = (value) => {
debouncedExecuteSearch(value);
};
const renderTitle = (title) => {
return <span>{title}</span>;
};
return (
<AutoComplete
options={data}
onSearch={handleSearch}
defaultActiveFirstOption
onSelect={(val, opt) => {
history.push(opt.label.props.to);
}}
onClear={() => setData([])}
>
<Input.Search
size="large"
placeholder={t("general.labels.globalsearch")}
enterButton
allowClear
loading={loading}
/>
</AutoComplete>
);
}

View File

@@ -8,7 +8,7 @@ import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import AlertComponent from "../alert/alert.component";
import OwnerNameDisplay, {
OwnerNameDisplayFunction
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
export default function GlobalSearch() {
@@ -18,11 +18,18 @@ export default function GlobalSearch() {
useLazyQuery(GLOBAL_SEARCH_QUERY);
const executeSearch = (v) => {
if (v && v.variables.search && v.variables.search !== "") callSearch(v);
if (
v &&
v.variables.search &&
v.variables.search !== "" &&
v.variables.search.length >= 3
)
callSearch(v);
};
const debouncedExecuteSearch = _.debounce(executeSearch, 750);
const handleSearch = (value) => {
console.log("Handle Search");
debouncedExecuteSearch({ variables: { search: value } });
};
@@ -37,7 +44,7 @@ export default function GlobalSearch() {
options: data.search_jobs.map((job) => {
return {
key: job.id,
value: job.ro_number,
value: job.ro_number || "N/A",
label: (
<Link to={`/manage/jobs/${job.id}`}>
<Space size="small" split={<Divider type="vertical" />}>

View File

@@ -109,8 +109,8 @@ export function JobsConvertButton({
]}
>
<Select>
{bodyshop.md_ins_cos.map((s) => (
<Select.Option key={s.name} value={s.name}>
{bodyshop.md_ins_cos.map((s, i) => (
<Select.Option key={i} value={s.name}>
{s.name}
</Select.Option>
))}
@@ -219,13 +219,15 @@ export function JobsConvertButton({
</Select>
</Form.Item>
)}
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}
name="ca_gst_registrant"
valuePropName="checked"
>
<Switch />
</Form.Item>
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}
name="ca_gst_registrant"
valuePropName="checked"
>
<Switch />
</Form.Item>
)}
<Form.Item
label={t("jobs.fields.driveable")}
name="driveable"

View File

@@ -224,13 +224,15 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
>
<CurrencyInput />
</Form.Item>
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}
name="ca_gst_registrant"
valuePropName="checked"
>
<Switch />
</Form.Item>
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}
name="ca_gst_registrant"
valuePropName="checked"
>
<Switch />
</Form.Item>
)}
<Form.Item
label={t("jobs.fields.other_amount_payable")}
name="other_amount_payable"

View File

@@ -40,24 +40,26 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
>
<CurrencyInput disabled={jobRO} min={0} />
</Form.Item>
<Tooltip title={t("jobs.labels.ca_gst_all_if_null")}>
<Form.Item
label={t("jobs.fields.ca_customer_gst")}
name="ca_customer_gst"
>
<CurrencyInput
disabled={jobRO}
min={0}
max={
Math.round(
(job.job_totals &&
job.job_totals.totals.federal_tax.amount) ||
0
) / 100
}
/>
</Form.Item>
</Tooltip>
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
<Tooltip title={t("jobs.labels.ca_gst_all_if_null")}>
<Form.Item
label={t("jobs.fields.ca_customer_gst")}
name="ca_customer_gst"
>
<CurrencyInput
disabled={jobRO}
min={0}
max={
Math.round(
(job.job_totals &&
job.job_totals.totals.federal_tax.amount) ||
0
) / 100
}
/>
</Form.Item>
</Tooltip>
)}
<Form.Item
label={t("jobs.fields.other_amount_payable")}
name="other_amount_payable"
@@ -82,12 +84,14 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
>
<CurrencyInput disabled={jobRO || bodyshop.cdk_dealerid} />
</Form.Item>
<Space align="end">
<Form.Item label={t("jobs.fields.ca_bc_pvrt")} name="ca_bc_pvrt">
<CurrencyInput disabled={jobRO} min={0} />
</Form.Item>
<CABCpvrtCalculator form={form} disabled={jobRO} />
</Space>
{bodyshop.region_config === "CA_BC" && (
<Space align="center">
<Form.Item label={t("jobs.fields.ca_bc_pvrt")} name="ca_bc_pvrt">
<CurrencyInput disabled={jobRO} min={0} />
</Form.Item>
<CABCpvrtCalculator form={form} disabled={jobRO} />
</Space>
)}
<Form.Item
label={t("jobs.fields.auto_add_ats")}
name="auto_add_ats"
@@ -141,13 +145,15 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
>
<InputNumber min={0} max={1} precision={2} disabled={jobRO} />
</Form.Item>
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}
name="ca_gst_registrant"
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
{bodyshop.region_config.toLowerCase().startsWith("ca") && (
<Form.Item
label={t("jobs.fields.ca_gst_registrant")}
name="ca_gst_registrant"
valuePropName="checked"
>
<Switch disabled={jobRO} />
</Form.Item>
)}
</FormRow>
<Divider
orientation="left"

View File

@@ -1,7 +1,7 @@
import { EditFilled, FileExcelFilled, SyncOutlined } from "@ant-design/icons";
import { Button, Card, Col, Row, Space } from "antd";
import React, { useEffect, useState } from "react";
import Gallery from "react-grid-gallery";
import { Gallery } from "react-grid-gallery";
import { useTranslation } from "react-i18next";
import DocumentsUploadComponent from "../documents-upload/documents-upload.component";
import { DetermineFileType } from "../documents-upload/documents-upload.utility";
@@ -11,6 +11,9 @@ import JobsDocumentsGalleryReassign from "./jobs-document-gallery.reassign.compo
import JobsDocumentsDeleteButton from "./jobs-documents-gallery.delete.component";
import JobsDocumentsGallerySelectAllComponent from "./jobs-documents-gallery.selectall.component";
import Lightbox from "react-image-lightbox";
import "react-image-lightbox/style.css";
function JobsDocumentsComponent({
data,
jobId,
@@ -23,11 +26,7 @@ function JobsDocumentsComponent({
}) {
const [galleryImages, setgalleryImages] = useState({ images: [], other: [] });
const { t } = useTranslation();
const [index, setIndex] = useState(0);
const onCurrentImageChange = (index) => {
setIndex(index);
};
const [modalState, setModalState] = useState({ open: false, index: 0 });
useEffect(() => {
let documents = data.reduce(
@@ -35,14 +34,16 @@ function JobsDocumentsComponent({
const fileType = DetermineFileType(value.type);
if (value.type.startsWith("image")) {
acc.images.push({
src: GenerateSrcUrl(value),
thumbnail: GenerateThumbUrl(value),
thumbnailHeight: 225,
thumbnailWidth: 225,
// src: GenerateSrcUrl(value),
src: GenerateThumbUrl(value),
// src: GenerateSrcUrl(value),
// thumbnail: GenerateThumbUrl(value),
fullsize: GenerateSrcUrl(value),
height: 225,
width: 225,
isSelected: false,
key: value.key,
extension: value.extension,
id: value.id,
type: value.type,
size: value.size,
@@ -62,7 +63,7 @@ function JobsDocumentsComponent({
const fileName = value.key.split("/").pop();
acc.other.push({
source: GenerateSrcUrl(value),
src: "",
src: thumb,
thumbnail: thumb,
tags: [
{
@@ -85,10 +86,9 @@ function JobsDocumentsComponent({
]
: []),
],
thumbnailHeight: 225,
thumbnailWidth: 225,
height: 225,
width: 225,
isSelected: false,
extension: value.extension,
key: value.key,
id: value.id,
@@ -148,35 +148,15 @@ function JobsDocumentsComponent({
<Card title={t("jobs.labels.documents-images")}>
<Gallery
images={galleryImages.images}
backdropClosesModal={true}
currentImageWillChange={onCurrentImageChange}
customControls={[
<Button
key="edit-button"
style={{
float: "right",
zIndex: "5",
}}
onClick={() => {
const newWindow = window.open(
`${window.location.protocol}//${window.location.host}/edit?documentId=${galleryImages.images[index].id}`,
"_blank",
"noopener,noreferrer"
);
if (newWindow) newWindow.opener = null;
}}
>
<EditFilled />
</Button>,
]}
onClickImage={(props) => {
window.open(
props.target.src,
"_blank",
"toolbar=0,location=0,menubar=0"
);
onClick={(index, item) => {
setModalState({ open: true, index: index });
// window.open(
// item.fullsize,
// "_blank",
// "toolbar=0,location=0,menubar=0"
// );
}}
onSelectImage={(index, image) => {
onSelect={(index, image) => {
setgalleryImages({
...galleryImages,
images: galleryImages.images.map((g, idx) =>
@@ -191,8 +171,6 @@ function JobsDocumentsComponent({
<Card title={t("jobs.labels.documents-other")}>
<Gallery
images={galleryImages.other}
backdropClosesModal={true}
enableLightbox={false}
thumbnailStyle={() => {
return {
backgroundImage: <FileExcelFilled />,
@@ -201,14 +179,14 @@ function JobsDocumentsComponent({
cursor: "pointer",
};
}}
onClickThumbnail={(index) => {
onClick={(index) => {
window.open(
galleryImages.other[index].source,
"_blank",
"toolbar=0,location=0,menubar=0"
);
}}
onSelectImage={(index) => {
onSelect={(index) => {
setgalleryImages({
...galleryImages,
other: galleryImages.other.map((g, idx) =>
@@ -219,6 +197,53 @@ function JobsDocumentsComponent({
/>
</Card>
</Col>
{modalState.open && (
<Lightbox
toolbarButtons={[
<EditFilled
onClick={() => {
const newWindow = window.open(
`${window.location.protocol}//${
window.location.host
}/edit?documentId=${
galleryImages.images[modalState.index].id
}`,
"_blank",
"noopener,noreferrer"
);
if (newWindow) newWindow.opener = null;
}}
/>,
]}
mainSrc={galleryImages.images[modalState.index].fullsize}
nextSrc={
galleryImages.images[
(modalState.index + 1) % galleryImages.images.length
].fullsize
}
prevSrc={
galleryImages.images[
(modalState.index + galleryImages.images.length - 1) %
galleryImages.images.length
].fullsize
}
onCloseRequest={() => setModalState({ open: false, index: 0 })}
onMovePrevRequest={() =>
setModalState({
...modalState,
index:
(modalState.index + galleryImages.images.length - 1) %
galleryImages.images.length,
})
}
onMoveNextRequest={() =>
setModalState({
...modalState,
index: (modalState.index + 1) % galleryImages.images.length,
})
}
/>
)}
</Row>
</div>
);

View File

@@ -1,7 +1,7 @@
import React, { useEffect } from "react";
import Gallery from "react-grid-gallery";
import { Gallery } from "react-grid-gallery";
import { useTranslation } from "react-i18next";
import { GenerateSrcUrl, GenerateThumbUrl } from "./job-documents.utility";
import { GenerateThumbUrl } from "./job-documents.utility";
function JobsDocumentGalleryExternal({
data,
@@ -15,8 +15,8 @@ function JobsDocumentGalleryExternal({
let documents = data.reduce((acc, value) => {
if (value.type.startsWith("image")) {
acc.push({
src: GenerateSrcUrl(value),
thumbnail: GenerateThumbUrl(value),
//src: GenerateSrcUrl(value),
src: GenerateThumbUrl(value),
thumbnailHeight: 225,
thumbnailWidth: 225,
isSelected: false,
@@ -39,7 +39,7 @@ function JobsDocumentGalleryExternal({
<Gallery
images={galleryImages}
backdropClosesModal={true}
onSelectImage={(index, image) => {
onSelect={(index, image) => {
setgalleryImages(
galleryImages.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g

View File

@@ -1,7 +1,7 @@
import { SyncOutlined, FileExcelFilled } from "@ant-design/icons";
import { Alert, Button, Card, Space } from "antd";
import React, { useEffect } from "react";
import Gallery from "react-grid-gallery";
import React, { useEffect, useState } from "react";
import { Gallery } from "react-grid-gallery";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -19,6 +19,9 @@ import JobsLocalGalleryDownloadButton from "./jobs-documents-local-gallery.downl
import JobsDocumentsLocalGalleryReassign from "./jobs-documents-local-gallery.reassign.component";
import JobsDocumentsLocalGallerySelectAllComponent from "./jobs-documents-local-gallery.selectall.component";
import Lightbox from "react-image-lightbox";
import "react-image-lightbox/style.css";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
allMedia: selectAllMedia,
@@ -49,6 +52,7 @@ export function JobsDocumentsLocalGallery({
vendorid,
}) {
const { t } = useTranslation();
const [modalState, setModalState] = useState({ open: false, index: 0 });
useEffect(() => {
if (job) {
if (invoice_number) {
@@ -70,12 +74,20 @@ export function JobsDocumentsLocalGallery({
) {
acc.images.push({
...val,
fullsize: val.src,
src: val.thumbnail,
height: val.thumbnailHeight,
width: val.thumbnailWidth,
...(val.optimized && { src: val.optimized, fullsize: val.src }),
});
if (val.optimized) optimized = true;
} else {
acc.other.push({
...val,
fullsize: val.src,
src: val.thumbnail,
height: val.thumbnailHeight,
width: val.thumbnailWidth,
tags: [{ value: val.filename, title: val.filename }],
});
}
@@ -120,8 +132,7 @@ export function JobsDocumentsLocalGallery({
<Card title={t("jobs.labels.documents-images")}>
<Gallery
images={jobMedia.images}
backdropClosesModal={true}
onSelectImage={(index, image) => {
onSelect={(index, image) => {
toggleMediaSelected({ jobid: job.id, filename: image.filename });
}}
{...(optimized && {
@@ -133,24 +144,23 @@ export function JobsDocumentsLocalGallery({
/>,
],
})}
onClickImage={(props) => {
const media = allMedia[job.id].find(
(m) => m.optimized === props.target.src
);
onClick={(index) => {
setModalState({ open: true, index: index });
// const media = allMedia[job.id].find(
// (m) => m.optimized === item.src
// );
window.open(
media ? media.src : props.target.src,
"_blank",
"toolbar=0,location=0,menubar=0"
);
// window.open(
// media ? media.fullsize : item.fullsize,
// "_blank",
// "toolbar=0,location=0,menubar=0"
// );
}}
/>
</Card>
<Card title={t("jobs.labels.documents-other")}>
<Gallery
images={jobMedia.other}
backdropClosesModal={true}
enableLightbox={false}
thumbnailStyle={() => {
return {
backgroundImage: <FileExcelFilled />,
@@ -159,18 +169,48 @@ export function JobsDocumentsLocalGallery({
cursor: "pointer",
};
}}
onClickThumbnail={(index) => {
onClick={(index) => {
window.open(
jobMedia.other[index].src,
jobMedia.other[index].fullsize,
"_blank",
"toolbar=0,location=0,menubar=0"
);
}}
onSelectImage={(index, image) => {
onSelect={(index, image) => {
toggleMediaSelected({ jobid: job.id, filename: image.filename });
}}
/>
</Card>
{modalState.open && (
<Lightbox
mainSrc={jobMedia.images[modalState.index].fullsize}
nextSrc={
jobMedia.images[(modalState.index + 1) % jobMedia.images.length]
.fullsize
}
prevSrc={
jobMedia.images[
(modalState.index + jobMedia.images.length - 1) %
jobMedia.images.length
].fullsize
}
onCloseRequest={() => setModalState({ open: false, index: 0 })}
onMovePrevRequest={() =>
setModalState({
...modalState,
index:
(modalState.index + jobMedia.images.length - 1) %
jobMedia.images.length,
})
}
onMoveNextRequest={() =>
setModalState({
...modalState,
index: (modalState.index + 1) % jobMedia.images.length,
})
}
/>
)}
</div>
);
}

View File

@@ -1,5 +1,5 @@
import React, { useEffect } from "react";
import Gallery from "react-grid-gallery";
import { Gallery } from "react-grid-gallery";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -38,7 +38,7 @@ function JobDocumentsLocalGalleryExternal({
const { t } = useTranslation();
useEffect(() => {
if ( jobId) {
if (jobId) {
getJobMedia(jobId);
}
}, [jobId, getJobMedia]);
@@ -52,11 +52,15 @@ function JobDocumentsLocalGalleryExternal({
val.type.mime &&
val.type.mime.startsWith("image")
) {
acc.push(val);
acc.push({ ...val, src: val.thumbnail });
}
return acc;
}, [])
: [];
console.log(
"🚀 ~ file: jobs-documents-local-gallery.external.component.jsx:48 ~ useEffect ~ documents:",
documents
);
setgalleryImages(documents);
}, [allMedia, jobId, setgalleryImages, t]);
@@ -65,8 +69,7 @@ function JobDocumentsLocalGalleryExternal({
<div className="clearfix">
<Gallery
images={galleryImages}
backdropClosesModal={true}
onSelectImage={(index, image) => {
onSelect={(index, image) => {
setgalleryImages(
galleryImages.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g

View File

@@ -1,8 +1,9 @@
import { SyncOutlined } from "@ant-design/icons";
import { Button, Card, Input, Space, Table, Typography } from "antd";
import axios from "axios";
import _ from "lodash";
import queryString from "query-string";
import React from "react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useHistory, useLocation } from "react-router-dom";
@@ -21,6 +22,8 @@ const mapDispatchToProps = (dispatch) => ({
export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
const search = queryString.parse(useLocation().search);
const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false);
const { page, sortcolumn, sortorder } = search;
const history = useHistory();
@@ -193,6 +196,28 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
history.push({ search: queryString.stringify(search) });
};
useEffect(() => {
if (search.search && search.search.trim() !== "") {
searchJobs();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
async function searchJobs(value) {
try {
setSearchLoading(true);
const searchData = await axios.post("/search", {
search: value || search.search,
index: "jobs",
});
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
} catch (error) {
console.log("Error while fetching search results", error);
} finally {
setSearchLoading(false);
}
}
return (
<Card
extra={
@@ -205,6 +230,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
<Button
onClick={() => {
delete search.search;
delete search.page;
history.push({ search: queryString.stringify(search) });
}}
>
@@ -220,24 +246,32 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
searchJobs(value);
}}
loading={loading || searchLoading}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
showSizeChanger: false,
}}
loading={loading || searchLoading}
pagination={
search?.search
? {
pageSize: 25,
showSizeChanger: false,
}
: {
pageSize: 25,
current: parseInt(page || 1),
total: total,
showSizeChanger: false,
}
}
columns={columns}
rowKey="id"
dataSource={jobs}
dataSource={search?.search ? openSearchResults : jobs}
onChange={handleTableChange}
/>
</Card>

View File

@@ -75,6 +75,27 @@ export function JobNotesComponent({
</span>
),
},
{
title: t("notes.fields.type"),
dataIndex: "type",
key: "type",
width: 120,
filteredValue: filter?.type || null,
filters: [
{ value: "general", text: t("notes.fields.types.general") },
{ value: "customer", text: t("notes.fields.types.customer") },
{ value: "shop", text: t("notes.fields.types.shop") },
{ value: "office", text: t("notes.fields.types.office") },
{ value: "parts", text: t("notes.fields.types.parts") },
{ value: "paint", text: t("notes.fields.types.paint") },
{
value: "supplement",
text: t("notes.fields.types.supplement"),
},
],
onFilter: (value, record) => value.includes(record.type),
render: (text, record) => t(`notes.fields.types.${record.type}`),
},
{
title: t("notes.fields.text"),
dataIndex: "text",
@@ -106,7 +127,7 @@ export function JobNotesComponent({
title: t("notes.actions.actions"),
dataIndex: "actions",
key: "actions",
width: 150,
width: 200,
render: (text, record) => (
<Space wrap>
<Button

View File

@@ -207,7 +207,7 @@ export function LaborAllocationsTable({
<Card title={t("jobs.labels.laborallocations")}>
<Table
columns={columns}
rowKey="cost_center"
rowKey={(record) => `${record.cost_center} ${record.mod_lbr_ty}`}
pagination={false}
onChange={handleTableChange}
dataSource={totals}

View File

@@ -6,10 +6,6 @@ export const CalculateAllocationsTotals = (
timetickets,
adjustments = []
) => {
console.log(
"🚀 ~ file: labor-allocations-table.utility.js ~ line 9 ~ adjustments",
adjustments
);
const responsibilitycenters = bodyshop.md_responsibility_centers;
const jobCodes = joblines.map((item) => item.mod_lbr_ty);
//.filter((value, index, self) => self.indexOf(value) === index && !!value);

View File

@@ -1,4 +1,14 @@
import { Checkbox, Col, Form, Input, Row, Space, Switch, Tag } from "antd";
import {
Checkbox,
Col,
Form,
Input,
Row,
Select,
Space,
Switch,
Tag,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -46,6 +56,28 @@ export function NoteUpsertModalComponent({ form, noteUpsertModal }) {
<Switch />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
label={t("notes.fields.type")}
name="type"
initialValue="general"
>
<Select
options={[
{ value: "general", label: t("notes.fields.types.general") },
{ value: "customer", label: t("notes.fields.types.customer") },
{ value: "shop", label: t("notes.fields.types.shop") },
{ value: "office", label: t("notes.fields.types.office") },
{ value: "parts", label: t("notes.fields.types.parts") },
{ value: "paint", label: t("notes.fields.types.paint") },
{
value: "supplement",
label: t("notes.fields.types.supplement"),
},
]}
/>
</Form.Item>
</Col>
<Col span={8}>
<NotesPresetButton form={form} />
</Col>

View File

@@ -34,7 +34,7 @@ export function NoteUpsertModalContainer({
const [updateNote] = useMutation(UPDATE_NOTE);
const { visible, context, actions } = noteUpsertModal;
const { jobId, existingNote } = context;
const { jobId, existingNote, text } = context;
const { refetch } = actions;
const [form] = Form.useForm();
@@ -45,8 +45,12 @@ export function NoteUpsertModalContainer({
form.setFieldsValue(existingNote);
} else if (!existingNote && visible) {
form.resetFields();
if (text) {
form.setFieldValue("text", text);
}
}
}, [existingNote, form, visible]);
}, [existingNote, form, visible, text]);
const handleFinish = async (formValues) => {
const { relatedros, ...values } = formValues;
@@ -82,6 +86,7 @@ export function NoteUpsertModalContainer({
{ ...values, jobid: jobId, created_by: currentUser.email },
],
},
refetchQueries: ["QUERY_NOTES_BY_JOB_PK"],
});
if (AdditionalNoteInserts.length > 0) {

View File

@@ -201,6 +201,7 @@ export function PartsOrderListTableComponent({
subject: record.return
? Templates.parts_return_slip.subject
: Templates.parts_order.subject,
to: record.vendor.email,
}}
id={job.id}
/>
@@ -296,7 +297,6 @@ export function PartsOrderListTableComponent({
sortOrder:
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
},
{
title: t("parts_orders.fields.act_price"),
dataIndex: "act_price",

View File

@@ -52,7 +52,7 @@ function PaymentModalContainer({
const { useStripe, sendby, ...paymentObj } = values;
setLoading(true);
let updatedPayment; //Moved up from if statement for greater scope.
try {
if (!context || (context && !context.id)) {
const newPayment = await insertPayment({
@@ -87,7 +87,7 @@ function PaymentModalContainer({
);
}
} else {
const updatedPayment = await updatePayment({
updatedPayment = await updatePayment({
variables: {
paymentId: context.id,
payment: paymentObj,
@@ -101,7 +101,11 @@ function PaymentModalContainer({
}
}
if (actions.refetch) actions.refetch();
if (actions.refetch)
actions.refetch(
updatedPayment && updatedPayment.data.update_payments.returning[0]
);
if (enterAgain) {
const prev = form.getFieldsValue(["date"]);

View File

@@ -1,20 +1,23 @@
import { EditFilled, SyncOutlined } from "@ant-design/icons";
import { useApolloClient } from "@apollo/client";
import { Button, Card, Input, Space, Table, Typography } from "antd";
import axios from "axios";
import queryString from "query-string";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { QUERY_PAYMENT_BY_ID } from "../../graphql/payments.queries";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters";
import { TemplateList } from "../../utils/TemplateConstants";
import { alphaSort } from "../../utils/sorters";
import CaBcEtfTableModalContainer from "../ca-bc-etf-table-modal/ca-bc-etf-table-modal.container";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -39,7 +42,10 @@ export function PaymentsListPaginated({
bodyshop,
}) {
const search = queryString.parse(useLocation().search);
const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false);
const { page, sortcolumn, sortorder } = search;
const client = useApolloClient();
const history = useHistory();
const [state, setState] = useState({
sortedInfo: {},
@@ -52,13 +58,17 @@ export function PaymentsListPaginated({
title: t("jobs.fields.ro_number"),
dataIndex: "ro_number",
key: "ro_number",
sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
sortOrder: sortcolumn === "ro_number" && sortorder,
render: (text, record) => (
<Link to={"/manage/jobs/" + record.job.id}>
{record.job.ro_number || t("general.labels.na")}
</Link>
),
// sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
// sortOrder: sortcolumn === "ro_number" && sortorder,
render: (text, record) => {
return record.job ? (
<Link to={"/manage/jobs/" + record.job.id}>
{record.job.ro_number || t("general.labels.na")}
</Link>
) : (
<span>{t("general.labels.na")}</span>
);
},
},
{
title: t("payments.fields.paymentnum"),
@@ -72,16 +82,16 @@ export function PaymentsListPaginated({
dataIndex: "owner",
key: "owner",
ellipsis: true,
sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln),
sortOrder: sortcolumn === "owner" && sortorder,
// sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln),
// sortOrder: sortcolumn === "owner" && sortorder,
render: (text, record) => {
return record.job.owner ? (
<Link to={"/manage/owners/" + record.job.owner.id}>
<OwnerNameDisplay ownerObject={record} />
return record.job?.owner ? (
<Link to={"/manage/owners/" + record.job?.owner?.id}>
<OwnerNameDisplay ownerObject={record.job} />
</Link>
) : (
<span>
<OwnerNameDisplay ownerObject={record} />
<OwnerNameDisplay ownerObject={record.job} />
</span>
);
},
@@ -147,10 +157,33 @@ export function PaymentsListPaginated({
<Space>
<Button
disabled={record.exportedat}
onClick={() => {
onClick={async () => {
let apolloResults;
if (search.search) {
const { data } = await client.query({
query: QUERY_PAYMENT_BY_ID,
variables: {
paymentId: record.id,
},
});
apolloResults = data.payments_by_pk;
}
setPaymentContext({
actions: { refetch: refetch },
context: record,
actions: {
refetch: apolloResults
? (updatedRecord) => {
setOpenSearchResults((results) =>
results.map((result) => {
if (result.id !== record.id) {
return result;
}
return updatedRecord;
})
);
}
: refetch,
},
context: apolloResults ? apolloResults : record,
});
}}
>
@@ -177,6 +210,28 @@ export function PaymentsListPaginated({
history.push({ search: queryString.stringify(search) });
};
useEffect(() => {
if (search.search && search.search.trim() !== "") {
searchPayments();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
async function searchPayments(value) {
try {
setSearchLoading(true);
const searchData = await axios.post("/search", {
search: value || search.search,
index: "payments",
});
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
} catch (error) {
console.log("Error while fetching search results", error);
} finally {
setSearchLoading(false);
}
}
return (
<Card
extra={
@@ -189,6 +244,7 @@ export function PaymentsListPaginated({
<Button
onClick={() => {
delete search.search;
delete search.page;
history.push({ search: queryString.stringify(search) });
}}
>
@@ -212,24 +268,33 @@ export function PaymentsListPaginated({
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
searchPayments(value);
}}
loading={loading || searchLoading}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
loading={loading || searchLoading}
scroll={{ x: true }}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
pagination={
search?.search
? {
pageSize: 25,
showSizeChanger: false,
}
: {
pageSize: 25,
current: parseInt(page || 1),
total: total,
showSizeChanger: false,
}
}
columns={columns}
rowKey="id"
dataSource={payments}
dataSource={search?.search ? openSearchResults : payments}
onChange={handleTableChange}
/>
</Card>

View File

@@ -29,7 +29,10 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop }) {
})
.filter(
(temp) =>
!temp.regions || (temp.regions && temp.regions[bodyshop.region_config])
!temp.regions ||
(temp.regions && temp.regions[bodyshop.region_config]) ||
(temp.regions &&
bodyshop.region_config.includes(Object.keys(temp.regions)) === true)
);
const filteredJobsReportsList =

View File

@@ -0,0 +1,51 @@
import { Col, List, Space, Typography } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
const CardColorLegend = ({ bodyshop }) => {
const { t } = useTranslation();
const data = bodyshop.ssbuckets.map((bucket) => {
let color = { r: 255, g: 255, b: 255 };
if (bucket.color) {
color = bucket.color;
if (bucket.color.rgb) {
color = bucket.color.rgb;
}
}
return {
label: bucket.label,
color,
};
});
return (
<Col>
<Typography>{t("production.labels.legend")}</Typography>
<List
grid={{
gutter: 16,
}}
dataSource={data}
renderItem={(item) => (
<List.Item>
<Space>
<div
style={{
width: "1.5rem",
aspectRatio: "1/1",
backgroundColor: `rgba(${item.color.r},${item.color.g},${item.color.b},${item.color.a})`,
}}
></div>
<div>{item.label}</div>
</Space>
</List.Item>
)}
/>
</Col>
);
};
export default CardColorLegend;

View File

@@ -18,6 +18,31 @@ import moment from "moment";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
const cardColor = (ssbuckets, totalHrs) => {
const bucket = ssbuckets.filter(
(bucket) =>
bucket.gte <= totalHrs && (!!bucket.lt ? bucket.lt > totalHrs : true)
)[0];
let color = { r: 255, g: 255, b: 255 };
if (bucket && bucket.color) {
color = bucket.color;
if (bucket.color.rgb) {
color = bucket.color.rgb;
}
}
return color;
};
function getContrastYIQ(bgColor) {
const yiq = (bgColor.r * 299 + bgColor.g * 587 + bgColor.b * 114) / 1000;
return yiq >= 128 ? "black" : "white";
}
export default function ProductionBoardCard(
technician,
card,
@@ -54,10 +79,22 @@ export default function ProductionBoardCard(
.isSame(moment(card.scheduled_completion), "day") &&
"production-completion-soon"));
const totalHrs =
card.labhrs.aggregate.sum.mod_lb_hrs + card.larhrs.aggregate.sum.mod_lb_hrs;
const bgColor = cardColor(bodyshop.ssbuckets, totalHrs);
return (
<Card
className="react-kanban-card imex-kanban-card"
size="small"
style={{
backgroundColor:
cardSettings &&
cardSettings.cardcolor &&
`rgba(${bgColor.r},${bgColor.g},${bgColor.b},${bgColor.a})`,
color:
cardSettings && cardSettings.cardcolor && getContrastYIQ(bgColor),
}}
title={
<Space>
<ProductionAlert record={card} key="alert" />

View File

@@ -104,6 +104,13 @@ export default function ProductionBoardKanbanCardSettings({
>
<Switch />
</Form.Item>
<Form.Item
valuePropName="checked"
label={t("production.labels.cardcolor")}
name="cardcolor"
>
<Switch />
</Form.Item>
</Col>
<Col span={12}>
<Form.Item
@@ -166,7 +173,7 @@ export default function ProductionBoardKanbanCardSettings({
</div>
);
return (
<Popover content={overlay} visible={visible}>
<Popover content={overlay} visible={visible} placement="topRight">
<Button loading={loading} onClick={() => setVisible(true)}>
{t("production.labels.cardsettings")}
</Button>

View File

@@ -22,6 +22,7 @@ import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-se
//import "@asseinfo/react-kanban/dist/styles.css";
import "./production-board-kanban.styles.scss";
import { createBoardData } from "./production-board-kanban.utils.js";
import CardColorLegend from "../production-board-kanban-card/production-board-kanban-card-color-legend.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
technician: selectTechnician,
@@ -221,6 +222,7 @@ export function ProductionBoardKanbanComponent({
employeeassignments: true,
scheduled_completion: true,
stickyheader: false,
cardcolor: false,
};
return (
@@ -256,6 +258,11 @@ export function ProductionBoardKanbanComponent({
</Space>
}
/>
{cardSettings.cardcolor && (
<CardColorLegend cardSettings={cardSettings} bodyshop={bodyshop} />
)}
<ProductionListDetailComponent jobs={data} />
<StickyContainer>
<Board

View File

@@ -91,11 +91,13 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
b.v_make_desc + b.v_model_desc
),
sortOrder:
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
render: (text, record) => (
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
} ${record.v_color || ""} ${record.plate_no || ""}`}</span>
<Link to={`/manage/vehicles/${record.vehicleid}`}>{`${
record.v_model_yr || ""
} ${record.v_make_desc || ""} ${record.v_model_desc || ""} ${
record.v_color || ""
} ${record.plate_no || ""}`}</Link>
),
},
{

View File

@@ -1,12 +1,23 @@
import Icon from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import { Button, Input, Popover } from "antd";
import { Button, Input, Popover, Space } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { FaRegStickyNote } from "react-icons/fa";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
export default function ProductionListColumnProductionNote({ record }) {
import { setModalContext } from "../../redux/modals/modals.actions";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({
setNoteUpsertContext: (context) =>
dispatch(setModalContext({ context: context, modal: "noteUpsert" })),
});
function ProductionListColumnProductionNote({ record, setNoteUpsertContext }) {
const { t } = useTranslation();
const [note, setNote] = useState(
@@ -60,12 +71,26 @@ export default function ProductionListColumnProductionNote({ record }) {
// onPressEnter={handleSaveNote}
autoFocus
allowClear
style={{ marginBottom: "1em" }}
/>
<div>
<Button onClick={handleSaveNote}>
<Space>
<Button onClick={handleSaveNote} type="primary">
{t("general.actions.save")}
</Button>
</div>
<Button
onClick={() => {
setVisible(false);
setNoteUpsertContext({
context: {
jobId: record.id,
text: note,
},
});
}}
>
{t("notes.actions.savetojobnotes")}
</Button>
</Space>
</div>
}
trigger={["click"]}
@@ -85,3 +110,8 @@ export default function ProductionListColumnProductionNote({ record }) {
</Popover>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProductionListColumnProductionNote);

View File

@@ -81,7 +81,7 @@ export function ProductionListTable({
state,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
}).find((e) => e.key === k.key),
width: k.width,
width: k.width ?? 100,
};
})) ||
[]
@@ -267,6 +267,8 @@ export function ProductionListTable({
sortOrder:
state.sortedInfo.columnKey === c.key && state.sortedInfo.order,
title: headerItem(c),
ellipsis: true,
width: c.width ?? 100,
onHeaderCell: (column) => ({
width: column.width,
onResize: handleResize(index),
@@ -276,11 +278,12 @@ export function ProductionListTable({
rowKey="id"
loading={loading}
dataSource={dataSource}
// scroll={{ x: true }}
scroll={{ x: 1000 }}
onChange={handleTableChange}
/>
</ReactDragListView.DragColumn>
</div>
);
}
export default connect(mapStateToProps, null)(ProductionListTable);

View File

@@ -3,8 +3,26 @@ import { Resizable } from "react-resizable";
export default function ResizableComponent(props) {
const { onResize, width, ...restProps } = props;
if (!width) {
return <th {...restProps} />;
}
return (
<Resizable width={width || 200} height={0} onResize={onResize}>
<Resizable
width={width || 200}
height={0}
onResize={onResize}
draggableOpts={{ enableUserSelectHack: false }}
handle={
<span
className="react-resizable-handle"
onClick={(e) => {
e.stopPropagation();
}}
/>
}
>
<th {...restProps} />
</Resizable>
);

View File

@@ -92,7 +92,11 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
to: values.to,
subject: Templates[values.key]?.subject,
},
values.sendby === "email" ? "e" : "p",
values.sendbyexcel === "excel"
? "x"
: values.sendby === "email"
? "e"
: "p",
id
);
setLoading(false);
@@ -250,15 +254,38 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
ranges={DatePIckerRanges}
/>
</Form.Item>
<Form.Item
label={t("general.labels.sendby")}
name="sendby"
initialValue="print"
>
<Radio.Group>
<Radio value="email">{t("general.labels.email")}</Radio>
<Radio value="print">{t("general.labels.print")}</Radio>
</Radio.Group>
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
{() => {
const key = form.getFieldValue("key");
//Kind of Id
const reporttype = Templates[key] && Templates[key].reporttype;
if (reporttype === "excel")
return (
<Form.Item
label={t("general.labels.sendby")}
name="sendbyexcel"
initialValue="excel"
>
<Radio.Group>
<Radio value="excel">{t("general.labels.excel")}</Radio>
</Radio.Group>
</Form.Item>
);
if (reporttype !== "excel")
return (
<Form.Item
label={t("general.labels.sendby")}
name="sendby"
initialValue="print"
>
<Radio.Group>
<Radio value="email">{t("general.labels.email")}</Radio>
<Radio value="print">{t("general.labels.print")}</Radio>
</Radio.Group>
</Form.Item>
);
}}
</Form.Item>
<div

View File

@@ -0,0 +1,39 @@
import Dinero from "dinero.js";
const CustomTooltip = ({ active, payload, label }) => {
if (active && payload && payload.length) {
return (
<div
style={{
backgroundColor: "white",
border: "1px solid gray",
padding: "0.5rem",
}}
>
<p style={{ margin: "0" }}>{label}</p>
{payload.map((data, index) => {
if (data.dataKey === "sales" || data.dataKey === "accSales")
return (
<p
style={{ margin: "10px 0", color: data.color }}
key={index}
>{`${data.name} : ${Dinero({
amount: Math.round(data.value * 100),
}).toFormat()}`}</p>
);
return (
<p
style={{ margin: "10px 0", color: data.color }}
key={index}
>{`${data.name} : ${data.value}`}</p>
);
})}
</div>
);
}
return null;
};
export default CustomTooltip;

View File

@@ -1,4 +1,6 @@
import { Card } from "antd";
import Dinero from "dinero.js";
import _ from "lodash";
import moment from "moment";
import React from "react";
import { connect } from "react-redux";
@@ -17,7 +19,7 @@ import {
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
import _ from "lodash";
import CustomTooltip from "./chart-custom-tooltip";
const graphProps = {
strokeWidth: 3,
@@ -44,14 +46,19 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
return {
bodyhrs: dayAcc.bodyhrs + dayVal.bodyhrs,
painthrs: dayAcc.painthrs + dayVal.painthrs,
sales:
dayAcc.painthrs +
dayVal.job.job_totals.totals.subtotal.amount / 100 +
2500,
};
},
{ bodyhrs: 0, painthrs: 0 }
{ bodyhrs: 0, painthrs: 0, sales: 0 }
);
} else {
dayhrs = {
bodyhrs: 0,
painthrs: 0,
sales: 0,
};
}
@@ -64,7 +71,9 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
bodyshop.scoreboard_target.dailyBodyTarget +
bodyshop.scoreboard_target.dailyPaintTarget,
val
),
) +
bodyshop.scoreboard_target.dailyBodyTarget +
bodyshop.scoreboard_target.dailyPaintTarget,
1
),
accHrs: _.round(
@@ -73,6 +82,13 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
: dayhrs.painthrs + dayhrs.bodyhrs,
1
),
sales: _.round(dayhrs.sales, 2),
accSales: _.round(
acc.length > 0
? acc[acc.length - 1].accSales + dayhrs.sales
: dayhrs.sales,
2
),
};
return [...acc, theValue];
@@ -87,22 +103,27 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
>
<CartesianGrid stroke="#f5f5f5" />
<XAxis dataKey="date" strokeWidth={graphProps.strokeWidth} />
<YAxis strokeWidth={graphProps.strokeWidth} />
<Tooltip />
<Legend />
<Area
type="monotone"
name="Accumulated Hours"
dataKey="accHrs"
fill="lightgreen"
stroke="green"
<YAxis
strokeWidth={graphProps.strokeWidth}
// allowDataOverflow
dataKey="sales"
yAxisId="right"
tickFormatter={(value) =>
Dinero({ amount: Math.round(value * 100) }).toFormat()
}
orientation="right"
/>
<YAxis yAxisId="left" strokeWidth={graphProps.strokeWidth} />
<Tooltip content={<CustomTooltip />} />
<Legend />
<Bar
name="Body Hours"
dataKey="bodyHrs"
stackId="day"
barSize={20}
fill="darkblue"
yAxisId="left"
/>
<Bar
name="Paint Hours"
@@ -110,12 +131,42 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
stackId="day"
barSize={20}
fill="darkred"
yAxisId="left"
/>
<Line
name="Target Hours"
type="monotone"
dataKey="accTargetHrs"
stroke="#ff7300"
yAxisId="left"
strokeWidth={graphProps.strokeWidth}
/>
<Area
type="monotone"
name="MTD Hours"
dataKey="accHrs"
fill="lightblue"
stroke="blue"
yAxisId="left"
/>
{
// <Area
// type="monotone"
// name="MTD Sales"
// dataKey="accSales"
// fill="lightgreen"
// stroke="green"
// yAxisId="right"
// />
}
<Bar
name="Sales"
dataKey="sales"
stackId="day"
barSize={20}
fill="darkgreen"
yAxisId="right"
strokeWidth={graphProps.strokeWidth}
/>
</ComposedChart>

View File

@@ -1,4 +1,4 @@
import { Card, Statistic } from "antd";
import { Card, Divider, Statistic } from "antd";
import moment from "moment";
import React from "react";
import { connect } from "react-redux";
@@ -41,6 +41,9 @@ export function ScoreboardDayStats({ bodyshop, date, entries }) {
label="P"
value={paintHrs.toFixed(1)}
/>
<Divider style={{ margin: 0 }} />
<Statistic value={(bodyHrs + paintHrs).toFixed(1)} />
</Card>
);
}

View File

@@ -1,5 +1,5 @@
import { CalendarOutlined } from "@ant-design/icons";
import { Card, Col, Row, Statistic } from "antd";
import { Card, Col, Divider, Row, Statistic } from "antd";
import _ from "lodash";
import moment from "moment";
import React, { useMemo } from "react";
@@ -177,6 +177,9 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
<Statistic value={values.toDatePaint.toFixed(1)} />
</Col>
</Row>
<Row>
<Divider style={{ margin: 5 }} />
</Row>
<Row>
<Col {...statSpans}></Col>
<Col {...statSpans}>
@@ -184,14 +187,53 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
value={(values.todayPaint + values.todayBody).toFixed(1)}
/>
</Col>
<Col {...statSpans}></Col>
<Col {...statSpans}>
<Statistic
value={(
Util.WeeklyTargetHrs(
bodyshop.scoreboard_target.dailyBodyTarget,
bodyshop
) +
Util.WeeklyTargetHrs(
bodyshop.scoreboard_target.dailyPaintTarget,
bodyshop
)
).toFixed(1)}
/>
</Col>
<Col {...statSpans}>
<Statistic
value={(values.weeklyPaint + values.weeklyBody).toFixed(1)}
/>
</Col>
<Col {...statSpans}></Col>
<Col {...statSpans}></Col>
<Col {...statSpans}>
<Statistic
value={(
Util.MonthlyTargetHrs(
bodyshop.scoreboard_target.dailyBodyTarget,
bodyshop
) +
Util.MonthlyTargetHrs(
bodyshop.scoreboard_target.dailyPaintTarget,
bodyshop
)
).toFixed(1)}
/>
</Col>
<Col {...statSpans}>
<Statistic
value={(
Util.AsOfTodayTargetHrs(
bodyshop.scoreboard_target.dailyBodyTarget,
bodyshop
) +
Util.AsOfTodayTargetHrs(
bodyshop.scoreboard_target.dailyPaintTarget,
bodyshop
)
).toFixed(1)}
/>
</Col>
<Col {...statSpans}>
<Statistic
value={(values.toDatePaint + values.toDateBody).toFixed(1)}

View File

@@ -81,6 +81,7 @@ export default function ScoreboardTimeTickets() {
totalLastMonth: 0,
totalOverPeriod: 0,
actualTotalOverPeriod: 0,
totalEffieciencyOverPeriod: 0,
employees: {},
};
data.fixedperiod.forEach((ticket) => {
@@ -94,6 +95,7 @@ export default function ScoreboardTimeTickets() {
totalLastMonth: 0,
totalOverPeriod: 0,
actualTotalOverPeriod: 0,
totalEffieciencyOverPeriod: 0,
};
}
@@ -221,6 +223,30 @@ export default function ScoreboardTimeTickets() {
ret2.push(r);
});
// Add total efficiency of employees
const totalActualAndProductive = Object.keys(ret.employees)
.map((key) => {
return { employee_number: key, ...ret.employees[key] };
})
.reduce(
(acc, e) => {
return {
totalOverPeriod: acc.totalOverPeriod + e.totalOverPeriod,
actualTotalOverPeriod:
acc.actualTotalOverPeriod + e.actualTotalOverPeriod,
};
},
{ totalOverPeriod: 0, actualTotalOverPeriod: 0 }
);
ret.totalEffieciencyOverPeriod =
totalActualAndProductive.actualTotalOverPeriod
? (totalActualAndProductive.totalOverPeriod /
totalActualAndProductive.actualTotalOverPeriod) *
100
: 0;
roundObject(ret);
roundObject(totals);
roundObject(ret2);

View File

@@ -62,7 +62,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
key: "efficiencyoverperiod",
render: (text, record) =>
`${(
(record.totalOverPeriod / (record.actualTotalOverPeriod || .1)) *
(record.totalOverPeriod / (record.actualTotalOverPeriod || 0.1)) *
100
).toFixed(1)} %`,
},
@@ -113,6 +113,12 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
value={data.totalOverPeriod}
/>
</Col>
<Col span={12}>
<Statistic
title={t("scoreboard.labels.efficiencyoverperiod")}
value={`${data.totalEffieciencyOverPeriod || 0}%`}
/>
</Col>
</Row>
<Typography.Text type="secondary">
{t("scoreboard.labels.calendarperiod")}
@@ -121,7 +127,7 @@ export function ScoreboardTicketsStats({ data, bodyshop }) {
<Col md={24} lg={20}>
<Table
columns={columns}
rowKey='employee_number'
rowKey="employee_number"
dataSource={tableData}
id="employee_number"
scroll={{ y: "300px" }}

View File

@@ -11,13 +11,13 @@ import {
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
import PhoneFormItem, {
PhoneItemFormatterValidation,
} from "../form-items-formatted/phone-form-item.component";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
import momentTZ from "moment-timezone";
const timeZonesList = momentTZ.tz.names();
@@ -551,6 +551,13 @@ export default function ShopInfoGeneral({ form }) {
>
<CurrencyInput />
</Form.Item>
<Form.Item
name={["use_paint_scale_data"]}
label={t("bodyshop.fields.use_paint_scale_data")}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
name={["attach_pdf_to_email"]}
label={t("bodyshop.fields.attach_pdf_to_email")}
@@ -589,6 +596,13 @@ export default function ShopInfoGeneral({ form }) {
>
<Switch />
</Form.Item>
<Form.Item
name={["tt_enforce_hours_for_tech_console"]}
label={t("bodyshop.fields.tt_enforce_hours_for_tech_console")}
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
name={["bill_allow_post_to_closed"]}
label={t("bodyshop.fields.bill_allow_post_to_closed")}

View File

@@ -396,7 +396,7 @@ export function ShopInfoROStatusComponent({ bodyshop, form }) {
);
}
const ColorPicker = ({ value, onChange, style, ...restProps }) => {
export const ColorPicker = ({ value, onChange, style, ...restProps }) => {
const handleChange = (color) => {
if (onChange) onChange(color.rgb);
};

View File

@@ -15,6 +15,7 @@ import { useTranslation } from "react-i18next";
import ColorpickerFormItemComponent from "../form-items-formatted/colorpicker-form-item.component";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import { ColorPicker } from "./shop-info.rostatus.component";
export default function ShopInfoSchedulingComponent({ form }) {
const { t } = useTranslation();
@@ -277,17 +278,50 @@ export default function ShopInfoSchedulingComponent({ form }) {
>
<InputNumber />
</Form.Item>
<Space wrap>
<DeleteFilled
onClick={() => {
remove(field.name);
}}
/>
<FormListMoveArrows
move={move}
index={index}
total={fields.length}
/>
<Space direction="horizontal">
<Form.Item
label={
<Space>
{t("bodyshop.fields.ssbuckets.color")}
<Button
size="small"
onClick={() => {
form.setFieldValue([
"ssbuckets",
field.name,
"color",
]);
form.setFields([
{
name: ["ssbuckets", field.name, "color"],
touched: true,
},
]);
}}
>
Reset
</Button>
</Space>
}
key={`${index}color`}
name={[field.name, "color"]}
>
<ColorPicker />
</Form.Item>
<Space wrap>
<DeleteFilled
onClick={() => {
remove(field.name);
}}
/>
<FormListMoveArrows
move={move}
index={index}
total={fields.length}
/>
</Space>
</Space>
</LayoutFormRow>
</Form.Item>

View File

@@ -26,6 +26,10 @@ export function TechClockInContainer({
technician,
bodyshop,
}) {
console.log(
"🚀 ~ file: tech-job-clock-in-form.container.jsx:29 ~ technician:",
technician
);
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET, {
@@ -33,6 +37,10 @@ export function TechClockInContainer({
});
const { t } = useTranslation();
const emps = bodyshop.employees.filter(
(e) => e.id === (technician && technician.id)
)[0];
const handleFinish = async (values) => {
setLoading(true);
const theTime = (await axios.post("/utils/time")).data;
@@ -87,7 +95,12 @@ export function TechClockInContainer({
onClick={() => {
setTimeTicketContext({
actions: {},
context: { timeticket: { employeeid: technician.id } },
context: {
timeticket: {
employeeid: technician.id,
flat_rate: emps.flat_rate,
},
},
});
}}
>

View File

@@ -1,4 +1,4 @@
import { useMutation } from "@apollo/client";
import { useMutation, useQuery } from "@apollo/client";
import {
Button,
Card,
@@ -21,6 +21,8 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -39,7 +41,17 @@ export function TechClockOffButton({
const [loading, setLoading] = useState(false);
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
const [form] = Form.useForm();
const { queryLoading, data: lineTicketData } = useQuery(
GET_LINE_TICKET_BY_PK,
{
variables: {
id: jobId,
},
skip: !jobId,
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
}
);
const { t } = useTranslation();
const emps = bodyshop.employees.filter(
(e) => e.id === (technician && technician.id)
@@ -59,6 +71,7 @@ export function TechClockOffButton({
emps &&
emps.rates.filter((r) => r.cost_center === values.cost_center)[0]
?.rate,
flat_rate: emps && emps.flat_rate,
ciecacode:
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
? values.cost_center
@@ -128,6 +141,54 @@ export function TechClockOffButton({
required: true,
//message: t("general.validation.required"),
},
({ getFieldValue }) => ({
validator(rule, value) {
console.log(
bodyshop.tt_enforce_hours_for_tech_console
);
if (!bodyshop.tt_enforce_hours_for_tech_console) {
return Promise.resolve();
}
if (
!value ||
getFieldValue("cost_center") === null ||
!lineTicketData
)
return Promise.resolve();
//Check the cost center,
const totals = CalculateAllocationsTotals(
bodyshop,
lineTicketData.joblines,
lineTicketData.timetickets,
lineTicketData.jobs_by_pk.lbr_adjustments
);
const fieldTypeToCheck =
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
? "mod_lbr_ty"
: "cost_center";
const costCenterDiff =
Math.round(
totals.find(
(total) =>
total[fieldTypeToCheck] ===
getFieldValue("cost_center")
)?.difference * 10
) / 10;
if (value > costCenterDiff)
return Promise.reject(
t(
"timetickets.validation.hoursenteredmorethanavailable"
)
);
else {
return Promise.resolve();
}
},
}),
]}
>
<InputNumber min={0} precision={1} />
@@ -177,7 +238,11 @@ export function TechClockOffButton({
</Col>
{!isShiftTicket && (
<Col span={16}>
<LaborAllocationContainer jobid={jobId} />
<LaborAllocationContainer
jobid={jobId || null}
loading={queryLoading}
lineTicketData={lineTicketData}
/>
</Col>
)}
</Row>

View File

@@ -0,0 +1,131 @@
import { useQuery } from "@apollo/client";
import { Card, Col, Space, Statistic, Typography } from "antd";
import moment from "moment";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE } from "../../graphql/timetickets.queries";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
const { Title } = Typography;
const mapStateToProps = createStructuredSelector({
technician: selectTechnician,
});
const mapDispatchToProps = (dispatch) => ({});
const TechJobStatistics = ({ technician }) => {
const { t } = useTranslation();
const startDate = moment().startOf("week");
const endDate = moment().endOf("week");
const { loading, error, data } = useQuery(
QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE,
{
variables: {
start: startDate.format("YYYY-MM-DD"),
end: endDate.format("YYYY-MM-DD"),
fixedStart: moment().startOf("month").format("YYYY-MM-DD"),
fixedEnd: moment().endOf("month").format("YYYY-MM-DD"),
employeeid: technician.id,
},
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
}
);
const totals = useMemo(() => {
if (data && data.timetickets && data.fixedperiod) {
const week = data.timetickets.reduce(
(acc, val) => {
acc.productivehrs = acc.productivehrs + val.productivehrs;
acc.actualhrs = acc.actualhrs + val.actualhrs;
return acc;
},
{ productivehrs: 0, actualhrs: 0 }
);
const month = data.fixedperiod.reduce(
(acc, val) => {
acc.productivehrs = acc.productivehrs + val.productivehrs;
acc.actualhrs = acc.actualhrs + val.actualhrs;
return acc;
},
{ productivehrs: 0, actualhrs: 0 }
);
return {
week,
month,
};
}
return {
week: { productivehrs: 0, actualhrs: 0 },
month: { productivehrs: 0, actualhrs: 0 },
};
}, [data]);
if (loading) return <LoadingSpinner />;
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<Card title={t("scoreboard.labels.productivestatistics")}>
<Space size={100}>
<Col>
<Title level={5}>{t("scoreboard.labels.thisweek")}</Title>
<Space size={20}>
<Statistic
title={t("timetickets.fields.productivehrs")}
value={totals.week.productivehrs.toFixed(2)}
/>
<Statistic
title={t("timetickets.fields.actualhrs")}
value={totals.week.actualhrs.toFixed(2)}
/>
<Statistic
title={t("timetickets.labels.efficiency")}
value={
totals.week.actualhrs
? `${(
(totals.week.productivehrs / totals.week.actualhrs) *
100
).toFixed(2)}%`
: "0%"
}
/>
</Space>
</Col>
<Col>
<Title level={5}>{t("scoreboard.labels.thismonth")}</Title>
<Space size={20}>
<Statistic
title={t("timetickets.fields.productivehrs")}
value={totals.month.productivehrs.toFixed(2)}
/>
<Statistic
title={t("timetickets.fields.actualhrs")}
value={totals.month.actualhrs.toFixed(2)}
/>
<Statistic
title={t("timetickets.labels.efficiency")}
value={
totals.month.actualhrs
? `${(
(totals.month.productivehrs / totals.month.actualhrs) *
100
).toFixed(2)}%`
: "0%"
}
/>
</Space>
</Col>
</Space>
</Card>
);
};
export default connect(mapStateToProps, mapDispatchToProps)(TechJobStatistics);

View File

@@ -29,7 +29,17 @@ export function TechSider({ technician, techLogout }) {
};
return (
<Sider collapsible collapsed={collapsed} onCollapse={onCollapse}>
<Sider
style={{
height: "100vh",
position: "sticky",
top: 0,
left: 0,
}}
collapsible
collapsed={collapsed}
onCollapse={onCollapse}
>
<Menu theme="dark" defaultSelectedKeys={["1"]} mode="inline">
<Menu.Item
key="1"

View File

@@ -1,4 +1,4 @@
import { useQuery } from "@apollo/client";
import { useLazyQuery } from "@apollo/client";
import { Form, Input, InputNumber, Select, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -14,6 +14,7 @@ import FormDatePicker from "../form-date-picker/form-date-picker.component";
import FormDateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
import JobSearchSelect from "../job-search-select/job-search-select.component";
import LaborAllocationsTable from "../labor-allocations-table/labor-allocations-table.component";
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
@@ -38,7 +39,11 @@ export function TimeTicketModalComponent({
employeeSelectDisabled,
}) {
const { t } = useTranslation();
const [loadLineTicketData, { called, loading, data: lineTicketData }] =
useLazyQuery(GET_LINE_TICKET_BY_PK, {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
});
const CostCenterSelect = ({ emps, value, ...props }) => {
return (
<Select
@@ -176,6 +181,51 @@ export function TimeTicketModalComponent({
label={t("timetickets.fields.productivehrs")}
name="productivehrs"
rules={[
({ getFieldValue }) => ({
validator(rule, value) {
if (!bodyshop.tt_enforce_hours_for_tech_console) {
return Promise.resolve();
}
if (
!value ||
getFieldValue("cost_center") === null ||
!lineTicketData
)
return Promise.resolve();
//Check the cost center,
const totals = CalculateAllocationsTotals(
bodyshop,
lineTicketData.joblines,
lineTicketData.timetickets,
lineTicketData.jobs_by_pk.lbr_adjustments
);
const fieldTypeToCheck =
bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber
? "mod_lbr_ty"
: "cost_center";
const costCenterDiff =
Math.round(
totals.find(
(total) =>
total[fieldTypeToCheck] ===
getFieldValue("cost_center")
)?.difference * 10
) / 10;
if (value > costCenterDiff)
return Promise.reject(
t(
"timetickets.validation.hoursenteredmorethanavailable"
)
);
else {
return Promise.resolve();
}
},
}),
{
required:
form.getFieldValue("cost_center") !==
@@ -291,23 +341,28 @@ export function TimeTicketModalComponent({
</Form.Item>
</LayoutFormRow>
<Form.Item dependencies={["jobid"]}>
{() => (
<LaborAllocationContainer
jobid={form.getFieldValue("jobid") || null}
/>
)}
{() => {
const jobid = form.getFieldValue("jobid");
if (
(!called && jobid) ||
(jobid && lineTicketData?.jobs_by_pk?.id !== jobid && !loading)
) {
loadLineTicketData({ variables: { id: jobid } });
}
return (
<LaborAllocationContainer
jobid={jobid || null}
loading={loading}
lineTicketData={lineTicketData}
/>
);
}}
</Form.Item>
</div>
);
}
export function LaborAllocationContainer({ jobid }) {
const { loading, data: lineTicketData } = useQuery(GET_LINE_TICKET_BY_PK, {
variables: { id: jobid },
skip: !jobid,
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
});
export function LaborAllocationContainer({ jobid, loading, lineTicketData }) {
if (loading) return <LoadingSkeleton />;
if (!lineTicketData) return null;
return (

View File

@@ -20,13 +20,11 @@ export const DELETE_BILL = gql`
export const QUERY_ALL_BILLS_PAGINATED = gql`
query QUERY_ALL_BILLS_PAGINATED(
$search: String
$offset: Int
$limit: Int
$order: [bills_order_by!]!
) {
search_bills(
args: { search: $search }
bills(
offset: $offset
limit: $limit
order_by: $order
@@ -51,7 +49,7 @@ export const QUERY_ALL_BILLS_PAGINATED = gql`
ro_number
}
}
search_bills_aggregate(args: { search: $search }) {
bills_aggregate {
aggregate {
count(distinct: true)
}
@@ -69,6 +67,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
vendor {
id
name
email
}
order_date
deliver_by
@@ -104,6 +103,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
vendor {
id
name
email
}
total
invoice_number

View File

@@ -116,6 +116,8 @@ export const QUERY_BODYSHOP = gql`
md_lost_sale_reasons
md_parts_scan
enforce_conversion_category
tt_enforce_hours_for_tech_console
use_paint_scale_data
employees {
user_email
id
@@ -125,6 +127,7 @@ export const QUERY_BODYSHOP = gql`
employee_number
rates
external_id
flat_rate
}
}
}
@@ -229,6 +232,7 @@ export const UPDATE_SHOP = gql`
md_lost_sale_reasons
md_parts_scan
enforce_conversion_category
tt_enforce_hours_for_tech_console
employees {
id
first_name

View File

@@ -284,6 +284,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
clm_no
v_make_desc
v_color
vehicleid
plate_no
actual_in
scheduled_completion
@@ -1277,7 +1278,7 @@ export const SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE = gql`
export const SEARCH_FOR_JOBS = gql`
query SEARCH_FOR_JOBS($search: String!) {
search_jobs(args: { search: $search }) {
search_jobs(args: { search: $search }, limit: 25) {
id
ro_number
ownr_fn
@@ -1780,14 +1781,12 @@ export const QUERY_ALL_JOB_FIELDS = gql`
export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
query QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED(
$search: String
$offset: Int
$limit: Int
$order: [jobs_order_by!]
$statusList: [String!]
) {
search_jobs(
args: { search: $search }
jobs(
offset: $offset
limit: $limit
order_by: $order
@@ -1818,10 +1817,7 @@ export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
updated_at
ded_amt
}
search_jobs_aggregate(
args: { search: $search }
where: { status: { _in: $statusList } }
) {
jobs_aggregate(where: { status: { _in: $statusList } }) {
aggregate {
count(distinct: true)
}

View File

@@ -4,7 +4,16 @@ export const INSERT_NEW_NOTE = gql`
mutation INSERT_NEW_NOTE($noteInput: [notes_insert_input!]!) {
insert_notes(objects: $noteInput) {
returning {
created_at
created_by
critical
id
jobid
private
text
updated_at
audit
type
}
}
}
@@ -15,8 +24,8 @@ export const QUERY_NOTES_BY_JOB_PK = gql`
jobs_by_pk(id: $id) {
id
ro_number
vehicle{
jobs{
vehicle {
jobs {
id
ro_number
status
@@ -33,6 +42,7 @@ export const QUERY_NOTES_BY_JOB_PK = gql`
text
updated_at
audit
type
}
}
}
@@ -52,6 +62,7 @@ export const UPDATE_NOTE = gql`
text
updated_at
audit
type
}
}
}

View File

@@ -12,39 +12,39 @@ export const INSERT_NEW_PAYMENT = gql`
export const QUERY_ALL_PAYMENTS_PAGINATED = gql`
query QUERY_ALL_PAYMENTS_PAGINATED(
$search: String
$offset: Int
$limit: Int
$order: [payments_order_by!]!
) {
search_payments(
args: { search: $search }
offset: $offset
limit: $limit
order_by: $order
) {
payments(offset: $offset, limit: $limit, order_by: $order) {
id
amount
created_at
jobid
paymentnum
date
exportedat
jobid
job {
id
ro_number
ownerid
ownr_co_nm
ownr_fn
ownr_ln
ownr_co_nm
owner {
id
ownr_co_nm
ownr_fn
ownr_ln
}
ro_number
}
transactionid
memo
type
amount
stripeid
exportedat
stripeid
payer
paymentnum
stripeid
transactionid
type
}
search_payments_aggregate(args: { search: $search }) {
payments_aggregate {
aggregate {
count(distinct: true)
}
@@ -57,16 +57,31 @@ export const UPDATE_PAYMENT = gql`
update_payments(where: { id: { _eq: $paymentId } }, _set: $payment) {
returning {
id
transactionid
memo
type
amount
stripeid
created_at
date
exportedat
stripeid
jobid
job {
id
ownerid
ownr_co_nm
ownr_fn
ownr_ln
owner {
id
ownr_co_nm
ownr_fn
ownr_ln
}
ro_number
}
memo
payer
paymentnum
date
stripeid
transactionid
type
}
}
}
@@ -80,17 +95,31 @@ export const UPDATE_PAYMENTS = gql`
update_payments(where: { id: { _in: $paymentIdList } }, _set: $payment) {
returning {
id
exportedat
transactionid
memo
type
amount
stripeid
created_at
date
exportedat
stripeid
jobid
job {
id
ownerid
ownr_co_nm
ownr_fn
ownr_ln
owner {
id
ownr_co_nm
ownr_fn
ownr_ln
}
ro_number
}
memo
payer
paymentnum
date
stripeid
transactionid
type
}
}
}
@@ -109,3 +138,36 @@ export const QUERY_JOB_PAYMENT_TOTALS = gql`
}
}
`;
export const QUERY_PAYMENT_BY_ID = gql`
query QUERY_PAYMENT_BY_ID($paymentId: uuid!) {
payments_by_pk(id: $paymentId) {
id
amount
created_at
exportedat
date
jobid
job {
id
ownerid
ownr_co_nm
ownr_fn
ownr_ln
owner {
id
ownr_co_nm
ownr_fn
ownr_ln
}
ro_number
}
memo
payer
paymentnum
stripeid
transactionid
type
}
}
`;

View File

@@ -19,6 +19,7 @@ export const QUERY_SCOREBOARD = gql`
v_make_desc
v_model_desc
v_model_yr
job_totals
}
}
}

View File

@@ -2,22 +2,20 @@ import { gql } from "@apollo/client";
export const GLOBAL_SEARCH_QUERY = gql`
query GLOBAL_SEARCH_QUERY($search: String) {
search_jobs(args: { search: $search }) {
search_jobs(args: { search: $search }, limit: 25) {
id
ro_number
status
clm_no
v_model_yr
v_model_desc
v_make_desc
v_color
ownr_fn
ownr_ln
ownr_co_nm
}
search_owners(args: { search: $search }) {
search_owners(args: { search: $search }, limit: 25) {
id
ownr_fn
ownr_ln
@@ -25,7 +23,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
ownr_ph1
ownr_ph2
}
search_vehicles(args: { search: $search }) {
search_vehicles(args: { search: $search }, limit: 25) {
id
v_model_yr
v_model_desc
@@ -34,7 +32,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
v_vin
plate_no
}
search_payments(args: { search: $search }) {
search_payments(args: { search: $search }, limit: 25) {
id
amount
paymentnum
@@ -45,7 +43,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
memo
transactionid
}
search_bills(args: { search: $search }) {
search_bills(args: { search: $search }, limit: 25) {
id
date
invoice_number
@@ -54,7 +52,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
name
}
}
search_phonebook(args: { search: $search }) {
search_phonebook(args: { search: $search }, limit: 25) {
id
firstname
lastname

View File

@@ -59,6 +59,81 @@ export const QUERY_TIME_TICKETS_IN_RANGE = gql`
}
`;
export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
query QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE(
$employeeid: uuid!
$start: date!
$end: date!
$fixedStart: date!
$fixedEnd: date!
) {
timetickets(
where: {
date: { _gte: $start, _lte: $end }
employeeid: { _eq: $employeeid }
}
order_by: { date: desc_nulls_first }
) {
actualhrs
ciecacode
clockoff
clockon
cost_center
created_at
date
id
rate
productivehrs
memo
jobid
flat_rate
job {
id
ro_number
}
employeeid
employee {
id
employee_number
first_name
last_name
}
}
fixedperiod: timetickets(
where: {
date: { _gte: $fixedStart, _lte: $fixedEnd }
employeeid: { _eq: $employeeid }
}
order_by: { date: desc_nulls_first }
) {
actualhrs
ciecacode
clockoff
clockon
cost_center
created_at
date
id
rate
productivehrs
memo
jobid
flat_rate
job {
id
ro_number
}
employeeid
employee {
id
employee_number
first_name
last_name
}
}
}
`;
export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
query QUERY_TIME_TICKETS_IN_RANGE_SB(
$start: date!

View File

@@ -1,7 +1,8 @@
import { SyncOutlined, EditFilled } from "@ant-design/icons";
import { EditFilled, SyncOutlined } from "@ant-design/icons";
import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd";
import axios from "axios";
import queryString from "query-string";
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useHistory, useLocation } from "react-router-dom";
@@ -11,8 +12,8 @@ import PrintWrapperComponent from "../../components/print-wrapper/print-wrapper.
import { setModalContext } from "../../redux/modals/modals.actions";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort, dateSort } from "../../utils/sorters";
import { TemplateList } from "../../utils/TemplateConstants";
import { alphaSort, dateSort } from "../../utils/sorters";
const mapDispatchToProps = (dispatch) => ({
setPartsOrderContext: (context) =>
@@ -29,34 +30,36 @@ export function BillsListPage({
setPartsOrderContext,
setBillEnterContext,
}) {
const { t } = useTranslation();
const search = queryString.parse(useLocation().search);
const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false);
const { page } = search;
const history = useHistory();
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: { text: "" },
});
const history = useHistory();
const search = queryString.parse(useLocation().search);
const { page } = search;
const Templates = TemplateList("bill");
const { t } = useTranslation();
const columns = [
{
title: t("bills.fields.vendorname"),
dataIndex: "vendorname",
key: "vendorname",
sortObject: (direction) => {
return {
vendor: {
name: direction
? direction === "descend"
? "desc"
: "asc"
: "desc",
},
};
},
sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
sortOrder:
state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
// sortObject: (direction) => {
// return {
// vendor: {
// name: direction
// ? direction === "descend"
// ? "desc"
// : "asc"
// : "desc",
// },
// };
// },
// sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
// sortOrder:
// state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
render: (text, record) => <span>{record.vendor.name}</span>,
},
{
@@ -72,20 +75,20 @@ export function BillsListPage({
title: t("jobs.fields.ro_number"),
dataIndex: "ro_number",
key: "ro_number",
sortObject: (direction) => {
return {
job: {
ro_number: direction
? direction === "descend"
? "desc"
: "asc"
: "desc",
},
};
},
sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
// sortObject: (direction) => {
// return {
// job: {
// ro_number: direction
// ? direction === "descend"
// ? "desc"
// : "asc"
// : "desc",
// },
// };
// },
// sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
// sortOrder:
// state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
render: (text, record) =>
record.job && (
<Link to={`/manage/jobs/${record.job.id}`}>
@@ -174,7 +177,15 @@ export function BillsListPage({
// {t("bills.actions.return")}
// </Button>
}
<BillDeleteButton bill={record} />
<BillDeleteButton
bill={record}
callback={(deletedBillid) => {
//Filter out the state and set it again.
setOpenSearchResults((currentResults) =>
currentResults.filter((bill) => bill.id !== deletedBillid)
);
}}
/>
{record.isinhouse && (
<PrintWrapperComponent
templateObject={{
@@ -199,11 +210,32 @@ export function BillsListPage({
search.sortcolumn = sorter.order ? sorter.columnKey : null;
search.sortorder = sorter.order;
}
search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order });
history.push({ search: queryString.stringify(search) });
};
useEffect(() => {
if (search.search && search.search.trim() !== "") {
searchBills();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
async function searchBills(value) {
try {
setSearchLoading(true);
const searchData = await axios.post("/search", {
search: value || search.search,
index: "bills",
});
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
} catch (error) {
console.log("Error while fetching search results", error);
} finally {
setSearchLoading(false);
}
}
return (
<Card
title={t("bills.labels.bills")}
@@ -217,6 +249,7 @@ export function BillsListPage({
<Button
onClick={() => {
delete search.search;
delete search.page;
history.push({ search: queryString.stringify(search) });
}}
>
@@ -243,7 +276,10 @@ export function BillsListPage({
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
searchBills(value);
}}
loading={loading || searchLoading}
enterButton
/>
</Space>
}
@@ -251,19 +287,27 @@ export function BillsListPage({
<PartsOrderModalContainer />
<Table
loading={loading}
scroll={{
x: "50%", // y: "40rem"
}}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
loading={loading || searchLoading}
// scroll={{
// x: "50%", // y: "40rem"
// }}
scroll={{ x: true }}
pagination={
search?.search
? {
pageSize: 25,
showSizeChanger: false,
}
: {
pageSize: 25,
current: parseInt(page || 1),
total: total,
showSizeChanger: false,
}
}
columns={columns}
rowKey="id"
dataSource={data}
dataSource={search?.search ? openSearchResults : data}
onChange={handleTableChange}
/>
</Card>

View File

@@ -1,6 +1,6 @@
import { useQuery } from "@apollo/client";
import queryString from "query-string";
import React, { useEffect } from "react";
import { useQuery } from "@apollo/client";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useLocation } from "react-router-dom";
@@ -22,7 +22,7 @@ const mapDispatchToProps = (dispatch) => ({
export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation();
const searchParams = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder, search, searchObj } = searchParams;
const { page, sortcolumn, sortorder, searchObj } = searchParams;
useEffect(() => {
document.title = t("titles.bills-list");
@@ -38,7 +38,6 @@ export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
variables: {
search: search || "",
offset: page ? (page - 1) * 25 : 0,
limit: 25,
order: [
@@ -61,10 +60,10 @@ export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
<RbacWrapper action="bills:list">
<div>
<BillsPageComponent
data={data ? data.search_bills : []}
data={data ? data.bills : []}
loading={loading}
refetch={refetch}
total={data ? data.search_bills_aggregate.aggregate.count : 0}
total={data ? data.bills_aggregate.aggregate.count : 0}
/>
<BillDetailEditContainer />

View File

@@ -25,7 +25,7 @@ const mapDispatchToProps = (dispatch) => ({
export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder, search, statusFilters } = searchParams;
const { page, sortcolumn, sortorder, statusFilters } = searchParams;
const { loading, error, data, refetch } = useQuery(
QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED,
@@ -33,13 +33,12 @@ export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
variables: {
search: search || "",
offset: page ? (page - 1) * 25 : 0,
limit: 25,
...(statusFilters ? { statusList: JSON.parse(statusFilters) } : {}),
order: [
{
[sortcolumn || "created_at"]:
[sortcolumn || "ro_number"]:
sortorder && sortorder !== "false"
? sortorder === "descend"
? "desc"
@@ -67,8 +66,8 @@ export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
refetch={refetch}
loading={loading}
searchParams={searchParams}
total={data ? data.search_jobs_aggregate.aggregate.count : 0}
jobs={data ? data.search_jobs : []}
total={data ? data.jobs_aggregate.aggregate.count : 0}
jobs={data ? data.jobs : []}
/>
</RbacWrapper>
);

View File

@@ -52,6 +52,7 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
import { insertAuditTrail } from "../../redux/application/application.actions";
import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
import UndefinedToNull from "../../utils/undefinedtonull";
import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -97,7 +98,11 @@ export function JobsDetailPage({
variables: {
jobId: job.id,
job: {
...UndefinedToNull(values, ["alt_transport", "category", "referral_source"]),
...UndefinedToNull(values, [
"alt_transport",
"category",
"referral_source",
]),
parts_tax_rates: {
...job.parts_tax_rates,
...values.parts_tax_rates,
@@ -231,6 +236,7 @@ export function JobsDetailPage({
<ScheduleJobModalContainer />
<JobReconciliationModal />
<JobLineUpsertModalContainer />
<NoteUpsertModalComponent />
<Form
form={form}
name="JobDetailForm"

View File

@@ -26,7 +26,7 @@ const mapDispatchToProps = (dispatch) => ({
export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder, search } = searchParams;
const { page, sortcolumn, sortorder, searchObj } = searchParams;
const { loading, error, data, refetch } = useQuery(
QUERY_ALL_PAYMENTS_PAGINATED,
@@ -34,11 +34,12 @@ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
variables: {
search: search || "",
offset: page ? (page - 1) * 25 : 0,
limit: 25,
order: [
{
searchObj
? JSON.parse(searchObj)
: {
[sortcolumn || "date"]: sortorder
? sortorder === "descend"
? "desc"
@@ -66,8 +67,8 @@ export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
refetch={refetch}
loading={loading}
searchParams={searchParams}
total={data ? data.search_payments_aggregate.aggregate.count : 0}
payments={data ? data.search_payments : []}
total={data ? data.payments_aggregate.aggregate.count : 0}
payments={data ? data.payments : []}
/>
</RbacWrapper>
);

View File

@@ -2,10 +2,12 @@ import { Divider } from "antd";
import React from "react";
import TechClockInFormContainer from "../../components/tech-job-clock-in-form/tech-job-clock-in-form.container";
import TechClockedInList from "../../components/tech-job-clocked-in-list/tech-job-clocked-in-list.component";
import TechJobStatistics from "../../components/tech-job-statistics/tech-job-statistics.component";
export default function TechClockComponent() {
return (
<div>
<TechJobStatistics />
<TechClockInFormContainer />
<Divider />
<TechClockedInList />

View File

@@ -1,9 +1,10 @@
.tech-content-container {
overflow-y: auto;
overflow-y: visible;
padding: 1rem;
background: #fff;
}
.tech-layout-container {
height: 100vh;
position: relative;
min-height: 100vh;
}

View File

@@ -63,6 +63,7 @@
"scheduledfor": "Scheduled appointment for: ",
"severalerrorsfound": "Several jobs have issues which may prevent accurate smart scheduling. Click to expand.",
"smartscheduling": "Smart Scheduling",
"smspaymentreminder": "",
"suggesteddates": "Suggested Dates"
},
"successes": {
@@ -103,6 +104,7 @@
"admin_jobunvoid": "ADMIN: Job has been unvoided.",
"billposted": "Bill with invoice number {{invoice_number}} posted.",
"billupdated": "Bill with invoice number {{invoice_number}} updated.",
"failedpayment": "",
"jobassignmentchange": "Employee {{name}} assigned to {{operation}}",
"jobassignmentremoved": "Employee assignment removed for {{operation}}",
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
@@ -227,6 +229,7 @@
},
"bodyshop": {
"actions": {
"add_task_preset": "",
"addapptcolor": "Add Appointment Color",
"addbucket": "Add Definition",
"addpartslocation": "Add Parts Location",
@@ -339,6 +342,12 @@
},
"md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources",
"md_tasks_presets": {
"hourstype": "",
"memo": "",
"name": "",
"percent": ""
},
"messaginglabel": "Messaging Preset Label",
"messagingtext": "Messaging Preset Text",
"noteslabel": "Note Label",
@@ -374,6 +383,9 @@
"export": "CSI -> Export",
"page": "CSI -> Page"
},
"employee_teams": {
"page": ""
},
"employees": {
"page": "Employees -> List"
},
@@ -432,10 +444,15 @@
},
"timetickets": {
"edit": "Time Tickets -> Edit",
"editcommitted": "",
"enter": "Time Tickets -> Enter",
"list": "Time Tickets -> List",
"shiftedit": "Time Tickets -> Shift Edit"
},
"ttapprovals": {
"approve": "",
"view": ""
},
"users": {
"editaccess": "Users -> Edit access"
}
@@ -453,6 +470,8 @@
"federal_tax": "Federal Tax",
"federal_tax_itc": "Federal Tax Credit",
"gst_override": "GST Override Account #",
"invoiceexemptcode": "",
"itemexemptcode": "",
"la1": "LA1",
"la2": "LA2",
"la3": "LA3",
@@ -504,6 +523,7 @@
"dailyhrslimit": "Daily Incoming Hours Limit"
},
"ssbuckets": {
"color": "Job Color",
"gte": "Greater Than/Equal to (hrs)",
"id": "ID",
"label": "Label",
@@ -541,7 +561,9 @@
"target_touchtime": "Target Touch Time",
"timezone": "Timezone",
"tt_allow_post_to_invoiced": "Allow Time Tickets to be posted to Invoiced & Exported Jobs",
"tt_enforce_hours_for_tech_console": "Restrict Claimable hours from Tech Console",
"use_fippa": "Use FIPPA for Names on Generated Documents?",
"use_paint_scale_data": "Use Paint Scale Data for Job Costing?",
"uselocalmediaserver": "Use Local Media Server?",
"website": "Website",
"zip_post": "Zip/Postal Code"
@@ -572,6 +594,7 @@
"title": "DMS"
},
"emaillater": "Email Later",
"employee_teams": "",
"employees": "Employees",
"estimators": "Estimators",
"filehandlers": "File Handlers",
@@ -580,6 +603,7 @@
"jobstatuses": "Job Statuses",
"laborrates": "Labor Rates",
"licensing": "Licensing",
"md_tasks_presets": "",
"md_to_emails": "Preset To Emails",
"md_to_emails_emails": "Emails",
"messagingpresets": "Messaging Presets",
@@ -606,6 +630,7 @@
"speedprint": "Speed Print Configuration",
"ssbuckets": "Job Size Definitions",
"systemsettings": "System Settings",
"task-presets": "",
"workingdays": "Working Days"
},
"successes": {
@@ -905,6 +930,18 @@
"sent": "Email sent successfully."
}
},
"employee_teams": {
"actions": {
"new": "",
"newmember": ""
},
"fields": {
"active": "",
"employeeid": "",
"name": "",
"percentage": ""
}
},
"employees": {
"actions": {
"addvacation": "Add Vacation",
@@ -1014,6 +1051,7 @@
"created_at": "Created At",
"email": "Email",
"errors": "Errors",
"excel": "Excel",
"exceptiontitle": "An error has occurred.",
"friday": "Friday",
"globalsearch": "Global Search",
@@ -1063,6 +1101,7 @@
"sunday": "Sunday",
"text": "Text",
"thursday": "Thursday",
"total": "Total",
"totals": "Totals",
"tuesday": "Tuesday",
"unknown": "Unknown",
@@ -1142,6 +1181,30 @@
"updated": "Inventory line updated."
}
},
"job_payments": {
"buttons": {
"goback": "",
"proceedtopayment": "",
"refundpayment": ""
},
"notifications": {
"error": {
"description": "",
"title": ""
}
},
"titles": {
"amount": "",
"dateOfPayment": "",
"descriptions": "",
"payer": "",
"payername": "",
"paymentid": "",
"paymenttype": "",
"refundamount": "",
"transactionid": ""
}
},
"joblines": {
"actions": {
"converttolabor": "Convert amount to Labor.",
@@ -1374,7 +1437,7 @@
"ded_amt": "Deductible",
"ded_note": "Deductible Note",
"ded_status": "Deductible Status",
"depreciation_taxes": "Depreciation/Taxes",
"depreciation_taxes": "Betterment/Depreciation/Taxes",
"dms": {
"address": "Customer Address",
"amount": "Amount",
@@ -1574,6 +1637,7 @@
"scheddates": "Schedule Dates"
},
"labels": {
"act_price_ppc": "",
"actual_completion_inferred": "$t(jobs.fields.actual_completion) inferred using $t(jobs.fields.scheduled_completion).",
"actual_delivery_inferred": "$t(jobs.fields.actual_delivery) inferred using $t(jobs.fields.scheduled_delivery).",
"actual_in_inferred": "$t(jobs.fields.actual_in) inferred using $t(jobs.fields.scheduled_in).",
@@ -1710,6 +1774,7 @@
"partstotal": "This is the total of all parts and sublet amounts on the vehicle (some of these may require an in-house invoice).<br/>\nItems such as shop and paint materials, labor online lines, etc. are not included in this total.",
"totalreturns": "The total <b>retail</b> amount of returns created for this job."
},
"ppc": "",
"profileadjustments": "",
"prt_dsmk_total": "Line Item Adjustment",
"rates": "Rates",
@@ -1850,6 +1915,7 @@
"customers": "Customers",
"dashboard": "Dashboard",
"enterbills": "Enter Bills",
"entercardpayment": "",
"enterpayment": "Enter Payments",
"entertimeticket": "Enter Time Tickets",
"export": "Export",
@@ -1861,6 +1927,7 @@
"newjob": "Create New Job",
"owners": "Owners",
"parts-queue": "Parts Queue",
"paymentremindersms": "",
"phonebook": "Phonebook",
"productionboard": "Production Board - Visual",
"productionlist": "Production Board - List",
@@ -1886,6 +1953,7 @@
"shop_vendors": "Vendors",
"temporarydocs": "Temporary Documents",
"timetickets": "Time Tickets",
"ttapprovals": "",
"vehicles": "Vehicles"
},
"jobsactions": {
@@ -1958,7 +2026,8 @@
"actions": "Actions",
"deletenote": "Delete Note",
"edit": "Edit Note",
"new": "New Note"
"new": "New Note",
"savetojobnotes": "Save to Job Notes"
},
"errors": {
"inserting": "Error inserting note. {{error}}"
@@ -1968,6 +2037,16 @@
"critical": "Critical",
"private": "Private",
"text": "Contents",
"type": "Type",
"types": {
"customer": "Customer",
"general": "General",
"office": "Office",
"paint": "Paint",
"parts": "Parts",
"shop": "Shop",
"supplement": "Supplement"
},
"updatedat": "Updated At"
},
"labels": {
@@ -2224,6 +2303,7 @@
"csi_invitation": "CSI Invitation",
"csi_invitation_action": "CSI Invite",
"diagnostic_authorization": "Diagnostic Authorization",
"dms_posting_sheet": "DMS Posting Sheet",
"envelope_return_address": "#10 Envelope Return Address Label",
"estimate": "Estimate Only",
"estimate_detail": "Estimate Details",
@@ -2236,7 +2316,7 @@
"folder_label_multiple": "Folder Label - Multi",
"glass_express_checklist": "Glass Express Checklist",
"guarantee": "Repair Guarantee",
"individual_job_note": "Job Note RO # {{ro_number}}",
"individual_job_note": "RO Job Note",
"invoice_customer_payable": "Invoice (Customer Payable)",
"invoice_total_payable": "Invoice (Total Payable)",
"iou_form": "IOU Form",
@@ -2314,6 +2394,7 @@
},
"subjects": {
"jobs": {
"individual_job_note": "Job Note RO: {{ro_number}}",
"parts_order": "Parts Order PO: {{ro_number}} - {{name}}",
"sublet_order": "Sublet Order PO: {{ro_number}} - {{name}}"
}
@@ -2357,6 +2438,7 @@
"qbo_usa": "QBO USA"
}
},
"cardcolor": "Card Colors",
"cardsettings": "Card Settings",
"clm_no": "Claim Number",
"comment": "Comment",
@@ -2367,6 +2449,7 @@
"ins_co_nm": "Insurance Company Name",
"jobdetail": "Job Details",
"laborhrs": "Labor Hours",
"legend": "Legend:",
"note": "Production Note",
"ownr_nm": "Owner Name",
"paintpriority": "P/P",
@@ -2442,6 +2525,8 @@
"export_payables": "Export Log - Payables",
"export_payments": "Export Log - Payments",
"export_receivables": "Export Log - Receivables",
"exported_gsr_by_ro": "Exported Gross Sales - Excel",
"exported_gsr_by_ro_labor": "Exported Gross Sales (Labor) - Excel",
"gsr_by_atp": "",
"gsr_by_ats": "Gross Sales by ATS",
"gsr_by_category": "Gross Sales by Category",
@@ -2603,6 +2688,7 @@
},
"timetickets": {
"actions": {
"claimtasks": "",
"clockin": "Clock In",
"clockout": "Clock Out",
"enter": "Enter New Time Ticket",
@@ -2623,10 +2709,12 @@
"clockhours": "Clock Hours",
"clockoff": "Clock Off",
"clockon": "Clocked In",
"committed": "",
"cost_center": "Cost Center",
"date": "Ticket Date",
"efficiency": "Efficiency",
"employee": "Employee",
"employee_team": "",
"flat_rate": "Flat Rate?",
"memo": "Memo",
"productivehrs": "Productive Hours",
@@ -2661,7 +2749,8 @@
},
"validation": {
"clockoffmustbeafterclockon": "Clock off time must be the same or after clock in time.",
"clockoffwithoutclockon": "Clock off time cannot be set without a clock in time."
"clockoffwithoutclockon": "Clock off time cannot be set without a clock in time.",
"hoursenteredmorethanavailable": "The number of hours entered is more than what is available for this cost center."
}
},
"titles": {
@@ -2712,6 +2801,7 @@
"shop-vendors": "Vendors",
"temporarydocs": "Temporary Documents",
"timetickets": "Time Tickets",
"ttapprovals": "",
"vehicle-details": "Vehicle: {{vehicle}}",
"vehicles": "Vehicles"
},
@@ -2757,9 +2847,15 @@
"shop_vendors": "Vendors | $t(titles.app)",
"temporarydocs": "Temporary Documents | $t(titles.app)",
"timetickets": "Time Tickets | $t(titles.app)",
"ttapprovals": "",
"vehicledetail": "Vehicle Details {{vehicle}} | $t(titles.app)",
"vehicles": "All Vehicles | $t(titles.app)"
},
"tt_approvals": {
"actions": {
"approveselected": ""
}
},
"user": {
"actions": {
"changepassword": "Change Password",

View File

@@ -63,6 +63,7 @@
"scheduledfor": "Cita programada para:",
"severalerrorsfound": "",
"smartscheduling": "",
"smspaymentreminder": "",
"suggesteddates": ""
},
"successes": {
@@ -103,6 +104,7 @@
"admin_jobunvoid": "",
"billposted": "",
"billupdated": "",
"failedpayment": "",
"jobassignmentchange": "",
"jobassignmentremoved": "",
"jobchecklist": "",
@@ -227,6 +229,7 @@
},
"bodyshop": {
"actions": {
"add_task_preset": "",
"addapptcolor": "",
"addbucket": "",
"addpartslocation": "",
@@ -339,6 +342,12 @@
},
"md_payment_types": "",
"md_referral_sources": "",
"md_tasks_presets": {
"hourstype": "",
"memo": "",
"name": "",
"percent": ""
},
"messaginglabel": "",
"messagingtext": "",
"noteslabel": "",
@@ -374,6 +383,9 @@
"export": "",
"page": ""
},
"employee_teams": {
"page": ""
},
"employees": {
"page": ""
},
@@ -432,10 +444,15 @@
},
"timetickets": {
"edit": "",
"editcommitted": "",
"enter": "",
"list": "",
"shiftedit": ""
},
"ttapprovals": {
"approve": "",
"view": ""
},
"users": {
"editaccess": ""
}
@@ -453,6 +470,8 @@
"federal_tax": "",
"federal_tax_itc": "",
"gst_override": "",
"invoiceexemptcode": "",
"itemexemptcode": "",
"la1": "",
"la2": "",
"la3": "",
@@ -504,6 +523,7 @@
"dailyhrslimit": ""
},
"ssbuckets": {
"color": "",
"gte": "",
"id": "",
"label": "",
@@ -541,7 +561,9 @@
"target_touchtime": "",
"timezone": "",
"tt_allow_post_to_invoiced": "",
"tt_enforce_hours_for_tech_console": "",
"use_fippa": "",
"use_paint_scale_data": "",
"uselocalmediaserver": "",
"website": "",
"zip_post": ""
@@ -572,6 +594,7 @@
"title": ""
},
"emaillater": "",
"employee_teams": "",
"employees": "",
"estimators": "",
"filehandlers": "",
@@ -580,6 +603,7 @@
"jobstatuses": "",
"laborrates": "",
"licensing": "",
"md_tasks_presets": "",
"md_to_emails": "",
"md_to_emails_emails": "",
"messagingpresets": "",
@@ -606,6 +630,7 @@
"speedprint": "",
"ssbuckets": "",
"systemsettings": "",
"task-presets": "",
"workingdays": ""
},
"successes": {
@@ -905,6 +930,18 @@
"sent": "Correo electrónico enviado con éxito."
}
},
"employee_teams": {
"actions": {
"new": "",
"newmember": ""
},
"fields": {
"active": "",
"employeeid": "",
"name": "",
"percentage": ""
}
},
"employees": {
"actions": {
"addvacation": "",
@@ -1014,6 +1051,7 @@
"created_at": "",
"email": "",
"errors": "",
"excel": "",
"exceptiontitle": "",
"friday": "",
"globalsearch": "",
@@ -1063,6 +1101,7 @@
"sunday": "",
"text": "",
"thursday": "",
"total": "",
"totals": "",
"tuesday": "",
"unknown": "Desconocido",
@@ -1142,6 +1181,30 @@
"updated": ""
}
},
"job_payments": {
"buttons": {
"goback": "",
"proceedtopayment": "",
"refundpayment": ""
},
"notifications": {
"error": {
"description": "",
"title": ""
}
},
"titles": {
"amount": "",
"dateOfPayment": "",
"descriptions": "",
"payer": "",
"payername": "",
"paymentid": "",
"paymenttype": "",
"refundamount": "",
"transactionid": ""
}
},
"joblines": {
"actions": {
"converttolabor": "",
@@ -1574,6 +1637,7 @@
"scheddates": ""
},
"labels": {
"act_price_ppc": "",
"actual_completion_inferred": "",
"actual_delivery_inferred": "",
"actual_in_inferred": "",
@@ -1710,6 +1774,7 @@
"partstotal": "",
"totalreturns": ""
},
"ppc": "",
"profileadjustments": "",
"prt_dsmk_total": "",
"rates": "Tarifas",
@@ -1850,6 +1915,7 @@
"customers": "Clientes",
"dashboard": "",
"enterbills": "",
"entercardpayment": "",
"enterpayment": "",
"entertimeticket": "",
"export": "",
@@ -1861,6 +1927,7 @@
"newjob": "",
"owners": "propietarios",
"parts-queue": "",
"paymentremindersms": "",
"phonebook": "",
"productionboard": "",
"productionlist": "",
@@ -1886,6 +1953,7 @@
"shop_vendors": "Vendedores",
"temporarydocs": "",
"timetickets": "",
"ttapprovals": "",
"vehicles": "Vehículos"
},
"jobsactions": {
@@ -1958,7 +2026,8 @@
"actions": "Comportamiento",
"deletenote": "Borrar nota",
"edit": "Editar nota",
"new": "Nueva nota"
"new": "Nueva nota",
"savetojobnotes": ""
},
"errors": {
"inserting": ""
@@ -1968,6 +2037,16 @@
"critical": "Crítico",
"private": "Privado",
"text": "Contenido",
"type": "",
"types": {
"customer": "",
"general": "",
"office": "",
"paint": "",
"parts": "",
"shop": "",
"supplement": ""
},
"updatedat": "Actualizado en"
},
"labels": {
@@ -2224,6 +2303,7 @@
"csi_invitation": "",
"csi_invitation_action": "",
"diagnostic_authorization": "",
"dms_posting_sheet": "",
"envelope_return_address": "",
"estimate": "",
"estimate_detail": "",
@@ -2314,6 +2394,7 @@
},
"subjects": {
"jobs": {
"individual_job_note": "",
"parts_order": "",
"sublet_order": ""
}
@@ -2357,6 +2438,7 @@
"qbo_usa": ""
}
},
"cardcolor": "",
"cardsettings": "",
"clm_no": "",
"comment": "",
@@ -2367,6 +2449,7 @@
"ins_co_nm": "",
"jobdetail": "",
"laborhrs": "",
"legend": "",
"note": "",
"ownr_nm": "",
"paintpriority": "",
@@ -2442,6 +2525,8 @@
"export_payables": "",
"export_payments": "",
"export_receivables": "",
"exported_gsr_by_ro": "",
"exported_gsr_by_ro_labor": "",
"gsr_by_atp": "",
"gsr_by_ats": "",
"gsr_by_category": "",
@@ -2603,6 +2688,7 @@
},
"timetickets": {
"actions": {
"claimtasks": "",
"clockin": "",
"clockout": "",
"enter": "",
@@ -2623,10 +2709,12 @@
"clockhours": "",
"clockoff": "",
"clockon": "",
"committed": "",
"cost_center": "",
"date": "",
"efficiency": "",
"employee": "",
"employee_team": "",
"flat_rate": "",
"memo": "",
"productivehrs": "",
@@ -2661,7 +2749,8 @@
},
"validation": {
"clockoffmustbeafterclockon": "",
"clockoffwithoutclockon": ""
"clockoffwithoutclockon": "",
"hoursenteredmorethanavailable": ""
}
},
"titles": {
@@ -2712,6 +2801,7 @@
"shop-vendors": "",
"temporarydocs": "",
"timetickets": "",
"ttapprovals": "",
"vehicle-details": "",
"vehicles": ""
},
@@ -2757,9 +2847,15 @@
"shop_vendors": "Vendedores | $t(titles.app)",
"temporarydocs": "",
"timetickets": "",
"ttapprovals": "",
"vehicledetail": "Detalles del vehículo {{vehicle}} | $t(titles.app)",
"vehicles": "Todos los vehiculos | $t(titles.app)"
},
"tt_approvals": {
"actions": {
"approveselected": ""
}
},
"user": {
"actions": {
"changepassword": "",

View File

@@ -63,6 +63,7 @@
"scheduledfor": "Rendez-vous prévu pour:",
"severalerrorsfound": "",
"smartscheduling": "",
"smspaymentreminder": "",
"suggesteddates": ""
},
"successes": {
@@ -103,6 +104,7 @@
"admin_jobunvoid": "",
"billposted": "",
"billupdated": "",
"failedpayment": "",
"jobassignmentchange": "",
"jobassignmentremoved": "",
"jobchecklist": "",
@@ -227,6 +229,7 @@
},
"bodyshop": {
"actions": {
"add_task_preset": "",
"addapptcolor": "",
"addbucket": "",
"addpartslocation": "",
@@ -339,6 +342,12 @@
},
"md_payment_types": "",
"md_referral_sources": "",
"md_tasks_presets": {
"hourstype": "",
"memo": "",
"name": "",
"percent": ""
},
"messaginglabel": "",
"messagingtext": "",
"noteslabel": "",
@@ -374,6 +383,9 @@
"export": "",
"page": ""
},
"employee_teams": {
"page": ""
},
"employees": {
"page": ""
},
@@ -432,10 +444,15 @@
},
"timetickets": {
"edit": "",
"editcommitted": "",
"enter": "",
"list": "",
"shiftedit": ""
},
"ttapprovals": {
"approve": "",
"view": ""
},
"users": {
"editaccess": ""
}
@@ -453,6 +470,8 @@
"federal_tax": "",
"federal_tax_itc": "",
"gst_override": "",
"invoiceexemptcode": "",
"itemexemptcode": "",
"la1": "",
"la2": "",
"la3": "",
@@ -504,6 +523,7 @@
"dailyhrslimit": ""
},
"ssbuckets": {
"color": "",
"gte": "",
"id": "",
"label": "",
@@ -541,7 +561,9 @@
"target_touchtime": "",
"timezone": "",
"tt_allow_post_to_invoiced": "",
"tt_enforce_hours_for_tech_console": "",
"use_fippa": "",
"use_paint_scale_data": "",
"uselocalmediaserver": "",
"website": "",
"zip_post": ""
@@ -572,6 +594,7 @@
"title": ""
},
"emaillater": "",
"employee_teams": "",
"employees": "",
"estimators": "",
"filehandlers": "",
@@ -580,6 +603,7 @@
"jobstatuses": "",
"laborrates": "",
"licensing": "",
"md_tasks_presets": "",
"md_to_emails": "",
"md_to_emails_emails": "",
"messagingpresets": "",
@@ -606,6 +630,7 @@
"speedprint": "",
"ssbuckets": "",
"systemsettings": "",
"task-presets": "",
"workingdays": ""
},
"successes": {
@@ -905,6 +930,18 @@
"sent": "E-mail envoyé avec succès."
}
},
"employee_teams": {
"actions": {
"new": "",
"newmember": ""
},
"fields": {
"active": "",
"employeeid": "",
"name": "",
"percentage": ""
}
},
"employees": {
"actions": {
"addvacation": "",
@@ -1014,6 +1051,7 @@
"created_at": "",
"email": "",
"errors": "",
"excel": "",
"exceptiontitle": "",
"friday": "",
"globalsearch": "",
@@ -1063,6 +1101,7 @@
"sunday": "",
"text": "",
"thursday": "",
"total": "",
"totals": "",
"tuesday": "",
"unknown": "Inconnu",
@@ -1142,6 +1181,30 @@
"updated": ""
}
},
"job_payments": {
"buttons": {
"goback": "",
"proceedtopayment": "",
"refundpayment": ""
},
"notifications": {
"error": {
"description": "",
"title": ""
}
},
"titles": {
"amount": "",
"dateOfPayment": "",
"descriptions": "",
"payer": "",
"payername": "",
"paymentid": "",
"paymenttype": "",
"refundamount": "",
"transactionid": ""
}
},
"joblines": {
"actions": {
"converttolabor": "",
@@ -1574,6 +1637,7 @@
"scheddates": ""
},
"labels": {
"act_price_ppc": "",
"actual_completion_inferred": "",
"actual_delivery_inferred": "",
"actual_in_inferred": "",
@@ -1710,6 +1774,7 @@
"partstotal": "",
"totalreturns": ""
},
"ppc": "",
"profileadjustments": "",
"prt_dsmk_total": "",
"rates": "Les taux",
@@ -1850,6 +1915,7 @@
"customers": "Les clients",
"dashboard": "",
"enterbills": "",
"entercardpayment": "",
"enterpayment": "",
"entertimeticket": "",
"export": "",
@@ -1861,6 +1927,7 @@
"newjob": "",
"owners": "Propriétaires",
"parts-queue": "",
"paymentremindersms": "",
"phonebook": "",
"productionboard": "",
"productionlist": "",
@@ -1886,6 +1953,7 @@
"shop_vendors": "Vendeurs",
"temporarydocs": "",
"timetickets": "",
"ttapprovals": "",
"vehicles": "Véhicules"
},
"jobsactions": {
@@ -1958,7 +2026,8 @@
"actions": "actes",
"deletenote": "Supprimer la note",
"edit": "Note éditée",
"new": "Nouvelle note"
"new": "Nouvelle note",
"savetojobnotes": ""
},
"errors": {
"inserting": ""
@@ -1968,6 +2037,16 @@
"critical": "Critique",
"private": "privé",
"text": "Contenu",
"type": "",
"types": {
"customer": "",
"general": "",
"office": "",
"paint": "",
"parts": "",
"shop": "",
"supplement": ""
},
"updatedat": "Mis à jour à"
},
"labels": {
@@ -2224,6 +2303,7 @@
"csi_invitation": "",
"csi_invitation_action": "",
"diagnostic_authorization": "",
"dms_posting_sheet": "",
"envelope_return_address": "",
"estimate": "",
"estimate_detail": "",
@@ -2314,6 +2394,7 @@
},
"subjects": {
"jobs": {
"individual_job_note": "",
"parts_order": "",
"sublet_order": ""
}
@@ -2357,6 +2438,7 @@
"qbo_usa": ""
}
},
"cardcolor": "",
"cardsettings": "",
"clm_no": "",
"comment": "",
@@ -2367,6 +2449,7 @@
"ins_co_nm": "",
"jobdetail": "",
"laborhrs": "",
"legend": "",
"note": "",
"ownr_nm": "",
"paintpriority": "",
@@ -2442,6 +2525,8 @@
"export_payables": "",
"export_payments": "",
"export_receivables": "",
"exported_gsr_by_ro": "",
"exported_gsr_by_ro_labor": "",
"gsr_by_atp": "",
"gsr_by_ats": "",
"gsr_by_category": "",
@@ -2603,6 +2688,7 @@
},
"timetickets": {
"actions": {
"claimtasks": "",
"clockin": "",
"clockout": "",
"enter": "",
@@ -2623,10 +2709,12 @@
"clockhours": "",
"clockoff": "",
"clockon": "",
"committed": "",
"cost_center": "",
"date": "",
"efficiency": "",
"employee": "",
"employee_team": "",
"flat_rate": "",
"memo": "",
"productivehrs": "",
@@ -2661,7 +2749,8 @@
},
"validation": {
"clockoffmustbeafterclockon": "",
"clockoffwithoutclockon": ""
"clockoffwithoutclockon": "",
"hoursenteredmorethanavailable": ""
}
},
"titles": {
@@ -2712,6 +2801,7 @@
"shop-vendors": "",
"temporarydocs": "",
"timetickets": "",
"ttapprovals": "",
"vehicle-details": "",
"vehicles": ""
},
@@ -2757,9 +2847,15 @@
"shop_vendors": "Vendeurs | $t(titles.app)",
"temporarydocs": "",
"timetickets": "",
"ttapprovals": "",
"vehicledetail": "Détails du véhicule {{vehicle} | $t(titles.app)",
"vehicles": "Tous les véhicules | $t(titles.app)"
},
"tt_approvals": {
"actions": {
"approveselected": ""
}
},
"user": {
"actions": {
"changepassword": "",

View File

@@ -1,6 +1,5 @@
import { gql } from "@apollo/client";
import { notification } from "antd";
import axios from "axios";
import jsreport from "@jsreport/browser-client";
import _ from "lodash";
import moment from "moment";
@@ -9,7 +8,8 @@ import { setEmailOptions } from "../redux/email/email.actions";
import { store } from "../redux/store";
import client from "../utils/GraphQLClient";
import { TemplateList } from "./TemplateConstants";
import cleanAxios from "./CleanAxios";
import axios from "axios";
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
jsreport.serverUrl = server;
@@ -26,10 +26,14 @@ export default async function RenderTemplate(
if (window.jsr3) {
jsreport.serverUrl = "https://reports3.test.imex.online/";
}
const jsrAuth = (await axios.post("/utils/jsr")).data;
jsreport.headers["Authorization"] = jsrAuth;
//Query assets that match the template name. Must be in format <<templateName>>.query
let { contextData, useShopSpecificTemplate } = await fetchContextData(
templateObject
templateObject,
jsrAuth
);
const { ignoreCustomMargins } = Templates[templateObject.name];
@@ -137,11 +141,15 @@ export async function RenderTemplates(
//Query assets that match the template name. Must be in format <<templateName>>.query
let unsortedTemplatesAndData = [];
let proms = [];
const jsrAuth = (await axios.post("/utils/jsr")).data;
jsreport.headers["Authorization"] = jsrAuth;
templateObjects.forEach((template) => {
proms.push(
(async () => {
let { contextData, useShopSpecificTemplate } = await fetchContextData(
template
template,
jsrAuth
);
unsortedTemplatesAndData.push({
templateObject: template,
@@ -298,19 +306,22 @@ export const GenerateDocuments = async (templates) => {
await RenderTemplates(templates, bodyshop);
};
const fetchContextData = async (templateObject) => {
const fetchContextData = async (templateObject, jsrAuth) => {
const bodyshop = store.getState().user.bodyshop;
jsreport.headers["Authorization"] =
jsreport.headers["FirebaseAuthorization"] =
"Bearer " + (await auth.currentUser.getIdToken());
const folders = await axios.get(`${server}/odata/folders`);
const folders = await cleanAxios.get(`${server}/odata/folders`, {
headers: { Authorization: jsrAuth },
});
const shopSpecificFolder = folders.data.value.find(
(f) => f.name === bodyshop.imexshopid
);
const jsReportQueries = await axios.get(
`${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`
const jsReportQueries = await cleanAxios.get(
`${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`,
{ headers: { Authorization: jsrAuth } }
);
let templateQueryToExecute;

View File

@@ -7,23 +7,24 @@ export const EmailSettings = {
export const TemplateList = (type, context) => {
//const { bodyshop } = store.getState().user;
return {
//If there's no type or the type is job, send it back.
...(!type || type === "job"
? {
casl_authorization: {
title: i18n.t("printcenter.jobs.casl_authorization"),
description: "CASL Authorization",
description: "",
subject: i18n.t("printcenter.jobs.casl_authorization"),
key: "casl_authorization",
disabled: false,
group: "authorization",
regions: {
CA: true,
},
},
fippa_authorization: {
title: i18n.t("printcenter.jobs.fippa_authorization"),
description: "CASL Authorization",
description: "",
subject: i18n.t("printcenter.jobs.fippa_authorization"),
key: "fippa_authorization",
disabled: false,
@@ -31,7 +32,7 @@ export const TemplateList = (type, context) => {
},
diagnostic_authorization: {
title: i18n.t("printcenter.jobs.diagnostic_authorization"),
description: "Diagnostic Authorization",
description: "",
subject: i18n.t("printcenter.jobs.diagnostic_authorization"),
key: "diagnostic_authorization",
disabled: false,
@@ -39,7 +40,7 @@ export const TemplateList = (type, context) => {
},
mechanical_authorization: {
title: i18n.t("printcenter.jobs.mechanical_authorization"),
description: "Diagnostic Authorization",
description: "",
subject: i18n.t("printcenter.jobs.mechanical_authorization"),
key: "mechanical_authorization",
disabled: false,
@@ -47,7 +48,7 @@ export const TemplateList = (type, context) => {
},
appointment_reminder: {
title: i18n.t("printcenter.jobs.appointment_reminder"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.appointment_reminder"),
key: "appointment_reminder",
disabled: false,
@@ -55,7 +56,7 @@ export const TemplateList = (type, context) => {
},
estimate_followup: {
title: i18n.t("printcenter.jobs.estimate_followup"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.estimate_followup"),
key: "estimate_followup",
disabled: false,
@@ -63,7 +64,7 @@ export const TemplateList = (type, context) => {
},
express_repair_checklist: {
title: i18n.t("printcenter.jobs.express_repair_checklist"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.express_repair_checklist"),
key: "express_repair_checklist",
disabled: false,
@@ -71,7 +72,7 @@ export const TemplateList = (type, context) => {
},
glass_express_checklist: {
title: i18n.t("printcenter.jobs.glass_express_checklist"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.glass_express_checklist"),
key: "glass_express_checklist",
disabled: false,
@@ -79,7 +80,7 @@ export const TemplateList = (type, context) => {
},
stolen_recovery_checklist: {
title: i18n.t("printcenter.jobs.stolen_recovery_checklist"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.stolen_recovery_checklist"),
key: "stolen_recovery_checklist",
disabled: false,
@@ -87,7 +88,7 @@ export const TemplateList = (type, context) => {
},
vehicle_check_in: {
title: i18n.t("printcenter.jobs.vehicle_check_in"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.vehicle_check_in"),
key: "vehicle_check_in",
disabled: false,
@@ -95,16 +96,15 @@ export const TemplateList = (type, context) => {
},
parts_order_history: {
title: i18n.t("printcenter.jobs.parts_order_history"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.parts_order_history"),
key: "parts_order_history",
disabled: false,
group: "ro",
},
job_notes: {
title: i18n.t("printcenter.jobs.job_notes"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.job_notes"),
key: "job_notes",
disabled: false,
@@ -112,7 +112,7 @@ export const TemplateList = (type, context) => {
},
ro_with_description: {
title: i18n.t("printcenter.jobs.ro_with_description"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.ro_with_description"),
key: "ro_with_description",
disabled: false,
@@ -120,7 +120,7 @@ export const TemplateList = (type, context) => {
},
window_tag: {
title: i18n.t("printcenter.jobs.window_tag"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.window_tag"),
key: "window_tag",
disabled: false,
@@ -128,7 +128,7 @@ export const TemplateList = (type, context) => {
},
supplement_request: {
title: i18n.t("printcenter.jobs.supplement_request"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.supplement_request"),
key: "supplement_request",
disabled: false,
@@ -136,7 +136,7 @@ export const TemplateList = (type, context) => {
},
estimate: {
title: i18n.t("printcenter.jobs.estimate"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.estimate"),
key: "estimate",
disabled: false,
@@ -144,7 +144,7 @@ export const TemplateList = (type, context) => {
},
parts_list: {
title: i18n.t("printcenter.jobs.parts_list"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.parts_list"),
key: "parts_list",
disabled: false,
@@ -152,7 +152,7 @@ export const TemplateList = (type, context) => {
},
coversheet_portrait: {
title: i18n.t("printcenter.jobs.coversheet_portrait"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.coversheet_portrait"),
key: "coversheet_portrait",
disabled: false,
@@ -160,7 +160,7 @@ export const TemplateList = (type, context) => {
},
coversheet_landscape: {
title: i18n.t("printcenter.jobs.coversheet_landscape"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.coversheet_landscape"),
key: "coversheet_landscape",
disabled: false,
@@ -168,7 +168,7 @@ export const TemplateList = (type, context) => {
},
key_tag: {
title: i18n.t("printcenter.jobs.key_tag"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.key_tag"),
key: "key_tag",
disabled: false,
@@ -176,7 +176,7 @@ export const TemplateList = (type, context) => {
},
paint_grid: {
title: i18n.t("printcenter.jobs.paint_grid"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.paint_grid"),
key: "paint_grid",
disabled: false,
@@ -184,7 +184,7 @@ export const TemplateList = (type, context) => {
},
worksheet_by_line_number: {
title: i18n.t("printcenter.jobs.worksheet_by_line_number"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.worksheet_by_line_number"),
key: "worksheet_by_line_number",
disabled: false,
@@ -194,7 +194,7 @@ export const TemplateList = (type, context) => {
title: i18n.t(
"printcenter.jobs.worksheet_sorted_by_operation_type"
),
description: "All Jobs Notes",
description: "",
subject: i18n.t(
"printcenter.jobs.worksheet_sorted_by_operation_type"
),
@@ -204,7 +204,7 @@ export const TemplateList = (type, context) => {
},
worksheet_sorted_by_operation: {
title: i18n.t("printcenter.jobs.worksheet_sorted_by_operation"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.worksheet_sorted_by_operation"),
key: "worksheet_sorted_by_operation",
disabled: false,
@@ -214,7 +214,7 @@ export const TemplateList = (type, context) => {
title: i18n.t(
"printcenter.jobs.worksheet_sorted_by_operation_no_hours"
),
description: "All Jobs Notes",
description: "",
subject: i18n.t(
"printcenter.jobs.worksheet_sorted_by_operation_no_hours"
),
@@ -226,7 +226,7 @@ export const TemplateList = (type, context) => {
title: i18n.t(
"printcenter.jobs.worksheet_sorted_by_operation_part_type"
),
description: "All Jobs Notes",
description: "",
subject: i18n.t(
"printcenter.jobs.worksheet_sorted_by_operation_part_type"
),
@@ -236,7 +236,7 @@ export const TemplateList = (type, context) => {
},
payments_by_job: {
title: i18n.t("printcenter.jobs.payments_by_job"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.payments_by_job"),
key: "payments_by_job",
disabled: false,
@@ -244,7 +244,7 @@ export const TemplateList = (type, context) => {
},
final_invoice: {
title: i18n.t("printcenter.jobs.final_invoice"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.final_invoice"),
key: "final_invoice",
disabled: false,
@@ -252,7 +252,7 @@ export const TemplateList = (type, context) => {
},
payment_request: {
title: i18n.t("printcenter.jobs.payment_request"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.payment_request"),
key: "payment_request",
disabled: false,
@@ -260,7 +260,7 @@ export const TemplateList = (type, context) => {
},
invoice_total_payable: {
title: i18n.t("printcenter.jobs.invoice_total_payable"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.invoice_total_payable"),
key: "invoice_total_payable",
disabled: false,
@@ -268,7 +268,7 @@ export const TemplateList = (type, context) => {
},
invoice_customer_payable: {
title: i18n.t("printcenter.jobs.invoice_customer_payable"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.invoice_customer_payable"),
key: "invoice_customer_payable",
disabled: false,
@@ -276,7 +276,7 @@ export const TemplateList = (type, context) => {
},
ro_totals: {
title: i18n.t("printcenter.jobs.ro_totals"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.ro_totals"),
key: "ro_totals",
disabled: false,
@@ -284,7 +284,7 @@ export const TemplateList = (type, context) => {
},
job_costing_ro: {
title: i18n.t("printcenter.jobs.job_costing_ro"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.job_costing_ro"),
key: "job_costing_ro",
disabled: false,
@@ -292,7 +292,7 @@ export const TemplateList = (type, context) => {
},
purchases_by_ro_detail: {
title: i18n.t("printcenter.jobs.purchases_by_ro_detail"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.purchases_by_ro_detail"),
key: "purchases_by_ro_detail",
disabled: false,
@@ -300,7 +300,7 @@ export const TemplateList = (type, context) => {
},
purchases_by_ro_summary: {
title: i18n.t("printcenter.jobs.purchases_by_ro_summary"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.purchases_by_ro_summary"),
key: "purchases_by_ro_summary",
disabled: false,
@@ -308,7 +308,7 @@ export const TemplateList = (type, context) => {
},
filing_coversheet_portrait: {
title: i18n.t("printcenter.jobs.filing_coversheet_portrait"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.filing_coversheet_portrait"),
key: "filing_coversheet_portrait",
disabled: false,
@@ -316,7 +316,7 @@ export const TemplateList = (type, context) => {
},
filing_coversheet_landscape: {
title: i18n.t("printcenter.jobs.filing_coversheet_landscape"),
description: "CASL Authorization",
description: "",
subject: i18n.t("printcenter.jobs.filing_coversheet_landscape"),
key: "filing_coversheet_landscape",
disabled: false,
@@ -324,25 +324,23 @@ export const TemplateList = (type, context) => {
},
qc_sheet: {
title: i18n.t("printcenter.jobs.qc_sheet"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.qc_sheet"),
key: "qc_sheet",
disabled: false,
group: "post",
},
vehicle_delivery_check: {
title: i18n.t("printcenter.jobs.vehicle_delivery_check"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.vehicle_delivery_check"),
key: "vehicle_delivery_check",
disabled: false,
group: "post",
},
guarantee: {
title: i18n.t("printcenter.jobs.guarantee"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.guarantee"),
key: "guarantee",
disabled: false,
@@ -350,7 +348,7 @@ export const TemplateList = (type, context) => {
},
csi_invitation: {
title: i18n.t("printcenter.jobs.csi_invitation"),
description: "CSI invite",
description: "",
key: "csi_invitation",
subject: i18n.t("printcenter.jobs.csi_invitation"),
disabled: false,
@@ -358,7 +356,7 @@ export const TemplateList = (type, context) => {
},
window_tag_sublet: {
title: i18n.t("printcenter.jobs.window_tag_sublet"),
description: "Window Tag Sublet",
description: "",
key: "window_tag_sublet",
subject: i18n.t("printcenter.jobs.window_tag_sublet"),
disabled: false,
@@ -366,7 +364,7 @@ export const TemplateList = (type, context) => {
},
thank_you_ro: {
title: i18n.t("printcenter.jobs.thank_you_ro"),
description: "Thank You Letter by RO",
description: "",
key: "thank_you_ro",
subject: i18n.t("printcenter.jobs.thank_you_ro"),
disabled: false,
@@ -374,7 +372,7 @@ export const TemplateList = (type, context) => {
},
parts_label_single: {
title: i18n.t("printcenter.jobs.parts_label_single"),
description: "Thank You Letter by RO",
description: "",
key: "parts_label_single",
subject: i18n.t("printcenter.jobs.parts_label_single"),
disabled: false,
@@ -383,7 +381,7 @@ export const TemplateList = (type, context) => {
},
envelope_return_address: {
title: i18n.t("printcenter.jobs.envelope_return_address"),
description: "All Jobs Notes",
description: "",
subject: i18n.t("printcenter.jobs.envelope_return_address"),
key: "envelope_return_address",
disabled: false,
@@ -392,7 +390,7 @@ export const TemplateList = (type, context) => {
},
sgi_certificate_of_repairs: {
title: i18n.t("printcenter.jobs.sgi_certificate_of_repairs"),
description: "Thank You Letter by RO",
description: "",
key: "sgi_certificate_of_repairs",
subject: i18n.t("printcenter.jobs.sgi_certificate_of_repairs"),
disabled: false,
@@ -403,7 +401,7 @@ export const TemplateList = (type, context) => {
},
sgi_windshield_auth: {
title: i18n.t("printcenter.jobs.sgi_windshield_auth"),
description: "Thank You Letter by RO",
description: "",
key: "sgi_windshield_auth",
subject: i18n.t("printcenter.jobs.sgi_windshield_auth"),
disabled: false,
@@ -414,7 +412,7 @@ export const TemplateList = (type, context) => {
},
mpi_final_acct_sheet: {
title: i18n.t("printcenter.jobs.mpi_final_acct_sheet"),
description: "Thank You Letter by RO",
description: "",
key: "mpi_final_acct_sheet",
subject: i18n.t("printcenter.jobs.mpi_final_acct_sheet"),
disabled: false,
@@ -425,7 +423,7 @@ export const TemplateList = (type, context) => {
},
mpi_eglass_auth: {
title: i18n.t("printcenter.jobs.mpi_eglass_auth"),
description: "Thank You Letter by RO",
description: "",
key: "mpi_eglass_auth",
subject: i18n.t("printcenter.jobs.mpi_eglass_auth"),
disabled: false,
@@ -436,7 +434,7 @@ export const TemplateList = (type, context) => {
},
mpi_animal_checklist: {
title: i18n.t("printcenter.jobs.mpi_animal_checklist"),
description: "Thank You Letter by RO",
description: "",
key: "mpi_animal_checklist",
subject: i18n.t("printcenter.jobs.mpi_animal_checklist"),
disabled: false,
@@ -447,7 +445,7 @@ export const TemplateList = (type, context) => {
},
ab_proof_of_loss: {
title: i18n.t("printcenter.jobs.ab_proof_of_loss"),
description: "Thank You Letter by RO",
description: "",
key: "ab_proof_of_loss",
subject: i18n.t("printcenter.jobs.ab_proof_of_loss"),
disabled: false,
@@ -458,7 +456,7 @@ export const TemplateList = (type, context) => {
},
// parts_label_multi: {
// title: i18n.t("printcenter.jobs.parts_label_multi"),
// description: "Thank You Letter by RO",
// description: "",
// key: "parts_label_multi",
// subject: i18n.t("printcenter.jobs.parts_label_multi"),
// disabled: false,
@@ -466,7 +464,7 @@ export const TemplateList = (type, context) => {
// },
iou_form: {
title: i18n.t("printcenter.jobs.iou_form"),
description: "CASL Authorization",
description: "",
subject: i18n.t("printcenter.jobs.iou_form"),
key: "iou_form",
disabled: false,
@@ -474,7 +472,7 @@ export const TemplateList = (type, context) => {
},
lag_time_ro: {
title: i18n.t("printcenter.jobs.lag_time_ro"),
description: "CASL Authorization",
description: "",
subject: i18n.t("printcenter.jobs.lag_time_ro"),
key: "lag_time_ro",
disabled: false,
@@ -482,7 +480,7 @@ export const TemplateList = (type, context) => {
},
rental_reservation: {
title: i18n.t("printcenter.jobs.rental_reservation"),
description: "CASL Authorization",
description: "",
subject: i18n.t("printcenter.jobs.rental_reservation"),
key: "rental_reservation",
disabled: false,
@@ -490,53 +488,61 @@ export const TemplateList = (type, context) => {
},
timetickets_ro: {
title: i18n.t("printcenter.jobs.timetickets_ro"),
description: "CASL Authorization",
description: "",
subject: i18n.t("printcenter.jobs.timetickets_ro"),
key: "timetickets_ro",
disabled: false,
group: "financial",
},
dms_posting_sheet: {
title: i18n.t("printcenter.jobs.dms_posting_sheet"),
description: "",
subject: i18n.t("printcenter.jobs.dms_posting_sheet"),
key: "dms_posting_sheet",
disabled: false,
group: "financial",
},
}
: {}),
...(!type || type === "job_special"
? {
special_thirdpartypayer: {
title: i18n.t("printcenter.jobs.thirdpartypayer"),
description: "CSI invite",
description: "",
key: "special_thirdpartypayer",
disabled: false,
},
folder_label_multiple: {
title: i18n.t("printcenter.jobs.folder_label_multiple"),
description: "Folder Label Multiple",
description: "",
key: "folder_label_multiple",
disabled: false,
},
parts_label_multiple: {
title: i18n.t("printcenter.jobs.parts_label_multiple"),
description: "Parts Label Multiple",
description: "",
key: "parts_label_multiple",
disabled: false,
},
parts_invoice_label_single: {
title: i18n.t("printcenter.jobs.parts_invoice_label_single"),
description: "Parts Label Multiple",
description: "",
key: "parts_invoice_label_single",
disabled: false,
ignoreCustomMargins: true,
},
csi_invitation_action: {
title: i18n.t("printcenter.jobs.csi_invitation_action"),
description: "CSI invite",
description: "",
key: "csi_invitation_action",
subject: i18n.t("printcenter.jobs.csi_invitation_action"),
disabled: false,
},
individual_job_note: {
title: i18n.t("printcenter.jobs.individual_job_note"),
description: "CSI invite",
description: "",
key: "individual_job_note",
subject: i18n.t("printcenter.jobs.individual_job_note", {
subject: i18n.t("printcenter.subjects.jobs.individual_job_note", {
ro_number: (context && context.ro_number) || "",
}),
disabled: false,
@@ -547,7 +553,7 @@ export const TemplateList = (type, context) => {
? {
appointment_confirmation: {
title: i18n.t("printcenter.appointments.appointment_confirmation"),
description: "Appointment Confirmation",
description: "",
subject: i18n.t(
"printcenter.appointments.appointment_confirmation"
),
@@ -560,7 +566,7 @@ export const TemplateList = (type, context) => {
? {
parts_order: {
title: i18n.t("printcenter.jobs.parts_order"),
description: "Parts Order",
description: "",
key: "parts_order",
subject: i18n.t("printcenter.subjects.jobs.parts_order", {
ro_number: context && context.job && context.job.ro_number,
@@ -574,7 +580,7 @@ export const TemplateList = (type, context) => {
},
sublet_order: {
title: i18n.t("printcenter.jobs.sublet_order"),
description: "Parts Order",
description: "",
key: "sublet_order",
subject: i18n.t("printcenter.subjects.jobs.sublet_order", {
ro_number: context && context.job && context.job.ro_number,
@@ -589,7 +595,7 @@ export const TemplateList = (type, context) => {
parts_return_slip: {
title: i18n.t("printcenter.jobs.parts_return_slip"),
subject: i18n.t("printcenter.jobs.parts_return_slip"),
description: "Parts Return",
description: "",
key: "parts_return_slip",
disabled: false,
},
@@ -599,7 +605,7 @@ export const TemplateList = (type, context) => {
? {
payment_receipt: {
title: i18n.t("printcenter.jobs.payment_receipt"),
description: "Payment Receipt",
description: "",
subject: i18n.t("printcenter.jobs.payment_receipt"),
key: "payment_receipt",
disabled: false,
@@ -622,7 +628,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
hours_sold_detail_closed_ins_co: {
title: i18n.t(
"reportcenter.templates.hours_sold_detail_closed_ins_co"
@@ -640,7 +645,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
hours_sold_summary_closed: {
title: i18n.t("reportcenter.templates.hours_sold_summary_closed"),
description: "",
@@ -654,7 +658,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
hours_sold_summary_closed_ins_co: {
title: i18n.t(
"reportcenter.templates.hours_sold_summary_closed_ins_co"
@@ -672,7 +675,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
hours_sold_detail_open: {
title: i18n.t("reportcenter.templates.hours_sold_detail_open"),
description: "",
@@ -686,7 +688,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
hours_sold_detail_open_ins_co: {
title: i18n.t(
"reportcenter.templates.hours_sold_detail_open_ins_co"
@@ -704,7 +705,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
hours_sold_summary_open: {
title: i18n.t("reportcenter.templates.hours_sold_summary_open"),
description: "",
@@ -718,7 +718,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
hours_sold_summary_open_ins_co: {
title: i18n.t(
"reportcenter.templates.hours_sold_summary_open_ins_co"
@@ -736,7 +735,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
hours_sold_detail_closed_csr: {
title: i18n.t(
"reportcenter.templates.hours_sold_detail_closed_csr"
@@ -1090,7 +1088,6 @@ export const TemplateList = (type, context) => {
},
group: "customers",
},
schedule: {
title: i18n.t("reportcenter.templates.schedule"),
subject: i18n.t("reportcenter.templates.schedule"),
@@ -1102,7 +1099,6 @@ export const TemplateList = (type, context) => {
},
group: "customers",
},
timetickets: {
title: i18n.t("reportcenter.templates.timetickets"),
subject: i18n.t("reportcenter.templates.timetickets"),
@@ -1126,7 +1122,6 @@ export const TemplateList = (type, context) => {
title: i18n.t("reportcenter.templates.attendance_detail"),
subject: i18n.t("reportcenter.templates.attendance_detail"),
key: "attendance_detail",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.timetickets"),
@@ -1138,7 +1133,6 @@ export const TemplateList = (type, context) => {
title: i18n.t("reportcenter.templates.attendance_summary"),
subject: i18n.t("reportcenter.templates.attendance_summary"),
key: "attendance_summary",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.timetickets"),
@@ -1158,7 +1152,6 @@ export const TemplateList = (type, context) => {
},
group: "payroll",
},
timetickets_summary: {
title: i18n.t("reportcenter.templates.timetickets_summary"),
subject: i18n.t("reportcenter.templates.timetickets_summary"),
@@ -1171,7 +1164,6 @@ export const TemplateList = (type, context) => {
},
group: "payroll",
},
estimator_detail: {
title: i18n.t("reportcenter.templates.estimator_detail"),
description: "",
@@ -1224,7 +1216,6 @@ export const TemplateList = (type, context) => {
},
group: "purchases",
},
void_ros: {
title: i18n.t("reportcenter.templates.void_ros"),
description: "",
@@ -1329,7 +1320,6 @@ export const TemplateList = (type, context) => {
},
group: "sales",
},
gsr_by_estimator: {
title: i18n.t("reportcenter.templates.gsr_by_estimator"),
description: "",
@@ -1814,7 +1804,9 @@ export const TemplateList = (type, context) => {
group: "jobs",
},
purchase_return_ratio_grouped_by_vendor_detail: {
title: i18n.t("reportcenter.templates.purchase_return_ratio_grouped_by_vendor_detail"),
title: i18n.t(
"reportcenter.templates.purchase_return_ratio_grouped_by_vendor_detail"
),
subject: i18n.t(
"reportcenter.templates.purchase_return_ratio_grouped_by_vendor_detail"
),
@@ -1828,7 +1820,9 @@ export const TemplateList = (type, context) => {
group: "purchases",
},
purchase_return_ratio_grouped_by_vendor_summary: {
title: i18n.t("reportcenter.templates.purchase_return_ratio_grouped_by_vendor_summary"),
title: i18n.t(
"reportcenter.templates.purchase_return_ratio_grouped_by_vendor_summary"
),
subject: i18n.t(
"reportcenter.templates.purchase_return_ratio_grouped_by_vendor_summary"
),
@@ -1843,9 +1837,7 @@ export const TemplateList = (type, context) => {
},
production_over_time: {
title: i18n.t("reportcenter.templates.production_over_time"),
subject: i18n.t(
"reportcenter.templates.production_over_time"
),
subject: i18n.t("reportcenter.templates.production_over_time"),
key: "production_over_time",
//idtype: "vendor",
disabled: false,
@@ -1857,9 +1849,7 @@ export const TemplateList = (type, context) => {
},
customer_list: {
title: i18n.t("reportcenter.templates.customer_list"),
subject: i18n.t(
"reportcenter.templates.customer_list"
),
subject: i18n.t("reportcenter.templates.customer_list"),
key: "customer_list",
//idtype: "vendor",
disabled: false,
@@ -1869,6 +1859,32 @@ export const TemplateList = (type, context) => {
},
group: "customers",
},
exported_gsr_by_ro: {
title: i18n.t("reportcenter.templates.exported_gsr_by_ro"),
subject: i18n.t("reportcenter.templates.exported_gsr_by_ro"),
key: "exported_gsr_by_ro",
//idtype: "vendor",
reporttype: "excel",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_exported"),
},
group: "sales",
},
exported_gsr_by_ro_labor: {
title: i18n.t("reportcenter.templates.exported_gsr_by_ro_labor"),
subject: i18n.t("reportcenter.templates.exported_gsr_by_ro_labor"),
key: "exported_gsr_by_ro_labor",
//idtype: "vendor",
reporttype: "excel",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_exported"),
},
group: "sales",
},
}
: {}),
...(!type || type === "courtesycarcontract"
@@ -1877,7 +1893,7 @@ export const TemplateList = (type, context) => {
title: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_contract"
),
description: "Est Detail",
description: "",
subject: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_contract"
),
@@ -1886,7 +1902,7 @@ export const TemplateList = (type, context) => {
},
courtesy_car_terms: {
title: i18n.t("printcenter.courtesycarcontract.courtesy_car_terms"),
description: "Est Detail",
description: "",
subject: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_terms"
),
@@ -1897,7 +1913,7 @@ export const TemplateList = (type, context) => {
title: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_impound"
),
description: "Est Detail",
description: "",
subject: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_impound"
),
@@ -1912,7 +1928,7 @@ export const TemplateList = (type, context) => {
title: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_inventory"
),
description: "Est Detail",
description: "",
subject: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_inventory"
),
@@ -1925,7 +1941,7 @@ export const TemplateList = (type, context) => {
? {
inhouse_invoice: {
title: i18n.t("printcenter.bills.inhouse_invoice"),
description: "Est Detail",
description: "",
subject: i18n.t("printcenter.bills.inhouse_invoice"),
key: "inhouse_invoice",
disabled: false,
@@ -1936,7 +1952,7 @@ export const TemplateList = (type, context) => {
? {
// timetickets: {
// title: i18n.t("printcenter.timetickets.timetickets"),
// description: "Est Detail",
// description: "",
// subject: `${i18n.t("printcenter.timetickets.timetickets")} - ${
// context && context.job && context.job.ro_number
// }`,
@@ -1949,21 +1965,20 @@ export const TemplateList = (type, context) => {
? {
purchases_by_vendor_detailed: {
title: i18n.t("printcenter.vendors.purchases_by_vendor_detailed"),
description: "Est Detail",
description: "",
subject: i18n.t("printcenter.vendors.purchases_by_vendor_detailed"),
key: "purchases_by_vendor_detailed",
disabled: false,
},
purchases_by_vendor_summary: {
title: i18n.t("printcenter.vendors.purchases_by_vendor_summary"),
description: "Est Detail",
description: "",
subject: i18n.t("printcenter.vendors.purchases_by_vendor_summary"),
key: "purchases_by_vendor_summary",
disabled: false,
},
}
: {}),
...(!type || type === "production"
? {
production_by_last_name: {
@@ -2030,21 +2045,21 @@ export const TemplateList = (type, context) => {
? {
ca_bc_etf_table: {
title: i18n.t("printcenter.payments.ca_bc_etf_table"),
description: "Est Detail",
description: "",
subject: i18n.t("printcenter.payments.ca_bc_etf_table"),
key: "ca_bc_etf_table",
disabled: false,
},
exported_payroll: {
title: i18n.t("printcenter.payments.exported_payroll"),
description: "Est Detail",
description: "",
subject: i18n.t("printcenter.payments.exported_payroll"),
key: "exported_payroll",
disabled: false,
},
attendance_detail_csv: {
title: i18n.t("printcenter.special.attendance_detail_csv"),
description: "Est Detail",
description: "",
subject: i18n.t("printcenter.special.attendance_detail_csv"),
key: "attendance_detail_csv",
disabled: false,

View File

@@ -3924,14 +3924,6 @@ anymatch@^3.0.3, anymatch@~3.1.2:
normalize-path "^3.0.0"
picomatch "^2.0.4"
aphrodite@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/aphrodite/-/aphrodite-0.5.0.tgz#a4b9a8902662395d2702e70ac7a2b4ca66f25703"
integrity sha512-bPcR/68OdLg+16XDYAaKnlGJufxrbOw86ucElS7qHm7Y6ZNvMT/D/VDEEfodjFgfyRyoTeKmSaikULG92kSYvQ==
dependencies:
asap "^2.0.3"
inline-style-prefixer "^2.0.0"
apollo-link-logger@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/apollo-link-logger/-/apollo-link-logger-2.0.1.tgz#63d86b4fe550c147c5a52108710075675694905c"
@@ -4073,7 +4065,7 @@ array.prototype.tosorted@^1.1.1:
es-shim-unscopables "^1.0.0"
get-intrinsic "^1.1.3"
asap@^2.0.3, asap@~2.0.6:
asap@~2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
@@ -4484,11 +4476,6 @@ boolbase@^1.0.0, boolbase@~1.0.0:
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
bowser@^1.0.0:
version "1.9.4"
resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.9.4.tgz#890c58a2813a9d3243704334fa81b96a5c150c9a"
integrity sha512-9IdMmj2KjigRq6oWhmwv1W36pDuA4STQZ8q6YO9um+x07xgYNCD3Oou+WP/3L1HNz7iqythGet3/p4wvc8AAwQ==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -6504,7 +6491,7 @@ executable@^4.1.1:
dependencies:
pify "^2.2.0"
exenv@^1.2.2:
exenv@^1.2.0:
version "1.2.2"
resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d"
integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==
@@ -7404,11 +7391,6 @@ human-signals@^2.1.0:
resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
hyphenate-style-name@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
i18next-browser-languagedetector@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.0.1.tgz#ead34592edc96c6c3a618a51cb57ad027c5b5d87"
@@ -7543,14 +7525,6 @@ ini@^1.3.5:
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
inline-style-prefixer@^2.0.0:
version "2.0.5"
resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7"
integrity sha512-rlgoApaAAv66JeDFqGYaXwglnlxjyIr7RMaFZqJw4opT0WKnZVXhXMC9SAfuMpN7NELPaImUhJmOO3hAamSlfw==
dependencies:
bowser "^1.0.0"
hyphenate-style-name "^1.0.1"
internal-slot@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c"
@@ -11157,13 +11131,10 @@ react-error-overlay@6.0.9, react-error-overlay@^6.0.11:
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.9.tgz#3c743010c9359608c375ecd6bc76f35d93995b0a"
integrity sha512-nQTTcUu+ATDbrSD1BZHr5kgSD4oF8OFjxun8uAaL8RwPBacGBNPf/yAuVVdx17N8XNzRDMrZ9XcKZHCjPW+9ew==
react-grid-gallery@^0.5.5:
version "0.5.5"
resolved "https://registry.yarnpkg.com/react-grid-gallery/-/react-grid-gallery-0.5.5.tgz#1b3f3c23a190834e587ab613c96d53ec3af4f0a2"
integrity sha512-DkKg2/Am+VZPDG39fazelTcsZSQrfM/YllnIcWToyUEfOZcrzHxUoqCziCkuTPmCuMbHnrjidBFuDbAFgvSnvQ==
dependencies:
prop-types "^15.5.8"
react-images "^0.5.16"
react-grid-gallery@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/react-grid-gallery/-/react-grid-gallery-1.0.0.tgz#31604b9488dfa75a899aa39bc8884138f0409a12"
integrity sha512-S1gr6WXBlPFVrE0x2BHuu7jhyaB61mabcMQyx+8KCgAyKzGza0WF67AfAnS9Q00aurFEq4IP8eqb2Bk5F4RAmQ==
react-grid-layout@^1.3.4:
version "1.3.4"
@@ -11189,15 +11160,13 @@ react-icons@^4.7.1:
resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-4.7.1.tgz#0f4b25a5694e6972677cb189d2a72eabea7a8345"
integrity sha512-yHd3oKGMgm7zxo3EA7H2n7vxSoiGmHk5t6Ou4bXsfcgWyhfDKMpyKfhHR6Bjnn63c+YXBLBPUql9H4wPJM6sXw==
react-images@^0.5.16:
version "0.5.19"
resolved "https://registry.yarnpkg.com/react-images/-/react-images-0.5.19.tgz#9339570029e065f9f28a19f03fdb5d9d5aa109d3"
integrity sha512-B3d4W1uFJj+m17K8S65iAyEJShKGBjPk7n7N1YsPiAydEm8mIq9a6CoeQFMY1d7N2QMs6FBCjT9vELyc5jP5JA==
react-image-lightbox@^5.1.4:
version "5.1.4"
resolved "https://registry.yarnpkg.com/react-image-lightbox/-/react-image-lightbox-5.1.4.tgz#5b847dcb79e9efdf9d7cd5621a92e0f156d2cf30"
integrity sha512-kTiAODz091bgT7SlWNHab0LSMZAPJtlNWDGKv7pLlLY1krmf7FuG1zxE0wyPpeA8gPdwfr3cu6sPwZRqWsc3Eg==
dependencies:
aphrodite "^0.5.0"
prop-types "^15.6.0"
react-scrolllock "^2.0.1"
react-transition-group "2"
prop-types "^15.7.2"
react-modal "^3.11.1"
react-is@^16.10.2, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
version "16.13.1"
@@ -11214,11 +11183,21 @@ react-is@^18.0.0:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
react-lifecycles-compat@^3.0.4:
react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-modal@^3.11.1:
version "3.16.1"
resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.1.tgz#34018528fc206561b1a5467fc3beeaddafb39b2b"
integrity sha512-VStHgI3BVcGo7OXczvnJN7yT2TWHJPDXZWyI/a0ssFNhGZWsPmB8cF0z33ewDXq4VfYMO1vXgiv/g8Nj9NDyWg==
dependencies:
exenv "^1.2.0"
prop-types "^15.7.2"
react-lifecycles-compat "^3.0.0"
warning "^4.0.3"
react-number-format@^5.1.3:
version "5.1.3"
resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-5.1.3.tgz#5534f5141cea29e0fe889f76c73dfad11ddf2e17"
@@ -11240,11 +11219,6 @@ react-overlays@^5.2.1:
uncontrollable "^7.2.1"
warning "^4.0.3"
react-prop-toggle@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/react-prop-toggle/-/react-prop-toggle-1.0.2.tgz#8b0b7e74653606b1427cfcf6c4eaa9198330568e"
integrity sha512-JmerjAXs7qJ959+d0Ygt7Cb2+4fG+n3I2VXO6JO0AcAY1vkRN/JpZKAN67CMXY889xEJcfylmMPhzvf6nWO68Q==
react-redux@^7.2.0:
version "7.2.8"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.8.tgz#a894068315e65de5b1b68899f9c6ee0923dd28de"
@@ -11373,14 +11347,6 @@ react-scripts@^5.0.1:
optionalDependencies:
fsevents "^2.3.2"
react-scrolllock@^2.0.1:
version "2.0.7"
resolved "https://registry.yarnpkg.com/react-scrolllock/-/react-scrolllock-2.0.7.tgz#3b879e1fe308fc900ab76e226e9be594c41226fd"
integrity sha512-Gzpu8+ulxdYcybAgJOFTXc70xs7SBZDQbZNpKzchZUgLCJKjz6lrgESx6LHHZgfELx1xYL4yHu3kYQGQPFas/g==
dependencies:
exenv "^1.2.2"
react-prop-toggle "^1.0.2"
react-smooth@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-2.0.1.tgz#74c7309916d6ccca182c4b30c8992f179e6c5a05"
@@ -11405,7 +11371,7 @@ react-sublime-video@^0.2.5:
prop-types "^15.5.10"
rc-tween-one "^1.2.5"
react-transition-group@2, react-transition-group@2.9.0:
react-transition-group@2.9.0:
version "2.9.0"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
integrity sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==

View File

@@ -673,6 +673,30 @@
_eq: true
- exported:
_eq: false
event_triggers:
- name: os_bills
definition:
delete:
columns: '*'
enable_manual: false
insert:
columns: '*'
update:
columns: '*'
retry_conf:
interval_sec: 10
num_retries: 3
timeout_sec: 60
webhook_from_env: HASURA_API_URL
headers:
- name: event-secret
value_from_env: EVENT_SECRET
request_transform:
method: POST
query_params: {}
template_engine: Kriti
url: '{{$base_url}}/opensearch'
version: 2
- table:
name: bodyshops
schema: public
@@ -761,6 +785,13 @@
table:
name: email_audit_trail
schema: public
- name: employee_teams
using:
foreign_key_constraint_on:
column: bodyshopid
table:
name: employee_teams
schema: public
- name: employees
using:
foreign_key_constraint_on:
@@ -824,6 +855,13 @@
table:
name: transitions
schema: public
- name: tt_approval_queues
using:
foreign_key_constraint_on:
column: bodyshopid
table:
name: tt_approval_queue
schema: public
- name: vehicles
using:
foreign_key_constraint_on:
@@ -903,6 +941,7 @@
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- md_tasks_presets
- md_to_emails
- messagingservicesid
- pbs_configuration
@@ -928,8 +967,10 @@
- textid
- timezone
- tt_allow_post_to_invoiced
- tt_enforce_hours_for_tech_console
- updated_at
- use_fippa
- use_paint_scale_data
- uselocalmediaserver
- website
- workingdays
@@ -998,6 +1039,7 @@
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- md_tasks_presets
- md_to_emails
- pbs_configuration
- phone
@@ -1016,8 +1058,10 @@
- target_touchtime
- timezone
- tt_allow_post_to_invoiced
- tt_enforce_hours_for_tech_console
- updated_at
- use_fippa
- use_paint_scale_data
- uselocalmediaserver
- website
- workingdays
@@ -1945,6 +1989,165 @@
- active:
_eq: true
check: null
- table:
name: employee_team_members
schema: public
object_relationships:
- name: employee
using:
foreign_key_constraint_on: employeeid
- name: employee_team
using:
foreign_key_constraint_on: teamid
insert_permissions:
- role: user
permission:
check:
employee_team:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- labor_rates
- percentage
- created_at
- updated_at
- employeeid
- id
- teamid
select_permissions:
- role: user
permission:
columns:
- labor_rates
- percentage
- created_at
- updated_at
- employeeid
- id
- teamid
filter:
employee_team:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
update_permissions:
- role: user
permission:
columns:
- labor_rates
- percentage
- created_at
- updated_at
- employeeid
- id
- teamid
filter:
employee_team:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
check: null
delete_permissions:
- role: user
permission:
backend_only: false
filter:
employee_team:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
- table:
name: employee_teams
schema: public
object_relationships:
- name: bodyshop
using:
foreign_key_constraint_on: bodyshopid
array_relationships:
- name: employee_team_members
using:
foreign_key_constraint_on:
column: teamid
table:
name: employee_team_members
schema: public
insert_permissions:
- role: user
permission:
check:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- active
- name
- created_at
- updated_at
- bodyshopid
- id
select_permissions:
- role: user
permission:
columns:
- active
- name
- created_at
- updated_at
- bodyshopid
- id
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
update_permissions:
- role: user
permission:
columns:
- active
- bodyshopid
- name
- updated_at
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
check: null
- table:
name: employee_vacation
schema: public
@@ -2045,6 +2248,13 @@
table:
name: allocations
schema: public
- name: employee_team_members
using:
foreign_key_constraint_on:
column: employeeid
table:
name: employee_team_members
schema: public
- name: employee_vacations
using:
foreign_key_constraint_on:
@@ -2087,6 +2297,13 @@
table:
name: timetickets
schema: public
- name: tt_approval_queues
using:
foreign_key_constraint_on:
column: employeeid
table:
name: tt_approval_queue
schema: public
insert_permissions:
- role: user
permission:
@@ -2218,30 +2435,32 @@
- active:
_eq: true
columns:
- id
- created_at
- updated_at
- jobid
- billid
- bodyshopid
- created_at
- id
- jobid
- message
- metadata
- paymentid
- successful
- message
- bodyshopid
- updated_at
- useremail
select_permissions:
- role: user
permission:
columns:
- successful
- message
- useremail
- created_at
- updated_at
- billid
- bodyshopid
- created_at
- id
- jobid
- message
- metadata
- paymentid
- successful
- updated_at
- useremail
filter:
bodyshop:
associations:
@@ -2493,6 +2712,7 @@
_eq: true
columns:
- act_price
- act_price_before_ppc
- ah_detail_line
- alt_co_id
- alt_overrd
@@ -2559,6 +2779,7 @@
permission:
columns:
- act_price
- act_price_before_ppc
- ah_detail_line
- alt_co_id
- alt_overrd
@@ -2637,6 +2858,7 @@
permission:
columns:
- act_price
- act_price_before_ppc
- ah_detail_line
- alt_co_id
- alt_overrd
@@ -2965,6 +3187,13 @@
table:
name: transitions
schema: public
- name: tt_approval_queues
using:
foreign_key_constraint_on:
column: jobid
table:
name: tt_approval_queue
schema: public
insert_permissions:
- role: user
permission:
@@ -3853,6 +4082,29 @@
template_engine: Kriti
url: '{{$base_url}}/record-handler/arms'
version: 2
- name: os_jobs
definition:
delete:
columns: '*'
enable_manual: false
insert:
columns: '*'
update:
columns: '*'
retry_conf:
interval_sec: 10
num_retries: 3
timeout_sec: 60
webhook_from_env: HASURA_API_URL
headers:
- name: event-secret
value_from_env: EVENT_SECRET
request_transform:
method: POST
query_params: {}
template_engine: Kriti
url: '{{$base_url}}/opensearch'
version: 2
- table:
name: masterdata
schema: public
@@ -4081,6 +4333,7 @@
- jobid
- private
- text
- type
- updated_at
select_permissions:
- role: user
@@ -4094,6 +4347,7 @@
- jobid
- private
- text
- type
- updated_at
filter:
job:
@@ -4117,6 +4371,7 @@
- jobid
- private
- text
- type
- updated_at
filter:
job:
@@ -4277,6 +4532,30 @@
_eq: X-Hasura-User-Id
- active:
_eq: true
event_triggers:
- name: os_owners
definition:
delete:
columns: '*'
enable_manual: false
insert:
columns: '*'
update:
columns: '*'
retry_conf:
interval_sec: 10
num_retries: 3
timeout_sec: 60
webhook_from_env: HASURA_API_URL
headers:
- name: event-secret
value_from_env: EVENT_SECRET
request_transform:
method: POST
query_params: {}
template_engine: Kriti
url: '{{$base_url}}/opensearch'
version: 2
- table:
name: parts_order_lines
schema: public
@@ -4700,6 +4979,30 @@
_eq: X-Hasura-User-Id
- active:
_eq: true
event_triggers:
- name: os_payments
definition:
delete:
columns: '*'
enable_manual: false
insert:
columns: '*'
update:
columns: '*'
retry_conf:
interval_sec: 10
num_retries: 3
timeout_sec: 60
webhook_from_env: HASURA_API_URL
headers:
- name: event-secret
value_from_env: EVENT_SECRET
request_transform:
method: POST
query_params: {}
template_engine: Kriti
url: '{{$base_url}}/opensearch'
version: 2
- table:
name: phonebook
schema: public
@@ -5030,6 +5333,12 @@
- name: job
using:
foreign_key_constraint_on: jobid
- name: tt_approval_queue
using:
foreign_key_constraint_on: ttapprovalqueueid
- name: user
using:
foreign_key_constraint_on: commited_by
insert_permissions:
- role: user
permission:
@@ -5048,6 +5357,8 @@
- ciecacode
- clockoff
- clockon
- commited_by
- committed_at
- cost_center
- created_at
- date
@@ -5058,6 +5369,7 @@
- memo
- productivehrs
- rate
- ttapprovalqueueid
- updated_at
select_permissions:
- role: user
@@ -5068,6 +5380,8 @@
- ciecacode
- clockoff
- clockon
- commited_by
- committed_at
- cost_center
- created_at
- date
@@ -5078,6 +5392,7 @@
- memo
- productivehrs
- rate
- ttapprovalqueueid
- updated_at
filter:
bodyshop:
@@ -5097,6 +5412,8 @@
- ciecacode
- clockoff
- clockon
- commited_by
- committed_at
- cost_center
- created_at
- date
@@ -5107,6 +5424,7 @@
- memo
- productivehrs
- rate
- ttapprovalqueueid
- updated_at
filter:
bodyshop:
@@ -5217,6 +5535,119 @@
authid:
_eq: X-Hasura-User-Id
check: {}
- table:
name: tt_approval_queue
schema: public
object_relationships:
- name: bodyshop
using:
foreign_key_constraint_on: bodyshopid
- name: employee
using:
foreign_key_constraint_on: employeeid
- name: job
using:
foreign_key_constraint_on: jobid
- name: user
using:
foreign_key_constraint_on: approved_by
array_relationships:
- name: timetickets
using:
foreign_key_constraint_on:
column: ttapprovalqueueid
table:
name: timetickets
schema: public
insert_permissions:
- role: user
permission:
check:
bodyshop:
associations:
_and:
- active:
_eq: true
- user:
authid:
_eq: X-Hasura-User-Id
columns:
- actualhrs
- approved_at
- approved_by
- bodyshopid
- ciecacode
- cost_center
- created_at
- date
- employeeid
- flat_rate
- id
- jobid
- memo
- productivehrs
- rate
- updated_at
select_permissions:
- role: user
permission:
columns:
- actualhrs
- approved_at
- approved_by
- bodyshopid
- ciecacode
- cost_center
- created_at
- date
- employeeid
- flat_rate
- id
- jobid
- memo
- productivehrs
- rate
- updated_at
filter:
bodyshop:
associations:
_and:
- active:
_eq: true
- user:
authid:
_eq: X-Hasura-User-Id
allow_aggregations: true
update_permissions:
- role: user
permission:
columns:
- actualhrs
- approved_at
- approved_by
- bodyshopid
- ciecacode
- cost_center
- created_at
- date
- employeeid
- flat_rate
- id
- jobid
- memo
- productivehrs
- rate
- updated_at
filter:
bodyshop:
associations:
_and:
- active:
_eq: true
- user:
authid:
_eq: X-Hasura-User-Id
check: null
- table:
name: users
schema: public
@@ -5287,6 +5718,20 @@
table:
name: parts_orders
schema: public
- name: timetickets
using:
foreign_key_constraint_on:
column: commited_by
table:
name: timetickets
schema: public
- name: tt_approval_queues
using:
foreign_key_constraint_on:
column: approved_by
table:
name: tt_approval_queue
schema: public
insert_permissions:
- role: user
permission:
@@ -5472,6 +5917,30 @@
_eq: X-Hasura-User-Id
- active:
_eq: true
event_triggers:
- name: os_vehicles
definition:
delete:
columns: '*'
enable_manual: false
insert:
columns: '*'
update:
columns: '*'
retry_conf:
interval_sec: 10
num_retries: 3
timeout_sec: 60
webhook_from_env: HASURA_API_URL
headers:
- name: event-secret
value_from_env: EVENT_SECRET
request_transform:
method: POST
query_params: {}
template_engine: Kriti
url: '{{$base_url}}/opensearch'
version: 2
- table:
name: vendors
schema: public

View File

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

View File

@@ -0,0 +1,2 @@
alter table "public"."joblines" add column "act_price_before_ppc" numeric
null;

View File

@@ -0,0 +1 @@
DROP TABLE "public"."employee_teams";

View File

@@ -0,0 +1,18 @@
CREATE TABLE "public"."employee_teams" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "bodyshopid" uuid NOT NULL, "name" text NOT NULL, "active" boolean NOT NULL DEFAULT true, PRIMARY KEY ("id") , FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE cascade ON DELETE cascade);
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_employee_teams_updated_at"
BEFORE UPDATE ON "public"."employee_teams"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_employee_teams_updated_at" ON "public"."employee_teams"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
CREATE EXTENSION IF NOT EXISTS pgcrypto;

View File

@@ -0,0 +1 @@
DROP TABLE "public"."employee_team_members";

View File

@@ -0,0 +1,18 @@
CREATE TABLE "public"."employee_team_members" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "teamid" uuid NOT NULL, "employeeid" uuid NOT NULL, "labor_rates" jsonb NOT NULL DEFAULT jsonb_build_object(), "percentage" numeric NOT NULL DEFAULT 0, PRIMARY KEY ("id") , FOREIGN KEY ("teamid") REFERENCES "public"."employee_teams"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("employeeid") REFERENCES "public"."employees"("id") ON UPDATE cascade ON DELETE cascade);
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_employee_team_members_updated_at"
BEFORE UPDATE ON "public"."employee_team_members"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_employee_team_members_updated_at" ON "public"."employee_team_members"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
CREATE EXTENSION IF NOT EXISTS pgcrypto;

View File

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

View File

@@ -0,0 +1,2 @@
alter table "public"."exportlog" add column "metadata" jsonb
null;

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."bodyshops" add column "tt_enforce_hours_for_tech_console" boolean
-- not null default 'false';

View File

@@ -0,0 +1,2 @@
alter table "public"."bodyshops" add column "tt_enforce_hours_for_tech_console" boolean
not null default 'false';

View File

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

View File

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

View File

@@ -0,0 +1 @@
DROP TABLE "public"."tt_approval_queue";

View File

@@ -0,0 +1,18 @@
CREATE TABLE "public"."tt_approval_queue" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "bodyshopid" uuid NOT NULL, "jobid" uuid NOT NULL, "employeeid" uuid NOT NULL, "timeticketid" uuid, "approved_by" text, "approved_at" timestamptz NOT NULL, "actualhrs" numeric NOT NULL DEFAULT 0, "productivehrs" numeric NOT NULL DEFAULT 0, "rate" numeric NOT NULL DEFAULT 0, "flat_rate" boolean NOT NULL DEFAULT true, "ciecacode" text, "cost_center" text NOT NULL, "date" date NOT NULL DEFAULT now(), "memo" text NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("bodyshopid") REFERENCES "public"."bodyshops"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("jobid") REFERENCES "public"."jobs"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("employeeid") REFERENCES "public"."employees"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("timeticketid") REFERENCES "public"."timetickets"("id") ON UPDATE cascade ON DELETE cascade, FOREIGN KEY ("approved_by") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict);
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_tt_approval_queue_updated_at"
BEFORE UPDATE ON "public"."tt_approval_queue"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_tt_approval_queue_updated_at" ON "public"."tt_approval_queue"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
CREATE EXTENSION IF NOT EXISTS pgcrypto;

View File

@@ -0,0 +1 @@
alter table "public"."tt_approval_queue" alter column "approved_at" set not null;

View File

@@ -0,0 +1 @@
alter table "public"."tt_approval_queue" alter column "approved_at" drop not null;

View File

@@ -0,0 +1 @@
alter table "public"."tt_approval_queue" alter column "memo" set not null;

View File

@@ -0,0 +1 @@
alter table "public"."tt_approval_queue" alter column "memo" drop not null;

View File

@@ -0,0 +1,5 @@
alter table "public"."tt_approval_queue"
add constraint "tt_approval_queue_timeticketid_fkey"
foreign key ("timeticketid")
references "public"."timetickets"
("id") on update cascade on delete cascade;

View File

@@ -0,0 +1 @@
alter table "public"."tt_approval_queue" drop constraint "tt_approval_queue_timeticketid_fkey";

View File

@@ -0,0 +1,2 @@
alter table "public"."tt_approval_queue" alter column "timeticketid" drop not null;
alter table "public"."tt_approval_queue" add column "timeticketid" uuid;

View File

@@ -0,0 +1 @@
alter table "public"."tt_approval_queue" drop column "timeticketid" cascade;

View File

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

View File

@@ -0,0 +1,2 @@
alter table "public"."timetickets" add column "ttapprovalqueueid" uuid
null;

View File

@@ -0,0 +1 @@
alter table "public"."timetickets" drop constraint "timetickets_ttapprovalqueueid_fkey";

View File

@@ -0,0 +1,5 @@
alter table "public"."timetickets"
add constraint "timetickets_ttapprovalqueueid_fkey"
foreign key ("ttapprovalqueueid")
references "public"."tt_approval_queue"
("id") on update cascade on delete set null;

View File

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

View File

@@ -0,0 +1,2 @@
alter table "public"."timetickets" add column "commited_by" text
null;

View File

@@ -0,0 +1 @@
alter table "public"."timetickets" drop constraint "timetickets_commited_by_fkey";

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