Compare commits
160 Commits
release/20
...
feature/pb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
09187bdb7f | ||
|
|
2aed392fbe | ||
|
|
1a0054a911 | ||
|
|
6e6f3d3d3e | ||
|
|
29df140680 | ||
|
|
f37c67a122 | ||
|
|
e53c9aab72 | ||
|
|
385ad06adc | ||
|
|
d1e2d943a9 | ||
|
|
90aa3557b7 | ||
|
|
8891167183 | ||
|
|
6631e645df | ||
|
|
b7f202969b | ||
|
|
1dc3353ecc | ||
|
|
b1a3f1a7b8 | ||
|
|
89f3a26635 | ||
|
|
506fe9b1af | ||
|
|
37c898d3ce | ||
|
|
e4eac5714a | ||
|
|
9d4a59ca16 | ||
|
|
8ec524061a | ||
|
|
434ed46b5a | ||
|
|
3ece5e0ba2 | ||
|
|
52a383ffb7 | ||
|
|
8ad1d5929a | ||
|
|
445c01499b | ||
|
|
0b05be841d | ||
|
|
6bcb5f2af5 | ||
|
|
7482751c5b | ||
|
|
7a025fff42 | ||
|
|
602fe36638 | ||
|
|
da08fc74f1 | ||
|
|
14af45baf0 | ||
|
|
420a88c505 | ||
|
|
f3c44f8dd1 | ||
|
|
c72111e18b | ||
|
|
1ca2870912 | ||
|
|
db9744e1e5 | ||
|
|
e700095551 | ||
|
|
99196a77ed | ||
|
|
289a8222a0 | ||
|
|
dc10f8d35b | ||
|
|
f448232fe7 | ||
|
|
4baf4b4afa | ||
|
|
1785093023 | ||
|
|
0d65f8d894 | ||
|
|
3d8c390291 | ||
|
|
f0a13856bc | ||
|
|
ad6394783d | ||
|
|
16e9843298 | ||
|
|
a4c949c376 | ||
|
|
0e0d5316b7 | ||
|
|
60cb6ee8fb | ||
|
|
7d3279d21a | ||
|
|
402d13ad99 | ||
|
|
e803f5a2d4 | ||
|
|
3989d0f1e2 | ||
|
|
161d476ab3 | ||
|
|
ce84a89cf3 | ||
|
|
1d210a9e52 | ||
|
|
660f463aea | ||
|
|
ad9f01111c | ||
|
|
1b885e4114 | ||
|
|
b56742bcb2 | ||
|
|
40d4d69a9a | ||
|
|
b54d5beb76 | ||
|
|
5cbcd440f5 | ||
|
|
1cdc34249a | ||
|
|
8bbb218777 | ||
|
|
755ac7f657 | ||
|
|
d7b884ff86 | ||
|
|
fda3620ed0 | ||
|
|
61ad9f0d58 | ||
|
|
804c8ad40a | ||
|
|
0ddf009f8f | ||
|
|
14309b5c96 | ||
|
|
57d9de469a | ||
|
|
404ade396c | ||
|
|
bdad6da6d9 | ||
|
|
e7ef3b94c1 | ||
|
|
c19c92ab7e | ||
|
|
944229bae3 | ||
|
|
661b05d9e3 | ||
|
|
4d1d471a66 | ||
|
|
3e84fbbaf4 | ||
|
|
c4e59c1a5e | ||
|
|
9ee8e9007a | ||
|
|
4d52a5c44a | ||
|
|
fff9073f9d | ||
|
|
71f0b8a005 | ||
|
|
d2b965f79e | ||
|
|
a02aa71a95 | ||
|
|
7562bf5c95 | ||
|
|
f9521483e2 | ||
|
|
ca85858885 | ||
|
|
c7b3a94533 | ||
|
|
b010c9ecb0 | ||
|
|
0b98d04bac | ||
|
|
e25e388e59 | ||
|
|
10654b7916 | ||
|
|
ff049ad3e8 | ||
|
|
3572fff2c1 | ||
|
|
774e4cdf94 | ||
|
|
65ade5cab8 | ||
|
|
bf21a073fb | ||
|
|
851f1c265f | ||
|
|
51f3b5927b | ||
|
|
42c779f368 | ||
|
|
c104ee4fd9 | ||
|
|
0b2efa31b5 | ||
|
|
17baa8fcb2 | ||
|
|
e550baf59d | ||
|
|
fd53eb92e6 | ||
|
|
6521c0bfb8 | ||
|
|
50489dd682 | ||
|
|
220afa5add | ||
|
|
9d549b02fe | ||
|
|
ca2ded047b | ||
|
|
c423e61ce8 | ||
|
|
65550c7bf4 | ||
|
|
cdb4da9e5f | ||
|
|
b59a5303c6 | ||
|
|
9a72abbed0 | ||
|
|
762a5ff01b | ||
|
|
2f6571e703 | ||
|
|
80c90f1819 | ||
|
|
4b0c2c60a2 | ||
|
|
ee7d7d2f6a | ||
|
|
0ad670013b | ||
|
|
064a66aa66 | ||
|
|
f46c19b152 | ||
|
|
ea2c583b26 | ||
|
|
7bd2a90141 | ||
|
|
632549dd9d | ||
|
|
70ef274821 | ||
|
|
7d9759fda4 | ||
|
|
0fd06d5e4e | ||
|
|
4995e44e06 | ||
|
|
fd43d7d56d | ||
|
|
96f292f61c | ||
|
|
e899e4545f | ||
|
|
c62f5e3911 | ||
|
|
9f1d184081 | ||
|
|
29e596eedb | ||
|
|
6e28afda67 | ||
|
|
eca7e9fba1 | ||
|
|
aa2ac2b296 | ||
|
|
ce57752b95 | ||
|
|
63163c6459 | ||
|
|
2712ee5c0b | ||
|
|
2e28a4a790 | ||
|
|
4179943df6 | ||
|
|
d38dd67c2f | ||
|
|
0eacf9a840 | ||
|
|
a7c9dde5e3 | ||
|
|
891aa649e8 | ||
|
|
a8a0167123 | ||
|
|
4b55719f86 | ||
|
|
5387ff207c | ||
|
|
e3804b103b |
@@ -4283,6 +4283,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>md_ded_notes</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>
|
||||
@@ -6134,6 +6155,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>laa</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>lab</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -7099,6 +7141,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>color</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>default_arrived</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -7435,6 +7498,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>production_colors</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_statuses</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -7998,6 +8082,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>estimators</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>insurancecos</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -16857,6 +16962,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>prt_dsmk_m</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>prt_dsmk_p</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -16899,6 +17025,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>tax_part</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</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -17386,6 +17533,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>changestimator</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>convert</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -19548,6 +19716,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>date_last_contacted</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_open</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -19611,6 +19800,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>ded_note</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_status</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -21075,6 +21285,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>loss_of_use</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>ma2s</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -21348,6 +21579,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>ownr_ph2</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>paa</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -22282,6 +22534,48 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>referral_source_extra</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>referral_source_other</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>referralsource</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -25834,6 +26128,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>savebeforeconversion</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>scheduledinchange</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -29289,6 +29604,32 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>errors</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>inserting</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>fields</name>
|
||||
<children>
|
||||
@@ -29423,6 +29764,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>notetoadd</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>
|
||||
@@ -29826,6 +30188,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>ownr_ph2</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>ownr_st</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -30354,6 +30737,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>comments</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</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32869,6 +33273,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>iou_form</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>job_costing_ro</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32932,6 +33357,69 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>mpi_animal_checklist</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_eglass_auth</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_final_acct_sheet</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>paint_grid</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -36590,6 +37078,37 @@
|
||||
</folder_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>schedule</name>
|
||||
<children>
|
||||
<folder_node>
|
||||
<name>labels</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>manualevent</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>
|
||||
<name>scoreboard</name>
|
||||
<children>
|
||||
|
||||
@@ -4,37 +4,38 @@
|
||||
"private": true,
|
||||
"proxy": "http://localhost:5000",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.4.14",
|
||||
"@craco/craco": "^6.3.0",
|
||||
"@apollo/client": "^3.4.16",
|
||||
"@craco/craco": "^6.4.0",
|
||||
"@fingerprintjs/fingerprintjs": "^3.3.0",
|
||||
"@lourenci/react-kanban": "^2.1.0",
|
||||
"@openreplay/tracker": "^3.4.0",
|
||||
"@openreplay/tracker-assist": "^3.4.0",
|
||||
"@openreplay/tracker": "^3.4.4",
|
||||
"@openreplay/tracker-assist": "^3.4.4",
|
||||
"@openreplay/tracker-graphql": "^3.0.0",
|
||||
"@openreplay/tracker-redux": "^3.0.0",
|
||||
"@sentry/react": "^6.13.2",
|
||||
"@sentry/tracing": "^6.13.2",
|
||||
"@stripe/react-stripe-js": "^1.5.0",
|
||||
"@stripe/stripe-js": "^1.18.0",
|
||||
"@tanem/react-nprogress": "^3.0.79",
|
||||
"@sentry/react": "^6.13.3",
|
||||
"@sentry/tracing": "^6.13.3",
|
||||
"@splitsoftware/splitio-react": "^1.3.0",
|
||||
"@stripe/react-stripe-js": "^1.6.0",
|
||||
"@stripe/stripe-js": "^1.20.2",
|
||||
"@tanem/react-nprogress": "^3.0.81",
|
||||
"antd": "^4.16.13",
|
||||
"apollo-link-logger": "^2.0.0",
|
||||
"axios": "^0.21.4",
|
||||
"axios": "^0.23.0",
|
||||
"craco-less": "^1.20.0",
|
||||
"dinero.js": "^1.9.0",
|
||||
"dinero.js": "^1.9.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"enquire-js": "^0.2.1",
|
||||
"env-cmd": "^10.1.0",
|
||||
"exifr": "^7.1.3",
|
||||
"firebase": "^9.1.0",
|
||||
"graphql": "^15.6.0",
|
||||
"i18next": "^21.1.1",
|
||||
"firebase": "^9.1.3",
|
||||
"graphql": "^15.6.1",
|
||||
"i18next": "^21.3.3",
|
||||
"i18next-browser-languagedetector": "^6.1.2",
|
||||
"jsoneditor": "^9.5.6",
|
||||
"jsreport-browser-client-dist": "^1.3.0",
|
||||
"libphonenumber-js": "^1.9.34",
|
||||
"logrocket": "^2.0.0",
|
||||
"markerjs2": "^2.12.0",
|
||||
"libphonenumber-js": "^1.9.38",
|
||||
"logrocket": "^2.1.1",
|
||||
"markerjs2": "^2.15.0",
|
||||
"moment-business-days": "^1.2.0",
|
||||
"phone": "^3.1.8",
|
||||
"preval.macro": "^5.0.0",
|
||||
@@ -43,7 +44,7 @@
|
||||
"rc-queue-anim": "^2.0.0",
|
||||
"rc-scroll-anim": "^2.7.6",
|
||||
"react": "^17.0.1",
|
||||
"react-big-calendar": "^0.35.0",
|
||||
"react-big-calendar": "^0.38.0",
|
||||
"react-color": "^2.19.3",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^17.0.1",
|
||||
@@ -51,7 +52,7 @@
|
||||
"react-grid-gallery": "^0.5.5",
|
||||
"react-grid-layout": "^1.3.0",
|
||||
"react-i18next": "^11.12.0",
|
||||
"react-icons": "^4.2.0",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-number-format": "^4.7.3",
|
||||
"react-redux": "^7.2.5",
|
||||
"react-resizable": "^3.0.4",
|
||||
@@ -59,17 +60,17 @@
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-sublime-video": "^0.2.5",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"recharts": "^2.1.4",
|
||||
"recharts": "^2.1.5",
|
||||
"redux": "^4.1.1",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-saga": "^1.1.3",
|
||||
"redux-state-sync": "^3.1.2",
|
||||
"reselect": "^4.0.0",
|
||||
"sass": "^1.42.1",
|
||||
"socket.io-client": "^4.2.0",
|
||||
"styled-components": "^5.3.1",
|
||||
"sass": "^1.43.3",
|
||||
"socket.io-client": "^4.3.2",
|
||||
"styled-components": "^5.3.3",
|
||||
"subscriptions-transport-ws": "^0.9.18",
|
||||
"web-vitals": "^2.1.0",
|
||||
"web-vitals": "^2.1.2",
|
||||
"workbox-background-sync": "^6.3.0",
|
||||
"workbox-broadcast-update": "^6.3.0",
|
||||
"workbox-cacheable-response": "^6.3.0",
|
||||
@@ -114,7 +115,7 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sentry/webpack-plugin": "^1.17.1",
|
||||
"@sentry/webpack-plugin": "^1.18.3",
|
||||
"patch-package": "^6.4.7",
|
||||
"redux-logger": "^3.0.6",
|
||||
"source-map-explorer": "^2.5.2"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { ApolloProvider } from "@apollo/client";
|
||||
//import trackerRedux from "@openreplay/tracker-redux";
|
||||
import Tracker from "@openreplay/tracker";
|
||||
import trackerGraphQL from "@openreplay/tracker-graphql";
|
||||
import { SplitFactory, SplitSdk } from "@splitsoftware/splitio-react";
|
||||
import { ConfigProvider } from "antd";
|
||||
import enLocale from "antd/es/locale/en_US";
|
||||
import LogRocket from "logrocket";
|
||||
@@ -6,13 +10,11 @@ import moment from "moment";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
|
||||
import client from "../utils/GraphQLClient";
|
||||
import App from "./App";
|
||||
import trackerGraphQL from "@openreplay/tracker-graphql";
|
||||
//import trackerRedux from "@openreplay/tracker-redux";
|
||||
import Tracker from "@openreplay/tracker";
|
||||
//import trackerAssist from "@openreplay/tracker-assist";
|
||||
import { getCurrentUser } from "../firebase/firebase.utils";
|
||||
import client from "../utils/GraphQLClient";
|
||||
import App from "./App";
|
||||
|
||||
moment.locale("en-US");
|
||||
|
||||
export const tracker = new Tracker({
|
||||
@@ -24,8 +26,8 @@ export const tracker = new Tracker({
|
||||
// beaconSize: 10485760,
|
||||
onStart: async ({ sessionID }) => {
|
||||
const user = await getCurrentUser();
|
||||
tracker.setUserID(user.email);
|
||||
console.log("ORS SESSION ", sessionID, user.email);
|
||||
if (user) tracker.setUserID(user.email);
|
||||
console.log("ORS SESSION ", sessionID, user && user.email);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -36,6 +38,13 @@ export const recordGraphQL = tracker.use(trackerGraphQL());
|
||||
tracker.start();
|
||||
if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp");
|
||||
|
||||
export const factory = SplitSdk({
|
||||
core: {
|
||||
authorizationKey: process.env.REACT_APP_SPLIT_API,
|
||||
key: "anon",
|
||||
},
|
||||
});
|
||||
|
||||
export default function AppContainer() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -53,7 +62,9 @@ export default function AppContainer() {
|
||||
}}
|
||||
>
|
||||
<GlobalLoadingBar />
|
||||
<App />
|
||||
<SplitFactory factory={factory}>
|
||||
<App />
|
||||
</SplitFactory>
|
||||
</ConfigProvider>
|
||||
</ApolloProvider>
|
||||
);
|
||||
|
||||
@@ -124,3 +124,13 @@
|
||||
z-index: 2 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.react-kanban-column {
|
||||
background-color: #ddd !important;
|
||||
}
|
||||
|
||||
.production-list-table {
|
||||
td.ant-table-column-sort {
|
||||
background: unset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,26 @@ import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import PaymentExportButton from "../payment-export-button/payment-export-button.component";
|
||||
import PaymentsExportAllButton from "../payments-export-all-button/payments-export-all-button.component";
|
||||
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
export default function AccountingPayablesTableComponent({
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(AccountingPayablesTableComponent);
|
||||
|
||||
export function AccountingPayablesTableComponent({
|
||||
bodyshop,
|
||||
loading,
|
||||
payments,
|
||||
}) {
|
||||
@@ -163,6 +181,9 @@ export default function AccountingPayablesTableComponent({
|
||||
loadingCallback={setTransInProgress}
|
||||
completedCallback={setSelectedPayments}
|
||||
/>
|
||||
{bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && (
|
||||
<QboAuthorizeComponent />
|
||||
)}
|
||||
<Input
|
||||
value={state.search}
|
||||
onChange={handleSearch}
|
||||
|
||||
@@ -199,7 +199,7 @@ export function AccountingReceivablesTableComponent({
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
{!bodyshop.cdk_dealerid && (
|
||||
{!bodyshop.cdk_dealerid && !bodyshop.pbs_serialnumber && (
|
||||
<JobsExportAllButton
|
||||
jobIds={selectedJobs}
|
||||
disabled={transInProgress || selectedJobs.length === 0}
|
||||
|
||||
@@ -216,7 +216,7 @@ function BillEnterModalContainer({
|
||||
|
||||
if (enterAgain) {
|
||||
form.resetFields();
|
||||
form.setFieldsValue(formValues);
|
||||
form.setFieldsValue({ ...form.getFieldsValue(), billlines: [] });
|
||||
} else {
|
||||
toggleModalVisible();
|
||||
}
|
||||
|
||||
@@ -156,7 +156,6 @@ export function BillEnterModalLinesComponent({
|
||||
setFieldsValue({
|
||||
billlines: getFieldsValue("billlines").billlines.map(
|
||||
(item, idx) => {
|
||||
console.log("Checking", index, idx);
|
||||
if (idx === index) {
|
||||
console.log(
|
||||
"Found and setting.",
|
||||
@@ -502,9 +501,9 @@ const EditableCell = ({
|
||||
labelCol={{ span: 0 }}
|
||||
{...(formItemProps && formItemProps(record))}
|
||||
>
|
||||
{(formInput && formInput(record, record.key)) || children}
|
||||
{(formInput && formInput(record, record.name)) || children}
|
||||
</Form.Item>
|
||||
{additional && additional(record, record.key)}
|
||||
{additional && additional(record, record.name)}
|
||||
</Space>
|
||||
</td>
|
||||
);
|
||||
@@ -516,7 +515,7 @@ const EditableCell = ({
|
||||
name={dataIndex}
|
||||
{...(formItemProps && formItemProps(record))}
|
||||
>
|
||||
{(formInput && formInput(record, record.key)) || children}
|
||||
{(formInput && formInput(record, record.name)) || children}
|
||||
</Form.Item>
|
||||
</td>
|
||||
);
|
||||
|
||||
@@ -12,7 +12,18 @@ const BillLineSearchSelect = ({ options, disabled, ...restProps }, ref) => {
|
||||
disabled={disabled}
|
||||
ref={ref}
|
||||
showSearch
|
||||
optionFilterProp="line_desc"
|
||||
// optionFilterProp="line_desc"
|
||||
filterOption={(inputValue, option) => {
|
||||
console.log(inputValue);
|
||||
return (
|
||||
(option.line_desc &&
|
||||
option.line_desc
|
||||
.toLowerCase()
|
||||
.includes(inputValue.toLowerCase())) ||
|
||||
(option.oem_partno &&
|
||||
option.oem_partno.toLowerCase().includes(inputValue.toLowerCase()))
|
||||
);
|
||||
}}
|
||||
notFoundContent={"Removed."}
|
||||
{...restProps}
|
||||
>
|
||||
@@ -29,6 +40,7 @@ const BillLineSearchSelect = ({ options, disabled, ...restProps }, ref) => {
|
||||
part_type={item.part_type}
|
||||
line_desc={item.line_desc}
|
||||
part_qty={item.part_qty}
|
||||
oem_partno={item.oem_partno}
|
||||
style={{
|
||||
...(item.removed ? { textDecoration: "line-through" } : {}),
|
||||
}}
|
||||
|
||||
@@ -53,6 +53,7 @@ export function ContractConvertToRo({
|
||||
const billingLines = [];
|
||||
if (contractLength > 0)
|
||||
billingLines.push({
|
||||
manual_line:true,
|
||||
unq_seq: 1,
|
||||
line_no: 1,
|
||||
line_ref: 1,
|
||||
@@ -70,6 +71,7 @@ export function ContractConvertToRo({
|
||||
contract.kmend - contract.kmstart - contract.dailyfreekm * contractLength;
|
||||
if (mileageDiff > 0) {
|
||||
billingLines.push({
|
||||
manual_line:true,
|
||||
unq_seq: 2,
|
||||
line_no: 2,
|
||||
line_ref: 2,
|
||||
@@ -86,6 +88,7 @@ export function ContractConvertToRo({
|
||||
|
||||
if (values.refuelqty > 0) {
|
||||
billingLines.push({
|
||||
manual_line:true,
|
||||
unq_seq: 3,
|
||||
line_no: 3,
|
||||
line_ref: 3,
|
||||
@@ -101,6 +104,7 @@ export function ContractConvertToRo({
|
||||
}
|
||||
if (values.applyCleanupCharge) {
|
||||
billingLines.push({
|
||||
manual_line:true,
|
||||
unq_seq: 4,
|
||||
line_no: 4,
|
||||
line_ref: 4,
|
||||
@@ -117,6 +121,7 @@ export function ContractConvertToRo({
|
||||
if (contract.damagewaiver) {
|
||||
//Add for cleanup fee.
|
||||
billingLines.push({
|
||||
manual_line:true,
|
||||
unq_seq: 5,
|
||||
line_no: 5,
|
||||
line_ref: 5,
|
||||
|
||||
@@ -259,7 +259,6 @@ export function DmsPostForm({ bodyshop, socket, job }) {
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="dashed"
|
||||
disabled={!(fields.length < 3)}
|
||||
onClick={() => {
|
||||
if (fields.length < 3) add();
|
||||
|
||||
@@ -51,7 +51,9 @@ export function EmailOverlayContainer({
|
||||
|
||||
const defaultEmailFrom = {
|
||||
from: {
|
||||
name: `${currentUser.displayName} @ ${bodyshop.shopname}`,
|
||||
name: currentUser.displayName
|
||||
? `${currentUser.displayName} @ ${bodyshop.shopname}`
|
||||
: bodyshop.shopname,
|
||||
address: EmailSettings.fromAddress,
|
||||
},
|
||||
ReplyTo: {
|
||||
|
||||
@@ -21,7 +21,7 @@ export const PhoneItemFormatterValidation = (getFieldValue, name) => ({
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
const p = parsePhoneNumber(value, "CA");
|
||||
if (p.isValid()) {
|
||||
if (p && p.isValid()) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject(i18n.t("general.validation.invalidphone"));
|
||||
|
||||
@@ -62,13 +62,16 @@ export default function GlobalSearch() {
|
||||
}`,
|
||||
label: (
|
||||
<Link to={`/manage/owners/${owner.id}`}>
|
||||
<Space size="small" split={<Divider type="vertical" />}>
|
||||
<Space size="small" split={<Divider type="vertical" />} wrap>
|
||||
<span>{`${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
|
||||
owner.ownr_co_nm || ""
|
||||
}`}</span>
|
||||
<PhoneNumberFormatter>
|
||||
{owner.ownr_ph1}
|
||||
</PhoneNumberFormatter>
|
||||
<PhoneNumberFormatter>
|
||||
{owner.ownr_ph2}
|
||||
</PhoneNumberFormatter>
|
||||
</Space>
|
||||
</Link>
|
||||
),
|
||||
|
||||
@@ -106,6 +106,12 @@ export function ScheduleEventComponent({
|
||||
jobid={event.job.id}
|
||||
/>
|
||||
</DataLabel>
|
||||
<DataLabel label={t("jobs.fields.ownr_ph2")}>
|
||||
<ChatOpenButton
|
||||
phone={event.job && event.job.ownr_ph2}
|
||||
jobid={event.job.id}
|
||||
/>
|
||||
</DataLabel>
|
||||
<DataLabel label={t("jobs.fields.alt_transport")}>
|
||||
{(event.job && event.job.alt_transport) || ""}
|
||||
<ScheduleAtChange job={event && event.job} />
|
||||
@@ -203,6 +209,9 @@ export function ScheduleEventComponent({
|
||||
jobId: event.job.id,
|
||||
job: event.job,
|
||||
previousEvent: event.id,
|
||||
color: event.color,
|
||||
alt_transport: event.job && event.job.alt_transport,
|
||||
note: event.note,
|
||||
},
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -167,7 +167,11 @@ export function JobChecklistForm({
|
||||
title={t("checklist.labels.checklist")}
|
||||
extra={
|
||||
!readOnly && (
|
||||
<Button loading={loading} onClick={() => form.submit()}>
|
||||
<Button
|
||||
loading={loading}
|
||||
type="primary"
|
||||
onClick={() => form.submit()}
|
||||
>
|
||||
{t("general.actions.submit")}
|
||||
</Button>
|
||||
)
|
||||
@@ -182,12 +186,14 @@ export function JobChecklistForm({
|
||||
allow_text_message: job.owner && job.owner.allow_text_message,
|
||||
scheduled_completion:
|
||||
(job && job.scheduled_completion) ||
|
||||
moment().businessAdd(
|
||||
(job.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
job.larhrs.aggregate.sum.mod_lb_hrs) /
|
||||
bodyshop.target_touchtime,
|
||||
"days"
|
||||
),
|
||||
(job.labbrs && job.larhrs
|
||||
? moment().businessAdd(
|
||||
(job.labhrs.aggregate.sum.mod_lb_hrs +
|
||||
job.larhrs.aggregate.sum.mod_lb_hrs) /
|
||||
bodyshop.target_touchtime,
|
||||
"days"
|
||||
)
|
||||
: null),
|
||||
scheduled_delivery: job && job.scheduled_delivery,
|
||||
}),
|
||||
...(type === "deliver" && {
|
||||
|
||||
@@ -112,60 +112,46 @@ export function JobDetailCards({ setPrintCenterContext }) {
|
||||
<Divider type="horizontal" />
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col {...span}>
|
||||
<Card.Grid style={{ width: "100%", height: "100%" }}>
|
||||
<JobDetailCardsInsuranceComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Card.Grid>
|
||||
<JobDetailCardsInsuranceComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...span}>
|
||||
<Card.Grid style={{ width: "100%", height: "100%" }}>
|
||||
<JobDetailCardsTotalsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Card.Grid>
|
||||
<JobDetailCardsTotalsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...span}>
|
||||
<Card.Grid style={{ width: "100%", height: "100%" }}>
|
||||
<JobDetailCardsDatesComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Card.Grid>
|
||||
<JobDetailCardsDatesComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...span}>
|
||||
<Card.Grid style={{ width: "100%", height: "100%" }}>
|
||||
<JobDetailCardsPartsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Card.Grid>
|
||||
<JobDetailCardsPartsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...span}>
|
||||
<Card.Grid style={{ width: "100%", height: "100%" }}>
|
||||
<JobDetailCardsNotesComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Card.Grid>
|
||||
<JobDetailCardsNotesComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...span}>
|
||||
<Card.Grid style={{ width: "100%", height: "100%" }}>
|
||||
<JobDetailCardsDocumentsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Card.Grid>
|
||||
<JobDetailCardsDocumentsComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Col>
|
||||
<Col {...span}>
|
||||
<Card.Grid style={{ width: "100%", height: "100%" }}>
|
||||
<JobDetailCardsDamageComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Card.Grid>
|
||||
<JobDetailCardsDamageComponent
|
||||
loading={loading}
|
||||
data={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
</Card>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Timeline } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import CardTemplate from "./job-detail-cards.template.component";
|
||||
|
||||
export default function JobDetailCardsDatesComponent({ loading, data }) {
|
||||
@@ -26,80 +26,86 @@ export default function JobDetailCardsDatesComponent({ loading, data }) {
|
||||
) ? (
|
||||
<div>{t("jobs.errors.nodates")}</div>
|
||||
) : null}
|
||||
{data.date_last_contacted ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.date_last_contacted")}: </label>
|
||||
<DateTimeFormatter>{data.date_last_contacted}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
{data.date_open ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.date_open")}: </label>
|
||||
<DateFormatter>{data.date_open}</DateFormatter>
|
||||
<DateTimeFormatter>{data.date_open}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.date_estimated ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.date_estimated")}: </label>
|
||||
<DateFormatter>{data.date_estimated}</DateFormatter>
|
||||
<DateTimeFormatter>{data.date_estimated}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.date_scheduled ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.date_scheduled")}: </label>
|
||||
<DateFormatter>{data.date_scheduled}</DateFormatter>
|
||||
<DateTimeFormatter>{data.date_scheduled}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.scheduled_in ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.scheduled_in")}: </label>
|
||||
<DateFormatter>{data.scheduled_in}</DateFormatter>
|
||||
<DateTimeFormatter>{data.scheduled_in}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.actual_in ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.actual_in")}: </label>
|
||||
<DateFormatter>{data.actual_in}</DateFormatter>
|
||||
<DateTimeFormatter>{data.actual_in}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.scheduled_completion ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.scheduled_completion")}: </label>
|
||||
<DateFormatter>{data.scheduled_completion}</DateFormatter>
|
||||
<DateTimeFormatter>{data.scheduled_completion}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.actual_completion ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.actual_completion")}: </label>
|
||||
<DateFormatter>{data.actual_completion}</DateFormatter>
|
||||
<DateTimeFormatter>{data.actual_completion}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.scheduled_delivery ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.scheduled_delivery")}: </label>
|
||||
<DateFormatter>{data.scheduled_delivery}</DateFormatter>
|
||||
<DateTimeFormatter>{data.scheduled_delivery}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.actual_delivery ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.actual_delivery")}: </label>
|
||||
<DateFormatter>{data.actual_delivery}</DateFormatter>
|
||||
<DateTimeFormatter>{data.actual_delivery}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.date_invoiced ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.date_invoiced")}: </label>
|
||||
<DateFormatter>{data.date_invoiced}</DateFormatter>
|
||||
<DateTimeFormatter>{data.date_invoiced}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
|
||||
{data.date_exported ? (
|
||||
<Timeline.Item>
|
||||
<label>{t("jobs.fields.date_exported")}: </label>
|
||||
<DateFormatter>{data.date_exported}</DateFormatter>
|
||||
<DateTimeFormatter>{data.date_exported}</DateTimeFormatter>
|
||||
</Timeline.Item>
|
||||
) : null}
|
||||
</Timeline>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Carousel } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { GenerateThumbUrl } from "../jobs-documents-gallery/job-documents.utility";
|
||||
import CardTemplate from "./job-detail-cards.template.component";
|
||||
import { DetermineFileType } from "../documents-upload/documents-upload.utility";
|
||||
export default function JobDetailCardsDocumentsComponent({ loading, data }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
@@ -22,15 +22,7 @@ export default function JobDetailCardsDocumentsComponent({ loading, data }) {
|
||||
{data.documents.length > 0 ? (
|
||||
<Carousel autoplay>
|
||||
{data.documents.map((item) => (
|
||||
<img
|
||||
key={item.id}
|
||||
src={`${
|
||||
process.env.REACT_APP_CLOUDINARY_ENDPOINT
|
||||
}/${DetermineFileType(item.type)}/upload/${
|
||||
process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS
|
||||
}/${item.key}`}
|
||||
alt={item.name}
|
||||
/>
|
||||
<img key={item.id} src={GenerateThumbUrl(item)} alt={item.name} />
|
||||
))}
|
||||
</Carousel>
|
||||
) : (
|
||||
|
||||
@@ -12,11 +12,13 @@ export default function JobDetailCardTemplate({
|
||||
if (extraLink) extra = { extra: <Link to={extraLink}>More</Link> };
|
||||
return (
|
||||
<Card
|
||||
size='small'
|
||||
className='job-card'
|
||||
size="small"
|
||||
className="job-card"
|
||||
title={title}
|
||||
loading={loading}
|
||||
{...extra}>
|
||||
style={{ height: "100%" }}
|
||||
{...extra}
|
||||
>
|
||||
{otherProps.children}
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -36,6 +36,7 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re
|
||||
// import AllocationsBulkAssignmentContainer from "../allocations-bulk-assignment/allocations-bulk-assignment.container";
|
||||
// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
|
||||
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
||||
import _ from "lodash";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -161,7 +162,11 @@ export function JobLinesComponent({
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<>
|
||||
<CurrencyFormatter>{record.act_price}</CurrencyFormatter>
|
||||
<CurrencyFormatter>
|
||||
{record.db_ref === "900510" || record.db_ref === "900511"
|
||||
? record.prt_dsmk_m
|
||||
: record.act_price}
|
||||
</CurrencyFormatter>
|
||||
{record.prt_dsmk_p && record.prt_dsmk_p !== 0 ? (
|
||||
<span
|
||||
style={{ marginLeft: ".2rem" }}
|
||||
@@ -295,18 +300,17 @@ export function JobLinesComponent({
|
||||
onClick={async () => {
|
||||
await deleteJobLine({
|
||||
variables: { joblineId: record.id },
|
||||
// update(cache) {
|
||||
// cache.modify({
|
||||
// id: cache.identify(job),
|
||||
// fields: {
|
||||
// joblines(existingJobLines, { readField }) {
|
||||
// return existingJobLines.filter(
|
||||
// (jlRef) => record.id !== readField("id", jlRef)
|
||||
// );
|
||||
// },
|
||||
// },
|
||||
// });
|
||||
// },
|
||||
update(cache) {
|
||||
cache.modify({
|
||||
fields: {
|
||||
joblines(existingJobLines, { readField }) {
|
||||
return existingJobLines.filter(
|
||||
(jlRef) => record.id !== readField("id", jlRef)
|
||||
);
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
await axios.post("/job/totalsssu", {
|
||||
id: job.id,
|
||||
@@ -334,10 +338,12 @@ export function JobLinesComponent({
|
||||
const markedTypes = [e.key];
|
||||
if (e.key === "PAN") markedTypes.push("PAP");
|
||||
if (e.key === "PAS") markedTypes.push("PASL");
|
||||
setSelectedLines([
|
||||
...selectedLines,
|
||||
...jobLines.filter((item) => markedTypes.includes(item.part_type)),
|
||||
]);
|
||||
setSelectedLines(
|
||||
_.uniq([
|
||||
...selectedLines,
|
||||
...jobLines.filter((item) => markedTypes.includes(item.part_type)),
|
||||
])
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Form, Input, InputNumber, Modal, Select } from "antd";
|
||||
import { Form, Input, InputNumber, Modal, Select, Switch } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import InputCurrency from "../form-items-formatted/currency-form-item.component";
|
||||
@@ -184,9 +184,9 @@ export default function JobLinesUpsertModalComponent({
|
||||
>
|
||||
<InputNumber precision={0} min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("joblines.fields.db_price")} name="db_price">
|
||||
{/* <Form.Item label={t("joblines.fields.db_price")} name="db_price">
|
||||
<InputCurrency precision={2} min={0} />
|
||||
</Form.Item>
|
||||
</Form.Item> */}
|
||||
<Form.Item
|
||||
label={t("joblines.fields.act_price")}
|
||||
name="act_price"
|
||||
@@ -222,6 +222,14 @@ export default function JobLinesUpsertModalComponent({
|
||||
>
|
||||
<InputNumber precision={0} min={0} max={100} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("joblines.fields.tax_part")}
|
||||
name="tax_part"
|
||||
valuePropName="checked"
|
||||
initialValue={true}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
</Form>
|
||||
</Modal>
|
||||
|
||||
@@ -44,6 +44,7 @@ function JobLinesUpsertModalContainer({
|
||||
},
|
||||
],
|
||||
},
|
||||
refetchQueries: ["GET_LINE_TICKET_BY_PK"],
|
||||
});
|
||||
if (!r.errors) {
|
||||
await Axios.post("/job/totalsssu", {
|
||||
@@ -69,6 +70,7 @@ function JobLinesUpsertModalContainer({
|
||||
lineId: jobLineEditModal.context.id,
|
||||
line: values,
|
||||
},
|
||||
refetchQueries: ["GET_LINE_TICKET_BY_PK"],
|
||||
});
|
||||
if (!r.errors) {
|
||||
notification["success"]({
|
||||
|
||||
@@ -108,6 +108,9 @@ export default function JobReconciliationBillsTable({
|
||||
rowSelection={{
|
||||
onChange: handleOnRowClick,
|
||||
selectedRowKeys: selectedLines,
|
||||
getCheckboxProps: (record) => {
|
||||
return { disabled: record.deductedfromlbr };
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@ export const reconcileByAssocLine = (
|
||||
const [selectedJobLines, setSelectedJobLines] = jobLineState;
|
||||
|
||||
const allJoblinesFromBills = billLines
|
||||
.filter((bl) => bl.joblineid && !(bl.jobline && bl.jobline.removed))
|
||||
.filter((bl) => bl.joblineid && bl.jobline && !bl.jobline.removed)
|
||||
.map((bl) => bl.joblineid);
|
||||
|
||||
const duplicatedJobLinesbyInvoiceId = _.filter(
|
||||
|
||||
@@ -74,7 +74,12 @@ export default function JobsAdminDatesChange({ job }) {
|
||||
<Form.Item label={t("jobs.fields.actual_in")} name="actual_in">
|
||||
<DateTimePicker />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t("jobs.fields.date_last_contacted")}
|
||||
name="date_last_contacted"
|
||||
>
|
||||
<DateTimePicker />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.scheduled_completion")}
|
||||
name="scheduled_completion"
|
||||
|
||||
@@ -100,7 +100,7 @@ export function JobsAvailableContainer({
|
||||
}
|
||||
//IO-539 Check for Parts Rate on PAL for SGI use case.
|
||||
await CheckTaxRates(estData.est_data, bodyshop);
|
||||
|
||||
console.log(estData);
|
||||
const newTotals = (
|
||||
await Axios.post("/job/totals", {
|
||||
job: {
|
||||
@@ -395,10 +395,6 @@ function replaceEmpty(someObj, replaceValue = null) {
|
||||
}
|
||||
|
||||
async function CheckTaxRates(estData, bodyshop) {
|
||||
console.log(
|
||||
"🚀 ~ file: jobs-available-table.container.jsx ~ line 398 ~ estData",
|
||||
estData
|
||||
);
|
||||
//LKQ Check
|
||||
if (
|
||||
!estData.parts_tax_rates?.PAL ||
|
||||
@@ -491,4 +487,23 @@ async function CheckTaxRates(estData, bodyshop) {
|
||||
estData.parts_tax_rates.PAR.prt_tax_in = true;
|
||||
}
|
||||
}
|
||||
|
||||
//IO-1387 If a sublet line is NOT R&R, use the labor tax. If it is, use the sublet tax rate.
|
||||
//Currently limited to SK shops only.
|
||||
//if (bodyshop.region_config === "CA_SK") {
|
||||
estData.joblines.data.forEach((jl, index) => {
|
||||
if (
|
||||
(jl.part_type === "PASL" || jl.part_type === "PAS") &&
|
||||
jl.lbr_op !== "OP11"
|
||||
) {
|
||||
estData.joblines.data[index].tax_part = jl.lbr_tax;
|
||||
}
|
||||
|
||||
//Set markup lines and tax lines as taxable.
|
||||
//900510 is a mark up. 900510 is a discount.
|
||||
if (jl.db_ref === "900510") {
|
||||
estData.joblines.data[index].tax_part = true;
|
||||
}
|
||||
});
|
||||
//}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||
import { useHistory } from "react-router-dom";
|
||||
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
currentUser: selectCurrentUser,
|
||||
@@ -35,7 +36,7 @@ export function JobsCloseExportButton({
|
||||
|
||||
const handleQbxml = async () => {
|
||||
//Check if it's a CDK setup.
|
||||
if (bodyshop.cdk_dealerid) {
|
||||
if (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) {
|
||||
history.push(`/manage/dms?jobId=${jobId}`);
|
||||
return;
|
||||
}
|
||||
@@ -45,10 +46,13 @@ export function JobsCloseExportButton({
|
||||
//Check if it's a QBO Setup.
|
||||
let PartnerResponse;
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||
PartnerResponse = await axios.post(`/qbo/receivables`, {
|
||||
withCredentials: true,
|
||||
jobIds: [jobId],
|
||||
});
|
||||
PartnerResponse = await axios.post(
|
||||
`/qbo/receivables`,
|
||||
{
|
||||
jobIds: [jobId],
|
||||
},
|
||||
|
||||
);
|
||||
} else {
|
||||
//Default is QBD
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) {
|
||||
<th>{t("joblines.fields.line_desc")}</th>
|
||||
<th>{t("joblines.fields.part_type")}</th>
|
||||
<th>{t("joblines.fields.act_price")}</th>
|
||||
<th>{t("joblines.fields.prt_dsmk_m")}</th>
|
||||
<th>{t("joblines.fields.op_code_desc")}</th>
|
||||
<th>{t("joblines.fields.mod_lbr_ty")}</th>
|
||||
<th>{t("joblines.fields.mod_lb_hrs")}</th>
|
||||
@@ -70,6 +71,16 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) {
|
||||
<ReadOnlyFormItem type="currency" />
|
||||
</Form.Item>
|
||||
</td>
|
||||
<td>
|
||||
<Form.Item
|
||||
span={2}
|
||||
// label={t("joblines.fields.prt_dsmk_m")}
|
||||
key={`${index}prt_dsmk_m`}
|
||||
name={[field.name, "prt_dsmk_m"]}
|
||||
>
|
||||
<ReadOnlyFormItem type="currency" />
|
||||
</Form.Item>
|
||||
</td>
|
||||
<td>
|
||||
<Form.Item
|
||||
span={2}
|
||||
@@ -108,7 +119,9 @@ export function JobsCloseLines({ bodyshop, job, jobRO }) {
|
||||
labelCol={{ span: 0 }}
|
||||
rules={[
|
||||
{
|
||||
required: !!job.joblines[index].act_price,
|
||||
required:
|
||||
!!job.joblines[index].act_price ||
|
||||
!!job.joblines[index].prt_dsmk_m,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useMutation } from "@apollo/client";
|
||||
import {
|
||||
Button,
|
||||
Form,
|
||||
Input,
|
||||
notification,
|
||||
Popover,
|
||||
Select,
|
||||
@@ -34,6 +35,7 @@ export function JobsConvertButton({
|
||||
refetch,
|
||||
jobRO,
|
||||
insertAuditTrail,
|
||||
parentFormIsFieldsTouched,
|
||||
}) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
@@ -42,6 +44,10 @@ export function JobsConvertButton({
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleConvert = async (values) => {
|
||||
if (parentFormIsFieldsTouched()) {
|
||||
alert(t("jobs.labels.savebeforeconversion"));
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
const res = await mutationConvertJob({
|
||||
variables: { jobId: job.id, ...values },
|
||||
@@ -112,24 +118,32 @@ export function JobsConvertButton({
|
||||
</Form.Item>
|
||||
)}
|
||||
{bodyshop.enforce_referral && (
|
||||
<Form.Item
|
||||
name={"referral_source"}
|
||||
label={t("jobs.fields.referralsource")}
|
||||
rules={[
|
||||
{
|
||||
required: bodyshop.enforce_referral,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{bodyshop.md_referral_sources.map((s) => (
|
||||
<Select.Option key={s} value={s}>
|
||||
{s}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<>
|
||||
<Form.Item
|
||||
name={"referral_source"}
|
||||
label={t("jobs.fields.referralsource")}
|
||||
rules={[
|
||||
{
|
||||
required: bodyshop.enforce_referral,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{bodyshop.md_referral_sources.map((s) => (
|
||||
<Select.Option key={s} value={s}>
|
||||
{s}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.referral_source_extra")}
|
||||
name="referral_source_extra"
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ca_gst_registrant")}
|
||||
|
||||
@@ -150,6 +150,9 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
||||
<Form.Item label={t("jobs.fields.loss_desc")} name="loss_desc">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.loss_of_use")} name="loss_of_use">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.ponumber")} name="po_number">
|
||||
<Input />
|
||||
</Form.Item>
|
||||
@@ -181,6 +184,12 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.referral_source_extra")}
|
||||
name="referral_source_extra"
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
</Collapse.Panel>
|
||||
<Collapse.Panel
|
||||
@@ -191,7 +200,7 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
||||
<JobsMarkPstExempt form={form} />
|
||||
<LayoutFormRow>
|
||||
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.ded_status")} name="ded_status">
|
||||
<Select>
|
||||
|
||||
@@ -129,6 +129,19 @@ export default function JobsCreateOwnerInfoNewComponent() {
|
||||
>
|
||||
<FormItemPhone disabled={!state.owner.new} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("owners.fields.ownr_ph2")}
|
||||
name={["owner", "data", "ownr_ph2"]}
|
||||
rules={[
|
||||
({ getFieldValue }) =>
|
||||
PhoneItemFormatterValidation(
|
||||
getFieldValue,
|
||||
"owner.data.ownr_ph2"
|
||||
),
|
||||
]}
|
||||
>
|
||||
<FormItemPhone disabled={!state.owner.new} />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow>
|
||||
<Form.Item
|
||||
|
||||
@@ -84,6 +84,18 @@ export default function JobsCreateOwnerInfoSearchComponent({
|
||||
tableState.sortedInfo.columnKey === "ownr_ph1" &&
|
||||
tableState.sortedInfo.order,
|
||||
},
|
||||
{
|
||||
title: t("owners.fields.ownr_ph2"),
|
||||
dataIndex: "ownr_ph2",
|
||||
key: "ownr_ph2",
|
||||
render: (text, record) => (
|
||||
<PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>
|
||||
),
|
||||
sorter: (a, b) => alphaSort(a.ownr_ph2, b.ownr_ph2),
|
||||
sortOrder:
|
||||
tableState.sortedInfo.columnKey === "ownr_ph2" &&
|
||||
tableState.sortedInfo.order,
|
||||
},
|
||||
];
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import { DownOutlined } from "@ant-design/icons";
|
||||
import { Dropdown, Menu } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
export function JobsDetailChangeEstimator({ disabled, form, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleClick = ({ item, key, keyPath }) => {
|
||||
const est = item.props.value;
|
||||
form.setFieldsValue(est);
|
||||
};
|
||||
|
||||
const menu = (
|
||||
<div>
|
||||
<Menu onClick={handleClick}>
|
||||
{bodyshop.md_estimators.map((est, idx) => (
|
||||
<Menu.Item value={est} key={idx}>
|
||||
{`${est.est_ct_fn} ${est.est_ct_ln}`}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Dropdown overlay={menu} disabled={disabled}>
|
||||
<a
|
||||
className="ant-dropdown-link"
|
||||
href=" #"
|
||||
onClick={(e) => e.preventDefault()}
|
||||
>
|
||||
{t("jobs.actions.changestimator")} <DownOutlined />
|
||||
</a>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(JobsDetailChangeEstimator);
|
||||
@@ -69,6 +69,12 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
|
||||
</Tooltip>
|
||||
</FormRow>
|
||||
<FormRow header={t("jobs.forms.repairdates")}>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.date_last_contacted")}
|
||||
name="date_last_contacted"
|
||||
>
|
||||
<DateTimePicker />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.scheduled_completion")}
|
||||
name="scheduled_completion"
|
||||
@@ -93,7 +99,6 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t("jobs.fields.scheduled_delivery")}
|
||||
name="scheduled_delivery"
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { Col, Form, Input, InputNumber, Row, Select, Switch } from "antd";
|
||||
import {
|
||||
Col,
|
||||
Divider,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
Row,
|
||||
Select,
|
||||
Switch,
|
||||
} from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -12,6 +21,7 @@ import FormItemPhone, {
|
||||
PhoneItemFormatterValidation,
|
||||
} from "../form-items-formatted/phone-form-item.component";
|
||||
import Car from "../job-damage-visual/job-damage-visual.component";
|
||||
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
|
||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -44,7 +54,14 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.ded_note")} name="ded_note">
|
||||
<Select disabled={jobRO}>
|
||||
{bodyshop.md_ded_notes.map((n, index) => (
|
||||
<Select.Option key={index}>{n}</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.policy_no")} name="policy_no">
|
||||
<Input disabled={jobRO} />
|
||||
@@ -114,6 +131,12 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.referral_source_extra")}
|
||||
name="referral_source_extra"
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.alt_transport")} name="alt_transport">
|
||||
<Select disabled={jobRO} allowClear>
|
||||
{bodyshop.appt_alt_transport.map((s) => (
|
||||
@@ -133,6 +156,9 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
<Form.Item label={t("jobs.fields.loss_date")} name="loss_date">
|
||||
<FormDatePicker disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.loss_of_use")} name="loss_of_use">
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.kmin")} name="kmin">
|
||||
<InputNumber precision={0} min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
@@ -185,8 +211,16 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
<Divider
|
||||
orientation="left"
|
||||
type="horizontal"
|
||||
style={{ marginTop: ".8rem", float: "right" }}
|
||||
>
|
||||
{t("jobs.forms.appraiserinfo")}
|
||||
</Divider>
|
||||
|
||||
<FormRow header={t("jobs.forms.appraiserinfo")}>
|
||||
<JobsDetailChangeEstimator form={form} disabled={jobRO} />
|
||||
<FormRow noDivider>
|
||||
<Form.Item label={t("jobs.fields.est_co_nm")} name="est_co_nm">
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
|
||||
@@ -101,6 +101,7 @@ export function JobsDetailHeaderActions({
|
||||
context: {
|
||||
jobId: job.id,
|
||||
job: job,
|
||||
alt_transport: job.alt_transport,
|
||||
},
|
||||
});
|
||||
}}
|
||||
|
||||
@@ -147,7 +147,7 @@ export function JobsDetailHeaderCsi({
|
||||
replyTo: bodyshop.email,
|
||||
},
|
||||
template: {
|
||||
name: TemplateList("job").csi_invitation.key,
|
||||
name: TemplateList("job_special").csi_invitation_action.key,
|
||||
variables: {
|
||||
id: job.csiinvites[0].id,
|
||||
},
|
||||
|
||||
@@ -21,47 +21,57 @@ export function JobsDetailHeaderActionexportCustomerData({
|
||||
|
||||
const handleExportCustData = async (e) => {
|
||||
logImEXEvent("job_export_cust_data");
|
||||
let QbXmlResponse;
|
||||
try {
|
||||
QbXmlResponse = await axios.post(
|
||||
"/accounting/qbxml/receivables",
|
||||
{ jobIds: [job.id], custDataOnly: true },
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log("handle -> XML", QbXmlResponse);
|
||||
} catch (error) {
|
||||
console.log("Error getting QBXML from Server.", error);
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.exporting", {
|
||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||
}),
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let PartnerResponse;
|
||||
try {
|
||||
PartnerResponse = await axios.post(
|
||||
"http://localhost:1337/qb/",
|
||||
QbXmlResponse.data,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("Error connecting to quickbooks or partner.", error);
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.exporting-partner"),
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||
PartnerResponse = await axios.post(`/qbo/receivables`, {
|
||||
jobIds: [job.id],
|
||||
custDataOnly: true,
|
||||
});
|
||||
} else {
|
||||
//Default is QBD
|
||||
|
||||
return;
|
||||
let QbXmlResponse;
|
||||
try {
|
||||
QbXmlResponse = await axios.post(
|
||||
"/accounting/qbxml/receivables",
|
||||
{ jobIds: [job.id], custDataOnly: true },
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log("handle -> XML", QbXmlResponse);
|
||||
} catch (error) {
|
||||
console.log("Error getting QBXML from Server.", error);
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.exporting", {
|
||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||
}),
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//let PartnerResponse;
|
||||
try {
|
||||
PartnerResponse = await axios.post(
|
||||
"http://localhost:1337/qb/",
|
||||
QbXmlResponse.data,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("Error connecting to quickbooks or partner.", error);
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.exporting-partner"),
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
//Check to see if any of them failed. If they didn't don't execute the update.
|
||||
const failedTransactions = PartnerResponse.data.filter((r) => !r.success);
|
||||
|
||||
@@ -16,6 +16,7 @@ import JobEmployeeAssignments from "../job-employee-assignments/job-employee-ass
|
||||
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
|
||||
import "./jobs-detail-header.styles.scss";
|
||||
import JobsRelatedRos from "../jobs-related-ros/jobs-related-ros.component";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
@@ -70,6 +71,12 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
||||
{job.production_vars && job.production_vars.alert ? (
|
||||
<ExclamationCircleFilled className="production-alert" />
|
||||
) : null}
|
||||
{job.status === bodyshop.md_ro_statuses.default_scheduled &&
|
||||
job.scheduled_in ? (
|
||||
<Tag>
|
||||
<DateTimeFormatter>{job.scheduled_in}</DateTimeFormatter>
|
||||
</Tag>
|
||||
) : null}
|
||||
</Space>
|
||||
</DataLabel>
|
||||
<DataLabel label={t("jobs.fields.ins_co_nm_short")}>
|
||||
@@ -141,6 +148,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
||||
<DataLabel key="2" label={t("jobs.fields.ownr_ph1")}>
|
||||
<ChatOpenButton phone={job.ownr_ph1} jobid={job.id} />
|
||||
</DataLabel>
|
||||
<DataLabel key="22" label={t("jobs.fields.ownr_ph2")}>
|
||||
<ChatOpenButton phone={job.ownr_ph2} jobid={job.id} />
|
||||
</DataLabel>
|
||||
<DataLabel key="3" label={t("owners.fields.address")}>
|
||||
{`${job.ownr_addr1 || ""} ${job.ownr_addr2 || ""} ${
|
||||
job.ownr_city || ""
|
||||
|
||||
@@ -38,7 +38,7 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
label={t("jobs.fields.depreciation_taxes")}
|
||||
name="depreciation_taxes"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Tooltip title={t("jobs.labels.ca_gst_all_if_null")}>
|
||||
<Form.Item
|
||||
@@ -47,6 +47,7 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
>
|
||||
<CurrencyInput
|
||||
disabled={jobRO}
|
||||
min={0}
|
||||
max={
|
||||
Math.round(
|
||||
(job.job_totals &&
|
||||
@@ -61,19 +62,19 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
label={t("jobs.fields.other_amount_payable")}
|
||||
name="other_amount_payable"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.towing_payable")}
|
||||
name="towing_payable"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.storage_payable")}
|
||||
name="storage_payable"
|
||||
>
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.adjustment_bottom_line")}
|
||||
@@ -83,7 +84,7 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
</Form.Item>
|
||||
<Space align="end">
|
||||
<Form.Item label={t("jobs.fields.ca_bc_pvrt")} name="ca_bc_pvrt">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput disabled={jobRO} min={0} />
|
||||
</Form.Item>
|
||||
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
||||
</Space>
|
||||
@@ -123,7 +124,6 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
{t("jobs.forms.laborrates")}
|
||||
</Divider>
|
||||
<Space>
|
||||
<div></div>
|
||||
<JobsDetailRatesChangeButton form={form} disabled={jobRO} />
|
||||
<JobsMarkPstExempt form={form} />
|
||||
</Space>
|
||||
@@ -135,72 +135,72 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_laa")} name="rate_laa">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lad")} name="rate_lad">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lae")} name="rate_lae">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lar")} name="rate_lar">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_las")} name="rate_las">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_laf")} name="rate_laf">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lam")} name="rate_lam">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lag")} name="rate_lag">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_la1")} name="rate_la1">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_la2")} name="rate_la2">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_la3")} name="rate_la3">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_la4")} name="rate_la4">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_lau")} name="rate_lau">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_mapa")} name="rate_mapa">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_mash")} name="rate_mash">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_mahw")} name="rate_mahw">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_ma2s")} name="rate_ma2s">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.rate_ma3s")} name="rate_ma3s">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
{
|
||||
// <Form.Item label={t("jobs.fields.rate_mabl")} name="rate_mabl">
|
||||
// <CurrencyInput disabled={jobRO} />
|
||||
// <CurrencyInput min={0}disabled={jobRO} />
|
||||
// </Form.Item>
|
||||
// <Form.Item label={t("jobs.fields.rate_macs")} name="rate_macs">
|
||||
// <CurrencyInput disabled={jobRO} />
|
||||
// <CurrencyInput min={0}disabled={jobRO} />
|
||||
// </Form.Item>
|
||||
}
|
||||
<Form.Item label={t("jobs.fields.rate_matd")} name="rate_matd">
|
||||
<CurrencyInput disabled={jobRO} />
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
</FormRow>
|
||||
<JobsDetailRatesParts form={form} />
|
||||
|
||||
@@ -29,20 +29,6 @@ function JobsDocumentsComponent({
|
||||
setIndex(index);
|
||||
};
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log("Added event listening for reteching.");
|
||||
// window.addEventListener("storage", (ev) => {
|
||||
// if (ev.key === "refetch" && ev.newValue === true) {
|
||||
// refetch && refetch();
|
||||
// localStorage.setItem("refetch", false);
|
||||
// }
|
||||
// });
|
||||
|
||||
// return () => {
|
||||
// window.removeEventListener("storage");
|
||||
// };
|
||||
// }, [refetch]);
|
||||
|
||||
useEffect(() => {
|
||||
let documents = data.reduce(
|
||||
(acc, value) => {
|
||||
|
||||
@@ -38,7 +38,6 @@ export function JobsExportAllButton({
|
||||
setLoading(true);
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||
PartnerResponse = await axios.post(`/qbo/receivables`, {
|
||||
withCredentials: true,
|
||||
jobIds: jobIds,
|
||||
});
|
||||
} else {
|
||||
@@ -170,12 +169,7 @@ export function JobsExportAllButton({
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
|
||||
{t("jobs.actions.export")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -69,6 +69,20 @@ export default function JobsFindModalComponent({
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.ownr_ph2"),
|
||||
dataIndex: "ownr_ph2",
|
||||
key: "ownr_ph2",
|
||||
width: "12%",
|
||||
ellipsis: true,
|
||||
render: (text, record) => {
|
||||
return record.ownr_ph2 ? (
|
||||
<PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>
|
||||
) : (
|
||||
t("general.labels.unknown")
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
dataIndex: "status",
|
||||
|
||||
@@ -73,6 +73,16 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
||||
<StartChatButton phone={record.ownr_ph1} jobid={record.id} />
|
||||
),
|
||||
},
|
||||
{
|
||||
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} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
dataIndex: "status",
|
||||
|
||||
@@ -145,6 +145,16 @@ export function JobsList({ bodyshop }) {
|
||||
<ChatOpenButton phone={record.ownr_ph1} jobid={record.id} />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.ownr_ph2"),
|
||||
dataIndex: "ownr_ph2",
|
||||
key: "ownr_ph2",
|
||||
ellipsis: true,
|
||||
responsive: ["md"],
|
||||
render: (text, record) => (
|
||||
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id} />
|
||||
),
|
||||
},
|
||||
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
|
||||
@@ -81,6 +81,16 @@ export default function OwnerDetailFormComponent({ form, loading }) {
|
||||
>
|
||||
<FormItemPhone />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("owners.fields.ownr_ph2")}
|
||||
name="ownr_ph2"
|
||||
rules={[
|
||||
({ getFieldValue }) =>
|
||||
PhoneItemFormatterValidation(getFieldValue, "ownr_ph2"),
|
||||
]}
|
||||
>
|
||||
<FormItemPhone />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("owners.fields.preferred_contact")}
|
||||
name="preferred_contact"
|
||||
|
||||
@@ -51,6 +51,14 @@ export default function OwnerFindModalComponent({
|
||||
<PhoneFormatter>{record.ownr_ph1}</PhoneFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("owners.fields.ownr_ph2"),
|
||||
dataIndex: "ownr_ph2",
|
||||
key: "ownr_ph2",
|
||||
render: (text, record) => (
|
||||
<PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const handleOnRowClick = (record) => {
|
||||
@@ -66,7 +74,6 @@ export default function OwnerFindModalComponent({
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
title={() => t("owners.labels.existing_owners")}
|
||||
pagination={{ position: "bottom" }}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Modal } from "antd";
|
||||
import React from "react";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { useLazyQuery } from "@apollo/client";
|
||||
import { Input, Modal } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { QUERY_SEARCH_OWNER_BY_IDX } from "../../graphql/owners.queries";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
@@ -17,14 +17,27 @@ export default function OwnerFindModalContainer({
|
||||
}) {
|
||||
//use owner object to run query and find what possible owners there are.
|
||||
const { t } = useTranslation();
|
||||
const [searchText, setSearchText] = useState(null);
|
||||
|
||||
const ownersList = useQuery(QUERY_SEARCH_OWNER_BY_IDX, {
|
||||
variables: {
|
||||
search: owner ? `${owner.ownr_fn || ""} ${owner.ownr_ln || ""}` : null,
|
||||
},
|
||||
skip: !owner,
|
||||
fetchPolicy: "network-only",
|
||||
});
|
||||
const [callSearchowners, ownersList] = useLazyQuery(
|
||||
QUERY_SEARCH_OWNER_BY_IDX,
|
||||
{
|
||||
variables: {
|
||||
search: searchText,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (modalProps.visible && owner) {
|
||||
const s = `${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
|
||||
owner.ownr_co_nm || ""
|
||||
}`;
|
||||
|
||||
setSearchText(s.trim());
|
||||
callSearchowners({ variables: { search: s.trim() } });
|
||||
}
|
||||
}, [callSearchowners, modalProps.visible, owner]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -35,16 +48,25 @@ export default function OwnerFindModalContainer({
|
||||
{loading ? <LoadingSpinner /> : null}
|
||||
{error ? <AlertComponent message={error.message} type="error" /> : null}
|
||||
{owner ? (
|
||||
<OwnerFindModalComponent
|
||||
selectedOwner={selectedOwner}
|
||||
setSelectedOwner={setSelectedOwner}
|
||||
ownersListLoading={ownersList.loading}
|
||||
ownersList={
|
||||
ownersList.data && ownersList.data.search_owners
|
||||
? ownersList.data.search_owners
|
||||
: null
|
||||
}
|
||||
/>
|
||||
<>
|
||||
<Input.Search
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
onSearch={(val) =>
|
||||
callSearchowners({ variables: { search: val.trim() } })
|
||||
}
|
||||
/>
|
||||
<OwnerFindModalComponent
|
||||
selectedOwner={selectedOwner}
|
||||
setSelectedOwner={setSelectedOwner}
|
||||
ownersListLoading={ownersList.loading}
|
||||
ownersList={
|
||||
ownersList.data && ownersList.data.search_owners
|
||||
? ownersList.data.search_owners
|
||||
: null
|
||||
}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
</Modal>
|
||||
);
|
||||
|
||||
@@ -16,6 +16,9 @@ export default function OwnerTagPopoverComponent({ job }) {
|
||||
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph1")}>
|
||||
<PhoneFormatter>{job.ownr_ph1 || ""}</PhoneFormatter>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key="22" label={t("jobs.fields.ownr_ph2")}>
|
||||
<PhoneFormatter>{job.ownr_ph2 || ""}</PhoneFormatter>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key="3" label={t("owners.fields.address")}>
|
||||
{`${job.ownr_addr1 || ""} ${job.ownr_addr2 || ""} ${
|
||||
job.ownr_city || ""
|
||||
@@ -36,6 +39,12 @@ export default function OwnerTagPopoverComponent({ job }) {
|
||||
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph1")}>
|
||||
<PhoneFormatter>{job.owner.ownr_ph1 || ""}</PhoneFormatter>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key="22" label={t("jobs.fields.ownr_ph2")}>
|
||||
<PhoneFormatter>{job.owner.ownr_ph2 || ""}</PhoneFormatter>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph2")}>
|
||||
<PhoneFormatter>{job.owner.ownr_ph2 || ""}</PhoneFormatter>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item key="3" label={t("owners.fields.address")}>
|
||||
{`${job.owner.ownr_addr1 || ""} ${job.owner.ownr_addr2 || ""} ${
|
||||
job.owner.ownr_city || ""
|
||||
|
||||
@@ -47,6 +47,14 @@ export default function OwnersListComponent({
|
||||
return <PhoneFormatter>{record.ownr_ph1}</PhoneFormatter>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("owners.fields.ownr_ph2"),
|
||||
dataIndex: "ownr_ph2",
|
||||
key: "ownr_ph2",
|
||||
render: (text, record) => {
|
||||
return <PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("owners.fields.ownr_ea"),
|
||||
dataIndex: "ownr_ea",
|
||||
|
||||
@@ -27,6 +27,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import DataLabel from "../data-label/data-label.component";
|
||||
import PartsOrderBackorderEta from "../parts-order-backorder-eta/parts-order-backorder-eta.component";
|
||||
import PartsOrderLineBackorderButton from "../parts-order-line-backorder-button/parts-order-line-backorder-button.component";
|
||||
import PartsReceiveModalContainer from "../parts-receive-modal/parts-receive-modal.container";
|
||||
@@ -379,6 +380,9 @@ export function PartsOrderListTableComponent({
|
||||
rowKey="id"
|
||||
dataSource={record.parts_order_lines}
|
||||
/>
|
||||
<DataLabel label={t("parts_orders.fields.comments")}>
|
||||
<div style={{ whiteSpace: "pre" }}>{record.comments}</div>
|
||||
</DataLabel>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -73,7 +73,7 @@ export default function PartsOrderModalComponent({
|
||||
<Form.Item required={false} key={field.key}>
|
||||
<LayoutFormRow grow noDivider>
|
||||
<Form.Item
|
||||
span={8}
|
||||
//span={8}
|
||||
label={t("parts_orders.fields.line_desc")}
|
||||
key={`${index}line_desc`}
|
||||
name={[field.name, "line_desc"]}
|
||||
@@ -132,19 +132,21 @@ export default function PartsOrderModalComponent({
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<DeleteFilled
|
||||
style={{ margin: "1rem" }}
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
<Space wrap align="center">
|
||||
<div>
|
||||
<DeleteFilled
|
||||
style={{ margin: "1rem" }}
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<FormListMoveArrows
|
||||
move={move}
|
||||
index={index}
|
||||
total={fields.length}
|
||||
/>
|
||||
</div>
|
||||
</Space>
|
||||
</LayoutFormRow>
|
||||
</Form.Item>
|
||||
))}
|
||||
@@ -152,6 +154,9 @@ export default function PartsOrderModalComponent({
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
<Form.Item name="comments" label={t("parts_orders.fields.comments")}>
|
||||
<Input.TextArea rows={3} />
|
||||
</Form.Item>
|
||||
<Radio.Group
|
||||
defaultValue={sendType}
|
||||
onChange={(e) => setSendType(e.target.value)}
|
||||
|
||||
@@ -260,7 +260,7 @@ export function PartsOrderModalContainer({
|
||||
onCancel={() => toggleModalVisible()}
|
||||
onOk={() => form.submit()}
|
||||
destroyOnClose
|
||||
width="50%"
|
||||
width="75%"
|
||||
forceRender
|
||||
>
|
||||
{error ? <AlertComponent message={error.message} type="error" /> : null}
|
||||
|
||||
@@ -40,8 +40,7 @@ export function PayableExportAll({
|
||||
setLoading(true);
|
||||
if (!!loadingCallback) loadingCallback(true);
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||
PartnerResponse = await axios.post(`/qbo/receivables`, {
|
||||
withCredentials: true,
|
||||
PartnerResponse = await axios.post(`/qbo/payables`, {
|
||||
bills: billids,
|
||||
});
|
||||
} else {
|
||||
@@ -169,12 +168,7 @@ export function PayableExportAll({
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
|
||||
{t("jobs.actions.exportselected")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -42,7 +42,6 @@ export function PayableExportButton({
|
||||
let PartnerResponse;
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||
PartnerResponse = await axios.post(`/qbo/payables`, {
|
||||
withCredentials: true,
|
||||
bills: [billId],
|
||||
});
|
||||
} else {
|
||||
@@ -171,12 +170,7 @@ export function PayableExportButton({
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
|
||||
{t("jobs.actions.export")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||
import { UPDATE_PAYMENTS } from "../../graphql/payments.queries";
|
||||
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
@@ -33,55 +34,63 @@ export function PaymentExportButton({
|
||||
|
||||
const handleQbxml = async () => {
|
||||
logImEXEvent("accounting_payment_export");
|
||||
|
||||
setLoading(true);
|
||||
if (!!loadingCallback) loadingCallback(true);
|
||||
|
||||
let QbXmlResponse;
|
||||
try {
|
||||
QbXmlResponse = await axios.post(
|
||||
"/accounting/qbxml/payments",
|
||||
{ payments: [paymentId] },
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log("handle -> XML", QbXmlResponse);
|
||||
} catch (error) {
|
||||
console.log("Error getting QBXML from Server.", error);
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting", {
|
||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||
}),
|
||||
});
|
||||
if (loadingCallback) loadingCallback(false);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
//Check if it's a QBO Setup.
|
||||
let PartnerResponse;
|
||||
|
||||
try {
|
||||
PartnerResponse = await axios.post(
|
||||
"http://localhost:1337/qb/",
|
||||
//"http://609feaeae986.ngrok.io/qb/",
|
||||
QbXmlResponse.data
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("Error connecting to quickbooks or partner.", error);
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting-partner"),
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||
PartnerResponse = await axios.post(`/qbo/payments`, {
|
||||
payments: [paymentId],
|
||||
});
|
||||
if (!!loadingCallback) loadingCallback(false);
|
||||
setLoading(false);
|
||||
return;
|
||||
} else {
|
||||
//Default is QBD
|
||||
|
||||
if (!!loadingCallback) loadingCallback(true);
|
||||
|
||||
let QbXmlResponse;
|
||||
try {
|
||||
QbXmlResponse = await axios.post(
|
||||
"/accounting/qbxml/payments",
|
||||
{ payments: [paymentId] },
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
|
||||
},
|
||||
}
|
||||
);
|
||||
console.log("handle -> XML", QbXmlResponse);
|
||||
} catch (error) {
|
||||
console.log("Error getting QBXML from Server.", error);
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting", {
|
||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||
}),
|
||||
});
|
||||
if (loadingCallback) loadingCallback(false);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
PartnerResponse = await axios.post(
|
||||
"http://localhost:1337/qb/",
|
||||
QbXmlResponse.data
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("Error connecting to quickbooks or partner.", error);
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting-partner"),
|
||||
});
|
||||
if (!!loadingCallback) loadingCallback(false);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("handleQbxml -> PartnerResponse", PartnerResponse);
|
||||
const failedTransactions = PartnerResponse.data.filter((r) => !r.success);
|
||||
|
||||
const successfulTransactions = PartnerResponse.data.filter(
|
||||
(r) => r.success
|
||||
);
|
||||
if (failedTransactions.length > 0) {
|
||||
//Uh oh. At least one was no good.
|
||||
failedTransactions.map((ft) =>
|
||||
@@ -123,7 +132,14 @@ export function PaymentExportButton({
|
||||
|
||||
const paymentUpdateResponse = await updatePayment({
|
||||
variables: {
|
||||
paymentIdList: [paymentId],
|
||||
paymentIdList: successfulTransactions.map(
|
||||
(st) =>
|
||||
st[
|
||||
bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
|
||||
? "paymentid"
|
||||
: "id"
|
||||
]
|
||||
),
|
||||
payment: {
|
||||
exportedat: new Date(),
|
||||
},
|
||||
@@ -155,12 +171,7 @@ export function PaymentExportButton({
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
|
||||
{t("jobs.actions.export")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -8,6 +8,7 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||
import { UPDATE_PAYMENTS } from "../../graphql/payments.queries";
|
||||
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
@@ -33,42 +34,49 @@ export function PaymentsExportAllButton({
|
||||
const handleQbxml = async () => {
|
||||
setLoading(true);
|
||||
if (!!loadingCallback) loadingCallback(true);
|
||||
|
||||
let QbXmlResponse;
|
||||
try {
|
||||
QbXmlResponse = await axios.post("/accounting/qbxml/payments", {
|
||||
let PartnerResponse;
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||
PartnerResponse = await axios.post(`/qbo/payments`, {
|
||||
payments: paymentIds,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error getting QBXML from Server.", error);
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting", {
|
||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||
}),
|
||||
});
|
||||
if (loadingCallback) loadingCallback(false);
|
||||
setLoading(false);
|
||||
return;
|
||||
} else {
|
||||
let QbXmlResponse;
|
||||
try {
|
||||
QbXmlResponse = await axios.post("/accounting/qbxml/payments", {
|
||||
payments: paymentIds,
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("Error getting QBXML from Server.", error);
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting", {
|
||||
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
|
||||
}),
|
||||
});
|
||||
if (loadingCallback) loadingCallback(false);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
PartnerResponse = await axios.post(
|
||||
"http://localhost:1337/qb/",
|
||||
QbXmlResponse.data
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("Error connecting to quickbooks or partner.", error);
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting-partner"),
|
||||
});
|
||||
if (!!loadingCallback) loadingCallback(false);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let PartnerResponse;
|
||||
|
||||
try {
|
||||
PartnerResponse = await axios.post(
|
||||
"http://localhost:1337/qb/",
|
||||
QbXmlResponse.data
|
||||
);
|
||||
} catch (error) {
|
||||
console.log("Error connecting to quickbooks or partner.", error);
|
||||
notification["error"]({
|
||||
message: t("payments.errors.exporting-partner"),
|
||||
});
|
||||
if (!!loadingCallback) loadingCallback(false);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
|
||||
const groupedData = _.groupBy(PartnerResponse.data, "id");
|
||||
const groupedData = _.groupBy(
|
||||
PartnerResponse.data,
|
||||
bodyshop.accountingconfig.qbo ? "paymentid" : "id"
|
||||
);
|
||||
const proms = [];
|
||||
Object.keys(groupedData).forEach((key) => {
|
||||
proms.push(
|
||||
@@ -144,12 +152,7 @@ export function PaymentsExportAllButton({
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
onClick={handleQbxml}
|
||||
loading={loading}
|
||||
disabled={disabled}
|
||||
type="dashed"
|
||||
>
|
||||
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
|
||||
{t("jobs.actions.exportselected")}
|
||||
</Button>
|
||||
);
|
||||
|
||||
@@ -38,6 +38,7 @@ export function ProductionBoardFilters({
|
||||
}}
|
||||
/>
|
||||
<EmployeeSearchSelectComponent
|
||||
style={{ minWidth: "20rem" }}
|
||||
options={bodyshop.employees.filter((e) => e.active)}
|
||||
value={filter.employeeId}
|
||||
placeholder={t("production.labels.employeesearch")}
|
||||
|
||||
@@ -6,9 +6,11 @@ import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
technician: selectTechnician,
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
@@ -21,6 +23,7 @@ export default connect(
|
||||
export function ProductionColumnsComponent({
|
||||
columnState,
|
||||
technician,
|
||||
bodyshop,
|
||||
tableState,
|
||||
}) {
|
||||
const [columns, setColumns] = columnState;
|
||||
@@ -29,9 +32,11 @@ export function ProductionColumnsComponent({
|
||||
const handleAdd = (e) => {
|
||||
setColumns([
|
||||
...columns,
|
||||
...dataSource({ technician, state: tableState }).filter(
|
||||
(i) => i.key === e.key
|
||||
),
|
||||
...dataSource({
|
||||
technician,
|
||||
state: tableState,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
}).filter((i) => i.key === e.key),
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -39,7 +44,11 @@ export function ProductionColumnsComponent({
|
||||
|
||||
const menu = (
|
||||
<Menu onClick={handleAdd}>
|
||||
{dataSource({ technician, state: tableState })
|
||||
{dataSource({
|
||||
technician,
|
||||
state: tableState,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
})
|
||||
.filter((i) => !columnKeys.includes(i.key))
|
||||
.map((item) => (
|
||||
<Menu.Item key={item.key}>{item.title}</Menu.Item>
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function ProductionListColumnBodyPriority({ record }) {
|
||||
key="set"
|
||||
title={t("production.actions.bodypriority-set")}
|
||||
>
|
||||
{new Array(9).fill().map((value, index) => (
|
||||
{new Array(15).fill().map((value, index) => (
|
||||
<Menu.Item key={index + 1}>{index + 1}</Menu.Item>
|
||||
))}
|
||||
</Menu.SubMenu>
|
||||
|
||||
@@ -3,7 +3,7 @@ import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
|
||||
import JobAltTransportChange from "../job-at-change/job-at-change.component";
|
||||
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
||||
import ProductionListColumnAlert from "./production-list-columns.alert.component";
|
||||
@@ -15,8 +15,9 @@ import ProductionListColumnPaintPriority from "./production-list-columns.paintpr
|
||||
import ProductionListColumnNote from "./production-list-columns.productionnote.component";
|
||||
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
||||
import ProductionListLastContacted from "./production-list-columns.lastcontacted.component";
|
||||
|
||||
const r = ({ technician, state }) => {
|
||||
const r = ({ technician, state, activeStatuses }) => {
|
||||
return [
|
||||
{
|
||||
title: i18n.t("jobs.actions.viewdetail"),
|
||||
@@ -97,6 +98,17 @@ const r = ({ technician, state }) => {
|
||||
<ProductionListDate record={record} field="scheduled_completion" />
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.t("jobs.fields.date_last_contacted"),
|
||||
dataIndex: "date_last_contacted",
|
||||
key: "date_last_contacted",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => dateSort(a.date_last_contacted, b.date_last_contacted),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "date_last_contacted" &&
|
||||
state.sortedInfo.order,
|
||||
render: (text, record) => <ProductionListLastContacted record={record} />,
|
||||
},
|
||||
{
|
||||
title: i18n.t("jobs.fields.scheduled_delivery"),
|
||||
dataIndex: "scheduled_delivery",
|
||||
@@ -161,6 +173,15 @@ const r = ({ technician, state }) => {
|
||||
<PhoneFormatter>{record.ownr_ph1}</PhoneFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.t("jobs.fields.ownr_ph2"),
|
||||
dataIndex: "ownr_ph2",
|
||||
key: "ownr_ph2",
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<PhoneFormatter>{record.ownr_ph2}</PhoneFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.t("jobs.fields.specialcoveragepolicy"),
|
||||
dataIndex: "special_coverage_policy",
|
||||
@@ -189,7 +210,7 @@ const r = ({ technician, state }) => {
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||
sorter: (a, b) => statusSort(a.status, b.status, activeStatuses),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||
render: (text, record) => <ProductionListColumnStatus record={record} />,
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { DatePicker, Dropdown } from "antd";
|
||||
import { DatePicker, Dropdown, TimePicker, Button, Card } from "antd";
|
||||
import moment from "moment";
|
||||
import React from "react";
|
||||
import React, { useState } from "react";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const OneCalendarDay = 60 * 60 * 24 * 1000;
|
||||
const Now = new Date();
|
||||
|
||||
export default function ProductionListDate({ record, field }) {
|
||||
export default function ProductionListDate({ record, field, time }) {
|
||||
const [updateAlert] = useMutation(UPDATE_JOB);
|
||||
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const handleChange = (date) => {
|
||||
logImEXEvent("product_toggle_date", { field });
|
||||
|
||||
@@ -25,27 +28,47 @@ export default function ProductionListDate({ record, field }) {
|
||||
},
|
||||
}).then(() => {
|
||||
if (record.refetch) record.refetch();
|
||||
if (!time) {
|
||||
setVisible(false);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dropdown
|
||||
trigger={["click"]}
|
||||
//trigger={["click"]}
|
||||
visible={visible}
|
||||
style={{
|
||||
height: "19px",
|
||||
}}
|
||||
overlay={
|
||||
<div onClick={(e) => e.stopPropagation()}>
|
||||
<Card
|
||||
style={{ padding: "1rem" }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<DatePicker
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
value={(record[field] && moment(record[field])) || null}
|
||||
onChange={handleChange}
|
||||
format="MM/DD/YYYY"
|
||||
/>
|
||||
</div>
|
||||
{time && (
|
||||
<TimePicker
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
value={(record[field] && moment(record[field])) || null}
|
||||
onChange={handleChange}
|
||||
format="hh:mm a"
|
||||
/>
|
||||
)}
|
||||
<Button onClick={() => setVisible(false)}>
|
||||
{t("general.actions.close")}
|
||||
</Button>
|
||||
</Card>
|
||||
}
|
||||
>
|
||||
<div
|
||||
onClick={() => setVisible(true)}
|
||||
style={{
|
||||
height: "19px",
|
||||
}}
|
||||
|
||||
@@ -40,7 +40,7 @@ export default function ProductionListColumnDetailPriority({ record }) {
|
||||
key="set"
|
||||
title={t("production.actions.detailpriority-set")}
|
||||
>
|
||||
{new Array(9).fill().map((value, index) => (
|
||||
{new Array(15).fill().map((value, index) => (
|
||||
<Menu.Item key={index + 1}>{index + 1}</Menu.Item>
|
||||
))}
|
||||
</Menu.SubMenu>
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Button, Card, Dropdown, Form, Input, notification, Space } from "antd";
|
||||
import moment from "moment";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { INSERT_NEW_NOTE } from "../../graphql/notes.queries";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ProductionLastContacted);
|
||||
|
||||
export function ProductionLastContacted({ currentUser, record }) {
|
||||
const [updateAlert] = useMutation(UPDATE_JOB);
|
||||
const [insertNote] = useMutation(INSERT_NEW_NOTE);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const handleFinish = async ({ date_last_contacted, note }) => {
|
||||
logImEXEvent("production_last_contacted");
|
||||
|
||||
//e.stopPropagation();
|
||||
const res = await updateAlert({
|
||||
variables: {
|
||||
jobId: record.id,
|
||||
job: {
|
||||
date_last_contacted,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (res.errors) {
|
||||
notification.open({
|
||||
type: "error",
|
||||
message: t("jobs.errors.saving", {
|
||||
error: JSON.stringify(res.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
if (note && note.trim() !== "") {
|
||||
//Insert a note.
|
||||
const res2 = await insertNote({
|
||||
variables: {
|
||||
noteInput: {
|
||||
jobid: record.id,
|
||||
text: note,
|
||||
created_by: currentUser.email,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (res2.errors) {
|
||||
notification.open({
|
||||
type: "error",
|
||||
message: t("notes.errors.inserting", {
|
||||
error: JSON.stringify(res.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
if (record.refetch) record.refetch();
|
||||
|
||||
setVisible(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
form.setFieldsValue({
|
||||
note: null,
|
||||
date_last_contacted:
|
||||
record.date_last_contacted && moment(record.date_last_contacted),
|
||||
});
|
||||
}
|
||||
}, [visible, form, record.date_last_contacted]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dropdown
|
||||
//trigger={["click"]}
|
||||
visible={visible}
|
||||
style={{
|
||||
height: "19px",
|
||||
}}
|
||||
overlay={
|
||||
<Card
|
||||
style={{ padding: "1rem" }}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Form form={form} onFinish={handleFinish} layout="vertical">
|
||||
<Form.Item name="date_last_contacted">
|
||||
<FormDateTimePickerComponent />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("notes.labels.notetoadd")} name="note">
|
||||
<Input.TextArea rows={4} />
|
||||
</Form.Item>
|
||||
<Space>
|
||||
<Button type="primary" htmlType="submit">
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
<Button onClick={() => setVisible(false)}>
|
||||
{t("general.actions.close")}
|
||||
</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</Card>
|
||||
}
|
||||
>
|
||||
<div
|
||||
onClick={() => setVisible(true)}
|
||||
style={{
|
||||
height: "19px",
|
||||
}}
|
||||
>
|
||||
<DateFormatter bordered={false}>
|
||||
{record.date_last_contacted}
|
||||
</DateFormatter>
|
||||
</div>
|
||||
</Dropdown>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -40,7 +40,7 @@ export default function ProductionListColumnPaintPriority({ record }) {
|
||||
key="set"
|
||||
title={t("production.actions.paintpriority-set")}
|
||||
>
|
||||
{new Array(9).fill().map((value, index) => (
|
||||
{new Array(15).fill().map((value, index) => (
|
||||
<Menu.Item key={index + 1}>{index + 1}</Menu.Item>
|
||||
))}
|
||||
</Menu.SubMenu>
|
||||
|
||||
@@ -77,6 +77,10 @@ export default function ProductionListDetail({ jobs }) {
|
||||
phone={data.jobs_by_pk.ownr_ph1}
|
||||
jobid={data.jobs_by_pk.id}
|
||||
/>
|
||||
<StartChatButton
|
||||
phone={data.jobs_by_pk.ownr_ph2}
|
||||
jobid={data.jobs_by_pk.id}
|
||||
/>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label={t("jobs.fields.vehicle")}>
|
||||
{`${theJob.v_model_yr || ""} ${theJob.v_color || ""} ${
|
||||
|
||||
@@ -66,12 +66,7 @@ export function ProductionListSaveConfigButton({
|
||||
};
|
||||
const popMenu = (
|
||||
<div>
|
||||
<Form
|
||||
layout="vertical"
|
||||
form={form}
|
||||
onFinish={handleSaveConfig}
|
||||
initialValues={{ driveable: true, towin: false }}
|
||||
>
|
||||
<Form layout="vertical" form={form} onFinish={handleSaveConfig}>
|
||||
<Form.Item
|
||||
label={t("production.labels.viewname")}
|
||||
name="name"
|
||||
|
||||
@@ -37,9 +37,11 @@ export function ProductionListTable({
|
||||
.filter((pc) => pc.name === value)[0]
|
||||
.columns.columnKeys.map((k) => {
|
||||
return {
|
||||
...ProductionListColumns({ technician, state }).find(
|
||||
(e) => e.key === k.key
|
||||
),
|
||||
...ProductionListColumns({
|
||||
technician,
|
||||
state,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
}).find((e) => e.key === k.key),
|
||||
width: k.width,
|
||||
};
|
||||
})
|
||||
@@ -55,6 +57,19 @@ export function ProductionListTable({
|
||||
if (assoc) {
|
||||
await updateDefaultProdView({
|
||||
variables: { assocId: assoc.id, view: value },
|
||||
update(cache) {
|
||||
cache.modify({
|
||||
id: cache.identify(bodyshop),
|
||||
fields: {
|
||||
associations(existingAssociations, { readField }) {
|
||||
return existingAssociations.map((a) => {
|
||||
if (a.useremail !== currentUser.email) return a;
|
||||
return { ...a, default_prod_list_view: value };
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -75,9 +90,11 @@ export function ProductionListTable({
|
||||
setColumns(
|
||||
bodyshop.production_config[0].columns.columnKeys.map((k) => {
|
||||
return {
|
||||
...ProductionListColumns({ technician, state }).find(
|
||||
(e) => e.key === k.key
|
||||
),
|
||||
...ProductionListColumns({
|
||||
technician,
|
||||
state,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
}).find((e) => e.key === k.key),
|
||||
width: k.width,
|
||||
};
|
||||
})
|
||||
@@ -85,13 +102,18 @@ export function ProductionListTable({
|
||||
|
||||
setState(bodyshop.production_config[0].columns.tableState);
|
||||
};
|
||||
const assoc = bodyshop.associations.find(
|
||||
(a) => a.useremail === currentUser.email
|
||||
);
|
||||
|
||||
const defaultView = assoc && assoc.default_prod_list_view;
|
||||
return (
|
||||
<div style={{ width: "10rem" }}>
|
||||
<Select
|
||||
onSelect={handleSelect}
|
||||
placeholder={t("production.labels.selectview")}
|
||||
optionLabelProp="label"
|
||||
defaultValue={defaultView}
|
||||
>
|
||||
{bodyshop.production_config.map((config) => (
|
||||
<Select.Option key={config.name} label={config.name}>
|
||||
|
||||
@@ -1,4 +1,12 @@
|
||||
import { Dropdown, Input, Menu, PageHeader, Space, Table } from "antd";
|
||||
import {
|
||||
Dropdown,
|
||||
Input,
|
||||
Menu,
|
||||
PageHeader,
|
||||
Space,
|
||||
Statistic,
|
||||
Table,
|
||||
} from "antd";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import ReactDragListView from "react-drag-listview";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -16,6 +24,7 @@ import ProductionListSaveConfigButton from "../production-list-save-config-butto
|
||||
import ProductionListPrint from "./production-list-print.component";
|
||||
import ProductionListTableViewSelect from "./production-list-table-view-select.component";
|
||||
import ResizeableTitle from "./production-list-table.resizeable.component";
|
||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -31,13 +40,14 @@ export function ProductionListTable({
|
||||
currentUser,
|
||||
}) {
|
||||
const [searchText, setSearchText] = useState("");
|
||||
const { Production_List_Status_Colors } = useTreatments([
|
||||
"Production_List_Status_Colors",
|
||||
]);
|
||||
const assoc = bodyshop.associations.find(
|
||||
(a) => a.useremail === currentUser.email
|
||||
);
|
||||
|
||||
const defaultView = useMemo(() => {
|
||||
const assoc = bodyshop.associations.find(
|
||||
(a) => a.useremail === currentUser.email
|
||||
);
|
||||
return assoc && assoc.default_prod_list_view;
|
||||
}, [bodyshop.associations, currentUser.email]);
|
||||
const defaultView = assoc && assoc.default_prod_list_view;
|
||||
|
||||
const [state, setState] = useState(
|
||||
(bodyshop.production_config &&
|
||||
@@ -60,9 +70,11 @@ export function ProductionListTable({
|
||||
matchingColumnConfig &&
|
||||
matchingColumnConfig.columns.columnKeys.map((k) => {
|
||||
return {
|
||||
...ProductionListColumns({ technician, state }).find(
|
||||
(e) => e.key === k.key
|
||||
),
|
||||
...ProductionListColumns({
|
||||
technician,
|
||||
state,
|
||||
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||
}).find((e) => e.key === k.key),
|
||||
width: k.width,
|
||||
};
|
||||
})) ||
|
||||
@@ -157,9 +169,24 @@ export function ProductionListTable({
|
||||
|
||||
if (!!!columns) return <div>No columns found.</div>;
|
||||
|
||||
const totalHrs = data
|
||||
.reduce(
|
||||
(acc, val) =>
|
||||
acc +
|
||||
(val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0) +
|
||||
(val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0),
|
||||
0
|
||||
)
|
||||
.toFixed(1);
|
||||
return (
|
||||
<div>
|
||||
<PageHeader
|
||||
title={
|
||||
<Statistic
|
||||
title={t("dashboard.titles.productionhours")}
|
||||
value={totalHrs}
|
||||
/>
|
||||
}
|
||||
extra={
|
||||
<Space wrap>
|
||||
<ProductionListColumnsAdd
|
||||
@@ -193,8 +220,28 @@ export function ProductionListTable({
|
||||
handleSelector=".prod-header-dropdown"
|
||||
>
|
||||
<Table
|
||||
sticky
|
||||
pagination={false}
|
||||
size="small"
|
||||
className="production-list-table"
|
||||
onRow={
|
||||
Production_List_Status_Colors.treatment === "on" &&
|
||||
((record, index) => {
|
||||
if (!bodyshop.md_ro_statuses.production_colors) return null;
|
||||
|
||||
const color = bodyshop.md_ro_statuses.production_colors.find(
|
||||
(x) => x.status === record.status
|
||||
);
|
||||
|
||||
if (!color) return null;
|
||||
|
||||
return {
|
||||
style: {
|
||||
backgroundColor: `rgb(${color.color.r},${color.color.g},${color.color.b},${color.color.a})`,
|
||||
},
|
||||
};
|
||||
})
|
||||
}
|
||||
components={{
|
||||
header: {
|
||||
cell: ResizeableTitle,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Space, Tag } from "antd";
|
||||
import { Space } from "antd";
|
||||
import Axios from "axios";
|
||||
import queryString from "query-string";
|
||||
import React, { useEffect } from "react";
|
||||
@@ -9,7 +9,7 @@ import QboSignIn from "../../assets/qbo/C2QB_green_btn_med_default.svg";
|
||||
export default function QboAuthorizeComponent() {
|
||||
const location = useLocation();
|
||||
const history = useHistory();
|
||||
const [cookies, setCookie] = useCookies(["access_token", "refresh_token"]);
|
||||
const [, setCookie] = useCookies(["access_token", "refresh_token"]);
|
||||
|
||||
const handleQbSignIn = async () => {
|
||||
const result = await Axios.post("/qbo/authorize");
|
||||
@@ -24,16 +24,20 @@ export default function QboAuthorizeComponent() {
|
||||
const hasBeenCalledBack = code && realmId && state;
|
||||
|
||||
if (hasBeenCalledBack) {
|
||||
setCookie("qbo_code", code, { path: "/" });
|
||||
setCookie("qbo_state", state, { path: "/" });
|
||||
// setCookie("qbo_code", code, { path: "/" });
|
||||
// setCookie("qbo_state", state, { path: "/" });
|
||||
|
||||
let expires = new Date();
|
||||
expires.setTime(expires.getTime() + 8726400 * 1000);
|
||||
// let expires = new Date();
|
||||
// expires.setTime(expires.getTime() + 8726400 * 1000);
|
||||
|
||||
setCookie("qbo_realmId", realmId, {
|
||||
path: "/",
|
||||
expires,
|
||||
});
|
||||
// setCookie("qbo_realmId", realmId, {
|
||||
// path: "/",
|
||||
// expires,
|
||||
|
||||
// ...(process.env.NODE_ENV !== "development"
|
||||
// ? { domain: `.${window.location.host}` }
|
||||
// : {}),
|
||||
// });
|
||||
|
||||
history.push({ pathname: `/manage/accounting/receivables` });
|
||||
}
|
||||
@@ -48,9 +52,7 @@ export default function QboAuthorizeComponent() {
|
||||
src={QboSignIn}
|
||||
style={{ cursor: "pointer" }}
|
||||
/>
|
||||
{!cookies.qbo_realmId && (
|
||||
<Tag color="red">No QuickBooks company has been connected.</Tag>
|
||||
)}
|
||||
|
||||
{error && JSON.parse(decodeURIComponent(error)).error_description}
|
||||
</Space>
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import { Button, Card, Col, PageHeader, Row, Space } from "antd";
|
||||
import React from "react";
|
||||
import ScheduleCalendarWrapperComponent from "../schedule-calendar-wrapper/scheduler-calendar-wrapper.component";
|
||||
import ScheduleModal from "../schedule-job-modal/schedule-job-modal.container";
|
||||
//import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component";
|
||||
import ScheduleProductionList from "../schedule-production-list/schedule-production-list.component";
|
||||
|
||||
export default function ScheduleCalendarComponent({ data, refetch }) {
|
||||
@@ -21,8 +22,10 @@ export default function ScheduleCalendarComponent({ data, refetch }) {
|
||||
>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
|
||||
<ScheduleProductionList />
|
||||
{
|
||||
// <ScheduleManualEvent />
|
||||
}
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -124,7 +124,7 @@ export function ScheduleJobModalComponent({
|
||||
handleDateBlur();
|
||||
}}
|
||||
>
|
||||
<DateFormatter>{d}</DateFormatter>
|
||||
<DateFormatter includeDay>{d}</DateFormatter>
|
||||
</Button>
|
||||
))}
|
||||
</Space>
|
||||
|
||||
@@ -63,6 +63,20 @@ export function ScheduleJobModalContainer({
|
||||
skip: !visible || !!!jobId,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
existingAppointments.data &&
|
||||
existingAppointments.data.appointments.length > 0 &&
|
||||
!existingAppointments.data.appointments[0].canceled
|
||||
) {
|
||||
form.setFieldsValue({
|
||||
color: existingAppointments.data.appointments[0].color,
|
||||
|
||||
note: existingAppointments.data.appointments[0].note,
|
||||
});
|
||||
}
|
||||
}, [existingAppointments.data, form]);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("schedule_new_appointment");
|
||||
|
||||
@@ -105,7 +119,7 @@ export function ScheduleJobModalContainer({
|
||||
start: moment(values.start),
|
||||
end: moment(values.start).add(bodyshop.appt_length || 60, "minutes"),
|
||||
color: values.color,
|
||||
note:values.note
|
||||
note: values.note,
|
||||
},
|
||||
jobId: jobId,
|
||||
altTransport: values.alt_transport,
|
||||
@@ -188,6 +202,9 @@ export function ScheduleJobModalContainer({
|
||||
start: null,
|
||||
// smartDates: [],
|
||||
scheduled_completion: null,
|
||||
color: context.color,
|
||||
alt_transport: context.alt_transport,
|
||||
note: context.note,
|
||||
}}
|
||||
>
|
||||
<ScheduleJobModalComponent
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Button, Card, Form, Input, Popover, Space } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import {
|
||||
INSERT_APPOINTMENT,
|
||||
UPDATE_APPOINTMENT,
|
||||
} from "../../graphql/appointments.queries";
|
||||
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
|
||||
|
||||
export default function ScheduleManualEvent({ event }) {
|
||||
const { t } = useTranslation();
|
||||
const [insertAppointment] = useMutation(INSERT_APPOINTMENT);
|
||||
const [updateAppointment] = useMutation(UPDATE_APPOINTMENT);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const [visibility, setVisibility] = useState(false);
|
||||
// const [callQuery, { loading: entryLoading, data: entryData }] = useLazyQuery(
|
||||
// QUERY_SCOREBOARD_ENTRY
|
||||
// );
|
||||
|
||||
useEffect(() => {
|
||||
if (visibility && event) {
|
||||
form.setFieldsValue({ event });
|
||||
}
|
||||
}, [visibility, form, event]);
|
||||
|
||||
useEffect(() => {
|
||||
// if (entryData && entryData.scoreboard && entryData.scoreboard[0]) {
|
||||
// console.log("Setting FOrm");
|
||||
// // form.setFieldsValue(entryData.scoreboard[0]);
|
||||
// }
|
||||
}, [form]);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
logImEXEvent("job_close_add_to_scoreboard");
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
if (event && event.id) {
|
||||
updateAppointment();
|
||||
} else {
|
||||
insertAppointment();
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setVisibility(false);
|
||||
}
|
||||
};
|
||||
|
||||
const overlay = (
|
||||
<Card>
|
||||
<div>
|
||||
<Form form={form} layout="vertical" onFinish={handleFinish}>
|
||||
<Form.Item
|
||||
label={t("schedule.fields.note")}
|
||||
name="note"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("schedule.fields.start")}
|
||||
name="start"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<FormDateTimePickerComponent />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("schedule.fields.end")}
|
||||
name="end"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<FormDateTimePickerComponent />
|
||||
</Form.Item>
|
||||
|
||||
<Space wrap>
|
||||
<Button type="primary" htmlType="submit">
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
<Button onClick={() => setVisibility(false)}>
|
||||
{t("general.actions.cancel")}
|
||||
</Button>
|
||||
</Space>
|
||||
</Form>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
||||
const handleClick = (e) => {
|
||||
setVisibility(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<Popover content={overlay} visible={visibility}>
|
||||
<Button loading={loading} onClick={handleClick}>
|
||||
{t("schedule.labels.manualevent")}
|
||||
</Button>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -17,6 +17,8 @@ import PhoneFormItem, {
|
||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||
|
||||
export default function ShopInfoGeneral({ form }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
@@ -472,6 +474,19 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["md_ded_notes"]}
|
||||
label={t("bodyshop.fields.md_ded_notes")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
type: "array",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select mode="tags" />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow header={t("bodyshop.labels.messagingpresets")}>
|
||||
<Form.List name={["md_messaging_presets"]}>
|
||||
@@ -706,7 +721,7 @@ export default function ShopInfoGeneral({ form }) {
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Space wrap>
|
||||
<Space>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.md_ins_co.zip")}
|
||||
key={`${index}zip`}
|
||||
@@ -744,6 +759,95 @@ export default function ShopInfoGeneral({ form }) {
|
||||
}}
|
||||
</Form.List>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow header={t("bodyshop.labels.estimators")}>
|
||||
<Form.List name={["md_estimators"]}>
|
||||
{(fields, { add, remove, move }) => {
|
||||
return (
|
||||
<div>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item key={field.key}>
|
||||
<LayoutFormRow noDivider>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.est_co_nm")}
|
||||
key={`${index}est_co_nm`}
|
||||
name={[field.name, "est_co_nm"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.est_ct_fn")}
|
||||
key={`${index}est_ct_fn`}
|
||||
name={[field.name, "est_ct_fn"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.est_ct_ln")}
|
||||
key={`${index}est_ct_ln`}
|
||||
name={[field.name, "est_ct_ln"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.est_ph1")}
|
||||
key={`${index}est_ph1`}
|
||||
name={[field.name, "est_ph1"]}
|
||||
rules={[
|
||||
({ getFieldValue }) =>
|
||||
PhoneItemFormatterValidation(getFieldValue, [
|
||||
field.name,
|
||||
"est_ph",
|
||||
]),
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.est_ea")}
|
||||
key={`${index}est_ea`}
|
||||
name={[field.name, "est_ea"]}
|
||||
rules={[
|
||||
{
|
||||
type: "email",
|
||||
message: "This is not a valid email address.",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<FormItemEmail
|
||||
email={form.getFieldValue([field.name, "est_ea"])}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Space>
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
<FormListMoveArrows
|
||||
move={move}
|
||||
index={index}
|
||||
total={fields.length}
|
||||
/>
|
||||
</Space>
|
||||
</LayoutFormRow>
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => {
|
||||
add();
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{t("general.actions.add")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow header={t("bodyshop.fields.md_ccc_rates")}>
|
||||
<Form.List name={["md_ccc_rates"]}>
|
||||
{(fields, { add, remove, move }) => {
|
||||
|
||||
@@ -42,7 +42,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_lab")}
|
||||
@@ -55,7 +55,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_lad")}
|
||||
@@ -68,7 +68,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_lae")}
|
||||
@@ -81,7 +81,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_laf")}
|
||||
@@ -94,7 +94,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_lag")}
|
||||
@@ -107,7 +107,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_lam")}
|
||||
@@ -120,7 +120,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_lar")}
|
||||
@@ -133,7 +133,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_las")}
|
||||
@@ -146,7 +146,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_la1")}
|
||||
@@ -159,7 +159,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_la2")}
|
||||
@@ -172,7 +172,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_la3")}
|
||||
@@ -185,7 +185,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_la4")}
|
||||
@@ -198,7 +198,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_mash")}
|
||||
@@ -211,7 +211,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_mapa")}
|
||||
@@ -224,7 +224,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_ma2s")}
|
||||
@@ -237,7 +237,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_ma3s")}
|
||||
@@ -250,7 +250,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
{
|
||||
// <Form.Item
|
||||
@@ -264,7 +264,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
// },
|
||||
// ]}
|
||||
// >
|
||||
// <CurrencyInput />
|
||||
// <CurrencyInput min={0} />
|
||||
// </Form.Item>
|
||||
// <Form.Item
|
||||
// label={t("jobs.fields.rate_macs")}
|
||||
@@ -277,7 +277,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
// },
|
||||
// ]}
|
||||
// >
|
||||
// <CurrencyInput />
|
||||
// <CurrencyInput min={0} />
|
||||
// </Form.Item>
|
||||
}
|
||||
<Form.Item
|
||||
@@ -291,7 +291,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.rate_mahw")}
|
||||
@@ -304,7 +304,7 @@ export default function ShopInfoLaborRates({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput />
|
||||
<CurrencyInput min={0} />
|
||||
</Form.Item>
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
|
||||
@@ -203,6 +203,14 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
</LayoutFormRow>
|
||||
</>
|
||||
)}
|
||||
|
||||
{bodyshop.pbs_serialnumber && (
|
||||
<>
|
||||
<DataLabel label={t("bodyshop.labels.dms.pbs_serialnumber")}>
|
||||
{form.getFieldValue("pbs_serialnumber")}
|
||||
</DataLabel>
|
||||
</>
|
||||
)}
|
||||
<LayoutFormRow header={t("bodyshop.labels.responsibilitycenters.costs")}>
|
||||
<Form.List name={["md_responsibility_centers", "costs"]}>
|
||||
{(fields, { add, remove }) => {
|
||||
@@ -515,6 +523,27 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t(
|
||||
"bodyshop.fields.responsibilitycenters.laa"
|
||||
)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
key={`${index}costs-LAA`}
|
||||
name={[field.name, "costs", "LAA"]}
|
||||
>
|
||||
<Select>
|
||||
{costOptions.map((item, idx) => (
|
||||
<Select.Option key={idx} value={item}>
|
||||
{item}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t(
|
||||
"bodyshop.fields.responsibilitycenters.lab"
|
||||
@@ -1086,6 +1115,27 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t(
|
||||
"bodyshop.fields.responsibilitycenters.laa"
|
||||
)}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
key={`${index}profits-LAA`}
|
||||
name={[field.name, "profits", "LAA"]}
|
||||
>
|
||||
<Select>
|
||||
{profitOptions.map((item, idx) => (
|
||||
<Select.Option key={idx} value={item}>
|
||||
{item}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t(
|
||||
"bodyshop.fields.responsibilitycenters.lab"
|
||||
@@ -1673,6 +1723,24 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.responsibilitycenters.laa")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
name={["md_responsibility_centers", "defaults", "costs", "LAA"]}
|
||||
>
|
||||
<Select>
|
||||
{costOptions.map((item, idx) => (
|
||||
<Select.Option key={idx} value={item}>
|
||||
{item}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.responsibilitycenters.lab")}
|
||||
rules={[
|
||||
@@ -2161,6 +2229,24 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.responsibilitycenters.laa")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
name={["md_responsibility_centers", "defaults", "profits", "LAA"]}
|
||||
>
|
||||
<Select>
|
||||
{profitOptions.map((item, idx) => (
|
||||
<Select.Option key={idx} value={item}>
|
||||
{item}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.responsibilitycenters.lab")}
|
||||
rules={[
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import { Form, Select } from "antd";
|
||||
import { DeleteFilled } from "@ant-design/icons";
|
||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||
import { Button, Form, Select, Space } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { ChromePicker } from "react-color";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import styled from "styled-components";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
|
||||
const SelectorDiv = styled.div`
|
||||
.ant-form-item .ant-select {
|
||||
width: 200px;
|
||||
@@ -11,6 +15,9 @@ const SelectorDiv = styled.div`
|
||||
|
||||
export default function ShopInfoROStatusComponent({ form }) {
|
||||
const { t } = useTranslation();
|
||||
const { Production_List_Status_Colors } = useTreatments([
|
||||
"Production_List_Status_Colors",
|
||||
]);
|
||||
|
||||
const [options, setOptions] = useState(
|
||||
form.getFieldValue(["md_ro_statuses", "statuses"]) || []
|
||||
@@ -257,6 +264,97 @@ export default function ShopInfoROStatusComponent({ form }) {
|
||||
</Select>
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
{Production_List_Status_Colors.treatment === "on" && (
|
||||
<LayoutFormRow
|
||||
grow
|
||||
header={t("bodyshop.fields.statuses.production_colors")}
|
||||
>
|
||||
<Form.List name={["md_ro_statuses", "production_colors"]}>
|
||||
{(fields, { add, remove, move }) => {
|
||||
return (
|
||||
<div>
|
||||
<LayoutFormRow>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item key={field.key}>
|
||||
<Space direction="vertical">
|
||||
<div style={{ display: "flex" }}>
|
||||
<Form.Item
|
||||
style={{ flex: 1 }}
|
||||
label={t("jobs.fields.status")}
|
||||
key={`${index}status`}
|
||||
name={[field.name, "status"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select>
|
||||
{options.map((item, idx) => (
|
||||
<Select.Option key={idx} value={item}>
|
||||
{item}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.statuses.color")}
|
||||
key={`${index}color`}
|
||||
name={[field.name, "color"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<ColorPicker />
|
||||
</Form.Item>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
))}
|
||||
</LayoutFormRow>
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => {
|
||||
add();
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{t("general.actions.add")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
</LayoutFormRow>
|
||||
)}
|
||||
</SelectorDiv>
|
||||
);
|
||||
}
|
||||
|
||||
const ColorPicker = ({ value, onChange, style, ...restProps }) => {
|
||||
const handleChange = (color) => {
|
||||
console.log(
|
||||
"🚀 ~ file: shop-info.rostatus.component.jsx ~ line 345 ~ color",
|
||||
color
|
||||
);
|
||||
if (onChange) onChange(color.rgb);
|
||||
};
|
||||
return (
|
||||
<ChromePicker
|
||||
{...restProps}
|
||||
color={value}
|
||||
onChangeComplete={handleChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -44,7 +44,7 @@ export default function ShopInfoSchedulingComponent({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<TimePicker showSecond={false} format="hh:mm" />
|
||||
<TimePicker showSecond={false} format="HH:mm" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.schedule_end_time")}
|
||||
@@ -56,7 +56,7 @@ export default function ShopInfoSchedulingComponent({ form }) {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<TimePicker showSecond={false} format="hh:mm" />
|
||||
<TimePicker showSecond={false} format="HH:mm" />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name={["appt_alt_transport"]}
|
||||
|
||||
@@ -50,7 +50,9 @@ export function TechClockInComponent({ form, bodyshop, technician }) {
|
||||
{emps &&
|
||||
emps.rates.map((item) => (
|
||||
<Select.Option key={item.cost_center}>
|
||||
{item.cost_center}
|
||||
{item.cost_center === "timetickets.labels.shift"
|
||||
? t(item.cost_center)
|
||||
: item.cost_center}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
|
||||
@@ -139,7 +139,9 @@ export function TechClockOffButton({
|
||||
emps &&
|
||||
emps.rates.map((item) => (
|
||||
<Select.Option key={item.cost_center}>
|
||||
{item.cost_center}
|
||||
{item.cost_center === "timetickets.labels.shift"
|
||||
? t(item.cost_center)
|
||||
: item.cost_center}
|
||||
</Select.Option>
|
||||
))
|
||||
)}
|
||||
|
||||
@@ -83,7 +83,9 @@ export function TechClockedInList({ technician }) {
|
||||
<DateTimeFormatter>{ticket.clockon}</DateTimeFormatter>
|
||||
</DataLabel>
|
||||
<DataLabel label={t("timetickets.fields.cost_center")}>
|
||||
{ticket.cost_center}
|
||||
{ticket.cost_center === "timetickets.labels.shift"
|
||||
? t(ticket.cost_center)
|
||||
: ticket.cost_center}
|
||||
</DataLabel>
|
||||
</Card>
|
||||
</List.Item>
|
||||
|
||||
@@ -28,6 +28,7 @@ export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
|
||||
ownr_co_nm
|
||||
ownr_fn
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_ea
|
||||
clm_total
|
||||
id
|
||||
@@ -126,6 +127,7 @@ export const QUERY_APPOINTMENT_BY_DATE = gql`
|
||||
ownr_ln
|
||||
ownr_fn
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_ea
|
||||
clm_total
|
||||
id
|
||||
@@ -194,10 +196,11 @@ export const CANCEL_APPOINTMENT_BY_ID = gql`
|
||||
|
||||
export const QUERY_APPOINTMENTS_BY_JOBID = gql`
|
||||
query QUERY_APPOINTMENTS_BY_JOBID($jobid: uuid!) {
|
||||
appointments(where: { jobid: { _eq: $jobid } }) {
|
||||
appointments(where: { jobid: { _eq: $jobid } }, order_by: { start: desc }) {
|
||||
start
|
||||
id
|
||||
end
|
||||
color
|
||||
isintake
|
||||
arrived
|
||||
canceled
|
||||
|
||||
@@ -93,6 +93,7 @@ export const QUERY_BILLS_BY_JOBID = gql`
|
||||
backordered_on
|
||||
}
|
||||
order_number
|
||||
comments
|
||||
user_email
|
||||
}
|
||||
bills(where: { jobid: { _eq: $jobid } }, order_by: { date: desc }) {
|
||||
|
||||
@@ -94,6 +94,10 @@ export const QUERY_BODYSHOP = gql`
|
||||
attach_pdf_to_email
|
||||
tt_allow_post_to_invoiced
|
||||
cdk_configuration
|
||||
md_estimators
|
||||
md_ded_notes
|
||||
pbs_configuration
|
||||
pbs_serialnumber
|
||||
employees {
|
||||
id
|
||||
active
|
||||
@@ -184,6 +188,10 @@ export const UPDATE_SHOP = gql`
|
||||
attach_pdf_to_email
|
||||
tt_allow_post_to_invoiced
|
||||
cdk_configuration
|
||||
md_estimators
|
||||
md_ded_notes
|
||||
pbs_configuration
|
||||
pbs_serialnumber
|
||||
employees {
|
||||
id
|
||||
first_name
|
||||
|
||||
@@ -10,6 +10,7 @@ export const QUERY_ALL_ACTIVE_JOBS = gql`
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_ea
|
||||
owner {
|
||||
id
|
||||
@@ -79,6 +80,7 @@ export const QUERY_PARTS_QUEUE = gql`
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_ea
|
||||
plate_no
|
||||
plate_st
|
||||
@@ -122,9 +124,11 @@ export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
|
||||
actual_in
|
||||
scheduled_completion
|
||||
scheduled_delivery
|
||||
date_last_contacted
|
||||
ins_co_nm
|
||||
clm_total
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
special_coverage_policy
|
||||
owner_owing
|
||||
production_vars
|
||||
@@ -359,6 +363,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
kmin
|
||||
kmout
|
||||
referral_source
|
||||
referral_source_extra
|
||||
unit_number
|
||||
po_number
|
||||
special_coverage_policy
|
||||
@@ -380,6 +385,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
vehicleid
|
||||
driveable
|
||||
towin
|
||||
loss_of_use
|
||||
vehicle {
|
||||
id
|
||||
plate_no
|
||||
@@ -454,9 +460,11 @@ export const GET_JOB_BY_PK = gql`
|
||||
ownr_zip
|
||||
ownr_ctry
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
production_vars
|
||||
ca_gst_registrant
|
||||
ownerid
|
||||
ded_note
|
||||
owner {
|
||||
id
|
||||
ownr_fn
|
||||
@@ -470,6 +478,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
ownr_zip
|
||||
ownr_ctry
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
}
|
||||
labor_rate_desc
|
||||
rate_la1
|
||||
@@ -508,6 +517,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
date_open
|
||||
date_scheduled
|
||||
date_invoiced
|
||||
date_last_contacted
|
||||
date_exported
|
||||
status
|
||||
owner_owing
|
||||
@@ -563,6 +573,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
parts_order {
|
||||
id
|
||||
order_number
|
||||
comments
|
||||
order_date
|
||||
user_email
|
||||
vendor {
|
||||
@@ -626,7 +637,7 @@ export const GET_JOB_RECONCILIATION_BY_PK = gql`
|
||||
is_credit_memo
|
||||
isinhouse
|
||||
exported
|
||||
billlines {
|
||||
billlines(where: { deductedfromlbr: { _eq: false } }) {
|
||||
actual_price
|
||||
quantity
|
||||
actual_cost
|
||||
@@ -684,8 +695,10 @@ export const QUERY_JOB_CARD_DETAILS = gql`
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_ea
|
||||
ca_gst_registrant
|
||||
owner_owing
|
||||
special_coverage_policy
|
||||
available_jobs {
|
||||
id
|
||||
@@ -724,6 +737,7 @@ export const QUERY_JOB_CARD_DETAILS = gql`
|
||||
actual_completion
|
||||
actual_delivery
|
||||
actual_in
|
||||
scheduled_in
|
||||
po_number
|
||||
id
|
||||
ins_co_nm
|
||||
@@ -745,6 +759,7 @@ export const QUERY_JOB_CARD_DETAILS = gql`
|
||||
scheduled_in
|
||||
scheduled_delivery
|
||||
date_invoiced
|
||||
date_last_contacted
|
||||
date_open
|
||||
date_exported
|
||||
|
||||
@@ -830,6 +845,7 @@ export const QUERY_TECH_JOB_DETAILS = gql`
|
||||
scheduled_in
|
||||
scheduled_delivery
|
||||
date_invoiced
|
||||
date_last_contacted
|
||||
date_open
|
||||
date_exported
|
||||
voided
|
||||
@@ -964,6 +980,7 @@ export const CONVERT_JOB_TO_RO = gql`
|
||||
$driveable: Boolean
|
||||
$towin: Boolean
|
||||
$referral_source: String
|
||||
$referral_source_extra: String
|
||||
) {
|
||||
update_jobs(
|
||||
where: { id: { _eq: $jobId } }
|
||||
@@ -975,6 +992,7 @@ export const CONVERT_JOB_TO_RO = gql`
|
||||
towin: $towin
|
||||
driveable: $driveable
|
||||
referral_source: $referral_source
|
||||
referral_source_extra: $referral_source_extra
|
||||
}
|
||||
) {
|
||||
returning {
|
||||
@@ -984,6 +1002,7 @@ export const CONVERT_JOB_TO_RO = gql`
|
||||
class
|
||||
ins_co_nm
|
||||
referral_source
|
||||
referral_source_extra
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1008,6 +1027,7 @@ export const GET_JOB_INFO_FOR_STRIPE = gql`
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_ea
|
||||
}
|
||||
}
|
||||
@@ -1497,6 +1517,7 @@ export const QUERY_ALL_JOB_FIELDS = gql`
|
||||
rate_mash
|
||||
rate_matd
|
||||
referral_source
|
||||
referral_source_extra
|
||||
regie_number
|
||||
selling_dealer
|
||||
selling_dealer_contact
|
||||
@@ -1643,6 +1664,7 @@ export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
|
||||
ownr_co_nm
|
||||
ownerid
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_ea
|
||||
plate_no
|
||||
plate_st
|
||||
@@ -1750,7 +1772,7 @@ export const QUERY_JOB_CLOSE_DETAILS = gql`
|
||||
actual_in
|
||||
kmin
|
||||
kmout
|
||||
joblines(where: { removed: { _eq: false } }) {
|
||||
joblines(where: { removed: { _eq: false } }, order_by: { line_no: asc }) {
|
||||
id
|
||||
removed
|
||||
tax_part
|
||||
@@ -1858,6 +1880,7 @@ export const GET_JOB_FOR_CC_CONTRACT = gql`
|
||||
ownr_city
|
||||
ownr_zip
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -2,7 +2,7 @@ import { gql } from "@apollo/client";
|
||||
|
||||
export const QUERY_SEARCH_OWNER_BY_IDX = gql`
|
||||
query QUERY_SEARCH_OWNER_BY_IDX($search: String!) {
|
||||
search_owners(args: { search: $search }) {
|
||||
search_owners(args: { search: $search }, limit: 100) {
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
ownr_ph1
|
||||
|
||||
@@ -23,6 +23,7 @@ export const GLOBAL_SEARCH_QUERY = gql`
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
}
|
||||
search_vehicles(args: { search: $search }) {
|
||||
id
|
||||
|
||||
@@ -23,6 +23,11 @@ Dinero.globalRoundingMode = "HALF_EVEN";
|
||||
if (process.env.NODE_ENV !== "development") {
|
||||
Sentry.init({
|
||||
dsn: "https://fd7e89369b6b4bdc9c6c4c9f22fa4ee4@o492140.ingest.sentry.io/5651027",
|
||||
ignoreErrors: [
|
||||
"ResizeObserver loop",
|
||||
"Module specifier, 'fs' does not start",
|
||||
"Module specifier, 'zlib' does not start with",
|
||||
],
|
||||
integrations: [
|
||||
// new Integrations.BrowserTracing(),
|
||||
// new Sentry.Integrations.Breadcrumbs({ console: true }),
|
||||
|
||||
@@ -612,7 +612,7 @@ export const Pricing11DataSource = {
|
||||
<br /> 14500GB流量包
|
||||
<br /> 14国内按峰值宽带账单
|
||||
<br /> 14弹性计算
|
||||
<br /> 14云服务器 ECS{" "}
|
||||
<br /> 14云服务器 ECS
|
||||
</span>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -196,7 +196,11 @@ export function JobsDetailPage({
|
||||
<PrinterFilled />
|
||||
{t("jobs.actions.printCenter")}
|
||||
</Button>
|
||||
<JobsConvertButton job={job} refetch={refetch} />
|
||||
<JobsConvertButton
|
||||
job={job}
|
||||
refetch={refetch}
|
||||
parentFormIsFieldsTouched={form.isFieldsTouched}
|
||||
/>
|
||||
<JobsDetailHeaderActions key="actions" job={job} refetch={refetch} />
|
||||
<Button
|
||||
type="primary"
|
||||
|
||||
@@ -5,12 +5,12 @@ import preval from "preval.macro";
|
||||
import React, { lazy, Suspense, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
|
||||
import { Link, Route, Switch } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component";
|
||||
import ChatAffixContainer from "../../components/chat-affix/chat-affix.container";
|
||||
import ConflictComponent from "../../components/conflict/conflict.component";
|
||||
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
|
||||
import FcmNotification from "../../components/fcm-notification/fcm-notification.component";
|
||||
//import FooterComponent from "../../components/footer/footer.component";
|
||||
//Component Imports
|
||||
|
||||
@@ -6,8 +6,8 @@ import AlertComponent from "../../components/alert/alert.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
||||
import { setBodyshop } from "../../redux/user/user.actions";
|
||||
import ManagePage from "./manage.page.component";
|
||||
import "../../utils/RegisterSw";
|
||||
import ManagePage from "./manage.page.component";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBodyshop: (bs) => dispatch(setBodyshop(bs)),
|
||||
@@ -21,7 +21,9 @@ function ManagePageContainer({ match, setBodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (data) setBodyshop(data.bodyshops[0] || { notfound: true });
|
||||
if (data) {
|
||||
setBodyshop(data.bodyshops[0] || { notfound: true });
|
||||
}
|
||||
}, [data, setBodyshop]);
|
||||
|
||||
if (loading)
|
||||
|
||||
@@ -13,7 +13,7 @@ import { doc } from "firebase/firestore";
|
||||
import i18next from "i18next";
|
||||
import LogRocket from "logrocket";
|
||||
import { all, call, delay, put, select, takeLatest } from "redux-saga/effects";
|
||||
import { tracker } from "../../App/App.container";
|
||||
import { factory, tracker } from "../../App/App.container";
|
||||
import {
|
||||
getCurrentUser,
|
||||
logImEXEvent,
|
||||
@@ -250,6 +250,8 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
|
||||
try {
|
||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||
|
||||
factory.client(payload.imexshopid);
|
||||
|
||||
const authRecord = payload.associations.filter(
|
||||
(a) => a.useremail === userEmail
|
||||
);
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
"md_categories": "Categories",
|
||||
"md_ccc_rates": "Courtesy Car Contract Rate Presets",
|
||||
"md_classes": "Classes",
|
||||
"md_ded_notes": "Deductible Notes",
|
||||
"md_hour_split": {
|
||||
"paint": "Paint Hour Split",
|
||||
"prep": "Prep Hour Split"
|
||||
@@ -396,6 +397,7 @@
|
||||
"la2": "LA2",
|
||||
"la3": "LA3",
|
||||
"la4": "LA4",
|
||||
"laa": "Aluminum",
|
||||
"lab": "Body",
|
||||
"lad": "Diagnostic",
|
||||
"lae": "Electrical",
|
||||
@@ -449,6 +451,7 @@
|
||||
"status": "Status Label",
|
||||
"statuses": {
|
||||
"active_statuses": "Active Statuses (Filtering for Active Jobs throughout system)",
|
||||
"color": "Color",
|
||||
"default_arrived": "Default Arrived Status (Transition to Production)",
|
||||
"default_bo": "Default Backordered Status",
|
||||
"default_canceled": "Default Canceled Status",
|
||||
@@ -465,6 +468,7 @@
|
||||
"open_statuses": "Open Statuses",
|
||||
"post_production_statuses": "Post-Production Statuses",
|
||||
"pre_production_statuses": "Pre-Production Statuses",
|
||||
"production_colors": "Production Status Colors",
|
||||
"production_statuses": "Production Statuses"
|
||||
},
|
||||
"target_touchtime": "Target Touch Time",
|
||||
@@ -498,6 +502,7 @@
|
||||
},
|
||||
"emaillater": "Email Later",
|
||||
"employees": "Employees",
|
||||
"estimators": "Estimators",
|
||||
"insurancecos": "Insurance Companies",
|
||||
"intakechecklist": "Intake Checklist",
|
||||
"jobstatuses": "Job Statuses",
|
||||
@@ -1052,8 +1057,10 @@
|
||||
},
|
||||
"profitcenter_labor": "Profit Center: Labor",
|
||||
"profitcenter_part": "Profit Center: Part",
|
||||
"prt_dsmk_p": "Line Markup %",
|
||||
"prt_dsmk_m": "Line Discount/Markup $",
|
||||
"prt_dsmk_p": "Line Discount/Markup %",
|
||||
"status": "Status",
|
||||
"tax_part": "Tax Part",
|
||||
"total": "Total",
|
||||
"unq_seq": "Seq #"
|
||||
},
|
||||
@@ -1086,6 +1093,7 @@
|
||||
"autoallocate": "Auto Allocate",
|
||||
"changelaborrate": "Change Labor Rate",
|
||||
"changestatus": "Change Status",
|
||||
"changestimator": "Change Estimator",
|
||||
"convert": "Convert",
|
||||
"deliver": "Deliver",
|
||||
"dms": {
|
||||
@@ -1196,9 +1204,11 @@
|
||||
"date_estimated": "Date Estimated",
|
||||
"date_exported": "Exported",
|
||||
"date_invoiced": "Invoiced",
|
||||
"date_last_contacted": "Last Contacted Date",
|
||||
"date_open": "Open",
|
||||
"date_scheduled": "Scheduled",
|
||||
"ded_amt": "Deductible",
|
||||
"ded_note": "Deductible Note",
|
||||
"ded_status": "Deductible Status",
|
||||
"depreciation_taxes": "Depreciation/Taxes",
|
||||
"dms": {
|
||||
@@ -1274,6 +1284,7 @@
|
||||
"local_tax_rate": "Local Tax Rate",
|
||||
"loss_date": "Loss Date",
|
||||
"loss_desc": "Loss Description",
|
||||
"loss_of_use": "Loss of Use",
|
||||
"ma2s": "2 Stage Paint",
|
||||
"ma3s": "3 Stage Pain",
|
||||
"mabl": "MABL?",
|
||||
@@ -1287,6 +1298,7 @@
|
||||
"owner_owing": "Cust. Owes",
|
||||
"ownr_ea": "Email",
|
||||
"ownr_ph1": "Phone 1",
|
||||
"ownr_ph2": "Phone 2",
|
||||
"paa": "Aftermarket",
|
||||
"pac": "Rechromed",
|
||||
"pae": "Existing",
|
||||
@@ -1335,6 +1347,8 @@
|
||||
"rate_mapa": "Paint Materials",
|
||||
"rate_mash": "Shop Material",
|
||||
"rate_matd": "Tire Disposal",
|
||||
"referral_source_extra": "Other Referral Source",
|
||||
"referral_source_other": "",
|
||||
"referralsource": "Referral Source",
|
||||
"regie_number": "Registration #",
|
||||
"repairtotal": "Repair Total",
|
||||
@@ -1520,6 +1534,7 @@
|
||||
"sale_labor": "Sales - Labor",
|
||||
"sale_parts": "Sales - Parts & 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. ",
|
||||
"specialcoveragepolicy": "Special Coverage Policy Applies",
|
||||
"state_tax_amt": "Provincial/State Taxes",
|
||||
@@ -1733,6 +1748,9 @@
|
||||
"edit": "Edit Note",
|
||||
"new": "New Note"
|
||||
},
|
||||
"errors": {
|
||||
"inserting": "Error inserting note. {{error}}"
|
||||
},
|
||||
"fields": {
|
||||
"createdby": "Created By",
|
||||
"critical": "Critical",
|
||||
@@ -1741,7 +1759,8 @@
|
||||
"updatedat": "Updated At"
|
||||
},
|
||||
"labels": {
|
||||
"newnoteplaceholder": "Add a note..."
|
||||
"newnoteplaceholder": "Add a note...",
|
||||
"notetoadd": "Note to Add"
|
||||
},
|
||||
"successes": {
|
||||
"create": "Note created successfully.",
|
||||
@@ -1770,6 +1789,7 @@
|
||||
"ownr_fn": "First Name",
|
||||
"ownr_ln": "Last Name",
|
||||
"ownr_ph1": "Phone 1",
|
||||
"ownr_ph2": "Phone 2",
|
||||
"ownr_st": "Province/State",
|
||||
"ownr_title": "Title",
|
||||
"ownr_zip": "Zip/Postal Code",
|
||||
@@ -1811,9 +1831,10 @@
|
||||
"act_price": "Price",
|
||||
"backordered_eta": "B.O. ETA",
|
||||
"backordered_on": "B.O. On",
|
||||
"comments": "Comments",
|
||||
"cost": "Cost",
|
||||
"db_price": "List Price",
|
||||
"deliver_by": "Date",
|
||||
"deliver_by": "Deliver By",
|
||||
"job_line_id": "Job Line Id",
|
||||
"line_desc": "Line Description",
|
||||
"line_remarks": "Remarks",
|
||||
@@ -1966,9 +1987,13 @@
|
||||
"guarantee": "Repair Guarantee",
|
||||
"invoice_customer_payable": "Invoice (Customer Payable)",
|
||||
"invoice_total_payable": "Invoice (Total Payable)",
|
||||
"iou_form": "IOU Form",
|
||||
"job_costing_ro": "Job Costing",
|
||||
"job_notes": "Job Notes",
|
||||
"key_tag": "Key Tag",
|
||||
"mpi_animal_checklist": "MPI - Animal Checklist",
|
||||
"mpi_eglass_auth": "MPI - eGlass Auth",
|
||||
"mpi_final_acct_sheet": "MPI - Final Accounting Sheet",
|
||||
"paint_grid": "Paint Grid",
|
||||
"parts_label_single": "Parts Label - Single",
|
||||
"parts_list": "Parts List",
|
||||
@@ -2020,7 +2045,7 @@
|
||||
},
|
||||
"subjects": {
|
||||
"jobs": {
|
||||
"parts_order": "$t(printcenter.jobs.parts_order) PO: {{ro_number}}"
|
||||
"parts_order": "Parts Order PO: {{ro_number}}"
|
||||
}
|
||||
},
|
||||
"vendors": {
|
||||
@@ -2182,6 +2207,11 @@
|
||||
"work_in_progress_payables": "Work in Progress - Payables"
|
||||
}
|
||||
},
|
||||
"schedule": {
|
||||
"labels": {
|
||||
"manualevent": "Add Manual Event"
|
||||
}
|
||||
},
|
||||
"scoreboard": {
|
||||
"actions": {
|
||||
"edit": "Edit"
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
"md_categories": "",
|
||||
"md_ccc_rates": "",
|
||||
"md_classes": "",
|
||||
"md_ded_notes": "",
|
||||
"md_hour_split": {
|
||||
"paint": "",
|
||||
"prep": ""
|
||||
@@ -396,6 +397,7 @@
|
||||
"la2": "",
|
||||
"la3": "",
|
||||
"la4": "",
|
||||
"laa": "",
|
||||
"lab": "",
|
||||
"lad": "",
|
||||
"lae": "",
|
||||
@@ -449,6 +451,7 @@
|
||||
"status": "",
|
||||
"statuses": {
|
||||
"active_statuses": "",
|
||||
"color": "",
|
||||
"default_arrived": "",
|
||||
"default_bo": "",
|
||||
"default_canceled": "",
|
||||
@@ -465,6 +468,7 @@
|
||||
"open_statuses": "",
|
||||
"post_production_statuses": "",
|
||||
"pre_production_statuses": "",
|
||||
"production_colors": "",
|
||||
"production_statuses": ""
|
||||
},
|
||||
"target_touchtime": "",
|
||||
@@ -498,6 +502,7 @@
|
||||
},
|
||||
"emaillater": "",
|
||||
"employees": "",
|
||||
"estimators": "",
|
||||
"insurancecos": "",
|
||||
"intakechecklist": "",
|
||||
"jobstatuses": "",
|
||||
@@ -1052,8 +1057,10 @@
|
||||
},
|
||||
"profitcenter_labor": "",
|
||||
"profitcenter_part": "",
|
||||
"prt_dsmk_m": "",
|
||||
"prt_dsmk_p": "",
|
||||
"status": "Estado",
|
||||
"tax_part": "",
|
||||
"total": "",
|
||||
"unq_seq": "Seq #"
|
||||
},
|
||||
@@ -1086,6 +1093,7 @@
|
||||
"autoallocate": "",
|
||||
"changelaborrate": "",
|
||||
"changestatus": "Cambiar Estado",
|
||||
"changestimator": "",
|
||||
"convert": "Convertir",
|
||||
"deliver": "",
|
||||
"dms": {
|
||||
@@ -1196,9 +1204,11 @@
|
||||
"date_estimated": "Fecha estimada",
|
||||
"date_exported": "Exportado",
|
||||
"date_invoiced": "Facturado",
|
||||
"date_last_contacted": "",
|
||||
"date_open": "Abierto",
|
||||
"date_scheduled": "Programado",
|
||||
"ded_amt": "Deducible",
|
||||
"ded_note": "",
|
||||
"ded_status": "Estado deducible",
|
||||
"depreciation_taxes": "Depreciación / Impuestos",
|
||||
"dms": {
|
||||
@@ -1274,6 +1284,7 @@
|
||||
"local_tax_rate": "",
|
||||
"loss_date": "Fecha de pérdida",
|
||||
"loss_desc": "",
|
||||
"loss_of_use": "",
|
||||
"ma2s": "",
|
||||
"ma3s": "",
|
||||
"mabl": "",
|
||||
@@ -1287,6 +1298,7 @@
|
||||
"owner_owing": "Cust. Debe",
|
||||
"ownr_ea": "Email",
|
||||
"ownr_ph1": "Teléfono 1",
|
||||
"ownr_ph2": "",
|
||||
"paa": "",
|
||||
"pac": "",
|
||||
"pae": "",
|
||||
@@ -1335,6 +1347,8 @@
|
||||
"rate_mapa": "Tasa de materiales de pintura",
|
||||
"rate_mash": "Comprar material de tarifa",
|
||||
"rate_matd": "Tasa de eliminación de neumáticos",
|
||||
"referral_source_extra": "",
|
||||
"referral_source_other": "",
|
||||
"referralsource": "Fuente de referencia",
|
||||
"regie_number": "N. ° de registro",
|
||||
"repairtotal": "Reparación total",
|
||||
@@ -1520,6 +1534,7 @@
|
||||
"sale_labor": "",
|
||||
"sale_parts": "",
|
||||
"sales": "",
|
||||
"savebeforeconversion": "",
|
||||
"scheduledinchange": "",
|
||||
"specialcoveragepolicy": "",
|
||||
"state_tax_amt": "",
|
||||
@@ -1733,6 +1748,9 @@
|
||||
"edit": "Editar nota",
|
||||
"new": "Nueva nota"
|
||||
},
|
||||
"errors": {
|
||||
"inserting": ""
|
||||
},
|
||||
"fields": {
|
||||
"createdby": "Creado por",
|
||||
"critical": "Crítico",
|
||||
@@ -1741,7 +1759,8 @@
|
||||
"updatedat": "Actualizado en"
|
||||
},
|
||||
"labels": {
|
||||
"newnoteplaceholder": "Agrega una nota..."
|
||||
"newnoteplaceholder": "Agrega una nota...",
|
||||
"notetoadd": ""
|
||||
},
|
||||
"successes": {
|
||||
"create": "Nota creada con éxito.",
|
||||
@@ -1770,6 +1789,7 @@
|
||||
"ownr_fn": "Nombre de pila",
|
||||
"ownr_ln": "Apellido",
|
||||
"ownr_ph1": "Teléfono 1",
|
||||
"ownr_ph2": "",
|
||||
"ownr_st": "Provincia del estado",
|
||||
"ownr_title": "Título",
|
||||
"ownr_zip": "código postal",
|
||||
@@ -1811,6 +1831,7 @@
|
||||
"act_price": "",
|
||||
"backordered_eta": "",
|
||||
"backordered_on": "",
|
||||
"comments": "",
|
||||
"cost": "",
|
||||
"db_price": "",
|
||||
"deliver_by": "",
|
||||
@@ -1966,9 +1987,13 @@
|
||||
"guarantee": "",
|
||||
"invoice_customer_payable": "",
|
||||
"invoice_total_payable": "",
|
||||
"iou_form": "",
|
||||
"job_costing_ro": "",
|
||||
"job_notes": "",
|
||||
"key_tag": "",
|
||||
"mpi_animal_checklist": "",
|
||||
"mpi_eglass_auth": "",
|
||||
"mpi_final_acct_sheet": "",
|
||||
"paint_grid": "",
|
||||
"parts_label_single": "",
|
||||
"parts_list": "",
|
||||
@@ -2182,6 +2207,11 @@
|
||||
"work_in_progress_payables": ""
|
||||
}
|
||||
},
|
||||
"schedule": {
|
||||
"labels": {
|
||||
"manualevent": ""
|
||||
}
|
||||
},
|
||||
"scoreboard": {
|
||||
"actions": {
|
||||
"edit": ""
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
"md_categories": "",
|
||||
"md_ccc_rates": "",
|
||||
"md_classes": "",
|
||||
"md_ded_notes": "",
|
||||
"md_hour_split": {
|
||||
"paint": "",
|
||||
"prep": ""
|
||||
@@ -396,6 +397,7 @@
|
||||
"la2": "",
|
||||
"la3": "",
|
||||
"la4": "",
|
||||
"laa": "",
|
||||
"lab": "",
|
||||
"lad": "",
|
||||
"lae": "",
|
||||
@@ -449,6 +451,7 @@
|
||||
"status": "",
|
||||
"statuses": {
|
||||
"active_statuses": "",
|
||||
"color": "",
|
||||
"default_arrived": "",
|
||||
"default_bo": "",
|
||||
"default_canceled": "",
|
||||
@@ -465,6 +468,7 @@
|
||||
"open_statuses": "",
|
||||
"post_production_statuses": "",
|
||||
"pre_production_statuses": "",
|
||||
"production_colors": "",
|
||||
"production_statuses": ""
|
||||
},
|
||||
"target_touchtime": "",
|
||||
@@ -498,6 +502,7 @@
|
||||
},
|
||||
"emaillater": "",
|
||||
"employees": "",
|
||||
"estimators": "",
|
||||
"insurancecos": "",
|
||||
"intakechecklist": "",
|
||||
"jobstatuses": "",
|
||||
@@ -1052,8 +1057,10 @@
|
||||
},
|
||||
"profitcenter_labor": "",
|
||||
"profitcenter_part": "",
|
||||
"prt_dsmk_m": "",
|
||||
"prt_dsmk_p": "",
|
||||
"status": "Statut",
|
||||
"tax_part": "",
|
||||
"total": "",
|
||||
"unq_seq": "Seq #"
|
||||
},
|
||||
@@ -1086,6 +1093,7 @@
|
||||
"autoallocate": "",
|
||||
"changelaborrate": "",
|
||||
"changestatus": "Changer le statut",
|
||||
"changestimator": "",
|
||||
"convert": "Convertir",
|
||||
"deliver": "",
|
||||
"dms": {
|
||||
@@ -1196,9 +1204,11 @@
|
||||
"date_estimated": "Date estimée",
|
||||
"date_exported": "Exportés",
|
||||
"date_invoiced": "Facturé",
|
||||
"date_last_contacted": "",
|
||||
"date_open": "Ouvrir",
|
||||
"date_scheduled": "Prévu",
|
||||
"ded_amt": "Déductible",
|
||||
"ded_note": "",
|
||||
"ded_status": "Statut de franchise",
|
||||
"depreciation_taxes": "Amortissement / taxes",
|
||||
"dms": {
|
||||
@@ -1274,6 +1284,7 @@
|
||||
"local_tax_rate": "",
|
||||
"loss_date": "Date de perte",
|
||||
"loss_desc": "",
|
||||
"loss_of_use": "",
|
||||
"ma2s": "",
|
||||
"ma3s": "",
|
||||
"mabl": "",
|
||||
@@ -1287,6 +1298,7 @@
|
||||
"owner_owing": "Cust. Owes",
|
||||
"ownr_ea": "Email",
|
||||
"ownr_ph1": "Téléphone 1",
|
||||
"ownr_ph2": "",
|
||||
"paa": "",
|
||||
"pac": "",
|
||||
"pae": "",
|
||||
@@ -1335,6 +1347,8 @@
|
||||
"rate_mapa": "Taux de matériaux de peinture",
|
||||
"rate_mash": "Tarif du matériel de la boutique",
|
||||
"rate_matd": "Taux d'élimination des pneus",
|
||||
"referral_source_extra": "",
|
||||
"referral_source_other": "",
|
||||
"referralsource": "Source de référence",
|
||||
"regie_number": "Enregistrement #",
|
||||
"repairtotal": "Réparation totale",
|
||||
@@ -1520,6 +1534,7 @@
|
||||
"sale_labor": "",
|
||||
"sale_parts": "",
|
||||
"sales": "",
|
||||
"savebeforeconversion": "",
|
||||
"scheduledinchange": "",
|
||||
"specialcoveragepolicy": "",
|
||||
"state_tax_amt": "",
|
||||
@@ -1733,6 +1748,9 @@
|
||||
"edit": "Note éditée",
|
||||
"new": "Nouvelle note"
|
||||
},
|
||||
"errors": {
|
||||
"inserting": ""
|
||||
},
|
||||
"fields": {
|
||||
"createdby": "Créé par",
|
||||
"critical": "Critique",
|
||||
@@ -1741,7 +1759,8 @@
|
||||
"updatedat": "Mis à jour à"
|
||||
},
|
||||
"labels": {
|
||||
"newnoteplaceholder": "Ajouter une note..."
|
||||
"newnoteplaceholder": "Ajouter une note...",
|
||||
"notetoadd": ""
|
||||
},
|
||||
"successes": {
|
||||
"create": "Remarque créée avec succès.",
|
||||
@@ -1770,6 +1789,7 @@
|
||||
"ownr_fn": "Prénom",
|
||||
"ownr_ln": "Nom de famille",
|
||||
"ownr_ph1": "Téléphone 1",
|
||||
"ownr_ph2": "",
|
||||
"ownr_st": "Etat / Province",
|
||||
"ownr_title": "Titre",
|
||||
"ownr_zip": "Zip / code postal",
|
||||
@@ -1811,6 +1831,7 @@
|
||||
"act_price": "",
|
||||
"backordered_eta": "",
|
||||
"backordered_on": "",
|
||||
"comments": "",
|
||||
"cost": "",
|
||||
"db_price": "",
|
||||
"deliver_by": "",
|
||||
@@ -1966,9 +1987,13 @@
|
||||
"guarantee": "",
|
||||
"invoice_customer_payable": "",
|
||||
"invoice_total_payable": "",
|
||||
"iou_form": "",
|
||||
"job_costing_ro": "",
|
||||
"job_notes": "",
|
||||
"key_tag": "",
|
||||
"mpi_animal_checklist": "",
|
||||
"mpi_eglass_auth": "",
|
||||
"mpi_final_acct_sheet": "",
|
||||
"paint_grid": "",
|
||||
"parts_label_single": "",
|
||||
"parts_list": "",
|
||||
@@ -2182,6 +2207,11 @@
|
||||
"work_in_progress_payables": ""
|
||||
}
|
||||
},
|
||||
"schedule": {
|
||||
"labels": {
|
||||
"manualevent": ""
|
||||
}
|
||||
},
|
||||
"scoreboard": {
|
||||
"actions": {
|
||||
"edit": ""
|
||||
|
||||
@@ -3,7 +3,11 @@ import moment from "moment";
|
||||
import React from "react";
|
||||
|
||||
export function DateFormatter(props) {
|
||||
return props.children ? moment(props.children).format("MM/DD/YYYY") : null;
|
||||
return props.children
|
||||
? moment(props.children).format(
|
||||
props.includeDay ? "ddd MM/DD/YYYY" : "MM/DD/YYYY"
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
export function DateTimeFormatter(props) {
|
||||
|
||||
@@ -2,13 +2,13 @@ import { gql } from "@apollo/client";
|
||||
import { notification } from "antd";
|
||||
import axios from "axios";
|
||||
import jsreport from "jsreport-browser-client-dist";
|
||||
import _ from "lodash";
|
||||
import moment from "moment";
|
||||
import { auth } from "../firebase/firebase.utils";
|
||||
import { setEmailOptions } from "../redux/email/email.actions";
|
||||
import { store } from "../redux/store";
|
||||
import client from "../utils/GraphQLClient";
|
||||
import { TemplateList } from "./TemplateConstants";
|
||||
import _ from "lodash";
|
||||
const server = process.env.REACT_APP_REPORTS_SERVER_URL;
|
||||
jsreport.serverUrl = server;
|
||||
|
||||
@@ -144,6 +144,7 @@ export async function RenderTemplates(
|
||||
// ...rootTemplate.templateObject.context,
|
||||
headerpath: `/${bodyshop.imexshopid}/header.html`,
|
||||
bodyshop: bodyshop,
|
||||
offset: moment().utcOffset(),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -195,35 +196,40 @@ export const GenerateDocuments = async (templates) => {
|
||||
|
||||
const fetchContextData = async (templateObject) => {
|
||||
console.log("Fetching context data", templateObject);
|
||||
const bodyshop = store.getState().user.bodyshop;
|
||||
|
||||
jsreport.headers["Authorization"] =
|
||||
"Bearer " + (await auth.currentUser.getIdToken());
|
||||
|
||||
const folders = await axios.get(`${server}/odata/folders`);
|
||||
const shopSpecificFolder = folders.data.value.find(
|
||||
(f) => f.name === bodyshop.imexshopid
|
||||
);
|
||||
|
||||
const jsReportQueries = await axios.get(
|
||||
`${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`
|
||||
);
|
||||
|
||||
let templateQueryToExecute,
|
||||
useShopSpecificTemplate = false;
|
||||
if (jsReportQueries.data.value.length === 0) {
|
||||
//We have no query to execute. Just render the template.
|
||||
} else if (jsReportQueries.data.value.length === 1) {
|
||||
//We're using the default template. Get the query and execute.
|
||||
templateQueryToExecute = atob(jsReportQueries.data.value[0].content);
|
||||
} else if (jsReportQueries.data.value.length === 2) {
|
||||
//There's a custom template. Use that query instead and execute. We find it because it has a parent folder.
|
||||
templateQueryToExecute = atob(
|
||||
jsReportQueries.data.value.filter((v) => !!v.folder)[0].content
|
||||
);
|
||||
useShopSpecificTemplate = true;
|
||||
} else {
|
||||
//We have too many queries to choose from. Throw an error.
|
||||
alert(
|
||||
"There are too many queries to choose from. Please ensure there are no conflicting keys."
|
||||
);
|
||||
throw new Error(
|
||||
"There are too many queries to choose from. Please ensure there are no conflicting keys."
|
||||
let templateQueryToExecute;
|
||||
let useShopSpecificTemplate = false;
|
||||
// let shopSpecificTemplate;
|
||||
|
||||
if (shopSpecificFolder) {
|
||||
let shopSpecificTemplate = jsReportQueries.data.value.find(
|
||||
(f) => f?.folder?.shortid === shopSpecificFolder.shortid
|
||||
);
|
||||
if (shopSpecificTemplate) {
|
||||
useShopSpecificTemplate = true;
|
||||
templateQueryToExecute = atob(shopSpecificTemplate.content);
|
||||
}
|
||||
}
|
||||
|
||||
if (!templateQueryToExecute) {
|
||||
const generalTemplate = jsReportQueries.data.value.find((f) => !f.folder);
|
||||
useShopSpecificTemplate = false;
|
||||
templateQueryToExecute = atob(generalTemplate.content);
|
||||
}
|
||||
|
||||
let contextData = {};
|
||||
if (templateQueryToExecute) {
|
||||
const { data } = await client.query({
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user