Compare commits

...

169 Commits

Author SHA1 Message Date
Patrick Fic
09f909142b Resolve sped print error. 2022-03-25 07:21:54 -06:00
Patrick Fic
fb380a5b31 IO-1799 Mark md_from_email 2022-03-24 15:40:25 -06:00
Patrick Fic
3896a0b03d IO-1799 Change from address for emails. 2022-03-24 14:54:36 -06:00
Patrick Fic
832674662d Autohouse add PVRT to salestax per request. 2022-03-24 11:55:48 -06:00
Patrick Fic
f2b2011900 Ignore custom margins on certain templates. 2022-03-22 13:41:06 -06:00
Patrick Fic
15c305317a Update header and footer margins. 2022-03-22 11:11:47 -06:00
Patrick Fic
d6924c2292 Add JSR margins to speed print. 2022-03-21 11:52:44 -06:00
Patrick Fic
7ccd356f0a Add margin to templates generation. 2022-03-21 10:51:44 -07:00
Patrick Fic
592b47b5d4 IO-1789 Incoming hours cap 2022-03-21 11:47:25 -06:00
Patrick Fic
d9beee7f2f Merged in release/2022-03-18 (pull request #427)
IO-1777 add check for paint materials threshold.
2022-03-18 22:19:43 +00:00
Patrick Fic
75743f44e7 IO-1777 add check for paint materials threshold. 2022-03-18 15:18:48 -07:00
Patrick Fic
3d68a7099b Merged in release/2022-03-18 (pull request #426)
Release/2022 03 18
2022-03-18 21:46:33 +00:00
Patrick Fic
71f161ec27 IO-1774 Remove scheduled completion date on void. 2022-03-17 15:47:40 -07:00
Patrick Fic
9b1f24926f Merged in hotfix/2022-03-16 (pull request #424)
Autohouse updates.
2022-03-16 23:42:16 +00:00
Patrick Fic
bcc153caa5 Autohouse updates. 2022-03-16 16:39:42 -07:00
Patrick Fic
f59911d5ab Autohouse Adjustment 2022-03-16 16:38:41 -07:00
Patrick Fic
417958e1e8 Additional Autohouse Updates. 2022-03-16 15:50:03 -07:00
Patrick Fic
ccf2f0ad47 IO-1780 Print off 1 job note. 2022-03-16 14:01:05 -07:00
Patrick Fic
bb993ab1fb IO-1783 Add production filtered by status. 2022-03-16 14:00:04 -07:00
Patrick Fic
9c39c8d59b Add header and footer margins. 2022-03-16 13:53:30 -07:00
Patrick Fic
3439f09d9a IO-1693 Allow 0 line supplements. 2022-03-16 11:47:32 -07:00
Patrick Fic
279e93f0c3 IO-1774 Cancel appointments when voiding. 2022-03-14 13:46:18 -07:00
Patrick Fic
92f14d6fa5 IO-1750 Add towin and rent resp date fields. 2022-03-14 13:25:13 -07:00
Patrick Fic
148c645f18 IO-177 Paint/Mat Thresholds 2022-03-14 10:41:52 -07:00
Patrick Fic
9a65b6a1ce Merged in release/2022-03-11 (pull request #420)
Release/2022 03 11
2022-03-11 18:47:44 +00:00
Patrick Fic
839c82abb9 IO-1776 Mechanical authorization added to print center. 2022-03-11 08:11:44 -08:00
Patrick Fic
471756d7ad IO-1769 Resolve error on part selection. 2022-03-10 11:00:13 -08:00
Patrick Fic
2e2a4920ca IO-1772 Add label for no vehicle info. 2022-03-10 10:55:44 -08:00
Patrick Fic
f775e09391 Merged in hotfix/2022-03-09 (pull request #417)
Remove autohouse log file creation.
2022-03-09 17:23:57 +00:00
Patrick Fic
c0b0bcd55e Merged in hotfix/2022-03-09 (pull request #416)
Remove autohouse log file creation.
2022-03-09 16:42:11 +00:00
Patrick Fic
1bc5493f3f Remove autohouse log file creation. 2022-03-09 08:41:36 -08:00
Patrick Fic
2579558090 IO-1606 IO-1607 IO-1752 Move towing rates. 2022-03-08 14:47:01 -08:00
Patrick Fic
bc9a3a21a8 Merged in release/2022-03-11 (pull request #415)
Remove special characters from Autohouse export.

Approved-by: Patrick Fic
2022-03-07 22:48:22 +00:00
Patrick Fic
f11eb6406d Remove special characters from Autohouse export. 2022-03-07 14:44:48 -08:00
Patrick Fic
3d6bad9e7d Merged in release/2022-03-04 (pull request #413)
release/2022-03-04

Approved-by: Patrick Fic
2022-03-04 18:15:38 +00:00
Patrick Fic
12a5f17351 Add create user. 2022-03-04 10:11:18 -08:00
Patrick Fic
a2032553d9 IO-1746 Smart Scheduling Dates to 10. 2022-03-03 12:39:18 -08:00
Patrick Fic
d22979dadc IO-1748 Remove show phone on vendor search select in report cente.r 2022-03-03 08:52:25 -08:00
Patrick Fic
c1068ec92b IO-1728 Set cc create form to be vertical. 2022-03-03 08:37:21 -08:00
Patrick Fic
a318f3e74b Merged in hotfix/2022-03-01 (pull request #410)
IO-1759 Replace offset with timezone.
2022-03-03 01:25:12 +00:00
Patrick Fic
e5a5cb4e85 IO-1759 Replace offset with timezone.
(cherry picked from commit 548d9255638839841e7ad7cbb24888c59dd398d3)
2022-03-02 17:23:10 -08:00
Patrick Fic
f8151e387e Resolve missing fields from time tickets query. 2022-03-02 16:04:49 -08:00
Patrick Fic
b98bfe566a IO-1760 2022-03-02 15:26:18 -08:00
Patrick Fic
c0220f0ca2 IO-1756 Include documents when sending job notes. 2022-03-02 14:36:19 -08:00
Patrick Fic
3e121a1a25 IO-1759 Replace offset with timezone. 2022-03-02 12:56:29 -08:00
Patrick Fic
a2a8868223 IO-1748 Add vendor # to parts order modal. 2022-03-02 11:18:10 -08:00
Patrick Fic
80d16b4651 IO-1747 Add CSR to Visual Board. 2022-03-02 10:54:10 -08:00
Patrick Fic
ce3fbab1dc Merged in hotfix/2022-03-01 (pull request #407)
Autohouse Extract Updates & Remove duedate on payables.

Approved-by: Patrick Fic
2022-03-02 02:24:43 +00:00
Patrick Fic
4c1a333514 Autohouse Extract Updates & Remove duedate on payables. 2022-03-01 18:23:52 -08:00
Patrick Fic
0660b79c01 Autohouse Extract Updates & Remove duedate on payables. 2022-03-01 17:27:04 -08:00
Patrick Fic
63ec578b6a IO-1749 Inactive employees removed from drop downs. 2022-03-01 15:17:33 -08:00
Patrick Fic
dcf388ff7c IO-1745 Resolve scheduling showing incorrect days. 2022-03-01 14:53:42 -08:00
Patrick Fic
0cd1b41ed9 IO-1728 Remove unsaved changes popup when creating CC 2022-03-01 13:24:07 -08:00
Patrick Fic
79124daa9a IO-1719 Add invoice number to job line 2022-03-01 13:14:03 -08:00
Patrick Fic
76ec55d709 Merged in release/2022-02-18 (pull request #405)
Updated task scheduler.

Approved-by: Patrick Fic
2022-02-18 20:59:57 +00:00
Patrick Fic
375b8ba050 Updated task scheduler. 2022-02-18 09:42:42 -08:00
Patrick Fic
2192cb1e7c IO-1744 Added missing totals to job costing modal. 2022-02-17 17:14:37 -08:00
Patrick Fic
65b505035a IO-1706 Resolve print center issue. 2022-02-17 17:08:25 -08:00
Patrick Fic
191f3f96a2 IO-1744 Resolve missing sublet calcuations. 2022-02-17 17:06:02 -08:00
Patrick Fic
14d873f795 IO-1742 Remove flat rate slider on time ticket entry. 2022-02-17 16:23:51 -08:00
Patrick Fic
55ad75df8a IO-1744 Break out sublet on job costing 2022-02-17 16:17:45 -08:00
Patrick Fic
5f112e797d CI Fix. 2022-02-16 17:11:55 -08:00
Patrick Fic
b842cee076 IO-1738 PVRT Update 2022-02-16 16:45:49 -08:00
Patrick Fic
2c1c11828d IO-1740 Scoreboard to 1 decimal. 2022-02-16 15:27:13 -08:00
Patrick Fic
e7c380d780 Standardize production minute picker. 2022-02-16 15:20:56 -08:00
Patrick Fic
0958ea5ba6 IO-1706 Payroll Table 2022-02-16 14:22:39 -08:00
Patrick Fic
8031f2b2ed Merge branch 'hotfix/2022-02-14' into release/2022-02-18 2022-02-15 16:03:39 -08:00
Patrick Fic
996863fcb7 Potential resolution to date time issues post 4pm. 2022-02-15 16:03:20 -08:00
Patrick Fic
066f395a40 IO-1738 Remove PVRT from subtotal. 2022-02-15 13:41:35 -08:00
Patrick Fic
51c5d163a5 Merged in hotfix/2022-02-14 (pull request #395)
Job costing additional fix.
2022-02-15 20:17:19 +00:00
Patrick Fic
d8ec6dd997 Merge branch 'hotfix/2022-02-14' into release/2022-02-18 2022-02-15 12:16:34 -08:00
Patrick Fic
cc636bdfe2 Job costing additional fix. 2022-02-15 12:16:08 -08:00
Patrick Fic
a3e8f56728 Resolve Date Picker Issues. 2022-02-15 09:30:17 -08:00
Patrick Fic
a6f2cfba0f Merged in hotfix/2022-02-14 (pull request #393)
Revert "Potential resolution to date time issues post 4pm."
2022-02-15 17:13:36 +00:00
Patrick Fic
2e7d8df781 Revert "Potential resolution to date time issues post 4pm."
This reverts commit e79b9f9084.
2022-02-15 09:13:10 -08:00
Patrick Fic
da51aeb135 Merged in hotfix/2022-02-14 (pull request #392)
Potential resolution to date time issues post 4pm.
2022-02-15 16:27:59 +00:00
Patrick Fic
680dd98f6d Merge branch 'hotfix/2022-02-14' into release/2022-02-18 2022-02-14 19:33:13 -08:00
Patrick Fic
e79b9f9084 Potential resolution to date time issues post 4pm. 2022-02-14 19:31:26 -08:00
Patrick Fic
22e6d596e6 Merge branch 'hotfix/2022-02-14' into release/2022-02-18 2022-02-14 13:14:12 -08:00
Patrick Fic
1ba904d082 Merged in hotfix/2022-02-14 (pull request #389)
Resolve bill update error.
2022-02-14 21:13:48 +00:00
Patrick Fic
62be2b0a0a Resolve bill update error. 2022-02-14 13:11:14 -08:00
Patrick Fic
dc77930950 Resolve bill update error. 2022-02-14 13:02:54 -08:00
Patrick Fic
520b61706f Merged in release/2022-02-18 (pull request #386)
Release/2022 02 18
2022-02-14 19:03:49 +00:00
Patrick Fic
09a87dd2a7 IO-1724 Update cancel appointment label. 2022-02-14 10:43:11 -08:00
Patrick Fic
f884d2e23f IO-1721 Update time ticket time fields to be in 5 minute increments. 2022-02-14 10:41:09 -08:00
Patrick Fic
b84935efdc IO-1707 Add employee filtering to time ticket list. 2022-02-14 10:38:58 -08:00
Patrick Fic
b3aeee4f45 IO-1667 Add print center to production detail drawer. 2022-02-14 10:33:21 -08:00
Patrick Fic
06f266a292 IO-1700 Add name to cc list. 2022-02-14 10:27:41 -08:00
Patrick Fic
a2d54d5dd5 Merged in release/2022-02-11 (pull request #385)
Release/2022 02 11
2022-02-11 23:06:48 +00:00
Patrick Fic
b34694f3c4 Merged in release/2022-02-11 (pull request #384)
Add PBS Error message.
2022-02-11 23:03:19 +00:00
Patrick Fic
43b8842027 Add PBS Error message. 2022-02-11 14:45:28 -08:00
Patrick Fic
0dbb3a446a Merged in release/2022-02-11 (pull request #383)
IO-1708 Revert timezone change in app
2022-02-11 16:28:12 +00:00
Patrick Fic
75b2398421 IO-1708 Revert timezone change in app 2022-02-11 08:24:34 -08:00
Patrick Fic
2409042450 Merged in release/2022-02-11 (pull request #382)
Release/2022 02 11
2022-02-11 01:52:23 +00:00
Patrick Fic
85ccb36b2e IO-1708 Revert time zone app side changes. 2022-02-10 17:51:55 -08:00
Patrick Fic
a616921e2b IO-1708 Remove setting application side time zone. 2022-02-10 17:50:46 -08:00
Patrick Fic
f509ea07c0 Merged in release/2022-02-11 (pull request #381)
IO-1723 Add Additional GP to summary for multi costing.
2022-02-11 01:01:59 +00:00
Patrick Fic
efb62b59f4 IO-1723 Add Additional GP to summary for multi costing. 2022-02-10 17:00:59 -08:00
Patrick Fic
e263c32d83 Merged in release/2022-02-11 (pull request #380)
Release/2022 02 11
2022-02-11 00:31:18 +00:00
Patrick Fic
30afe97fba IO-1685 Task Scheduler. 2022-02-10 16:30:49 -08:00
Patrick Fic
e383b0800c IO-1723 Add GPs for additional items on costing. 2022-02-10 16:30:04 -08:00
Patrick Fic
e0507f2d17 IO-1723 Add GPs for additional items on costing. 2022-02-10 16:29:45 -08:00
Patrick Fic
cdd3841d49 IO-1708 Updated timezone for date fields. 2022-02-10 16:21:10 -08:00
Patrick Fic
4a023faf67 Merged in release/2022-02-11 (pull request #379)
IO-1718 Only allow type change based on split for part order.
2022-02-10 23:15:13 +00:00
Patrick Fic
e9f4b48839 IO-1718 Only allow type change based on split for part order. 2022-02-10 15:14:25 -08:00
Patrick Fic
90f0232ff0 Merged in release/2022-02-11 (pull request #378)
Release/2022 02 11
2022-02-10 22:49:49 +00:00
Patrick Fic
b94ea099b9 Smart Scheduling Updates. 2022-02-10 14:49:19 -08:00
Patrick Fic
9f5b1c4ea5 Resolve in house bill posting. 2022-02-10 14:21:56 -08:00
Patrick Fic
4842605035 Autohouse year parsing upddate. 2022-02-10 11:01:23 -08:00
Patrick Fic
f9f14255a8 AH Updates. 2022-02-10 10:48:31 -08:00
Patrick Fic
139dedd3e7 Add upload logging. 2022-02-10 08:35:49 -08:00
Patrick Fic
bd9c2cd0af IO-1727 Skip posting contact and vehicle for PBS.. 2022-02-09 16:46:32 -08:00
Patrick Fic
e0e2183d86 Merged in release/2022-02-11 (pull request #377)
Release/2022 02 11
2022-02-10 00:30:28 +00:00
Patrick Fic
f8695972a3 IO-1708 Remove timezone from date fields on server calcuations. 2022-02-09 16:29:16 -08:00
Patrick Fic
4c70351429 Remove OEC from return modal. 2022-02-09 16:00:07 -08:00
Patrick Fic
bc504d2a78 Merged in release/2022-02-11 (pull request #376)
Release/2022 02 11
2022-02-09 23:52:27 +00:00
Patrick Fic
22dfcc215e IO-1718 Add part type to OEC. 2022-02-09 15:51:19 -08:00
Patrick Fic
415d6cca29 IO-1723 Job Costing Additional Items 2022-02-09 15:06:00 -08:00
Patrick Fic
6c0bf67f37 IO-1723 Updated job costing. 2022-02-09 14:55:16 -08:00
Patrick Fic
351459681c IO-1637 Tax rates randomly not pulling. 2022-02-09 10:55:12 -08:00
Patrick Fic
e7e9ca6dfc Schema Updates. 2022-02-09 10:35:15 -08:00
Patrick Fic
39998a279e Autohouse Fixes. 2022-02-09 10:34:52 -08:00
Patrick Fic
7c66e5cb90 Merged in release/2022-02-11 (pull request #375)
Release/2022 02 11
2022-02-09 17:46:15 +00:00
Patrick Fic
b4e0dcc395 IO-1699 Add additional scoreboard total details. 2022-02-08 13:08:50 -08:00
Patrick Fic
c16a2a83a5 IO-1679 Add returns to reconciliation calculation. 2022-02-08 13:08:31 -08:00
Patrick Fic
a2dca6c1a1 IO-1720 Add bill mark as exported. 2022-02-08 11:11:56 -08:00
Patrick Fic
ffb39bbee7 IO-1687 Add payable due date. 2022-02-08 11:07:31 -08:00
Patrick Fic
46731975e6 Merge branch 'hotfix/2022-02-08' into release/2022-02-11 2022-02-08 10:50:33 -08:00
Patrick Fic
06f725ebb1 Merged in hotfix/2022-02-08 (pull request #374)
Resolve monthly employee efficiency for infinity.
2022-02-08 18:05:04 +00:00
Patrick Fic
8745ffd08f Merged in hotfix/2022-02-08 (pull request #373)
Resolve monthly employee efficiency for infinity.
2022-02-08 18:04:24 +00:00
Patrick Fic
634adb6e9a Resolve monthly employee efficiency for infinity. 2022-02-08 09:47:58 -08:00
Patrick Fic
b5386be6af Merged in hotfix/2022-02-08 (pull request #372)
Hotfix/2022 02 08
2022-02-08 17:25:38 +00:00
Patrick Fic
14e9ac2cdb IO-1714 Resolve monthly efficiency component. 2022-02-08 09:08:16 -08:00
Patrick Fic
76fb8f453d Updated projected monthly sales. 2022-02-08 09:08:09 -08:00
Patrick Fic
afc674d74c IO-1676 Add RO Comment. 2022-02-07 19:31:08 -08:00
Patrick Fic
8c67a94387 IO-1714 Resolve monthly efficiency component. 2022-02-07 18:50:18 -08:00
Patrick Fic
a17b2b0923 Updated projected monthly sales. 2022-02-07 18:31:06 -08:00
Patrick Fic
91c5560fe8 IO-1708 Add shop timezone & update server side calculations. 2022-02-07 17:43:34 -08:00
Patrick Fic
356928ce77 Resolve double partner notification. 2022-02-07 15:04:07 -08:00
Patrick Fic
eb05a746c4 Resolve dashboard/reporting discrepancy. 2022-02-07 10:38:05 -08:00
Patrick Fic
07b5c5e93c Merged in release/2022-02-04 (pull request #368)
Update QBO Export.
2022-02-07 16:55:08 +00:00
Patrick Fic
7ef8ef5f2f Update QBO Export. 2022-02-07 08:46:27 -08:00
Patrick Fic
dcb9c32336 Merged in release/2022-02-04 (pull request #366)
Release/2022 02 04
2022-02-05 01:35:28 +00:00
Patrick Fic
f41277c081 Remove unnecessary logging. 2022-02-04 09:44:31 -08:00
Patrick Fic
7f15e9ef7a IO-1695 Add validation to time ticket window for clock times. 2022-02-04 09:29:37 -08:00
Patrick Fic
6d3fc783d6 IO-1697 Dont display partner message unless QBD. 2022-02-04 09:18:31 -08:00
Patrick Fic
0052a54915 IO-1662 removed scheduled completion on event cancel. 2022-02-03 12:20:45 -08:00
Patrick Fic
375856bd68 Remove customer name from QBO payables. 2022-02-03 12:15:33 -08:00
Patrick Fic
cf4f6f6e55 QBO Resolve classes issues. 2022-02-03 12:07:20 -08:00
Patrick Fic
173e9a278c QBO Updates. 2022-02-03 11:15:23 -08:00
Patrick Fic
35ab86c5fd Missed QBO receivables change. 2022-02-02 14:16:01 -08:00
Patrick Fic
932c89f8f9 Resolve QBO Receivables incorrectly labels. 2022-02-02 14:10:11 -08:00
Patrick Fic
ddd5ce4bf0 IO-1702 OEC Price. 2022-02-02 10:52:23 -08:00
Patrick Fic
1d0e526466 Autohouse query updates. 2022-02-02 09:50:47 -08:00
Patrick Fic
73e2b2d65d IO-1697 Remove acct path popup if not qbd. 2022-02-02 08:47:32 -08:00
Patrick Fic
88bc8d4d05 IO-1695 Edit time stamp when creating time ticket. 2022-02-01 15:09:20 -08:00
Patrick Fic
53cecd68f0 IO-1678 Add actual hours deducted from labor on bill posting. 2022-02-01 14:52:59 -08:00
Patrick Fic
4bce6d996e Create additional indexes for system performance. 2022-02-01 14:36:48 -08:00
Patrick Fic
6a59092d6a Merged in release/2022-01-28 (pull request #362)
release/2022-01-28

Approved-by: Patrick Fic
2022-01-28 01:51:05 +00:00
Patrick Fic
83b51384c7 Merged in release/2022-01-28 (pull request #361)
release/2022-01-28

Approved-by: Patrick Fic
2022-01-27 23:20:06 +00:00
Patrick Fic
09a0309108 Merged in release/2022-01-28 (pull request #360)
release/2022-01-28

Approved-by: Patrick Fic
2022-01-27 22:35:43 +00:00
Patrick Fic
b19120af3d Merged in release/2022-01-28 (pull request #359)
release/2022-01-28
2022-01-27 19:11:54 +00:00
Patrick Fic
9d770a4cd5 Merged in release/2022-01-28 (pull request #358)
release/2022-01-28

Approved-by: Patrick Fic
2022-01-24 23:57:37 +00:00
Patrick Fic
f71a4b7c83 Merged in release/2022-01-28 (pull request #357)
release/2022-01-28

Approved-by: Patrick Fic
2022-01-24 21:44:40 +00:00
Patrick Fic
a20e005583 Merged in release/2022-01-21 (pull request #356)
PBS Improvements.
2022-01-21 22:55:52 +00:00
Patrick Fic
b81d3369af Merged in release/2022-01-21 (pull request #355)
Release/2022 01 21
2022-01-21 22:21:45 +00:00
Patrick Fic
9ab08fbdd0 Merged in release/2022-01-14 (pull request #349)
release/2022-01-14

Approved-by: Patrick Fic
2022-01-14 22:41:23 +00:00
Patrick Fic
1a53e7c2f7 Merged in release/2022-01-14 (pull request #346)
Release/2022 01 14
2022-01-12 16:53:58 +00:00
Patrick Fic
36a7b8346e Merged in release/2022-01-14 (pull request #344)
Release/2022 01 14
2022-01-11 20:44:01 +00:00
162 changed files with 8328 additions and 462 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project version="1.2" be_version="2.7.1">
<babeledit_project be_version="2.7.1" version="1.2">
<!--
BabelEdit project file
@@ -2863,6 +2863,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>markexported</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>markforreexport</name>
<definition_loaded>false</definition_loaded>
@@ -3120,6 +3141,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>markexported</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>reexport</name>
<definition_loaded>false</definition_loaded>
@@ -3830,6 +3872,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>disablecontactvehiclecreation</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>dms_acctnumber</name>
<definition_loaded>false</definition_loaded>
@@ -4325,6 +4388,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>logo_img_footer_margin</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>logo_img_header_margin</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>logo_img_path</name>
<definition_loaded>false</definition_loaded>
@@ -4493,6 +4598,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>md_from_emails</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<folder_node>
<name>md_hour_split</name>
<children>
@@ -7175,6 +7301,32 @@
</concept_node>
</children>
</folder_node>
<folder_node>
<name>ss_configuration</name>
<children>
<concept_node>
<name>dailyhrslimit</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>ssbuckets</name>
<children>
@@ -7794,6 +7946,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>timezone</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>tt_allow_post_to_invoiced</name>
<definition_loaded>false</definition_loaded>
@@ -13079,6 +13252,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>from</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>subject</name>
<definition_loaded>false</definition_loaded>
@@ -20329,6 +20523,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>comment</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>customerowing</name>
<definition_loaded>false</definition_loaded>
@@ -20476,6 +20691,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>date_rentalresp</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>date_scheduled</name>
<definition_loaded>false</definition_loaded>
@@ -20497,6 +20733,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>date_towin</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>ded_amt</name>
<definition_loaded>false</definition_loaded>
@@ -25036,6 +25293,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>cost_Additional</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>cost_labor</name>
<definition_loaded>false</definition_loaded>
@@ -25078,6 +25356,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>cost_sublet</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>costs</name>
<definition_loaded>false</definition_loaded>
@@ -26930,6 +27229,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>sale_additional</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>sale_labor</name>
<definition_loaded>false</definition_loaded>
@@ -26972,6 +27292,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>sale_sublet</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>sales</name>
<definition_loaded>false</definition_loaded>
@@ -27182,6 +27523,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>threshhold</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_cost</name>
<definition_loaded>false</definition_loaded>
@@ -32001,6 +32363,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>part_type</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>quantity</name>
<definition_loaded>false</definition_loaded>
@@ -34542,6 +34925,27 @@
</concept_node>
</children>
</folder_node>
<concept_node>
<name>mechanical_authorization</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>mpi_animal_checklist</name>
<definition_loaded>false</definition_loaded>
@@ -35523,6 +35927,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>exported_payroll</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@@ -36104,6 +36529,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>comment</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>compact</name>
<definition_loaded>false</definition_loaded>
@@ -38175,6 +38621,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>production_by_repair_status_one</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>production_by_ro</name>
<definition_loaded>false</definition_loaded>
@@ -38903,6 +39370,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>dailyactual</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>dailytarget</name>
<definition_loaded>false</definition_loaded>
@@ -38966,6 +39454,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>todateactual</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>weeklyactual</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>weeklytarget</name>
<definition_loaded>false</definition_loaded>
@@ -40261,6 +40791,53 @@
</concept_node>
</children>
</folder_node>
<folder_node>
<name>validation</name>
<children>
<concept_node>
<name>clockoffmustbeafterclockon</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>clockoffwithoutclockon</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
</children>
</folder_node>
<folder_node>
@@ -42991,6 +43568,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>novehinfo</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>relatedjobs</name>
<definition_loaded>false</definition_loaded>

View File

@@ -33,6 +33,7 @@
"logrocket": "^2.1.2",
"markerjs2": "^2.17.2",
"moment-business-days": "^1.2.0",
"moment-timezone": "^0.5.34",
"phone": "^3.1.10",
"preval.macro": "^5.0.0",
"prop-types": "^15.7.2",

View File

@@ -28,6 +28,7 @@ import { createStructuredSelector } from "reselect";
import { setModalContext } from "../../redux/modals/modals.actions";
import { insertAuditTrail } from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
import BillMarkExportedButton from "../bill-mark-exported-button/bill-mark-exported-button.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -107,7 +108,7 @@ export function BillDetailEditcontainer({
);
billlines.forEach((billline) => {
const { deductedfromlbr, ...il } = billline;
const { deductedfromlbr, jobline, ...il } = billline;
delete il.__typename;
if (il.id) {
@@ -206,6 +207,8 @@ export function BillDetailEditcontainer({
cost: i.actual_cost,
quantity: i.quantity,
joblineid: i.joblineid,
oem_partno: i.jobline && i.jobline.oem_partno,
part_type: i.jobline && i.jobline.part_type,
};
}),
isReturn: true,
@@ -234,6 +237,7 @@ export function BillDetailEditcontainer({
</Button>
</Popconfirm>
<BillReeportButtonComponent bill={data && data.bills_by_pk} />
<BillMarkExportedButton bill={data && data.bills_by_pk} />
</Space>
}
/>

View File

@@ -93,6 +93,7 @@ function BillEnterModalContainer({
deductedfromlbr,
lbr_adjustment,
location: lineLocation,
part_type,
...restI
} = i;
@@ -216,7 +217,11 @@ function BillEnterModalContainer({
if (enterAgain) {
form.resetFields();
form.setFieldsValue({ ...form.getFieldsValue(), billlines: [] });
form.resetFields();
form.setFieldsValue({
...formValues,
billlines: [],
});
} else {
toggleModalVisible();
}

View File

@@ -8,7 +8,7 @@ import {
Space,
Switch,
Table,
Tooltip,
Tooltip
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -334,6 +334,19 @@ export function BillEnterModalLinesComponent({
additional: (record, index) => (
<Form.Item shouldUpdate style={{ display: "inline-block" }}>
{() => {
const price = getFieldValue([
"billlines",
record.name,
"actual_price",
]);
const adjustmentRate = getFieldValue([
"billlines",
record.name,
"lbr_adjustment",
"rate",
]);
if (getFieldValue(["billlines", record.name, "deductedfromlbr"]))
return (
<div>
@@ -406,6 +419,9 @@ export function BillEnterModalLinesComponent({
>
<InputNumber precision={2} min={0.01} />
</Form.Item>
{price &&
adjustmentRate &&
`${(price / adjustmentRate).toFixed(1)} hrs`}
</div>
);
return <></>;

View File

@@ -0,0 +1,82 @@
import { useMutation } from "@apollo/client";
import { Button, notification } from "antd";
import { gql } from "@apollo/client";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
selectAuthLevel,
selectBodyshop,
} from "../../redux/user/user.selectors";
import { HasRbacAccess } from "../rbac-wrapper/rbac-wrapper.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
authLevel: selectAuthLevel,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(BillMarkExportedButton);
export function BillMarkExportedButton({ bodyshop, authLevel, bill }) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [updateBill] = useMutation(gql`
mutation UPDATE_BILL($billId: uuid!) {
update_bills(where: { id: { _eq: $billId } }, _set: { exported: true }) {
returning {
id
exported
exported_at
}
}
}
`);
const handleUpdate = async () => {
setLoading(true);
const result = await updateBill({
variables: { billId: bill.id },
});
if (!result.errors) {
notification["success"]({
message: t("bills.successes.markexported"),
});
} else {
notification["error"]({
message: t("bills.errors.saving", {
error: JSON.stringify(result.errors),
}),
});
}
setLoading(false);
//Get the owner details, populate it all back into the job.
};
const hasAccess = HasRbacAccess({
bodyshop,
authLevel,
action: "bills:reexport",
});
if (hasAccess)
return (
<Button
loading={loading}
disabled={bill.exported}
onClick={handleUpdate}
>
{t("bills.labels.markexported")}
</Button>
);
return <></>;
}

View File

@@ -76,6 +76,7 @@ export function BillsListTableComponent({
quantity: i.quantity,
joblineid: i.joblineid,
oem_partno: i.jobline && i.jobline.oem_partno,
part_type: i.jobline && i.jobline.part_type,
};
}),
isReturn: true,

View File

@@ -9,7 +9,7 @@ import { DateFormatter } from "../../utils/DateFormatter";
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component";
import FormDatePicker from "../form-date-picker/form-date-picker.component";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
//import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
@@ -32,7 +32,7 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
}
/>
<FormFieldsChanged form={form} />
{/* <FormFieldsChanged form={form} /> */}
<LayoutFormRow header={t("courtesycars.labels.vehicle")}>
<Form.Item
label={t("courtesycars.fields.make")}

View File

@@ -97,7 +97,9 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
render: (text, record) =>
record.cccontracts.length === 1 ? (
<Link to={`/manage/jobs/${record.cccontracts[0].job.id}`}>
{record.cccontracts[0].job.ro_number}
{`${record.cccontracts[0].job.ro_number} - ${
record.cccontracts[0].job.ownr_fn || ""
} ${record.cccontracts[0].job.ownr_ln || ""} ${record.cccontracts[0].job.ownr_co_nm || ""}`}
</Link>
) : null,
},

View File

@@ -40,7 +40,7 @@ export default function DashboardMonthlyEmployeeEfficiency({
(dayAcc, dayVal) => {
return {
actual: dayAcc.actual + dayVal.actualhrs,
productive: dayAcc.actual + dayVal.productivehrs,
productive: dayAcc.productive + dayVal.productivehrs,
};
},
{ actual: 0, productive: 0 }
@@ -50,11 +50,13 @@ export default function DashboardMonthlyEmployeeEfficiency({
}
const dailyEfficiency =
((dailyHrs.productive - dailyHrs.actual) / dailyHrs.productive + 1) * 100;
((dailyHrs.productive - dailyHrs.actual) / dailyHrs.actual + 1) * 100;
const theValue = {
date: moment(val).format("DD"),
...dailyHrs,
// ...dailyHrs,
actual: dailyHrs.actual.toFixed(1),
productive: dailyHrs.productive.toFixed(1),
dailyEfficiency: isNaN(dailyEfficiency) ? 0 : dailyEfficiency.toFixed(1),
accActual:
acc.length > 0
@@ -67,12 +69,18 @@ export default function DashboardMonthlyEmployeeEfficiency({
: dailyHrs.productive,
accEfficiency: 0,
};
theValue.accEfficiency = (
theValue.accEfficiency =
((theValue.accProductive - theValue.accActual) /
(theValue.accProductive || 1) +
(theValue.accActual || 0) +
1) *
100
).toFixed(1);
100;
if (isNaN(theValue.accEfficiency)) {
theValue.accEfficiency = 0;
} else {
theValue.accEfficiency = theValue.accEfficiency.toFixed(1);
}
return [...acc, theValue];
}, []);
@@ -131,6 +139,7 @@ export default function DashboardMonthlyEmployeeEfficiency({
//stackId="day"
barSize={20}
fill="#102568"
format={"0.0"}
/>
<Bar
name="Productive Hours"
@@ -140,6 +149,7 @@ export default function DashboardMonthlyEmployeeEfficiency({
//stackId="day"
barSize={20}
fill="#017664"
format={"0.0"}
/>
</ComposedChart>
</ResponsiveContainer>

View File

@@ -31,16 +31,51 @@ export default function DashboardProjectedMonthlySales({ data, ...cardProps }) {
}
export const DashboardProjectedMonthlySalesGql = `
projected_monthly_sales: jobs(where: {_or: [{_and: [{date_invoiced: {_gte: "${moment()
projected_monthly_sales: jobs(where: {
voided: {_eq: false},
_or: [
{_and: [
{date_invoiced:{_is_null: false }},
{date_invoiced: {_gte: "${moment()
.startOf("month")
.startOf("day")
.toISOString()}"}}, {date_invoiced: {_lte: "${moment()
.endOf("month")
.endOf("day")
.toISOString()}"}}]},
{
_and:[
{date_invoiced:{_is_null: true }},
{actual_completion: {_gte: "${moment()
.startOf("month")
.startOf("day")
.toISOString()}"}}, {actual_completion: {_lte: "${moment()
.endOf("month")
.endOf("day")
.toISOString()}"}}
]
},
{_and: [
{date_invoiced: {_is_null: true}},
{actual_completion: {_is_null: true}}
{scheduled_completion: {_gte: "${moment()
.startOf("month")
.format("YYYY-MM-DD")}"}}, {date_invoiced: {_lte: "${moment()
.startOf("day")
.toISOString()}"}}, {scheduled_completion: {_lte: "${moment()
.endOf("month")
.format("YYYY-MM-DD")}"}}]}, {_and: [{scheduled_completion: {_gte: "${moment()
.startOf("month")
.format("YYYY-MM-DD")}"}}, {scheduled_completion: {_lte: "${moment()
.endOf("month")
.format("YYYY-MM-DD")}"}}]}]}) {
.endOf("day")
.toISOString()}"}}
]}
]}) {
id
ro_number
voided
date_invoiced
job_totals
}

View File

@@ -280,12 +280,13 @@ const createDashboardQuery = (state) => {
return gql`
query QUERY_DASHBOARD_DETAILS {
${componentBasedAdditions || ""}
monthly_sales: jobs(where: {_and: [{date_invoiced: {_gte: "${moment()
.startOf("month")
.format("YYYY-MM-DD")}"}}, {date_invoiced: {_lte: "${moment()
.endOf("month")
.format("YYYY-MM-DD")}"}}]}) {
monthly_sales: jobs(where: {_and: [
{ voided: {_eq: false}},
{date_invoiced: {_gte: "${moment()
.startOf("month").startOf('day').toISOString()}"}}, {date_invoiced: {_lte: "${moment()
.endOf("month").endOf('day').toISOString()}"}}]}) {
id
ro_number
date_invoiced
job_totals
rate_la1
@@ -333,14 +334,14 @@ const createDashboardQuery = (state) => {
part_qty
part_type
}
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" } }) {
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }) {
aggregate {
sum {
mod_lb_hrs
}
}
}
larhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAR" } }) {
larhrs: joblines_aggregate(where: { mod_lbr_ty: { _eq: "LAR" }, removed: { _eq: false } }) {
aggregate {
sum {
mod_lb_hrs

View File

@@ -6,6 +6,7 @@ import { INSERT_NEW_DOCUMENT } from "../../graphql/documents.queries";
import { axiosAuthInterceptorId } from "../../utils/CleanAxios";
import client from "../../utils/GraphQLClient";
import exifr from "exifr";
import { store } from "../../redux/store";
//Context: currentUserEmail, bodyshop, jobid, invoiceid
@@ -112,7 +113,19 @@ export const uploadToCloudinary = async (
);
if (cloudinaryUploadResponse.status !== 200) {
if (!!onError) onError(cloudinaryUploadResponse.statusText);
if (!!onError) {
onError(cloudinaryUploadResponse.statusText);
}
try {
axios.post("/newlog", {
message: "client-cloudinary-upload-error",
type: "error",
user: store.getState().user.email,
object: cloudinaryUploadResponse,
});
} catch (error) {}
notification["error"]({
message: i18n.t("documents.errors.insert", {
message: cloudinaryUploadResponse.statusText,

View File

@@ -16,9 +16,14 @@ import EmailDocumentsComponent from "../email-documents/email-documents.componen
import _ from "lodash";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
currentUser: selectCurrentUser,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
@@ -28,7 +33,12 @@ export default connect(
mapDispatchToProps
)(EmailOverlayComponent);
export function EmailOverlayComponent({ form, selectedMediaState, bodyshop }) {
export function EmailOverlayComponent({
form,
selectedMediaState,
bodyshop,
currentUser,
}) {
const { t } = useTranslation();
const handleClick = ({ item, key, keyPath }) => {
const email = item.props.value;
@@ -51,6 +61,27 @@ export function EmailOverlayComponent({ form, selectedMediaState, bodyshop }) {
return (
<div>
<Form.Item
label={t("emails.fields.from")}
name="from"
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
>
<Select>
<Select.Option key={currentUser.email}>
{currentUser.email}
</Select.Option>
<Select.Option key={bodyshop.email}>{bodyshop.email}</Select.Option>
{bodyshop.md_from_emails &&
bodyshop.md_from_emails.map((e) => (
<Select.Option key={e}>{e}</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
label={
<Space>

View File

@@ -56,13 +56,9 @@ export function EmailOverlayContainer({
: bodyshop.shopname,
address: EmailSettings.fromAddress,
},
ReplyTo: {
Email: currentUser.validemail ? currentUser.email : bodyshop.email,
Name: currentUser.displayName,
},
};
const handleFinish = async (values) => {
const handleFinish = async (allValues) => {
logImEXEvent("email_send_from_modal");
//const attachments = [];
@@ -77,10 +73,15 @@ export function EmailOverlayContainer({
// attachments.push(t);
// });
const { from, ...values } = allValues;
setSending(true);
try {
await axios.post("/sendemail", {
...defaultEmailFrom,
ReplyTo: {
Email: from,
Name: currentUser.displayName,
},
...values,
html: rawHtml,
attachments: [
@@ -138,6 +139,7 @@ export function EmailOverlayContainer({
}
form.setFieldsValue({
from: currentUser.validemail ? currentUser.email : bodyshop.email,
...emailConfig.messageOptions,
cc:
emailConfig.messageOptions.cc &&

View File

@@ -3,27 +3,41 @@ import moment from "moment";
import React, { useRef } from "react";
//To be used as a form element only.
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(FormDatePicker);
const dateFormat = "MM/DD/YYYY";
export default function FormDatePicker({
export function FormDatePicker({
bodyshop,
value,
onChange,
onBlur,
onlyFuture,
isDateOnly = true,
...restProps
}) {
const ref = useRef();
const handleChange = (newDate) => {
if (value !== newDate && onChange) {
onChange(newDate);
onChange(isDateOnly ? newDate && newDate.format("YYYY-MM-DD") : newDate);
}
};
const handleKeyDown = (e) => {
if (e.key.toLowerCase() === "t") {
if (onChange) {
onChange(new moment());
onChange(isDateOnly ? moment().format("YYYY-MM-DD") : moment());
// if (ref.current && ref.current.blur) ref.current.blur();
}
} else if (e.key.toLowerCase() === "enter") {
@@ -51,7 +65,8 @@ export default function FormDatePicker({
});
}
if (_a.isValid() && onChange) onChange(_a);
if (_a.isValid() && onChange)
onChange(isDateOnly ? _a.format("YYYY-MM-DD") : _a);
};
return (
@@ -62,6 +77,7 @@ export default function FormDatePicker({
onChange={handleChange}
format={dateFormat}
onBlur={onBlur || handleBlur}
showToday={false}
disabledTime
{...(onlyFuture && {
disabledDate: (d) => moment().subtract(1, "day").isAfter(d),

View File

@@ -26,19 +26,20 @@ const DateTimePicker = (
value={value}
onBlur={onBlur}
onChange={onChange}
isDateOnly={false}
/>
<TimePicker
{...restProps}
value={value ? moment(value) : null}
{...(onlyFuture && {
disabledDate: (d) => moment().isAfter(d),
})}
onChange={onChange}
showSecond={false}
minuteStep={15}
onBlur={onBlur}
format="hh:mm a"
value={value ? moment(value) : null}
{...(onlyFuture && {
disabledDate: (d) => moment().isAfter(d),
})}
onChange={onChange}
showSecond={false}
minuteStep={15}
onBlur={onBlur}
format="hh:mm a"
{...restProps}
/>
</div>
);

View File

@@ -38,6 +38,7 @@ export default function ScheduleEventContainer({ bodyshop, event, refetch }) {
job: {
date_scheduled: null,
scheduled_in: null,
scheduled_completion:null,
status: bodyshop.md_ro_statuses.default_imported,
},
},

View File

@@ -64,15 +64,15 @@ export default function JobBillsTotalComponent({
})
);
const totalPartsSublet = Dinero(totals.parts.parts.total).add(
Dinero(totals.parts.sublets.total)
);
const totalPartsSublet = Dinero(totals.parts.parts.total)
.add(Dinero(totals.parts.sublets.total))
.add(Dinero(totals.additional.towing));
const discrepancy = totalPartsSublet.subtract(billTotals);
const discrepWithLbrAdj = discrepancy.add(lbrAdjustments);
const discrepWithCms = discrepWithLbrAdj.add(billCms);
const discrepWithCms = discrepWithLbrAdj.add(totalReturns);
const creditsNotReceived = totalReturns.subtract(billCms); //billCms is tracked as a negative number.
return (
@@ -171,8 +171,8 @@ export default function JobBillsTotalComponent({
}
>
<Statistic
title={t("bills.labels.billcmtotal")}
value={billCms.toFormat()}
title={t("bills.labels.totalreturns")}
value={totalReturns.toFormat()}
/>
</Tooltip>
<Typography.Title>=</Typography.Title>

View File

@@ -26,11 +26,6 @@ export function JobCostingModalContainer({
const { visible, context } = jobCostingModal;
const { jobId } = context;
// const { loading, error, data } = useQuery(QUERY_JOB_COSTING_DETAILS, {
// variables: { id: jobId },
// skip: !jobId,
// });
useEffect(() => {
async function getData() {
if (jobId && visible) {
@@ -46,8 +41,14 @@ export function JobCostingModalContainer({
<Modal
visible={visible}
title={t("jobs.labels.jobcosting")}
onOk={() => toggleModalVisible()}
onCancel={() => toggleModalVisible()}
onOk={() => {
toggleModalVisible();
setCostingData(null);
}}
onCancel={() => {
toggleModalVisible();
setCostingData(null);
}}
cancelButtonProps={{ style: { display: "none" } }}
width="90%"
destroyOnClose

View File

@@ -16,6 +16,14 @@ export default function JobCostingStatistics({ summaryData }) {
value={Dinero(summaryData.totalPartsSales).toFormat()}
title={t("jobs.labels.sale_parts")}
/>
<Statistic
value={Dinero(summaryData.totalSubletSales).toFormat()}
title={t("jobs.labels.sale_sublet")}
/>
<Statistic
value={Dinero(summaryData.totalAdditionalSales).toFormat()}
title={t("jobs.labels.sale_additional")}
/>
<Statistic
value={Dinero(summaryData.totalSales).toFormat()}
title={t("jobs.labels.total_sales")}
@@ -28,6 +36,14 @@ export default function JobCostingStatistics({ summaryData }) {
value={Dinero(summaryData.totalPartsCost).toFormat()}
title={t("jobs.labels.cost_parts")}
/>
<Statistic
value={Dinero(summaryData.totalSubletCost).toFormat()}
title={t("jobs.labels.cost_sublet")}
/>
<Statistic
value={Dinero(summaryData.totalAdditionalCost).toFormat()}
title={t("jobs.labels.cost_Additional")}
/>
<Statistic
value={Dinero(summaryData.totalCost).toFormat()}
title={t("jobs.labels.total_cost")}

View File

@@ -462,7 +462,7 @@ export function JobLinesComponent({
};
}}
rowSelection={{
selectedRowKeys: selectedLines.map((item) => item.id),
selectedRowKeys: selectedLines.map((item) => item && item.id),
onSelectAll: (selected, selectedRows, changeRows) => {
setSelectedLines(selectedRows);
},

View File

@@ -55,15 +55,17 @@ export function JobEmployeeAssignments({
0
}
>
{bodyshop.employees.map((emp) => (
<Select.Option
value={emp.id}
key={emp.id}
name={`${emp.first_name} ${emp.last_name}`}
>
{`${emp.first_name} ${emp.last_name}`}
</Select.Option>
))}
{bodyshop.employees
.filter((emp) => emp.active)
.map((emp) => (
<Select.Option
value={emp.id}
key={emp.id}
name={`${emp.first_name} ${emp.last_name}`}
>
{`${emp.first_name} ${emp.last_name}`}
</Select.Option>
))}
</Select>
</Col>
<Col span={24}>

View File

@@ -10,7 +10,7 @@ export default function JobLinesBillRefernece({ jobline }) {
{subletRequired && <WarningFilled />}
{`${(billLine.actual_price * billLine.quantity).toFixed(2)} (${
billLine.bill.vendor.name
})`}
} #${billLine.bill.invoice_number})`}
</div>
);
}

View File

@@ -18,7 +18,11 @@ export default function JobReconciliationModalComponent({ job, bills }) {
.flat() || [];
const jobLineData = job.joblines.filter(
(j) => j.part_type !== null && j.part_type !== "PAE"
(j) =>
(j.part_type !== null && j.part_type !== "PAE") ||
(j.line_desc &&
j.line_desc.toLowerCase().includes("towing") &&
j.lbr_op === "OP13")
);
return (

View File

@@ -1,4 +1,4 @@
import { Table } from "antd";
import { Space, Table } from "antd";
import Dinero from "dinero.js";
import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -119,7 +119,18 @@ export default function JobTotalsTableLabor({ job }) {
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>{t("jobs.labels.mapa")}</Table.Summary.Cell>
<Table.Summary.Cell>
<Space>
{t("jobs.labels.mapa")}
{job.materials &&
job.materials.mapa &&
job.materials.mapa.cal_maxdlr &&
job.materials.mapa.cal_maxdlr > 0 &&
t("jobs.labels.threshhold", {
amount: job.materials.mapa.cal_maxdlr,
})}
</Space>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<CurrencyFormatter>
{job.job_totals.rates.mapa.rate}
@@ -133,7 +144,18 @@ export default function JobTotalsTableLabor({ job }) {
</Table.Summary.Cell>
</Table.Summary.Row>
<Table.Summary.Row>
<Table.Summary.Cell>{t("jobs.labels.mash")}</Table.Summary.Cell>
<Table.Summary.Cell>
<Space wrap>
{t("jobs.labels.mash")}
{job.materials &&
job.materials.mash &&
job.materials.mash.cal_maxdlr &&
job.materials.mash.cal_maxdlr > 0 &&
t("jobs.labels.threshhold", {
amount: job.materials.mash.cal_maxdlr,
})}
</Space>
</Table.Summary.Cell>
<Table.Summary.Cell align="right">
<CurrencyFormatter>
{job.job_totals.rates.mash.rate}

View File

@@ -33,10 +33,10 @@ export default function JobTotalsTableOther({ job }) {
key: t("jobs.fields.storage_payable"),
total: job.job_totals.additional.storage,
},
{
key: t("jobs.fields.ca_bc_pvrt"),
total: job.job_totals.additional.pvrt,
},
// {
// key: t("jobs.fields.ca_bc_pvrt"),
// total: job.job_totals.additional.pvrt,
// },
];
}, [job.job_totals, t]);

View File

@@ -3,7 +3,22 @@ import Dinero from "dinero.js";
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
export default function JobTotalsTableTotals({ job }) {
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobTotalsTableTotals);
export function JobTotalsTableTotals({ bodyshop, job }) {
const { t } = useTranslation();
const data = useMemo(() => {
@@ -21,6 +36,14 @@ export default function JobTotalsTableTotals({ job }) {
key: t("jobs.labels.state_tax_amt"),
total: job.job_totals.totals.state_tax,
},
...(bodyshop.region_config === "CA_BC"
? [
{
key: t("jobs.fields.ca_bc_pvrt"),
total: job.job_totals.additional.pvrt,
},
]
: []),
{
key: t("jobs.labels.federal_tax_amt"),
total: job.job_totals.totals.federal_tax,
@@ -58,7 +81,7 @@ export default function JobTotalsTableTotals({ job }) {
bold: true,
},
];
}, [job.job_totals, t]);
}, [job.job_totals, t, bodyshop.region_config]);
const columns = [
{

View File

@@ -58,6 +58,15 @@ export default function JobsAdminDatesChange({ job }) {
>
<FormDatePicker format="MM/DD/YYYY" />
</Form.Item>
<Form.Item label={t("jobs.fields.date_towin")} name="date_towin">
<DateTimePicker />
</Form.Item>
<Form.Item
label={t("jobs.fields.date_rentalresp")}
name="date_rentalresp"
>
<DateTimePicker />
</Form.Item>
<Form.Item label={t("jobs.fields.date_open")} name="date_open">
<DateTimePicker />
</Form.Item>

View File

@@ -37,7 +37,6 @@ export const GetSupplementDelta = async (client, jobId, newLines) => {
});
//Wahtever is left in the existing lines, are lines that should be removed.
const insertQueries = linesToInsert.reduce((acc, value, idx) => {
return acc + generateInsertQuery(value, idx, jobId);
}, "");
@@ -49,6 +48,13 @@ export const GetSupplementDelta = async (client, jobId, newLines) => {
const removeQueries = existingLines.reduce((acc, value, idx) => {
return acc + generateRemoveQuery(value, idx);
}, "");
console.log(insertQueries, updateQueries, removeQueries);
if ((insertQueries + updateQueries + removeQueries).trim() === "") {
return new Promise((resolve, reject) => {
resolve(null);
});
}
return new Promise((resolve, reject) => {
resolve(gql`

View File

@@ -220,12 +220,13 @@ export function JobsAvailableContainer({
);
delete supp.joblines;
await client.mutate({
mutation: gql`
${suppDelta}
`,
});
if (suppDelta !== null) {
await client.mutate({
mutation: gql`
${suppDelta}
`,
});
}
const updateResult = await updateJob({
variables: {
jobId: selectedJob,

View File

@@ -39,6 +39,12 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
<Form.Item label={t("jobs.fields.date_open")} name="date_open">
<DateTimePicker disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.date_towin")} name="date_towin">
<DateTimePicker disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.date_rentalresp")} name="date_rentalresp">
<DateTimePicker disabled={jobRO} />
</Form.Item>
</FormRow>
<FormRow header={t("jobs.forms.scheddates")}>

View File

@@ -401,6 +401,9 @@ export function JobsDetailHeaderActions({
job: {
status: bodyshop.md_ro_statuses.default_void,
voided: true,
scheduled_in: null,
scheduled_completion: null,
inproduction: false,
},
note: [
{

View File

@@ -21,6 +21,7 @@ import ProductionListColumnProductionNote from "../production-list-columns/produ
import "./jobs-detail-header.styles.scss";
import JobsRelatedRos from "../jobs-related-ros/jobs-related-ros.component";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -59,6 +60,13 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
);
}, [job.status, bodyshop.md_ro_statuses.post_production_statuses]);
const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""}
${job.v_make_desc || ""}
${job.v_model_desc || ""}`.trim();
console.log(
"🚀 ~ file: jobs-detail-header.component.jsx ~ line 64 ~ vehicleTitle",
vehicleTitle.length
);
return (
<Row gutter={[16, 16]} style={{ alignItems: "stretch" }}>
<Col {...colSpan}>
@@ -86,6 +94,12 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
) : null}
</Space>
</DataLabel>
<DataLabel
label={t("jobs.fields.comment")}
valueStyle={{ overflow: "hidden", textOverflow: "ellipsis" }}
>
<ProductionListColumnComment record={job} />
</DataLabel>
<DataLabel label={t("jobs.fields.ins_co_nm_short")}>
{job.ins_co_nm}
</DataLabel>
@@ -181,9 +195,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
: job.vehicle && `/manage/vehicles/${job.vehicle.id}`
}
>
{`${job.v_model_yr || ""} ${job.v_color || ""}
${job.v_make_desc || ""}
${job.v_model_desc || ""}`}
{vehicleTitle.length > 0
? vehicleTitle
: t("vehicles.labels.novehinfo")}
</Link>
) : (
<span></span>

View File

@@ -30,7 +30,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ro_number"),
dataIndex: "ro_number",
key: "ro_number",
width: "8%",
sorter: true, //(a, b) => alphaSort(a.ro_number, b.ro_number),
sortOrder: sortcolumn === "ro_number" && sortorder,
@@ -47,7 +47,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
key: "ownr_ln",
ellipsis: true,
//sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
width: "25%",
//sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => {
return record.ownerid ? (
@@ -67,7 +67,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ownr_ph1"),
dataIndex: "ownr_ph1",
key: "ownr_ph1",
width: "12%",
ellipsis: true,
render: (text, record) => (
<StartChatButton phone={record.ownr_ph1} jobid={record.id} />
@@ -77,7 +77,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ownr_ph2"),
dataIndex: "ownr_ph2",
key: "ownr_ph2",
width: "12%",
ellipsis: true,
render: (text, record) => (
<StartChatButton phone={record.ownr_ph2} jobid={record.id} />
@@ -87,7 +87,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.status"),
dataIndex: "status",
key: "status",
width: "10%",
ellipsis: true,
sorter: true, // (a, b) => alphaSort(a.status, b.status),
sortOrder: sortcolumn === "status" && sortorder,
@@ -104,7 +104,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",
key: "vehicle",
width: "15%",
ellipsis: true,
render: (text, record) => {
return record.vehicleid ? (
@@ -124,7 +124,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("vehicles.fields.plate_no"),
dataIndex: "plate_no",
key: "plate_no",
width: "8%",
ellipsis: true,
sorter: true, //(a, b) => alphaSort(a.plate_no, b.plate_no),
sortOrder: sortcolumn === "plate_no" && sortorder,
@@ -136,7 +136,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
key: "clm_no",
width: "12%",
ellipsis: true,
sorter: true, //(a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder: sortcolumn === "clm_no" && sortorder,
@@ -155,7 +155,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.clm_total"),
dataIndex: "clm_total",
key: "clm_total",
width: "10%",
sorter: true, //(a, b) => a.clm_total - b.clm_total,
sortOrder: sortcolumn === "clm_total" && sortorder,
render: (text, record) => {
@@ -170,11 +170,17 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.owner_owing"),
dataIndex: "owner_owing",
key: "owner_owing",
width: "8%",
render: (text, record) => (
<CurrencyFormatter>{record.owner_owing}</CurrencyFormatter>
),
},
{
title: t("jobs.fields.comment"),
dataIndex: "comment",
key: "comment",
ellipsis: true,
},
];
const handleTableChange = (pagination, filters, sorter) => {
@@ -224,7 +230,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
>
<Table
loading={loading}
scroll={{ x: true }}
pagination={{
position: "top",
pageSize: 25,

View File

@@ -60,6 +60,9 @@ export function JobsList({ bodyshop }) {
(j.ownr_co_nm || "")
.toLowerCase()
.includes(searchText.toLowerCase()) ||
(j.comments || "")
.toLowerCase()
.includes(searchText.toLowerCase()) ||
(j.ownr_fn || "")
.toLowerCase()
.includes(searchText.toLowerCase()) ||
@@ -262,6 +265,13 @@ export function JobsList({ bodyshop }) {
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
),
},
{
title: t("jobs.fields.comment"),
dataIndex: "comment",
key: "comment",
ellipsis: true,
responsive: ["md"],
},
// {
// title: t("jobs.fields.owner_owing"),
// dataIndex: "owner_owing",

View File

@@ -115,7 +115,6 @@ export function JobNotesComponent({
<EditFilled />
</Button>
<PrintWrapperComponent
emailOnly
templateObject={{
name: Templates.individual_job_note.key,
@@ -124,7 +123,7 @@ export function JobNotesComponent({
messageObject={{
subject: Templates.individual_job_note.subject,
}}
id={record.id}
id={jobId}
/>
</Space>
),

View File

@@ -6,9 +6,11 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { setPartnerVersion } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
@@ -19,26 +21,35 @@ export default connect(
mapDispatchToProps
)(PartnerPingComponent);
export function PartnerPingComponent({ setPartnerVersion }) {
export function PartnerPingComponent({ bodyshop, setPartnerVersion }) {
const { t } = useTranslation();
useEffect(() => {
// Create an scoped async function in the hook
async function checkPartnerStatus() {
if (!bodyshop) return;
try {
//if (process.env.NODE_ENV === "development") return;
const PartnerResponse = await axios.post("http://localhost:1337/ping/");
const { appver, qbpath } = PartnerResponse.data;
setPartnerVersion(appver);
console.log({ appver, qbpath });
if (!qbpath) {
if (
!qbpath &&
!(
bodyshop &&
(bodyshop.cdk_dealerid ||
bodyshop.pbs_serialnumber ||
bodyshop.accountingconfig.qbo)
)
) {
notification["error"]({
title: "",
message: t("general.messages.noacctfilepath"),
});
}
} catch (error) {
console.log(error);
notification["error"]({
title: "",
message: t("general.messages.partnernotrunning"),
@@ -48,7 +59,7 @@ export function PartnerPingComponent({ setPartnerVersion }) {
// Execute the created function directly
checkPartnerStatus();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [bodyshop]);
return <></>;
}

View File

@@ -319,6 +319,15 @@ export function PartsOrderListTableComponent({
},
]
: []),
{
title: t("parts_orders.fields.part_type"),
dataIndex: "part_type",
key: "part_type",
render: (text, record) =>
record.part_type
? t(`joblines.fields.part_types.${record.part_type}`)
: null,
},
{
title: t("parts_orders.fields.oem_partno"),
dataIndex: "oem_partno",

View File

@@ -1,6 +1,15 @@
import { DeleteFilled, WarningFilled } from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react";
import { Divider, Form, Input, InputNumber, Radio, Space, Tag } from "antd";
import {
Divider,
Form,
Input,
InputNumber,
Radio,
Space,
Tag,
Select,
} from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -37,6 +46,11 @@ export function PartsOrderModalComponent({
{},
bodyshop.imexshopid
);
const { OEConnection_PriceChange } = useTreatments(
["OEConnection_PriceChange"],
{},
bodyshop.imexshopid
);
const { t } = useTranslation();
return (
@@ -59,6 +73,7 @@ export function PartsOrderModalComponent({
options={vendorList}
disabled={isReturn}
preferredMake={preferredMake}
showPhone
/>
</Form.Item>
<Form.Item
@@ -114,6 +129,52 @@ export function PartsOrderModalComponent({
>
<Input />
</Form.Item>
<Form.Item
label={t("parts_orders.fields.part_type")}
key={`${index}part_type`}
name={[field.name, "part_type"]}
>
<Select
disabled={
!(
sendType === "oec" &&
OEConnection_PriceChange.treatment === "on"
)
}
>
<Select.Option value="PAA">
{t("joblines.fields.part_types.PAA")}
</Select.Option>
<Select.Option value="PAC">
{t("joblines.fields.part_types.PAC")}
</Select.Option>
<Select.Option value="PAL">
{t("joblines.fields.part_types.PAL")}
</Select.Option>
<Select.Option value="PAG">
{t("joblines.fields.part_types.PAG")}
</Select.Option>
<Select.Option value="PAM">
{t("joblines.fields.part_types.PAM")}
</Select.Option>
<Select.Option value="PAP">
{t("joblines.fields.part_types.PAP")}
</Select.Option>
<Select.Option value="PAN">
{t("joblines.fields.part_types.PAN")}
</Select.Option>
<Select.Option value="PAO">
{t("joblines.fields.part_types.PAO")}
</Select.Option>
<Select.Option value="PAR">
{t("joblines.fields.part_types.PAR")}
</Select.Option>
<Select.Option value="PAS">
{t("joblines.fields.part_types.PAS")}
</Select.Option>
</Select>
</Form.Item>
<Form.Item
label={t("parts_orders.fields.oem_partno")}
key={`${index}oem_partno`}
@@ -192,7 +253,7 @@ export function PartsOrderModalComponent({
<Radio value={"none"}>{t("general.labels.none")}</Radio>
<Radio value={"e"}>{t("parts_orders.labels.email")}</Radio>
<Radio value={"p"}>{t("parts_orders.labels.print")}</Radio>
{OEConnection.treatment === "on" && (
{OEConnection.treatment === "on" && !isReturn && (
<Radio value={"oec"}>{t("parts_orders.labels.oec")}</Radio>
)}
</Radio.Group>

View File

@@ -30,6 +30,8 @@ import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import PartsOrderModalComponent from "./parts-order-modal.component";
import axios from "axios";
import { useTreatments } from "@splitsoftware/splitio-react";
import _ from "lodash";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
@@ -57,6 +59,11 @@ export function PartsOrderModalContainer({
}) {
const { t } = useTranslation();
const client = useApolloClient();
const { OEConnection_PriceChange } = useTreatments(
["OEConnection_PriceChange"],
{},
bodyshop.imexshopid
);
const { visible, context, actions } = partsOrderModal;
const {
jobId,
@@ -70,7 +77,7 @@ export function PartsOrderModalContainer({
const { refetch } = actions;
const [form] = Form.useForm();
const [saving, setSaving] = useState(false);
const sendTypeState = useState("e");
const sendType = sendTypeState[0];
@@ -86,7 +93,7 @@ export function PartsOrderModalContainer({
const handleFinish = async (values) => {
logImEXEvent("parts_order_insert");
setSaving(true);
const insertResult = await insertPartOrder({
variables: {
po: [
@@ -189,6 +196,11 @@ export function PartsOrderModalContainer({
(item) => item.id === values.vendorid
)[0];
let vendorEmails =
matchingVendor &&
matchingVendor.email &&
matchingVendor.email.split(RegExp("[;,]"));
GenerateDocument(
{
name: isReturn
@@ -199,7 +211,7 @@ export function PartsOrderModalContainer({
},
},
{
to: matchingVendor ? [matchingVendor.email] : null,
to: matchingVendor ? vendorEmails : null,
replyTo: bodyshop.email,
subject: isReturn
? Templates.parts_return_slip.subject
@@ -230,11 +242,20 @@ export function PartsOrderModalContainer({
id: insertResult.data.insert_parts_orders.returning[0].id,
},
});
let po;
//Massage the data based on the split. Should they be able to overwrite OEC pricing?
if (OEConnection_PriceChange.treatment === "on") {
//Set the flag to include the override.
po = _.cloneDeep(partsOrder.data.parts_orders_by_pk);
po.parts_order_lines.forEach((pol) => {
pol.priceChange = true;
});
}
const oecResponse = await axios.post(
"http://localhost:1337/oec/",
partsOrder.data.parts_orders_by_pk,
po || partsOrder.data.parts_orders_by_pk,
{
headers: {
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
@@ -257,11 +278,11 @@ export function PartsOrderModalContainer({
error: JSON.stringify(error.message),
}),
});
setSaving(false);
return;
}
}
setSaving(false);
toggleModalVisible();
};
@@ -283,6 +304,7 @@ export function PartsOrderModalContainer({
cost: value.cost,
quantity: value.part_qty,
job_line_id: isReturn ? value.joblineid : value.id,
part_type: value.part_type,
});
return acc;
}, [])
@@ -306,6 +328,8 @@ export function PartsOrderModalContainer({
}
onCancel={() => toggleModalVisible()}
onOk={() => form.submit()}
okButtonProps={{ loading: saving }}
cancelButtonProps={{ loading: saving }}
destroyOnClose
width="75%"
forceRender

View File

@@ -22,7 +22,7 @@ export default function ProductionBoardCard(
) {
const { t } = useTranslation();
let employee_body, employee_prep, employee_refinish; //employee_csr;
let employee_body, employee_prep, employee_refinish, employee_csr;
if (card.employee_body) {
employee_body = bodyshop.employees.find((e) => e.id === card.employee_body);
}
@@ -34,6 +34,9 @@ export default function ProductionBoardCard(
(e) => e.id === card.employee_refinish
);
}
if (card.employee_csr) {
employee_csr = bodyshop.employees.find((e) => e.id === card.employee_csr);
}
// if (card.employee_csr) {
// employee_csr = bodyshop.employees.find((e) => e.id === card.employee_csr);
// }
@@ -131,11 +134,11 @@ export default function ProductionBoardCard(
)} ${employee_refinish.last_name.charAt(0)}`
: ""
} ${card.larhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
{/* <Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`C: ${
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`C: ${
employee_csr
? `${employee_csr.first_name} ${employee_csr.last_name}`
: ""
}`}</Col> */}
}`}</Col>
</Row>
</Col>
)}

View File

@@ -66,6 +66,7 @@ export const createBoardData = (AllStatuses, Jobs, filter) => {
include ||
j.employee_body === employeeId ||
j.employee_prep === employeeId ||
j.employee_csr === employeeId ||
j.employee_refinish === employeeId;
}
@@ -76,9 +77,8 @@ export const createBoardData = (AllStatuses, Jobs, filter) => {
Object.keys(DataGroupedByStatus).map((statusGroupKey) => {
try {
boardLanes.columns.find(
(l) => l.id === statusGroupKey
).cards = sortByParentId(DataGroupedByStatus[statusGroupKey]);
boardLanes.columns.find((l) => l.id === statusGroupKey).cards =
sortByParentId(DataGroupedByStatus[statusGroupKey]);
} catch (error) {
console.log("Error while creating board card", error);
}

View File

@@ -0,0 +1,79 @@
import Icon from "@ant-design/icons";
import { useMutation } from "@apollo/client";
import { Button, Input, Popover } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { FaRegStickyNote } from "react-icons/fa";
import { UPDATE_JOB } from "../../graphql/jobs.queries";
export default function ProductionListColumnComment({ record }) {
const { t } = useTranslation();
const [note, setNote] = useState(record.comment || "");
const [visible, setVisible] = useState(false);
const [updateAlert] = useMutation(UPDATE_JOB);
const handleSaveNote = (e) => {
e.stopPropagation();
setVisible(false);
updateAlert({
variables: {
jobId: record.id,
job: {
comment: note,
},
},
}).then(() => {
if (record.refetch) record.refetch();
});
};
const handleChange = (e) => {
e.stopPropagation();
setNote(e.target.value);
};
const handleVisibleChange = (flag) => {
setVisible(flag);
if (flag) setNote(record.comment || "");
};
return (
<Popover
onVisibleChange={handleVisibleChange}
visible={visible}
content={
<div style={{ width: "30em" }}>
<Input.TextArea
rows={5}
value={note}
onChange={handleChange}
// onPressEnter={handleSaveNote}
autoFocus
allowClear
/>
<div>
<Button onClick={handleSaveNote}>
{t("general.actions.save")}
</Button>
</div>
</div>
}
trigger={["click"]}
>
<div
style={{
width: "100%",
height: "19px",
cursor: "pointer",
overflow: "hidden",
textOverflow: "ellipsis",
}}
>
<Icon component={FaRegStickyNote} style={{ marginRight: ".2rem" }} />
{record.comment || " "}
</div>
</Popover>
);
}

View File

@@ -20,6 +20,7 @@ import ProductionListColumnNote from "./production-list-columns.productionnote.c
import ProductionListColumnStatus from "./production-list-columns.status.component";
import ProductionListColumnCategory from "./production-list-columns.status.category";
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
import ProductionListColumnComment from "./production-list-columns.comment.component";
const r = ({ technician, state, activeStatuses, bodyshop }) => {
return [
@@ -95,7 +96,7 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
sortOrder:
state.sortedInfo.columnKey === "actual_in" && state.sortedInfo.order,
render: (text, record) => (
<ProductionListDate record={record} field="actual_in" />
<ProductionListDate record={record} field="actual_in" time/>
),
},
{
@@ -109,7 +110,12 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
state.sortedInfo.columnKey === "scheduled_completion" &&
state.sortedInfo.order,
render: (text, record) => (
<ProductionListDate record={record} field="scheduled_completion" pastIndicator />
<ProductionListDate
record={record}
field="scheduled_completion"
pastIndicator
time
/>
),
},
{
@@ -156,7 +162,12 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
state.sortedInfo.columnKey === "scheduled_delivery" &&
state.sortedInfo.order,
render: (text, record) => (
<ProductionListDate record={record} field="scheduled_delivery" pastIndicator/>
<ProductionListDate
record={record}
field="scheduled_delivery"
pastIndicator
time
/>
),
},
{
@@ -325,6 +336,13 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
ellipsis: true,
render: (text, record) => <ProductionListColumnNote record={record} />,
},
{
title: i18n.t("production.labels.comment"),
dataIndex: "comment",
key: "comment",
ellipsis: true,
render: (text, record) => <ProductionListColumnComment record={record} />,
},
{
title: i18n.t("production.labels.touchtime"),
dataIndex: "tt",

View File

@@ -20,9 +20,9 @@ export default function ProductionListDate({
const handleChange = (date) => {
logImEXEvent("product_toggle_date", { field });
if (date.isSame(record[field] && moment(record[field]))) {
return;
}
// if (date.isSame(record[field] && moment(record[field]))) {
// return;
// }
//e.stopPropagation();
updateAlert({
@@ -67,12 +67,14 @@ export default function ProductionListDate({
value={(record[field] && moment(record[field])) || null}
onChange={handleChange}
format="MM/DD/YYYY"
isDateOnly={!time}
/>
{time && (
<TimePicker
onClick={(e) => e.stopPropagation()}
value={(record[field] && moment(record[field])) || null}
onChange={handleChange}
minuteStep={15}
format="hh:mm a"
/>
)}

View File

@@ -116,15 +116,17 @@ export function ProductionListEmpAssignment({
0
}
>
{bodyshop.employees.map((emp) => (
<Select.Option
value={emp.id}
key={emp.id}
name={`${emp.first_name} ${emp.last_name}`}
>
{`${emp.first_name} ${emp.last_name}`}
</Select.Option>
))}
{bodyshop.employees
.filter((emp) => emp.active)
.map((emp) => (
<Select.Option
value={emp.id}
key={emp.id}
name={`${emp.first_name} ${emp.last_name}`}
>
{`${emp.first_name} ${emp.last_name}`}
</Select.Option>
))}
</Select>
</Col>
<Col span={24}>

View File

@@ -1,5 +1,5 @@
import { useQuery } from "@apollo/client";
import { Descriptions, Drawer, Space } from "antd";
import { Descriptions, Drawer, Space, PageHeader, Button } from "antd";
import queryString from "query-string";
import React from "react";
import { useTranslation } from "react-i18next";
@@ -16,8 +16,25 @@ import JobEmployeeAssignments from "../job-employee-assignments/job-employee-ass
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
import JobAtChange from "../job-at-change/job-at-change.component";
import { PrinterFilled } from "@ant-design/icons";
export default function ProductionListDetail({ jobs }) {
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { setModalContext } from "../../redux/modals/modals.actions";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
});
const mapDispatchToProps = (dispatch) => ({
setPrintCenterContext: (context) =>
dispatch(setModalContext({ context: context, modal: "printCenter" })),
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProductionListDetail);
export function ProductionListDetail({ jobs, setPrintCenterContext }) {
const search = queryString.parse(useLocation().search);
const history = useHistory();
const { selected } = search;
@@ -39,11 +56,29 @@ export default function ProductionListDetail({ jobs }) {
return (
<Drawer
title={
<Space>
<span>{t("production.labels.jobdetail")}</span>
<span>{theJob.ro_number}</span>
<ProductionRemoveButton jobId={theJob.id} />
</Space>
<PageHeader
title={theJob.ro_number}
extra={
<Space>
<ProductionRemoveButton jobId={theJob.id} />{" "}
<Button
onClick={() => {
setPrintCenterContext({
actions: { refetch: refetch },
context: {
id: theJob.id,
job: theJob,
type: "job",
},
});
}}
>
<PrinterFilled />
{t("jobs.actions.printCenter")}
</Button>
</Space>
}
/>
}
placement="right"
width={"33%"}

View File

@@ -8,8 +8,11 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
const ProdTemplates = TemplateList("production");
const { production_by_technician_one, production_by_category_one } =
TemplateList("special");
const {
production_by_technician_one,
production_by_category_one,
production_by_repair_status_one,
} = TemplateList("special");
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -95,6 +98,29 @@ export function ProductionListPrint({ bodyshop }) {
</Menu.Item>
))}
</Menu.SubMenu>
<Menu.SubMenu
title={t("reportcenter.templates.production_by_repair_status_one")}
>
{bodyshop.md_ro_statuses.production_statuses.map((e) => (
<Menu.Item
key={e}
onClick={async () => {
setLoading(true);
await GenerateDocument(
{
name: production_by_repair_status_one.key,
variables: { status: e },
},
{},
"p"
);
setLoading(false);
}}
>
{e}
</Menu.Item>
))}
</Menu.SubMenu>
</Menu>
}
>

View File

@@ -65,6 +65,7 @@ export function ScheduleCalendarContainer({ calculateScheduleLoad }) {
color: "red",
start: moment(e.start).startOf("day").toDate(),
end: moment(e.end).startOf("day").toDate(),
allDay: true,
vacation: true,
};
}),

View File

@@ -1,6 +1,8 @@
import { CalendarOutlined } from "@ant-design/icons";
import { Card, Col, Row, Statistic } from "antd";
import React from "react";
import _ from "lodash";
import moment from "moment";
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -16,25 +18,78 @@ const mapDispatchToProps = (dispatch) => ({
});
const rowGutter = [16, 16];
const statSpans = { xs: 24, sm: 6 };
const statSpans = { xs: 24, sm: 3 };
export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
const { t } = useTranslation();
const values = useMemo(() => {
const dateHash = _.groupBy(scoreBoardlist, "date");
console.log(
"🚀 ~ file: scoreboard-targets-table.component.jsx ~ line 31 ~ values ~ dateHash",
dateHash
);
let ret = {
todayBody: 0,
todayPaint: 0,
weeklyPaint: 0,
weeklyBody: 0,
toDateBody: 0,
toDatePaint: 0,
};
const today = moment();
if (dateHash[today.format("YYYY-MM-DD")]) {
dateHash[today.format("YYYY-MM-DD")].forEach((d) => {
ret.todayBody = ret.todayBody + d.bodyhrs;
ret.todayPaint = ret.todayPaint + d.painthrs;
});
}
let StartOfWeek = moment().startOf("week");
while (StartOfWeek.isSameOrBefore(today)) {
if (dateHash[StartOfWeek.format("YYYY-MM-DD")]) {
dateHash[StartOfWeek.format("YYYY-MM-DD")].forEach((d) => {
ret.weeklyBody = ret.weeklyBody + d.bodyhrs;
ret.weeklyPaint = ret.weeklyPaint + d.painthrs;
});
}
StartOfWeek = StartOfWeek.add(1, "day");
}
let startOfMonth = moment().startOf("month");
while (startOfMonth.isSameOrBefore(today)) {
if (dateHash[startOfMonth.format("YYYY-MM-DD")]) {
dateHash[startOfMonth.format("YYYY-MM-DD")].forEach((d) => {
ret.toDateBody = ret.toDateBody + d.bodyhrs;
ret.toDatePaint = ret.toDatePaint + d.painthrs;
});
}
startOfMonth = startOfMonth.add(1, "day");
}
return ret;
}, [scoreBoardlist]);
console.log(
"🚀 ~ file: scoreboard-targets-table.component.jsx ~ line 51 ~ values ~ values",
values
);
return (
<Card
title={t("scoreboard.labels.targets")}
extra={<ScoreboardJobsList scoreBoardlist={scoreBoardlist} />}
>
<Row gutter={rowGutter}>
<Col xs={24} sm={{ offset: 0, span: 4 }} lg={{ offset: 5, span: 4 }}>
<Col xs={24} sm={{ offset: 0, span: 4 }} lg={{ span: 4 }}>
<Statistic
title={t("scoreboard.labels.workingdays")}
value={Util.CalculateWorkingDaysThisMonth()}
prefix={<CalendarOutlined />}
/>
</Col>
<Col xs={24} sm={{ offset: 0, span: 20 }} lg={{ offset: 0, span: 13 }}>
<Col xs={24} sm={{ offset: 0, span: 20 }} lg={{ offset: 0, span: 20 }}>
<Row>
<Col {...statSpans}>
<Statistic
@@ -43,6 +98,12 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
prefix="B"
/>
</Col>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.dailyactual")}
value={values.todayBody.toFixed(1)}
/>
</Col>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.weeklytarget")}
@@ -52,6 +113,12 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
)}
/>
</Col>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.weeklyactual")}
value={values.weeklyBody.toFixed(1)}
/>
</Col>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.monthlytarget")}
@@ -70,6 +137,12 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
)}
/>
</Col>
<Col {...statSpans}>
<Statistic
title={t("scoreboard.labels.todateactual")}
value={values.toDateBody.toFixed(1)}
/>
</Col>
</Row>
<Row>
<Col {...statSpans}>
@@ -78,6 +151,9 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
prefix="P"
/>
</Col>
<Col {...statSpans}>
<Statistic value={values.todayPaint.toFixed(1)} />
</Col>
<Col {...statSpans}>
<Statistic
value={Util.WeeklyTargetHrs(
@@ -86,6 +162,9 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
)}
/>
</Col>
<Col {...statSpans}>
<Statistic value={values.weeklyPaint.toFixed(1)} />
</Col>
<Col {...statSpans}>
<Statistic
value={Util.MonthlyTargetHrs(
@@ -102,6 +181,9 @@ export function ScoreboardTargetsTable({ bodyshop, scoreBoardlist }) {
)}
/>
</Col>
<Col {...statSpans}>
<Statistic value={values.toDatePaint.toFixed(1)} />
</Col>
</Row>
</Col>
</Row>

View File

@@ -19,6 +19,9 @@ 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();
export default function ShopInfoGeneral({ form }) {
const { t } = useTranslation();
return (
@@ -84,6 +87,7 @@ export default function ShopInfoGeneral({ form }) {
<Form.Item label={t("bodyshop.fields.email")} name="email">
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.phone")}
name="phone"
@@ -97,6 +101,23 @@ export default function ShopInfoGeneral({ form }) {
<Form.Item label={t("bodyshop.fields.website")} name="website">
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.timezone")}
rules={[
{
required: true,
//message: t("general.validation.required"),
},
]}
name="timezone"
>
<Select
showSearch
options={timeZonesList.map((z) => {
return { label: z, value: z };
})}
/>
</Form.Item>
<Form.Item
label={t("bodyshop.fields.insurance_vendor_id")}
name="insurance_vendor_id"
@@ -121,6 +142,18 @@ export default function ShopInfoGeneral({ form }) {
>
<Input />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.logo_img_header_margin")}
name={["logo_img_path", "headerMargin"]}
>
<InputNumber min={0} />
</Form.Item>
<Form.Item
label={t("bodyshop.fields.logo_img_footer_margin")}
name={["logo_img_path", "footerMargin"]}
>
<InputNumber min={0} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("bodyshop.labels.accountingsetup")}>
<Form.Item
@@ -474,6 +507,18 @@ export default function ShopInfoGeneral({ form }) {
>
<Switch />
</Form.Item>
<Form.Item
name={["md_from_emails"]}
label={t("bodyshop.fields.md_from_emails")}
// rules={[
// {
// //message: t("general.validation.required"),
// type: "array",
// },
// ]}
>
<Select mode="tags" />
</Form.Item>
<Form.Item
name={["md_email_cc", "parts_order"]}
label={t("bodyshop.fields.md_email_cc", { template: "parts_order" })}

View File

@@ -129,6 +129,15 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
>
<Input />
</Form.Item>
{bodyshop.pbs_serialnumber && (
<Form.Item
label={t("bodyshop.fields.dms.disablecontactvehiclecreation")}
valuePropName="checked"
name={["pbs_configuration", "disablecontactvehicle"]}
>
<Switch />
</Form.Item>
)}
</LayoutFormRow>
<LayoutFormRow header={t("bodyshop.labels.dms.cdk.payers")}>
<Form.List name={["cdk_configuration", "payers"]}>

View File

@@ -70,6 +70,12 @@ export default function ShopInfoSchedulingComponent({ form }) {
>
<Select mode="tags" />
</Form.Item>
<Form.Item
name={["ss_configuration", "dailyhrslimit"]}
label={t("bodyshop.fields.ss_configuration.dailyhrslimit")}
>
<InputNumber min={0} />
</Form.Item>
</LayoutFormRow>
<Divider orientation="left">{t("bodyshop.labels.workingdays")}</Divider>
<Space wrap size="large">

View File

@@ -76,6 +76,21 @@ export function TimeTicketList({
state.sortedInfo.columnKey === "employee" && state.sortedInfo.order,
render: (text, record) =>
`${record.employee.first_name} ${record.employee.last_name}`,
filters:
timetickets
.map((l) => l.employeeid)
.filter(onlyUnique)
.map((s) => {
return {
text: (() => {
const emp = bodyshop.employees.find((e) => e.id === s);
return `${emp.first_name} ${emp.last_name}`;
})(), //
value: [s],
};
}) || [],
onFilter: (value, record) => value.includes(record.employeeid),
},
{
title: t("timetickets.fields.cost_center"),

View File

@@ -159,8 +159,10 @@ export function TimeTicketModalComponent({
name="flat_rate"
label={t("timetickets.fields.flat_rate")}
valuePropName="checked"
noStyle
style={{ display: "none" }}
>
<Switch />
<Switch style={{ display: "none" }} />
</Form.Item>
</LayoutFormRow>
@@ -208,10 +210,11 @@ export function TimeTicketModalComponent({
>
<InputNumber min={0} precision={1} />
</Form.Item>
{isEdit && (
{
<>
<Form.Item label={t("timetickets.fields.clockon")} name="clockon">
<FormDateTimePicker
minuteStep={5}
disabled={
!HasRbacAccess({
bodyshop,
@@ -221,8 +224,31 @@ export function TimeTicketModalComponent({
}
/>
</Form.Item>
<Form.Item label={t("timetickets.fields.clockoff")} name="clockoff">
<Form.Item
label={t("timetickets.fields.clockoff")}
name="clockoff"
rules={[
({ getFieldValue }) => ({
validator(rule, value) {
const clockon = getFieldValue("clockon");
if (!value) return Promise.resolve();
if (!clockon && value)
return Promise.reject(
t("timetickets.validation.clockoffwithoutclockon")
);
if (!value.isSameOrAfter(clockon))
return Promise.reject(
t("timetickets.validation.clockoffmustbeafterclockon")
);
return Promise.resolve();
},
}),
]}
>
<FormDateTimePicker
minuteStep={5}
disabled={
!HasRbacAccess({
bodyshop,
@@ -233,7 +259,7 @@ export function TimeTicketModalComponent({
/>
</Form.Item>
</>
)}
}
<Form.Item label={t("timetickets.fields.memo")} name="memo">
<MemoInput />

View File

@@ -0,0 +1,41 @@
import { Button } from "antd";
import queryString from "query-string";
import React, { useState } from "react";
import { useLocation } from "react-router-dom";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants";
import { useTranslation } from "react-i18next";
import moment from "moment";
const PayrollTemplate = TemplateList("special").exported_payroll;
export default function TimeTicketsPayrollTable() {
const searchParams = queryString.parse(useLocation().search);
const { start, end } = searchParams;
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const handleClick = async () => {
setLoading(true);
await GenerateDocument(
{
name: PayrollTemplate.key,
variables: {
start: start
? start
: moment().startOf("week").subtract(7, "days").format("YYYY-MM-DD"),
end: end ? end : moment().endOf("week").format("YYYY-MM-DD"),
},
},
{},
"x"
);
setLoading(false);
};
return (
<Button loading={loading} onClick={handleClick}>
{t("printcenter.payments.exported_payroll")}
</Button>
);
}

View File

@@ -1,12 +1,13 @@
import { HeartOutlined } from "@ant-design/icons";
import { Select, Tag } from "antd";
import { Select, Space, Tag } from "antd";
import React, { forwardRef, useEffect, useState } from "react";
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
const { Option } = Select;
//To be used as a form element only.
const VendorSearchSelect = (
{ value, onChange, options, onSelect, disabled, preferredMake },
{ value, onChange, options, onSelect, disabled, preferredMake, showPhone },
ref
) => {
const [option, setOption] = useState(value);
@@ -35,6 +36,7 @@ const VendorSearchSelect = (
style={{
width: "100%",
}}
dropdownMatchSelectWidth={false}
onChange={setOption}
optionFilterProp="name"
onSelect={onSelect}
@@ -50,10 +52,15 @@ const VendorSearchSelect = (
>
<div className="imex-flex-row">
<div style={{ flex: 1 }}>{o.name}</div>
<HeartOutlined />
{o.discount && o.discount !== 0 ? (
<Tag color="green">{`${o.discount * 100}%`}</Tag>
) : null}
<Space style={{ marginLeft: "1rem" }}>
<HeartOutlined style={{ color: "red" }} />
{o.phone && showPhone && (
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
)}
{o.discount && o.discount !== 0 ? (
<Tag color="green">{`${o.discount * 100}%`}</Tag>
) : null}
</Space>
</div>
</Option>
))
@@ -64,9 +71,14 @@ const VendorSearchSelect = (
<div className="imex-flex-row" style={{ width: "100%" }}>
<div style={{ flex: 1 }}>{o.name}</div>
{o.discount && o.discount !== 0 ? (
<Tag color="green">{`${o.discount * 100}%`}</Tag>
) : null}
<Space style={{ marginLeft: "1rem" }}>
{o.phone && showPhone && (
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
)}
{o.discount && o.discount !== 0 ? (
<Tag color="green">{`${o.discount * 100}%`}</Tag>
) : null}
</Space>
</div>
</Option>
))

View File

@@ -109,12 +109,14 @@ export default function VendorsFormComponent({
<Form.Item
label={t("vendors.fields.email")}
rules={[
{
type: "email",
message: t("general.validation.invalidemail"),
},
]}
rules={
[
// {
// type: "email",
// message: t("general.validation.invalidemail"),
// },
]
}
name="email"
>
<FormItemEmail email={getFieldValue("email")} />
@@ -158,7 +160,7 @@ export default function VendorsFormComponent({
<InputNumber min={0} max={1} precision={2} step={0.01} />
</Form.Item>
<Form.Item label={t("vendors.fields.due_date")} name="due_date">
<InputNumber />
<InputNumber min={0} />
</Form.Item>
{
// <Form.Item

View File

@@ -84,6 +84,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
line_remarks
quantity
job_line_id
part_type
cost
jobline {
id
@@ -123,6 +124,10 @@ export const QUERY_BILLS_BY_JOBID = gql`
applicable_taxes
deductedfromlbr
lbr_adjustment
jobline{
oem_partno
part_type
}
}
}
}
@@ -159,6 +164,10 @@ export const QUERY_BILL_BY_PK = gql`
cost_center
quantity
joblineid
jobline{
oem_partno
part_type
}
applicable_taxes
deductedfromlbr
lbr_adjustment

View File

@@ -100,6 +100,9 @@ export const QUERY_BODYSHOP = gql`
pbs_serialnumber
md_filehandlers
md_email_cc
timezone
ss_configuration
md_from_emails
employees {
user_email
id
@@ -197,6 +200,9 @@ export const UPDATE_SHOP = gql`
pbs_serialnumber
md_filehandlers
md_email_cc
timezone
ss_configuration
md_from_emails
employees {
id
first_name
@@ -264,7 +270,6 @@ export const QUERY_DELIVER_CHECKLIST = gql`
ro_number
actual_completion
actual_delivery
}
}
`;

View File

@@ -89,6 +89,9 @@ export const QUERY_ALL_CC = gql`
job {
id
ro_number
ownr_fn
ownr_ln
ownr_co_nm
}
}
}

View File

@@ -59,6 +59,8 @@ export const GET_LINE_TICKET_BY_PK = gql`
employeeid
memo
flat_rate
clockon
clockoff
employee {
id
first_name

View File

@@ -12,11 +12,7 @@ export const QUERY_ALL_ACTIVE_JOBS = gql`
ownr_ph1
ownr_ph2
ownr_ea
owner {
id
allow_text_message
preferred_contact
}
comment
plate_no
plate_st
v_vin
@@ -121,6 +117,7 @@ export const QUERY_EXACT_JOB_IN_PRODUCTION = gql`
id
status
ro_number
comment
ownr_fn
ownr_ln
category
@@ -193,6 +190,7 @@ export const QUERY_EXACT_JOBS_IN_PRODUCTION = gql`
id
status
ro_number
comment
ownr_fn
category
ownr_ln
@@ -264,6 +262,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
jobs(where: { inproduction: { _eq: true } }) {
id
updated_at
comment
status
category
ro_number
@@ -489,6 +488,7 @@ export const GET_JOB_BY_PK = gql`
alt_transport
intakechecklist
invoice_final_note
comment
loss_desc
kmin
kmout
@@ -595,6 +595,7 @@ export const GET_JOB_BY_PK = gql`
ca_gst_registrant
ownerid
ded_note
materials
owner {
id
ownr_fn
@@ -649,6 +650,8 @@ export const GET_JOB_BY_PK = gql`
date_invoiced
date_last_contacted
date_next_contact
date_towin
date_rentalresp
date_exported
status
owner_owing
@@ -696,6 +699,7 @@ export const GET_JOB_BY_PK = gql`
joblineid
bill {
id
invoice_number
vendor {
id
name
@@ -830,6 +834,7 @@ export const QUERY_JOB_CARD_DETAILS = gql`
ownr_co_nm
ownr_ph1
ownr_ph2
comment
ownr_ea
ca_gst_registrant
owner_owing
@@ -1034,7 +1039,7 @@ export const UPDATE_JOB = gql`
update_jobs(where: { id: { _eq: $jobId } }, _set: $job) {
returning {
id
comment
date_exported
status
alt_transport
@@ -1095,6 +1100,15 @@ export const VOID_JOB = gql`
insert_notes(objects: $note) {
affected_rows
}
update_appointments(
where: { jobid: { _eq: $jobId } }
_set: { canceled: true }
) {
returning {
id
canceled
}
}
}
`;
@@ -1766,13 +1780,12 @@ export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
order_by: $order
where: { status: { _in: $statusList } }
) {
comment
ownr_fn
ownr_ln
ownr_co_nm
ownerid
ownr_ph1
ownr_ph2
ownr_ea
plate_no
plate_st
v_vin
@@ -1781,32 +1794,16 @@ export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
v_make_desc
v_color
vehicleid
actual_completion
actual_delivery
actual_in
id
ins_co_nm
ins_ct_fn
ins_ct_ln
ins_ph1
ins_ea
est_co_nm
est_ph1
est_ea
est_ct_fn
est_ct_ln
clm_no
clm_total
owner_owing
ro_number
po_number
scheduled_completion
scheduled_in
scheduled_delivery
status
updated_at
ded_amt
vehicleid
}
search_jobs_aggregate(
args: { search: $search }

View File

@@ -69,6 +69,7 @@ export const QUERY_PARTS_ORDER_OEC = gql`
db_price
line_desc
quantity
part_type
}
job {
bodyshop{

View File

@@ -87,6 +87,7 @@ export const QUERY_ALL_VENDORS_FOR_ORDER = gql`
discount
email
active
phone
}
jobs(where: { id: { _eq: $jobId } }) {
v_make_desc

View File

@@ -70,7 +70,12 @@ export function CourtesyCarCreateContainer({
return (
<RbacWrapper action="courtesycar:create">
<Form form={form} autoComplete="new-password" onFinish={handleFinish}>
<Form
form={form}
autoComplete="new-password"
onFinish={handleFinish}
layout="vertical"
>
<CourtesyCarFormComponent form={form} saveLoading={loading} />
</Form>
</RbacWrapper>

View File

@@ -1,5 +1,5 @@
import { useQuery } from "@apollo/client";
import { Col, Row } from "antd";
import { Col, Row, Space } from "antd";
import moment from "moment";
import queryString from "query-string";
import React, { useEffect } from "react";
@@ -11,6 +11,7 @@ import AlertComponent from "../../components/alert/alert.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import TimeTicketsDatesSelector from "../../components/ticket-tickets-dates-selector/time-tickets-dates-selector.component";
import TimeTicketList from "../../components/time-ticket-list/time-ticket-list.component";
import TimeTicketsPayrollTable from "../../components/time-tickets-payroll-table/time-tickets-payroll-table.component";
import TimeTicketsSummaryEmployees from "../../components/time-tickets-summary-employees/time-tickets-summary-employees.component";
import { QUERY_TIME_TICKETS_IN_RANGE } from "../../graphql/timetickets.queries";
import {
@@ -68,7 +69,12 @@ export function TimeTicketsContainer({
<TimeTicketList
loading={loading}
timetickets={data ? data.timetickets : []}
extra={<TimeTicketsDatesSelector />}
extra={
<Space wrap>
<TimeTicketsPayrollTable />
<TimeTicketsDatesSelector />
</Space>
}
/>
</Col>
<Col span={24}>

View File

@@ -41,6 +41,7 @@ import UserActionTypes from "./user.types";
import axios from "axios";
import { messaging } from "../../firebase/firebase.utils";
import { getToken } from "firebase/messaging";
export function* onEmailSignInStart() {
yield takeLatest(UserActionTypes.EMAIL_SIGN_IN_START, signInWithEmail);
}
@@ -266,6 +267,12 @@ export function* onSetShopDetails() {
export function* SetAuthLevelFromShopDetails({ payload }) {
try {
const userEmail = yield select((state) => state.user.currentUser.email);
try {
console.log("Setting shop timezone.");
// moment.tz.setDefault(payload.timezone);
} catch (error) {
console.log(error);
}
factory.client(payload.imexshopid);

View File

@@ -21,7 +21,7 @@
"actions": {
"block": "Block Day",
"calculate": "Calculate SMART Dates",
"cancel": "Cancel",
"cancel": "Cancel Appointment",
"intake": "Intake",
"new": "New Appointment",
"preview": "Preview",
@@ -183,6 +183,7 @@
"federal_tax": "Federal Tax",
"iouexists": "An IOU exists that is associated to this RO.",
"local_tax": "Local Tax",
"markexported": "Mark Exported",
"markforreexport": "Mark for Re-export",
"new": "New Bill",
"noneselected": "No bill selected.",
@@ -197,6 +198,7 @@
"created": "Invoice added successfully.",
"deleted": "Bill deleted successfully.",
"exported": "Bill(s) exported successfully.",
"markexported": "Bill marked as exported.",
"reexport": "Bill marked for re-export."
},
"validation": {
@@ -244,6 +246,7 @@
"dms": {
"cashierid": "Cashier ID",
"default_journal": "Default Journal",
"disablecontactvehiclecreation": "Disable Contact & Vehicle Updates/Creation",
"dms_acctnumber": "DMS Account #",
"dms_wip_acctnumber": "DMS W.I.P. Account #",
"generic_customer_number": "Generic Customer Number",
@@ -272,6 +275,8 @@
"mash": "Job Costing - Shop Materials Hourly Cost Rate"
},
"lastnumberworkingdays": "Scoreboard - Last Number of Working Days",
"logo_img_footer_margin": "Footer Margin (px)",
"logo_img_header_margin": "Header Margin (px)",
"logo_img_path": "Shop Logo",
"logo_img_path_height": "Logo Image Height",
"logo_img_path_width": "Logo Image Width",
@@ -280,6 +285,7 @@
"md_classes": "Classes",
"md_ded_notes": "Deductible Notes",
"md_email_cc": "Auto Email CC: $t(printcenter.subjects.jobs.{{template}})",
"md_from_emails": "Additional From Emails",
"md_hour_split": {
"paint": "Paint Hour Split",
"prep": "Prep Hour Split"
@@ -450,6 +456,9 @@
"label": "Label",
"templates": "Templates"
},
"ss_configuration": {
"dailyhrslimit": "Daily Incoming Hours Limit"
},
"ssbuckets": {
"gte": "Greater Than/Equal to (hrs)",
"id": "ID",
@@ -483,6 +492,7 @@
"production_statuses": "Production Statuses"
},
"target_touchtime": "Target Touch Time",
"timezone": "Timezone",
"tt_allow_post_to_invoiced": "Allow Time Tickets to be posted to Invoiced & Exported Jobs",
"use_fippa": "Use FIPPA for Names on Generated Documents?",
"website": "Website",
@@ -821,6 +831,7 @@
},
"fields": {
"cc": "CC",
"from": "From",
"subject": "Subject",
"to": "To"
},
@@ -1242,6 +1253,7 @@
"class": "Class",
"clm_no": "Claim #",
"clm_total": "Claim Total",
"comment": "Comment",
"customerowing": "Customer Owing",
"date_estimated": "Date Estimated",
"date_exported": "Exported",
@@ -1249,7 +1261,9 @@
"date_last_contacted": "Last Contacted Date",
"date_next_contact": "Next Contact Date",
"date_open": "Open",
"date_rentalresp": "Shop Rental Responsibility Start",
"date_scheduled": "Scheduled",
"date_towin": "Towed In",
"ded_amt": "Deductible",
"ded_note": "Deductible Note",
"ded_status": "Deductible Status",
@@ -1482,8 +1496,10 @@
"closejob": "Close Job {{ro_number}}",
"contracts": "CC Contracts",
"cost": "Cost",
"cost_Additional": "Cost - Additional",
"cost_labor": "Cost - Labor",
"cost_parts": "Cost - Parts",
"cost_sublet": "Cost - Sublet",
"costs": "Costs",
"create": {
"jobinfo": "Job Info",
@@ -1553,7 +1569,7 @@
"partstotal": "Parts Total (ex. Taxes)",
"plitooltips": {
"billtotal": "The total amount of all bill lines that have been posted against this RO (not including credits, taxes, or labor adjustments).",
"creditmemos": "The total amount of all credit memos entered. This amount does not reflect any parts returns created.",
"creditmemos": "The total amount of all returns created. This amount does not reflect credit memos that have been posted.",
"creditsnotreceived": "The total amount of returns created for this job that do not have a corresponding credit memo posted. An amount greater than $0 indicates that vendors have not provided requested credit memos.",
"discrep1": "If the discrepancy is not $0, you may have one of the following: <br/><br/>\n\n<ul>\n<li>Too many bills/bill lines that have been posted against this RO. Check to make sure every bill posted on this RO is correctly posted and assigned.</li>\n<li>You do not have the latest supplement imported, or, a supplement must be submitted and then imported.</li>\n<li>You have posted a bill line to labor.</li>\n</ul>\n<br/>\n<i>There may be additional issues not listed above that prevent this job from reconciling.</i>",
"discrep2": "If the discrepancy is not $0, you may have one of the following: <br/><br/>\n\n<ul>\n<li>Used an incorrect rate when deducting from labor.</li>\n<li>An outstanding imbalance higher in the reconciliation process.</li>\n</ul>\n<br/>\n<i>There may be additional issues not listed above that prevent this job from reconciling.</i>",
@@ -1581,8 +1597,10 @@
"relatedros": "Related ROs",
"returntotals": "Return Totals",
"rosaletotal": "RO Parts Total",
"sale_additional": "Sales - Additional",
"sale_labor": "Sales - Labor",
"sale_parts": "Sales - Parts & Sublet",
"sale_parts": "Sales - Parts",
"sale_sublet": "Sales - Sublet",
"sales": "Sales",
"savebeforeconversion": "You have unsaved changes on the job. Please save them before converting it. ",
"scheduledinchange": "The scheduled in is based off the latest appointment. To change this date, please schedule or reschedule the job. ",
@@ -1593,6 +1611,7 @@
"supplementnote": "The job had a supplement imported.",
"suspended": "SUSPENDED",
"suspense": "Suspense",
"threshhold": "Max Threshold: ${{amount}}",
"total_cost": "Total Cost",
"total_cust_payable": "Total Customer Amount Payable",
"total_repairs": "Total Repairs",
@@ -1900,6 +1919,7 @@
"order_date": "Order Date",
"order_number": "Order Number",
"orderedby": "Ordered By",
"part_type": "Type",
"quantity": "Qty.",
"return": "Return",
"status": "Status"
@@ -2058,6 +2078,7 @@
"labels": "Labels",
"position": "Starting Position"
},
"mechanical_authorization": "Mechanical Authorization",
"mpi_animal_checklist": "MPI - Animal Checklist",
"mpi_eglass_auth": "MPI - eGlass Auth",
"mpi_final_acct_sheet": "MPI - Final Accounting Sheet",
@@ -2109,7 +2130,8 @@
"title": "Print Center"
},
"payments": {
"ca_bc_etf_table": "ICBC ETF Table"
"ca_bc_etf_table": "ICBC ETF Table",
"exported_payroll": "Payroll Table"
},
"subjects": {
"jobs": {
@@ -2150,6 +2172,7 @@
"bodypriority": "B/P",
"cardsettings": "Card Settings",
"clm_no": "Claim Number",
"comment": "Comment",
"compact": "Compact Cards",
"detailpriority": "D/P",
"employeeassignments": "Employee Assignments",
@@ -2230,7 +2253,7 @@
"gsr_by_csr": "Gross Sales by CSR",
"gsr_by_delivery_date": "Gross Sales by Delivery Date",
"gsr_by_estimator": "Gross Sales by Estimator",
"gsr_by_exported_date": "Gross Sales by Export Date",
"gsr_by_exported_date": "Exported Gross Sales",
"gsr_by_ins_co": "Gross Sales by Insurance Company",
"gsr_by_make": "Gross Sales by Vehicle Make",
"gsr_by_referral": "Gross Sales by Referral Source",
@@ -2268,6 +2291,7 @@
"production_by_csr": "Production by CSR",
"production_by_last_name": "Production by Last Name",
"production_by_repair_status": "Production by Status",
"production_by_repair_status_one": "Production filtered by Status",
"production_by_ro": "Production by RO",
"production_by_target_date": "Production by Target Date",
"production_by_technician": "Production by Technician",
@@ -2315,9 +2339,12 @@
},
"labels": {
"asoftodaytarget": "As of Today",
"dailyactual": "Actual (D)",
"dailytarget": "Daily",
"monthlytarget": "Monthly",
"targets": "Targets",
"todateactual": "Actual (MTD)",
"weeklyactual": "Actual (W)",
"weeklytarget": "Weekly",
"workingdays": "Working Days / Month"
},
@@ -2406,6 +2433,10 @@
"clockedout": "Clocked out successfully.",
"created": "Time ticket entered successfully.",
"deleted": "Time ticket deleted successfully."
},
"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."
}
},
"titles": {
@@ -2559,6 +2590,7 @@
},
"labels": {
"fromvehicle": "Historical Vehicle Record",
"novehinfo": "No Vehicle Information",
"relatedjobs": "Related Jobs",
"updatevehicle": "Update Vehicle Information"
},
@@ -2584,7 +2616,7 @@
"country": "Country",
"discount": "Discount % (as decimal)",
"display_name": "Display Name",
"due_date": "Payment Due Date",
"due_date": "Payment Due Date (# of days)",
"email": "Contact Email",
"favorite": "Favorite?",
"lkq": "LKQ",

View File

@@ -183,6 +183,7 @@
"federal_tax": "",
"iouexists": "",
"local_tax": "",
"markexported": "",
"markforreexport": "",
"new": "",
"noneselected": "",
@@ -197,6 +198,7 @@
"created": "",
"deleted": "",
"exported": "",
"markexported": "",
"reexport": ""
},
"validation": {
@@ -244,6 +246,7 @@
"dms": {
"cashierid": "",
"default_journal": "",
"disablecontactvehiclecreation": "",
"dms_acctnumber": "",
"dms_wip_acctnumber": "",
"generic_customer_number": "",
@@ -272,6 +275,8 @@
"mash": ""
},
"lastnumberworkingdays": "",
"logo_img_footer_margin": "",
"logo_img_header_margin": "",
"logo_img_path": "",
"logo_img_path_height": "",
"logo_img_path_width": "",
@@ -280,6 +285,7 @@
"md_classes": "",
"md_ded_notes": "",
"md_email_cc": "",
"md_from_emails": "",
"md_hour_split": {
"paint": "",
"prep": ""
@@ -450,6 +456,9 @@
"label": "",
"templates": ""
},
"ss_configuration": {
"dailyhrslimit": ""
},
"ssbuckets": {
"gte": "",
"id": "",
@@ -483,6 +492,7 @@
"production_statuses": ""
},
"target_touchtime": "",
"timezone": "",
"tt_allow_post_to_invoiced": "",
"use_fippa": "",
"website": "",
@@ -821,6 +831,7 @@
},
"fields": {
"cc": "",
"from": "",
"subject": "",
"to": ""
},
@@ -1242,6 +1253,7 @@
"class": "",
"clm_no": "Reclamación #",
"clm_total": "Reclamar total",
"comment": "",
"customerowing": "Cliente debido",
"date_estimated": "Fecha estimada",
"date_exported": "Exportado",
@@ -1249,7 +1261,9 @@
"date_last_contacted": "",
"date_next_contact": "",
"date_open": "Abierto",
"date_rentalresp": "",
"date_scheduled": "Programado",
"date_towin": "",
"ded_amt": "Deducible",
"ded_note": "",
"ded_status": "Estado deducible",
@@ -1482,8 +1496,10 @@
"closejob": "",
"contracts": "",
"cost": "",
"cost_Additional": "",
"cost_labor": "",
"cost_parts": "",
"cost_sublet": "",
"costs": "",
"create": {
"jobinfo": "",
@@ -1581,8 +1597,10 @@
"relatedros": "",
"returntotals": "",
"rosaletotal": "",
"sale_additional": "",
"sale_labor": "",
"sale_parts": "",
"sale_sublet": "",
"sales": "",
"savebeforeconversion": "",
"scheduledinchange": "",
@@ -1593,6 +1611,7 @@
"supplementnote": "",
"suspended": "",
"suspense": "",
"threshhold": "",
"total_cost": "",
"total_cust_payable": "",
"total_repairs": "",
@@ -1900,6 +1919,7 @@
"order_date": "",
"order_number": "",
"orderedby": "",
"part_type": "",
"quantity": "",
"return": "",
"status": ""
@@ -2058,6 +2078,7 @@
"labels": "",
"position": ""
},
"mechanical_authorization": "",
"mpi_animal_checklist": "",
"mpi_eglass_auth": "",
"mpi_final_acct_sheet": "",
@@ -2109,7 +2130,8 @@
"title": ""
},
"payments": {
"ca_bc_etf_table": ""
"ca_bc_etf_table": "",
"exported_payroll": ""
},
"subjects": {
"jobs": {
@@ -2150,6 +2172,7 @@
"bodypriority": "",
"cardsettings": "",
"clm_no": "",
"comment": "",
"compact": "",
"detailpriority": "",
"employeeassignments": "",
@@ -2268,6 +2291,7 @@
"production_by_csr": "",
"production_by_last_name": "",
"production_by_repair_status": "",
"production_by_repair_status_one": "",
"production_by_ro": "",
"production_by_target_date": "",
"production_by_technician": "",
@@ -2315,9 +2339,12 @@
},
"labels": {
"asoftodaytarget": "",
"dailyactual": "",
"dailytarget": "",
"monthlytarget": "",
"targets": "",
"todateactual": "",
"weeklyactual": "",
"weeklytarget": "",
"workingdays": ""
},
@@ -2406,6 +2433,10 @@
"clockedout": "",
"created": "",
"deleted": ""
},
"validation": {
"clockoffmustbeafterclockon": "",
"clockoffwithoutclockon": ""
}
},
"titles": {
@@ -2559,6 +2590,7 @@
},
"labels": {
"fromvehicle": "",
"novehinfo": "",
"relatedjobs": "",
"updatevehicle": ""
},

View File

@@ -183,6 +183,7 @@
"federal_tax": "",
"iouexists": "",
"local_tax": "",
"markexported": "",
"markforreexport": "",
"new": "",
"noneselected": "",
@@ -197,6 +198,7 @@
"created": "",
"deleted": "",
"exported": "",
"markexported": "",
"reexport": ""
},
"validation": {
@@ -244,6 +246,7 @@
"dms": {
"cashierid": "",
"default_journal": "",
"disablecontactvehiclecreation": "",
"dms_acctnumber": "",
"dms_wip_acctnumber": "",
"generic_customer_number": "",
@@ -272,6 +275,8 @@
"mash": ""
},
"lastnumberworkingdays": "",
"logo_img_footer_margin": "",
"logo_img_header_margin": "",
"logo_img_path": "",
"logo_img_path_height": "",
"logo_img_path_width": "",
@@ -280,6 +285,7 @@
"md_classes": "",
"md_ded_notes": "",
"md_email_cc": "",
"md_from_emails": "",
"md_hour_split": {
"paint": "",
"prep": ""
@@ -450,6 +456,9 @@
"label": "",
"templates": ""
},
"ss_configuration": {
"dailyhrslimit": ""
},
"ssbuckets": {
"gte": "",
"id": "",
@@ -483,6 +492,7 @@
"production_statuses": ""
},
"target_touchtime": "",
"timezone": "",
"tt_allow_post_to_invoiced": "",
"use_fippa": "",
"website": "",
@@ -821,6 +831,7 @@
},
"fields": {
"cc": "",
"from": "",
"subject": "",
"to": ""
},
@@ -1242,6 +1253,7 @@
"class": "",
"clm_no": "Prétendre #",
"clm_total": "Total réclamation",
"comment": "",
"customerowing": "Client propriétaire",
"date_estimated": "Date estimée",
"date_exported": "Exportés",
@@ -1249,7 +1261,9 @@
"date_last_contacted": "",
"date_next_contact": "",
"date_open": "Ouvrir",
"date_rentalresp": "",
"date_scheduled": "Prévu",
"date_towin": "",
"ded_amt": "Déductible",
"ded_note": "",
"ded_status": "Statut de franchise",
@@ -1482,8 +1496,10 @@
"closejob": "",
"contracts": "",
"cost": "",
"cost_Additional": "",
"cost_labor": "",
"cost_parts": "",
"cost_sublet": "",
"costs": "",
"create": {
"jobinfo": "",
@@ -1581,8 +1597,10 @@
"relatedros": "",
"returntotals": "",
"rosaletotal": "",
"sale_additional": "",
"sale_labor": "",
"sale_parts": "",
"sale_sublet": "",
"sales": "",
"savebeforeconversion": "",
"scheduledinchange": "",
@@ -1593,6 +1611,7 @@
"supplementnote": "",
"suspended": "",
"suspense": "",
"threshhold": "",
"total_cost": "",
"total_cust_payable": "",
"total_repairs": "",
@@ -1900,6 +1919,7 @@
"order_date": "",
"order_number": "",
"orderedby": "",
"part_type": "",
"quantity": "",
"return": "",
"status": ""
@@ -2058,6 +2078,7 @@
"labels": "",
"position": ""
},
"mechanical_authorization": "",
"mpi_animal_checklist": "",
"mpi_eglass_auth": "",
"mpi_final_acct_sheet": "",
@@ -2109,7 +2130,8 @@
"title": ""
},
"payments": {
"ca_bc_etf_table": ""
"ca_bc_etf_table": "",
"exported_payroll": ""
},
"subjects": {
"jobs": {
@@ -2150,6 +2172,7 @@
"bodypriority": "",
"cardsettings": "",
"clm_no": "",
"comment": "",
"compact": "",
"detailpriority": "",
"employeeassignments": "",
@@ -2268,6 +2291,7 @@
"production_by_csr": "",
"production_by_last_name": "",
"production_by_repair_status": "",
"production_by_repair_status_one": "",
"production_by_ro": "",
"production_by_target_date": "",
"production_by_technician": "",
@@ -2315,9 +2339,12 @@
},
"labels": {
"asoftodaytarget": "",
"dailyactual": "",
"dailytarget": "",
"monthlytarget": "",
"targets": "",
"todateactual": "",
"weeklyactual": "",
"weeklytarget": "",
"workingdays": ""
},
@@ -2406,6 +2433,10 @@
"clockedout": "",
"created": "",
"deleted": ""
},
"validation": {
"clockoffmustbeafterclockon": "",
"clockoffwithoutclockon": ""
}
},
"titles": {
@@ -2559,6 +2590,7 @@
},
"labels": {
"fromvehicle": "",
"novehinfo": "",
"relatedjobs": "",
"updatevehicle": ""
},

View File

@@ -17,19 +17,42 @@ const Templates = TemplateList();
export default async function RenderTemplate(
templateObject,
bodyshop,
renderAsHtml = false
renderAsHtml = false,
renderAsExcel = false
) {
//Query assets that match the template name. Must be in format <<templateName>>.query
let { contextData, useShopSpecificTemplate } = await fetchContextData(
templateObject
);
const { ignoreCustomMargins } = Templates[templateObject.name];
let reportRequest = {
template: {
name: useShopSpecificTemplate
? `/${bodyshop.imexshopid}/${templateObject.name}`
: `/${templateObject.name}`,
...(renderAsHtml ? {} : { recipe: "chrome-pdf" }),
...(renderAsHtml
? {}
: {
recipe: "chrome-pdf",
...(!ignoreCustomMargins && {
chrome: {
marginTop:
bodyshop.logo_img_path &&
bodyshop.logo_img_path.headerMargin &&
bodyshop.logo_img_path.headerMargin > 36
? bodyshop.logo_img_path.headerMargin
: "36px",
marginBottom:
bodyshop.logo_img_path &&
bodyshop.logo_img_path.footerMargin &&
bodyshop.logo_img_path.footerMargin > 36
? bodyshop.logo_img_path.footerMargin
: "36px",
},
}),
}),
...(renderAsExcel ? { recipe: "html-to-xlsx" } : {}),
},
data: {
...contextData,
@@ -37,7 +60,7 @@ export default async function RenderTemplate(
...templateObject.context,
headerpath: `/${bodyshop.imexshopid}/header.html`,
bodyshop: bodyshop,
offset: moment().utcOffset(),
offset: bodyshop.timezone, //moment().utcOffset(),
},
};
@@ -119,7 +142,25 @@ export async function RenderTemplates(
name: rootTemplate.useShopSpecificTemplate
? `/${bodyshop.imexshopid}/${rootTemplate.templateObject.name}`
: `/${rootTemplate.templateObject.name}`,
...(renderAsHtml ? {} : { recipe: "chrome-pdf" }),
...(renderAsHtml
? {}
: {
recipe: "chrome-pdf",
chrome: {
marginTop:
bodyshop.logo_img_path &&
bodyshop.logo_img_path.headerMargin &&
bodyshop.logo_img_path.headerMargin > 36
? bodyshop.logo_img_path.headerMargin
: "36px",
marginBottom:
bodyshop.logo_img_path &&
bodyshop.logo_img_path.footerMargin &&
bodyshop.logo_img_path.footerMargin > 36
? bodyshop.logo_img_path.footerMargin
: "36px",
},
}),
pdfOperations: templateAndData.map((template) => {
return {
template: {
@@ -182,6 +223,9 @@ export const GenerateDocument = async (
template,
})
);
} else if (sendType === "x") {
console.log("excel");
await RenderTemplate(template, bodyshop, false, true);
} else {
await RenderTemplate(template, bodyshop);
}

View File

@@ -37,6 +37,14 @@ export const TemplateList = (type, context) => {
disabled: false,
group: "authorization",
},
mechanical_authorization: {
title: i18n.t("printcenter.jobs.mechanical_authorization"),
description: "Diagnostic Authorization",
subject: i18n.t("printcenter.jobs.mechanical_authorization"),
key: "mechanical_authorization",
disabled: false,
group: "authorization",
},
appointment_reminder: {
title: i18n.t("printcenter.jobs.appointment_reminder"),
description: "All Jobs Notes",
@@ -363,6 +371,7 @@ export const TemplateList = (type, context) => {
subject: i18n.t("printcenter.jobs.parts_label_single"),
disabled: false,
group: "ro",
ignoreCustomMargins: true,
},
envelope_return_address: {
title: i18n.t("printcenter.jobs.envelope_return_address"),
@@ -371,6 +380,7 @@ export const TemplateList = (type, context) => {
key: "envelope_return_address",
disabled: false,
group: "ro",
ignoreCustomMargins: true,
},
sgi_certificate_of_repairs: {
title: i18n.t("printcenter.jobs.sgi_certificate_of_repairs"),
@@ -1635,6 +1645,13 @@ export const TemplateList = (type, context) => {
key: "ca_bc_etf_table",
disabled: false,
},
exported_payroll: {
title: i18n.t("printcenter.payments.exported_payroll"),
description: "Est Detail",
subject: i18n.t("printcenter.payments.exported_payroll"),
key: "exported_payroll",
disabled: false,
},
production_by_technician_one: {
title: i18n.t(
"reportcenter.templates.production_by_technician_one"
@@ -1657,6 +1674,18 @@ export const TemplateList = (type, context) => {
//idtype: "vendor",
disabled: false,
},
production_by_repair_status_one: {
title: i18n.t(
"reportcenter.templates.production_by_repair_status_one"
),
description: "",
subject: i18n.t(
"reportcenter.templates.production_by_repair_status_one"
),
key: "production_by_repair_status_one",
//idtype: "vendor",
disabled: false,
},
}
: {}),
};

View File

@@ -9460,7 +9460,14 @@ moment-business-days@^1.2.0:
resolved "https://registry.yarnpkg.com/moment-business-days/-/moment-business-days-1.2.0.tgz#6172f9f38dbf443c2f859baabeabbd2935f63d65"
integrity sha512-QJlceLfMSxy/jZSOgJYCKeKw+qGYHj8W0jMa/fYruyoJ85+bJuLRiYv5DIaflyuRipmYRfD4kDlSwVYteLN+Jw==
moment@^2.24.0, moment@^2.25.3:
moment-timezone@^0.5.34:
version "0.5.34"
resolved "https://registry.yarnpkg.com/moment-timezone/-/moment-timezone-0.5.34.tgz#a75938f7476b88f155d3504a9343f7519d9a405c"
integrity sha512-3zAEHh2hKUs3EXLESx/wsgw6IQdusOT8Bxm3D9UrHPQR7zlMmzwybC8zHEM1tQ4LJwP7fcxrWr8tuBg05fFCbg==
dependencies:
moment ">= 2.9.0"
"moment@>= 2.9.0", moment@^2.24.0, moment@^2.25.3:
version "2.29.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==

View File

@@ -815,6 +815,8 @@
- email
- enforce_class
- enforce_referral
- entegral_configuration
- entegral_id
- features
- federal_tax_id
- id
@@ -832,6 +834,7 @@
- md_email_cc
- md_estimators
- md_filehandlers
- md_from_emails
- md_hour_split
- md_ins_cos
- md_jobline_presets
@@ -858,6 +861,7 @@
- shopname
- shoprates
- speedprint
- ss_configuration
- ssbuckets
- state
- state_tax_id
@@ -866,6 +870,7 @@
- target_touchtime
- template_header
- textid
- timezone
- tt_allow_post_to_invoiced
- updated_at
- use_fippa
@@ -912,6 +917,7 @@
- md_email_cc
- md_estimators
- md_filehandlers
- md_from_emails
- md_hour_split
- md_ins_cos
- md_jobline_presets
@@ -925,6 +931,7 @@
- md_referral_sources
- md_responsibility_centers
- md_ro_statuses
- pbs_configuration
- phone
- prodtargethrs
- production_config
@@ -934,10 +941,12 @@
- shopname
- shoprates
- speedprint
- ss_configuration
- ssbuckets
- state
- state_tax_id
- target_touchtime
- timezone
- tt_allow_post_to_invoiced
- updated_at
- use_fippa
@@ -2706,6 +2715,7 @@
- clm_title
- clm_total
- clm_zip
- comment
- converted
- created_at
- cust_pr
@@ -2715,7 +2725,9 @@
- date_last_contacted
- date_next_contact
- date_open
- date_rentalresp
- date_scheduled
- date_towin
- ded_amt
- ded_note
- ded_status
@@ -2798,6 +2810,7 @@
- loss_desc
- loss_of_use
- loss_type
- materials
- other_amount_payable
- owner_owing
- ownerid
@@ -2962,6 +2975,7 @@
- clm_title
- clm_total
- clm_zip
- comment
- converted
- created_at
- cust_pr
@@ -2971,7 +2985,9 @@
- date_last_contacted
- date_next_contact
- date_open
- date_rentalresp
- date_scheduled
- date_towin
- ded_amt
- ded_note
- ded_status
@@ -3054,6 +3070,7 @@
- loss_desc
- loss_of_use
- loss_type
- materials
- other_amount_payable
- owner_owing
- ownerid
@@ -3228,6 +3245,7 @@
- clm_title
- clm_total
- clm_zip
- comment
- converted
- created_at
- cust_pr
@@ -3237,7 +3255,9 @@
- date_last_contacted
- date_next_contact
- date_open
- date_rentalresp
- date_scheduled
- date_towin
- ded_amt
- ded_note
- ded_status
@@ -3320,6 +3340,7 @@
- loss_desc
- loss_of_use
- loss_type
- materials
- other_amount_payable
- owner_owing
- ownerid

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "appointments_bodyshopid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "appointments_bodyshopid" on
"public"."appointments" using btree ("bodyshopid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "appointments_jobid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "appointments_jobid" on
"public"."appointments" using btree ("jobid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "appointments_start";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "appointments_start" on
"public"."appointments" using btree ("start");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "appointments_end";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "appointments_end" on
"public"."appointments" using btree ("end");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "associations_bodyshopid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "associations_bodyshopid" on
"public"."associations" using btree ("shopid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "associations_useremail";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "associations_useremail" on
"public"."associations" using btree ("useremail");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "invoicelines_billid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "invoicelines_billid" on
"public"."billlines" using btree ("billid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "invoicelines_jobid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "invoicelines_jobid" on
"public"."billlines" using btree ("joblineid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "bills_jobid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "bills_jobid" on
"public"."bills" using btree ("jobid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "conversations_shopid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "conversations_shopid" on
"public"."conversations" using btree ("bodyshopid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "documents_shopid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "documents_shopid" on
"public"."documents" using btree ("bodyshopid");

View File

@@ -0,0 +1 @@
DROP INDEX IF EXISTS "documents_jobid";

View File

@@ -0,0 +1,2 @@
CREATE INDEX "documents_jobid" on
"public"."documents" using btree ("jobid");

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