Compare commits
179 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6319fd20fa | ||
|
|
64851047bf | ||
|
|
73fac34ef4 | ||
|
|
5ca34105ef | ||
|
|
fcfa1a9be8 | ||
|
|
41849644f3 | ||
|
|
f36fb06dd6 | ||
|
|
af4c4a4fa3 | ||
|
|
d6045a9334 | ||
|
|
dcc29f23d4 | ||
|
|
638a9fc76b | ||
|
|
53e3b3fa03 | ||
|
|
56c1b6f992 | ||
|
|
22f9a7ee3d | ||
|
|
cfcad472fd | ||
|
|
1a622f1b2c | ||
|
|
87e3adf579 | ||
|
|
aa7a4ccdd0 | ||
|
|
28dc10f5a1 | ||
|
|
b2d615b9c1 | ||
|
|
1e40a22762 | ||
|
|
d1407162d9 | ||
|
|
7a1984d037 | ||
|
|
9bcc449f20 | ||
|
|
bc7d0ef171 | ||
|
|
3e9b046476 | ||
|
|
e0ccd62c82 | ||
|
|
fd0970aef2 | ||
|
|
b673bcae7a | ||
|
|
63673548a0 | ||
|
|
29b74a8c0e | ||
|
|
2658626c7e | ||
|
|
763b199646 | ||
|
|
17905fa844 | ||
|
|
74a0b78a71 | ||
|
|
797a423702 | ||
|
|
2fce8c9644 | ||
|
|
9cd39c1c3e | ||
|
|
6264a2f45c | ||
|
|
94e47d14ad | ||
|
|
9319f492dd | ||
|
|
8f04c5a12c | ||
|
|
436a41405d | ||
|
|
a2150009db | ||
|
|
e1c785322f | ||
|
|
c1d71720ab | ||
|
|
89ff7740e2 | ||
|
|
4e69fe819e | ||
|
|
a8cc3fa190 | ||
|
|
10fceb7ddf | ||
|
|
6c1a0cff8d | ||
|
|
d92d2cca9a | ||
|
|
62a800a2c0 | ||
|
|
9c408d8bf5 | ||
|
|
45ad09c100 | ||
|
|
dd5cafcd42 | ||
|
|
eb48b56f47 | ||
|
|
a879e99e77 | ||
|
|
ddd816e7ca | ||
|
|
d646e5f285 | ||
|
|
c10517a11b | ||
|
|
ba683a2e8a | ||
|
|
6b66b76f84 | ||
|
|
c3fe763261 | ||
|
|
5209c12b89 | ||
|
|
bf7aa17f65 | ||
|
|
cd6e0dcde3 | ||
|
|
a2822f5592 | ||
|
|
ca129fa4a0 | ||
|
|
cbe0c78553 | ||
|
|
2e763f1dd5 | ||
|
|
b8942c320e | ||
|
|
eee135f4ef | ||
|
|
de92b2d47e | ||
|
|
5d7384aa8b | ||
|
|
bf18e687da | ||
|
|
e69e844568 | ||
|
|
2b5268fb77 | ||
|
|
eebe7edba8 | ||
|
|
1a5c74dc79 | ||
|
|
be62ab5ff9 | ||
|
|
85497eb815 | ||
|
|
5724d0129c | ||
|
|
fd579fc509 | ||
|
|
6e21b1bdf6 | ||
|
|
a7ad18fae2 | ||
|
|
8bfa879485 | ||
|
|
ea774ff22b | ||
|
|
88101b0252 | ||
|
|
60ec76701d | ||
|
|
6b52723ba9 | ||
|
|
910c2a0f9b | ||
|
|
6c93e600c4 | ||
|
|
e70edaec7c | ||
|
|
acaba96e3b | ||
|
|
12d1613b04 | ||
|
|
df878672fc | ||
|
|
076115253f | ||
|
|
6f58528de2 | ||
|
|
3defe7201f | ||
|
|
4ce75ead52 | ||
|
|
6de7ec00fe | ||
|
|
90ea2cd699 | ||
|
|
800552210b | ||
|
|
80abea56b4 | ||
|
|
480f081c40 | ||
|
|
9529335c96 | ||
|
|
4334b3f419 | ||
|
|
94353bb342 | ||
|
|
5aad7acdd5 | ||
|
|
cd4f7ffb9c | ||
|
|
400dc79ed6 | ||
|
|
1dfb309223 | ||
|
|
29c9fb37a1 | ||
|
|
41d6f0a4bc | ||
|
|
af70c80e09 | ||
|
|
b02d4e0fdd | ||
|
|
27bf8d9ed6 | ||
|
|
582ad03e05 | ||
|
|
babdfe4cc5 | ||
|
|
8a7a94dd70 | ||
|
|
2654519277 | ||
|
|
02eddcbbf4 | ||
|
|
b967bb6d4e | ||
|
|
f60870a087 | ||
|
|
39aa21d985 | ||
|
|
512bb5e013 | ||
|
|
78f041a34f | ||
|
|
2c456cbf03 | ||
|
|
da76021802 | ||
|
|
6de06e084b | ||
|
|
cb49c91983 | ||
|
|
b0df5fa91c | ||
|
|
0652404334 | ||
|
|
bd7d8068df | ||
|
|
4dd868130c | ||
|
|
71860cf899 | ||
|
|
3512905264 | ||
|
|
2c072a9e7a | ||
|
|
fee5bee569 | ||
|
|
0a1cdbdfe3 | ||
|
|
8af79989ff | ||
|
|
5d2bdc7ee1 | ||
|
|
255d65e47d | ||
|
|
f0805e0a79 | ||
|
|
c875ade35c | ||
|
|
31b4f4e561 | ||
|
|
2c1844fb13 | ||
|
|
bd59e40761 | ||
|
|
0652114013 | ||
|
|
3150647ff6 | ||
|
|
e2258bb91f | ||
|
|
3dd4b3dd77 | ||
|
|
d2f7585ea5 | ||
|
|
1af511be2f | ||
|
|
14b38604a3 | ||
|
|
40c7b706aa | ||
|
|
88c03ce655 | ||
|
|
d5b1496898 | ||
|
|
3486e16d4e | ||
|
|
3641363d3d | ||
|
|
fde13436c9 | ||
|
|
b9a9f07d7b | ||
|
|
f4473d11a8 | ||
|
|
965af6da5f | ||
|
|
fb5c5561e9 | ||
|
|
a5e3985745 | ||
|
|
88ee4f13e1 | ||
|
|
fa05d0b401 | ||
|
|
cf017fb80b | ||
|
|
56c366e9e8 | ||
|
|
07b7394fec | ||
|
|
0617d79d19 | ||
|
|
885e9c6958 | ||
|
|
6bf5f2fe77 | ||
|
|
a3cc5c2324 | ||
|
|
a44ed3c406 | ||
|
|
aa5110ae13 | ||
|
|
c8ee9ca5a7 |
@@ -1009,27 +1009,6 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
<concept_node>
|
|
||||||
<name>smspaymentreminder</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>
|
<concept_node>
|
||||||
<name>suggesteddates</name>
|
<name>suggesteddates</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -1474,6 +1453,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>admin_jobuninvoice</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>
|
<concept_node>
|
||||||
<name>admin_jobunvoid</name>
|
<name>admin_jobunvoid</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -3571,6 +3571,27 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>validation</name>
|
<name>validation</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>closingperiod</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>
|
<concept_node>
|
||||||
<name>inventoryquantity</name>
|
<name>inventoryquantity</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -4205,6 +4226,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>closingperiod</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>
|
<concept_node>
|
||||||
<name>country</name>
|
<name>country</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -4318,6 +4360,48 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>dms</name>
|
<name>dms</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>apcontrol</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>appostingaccount</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>
|
<concept_node>
|
||||||
<name>cashierid</name>
|
<name>cashierid</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -6622,6 +6706,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>void</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>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
<folder_node>
|
<folder_node>
|
||||||
@@ -14004,6 +14109,48 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>scheduledintoday</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>scheduledouttoday</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>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
</children>
|
</children>
|
||||||
@@ -16060,6 +16207,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>copied</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>
|
<concept_node>
|
||||||
<name>copylink</name>
|
<name>copylink</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -16396,6 +16564,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>sendbysms</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>
|
<concept_node>
|
||||||
<name>senderrortosupport</name>
|
<name>senderrortosupport</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -19108,6 +19297,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>openingip</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>
|
<concept_node>
|
||||||
<name>title</name>
|
<name>title</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -23584,6 +23794,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>date_void</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>
|
<concept_node>
|
||||||
<name>ded_amt</name>
|
<name>ded_amt</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -23844,6 +24075,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>dms_unsold</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>
|
<concept_node>
|
||||||
<name>dms_wip_acctnumber</name>
|
<name>dms_wip_acctnumber</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -28343,6 +28595,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>closingperiod</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>
|
<concept_node>
|
||||||
<name>contracts</name>
|
<name>contracts</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -32753,27 +33026,6 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
<concept_node>
|
|
||||||
<name>paymentremindersms</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>
|
<concept_node>
|
||||||
<name>phonebook</name>
|
<name>phonebook</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -36978,6 +37230,32 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>payments</name>
|
<name>payments</name>
|
||||||
<children>
|
<children>
|
||||||
|
<folder_node>
|
||||||
|
<name>actions</name>
|
||||||
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>generatepaymentlink</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>
|
<folder_node>
|
||||||
<name>errors</name>
|
<name>errors</name>
|
||||||
<children>
|
<children>
|
||||||
@@ -37023,6 +37301,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<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>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
<folder_node>
|
<folder_node>
|
||||||
@@ -37411,6 +37710,48 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>markexported</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>markforreexport</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<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>
|
<concept_node>
|
||||||
<name>new</name>
|
<name>new</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -37453,6 +37794,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>smspaymentreminder</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>
|
<concept_node>
|
||||||
<name>title</name>
|
<name>title</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -37542,6 +37904,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>markreexported</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>
|
<concept_node>
|
||||||
<name>payment</name>
|
<name>payment</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -39355,6 +39738,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>mpi_final_repair_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>
|
<concept_node>
|
||||||
<name>paint_grid</name>
|
<name>paint_grid</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -40433,6 +40837,27 @@
|
|||||||
<folder_node>
|
<folder_node>
|
||||||
<name>jobs</name>
|
<name>jobs</name>
|
||||||
<children>
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>individual_job_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>
|
<concept_node>
|
||||||
<name>parts_order</name>
|
<name>parts_order</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -40454,6 +40879,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>parts_return_slip</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>
|
<concept_node>
|
||||||
<name>sublet_order</name>
|
<name>sublet_order</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -43276,6 +43722,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>jobs_scheduled_completion</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>
|
<concept_node>
|
||||||
<name>lag_time</name>
|
<name>lag_time</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -44284,6 +44751,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>work_in_progress_jobs</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>
|
<concept_node>
|
||||||
<name>work_in_progress_labour</name>
|
<name>work_in_progress_labour</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -44378,6 +44866,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</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>
|
<concept_node>
|
||||||
<name>ins_co_nm_filter</name>
|
<name>ins_co_nm_filter</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
|
|||||||
@@ -148,6 +148,10 @@
|
|||||||
background: #e7f3ff !important;
|
background: #e7f3ff !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-table-tbody > tr.ant-table-row-selected > td {
|
||||||
|
background: #e6f7ff !important;
|
||||||
|
}
|
||||||
|
|
||||||
.job-line-manual {
|
.job-line-manual {
|
||||||
color: tomato;
|
color: tomato;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|||||||
@@ -1,49 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
|
||||||
import { setEmailOptions } from "../../redux/email/email.actions";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
});
|
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
|
|
||||||
});
|
|
||||||
|
|
||||||
function Test({ bodyshop, setEmailOptions }) {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
setEmailOptions({
|
|
||||||
messageOptions: {
|
|
||||||
to: ["patrickwf@gmail.com"],
|
|
||||||
replyTo: bodyshop.email,
|
|
||||||
},
|
|
||||||
template: {
|
|
||||||
name: TemplateList().parts_order.key,
|
|
||||||
variables: {
|
|
||||||
id: "a7c2d4e1-f519-42a9-a071-c48cf0f22979",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
send email
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
logImEXEvent("IMEXEVENT", { somethignArThare: 5 });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Log an ImEX Event.
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Test);
|
|
||||||
63
client/src/components/_test/payment_response.json
Normal file
63
client/src/components/_test/payment_response.json
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
{
|
||||||
|
"status": 24201299,
|
||||||
|
"custid": 19607899,
|
||||||
|
"paymentid": 24201299,
|
||||||
|
"response": "A",
|
||||||
|
"authcode": "498680",
|
||||||
|
"declinereason": "Approved",
|
||||||
|
"fee": 0,
|
||||||
|
"invoice": "",
|
||||||
|
"account": "john",
|
||||||
|
"amount": 1000,
|
||||||
|
"amountincludesfee": false,
|
||||||
|
"total": 1000,
|
||||||
|
"paymenttype": "C",
|
||||||
|
"methodhint": "VI ***1111",
|
||||||
|
"cardbrand": "Visa",
|
||||||
|
"cardnumdisplay": "***1111",
|
||||||
|
"receiptelements": {
|
||||||
|
"authcode": "498680",
|
||||||
|
"cust_srv_ph_num": "1-555-555-5555",
|
||||||
|
"rcpt_pg_ftr_txt": "Thank You\nPlease Come Again",
|
||||||
|
"rcpt_currency": "USD",
|
||||||
|
"responsecode": "A",
|
||||||
|
"rcpt_pay_mthd": "Visa",
|
||||||
|
"transid": "C00 915799",
|
||||||
|
"merch_disp_nm": "CP Devel Test",
|
||||||
|
"rcpt_input_mthd": "Keyed",
|
||||||
|
"rcpt_pg_hdr_txt": "Welcome!",
|
||||||
|
"rcpt_tran_time": "Thursday February 23 2023, 11:25:36 pm +08",
|
||||||
|
"rcpt_trans_type": "Normal Transaction (Sale)",
|
||||||
|
"message": "Approved",
|
||||||
|
"rcpt_dba_addr": "1234 Storefront Ave\nSome City, UT 84111",
|
||||||
|
"avsdata": "N",
|
||||||
|
"receiptrequirements": "S",
|
||||||
|
"rcpt_cardnum": "************1111",
|
||||||
|
"cv2result": "M",
|
||||||
|
"rfnd_policy_txt": "<b>No Refunds</b>\nStore Credit Only",
|
||||||
|
"labels": {
|
||||||
|
"tranref": "REF#",
|
||||||
|
"tid": "TID",
|
||||||
|
"validationcode": "ValCode",
|
||||||
|
"emvapplicationid": "AID",
|
||||||
|
"emvatc": "ATC",
|
||||||
|
"rcpt_pay_mthd": "Pay Method",
|
||||||
|
"transid": "TransID",
|
||||||
|
"rcpt_input_mthd": "IMode",
|
||||||
|
"emvtsi": "TSI",
|
||||||
|
"emvac": "AC",
|
||||||
|
"rcpt_trans_type": "TranType",
|
||||||
|
"emvapplicationname": "PApp",
|
||||||
|
"visarewards": "RewardsProg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"receipttoken": "H4sIAAAAAAAAACXMTQuCMBgA4P/ynh3tw_3dBI/ipQ8NOtRN53QiblpBRfTfCzo/8LwhxGAdZCCwFYoJJFQjI2kvHdGu74lVkgmrWyWNhASW5jW7cB87yHjKKePGJODnxrrnMl7dDTKmEJlSOqV/_N30XPpyj2Eddq57_KKZ8FLzmh_G1VQnVfhjiXGK1XYTc/h8AVOkf4qUAAAA",
|
||||||
|
"call": "card_payment",
|
||||||
|
"nonce": "488b5568-b5c1-4f38-8b2f-3b050f3abb11P",
|
||||||
|
"hmac": "JyPAJ9Yx0SlYBTtqns1OxAFRt+xF3l2UiLPO5zTDRBE=",
|
||||||
|
"paymentreferenceid": "C19607899P24201299",
|
||||||
|
"cardnum": "...1111",
|
||||||
|
"email": "",
|
||||||
|
"nameOnCard": "John Allen",
|
||||||
|
"cardType": "visa"
|
||||||
|
}
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
|
||||||
export default function Test() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<QboAuthorizeComponent />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
31
client/src/components/_test/test.page.jsx
Normal file
31
client/src/components/_test/test.page.jsx
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Button } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
setRefundPaymentContext: (context) =>
|
||||||
|
dispatch(setModalContext({ context: context, modal: "refund_payment" })),
|
||||||
|
});
|
||||||
|
|
||||||
|
function Test({ setRefundPaymentContext, refundPaymentModal }) {
|
||||||
|
console.log("refundPaymentModal", refundPaymentModal);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
setRefundPaymentContext({
|
||||||
|
context: {},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Open Modal
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(Test);
|
||||||
@@ -1,18 +1,18 @@
|
|||||||
import { useApolloClient, useMutation } from "@apollo/client";
|
import { useApolloClient, useMutation } from "@apollo/client";
|
||||||
import { Button, Checkbox, Form, Modal, notification, Space } from "antd";
|
import { Button, Checkbox, Form, Modal, Space, notification } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, { useEffect, useState, useMemo } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { INSERT_NEW_BILL } from "../../graphql/bills.queries";
|
import { INSERT_NEW_BILL } from "../../graphql/bills.queries";
|
||||||
|
import { UPDATE_INVENTORY_LINES } from "../../graphql/inventory.queries";
|
||||||
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
||||||
import {
|
import {
|
||||||
QUERY_JOB_LBR_ADJUSTMENTS,
|
QUERY_JOB_LBR_ADJUSTMENTS,
|
||||||
UPDATE_JOB,
|
UPDATE_JOB,
|
||||||
} from "../../graphql/jobs.queries";
|
} from "../../graphql/jobs.queries";
|
||||||
import { MUTATION_MARK_RETURN_RECEIVED } from "../../graphql/parts-orders.queries";
|
import { MUTATION_MARK_RETURN_RECEIVED } from "../../graphql/parts-orders.queries";
|
||||||
import { UPDATE_INVENTORY_LINES } from "../../graphql/inventory.queries";
|
|
||||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
|
import { selectBillEnterModal } from "../../redux/modals/modals.selectors";
|
||||||
@@ -20,15 +20,15 @@ import {
|
|||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import confirmDialog from "../../utils/asyncConfirm";
|
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import BillFormContainer from "../bill-form/bill-form.container";
|
|
||||||
import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility";
|
|
||||||
import { handleUpload } from "../documents-upload/documents-upload.utility";
|
|
||||||
import { handleUpload as handleLocalUpload } from "../documents-local-upload/documents-local-upload.utility";
|
|
||||||
import useLocalStorage from "../../utils/useLocalStorage";
|
|
||||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
|
import confirmDialog from "../../utils/asyncConfirm";
|
||||||
|
import useLocalStorage from "../../utils/useLocalStorage";
|
||||||
|
import BillFormContainer from "../bill-form/bill-form.container";
|
||||||
|
import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility";
|
||||||
|
import { handleUpload as handleLocalUpload } from "../documents-local-upload/documents-local-upload.utility";
|
||||||
|
import { handleUpload } from "../documents-upload/documents-upload.utility";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
billEnterModal: selectBillEnterModal,
|
billEnterModal: selectBillEnterModal,
|
||||||
@@ -37,8 +37,8 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
toggleModalVisible: () => dispatch(toggleModalVisible("billEnter")),
|
toggleModalVisible: () => dispatch(toggleModalVisible("billEnter")),
|
||||||
insertAuditTrail: ({ jobid, operation }) =>
|
insertAuditTrail: ({ jobid, billid, operation }) =>
|
||||||
dispatch(insertAuditTrail({ jobid, operation })),
|
dispatch(insertAuditTrail({ jobid, billid, operation })),
|
||||||
});
|
});
|
||||||
|
|
||||||
const Templates = TemplateList("job_special");
|
const Templates = TemplateList("job_special");
|
||||||
@@ -126,6 +126,17 @@ function BillEnterModalContainer({
|
|||||||
deductedfromlbr: deductedfromlbr,
|
deductedfromlbr: deductedfromlbr,
|
||||||
lbr_adjustment,
|
lbr_adjustment,
|
||||||
joblineid: i.joblineid === "noline" ? null : i.joblineid,
|
joblineid: i.joblineid === "noline" ? null : i.joblineid,
|
||||||
|
applicable_taxes: {
|
||||||
|
federal:
|
||||||
|
(i.applicable_taxes && i.applicable_taxes.federal) ||
|
||||||
|
false,
|
||||||
|
state:
|
||||||
|
(i.applicable_taxes && i.applicable_taxes.state) ||
|
||||||
|
false,
|
||||||
|
local:
|
||||||
|
(i.applicable_taxes && i.applicable_taxes.local) ||
|
||||||
|
false,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@@ -305,7 +316,7 @@ function BillEnterModalContainer({
|
|||||||
insertAuditTrail({
|
insertAuditTrail({
|
||||||
jobid: values.jobid,
|
jobid: values.jobid,
|
||||||
billid: billId,
|
billid: billId,
|
||||||
operation: AuditTrailMapping.billposted(remainingValues.invoice_number),
|
operation: AuditTrailMapping.billposted(r1.data.insert_bills.returning[0].invoice_number),
|
||||||
});
|
});
|
||||||
|
|
||||||
if (enterAgain) {
|
if (enterAgain) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import Icon, { UploadOutlined } from "@ant-design/icons";
|
import Icon, { UploadOutlined } from "@ant-design/icons";
|
||||||
import { useApolloClient } from "@apollo/client";
|
import { useApolloClient } from "@apollo/client";
|
||||||
import { MdOpenInNew } from "react-icons/md";
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import {
|
import {
|
||||||
Alert,
|
Alert,
|
||||||
Divider,
|
Divider,
|
||||||
@@ -12,14 +12,17 @@ import {
|
|||||||
Switch,
|
Switch,
|
||||||
Upload,
|
Upload,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
|
import moment from "moment";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { MdOpenInNew } from "react-icons/md";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { CHECK_BILL_INVOICE_NUMBER } from "../../graphql/bills.queries";
|
import { CHECK_BILL_INVOICE_NUMBER } from "../../graphql/bills.queries";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||||
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
@@ -28,8 +31,6 @@ import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|||||||
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
||||||
import BillFormLines from "./bill-form.lines.component";
|
import BillFormLines from "./bill-form.lines.component";
|
||||||
import { CalculateBillTotal } from "./bill-form.totals.utility";
|
import { CalculateBillTotal } from "./bill-form.totals.utility";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -58,6 +59,11 @@ export function BillFormComponent({
|
|||||||
{},
|
{},
|
||||||
bodyshop.imexshopid
|
bodyshop.imexshopid
|
||||||
);
|
);
|
||||||
|
const { ClosingPeriod } = useTreatments(
|
||||||
|
["ClosingPeriod"],
|
||||||
|
{},
|
||||||
|
bodyshop.imexshopid
|
||||||
|
);
|
||||||
|
|
||||||
const handleVendorSelect = (props, opt) => {
|
const handleVendorSelect = (props, opt) => {
|
||||||
setDiscount(opt.discount);
|
setDiscount(opt.discount);
|
||||||
@@ -259,6 +265,37 @@ export function BillFormComponent({
|
|||||||
required: true,
|
required: true,
|
||||||
//message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
},
|
},
|
||||||
|
({ getFieldValue }) => ({
|
||||||
|
validator(rule, value) {
|
||||||
|
if (
|
||||||
|
ClosingPeriod.treatment === "on" &&
|
||||||
|
bodyshop.accountingconfig.ClosingPeriod
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
moment(value)
|
||||||
|
.startOf("day")
|
||||||
|
.isSameOrAfter(
|
||||||
|
moment(
|
||||||
|
bodyshop.accountingconfig.ClosingPeriod[0]
|
||||||
|
).startOf("day")
|
||||||
|
) &&
|
||||||
|
moment(value)
|
||||||
|
.startOf("day")
|
||||||
|
.isSameOrBefore(
|
||||||
|
moment(
|
||||||
|
bodyshop.accountingconfig.ClosingPeriod[1]
|
||||||
|
).endOf("day")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
return Promise.reject(t("bills.validation.closingperiod"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<FormDatePicker disabled={disabled} />
|
<FormDatePicker disabled={disabled} />
|
||||||
|
|||||||
@@ -0,0 +1,374 @@
|
|||||||
|
import { DeleteFilled } from "@ant-design/icons";
|
||||||
|
import { useLazyQuery, useMutation } from "@apollo/client";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Card,
|
||||||
|
Col,
|
||||||
|
Form,
|
||||||
|
Input,
|
||||||
|
Row,
|
||||||
|
Space,
|
||||||
|
Spin,
|
||||||
|
Statistic,
|
||||||
|
notification,
|
||||||
|
} from "antd";
|
||||||
|
import axios from "axios";
|
||||||
|
import moment from "moment";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import {
|
||||||
|
INSERT_PAYMENT_RESPONSE,
|
||||||
|
QUERY_RO_AND_OWNER_BY_JOB_PKS,
|
||||||
|
} from "../../graphql/payment_response.queries";
|
||||||
|
import { INSERT_NEW_PAYMENT } from "../../graphql/payments.queries";
|
||||||
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
|
import { selectCardPayment } from "../../redux/modals/modals.selectors";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
||||||
|
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
cardPaymentModal: selectCardPayment,
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
insertAuditTrail: ({ jobid, operation }) =>
|
||||||
|
dispatch(insertAuditTrail({ jobid, operation })),
|
||||||
|
toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment")),
|
||||||
|
});
|
||||||
|
|
||||||
|
const CardPaymentModalComponent = ({
|
||||||
|
bodyshop,
|
||||||
|
cardPaymentModal,
|
||||||
|
toggleModalVisible,
|
||||||
|
insertAuditTrail,
|
||||||
|
}) => {
|
||||||
|
const { context } = cardPaymentModal;
|
||||||
|
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
|
||||||
|
const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const [, { data, refetch, queryLoading }] = useLazyQuery(
|
||||||
|
QUERY_RO_AND_OWNER_BY_JOB_PKS,
|
||||||
|
{
|
||||||
|
variables: { jobids: [context.jobid] },
|
||||||
|
skip: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log("🚀 ~ file: card-payment-modal.component..jsx:61 ~ data:", data);
|
||||||
|
//Initialize the intellipay window.
|
||||||
|
const SetIntellipayCallbackFunctions = () => {
|
||||||
|
console.log("*** Set IntelliPay callback functions.");
|
||||||
|
window.intellipay.runOnClose(() => {
|
||||||
|
//window.intellipay.initialize();
|
||||||
|
});
|
||||||
|
|
||||||
|
window.intellipay.runOnApproval(async function (response) {
|
||||||
|
console.warn("*** Running On Approval Script ***");
|
||||||
|
form.setFieldValue("paymentResponse", response);
|
||||||
|
form.submit();
|
||||||
|
});
|
||||||
|
|
||||||
|
window.intellipay.runOnNonApproval(async function (response) {
|
||||||
|
// Mutate unsuccessful payment
|
||||||
|
|
||||||
|
const { payments } = form.getFieldsValue();
|
||||||
|
|
||||||
|
await insertPaymentResponse({
|
||||||
|
variables: {
|
||||||
|
paymentResponse: payments.map((payment) => ({
|
||||||
|
amount: payment.amount,
|
||||||
|
bodyshopid: bodyshop.id,
|
||||||
|
jobid: payment.jobid,
|
||||||
|
declinereason: response.declinereason,
|
||||||
|
ext_paymentid: response.paymentid.toString(),
|
||||||
|
successful: false,
|
||||||
|
response,
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
payments.forEach((payment) =>
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: payment.jobid,
|
||||||
|
operation: AuditTrailMapping.failedpayment(),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleFinish = async (values) => {
|
||||||
|
try {
|
||||||
|
await insertPayment({
|
||||||
|
variables: {
|
||||||
|
paymentInput: values.payments.map((payment) => ({
|
||||||
|
amount: payment.amount,
|
||||||
|
transactionid: (values.paymentResponse.paymentid || "").toString(),
|
||||||
|
payer: t("payments.labels.customer"),
|
||||||
|
type: values.paymentResponse.cardbrand,
|
||||||
|
jobid: payment.jobid,
|
||||||
|
date: moment(Date.now()),
|
||||||
|
payment_responses: {
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
amount: payment.amount,
|
||||||
|
bodyshopid: bodyshop.id,
|
||||||
|
|
||||||
|
jobid: payment.jobid,
|
||||||
|
declinereason: values.paymentResponse.declinereason,
|
||||||
|
ext_paymentid: values.paymentResponse.paymentid.toString(),
|
||||||
|
successful: true,
|
||||||
|
response: values.paymentResponse,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
refetchQueries: ["GET_JOB_BY_PK"],
|
||||||
|
});
|
||||||
|
toggleModalVisible();
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
notification.open({
|
||||||
|
type: "error",
|
||||||
|
message: t("payments.errors.inserting", { error: error.message }),
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleIntelliPayCharge = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
//Validate
|
||||||
|
try {
|
||||||
|
await form.validateFields();
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post("/intellipay/lightbox_credentials", {
|
||||||
|
bodyshop,
|
||||||
|
refresh: !!window.intellipay,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window.intellipay) {
|
||||||
|
// eslint-disable-next-line no-eval
|
||||||
|
eval(response.data);
|
||||||
|
SetIntellipayCallbackFunctions();
|
||||||
|
window.intellipay.autoOpen();
|
||||||
|
} else {
|
||||||
|
var rg = document.createRange();
|
||||||
|
let node = rg.createContextualFragment(response.data);
|
||||||
|
document.documentElement.appendChild(node);
|
||||||
|
SetIntellipayCallbackFunctions();
|
||||||
|
window.intellipay.isAutoOpen = true;
|
||||||
|
window.intellipay.initialize();
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
notification.open({
|
||||||
|
type: "error",
|
||||||
|
message: t("job_payments.notifications.error.openingip"),
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card title="Card Payment">
|
||||||
|
<Spin spinning={loading}>
|
||||||
|
<Form
|
||||||
|
onFinish={handleFinish}
|
||||||
|
form={form}
|
||||||
|
layout="vertical"
|
||||||
|
initialValues={{
|
||||||
|
payments: context.jobid ? [{ jobid: context.jobid }] : [],
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Form.List name={["payments"]}>
|
||||||
|
{(fields, { add, remove, move }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<Form.Item key={field.key}>
|
||||||
|
<Row gutter={[16, 16]}>
|
||||||
|
<Col span={16}>
|
||||||
|
<Form.Item
|
||||||
|
key={`${index}jobid`}
|
||||||
|
label={t("jobs.fields.ro_number")}
|
||||||
|
name={[field.name, "jobid"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<JobSearchSelectComponent
|
||||||
|
notExported={false}
|
||||||
|
clm_no
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={6}>
|
||||||
|
<Form.Item
|
||||||
|
key={`${index}amount`}
|
||||||
|
label={t("payments.fields.amount")}
|
||||||
|
name={[field.name, "amount"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<CurrencyFormItemComponent />
|
||||||
|
</Form.Item>
|
||||||
|
</Col>
|
||||||
|
<Col span={2}>
|
||||||
|
<DeleteFilled
|
||||||
|
style={{ margin: "1rem" }}
|
||||||
|
onClick={() => {
|
||||||
|
remove(field.name);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Form.Item>
|
||||||
|
))}
|
||||||
|
<Form.Item>
|
||||||
|
<Button
|
||||||
|
type="dashed"
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
>
|
||||||
|
{t("general.actions.add")}
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.List>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
shouldUpdate={(prevValues, curValues) =>
|
||||||
|
prevValues.payments?.map((p) => p?.jobid).join() !==
|
||||||
|
curValues.payments?.map((p) => p?.jobid).join()
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{() => {
|
||||||
|
console.log("Updating the owner info section.");
|
||||||
|
//If all of the job ids have been fileld in, then query and update the IP field.
|
||||||
|
const { payments } = form.getFieldsValue();
|
||||||
|
if (
|
||||||
|
payments?.length > 0 &&
|
||||||
|
payments?.filter((p) => p?.jobid).length === payments?.length
|
||||||
|
) {
|
||||||
|
console.log("**Calling refetch.");
|
||||||
|
refetch({ jobids: payments.map((p) => p.jobid) });
|
||||||
|
}
|
||||||
|
console.log(
|
||||||
|
"Acc info",
|
||||||
|
data,
|
||||||
|
payments && data && data.jobs.length > 0
|
||||||
|
? data.jobs.map((j) => j.ro_number).join(", ")
|
||||||
|
: null
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Input
|
||||||
|
className="ipayfield"
|
||||||
|
data-ipayname="account"
|
||||||
|
//type="hidden"
|
||||||
|
value={
|
||||||
|
payments && data && data.jobs.length > 0
|
||||||
|
? data.jobs.map((j) => j.ro_number).join(", ")
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
hidden
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
className="ipayfield"
|
||||||
|
data-ipayname="email"
|
||||||
|
// type="hidden"
|
||||||
|
value={
|
||||||
|
payments && data && data.jobs.length > 0
|
||||||
|
? data.jobs.filter((j) => j.ownr_ea)[0]?.ownr_ea
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
hidden
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
shouldUpdate={(prevValues, curValues) =>
|
||||||
|
prevValues.payments?.map((p) => p?.amount).join() !==
|
||||||
|
curValues.payments?.map((p) => p?.amount).join()
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{() => {
|
||||||
|
const { payments } = form.getFieldsValue();
|
||||||
|
const totalAmountToCharge = payments?.reduce((acc, val) => {
|
||||||
|
return acc + (val?.amount || 0);
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Space style={{ float: "right" }}>
|
||||||
|
<Statistic
|
||||||
|
title="Amount To Charge"
|
||||||
|
value={totalAmountToCharge}
|
||||||
|
precision={2}
|
||||||
|
/>
|
||||||
|
<Input
|
||||||
|
className="ipayfield"
|
||||||
|
data-ipayname="amount"
|
||||||
|
//type="hidden"
|
||||||
|
value={totalAmountToCharge?.toFixed(2)}
|
||||||
|
hidden
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
// data-ipayname="submit"
|
||||||
|
className="ipayfield"
|
||||||
|
loading={queryLoading || loading}
|
||||||
|
disabled={!(totalAmountToCharge > 0)}
|
||||||
|
onClick={handleIntelliPayCharge}
|
||||||
|
>
|
||||||
|
{t("job_payments.buttons.proceedtopayment")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
{/* Lightbox payment response when it is completed */}
|
||||||
|
<Form.Item name="paymentResponse" hidden>
|
||||||
|
<Input type="hidden" />
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</Spin>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(CardPaymentModalComponent);
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import { Button, Modal } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
|
import { selectCardPayment } from "../../redux/modals/modals.selectors";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import CardPaymentModalComponent from "./card-payment-modal.component.";
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
cardPaymentModal: selectCardPayment,
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment")),
|
||||||
|
});
|
||||||
|
|
||||||
|
function CardPaymentModalContainer({
|
||||||
|
cardPaymentModal,
|
||||||
|
toggleModalVisible,
|
||||||
|
bodyshop,
|
||||||
|
}) {
|
||||||
|
const { visible } = cardPaymentModal;
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleCancel = () => {
|
||||||
|
toggleModalVisible();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOK = () => {
|
||||||
|
toggleModalVisible();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
open={visible}
|
||||||
|
onOk={handleOK}
|
||||||
|
onCancel={handleCancel}
|
||||||
|
footer={[
|
||||||
|
<Button key="back" onClick={handleCancel}>
|
||||||
|
{t("job_payments.buttons.goback")}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
width="80%"
|
||||||
|
destroyOnClose
|
||||||
|
>
|
||||||
|
<CardPaymentModalComponent />
|
||||||
|
</Modal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(CardPaymentModalContainer);
|
||||||
@@ -59,6 +59,14 @@ export default function ContractsCarsComponent({
|
|||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "model" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "model" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t("courtesycars.fields.color"),
|
||||||
|
dataIndex: "color",
|
||||||
|
key: "color",
|
||||||
|
sorter: (a, b) => alphaSort(a.color, b.color),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "color" && state.sortedInfo.order,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t("courtesycars.fields.plate"),
|
title: t("courtesycars.fields.plate"),
|
||||||
dataIndex: "plate",
|
dataIndex: "plate",
|
||||||
@@ -93,6 +101,9 @@ export default function ContractsCarsComponent({
|
|||||||
(cc.model || "")
|
(cc.model || "")
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(state.search.toLowerCase()) ||
|
.includes(state.search.toLowerCase()) ||
|
||||||
|
(cc.color || "")
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(state.search.toLowerCase()) ||
|
||||||
(cc.plate || "").toLowerCase().includes(state.search.toLowerCase())
|
(cc.plate || "").toLowerCase().includes(state.search.toLowerCase())
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export default function DataLabel({
|
|||||||
<div {...props} style={{ display: "flex" }}>
|
<div {...props} style={{ display: "flex" }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
flex: 2,
|
// flex: 2,
|
||||||
marginRight: ".2rem",
|
marginRight: ".2rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
Select,
|
Select,
|
||||||
Space,
|
Space,
|
||||||
Statistic,
|
Statistic,
|
||||||
|
Switch,
|
||||||
Typography,
|
Typography,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import Dinero from "dinero.js";
|
import Dinero from "dinero.js";
|
||||||
@@ -183,6 +184,13 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
|
|||||||
<Space>
|
<Space>
|
||||||
<DmsCdkMakes form={form} socket={socket} job={job} />
|
<DmsCdkMakes form={form} socket={socket} job={job} />
|
||||||
<DmsCdkMakesRefetch />
|
<DmsCdkMakesRefetch />
|
||||||
|
<Form.Item
|
||||||
|
name="dms_unsold"
|
||||||
|
label={t("jobs.fields.dms.dms_unsold")}
|
||||||
|
initialValue={false}
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
import Icon, {
|
import Icon, {
|
||||||
BankFilled,
|
BankFilled,
|
||||||
BarChartOutlined,
|
BarChartOutlined,
|
||||||
CarFilled,
|
CarFilled,
|
||||||
ClockCircleFilled,
|
|
||||||
CheckCircleOutlined,
|
CheckCircleOutlined,
|
||||||
|
ClockCircleFilled,
|
||||||
DashboardFilled,
|
DashboardFilled,
|
||||||
DollarCircleFilled,
|
DollarCircleFilled,
|
||||||
ExportOutlined,
|
ExportOutlined,
|
||||||
@@ -26,6 +25,7 @@ import Icon, {
|
|||||||
UnorderedListOutlined,
|
UnorderedListOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { Layout, Menu } from "antd";
|
import { Layout, Menu } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -70,6 +70,8 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
setReportCenterContext: (context) =>
|
setReportCenterContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "reportCenter" })),
|
dispatch(setModalContext({ context: context, modal: "reportCenter" })),
|
||||||
signOutStart: () => dispatch(signOutStart()),
|
signOutStart: () => dispatch(signOutStart()),
|
||||||
|
setCardPaymentContext: (context) =>
|
||||||
|
dispatch(setModalContext({ context: context, modal: "cardPayment" })),
|
||||||
});
|
});
|
||||||
|
|
||||||
function Header({
|
function Header({
|
||||||
@@ -83,6 +85,7 @@ function Header({
|
|||||||
setPaymentContext,
|
setPaymentContext,
|
||||||
setReportCenterContext,
|
setReportCenterContext,
|
||||||
recentItems,
|
recentItems,
|
||||||
|
setCardPaymentContext,
|
||||||
}) {
|
}) {
|
||||||
const { Simple_Inventory } = useTreatments(
|
const { Simple_Inventory } = useTreatments(
|
||||||
["Simple_Inventory"],
|
["Simple_Inventory"],
|
||||||
@@ -94,6 +97,11 @@ function Header({
|
|||||||
{},
|
{},
|
||||||
bodyshop && bodyshop.imexshopid
|
bodyshop && bodyshop.imexshopid
|
||||||
);
|
);
|
||||||
|
const { ImEXPay } = useTreatments(
|
||||||
|
["ImEXPay"],
|
||||||
|
{},
|
||||||
|
bodyshop && bodyshop.imexshopid
|
||||||
|
);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -240,6 +248,20 @@ function Header({
|
|||||||
>
|
>
|
||||||
{t("menus.header.enterpayment")}
|
{t("menus.header.enterpayment")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
{ImEXPay.treatment === "on" && (
|
||||||
|
<Menu.Item
|
||||||
|
key="entercardpayments"
|
||||||
|
onClick={() => {
|
||||||
|
setCardPaymentContext({
|
||||||
|
actions: {},
|
||||||
|
context: {},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
icon={<Icon component={FaCreditCard} />}
|
||||||
|
>
|
||||||
|
{t("menus.header.entercardpayment")}
|
||||||
|
</Menu.Item>
|
||||||
|
)}
|
||||||
<Menu.Divider key="div5" />
|
<Menu.Divider key="div5" />
|
||||||
<Menu.Item key="timetickets" icon={<FieldTimeOutlined />}>
|
<Menu.Item key="timetickets" icon={<FieldTimeOutlined />}>
|
||||||
<Link to="/manage/timetickets">
|
<Link to="/manage/timetickets">
|
||||||
@@ -252,7 +274,11 @@ function Header({
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
setTimeTicketContext({
|
setTimeTicketContext({
|
||||||
actions: {},
|
actions: {},
|
||||||
context: {},
|
context: {
|
||||||
|
created_by: currentUser.displayName
|
||||||
|
? currentUser.email.concat(" | ", currentUser.displayName)
|
||||||
|
: currentUser.email,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { SEARCH_VENDOR_AUTOCOMPLETE_WITH_ADDR } from "../../graphql/vendors.queries";
|
import { SEARCH_VENDOR_AUTOCOMPLETE_WITH_ADDR } from "../../graphql/vendors.queries";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
@@ -13,13 +14,14 @@ import VendorSearchSelect from "../vendor-search-select/vendor-search-select.com
|
|||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
technician: selectTechnician,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
});
|
});
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(Jobd3RdPartyModal);
|
export default connect(mapStateToProps, mapDispatchToProps)(Jobd3RdPartyModal);
|
||||||
|
|
||||||
export function Jobd3RdPartyModal({ bodyshop, jobId, job }) {
|
export function Jobd3RdPartyModal({ bodyshop, jobId, job, technician }) {
|
||||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
@@ -212,7 +214,9 @@ export function Jobd3RdPartyModal({ bodyshop, jobId, job }) {
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Radio.Group>
|
<Radio.Group>
|
||||||
<Radio value={"e"}>{t("parts_orders.labels.email")}</Radio>
|
{!technician ? (
|
||||||
|
<Radio value={"e"}>{t("parts_orders.labels.email")}</Radio>
|
||||||
|
) : null}
|
||||||
<Radio value={"p"}>{t("parts_orders.labels.print")}</Radio>
|
<Radio value={"p"}>{t("parts_orders.labels.print")}</Radio>
|
||||||
</Radio.Group>
|
</Radio.Group>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -29,11 +29,11 @@ import { GenerateDocument } from "../../utils/RenderTemplate";
|
|||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
||||||
import DataLabel from "../data-label/data-label.component";
|
import DataLabel from "../data-label/data-label.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component";
|
import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.component";
|
||||||
import ScheduleAtChange from "./job-at-change.component";
|
import ScheduleAtChange from "./job-at-change.component";
|
||||||
import ScheduleEventColor from "./schedule-event.color.component";
|
import ScheduleEventColor from "./schedule-event.color.component";
|
||||||
import ScheduleEventNote from "./schedule-event.note.component";
|
import ScheduleEventNote from "./schedule-event.note.component";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -208,46 +208,56 @@ export function ScheduleEventComponent({
|
|||||||
<Button>{t("appointments.actions.sendreminder")}</Button>
|
<Button>{t("appointments.actions.sendreminder")}</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
) : null}
|
) : null}
|
||||||
<Popover
|
{event.arrived ? (
|
||||||
trigger="click"
|
|
||||||
disabled={event.arrived}
|
|
||||||
content={
|
|
||||||
<Form
|
|
||||||
layout="vertical"
|
|
||||||
onFinish={({ lost_sale_reason }) => {
|
|
||||||
handleCancel({ id: event.id, lost_sale_reason });
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
name="lost_sale_reason"
|
|
||||||
label={t("jobs.fields.lost_sale_reason")}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
options={bodyshop.md_lost_sale_reasons.map((lsr) => ({
|
|
||||||
label: lsr,
|
|
||||||
value: lsr,
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
<Button htmlType="submit">
|
|
||||||
{t("appointments.actions.cancel")}
|
|
||||||
</Button>
|
|
||||||
</Form>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button
|
<Button
|
||||||
// onClick={() => handleCancel(event.id)}
|
// onClick={() => handleCancel(event.id)}
|
||||||
disabled={event.arrived}
|
disabled={event.arrived}
|
||||||
>
|
>
|
||||||
{t("appointments.actions.cancel")}
|
{t("appointments.actions.cancel")}
|
||||||
</Button>
|
</Button>
|
||||||
</Popover>
|
) : (
|
||||||
|
<Popover
|
||||||
|
trigger="click"
|
||||||
|
disabled={event.arrived}
|
||||||
|
content={
|
||||||
|
<Form
|
||||||
|
layout="vertical"
|
||||||
|
onFinish={({ lost_sale_reason }) => {
|
||||||
|
handleCancel({ id: event.id, lost_sale_reason });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
name="lost_sale_reason"
|
||||||
|
label={t("jobs.fields.lost_sale_reason")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={bodyshop.md_lost_sale_reasons.map((lsr) => ({
|
||||||
|
label: lsr,
|
||||||
|
value: lsr,
|
||||||
|
}))}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Button htmlType="submit">
|
||||||
|
{t("appointments.actions.cancel")}
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
// onClick={() => handleCancel(event.id)}
|
||||||
|
disabled={event.arrived}
|
||||||
|
>
|
||||||
|
{t("appointments.actions.cancel")}
|
||||||
|
</Button>
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
|
|
||||||
{event.isintake ? (
|
{event.isintake ? (
|
||||||
<Button
|
<Button
|
||||||
disabled={event.arrived}
|
disabled={event.arrived}
|
||||||
|
|||||||
@@ -401,7 +401,7 @@ export function JobLinesComponent({
|
|||||||
const markedTypes = [e.key];
|
const markedTypes = [e.key];
|
||||||
if (e.key === "PAN") markedTypes.push("PAP");
|
if (e.key === "PAN") markedTypes.push("PAP");
|
||||||
if (e.key === "PAS") markedTypes.push("PASL");
|
if (e.key === "PAS") markedTypes.push("PASL");
|
||||||
setSelectedLines(
|
setSelectedLines((selectedLines) =>
|
||||||
_.uniq([
|
_.uniq([
|
||||||
...selectedLines,
|
...selectedLines,
|
||||||
...jobLines.filter((item) => markedTypes.includes(item.part_type)),
|
...jobLines.filter((item) => markedTypes.includes(item.part_type)),
|
||||||
@@ -614,8 +614,17 @@ export function JobLinesComponent({
|
|||||||
onSelectAll: (selected, selectedRows, changeRows) => {
|
onSelectAll: (selected, selectedRows, changeRows) => {
|
||||||
setSelectedLines(selectedRows);
|
setSelectedLines(selectedRows);
|
||||||
},
|
},
|
||||||
onSelect: (record, selected, selectedRows, nativeEvent) =>
|
onSelect: (record, selected, selectedRows, nativeEvent) => {
|
||||||
setSelectedLines(selectedRows),
|
if (selected) {
|
||||||
|
setSelectedLines((selectedLines) =>
|
||||||
|
_.uniqBy([...selectedLines, record], "id")
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setSelectedLines((selectedLines) =>
|
||||||
|
selectedLines.filter((l) => l.id !== record.id)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,19 +1,26 @@
|
|||||||
import { Button, Card, Space, Table } from "antd";
|
|
||||||
import { EditFilled } from "@ant-design/icons";
|
import { EditFilled } from "@ant-design/icons";
|
||||||
|
import { Button, Card, Space, Table } from "antd";
|
||||||
import Dinero from "dinero.js";
|
import Dinero from "dinero.js";
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
|
import {
|
||||||
|
openChatByPhone,
|
||||||
|
setMessage,
|
||||||
|
} from "../../redux/messaging/messaging.actions";
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
|
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||||
import DataLabel from "../data-label/data-label.component";
|
import DataLabel from "../data-label/data-label.component";
|
||||||
|
import PaymentExpandedRowComponent from "../payment-expanded-row/payment-expanded-row.component";
|
||||||
|
import PaymentsGenerateLink from "../payments-generate-link/payments-generate-link.component";
|
||||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||||
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -23,20 +30,34 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setPaymentContext: (context) =>
|
setPaymentContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "payment" })),
|
dispatch(setModalContext({ context: context, modal: "payment" })),
|
||||||
|
setCardPaymentContext: (context) =>
|
||||||
|
dispatch(setModalContext({ context: context, modal: "cardPayment" })),
|
||||||
|
openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
|
||||||
|
setMessage: (text) => dispatch(setMessage(text)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function JobPayments({
|
export function JobPayments({
|
||||||
job,
|
job,
|
||||||
jobRO,
|
jobRO,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
|
setMessage,
|
||||||
|
openChatByPhone,
|
||||||
setPaymentContext,
|
setPaymentContext,
|
||||||
|
setCardPaymentContext,
|
||||||
refetch,
|
refetch,
|
||||||
}) {
|
}) {
|
||||||
|
const { ImEXPay } = useTreatments(
|
||||||
|
["ImEXPay"],
|
||||||
|
{},
|
||||||
|
bodyshop && bodyshop.imexshopid
|
||||||
|
);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
filteredInfo: {},
|
filteredInfo: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("payments.fields.date"),
|
title: t("payments.fields.date"),
|
||||||
@@ -149,6 +170,21 @@ export function JobPayments({
|
|||||||
title={t("payments.labels.title")}
|
title={t("payments.labels.title")}
|
||||||
extra={
|
extra={
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
|
{ImEXPay.treatment === "on" && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
onClick={() =>
|
||||||
|
setCardPaymentContext({
|
||||||
|
actions: { refetch },
|
||||||
|
context: { jobid: job.id, balance },
|
||||||
|
})
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t("menus.header.entercardpayment")}
|
||||||
|
</Button>
|
||||||
|
<PaymentsGenerateLink job={job} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
disabled={!job.converted}
|
disabled={!job.converted}
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
@@ -160,6 +196,7 @@ export function JobPayments({
|
|||||||
>
|
>
|
||||||
{t("menus.header.enterpayment")}
|
{t("menus.header.enterpayment")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<DataLabel
|
<DataLabel
|
||||||
valueStyle={{ color: balance.getAmount() !== 0 ? "red" : "green" }}
|
valueStyle={{ color: balance.getAmount() !== 0 ? "red" : "green" }}
|
||||||
label={t("payments.labels.balance")}
|
label={t("payments.labels.balance")}
|
||||||
@@ -178,6 +215,11 @@ export function JobPayments({
|
|||||||
scroll={{
|
scroll={{
|
||||||
x: true,
|
x: true,
|
||||||
}}
|
}}
|
||||||
|
expandable={{
|
||||||
|
expandedRowRender: (record) => (
|
||||||
|
<PaymentExpandedRowComponent record={record} bodyshop={bodyshop} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
summary={() => (
|
summary={() => (
|
||||||
<>
|
<>
|
||||||
<Table.Summary.Row>
|
<Table.Summary.Row>
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Form, notification } from "antd";
|
import { Button, Form, notification } from "antd";
|
||||||
|
import moment from "moment";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|
||||||
import moment from "moment";
|
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
||||||
|
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
@@ -38,8 +38,8 @@ export function JobsAdminDatesChange({ insertAuditTrail, job }) {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const result = await updateJob({
|
const result = await updateJob({
|
||||||
variables: { jobId: job.id, job: values },
|
variables: { jobId: job.id, job: values },
|
||||||
refetchQueries: ['GET_JOB_BY_PK'],
|
refetchQueries: ["GET_JOB_BY_PK"],
|
||||||
awaitRefetchQueries:true
|
awaitRefetchQueries: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
const changedAuditFields = form.getFieldsValue(
|
const changedAuditFields = form.getFieldsValue(
|
||||||
@@ -126,7 +126,10 @@ export function JobsAdminDatesChange({ insertAuditTrail, job }) {
|
|||||||
<Form.Item label={t("jobs.fields.actual_in")} name="actual_in">
|
<Form.Item label={t("jobs.fields.actual_in")} name="actual_in">
|
||||||
<DateTimePicker />
|
<DateTimePicker />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.date_repairstarted")} name="date_repairstarted">
|
<Form.Item
|
||||||
|
label={t("jobs.fields.date_repairstarted")}
|
||||||
|
name="date_repairstarted"
|
||||||
|
>
|
||||||
<DateTimePicker />
|
<DateTimePicker />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -173,6 +176,9 @@ export function JobsAdminDatesChange({ insertAuditTrail, job }) {
|
|||||||
>
|
>
|
||||||
<DateTimePicker />
|
<DateTimePicker />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item label={t("jobs.fields.date_void")} name="date_void">
|
||||||
|
<DateTimePicker />
|
||||||
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,18 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { gql, useMutation } from "@apollo/client";
|
||||||
import { Button, notification } from "antd";
|
import { Button, notification } from "antd";
|
||||||
import { gql } from "@apollo/client";
|
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
import moment from "moment";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||||
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
import {
|
import {
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import moment from "moment";
|
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
|
||||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
@@ -150,6 +149,10 @@ export function JobAdminMarkReexport({
|
|||||||
|
|
||||||
if (!result.errors) {
|
if (!result.errors) {
|
||||||
notification["success"]({ message: t("jobs.successes.save") });
|
notification["success"]({ message: t("jobs.successes.save") });
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid: job.id,
|
||||||
|
operation: AuditTrailMapping.admin_jobuninvoice(),
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.saving", {
|
message: t("jobs.errors.saving", {
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ export function JobsAdminUnvoid({
|
|||||||
mutation UNVOID_JOB($jobId: uuid!) {
|
mutation UNVOID_JOB($jobId: uuid!) {
|
||||||
update_jobs_by_pk(pk_columns: {id: $jobId}, _set: {voided: false, status: "${
|
update_jobs_by_pk(pk_columns: {id: $jobId}, _set: {voided: false, status: "${
|
||||||
bodyshop.md_ro_statuses.default_imported
|
bodyshop.md_ro_statuses.default_imported
|
||||||
}"}) {
|
}", date_void: null}) {
|
||||||
id
|
id
|
||||||
|
date_void
|
||||||
voided
|
voided
|
||||||
status
|
status
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import {
|
|||||||
useApolloClient,
|
useApolloClient,
|
||||||
useLazyQuery,
|
useLazyQuery,
|
||||||
useMutation,
|
useMutation,
|
||||||
useQuery
|
useQuery,
|
||||||
} from "@apollo/client";
|
} from "@apollo/client";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { Col, notification, Row } from "antd";
|
import { Col, notification, Row } from "antd";
|
||||||
@@ -20,7 +20,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
|
|||||||
import {
|
import {
|
||||||
DELETE_AVAILABLE_JOB,
|
DELETE_AVAILABLE_JOB,
|
||||||
QUERY_AVAILABLE_JOBS,
|
QUERY_AVAILABLE_JOBS,
|
||||||
QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK
|
QUERY_AVAILABLE_NEW_JOBS_EST_DATA_BY_PK,
|
||||||
} from "../../graphql/available-jobs.queries";
|
} from "../../graphql/available-jobs.queries";
|
||||||
import { INSERT_NEW_JOB, UPDATE_JOB } from "../../graphql/jobs.queries";
|
import { INSERT_NEW_JOB, UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||||
import { INSERT_NEW_NOTE } from "../../graphql/notes.queries";
|
import { INSERT_NEW_NOTE } from "../../graphql/notes.queries";
|
||||||
@@ -28,7 +28,7 @@ import { SEARCH_VEHICLE_BY_VIN } from "../../graphql/vehicles.queries";
|
|||||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
import {
|
import {
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import confirmDialog from "../../utils/asyncConfirm";
|
import confirmDialog from "../../utils/asyncConfirm";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
@@ -135,6 +135,7 @@ export function JobsAvailableContainer({
|
|||||||
owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
|
owner_owing: Dinero(newTotals.totals.custPayable.total).toFormat("0.00"),
|
||||||
job_totals: newTotals,
|
job_totals: newTotals,
|
||||||
date_open: moment(),
|
date_open: moment(),
|
||||||
|
status: bodyshop.md_ro_statuses.default_imported,
|
||||||
notes: {
|
notes: {
|
||||||
data: {
|
data: {
|
||||||
created_by: currentUser.email,
|
created_by: currentUser.email,
|
||||||
|
|||||||
@@ -4,22 +4,35 @@ import axios from "axios";
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
import { useHistory } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { auth } from "../../firebase/firebase.utils";
|
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||||
import {
|
import {
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import client from "../../utils/GraphQLClient";
|
||||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
|
||||||
import { useHistory } from "react-router-dom";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateJobCache(items) {
|
||||||
|
client.cache.modify({
|
||||||
|
id: "ROOT_QUERY",
|
||||||
|
fields: {
|
||||||
|
jobs(existingJobs = []) {
|
||||||
|
return existingJobs.filter(
|
||||||
|
(jobRef) => jobRef.__ref.includes(items) === false
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function JobsCloseExportButton({
|
export function JobsCloseExportButton({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
currentUser,
|
currentUser,
|
||||||
@@ -101,6 +114,9 @@ export function JobsCloseExportButton({
|
|||||||
|
|
||||||
//Check to see if any of them failed. If they didn't don't execute the update.
|
//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);
|
const failedTransactions = PartnerResponse.data.filter((r) => !r.success);
|
||||||
|
const successfulTransactions = PartnerResponse.data.filter(
|
||||||
|
(r) => r.success
|
||||||
|
);
|
||||||
if (failedTransactions.length > 0) {
|
if (failedTransactions.length > 0) {
|
||||||
//Uh oh. At least one was no good.
|
//Uh oh. At least one was no good.
|
||||||
failedTransactions.forEach((ft) => {
|
failedTransactions.forEach((ft) => {
|
||||||
@@ -159,12 +175,15 @@ export function JobsCloseExportButton({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!jobUpdateResponse.errors) {
|
if (!!!jobUpdateResponse.errors) {
|
||||||
notification.open({
|
notification.open({
|
||||||
type: "success",
|
type: "success",
|
||||||
key: "jobsuccessexport",
|
key: "jobsuccessexport",
|
||||||
message: t("jobs.successes.exported"),
|
message: t("jobs.successes.exported"),
|
||||||
});
|
});
|
||||||
|
updateJobCache(
|
||||||
|
jobUpdateResponse.data.update_jobs.returning.map((job) => job.id)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.exporting", {
|
message: t("jobs.errors.exporting", {
|
||||||
@@ -173,13 +192,31 @@ export function JobsCloseExportButton({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
||||||
|
notification.open({
|
||||||
|
type: "success",
|
||||||
|
key: "jobsuccessexport",
|
||||||
|
message: t("jobs.successes.exported"),
|
||||||
|
});
|
||||||
|
updateJobCache([
|
||||||
|
...new Set(
|
||||||
|
successfulTransactions.map(
|
||||||
|
(st) =>
|
||||||
|
st[
|
||||||
|
bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
|
||||||
|
? "jobid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
if (setSelectedJobs) {
|
if (setSelectedJobs) {
|
||||||
setSelectedJobs((selectedJobs) => {
|
setSelectedJobs((selectedJobs) => {
|
||||||
return selectedJobs.filter((i) => i !== jobId);
|
return selectedJobs.filter((i) => i !== jobId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) refetch();
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -141,6 +141,10 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
|
|||||||
<Form.Item label={t("jobs.fields.date_exported")} name="date_exported">
|
<Form.Item label={t("jobs.fields.date_exported")} name="date_exported">
|
||||||
<DateTimePicker disabled={true || jobRO} />
|
<DateTimePicker disabled={true || jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item label={t("jobs.fields.date_void")} name="date_void">
|
||||||
|
<DateTimePicker disabled={true || jobRO} />
|
||||||
|
</Form.Item>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import {
|
|||||||
Dropdown,
|
Dropdown,
|
||||||
Form,
|
Form,
|
||||||
Menu,
|
Menu,
|
||||||
notification,
|
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
Popover,
|
Popover,
|
||||||
Select,
|
Select,
|
||||||
|
notification,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -24,12 +24,12 @@ import {
|
|||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
|
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
import JobsDetailHeaderActionsAddevent from "./jobs-detail-header-actions.addevent";
|
import JobsDetailHeaderActionsAddevent from "./jobs-detail-header-actions.addevent";
|
||||||
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
|
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
|
||||||
import JobsDetaiLheaderCsi from "./jobs-detail-header-actions.csi.component";
|
import JobsDetaiLheaderCsi from "./jobs-detail-header-actions.csi.component";
|
||||||
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
|
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
|
||||||
import JobsDetailHeaderActionsExportcustdataComponent from "./jobs-detail-header-actions.exportcustdata.component";
|
import JobsDetailHeaderActionsExportcustdataComponent from "./jobs-detail-header-actions.exportcustdata.component";
|
||||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -48,6 +48,8 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
dispatch(setModalContext({ context: context, modal: "jobCosting" })),
|
dispatch(setModalContext({ context: context, modal: "jobCosting" })),
|
||||||
setTimeTicketContext: (context) =>
|
setTimeTicketContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
|
dispatch(setModalContext({ context: context, modal: "timeTicket" })),
|
||||||
|
setCardPaymentContext: (context) =>
|
||||||
|
dispatch(setModalContext({ context: context, modal: "cardPayment" })),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function JobsDetailHeaderActions({
|
export function JobsDetailHeaderActions({
|
||||||
@@ -61,6 +63,7 @@ export function JobsDetailHeaderActions({
|
|||||||
setJobCostingContext,
|
setJobCostingContext,
|
||||||
jobRO,
|
jobRO,
|
||||||
setTimeTicketContext,
|
setTimeTicketContext,
|
||||||
|
setCardPaymentContext,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
@@ -137,63 +140,67 @@ export function JobsDetailHeaderActions({
|
|||||||
<Menu.Item
|
<Menu.Item
|
||||||
disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled}
|
disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled}
|
||||||
>
|
>
|
||||||
<Popover
|
{job.status !== bodyshop.md_ro_statuses.default_scheduled ? (
|
||||||
trigger="click"
|
t("menus.jobsactions.cancelallappointments")
|
||||||
disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled}
|
) : (
|
||||||
content={
|
<Popover
|
||||||
<Form
|
trigger="click"
|
||||||
layout="vertical"
|
disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled}
|
||||||
onFinish={async ({ lost_sale_reason }) => {
|
content={
|
||||||
const jobUpdate = await cancelAllAppointments({
|
<Form
|
||||||
variables: {
|
layout="vertical"
|
||||||
jobid: job.id,
|
onFinish={async ({ lost_sale_reason }) => {
|
||||||
job: {
|
const jobUpdate = await cancelAllAppointments({
|
||||||
date_scheduled: null,
|
variables: {
|
||||||
scheduled_in: null,
|
jobid: job.id,
|
||||||
scheduled_completion: null,
|
job: {
|
||||||
lost_sale_reason,
|
date_scheduled: null,
|
||||||
status: bodyshop.md_ro_statuses.default_imported,
|
scheduled_in: null,
|
||||||
|
scheduled_completion: null,
|
||||||
|
lost_sale_reason,
|
||||||
|
status: bodyshop.md_ro_statuses.default_imported,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
|
||||||
});
|
|
||||||
if (!jobUpdate.errors) {
|
|
||||||
notification["success"]({
|
|
||||||
message: t("appointments.successes.canceled"),
|
|
||||||
});
|
});
|
||||||
return;
|
if (!jobUpdate.errors) {
|
||||||
}
|
notification["success"]({
|
||||||
}}
|
message: t("appointments.successes.canceled"),
|
||||||
>
|
});
|
||||||
<Form.Item
|
return;
|
||||||
name="lost_sale_reason"
|
}
|
||||||
label={t("jobs.fields.lost_sale_reason")}
|
}}
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<Select
|
<Form.Item
|
||||||
options={bodyshop.md_lost_sale_reasons.map((lsr) => ({
|
name="lost_sale_reason"
|
||||||
label: lsr,
|
label={t("jobs.fields.lost_sale_reason")}
|
||||||
value: lsr,
|
rules={[
|
||||||
}))}
|
{
|
||||||
/>
|
required: true,
|
||||||
</Form.Item>
|
//message: t("general.validation.required"),
|
||||||
<Button
|
},
|
||||||
htmlType="submit"
|
]}
|
||||||
disabled={
|
>
|
||||||
job.status !== bodyshop.md_ro_statuses.default_scheduled
|
<Select
|
||||||
}
|
options={bodyshop.md_lost_sale_reasons.map((lsr) => ({
|
||||||
>
|
label: lsr,
|
||||||
{t("appointments.actions.cancel")}
|
value: lsr,
|
||||||
</Button>
|
}))}
|
||||||
</Form>
|
/>
|
||||||
}
|
</Form.Item>
|
||||||
>
|
<Button
|
||||||
{t("menus.jobsactions.cancelallappointments")}
|
htmlType="submit"
|
||||||
</Popover>
|
disabled={
|
||||||
|
job.status !== bodyshop.md_ro_statuses.default_scheduled
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t("appointments.actions.cancel")}
|
||||||
|
</Button>
|
||||||
|
</Form>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{t("menus.jobsactions.cancelallappointments")}
|
||||||
|
</Popover>
|
||||||
|
)}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
disabled={
|
disabled={
|
||||||
@@ -239,7 +246,12 @@ export function JobsDetailHeaderActions({
|
|||||||
|
|
||||||
setTimeTicketContext({
|
setTimeTicketContext({
|
||||||
actions: {},
|
actions: {},
|
||||||
context: { jobId: job.id },
|
context: {
|
||||||
|
jobId: job.id,
|
||||||
|
created_by: currentUser.displayName
|
||||||
|
? currentUser.email.concat(" | ", currentUser.displayName)
|
||||||
|
: currentUser.email,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -259,6 +271,18 @@ export function JobsDetailHeaderActions({
|
|||||||
>
|
>
|
||||||
{t("menus.header.enterpayment")}
|
{t("menus.header.enterpayment")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item
|
||||||
|
key="entercardpayments"
|
||||||
|
disabled={!job.converted}
|
||||||
|
onClick={() => {
|
||||||
|
setCardPaymentContext({
|
||||||
|
actions: {},
|
||||||
|
context: { jobid: job.id },
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("menus.header.entercardpayment")}
|
||||||
|
</Menu.Item>
|
||||||
<Menu.Item key="cccontract" disabled={jobRO || !job.converted}>
|
<Menu.Item key="cccontract" disabled={jobRO || !job.converted}>
|
||||||
<Link
|
<Link
|
||||||
to={{
|
to={{
|
||||||
@@ -480,6 +504,7 @@ export function JobsDetailHeaderActions({
|
|||||||
scheduled_in: null,
|
scheduled_in: null,
|
||||||
scheduled_completion: null,
|
scheduled_completion: null,
|
||||||
inproduction: false,
|
inproduction: false,
|
||||||
|
date_void: new Date(),
|
||||||
},
|
},
|
||||||
note: [
|
note: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,12 +13,26 @@ import {
|
|||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
|
import client from "../../utils/GraphQLClient";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateJobCache(items) {
|
||||||
|
client.cache.modify({
|
||||||
|
id: "ROOT_QUERY",
|
||||||
|
fields: {
|
||||||
|
jobs(existingJobs = []) {
|
||||||
|
return existingJobs.filter(
|
||||||
|
(jobRef) => jobRef.__ref.includes(items) === false
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function JobsExportAllButton({
|
export function JobsExportAllButton({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
currentUser,
|
currentUser,
|
||||||
@@ -96,7 +110,9 @@ export function JobsExportAllButton({
|
|||||||
Object.keys(groupedData).map(async (key) => {
|
Object.keys(groupedData).map(async (key) => {
|
||||||
//Check to see if any of them failed. If they didn't don't execute the update.
|
//Check to see if any of them failed. If they didn't don't execute the update.
|
||||||
const failedTransactions = groupedData[key].filter((r) => !r.success);
|
const failedTransactions = groupedData[key].filter((r) => !r.success);
|
||||||
|
const successfulTransactions = groupedData[key].filter(
|
||||||
|
(r) => r.success
|
||||||
|
);
|
||||||
if (failedTransactions.length > 0) {
|
if (failedTransactions.length > 0) {
|
||||||
//Uh oh. At least one was no good.
|
//Uh oh. At least one was no good.
|
||||||
failedTransactions.forEach((ft) => {
|
failedTransactions.forEach((ft) => {
|
||||||
@@ -155,12 +171,17 @@ export function JobsExportAllButton({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!jobUpdateResponse.errors) {
|
if (!!!jobUpdateResponse.errors) {
|
||||||
notification.open({
|
notification.open({
|
||||||
type: "success",
|
type: "success",
|
||||||
key: "jobsuccessexport",
|
key: "jobsuccessexport",
|
||||||
message: t("jobs.successes.exported"),
|
message: t("jobs.successes.exported"),
|
||||||
});
|
});
|
||||||
|
updateJobCache(
|
||||||
|
jobUpdateResponse.data.update_jobs.returning.map(
|
||||||
|
(job) => job.id
|
||||||
|
)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("jobs.errors.exporting", {
|
message: t("jobs.errors.exporting", {
|
||||||
@@ -169,14 +190,31 @@ export function JobsExportAllButton({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
||||||
|
notification.open({
|
||||||
|
type: "success",
|
||||||
|
key: "jobsuccessexport",
|
||||||
|
message: t("jobs.successes.exported"),
|
||||||
|
});
|
||||||
|
updateJobCache([
|
||||||
|
...new Set(
|
||||||
|
successfulTransactions.map(
|
||||||
|
(st) =>
|
||||||
|
st[
|
||||||
|
bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
|
||||||
|
? "jobid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) refetch();
|
|
||||||
|
|
||||||
if (!!completedCallback) completedCallback([]);
|
if (!!completedCallback) completedCallback([]);
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { Link } from "react-router-dom";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
|
import { alphaSort, statusSort } from "../../utils/sorters";
|
||||||
import OwnerDetailUpdateJobsComponent from "../owner-detail-update-jobs/owner-detail-update-jobs.component";
|
import OwnerDetailUpdateJobsComponent from "../owner-detail-update-jobs/owner-detail-update-jobs.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -15,6 +16,15 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
function OwnerDetailJobsComponent({ bodyshop, owner }) {
|
function OwnerDetailJobsComponent({ bodyshop, owner }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [selectedJobs, setSelectedJobs] = useState([]);
|
const [selectedJobs, setSelectedJobs] = useState([]);
|
||||||
|
const [state, setState] = useState({
|
||||||
|
sortedInfo: {},
|
||||||
|
filteredInfo: { text: "" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.ro_number"),
|
title: t("jobs.fields.ro_number"),
|
||||||
@@ -26,6 +36,9 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
|
|||||||
{record.ro_number || t("general.labels.na")}
|
{record.ro_number || t("general.labels.na")}
|
||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
|
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.vehicle"),
|
title: t("jobs.fields.vehicle"),
|
||||||
@@ -46,11 +59,17 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
|
|||||||
title: t("jobs.fields.clm_no"),
|
title: t("jobs.fields.clm_no"),
|
||||||
dataIndex: "clm_no",
|
dataIndex: "clm_no",
|
||||||
key: "clm_no",
|
key: "clm_no",
|
||||||
|
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.status"),
|
title: t("jobs.fields.status"),
|
||||||
dataIndex: "status",
|
dataIndex: "status",
|
||||||
key: "status",
|
key: "status",
|
||||||
|
sorter: (a, b) => statusSort(a.status, b.status, bodyshop.md_ro_statuses.statuses),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -60,6 +79,9 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
|
|||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
|
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
|
||||||
),
|
),
|
||||||
|
sorter: (a, b) => a.clm_total - b.clm_total,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -80,6 +102,7 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
|
|||||||
scroll={{ x: true }}
|
scroll={{ x: true }}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
dataSource={owner.jobs}
|
dataSource={owner.jobs}
|
||||||
|
onChange={handleTableChange}
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
onSelect: (record, selected, selectedRows) => {
|
onSelect: (record, selected, selectedRows) => {
|
||||||
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
|
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
|
||||||
|
|||||||
@@ -113,6 +113,8 @@ export function PartsOrderListTableComponent({
|
|||||||
id: pol.id,
|
id: pol.id,
|
||||||
line_desc: pol.line_desc,
|
line_desc: pol.line_desc,
|
||||||
quantity: pol.quantity,
|
quantity: pol.quantity,
|
||||||
|
act_price: pol.act_price,
|
||||||
|
oem_partno: pol.oem_partno,
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -79,6 +79,20 @@ export function PartsReceiveModalComponent({ bodyshop, form }) {
|
|||||||
>
|
>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("joblines.fields.oem_partno")}
|
||||||
|
key={`${index}oem_partno`}
|
||||||
|
name={[field.name, "oem_partno"]}
|
||||||
|
>
|
||||||
|
<Input disabled />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("joblines.fields.act_price")}
|
||||||
|
key={`${index}act_price`}
|
||||||
|
name={[field.name, "act_price"]}
|
||||||
|
>
|
||||||
|
<Input disabled />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("joblines.fields.location")}
|
label={t("joblines.fields.location")}
|
||||||
key={`${index}location`}
|
key={`${index}location`}
|
||||||
|
|||||||
@@ -1,26 +1,39 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, notification } from "antd";
|
import { Button, notification } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import _ from "lodash";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { auth } from "../../firebase/firebase.utils";
|
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||||
import { UPDATE_BILLS } from "../../graphql/bills.queries";
|
import { UPDATE_BILLS } from "../../graphql/bills.queries";
|
||||||
import {
|
import {
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import client from "../../utils/GraphQLClient";
|
||||||
import _ from "lodash";
|
|
||||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateBillCache(items) {
|
||||||
|
client.cache.modify({
|
||||||
|
id: "ROOT_QUERY",
|
||||||
|
fields: {
|
||||||
|
bills(existingJobs = []) {
|
||||||
|
return existingJobs.filter(
|
||||||
|
(billRef) => billRef.__ref.includes(items) === false
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function PayableExportAll({
|
export function PayableExportAll({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
currentUser,
|
currentUser,
|
||||||
@@ -97,7 +110,9 @@ export function PayableExportAll({
|
|||||||
proms.push(
|
proms.push(
|
||||||
(async () => {
|
(async () => {
|
||||||
const failedTransactions = groupedData[key].filter((r) => !r.success);
|
const failedTransactions = groupedData[key].filter((r) => !r.success);
|
||||||
|
const successfulTransactions = groupedData[key].filter(
|
||||||
|
(r) => r.success
|
||||||
|
);
|
||||||
if (failedTransactions.length > 0) {
|
if (failedTransactions.length > 0) {
|
||||||
//Uh oh. At least one was no good.
|
//Uh oh. At least one was no good.
|
||||||
failedTransactions.map((ft) =>
|
failedTransactions.map((ft) =>
|
||||||
@@ -143,7 +158,15 @@ export function PayableExportAll({
|
|||||||
|
|
||||||
const billUpdateResponse = await updateBill({
|
const billUpdateResponse = await updateBill({
|
||||||
variables: {
|
variables: {
|
||||||
billIdList: [key],
|
billIdList: successfulTransactions.map(
|
||||||
|
(st) =>
|
||||||
|
st[
|
||||||
|
bodyshop.accountingconfig &&
|
||||||
|
bodyshop.accountingconfig.qbo
|
||||||
|
? "billid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
),
|
||||||
bill: {
|
bill: {
|
||||||
exported: true,
|
exported: true,
|
||||||
exported_at: new Date(),
|
exported_at: new Date(),
|
||||||
@@ -156,6 +179,11 @@ export function PayableExportAll({
|
|||||||
key: "billsuccessexport",
|
key: "billsuccessexport",
|
||||||
message: t("bills.successes.exported"),
|
message: t("bills.successes.exported"),
|
||||||
});
|
});
|
||||||
|
updateBillCache(
|
||||||
|
billUpdateResponse.data.update_bills.returning.map(
|
||||||
|
(bill) => bill.id
|
||||||
|
)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("bills.errors.exporting", {
|
message: t("bills.errors.exporting", {
|
||||||
@@ -164,6 +192,26 @@ export function PayableExportAll({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
||||||
|
notification.open({
|
||||||
|
type: "success",
|
||||||
|
key: "billsuccessexport",
|
||||||
|
message: t("bills.successes.exported"),
|
||||||
|
});
|
||||||
|
updateBillCache([
|
||||||
|
...new Set(
|
||||||
|
successfulTransactions.map(
|
||||||
|
(st) =>
|
||||||
|
st[
|
||||||
|
bodyshop.accountingconfig &&
|
||||||
|
bodyshop.accountingconfig.qbo
|
||||||
|
? "billid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
@@ -172,8 +220,6 @@ export function PayableExportAll({
|
|||||||
await Promise.all(proms);
|
await Promise.all(proms);
|
||||||
if (!!completedCallback) completedCallback([]);
|
if (!!completedCallback) completedCallback([]);
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) refetch();
|
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,22 +4,35 @@ import axios from "axios";
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { auth } from "../../firebase/firebase.utils";
|
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
||||||
import { UPDATE_BILLS } from "../../graphql/bills.queries";
|
import { UPDATE_BILLS } from "../../graphql/bills.queries";
|
||||||
import {
|
import {
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import client from "../../utils/GraphQLClient";
|
||||||
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updateBillCache(items) {
|
||||||
|
client.cache.modify({
|
||||||
|
id: "ROOT_QUERY",
|
||||||
|
fields: {
|
||||||
|
bills(existingJobs = []) {
|
||||||
|
return existingJobs.filter(
|
||||||
|
(billRef) => billRef.__ref.includes(items) === false
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function PayableExportButton({
|
export function PayableExportButton({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
currentUser,
|
currentUser,
|
||||||
@@ -159,6 +172,11 @@ export function PayableExportButton({
|
|||||||
key: "billsuccessexport",
|
key: "billsuccessexport",
|
||||||
message: t("bills.successes.exported"),
|
message: t("bills.successes.exported"),
|
||||||
});
|
});
|
||||||
|
updateBillCache(
|
||||||
|
billUpdateResponse.data.update_bills.returning.map(
|
||||||
|
(bill) => bill.id
|
||||||
|
)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("bills.errors.exporting", {
|
message: t("bills.errors.exporting", {
|
||||||
@@ -167,7 +185,25 @@ export function PayableExportButton({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) refetch();
|
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
||||||
|
notification.open({
|
||||||
|
type: "success",
|
||||||
|
key: "billsuccessexport",
|
||||||
|
message: t("bills.successes.exported"),
|
||||||
|
});
|
||||||
|
updateBillCache([
|
||||||
|
...new Set(
|
||||||
|
successfulTransactions.map(
|
||||||
|
(st) =>
|
||||||
|
st[
|
||||||
|
bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
|
||||||
|
? "billid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
if (setSelectedBills) {
|
if (setSelectedBills) {
|
||||||
setSelectedBills((selectedBills) => {
|
setSelectedBills((selectedBills) => {
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
|
import {
|
||||||
|
Button,
|
||||||
|
Descriptions,
|
||||||
|
InputNumber,
|
||||||
|
Modal,
|
||||||
|
Space,
|
||||||
|
notification,
|
||||||
|
} from "antd";
|
||||||
|
import axios from "axios";
|
||||||
|
import moment from "moment";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import {
|
||||||
|
GET_REFUNDABLE_AMOUNT_BY_JOBID,
|
||||||
|
INSERT_PAYMENT_RESPONSE,
|
||||||
|
QUERY_PAYMENT_RESPONSE_BY_PAYMENT_ID,
|
||||||
|
} from "../../graphql/payment_response.queries";
|
||||||
|
import { INSERT_NEW_PAYMENT } from "../../graphql/payments.queries";
|
||||||
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
|
|
||||||
|
const { confirm } = Modal;
|
||||||
|
|
||||||
|
const openNotificationWithIcon = (type, t) => {
|
||||||
|
notification[type]({
|
||||||
|
message: t("job_payments.notifications.error.title"),
|
||||||
|
description: t("job_payments.notifications.error.description"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const PaymentExpandedRowComponent = ({ record, bodyshop }) => {
|
||||||
|
const [refundAmount, setRefundAmount] = useState(0);
|
||||||
|
const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
|
||||||
|
const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const { loading, error, data } = useQuery(
|
||||||
|
QUERY_PAYMENT_RESPONSE_BY_PAYMENT_ID,
|
||||||
|
{
|
||||||
|
variables: {
|
||||||
|
paymentid: record.id,
|
||||||
|
fetchPolicy: "network-only",
|
||||||
|
nextFetchPolicy: "network-only",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const { data: refundable_amount, refetch } = useQuery(
|
||||||
|
GET_REFUNDABLE_AMOUNT_BY_JOBID,
|
||||||
|
{
|
||||||
|
variables: {
|
||||||
|
jobid: record.jobid,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const insertPayments = async (payment_response, refund_response) => {
|
||||||
|
await insertPayment({
|
||||||
|
variables: {
|
||||||
|
paymentInput: {
|
||||||
|
amount: -refund_response.data.amount,
|
||||||
|
transactionid: payment_response.response.receiptelements.transid,
|
||||||
|
payer: record.payer,
|
||||||
|
type: "Refund",
|
||||||
|
jobid: payment_response.jobid,
|
||||||
|
date: moment(Date.now()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update(cache, { data }) {
|
||||||
|
cache.modify({
|
||||||
|
id: cache.identify({
|
||||||
|
id: payment_response.jobid,
|
||||||
|
__typename: "jobs",
|
||||||
|
}),
|
||||||
|
fields: {
|
||||||
|
payments(payments) {
|
||||||
|
return [...data.insert_payments.returning, ...payments];
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await insertPaymentResponse({
|
||||||
|
variables: {
|
||||||
|
paymentResponse: {
|
||||||
|
amount: -refund_response.data.amount,
|
||||||
|
bodyshopid: payment_response.bodyshopid,
|
||||||
|
paymentid: payment_response.paymentid,
|
||||||
|
jobid: payment_response.jobid,
|
||||||
|
declinereason: "Refund",
|
||||||
|
ext_paymentid: payment_response.ext_paymentid,
|
||||||
|
successful: true,
|
||||||
|
response: refund_response.data,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const showConfirm = (payment_response) => {
|
||||||
|
confirm({
|
||||||
|
title: "Do you want to refund payment?",
|
||||||
|
content:
|
||||||
|
"The payment will be refunded. Click OK to confirm and Cancel to dismiss.",
|
||||||
|
async onOk() {
|
||||||
|
const refundResponse = await axios.post("/intellipay/payment_refund", {
|
||||||
|
bodyshop,
|
||||||
|
amount: refundAmount,
|
||||||
|
paymentid: payment_response.ext_paymentid,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (refundResponse.data.status < 0) {
|
||||||
|
openNotificationWithIcon("error", t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
insertPayments(payment_response, refundResponse);
|
||||||
|
|
||||||
|
// refetch refundable amount
|
||||||
|
refetch();
|
||||||
|
},
|
||||||
|
onCancel() {},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) return null;
|
||||||
|
|
||||||
|
if (error) return <p>Error loading data. Please Reload</p>;
|
||||||
|
|
||||||
|
const payment_response = data.payment_response[0];
|
||||||
|
const max_refundable_amount =
|
||||||
|
refundable_amount?.payment_response_aggregate.aggregate.sum.amount;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Descriptions
|
||||||
|
title={t("job_payments.titles.descriptions")}
|
||||||
|
contentStyle={{ fontWeight: "600" }}
|
||||||
|
column={4}
|
||||||
|
>
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.payer")}>
|
||||||
|
{record.payer}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.payername")}>
|
||||||
|
{payment_response?.response?.nameOnCard ?? ""}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.amount")}>
|
||||||
|
<CurrencyFormatter>{record.amount}</CurrencyFormatter>
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.dateOfPayment")}>
|
||||||
|
{<DateTimeFormatter>{record.created_at}</DateTimeFormatter>}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.transactionid")}>
|
||||||
|
{record.transactionid}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.paymentid")}>
|
||||||
|
{payment_response?.response?.paymentreferenceid ?? ""}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.paymenttype")}>
|
||||||
|
{record.type}
|
||||||
|
</Descriptions.Item>
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.paymentnum")}>
|
||||||
|
{record.paymentnum}
|
||||||
|
</Descriptions.Item>
|
||||||
|
{payment_response && (
|
||||||
|
<Descriptions.Item label={t("job_payments.titles.refundamount")}>
|
||||||
|
<Space>
|
||||||
|
<InputNumber
|
||||||
|
onChange={setRefundAmount}
|
||||||
|
max={max_refundable_amount}
|
||||||
|
min={0}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Button onClick={() => showConfirm(payment_response)}>
|
||||||
|
{t("job_payments.buttons.refundpayment")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</Descriptions.Item>
|
||||||
|
)}
|
||||||
|
</Descriptions>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default PaymentExpandedRowComponent;
|
||||||
@@ -13,12 +13,26 @@ import {
|
|||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
|
import client from "../../utils/GraphQLClient";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updatePaymentCache(items) {
|
||||||
|
client.cache.modify({
|
||||||
|
id: "ROOT_QUERY",
|
||||||
|
fields: {
|
||||||
|
payments(existingJobs = []) {
|
||||||
|
return existingJobs.filter(
|
||||||
|
(paymentRef) => paymentRef.__ref.includes(items) === false
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function PaymentExportButton({
|
export function PaymentExportButton({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
currentUser,
|
currentUser,
|
||||||
@@ -157,6 +171,11 @@ export function PaymentExportButton({
|
|||||||
key: "paymentsuccessexport",
|
key: "paymentsuccessexport",
|
||||||
message: t("payments.successes.exported"),
|
message: t("payments.successes.exported"),
|
||||||
});
|
});
|
||||||
|
updatePaymentCache(
|
||||||
|
paymentUpdateResponse.data.update_payments.returning.map(
|
||||||
|
(payment) => payment.id
|
||||||
|
)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("payments.errors.exporting", {
|
message: t("payments.errors.exporting", {
|
||||||
@@ -172,7 +191,25 @@ export function PaymentExportButton({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) refetch();
|
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
||||||
|
notification.open({
|
||||||
|
type: "success",
|
||||||
|
key: "paymentsuccessexport",
|
||||||
|
message: t("payments.successes.exported"),
|
||||||
|
});
|
||||||
|
updatePaymentCache([
|
||||||
|
...new Set(
|
||||||
|
successfulTransactions.map(
|
||||||
|
(st) =>
|
||||||
|
st[
|
||||||
|
bodyshop.accountingconfig && bodyshop.accountingconfig.qbo
|
||||||
|
? "paymentid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,11 +13,25 @@ import {
|
|||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
|
import client from "../../utils/GraphQLClient";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function updatePaymentCache(items) {
|
||||||
|
client.cache.modify({
|
||||||
|
id: "ROOT_QUERY",
|
||||||
|
fields: {
|
||||||
|
payments(existingJobs = []) {
|
||||||
|
return existingJobs.filter(
|
||||||
|
(paymentRef) => paymentRef.__ref.includes(items) === false
|
||||||
|
);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function PaymentsExportAllButton({
|
export function PaymentsExportAllButton({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
currentUser,
|
currentUser,
|
||||||
@@ -25,7 +39,7 @@ export function PaymentsExportAllButton({
|
|||||||
disabled,
|
disabled,
|
||||||
loadingCallback,
|
loadingCallback,
|
||||||
completedCallback,
|
completedCallback,
|
||||||
refetch
|
refetch,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [updatePayments] = useMutation(UPDATE_PAYMENTS);
|
const [updatePayments] = useMutation(UPDATE_PAYMENTS);
|
||||||
@@ -84,7 +98,9 @@ export function PaymentsExportAllButton({
|
|||||||
proms.push(
|
proms.push(
|
||||||
(async () => {
|
(async () => {
|
||||||
const failedTransactions = groupedData[key].filter((r) => !r.success);
|
const failedTransactions = groupedData[key].filter((r) => !r.success);
|
||||||
|
const successfulTransactions = groupedData[key].filter(
|
||||||
|
(r) => r.success
|
||||||
|
);
|
||||||
if (failedTransactions.length > 0) {
|
if (failedTransactions.length > 0) {
|
||||||
//Uh oh. At least one was no good.
|
//Uh oh. At least one was no good.
|
||||||
failedTransactions.map((ft) =>
|
failedTransactions.map((ft) =>
|
||||||
@@ -130,7 +146,15 @@ export function PaymentsExportAllButton({
|
|||||||
});
|
});
|
||||||
const paymentUpdateResponse = await updatePayments({
|
const paymentUpdateResponse = await updatePayments({
|
||||||
variables: {
|
variables: {
|
||||||
paymentIdList: [key],
|
paymentIdList: successfulTransactions.map(
|
||||||
|
(st) =>
|
||||||
|
st[
|
||||||
|
bodyshop.accountingconfig &&
|
||||||
|
bodyshop.accountingconfig.qbo
|
||||||
|
? "paymentid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
),
|
||||||
payment: {
|
payment: {
|
||||||
exportedat: new Date(),
|
exportedat: new Date(),
|
||||||
},
|
},
|
||||||
@@ -142,6 +166,11 @@ export function PaymentsExportAllButton({
|
|||||||
key: "paymentsuccessexport",
|
key: "paymentsuccessexport",
|
||||||
message: t("payments.successes.exported"),
|
message: t("payments.successes.exported"),
|
||||||
});
|
});
|
||||||
|
updatePaymentCache(
|
||||||
|
paymentUpdateResponse.data.update_payments.returning.map(
|
||||||
|
(payment) => payment.id
|
||||||
|
)
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
notification["error"]({
|
notification["error"]({
|
||||||
message: t("payments.errors.exporting", {
|
message: t("payments.errors.exporting", {
|
||||||
@@ -150,6 +179,26 @@ export function PaymentsExportAllButton({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && successfulTransactions.length > 0) {
|
||||||
|
notification.open({
|
||||||
|
type: "success",
|
||||||
|
key: "paymentsuccessexport",
|
||||||
|
message: t("payments.successes.exported"),
|
||||||
|
});
|
||||||
|
updatePaymentCache([
|
||||||
|
...new Set(
|
||||||
|
successfulTransactions.map(
|
||||||
|
(st) =>
|
||||||
|
st[
|
||||||
|
bodyshop.accountingconfig &&
|
||||||
|
bodyshop.accountingconfig.qbo
|
||||||
|
? "paymentid"
|
||||||
|
: "id"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
);
|
);
|
||||||
@@ -157,7 +206,6 @@ export function PaymentsExportAllButton({
|
|||||||
await Promise.all(proms);
|
await Promise.all(proms);
|
||||||
if (!!completedCallback) completedCallback([]);
|
if (!!completedCallback) completedCallback([]);
|
||||||
if (!!loadingCallback) loadingCallback(false);
|
if (!!loadingCallback) loadingCallback(false);
|
||||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) refetch();
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
import { CopyFilled } from "@ant-design/icons";
|
||||||
|
import { Button, Form, Popover, Space, message } from "antd";
|
||||||
|
import axios from "axios";
|
||||||
|
import Dinero from "dinero.js";
|
||||||
|
import { parsePhoneNumber } from "libphonenumber-js";
|
||||||
|
import React, { useState } from "react";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import {
|
||||||
|
openChatByPhone,
|
||||||
|
setMessage,
|
||||||
|
} from "../../redux/messaging/messaging.actions";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
openChatByPhone: (phone) => dispatch(openChatByPhone(phone)),
|
||||||
|
setMessage: (text) => dispatch(setMessage(text)),
|
||||||
|
});
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(PaymentsGenerateLink);
|
||||||
|
|
||||||
|
export function PaymentsGenerateLink({
|
||||||
|
bodyshop,
|
||||||
|
callback,
|
||||||
|
job,
|
||||||
|
openChatByPhone,
|
||||||
|
setMessage,
|
||||||
|
}) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [paymentLink, setPaymentLink] = useState(null);
|
||||||
|
|
||||||
|
const handleFinish = async ({ amount }) => {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
const p = parsePhoneNumber(job.ownr_ph1, "CA");
|
||||||
|
setLoading(true);
|
||||||
|
const response = await axios.post("/intellipay/generate_payment_url", {
|
||||||
|
bodyshop,
|
||||||
|
amount: amount,
|
||||||
|
account: job.ro_number,
|
||||||
|
invoice: job.id,
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
setPaymentLink(response.data.shorUrl);
|
||||||
|
|
||||||
|
openChatByPhone({
|
||||||
|
phone_num: p.formatInternational(),
|
||||||
|
jobid: job.id,
|
||||||
|
});
|
||||||
|
setMessage(
|
||||||
|
t("payments.labels.smspaymentreminder", {
|
||||||
|
shopname: bodyshop.shopname,
|
||||||
|
amount: amount,
|
||||||
|
payment_link: response.data.shorUrl,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
//Add in confirmation & errors.
|
||||||
|
if (callback) callback();
|
||||||
|
|
||||||
|
// setVisible(false);
|
||||||
|
setLoading(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const popContent = (
|
||||||
|
<div>
|
||||||
|
<Form onFinish={handleFinish} layout="vertical" form={form}>
|
||||||
|
<Form.Item
|
||||||
|
label={t("payments.fields.amount")}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
name="amount"
|
||||||
|
>
|
||||||
|
<CurrencyFormItemComponent />
|
||||||
|
</Form.Item>
|
||||||
|
{paymentLink && (
|
||||||
|
<Space direction="vertical">
|
||||||
|
<Space
|
||||||
|
style={{ cursor: "pointer" }}
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(paymentLink);
|
||||||
|
message.success(t("general.actions.copied"));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
onClick={() => {
|
||||||
|
//Copy the link.
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{paymentLink}
|
||||||
|
</div>{" "}
|
||||||
|
<CopyFilled />
|
||||||
|
</Space>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
const p = parsePhoneNumber(job.ownr_ph1, "CA");
|
||||||
|
openChatByPhone({
|
||||||
|
phone_num: p.formatInternational(),
|
||||||
|
jobid: job.id,
|
||||||
|
});
|
||||||
|
setMessage(
|
||||||
|
t("payments.labels.smspaymentreminder", {
|
||||||
|
shopname: bodyshop.shopname,
|
||||||
|
amount: Dinero({
|
||||||
|
amount: Math.round(form.getFieldValue("amount") * 100),
|
||||||
|
}).toFormat(),
|
||||||
|
payment_link: paymentLink,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("general.actions.sendbysms")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
|
</Form>
|
||||||
|
<Space>
|
||||||
|
<Button type="primary" onClick={() => form.submit()}>
|
||||||
|
{t("general.actions.submit")}
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
form.resetFields();
|
||||||
|
setPaymentLink(null);
|
||||||
|
setVisible(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("general.actions.cancel")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover content={popContent} visible={visible}>
|
||||||
|
<Button onClick={() => setVisible(true)} loading={loading}>
|
||||||
|
{t("payments.actions.generatepaymentlink")}
|
||||||
|
</Button>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -5,11 +5,13 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { setEmailOptions } from "../../redux/email/email.actions";
|
import { setEmailOptions } from "../../redux/email/email.actions";
|
||||||
import { selectPrintCenter } from "../../redux/modals/modals.selectors";
|
import { selectPrintCenter } from "../../redux/modals/modals.selectors";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
printCenterModal: selectPrintCenter,
|
printCenterModal: selectPrintCenter,
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
technician: selectTechnician,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
|
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
|
||||||
@@ -22,6 +24,7 @@ export function PrintCenterItemComponent({
|
|||||||
id,
|
id,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
disabled,
|
disabled,
|
||||||
|
technician,
|
||||||
}) {
|
}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { context } = printCenterModal;
|
const { context } = printCenterModal;
|
||||||
@@ -44,19 +47,24 @@ export function PrintCenterItemComponent({
|
|||||||
<Space wrap>
|
<Space wrap>
|
||||||
{item.title}
|
{item.title}
|
||||||
<PrinterOutlined onClick={renderToNewWindow} />
|
<PrinterOutlined onClick={renderToNewWindow} />
|
||||||
<MailOutlined
|
{!technician ? (
|
||||||
onClick={() => {
|
<MailOutlined
|
||||||
GenerateDocument(
|
onClick={() => {
|
||||||
{
|
GenerateDocument(
|
||||||
name: item.key,
|
{
|
||||||
variables: { id: id },
|
name: item.key,
|
||||||
},
|
variables: { id: id },
|
||||||
{ to: context.job && context.job.ownr_ea, subject: item.subject },
|
},
|
||||||
"e",
|
{
|
||||||
id
|
to: context.job && context.job.ownr_ea,
|
||||||
);
|
subject: item.subject,
|
||||||
}}
|
},
|
||||||
/>
|
"e",
|
||||||
|
id
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
{loading && <Spin />}
|
{loading && <Spin />}
|
||||||
</Space>
|
</Space>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,31 +1,33 @@
|
|||||||
|
import { PrinterFilled } from "@ant-design/icons";
|
||||||
import { useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
import { Descriptions, Drawer, Space, PageHeader, Button } from "antd";
|
import { Button, Descriptions, Drawer, PageHeader, Space } from "antd";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import { useHistory, useLocation } from "react-router-dom";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
import { QUERY_JOB_CARD_DETAILS } from "../../graphql/jobs.queries";
|
import { QUERY_JOB_CARD_DETAILS } from "../../graphql/jobs.queries";
|
||||||
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import StartChatButton from "../chat-open-button/chat-open-button.component";
|
import StartChatButton from "../chat-open-button/chat-open-button.component";
|
||||||
|
import JobAtChange from "../job-at-change/job-at-change.component";
|
||||||
import JobDetailCardsDocumentsComponent from "../job-detail-cards/job-detail-cards.documents.component";
|
import JobDetailCardsDocumentsComponent from "../job-detail-cards/job-detail-cards.documents.component";
|
||||||
import JobDetailCardsNotesComponent from "../job-detail-cards/job-detail-cards.notes.component";
|
import JobDetailCardsNotesComponent from "../job-detail-cards/job-detail-cards.notes.component";
|
||||||
import JobDetailCardsPartsComponent from "../job-detail-cards/job-detail-cards.parts.component";
|
import JobDetailCardsPartsComponent from "../job-detail-cards/job-detail-cards.parts.component";
|
||||||
import JobEmployeeAssignments from "../job-employee-assignments/job-employee-assignments.container";
|
import JobEmployeeAssignments from "../job-employee-assignments/job-employee-assignments.container";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
|
||||||
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
|
|
||||||
import JobAtChange from "../job-at-change/job-at-change.component";
|
|
||||||
import { PrinterFilled } from "@ant-design/icons";
|
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
|
||||||
import ScoreboardAddButton from "../job-scoreboard-add-button/job-scoreboard-add-button.component";
|
import ScoreboardAddButton from "../job-scoreboard-add-button/job-scoreboard-add-button.component";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
technician: selectTechnician,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setPrintCenterContext: (context) =>
|
setPrintCenterContext: (context) =>
|
||||||
@@ -40,6 +42,7 @@ export function ProductionListDetail({
|
|||||||
bodyshop,
|
bodyshop,
|
||||||
jobs,
|
jobs,
|
||||||
setPrintCenterContext,
|
setPrintCenterContext,
|
||||||
|
technician,
|
||||||
}) {
|
}) {
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
@@ -66,7 +69,9 @@ export function ProductionListDetail({
|
|||||||
title={theJob.ro_number}
|
title={theJob.ro_number}
|
||||||
extra={
|
extra={
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
<ProductionRemoveButton jobId={theJob.id} />{" "}
|
{!technician ? (
|
||||||
|
<ProductionRemoveButton jobId={theJob.id} />
|
||||||
|
) : null}
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setPrintCenterContext({
|
setPrintCenterContext({
|
||||||
@@ -82,7 +87,9 @@ export function ProductionListDetail({
|
|||||||
<PrinterFilled />
|
<PrinterFilled />
|
||||||
{t("jobs.actions.printCenter")}
|
{t("jobs.actions.printCenter")}
|
||||||
</Button>
|
</Button>
|
||||||
<ScoreboardAddButton job={data ? data.jobs_by_pk : {}} />
|
{!technician ? (
|
||||||
|
<ScoreboardAddButton job={data ? data.jobs_by_pk : {}} />
|
||||||
|
) : null}
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -59,11 +59,12 @@ export function ScheduleManualEvent({ bodyshop, event }) {
|
|||||||
refetchQueries: ["QUERY_ALL_ACTIVE_APPOINTMENTS"],
|
refetchQueries: ["QUERY_ALL_ACTIVE_APPOINTMENTS"],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
form.resetFields();
|
||||||
|
setVisibility(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
setVisibility(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -47,9 +47,7 @@ export function ScoreboardChart({ sbEntriesByDate, bodyshop }) {
|
|||||||
bodyhrs: dayAcc.bodyhrs + dayVal.bodyhrs,
|
bodyhrs: dayAcc.bodyhrs + dayVal.bodyhrs,
|
||||||
painthrs: dayAcc.painthrs + dayVal.painthrs,
|
painthrs: dayAcc.painthrs + dayVal.painthrs,
|
||||||
sales:
|
sales:
|
||||||
dayAcc.painthrs +
|
dayAcc.sales + dayVal.job.job_totals.totals.subtotal.amount / 100,
|
||||||
dayVal.job.job_totals.totals.subtotal.amount / 100 +
|
|
||||||
2500,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
{ bodyhrs: 0, painthrs: 0, sales: 0 }
|
{ bodyhrs: 0, painthrs: 0, sales: 0 }
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
import ShopInfoComponent from "./shop-info.component";
|
|
||||||
import { Form, notification } from "antd";
|
import { Form, notification } from "antd";
|
||||||
import { useQuery, useMutation } from "@apollo/client";
|
import moment from "moment";
|
||||||
import { QUERY_BODYSHOP, UPDATE_SHOP } from "../../graphql/bodyshop.queries";
|
import React, { useEffect, useState } from "react";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
|
||||||
import AlertComponent from "../alert/alert.component";
|
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { QUERY_BODYSHOP, UPDATE_SHOP } from "../../graphql/bodyshop.queries";
|
||||||
|
import AlertComponent from "../alert/alert.component";
|
||||||
import FormsFieldChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
import FormsFieldChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
import moment from "moment";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
|
import ShopInfoComponent from "./shop-info.component";
|
||||||
export default function ShopInfoContainer() {
|
export default function ShopInfoContainer() {
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -52,13 +52,28 @@ export default function ShopInfoContainer() {
|
|||||||
onFinish={handleFinish}
|
onFinish={handleFinish}
|
||||||
initialValues={
|
initialValues={
|
||||||
data
|
data
|
||||||
? {
|
? data.bodyshops[0].accountingconfig.ClosingPeriod
|
||||||
...data.bodyshops[0],
|
? {
|
||||||
schedule_start_time: moment(
|
...data.bodyshops[0],
|
||||||
data.bodyshops[0].schedule_start_time
|
accountingconfig: {
|
||||||
),
|
...data.bodyshops[0].accountingconfig,
|
||||||
schedule_end_time: moment(data.bodyshops[0].schedule_end_time),
|
ClosingPeriod: [
|
||||||
}
|
moment(data.bodyshops[0].accountingconfig.ClosingPeriod[0]),
|
||||||
|
moment(data.bodyshops[0].accountingconfig.ClosingPeriod[1]),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
schedule_start_time: moment(
|
||||||
|
data.bodyshops[0].schedule_start_time
|
||||||
|
),
|
||||||
|
schedule_end_time: moment(data.bodyshops[0].schedule_end_time),
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
...data.bodyshops[0],
|
||||||
|
schedule_start_time: moment(
|
||||||
|
data.bodyshops[0].schedule_start_time
|
||||||
|
),
|
||||||
|
schedule_end_time: moment(data.bodyshops[0].schedule_end_time),
|
||||||
|
}
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import { DeleteFilled } from "@ant-design/icons";
|
import { DeleteFilled } from "@ant-design/icons";
|
||||||
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
|
DatePicker,
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
@@ -9,8 +11,13 @@ import {
|
|||||||
Space,
|
Space,
|
||||||
Switch,
|
Switch,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
|
import momentTZ from "moment-timezone";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import DatePickerRanges from "../../utils/DatePickerRanges";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||||
import PhoneFormItem, {
|
import PhoneFormItem, {
|
||||||
@@ -18,12 +25,22 @@ import PhoneFormItem, {
|
|||||||
} from "../form-items-formatted/phone-form-item.component";
|
} from "../form-items-formatted/phone-form-item.component";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
|
||||||
import momentTZ from "moment-timezone";
|
|
||||||
const timeZonesList = momentTZ.tz.names();
|
const timeZonesList = momentTZ.tz.names();
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
bodyshop: selectBodyshop,
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
|
});
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(ShopInfoGeneral);
|
||||||
|
|
||||||
export default function ShopInfoGeneral({ form }) {
|
export function ShopInfoGeneral({ form, bodyshop }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const { ClosingPeriod } = useTreatments(
|
||||||
|
["ClosingPeriod"],
|
||||||
|
{},
|
||||||
|
bodyshop && bodyshop.imexshopid
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -392,6 +409,20 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<Select mode="tags" />
|
<Select mode="tags" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{ClosingPeriod.treatment === "on" && (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
allowClear
|
||||||
|
name={["accountingconfig", "ClosingPeriod"]}
|
||||||
|
label={t("bodyshop.fields.closingperiod")} //{t("reportcenter.labels.dates")}
|
||||||
|
>
|
||||||
|
<DatePicker.RangePicker
|
||||||
|
format="MM/DD/YYYY"
|
||||||
|
ranges={DatePickerRanges}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow
|
<LayoutFormRow
|
||||||
header={t("bodyshop.labels.scoreboardsetup")}
|
header={t("bodyshop.labels.scoreboardsetup")}
|
||||||
@@ -602,6 +633,20 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<Select mode="tags" />
|
<Select mode="tags" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={["md_email_cc", "parts_return_slip"]}
|
||||||
|
label={t("bodyshop.fields.md_email_cc", {
|
||||||
|
template: "parts_return_slip",
|
||||||
|
})}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
type: "array",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select mode="tags" />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={["tt_allow_post_to_invoiced"]}
|
name={["tt_allow_post_to_invoiced"]}
|
||||||
label={t("bodyshop.fields.tt_allow_post_to_invoiced")}
|
label={t("bodyshop.fields.tt_allow_post_to_invoiced")}
|
||||||
|
|||||||
@@ -162,6 +162,32 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
|||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
|
{bodyshop.pbs_serialnumber && (
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.dms.appostingaccount")}
|
||||||
|
name={["pbs_configuration", "appostingaccount"]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={[
|
||||||
|
{ value: "wip", label: "WIP" },
|
||||||
|
{ value: "cogs", label: "COGS" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
{bodyshop.pbs_serialnumber && (
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.dms.apcontrol")}
|
||||||
|
name={["pbs_configuration", "apcontrol"]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={[
|
||||||
|
{ value: "ro", label: "RO Number" },
|
||||||
|
{ value: "vendordmsid", label: "Vendor DMS ID" },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("bodyshop.labels.dms.cdk.payers")}>
|
<LayoutFormRow header={t("bodyshop.labels.dms.cdk.payers")}>
|
||||||
<Form.List name={["cdk_configuration", "payers"]}>
|
<Form.List name={["cdk_configuration", "payers"]}>
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Card, Form, notification, Space } from "antd";
|
import { Button, Card, Form, notification, Space } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import moment from "moment";
|
||||||
|
import momenttz from "moment-timezone";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries";
|
import { INSERT_NEW_TIME_TICKET } from "../../graphql/timetickets.queries";
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import TechClockInComponent from "./tech-job-clock-in-form.component";
|
|
||||||
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
|
|
||||||
import moment from "moment";
|
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
|
import {
|
||||||
|
selectBodyshop,
|
||||||
|
selectCurrentUser,
|
||||||
|
} from "../../redux/user/user.selectors";
|
||||||
|
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
|
||||||
|
import TechClockInComponent from "./tech-job-clock-in-form.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
technician: selectTechnician,
|
technician: selectTechnician,
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setTimeTicketContext: (context) =>
|
setTimeTicketContext: (context) =>
|
||||||
@@ -25,9 +30,10 @@ export function TechClockInContainer({
|
|||||||
setTimeTicketContext,
|
setTimeTicketContext,
|
||||||
technician,
|
technician,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
|
currentUser,
|
||||||
}) {
|
}) {
|
||||||
console.log(
|
console.log(
|
||||||
"🚀 ~ file: tech-job-clock-in-form.container.jsx:29 ~ technician:",
|
"🚀 ~ file: tech-job-clock-in-form.container.jsx:30 ~ technician:",
|
||||||
technician
|
technician
|
||||||
);
|
);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
@@ -44,14 +50,20 @@ export function TechClockInContainer({
|
|||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const theTime = (await axios.post("/utils/time")).data;
|
const theTime = (await axios.post("/utils/time")).data;
|
||||||
|
|
||||||
const result = await insertTimeTicket({
|
const result = await insertTimeTicket({
|
||||||
variables: {
|
variables: {
|
||||||
timeTicketInput: [
|
timeTicketInput: [
|
||||||
{
|
{
|
||||||
bodyshopid: bodyshop.id,
|
bodyshopid: bodyshop.id,
|
||||||
employeeid: technician.id,
|
employeeid: technician.id,
|
||||||
date: moment(theTime).format("YYYY-MM-DD"),
|
date:
|
||||||
|
typeof bodyshop.timezone === "string"
|
||||||
|
? momenttz.tz(theTime, bodyshop.timezone).format("YYYY-MM-DD")
|
||||||
|
: typeof bodyshop.timezone === "number"
|
||||||
|
? moment(theTime)
|
||||||
|
.format("YYYY-MM-DD")
|
||||||
|
.utcOffset(bodyshop.timezone)
|
||||||
|
: moment(theTime).format("YYYY-MM-DD"),
|
||||||
clockon: moment(theTime),
|
clockon: moment(theTime),
|
||||||
jobid: values.jobid,
|
jobid: values.jobid,
|
||||||
cost_center: values.cost_center,
|
cost_center: values.cost_center,
|
||||||
@@ -66,6 +78,12 @@ export function TechClockInContainer({
|
|||||||
values.cost_center
|
values.cost_center
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
created_by: currentUser.email.concat(
|
||||||
|
" | ",
|
||||||
|
technician.employee_number
|
||||||
|
.concat(" ", technician.first_name, " ", technician.last_name)
|
||||||
|
.trim()
|
||||||
|
),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -100,13 +118,24 @@ export function TechClockInContainer({
|
|||||||
employeeid: technician.id,
|
employeeid: technician.id,
|
||||||
flat_rate: emps.flat_rate,
|
flat_rate: emps.flat_rate,
|
||||||
},
|
},
|
||||||
|
created_by: currentUser.email.concat(
|
||||||
|
" | ",
|
||||||
|
technician.employee_number
|
||||||
|
.concat(
|
||||||
|
" ",
|
||||||
|
technician.first_name,
|
||||||
|
" ",
|
||||||
|
technician.last_name
|
||||||
|
)
|
||||||
|
.trim()
|
||||||
|
),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("timetickets.actions.enter")}
|
{t("timetickets.actions.enter")}
|
||||||
</Button>
|
</Button>
|
||||||
<TechJobPrintTickets />
|
<TechJobPrintTickets attendacePrint={false} />
|
||||||
<Button
|
<Button
|
||||||
type="primary"
|
type="primary"
|
||||||
onClick={() => form.submit()}
|
onClick={() => form.submit()}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ import {
|
|||||||
Col,
|
Col,
|
||||||
Form,
|
Form,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
notification,
|
|
||||||
Popover,
|
Popover,
|
||||||
Row,
|
Row,
|
||||||
Select,
|
Select,
|
||||||
|
notification,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
@@ -16,13 +16,14 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
|
||||||
|
import { UPDATE_JOB_STATUS } from "../../graphql/jobs.queries";
|
||||||
import { UPDATE_TIME_TICKET } from "../../graphql/timetickets.queries";
|
import { UPDATE_TIME_TICKET } from "../../graphql/timetickets.queries";
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
|
||||||
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
|
import TechJobClockoutDelete from "../tech-job-clock-out-delete/tech-job-clock-out-delete.component";
|
||||||
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
|
import { LaborAllocationContainer } from "../time-ticket-modal/time-ticket-modal.component";
|
||||||
import { GET_LINE_TICKET_BY_PK } from "../../graphql/jobs-lines.queries";
|
|
||||||
import { CalculateAllocationsTotals } from "../labor-allocations-table/labor-allocations-table.utility";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -40,6 +41,7 @@ export function TechClockOffButton({
|
|||||||
}) {
|
}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
|
const [updateTimeticket] = useMutation(UPDATE_TIME_TICKET);
|
||||||
|
const [updateJobStatus] = useMutation(UPDATE_JOB_STATUS);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const { queryLoading, data: lineTicketData } = useQuery(
|
const { queryLoading, data: lineTicketData } = useQuery(
|
||||||
GET_LINE_TICKET_BY_PK,
|
GET_LINE_TICKET_BY_PK,
|
||||||
@@ -59,7 +61,8 @@ export function TechClockOffButton({
|
|||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
logImEXEvent("tech_clock_out_job");
|
logImEXEvent("tech_clock_out_job");
|
||||||
|
const status = values.status;
|
||||||
|
delete values.status;
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const result = await updateTimeticket({
|
const result = await updateTimeticket({
|
||||||
variables: {
|
variables: {
|
||||||
@@ -98,6 +101,26 @@ export function TechClockOffButton({
|
|||||||
message: t("timetickets.successes.clockedout"),
|
message: t("timetickets.successes.clockedout"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (!isShiftTicket) {
|
||||||
|
const job_update_result = await updateJobStatus({
|
||||||
|
variables: {
|
||||||
|
jobId: jobId,
|
||||||
|
status: status,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!!job_update_result.errors) {
|
||||||
|
notification["error"]({
|
||||||
|
message: t("jobs.errors.updating", {
|
||||||
|
message: JSON.stringify(result.errors),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification["success"]({
|
||||||
|
message: t("jobs.successes.updated"),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
if (completedCallback) completedCallback();
|
if (completedCallback) completedCallback();
|
||||||
};
|
};
|
||||||
@@ -195,7 +218,6 @@ export function TechClockOffButton({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name="cost_center"
|
name="cost_center"
|
||||||
label={t("timetickets.fields.cost_center")}
|
label={t("timetickets.fields.cost_center")}
|
||||||
@@ -228,6 +250,29 @@ export function TechClockOffButton({
|
|||||||
</Select>
|
</Select>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
{isShiftTicket ? (
|
||||||
|
<div></div>
|
||||||
|
) : (
|
||||||
|
<Form.Item
|
||||||
|
name="status"
|
||||||
|
label={t("jobs.fields.status")}
|
||||||
|
initialValue={
|
||||||
|
lineTicketData && lineTicketData.jobs_by_pk.status
|
||||||
|
}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select>
|
||||||
|
{bodyshop.md_ro_statuses.production_statuses.map((item) => (
|
||||||
|
<Select.Option key={item}></Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
<Button type="primary" htmlType="submit" loading={loading}>
|
<Button type="primary" htmlType="submit" loading={loading}>
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Button, Card, DatePicker, Form, Popover, Space } from "antd";
|
import { Button, Card, DatePicker, Form, Popover, Radio, Space } from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -21,12 +21,13 @@ export default connect(
|
|||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(TechJobPrintTickets);
|
)(TechJobPrintTickets);
|
||||||
|
|
||||||
export function TechJobPrintTickets({ technician, event }) {
|
export function TechJobPrintTickets({ technician, event, attendacePrint }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [visibility, setVisibility] = useState(false);
|
const [visibility, setVisibility] = useState(false);
|
||||||
|
const Templates = TemplateList("report_center");
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visibility && event) {
|
if (visibility && event) {
|
||||||
@@ -44,7 +45,10 @@ export function TechJobPrintTickets({ technician, event }) {
|
|||||||
try {
|
try {
|
||||||
await GenerateDocument(
|
await GenerateDocument(
|
||||||
{
|
{
|
||||||
name: TemplateList().timetickets_employee.key,
|
name:
|
||||||
|
attendacePrint === true
|
||||||
|
? Templates.attendance_employee.key
|
||||||
|
: Templates.timetickets_employee.key,
|
||||||
variables: {
|
variables: {
|
||||||
...(start
|
...(start
|
||||||
? { start: moment(start).startOf("day").format("YYYY-MM-DD") }
|
? { start: moment(start).startOf("day").format("YYYY-MM-DD") }
|
||||||
@@ -60,9 +64,12 @@ export function TechJobPrintTickets({ technician, event }) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
to: technician.email,
|
to: technician.email,
|
||||||
subject: TemplateList().timetickets_employee.subject,
|
subject:
|
||||||
|
attendacePrint === true
|
||||||
|
? Templates.attendance_employee.subject
|
||||||
|
: Templates.timetickets_employee.subject,
|
||||||
},
|
},
|
||||||
"p"
|
values.sendby // === "email" ? "e" : "p"
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@@ -92,10 +99,25 @@ export function TechJobPrintTickets({ technician, event }) {
|
|||||||
format={"MM/DD/YYYY"}
|
format={"MM/DD/YYYY"}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item dependencies={["dates"]}>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("general.labels.sendby")}
|
||||||
|
name="sendby"
|
||||||
|
initialValue="p"
|
||||||
|
>
|
||||||
|
<Radio.Group>
|
||||||
|
<Radio value="e">{t("general.labels.email")}</Radio>
|
||||||
|
<Radio value="p">{t("general.labels.print")}</Radio>
|
||||||
|
</Radio.Group>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
<Button type="primary" onClick={() => form.submit()}>
|
<Button type="primary" onClick={() => form.submit()}>
|
||||||
{t("general.actions.print")}
|
{t("reportcenter.actions.generate")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -118,7 +140,7 @@ export function TechJobPrintTickets({ technician, event }) {
|
|||||||
return (
|
return (
|
||||||
<Popover content={overlay} visible={visibility}>
|
<Popover content={overlay} visible={visibility}>
|
||||||
<Button loading={loading} onClick={handleClick}>
|
<Button loading={loading} onClick={handleClick}>
|
||||||
{t("general.actions.print")}
|
{t("general.labels.reports")}
|
||||||
</Button>
|
</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import {
|
import {
|
||||||
selectAuthLevel,
|
selectAuthLevel,
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
|
||||||
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
|
import { onlyUnique } from "../../utils/arrayHelper";
|
||||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||||
import RbacWrapper, {
|
import RbacWrapper, {
|
||||||
HasRbacAccess,
|
HasRbacAccess,
|
||||||
@@ -20,6 +21,7 @@ import TimeTicketEnterButton from "../time-ticket-enter-button/time-ticket-enter
|
|||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
authLevel: selectAuthLevel,
|
authLevel: selectAuthLevel,
|
||||||
|
currentUser: selectCurrentUser,
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
@@ -29,6 +31,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(TimeTicketList);
|
|||||||
export function TimeTicketList({
|
export function TimeTicketList({
|
||||||
bodyshop,
|
bodyshop,
|
||||||
authLevel,
|
authLevel,
|
||||||
|
currentUser,
|
||||||
disabled,
|
disabled,
|
||||||
loading,
|
loading,
|
||||||
timetickets,
|
timetickets,
|
||||||
@@ -193,7 +196,15 @@ export function TimeTicketList({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t("timetickets.fields.created_by"),
|
||||||
|
dataIndex: "created_by",
|
||||||
|
key: "created_by",
|
||||||
|
sorter: (a, b) => alphaSort(a.created_by, b.created_by),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "created_by" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => record.created_by,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t("general.labels.actions"),
|
title: t("general.labels.actions"),
|
||||||
dataIndex: "actions",
|
dataIndex: "actions",
|
||||||
@@ -254,7 +265,12 @@ export function TimeTicketList({
|
|||||||
(techConsole ? null : (
|
(techConsole ? null : (
|
||||||
<TimeTicketEnterButton
|
<TimeTicketEnterButton
|
||||||
actions={{ refetch }}
|
actions={{ refetch }}
|
||||||
context={{ jobId: jobId }}
|
context={{
|
||||||
|
jobId: jobId,
|
||||||
|
created_by: currentUser.displayName
|
||||||
|
? currentUser.email.concat(" | ", currentUser.displayName)
|
||||||
|
: currentUser.email,
|
||||||
|
}}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{t("timetickets.actions.enter")}
|
{t("timetickets.actions.enter")}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useMutation, useQuery } from "@apollo/client";
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
import { Button, Form, Modal, notification, PageHeader, Space } from "antd";
|
import { Button, Form, Modal, PageHeader, Space, notification } from "antd";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -77,6 +77,7 @@ export function TimeTicketModalContainer({
|
|||||||
)[0].rate
|
)[0].rate
|
||||||
: null,
|
: null,
|
||||||
bodyshopid: bodyshop.id,
|
bodyshopid: bodyshop.id,
|
||||||
|
created_by: timeTicketModal.context.created_by,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -4,48 +4,67 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
import DataLabel from "../data-label/data-label.component";
|
import DataLabel from "../data-label/data-label.component";
|
||||||
import TechClockOffButton from "../tech-job-clock-out-button/tech-job-clock-out-button.component";
|
import TechClockOffButton from "../tech-job-clock-out-button/tech-job-clock-out-button.component";
|
||||||
|
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
|
||||||
|
|
||||||
export default function TimeTicketShiftActive({ timetickets, refetch }) {
|
export default function TimeTicketShiftActive({
|
||||||
|
timetickets,
|
||||||
|
refetch,
|
||||||
|
isTechConsole,
|
||||||
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{timetickets.length > 0 ? (
|
{timetickets.length > 0 ? (
|
||||||
<div>
|
<div
|
||||||
<Typography.Title level={2}>
|
style={{
|
||||||
{t("timetickets.labels.shiftalreadyclockedon")}
|
display: "flex",
|
||||||
</Typography.Title>
|
justifyContent: "space-between",
|
||||||
<List
|
flexDirection: "column",
|
||||||
grid={{
|
height: "100%",
|
||||||
gutter: 32,
|
}}
|
||||||
xs: 1,
|
>
|
||||||
sm: 2,
|
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||||
md: 3,
|
<Typography.Title level={2}>
|
||||||
lg: 4,
|
{t("timetickets.labels.shiftalreadyclockedon")}
|
||||||
xl: 5,
|
</Typography.Title>
|
||||||
xxl: 6,
|
{isTechConsole ? (
|
||||||
}}
|
<TechJobPrintTickets attendacePrint={true} />
|
||||||
dataSource={timetickets || []}
|
) : null}
|
||||||
renderItem={(ticket) => (
|
</div>
|
||||||
<List.Item>
|
<div style={{ flexGrow: 1 }}>
|
||||||
<Card
|
<List
|
||||||
title={t(ticket.memo)}
|
grid={{
|
||||||
actions={[
|
gutter: 32,
|
||||||
<TechClockOffButton
|
xs: 1,
|
||||||
jobId={ticket.jobid}
|
sm: 2,
|
||||||
timeTicketId={ticket.id}
|
md: 3,
|
||||||
completedCallback={refetch}
|
lg: 4,
|
||||||
isShiftTicket
|
xl: 5,
|
||||||
/>,
|
xxl: 6,
|
||||||
]}
|
}}
|
||||||
>
|
dataSource={timetickets || []}
|
||||||
<DataLabel label={t("timetickets.fields.clockon")}>
|
renderItem={(ticket) => (
|
||||||
<DateTimeFormatter>{ticket.clockon}</DateTimeFormatter>
|
<List.Item>
|
||||||
</DataLabel>
|
<Card
|
||||||
</Card>
|
title={t(ticket.memo)}
|
||||||
</List.Item>
|
actions={[
|
||||||
)}
|
<TechClockOffButton
|
||||||
></List>
|
jobId={ticket.jobid}
|
||||||
|
timeTicketId={ticket.id}
|
||||||
|
completedCallback={refetch}
|
||||||
|
isShiftTicket
|
||||||
|
/>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<DataLabel label={t("timetickets.fields.clockon")}>
|
||||||
|
<DateTimeFormatter>{ticket.clockon}</DateTimeFormatter>
|
||||||
|
</DataLabel>
|
||||||
|
</Card>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
></List>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Form, notification } from "antd";
|
import { Button, Form, Space, notification } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import momenttz from "moment-timezone";
|
||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -12,6 +13,7 @@ import {
|
|||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
selectCurrentUser,
|
selectCurrentUser,
|
||||||
} from "../../redux/user/user.selectors";
|
} from "../../redux/user/user.selectors";
|
||||||
|
import TechJobPrintTickets from "../tech-job-print-tickets/tech-job-print-tickets.component";
|
||||||
import TimeTicektShiftComponent from "./time-ticket-shift-form.component";
|
import TimeTicektShiftComponent from "./time-ticket-shift-form.component";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
@@ -29,6 +31,10 @@ export function TimeTicektShiftContainer({
|
|||||||
isTechConsole,
|
isTechConsole,
|
||||||
checkIfAlreadyClocked,
|
checkIfAlreadyClocked,
|
||||||
}) {
|
}) {
|
||||||
|
console.log(
|
||||||
|
"🚀 ~ file: time-ticket-shift-form.container.jsx:28 ~ technician:",
|
||||||
|
technician
|
||||||
|
);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET);
|
const [insertTimeTicket] = useMutation(INSERT_NEW_TIME_TICKET);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -63,8 +69,30 @@ export function TimeTicektShiftContainer({
|
|||||||
employeeid: isTechConsole ? technician.id : employeeId,
|
employeeid: isTechConsole ? technician.id : employeeId,
|
||||||
cost_center: "timetickets.labels.shift",
|
cost_center: "timetickets.labels.shift",
|
||||||
clockon: theTime,
|
clockon: theTime,
|
||||||
date: theTime,
|
date:
|
||||||
|
typeof bodyshop.timezone === "string"
|
||||||
|
? momenttz.tz(theTime, bodyshop.timezone).format("YYYY-MM-DD")
|
||||||
|
: typeof bodyshop.timezone === "number"
|
||||||
|
? moment(theTime)
|
||||||
|
.utcOffset(bodyshop.timezone)
|
||||||
|
.format("YYYY-MM-DD")
|
||||||
|
: moment(theTime).format("YYYY-MM-DD"),
|
||||||
memo: values.memo,
|
memo: values.memo,
|
||||||
|
created_by: isTechConsole
|
||||||
|
? currentUser.email.concat(
|
||||||
|
" | ",
|
||||||
|
technician.employee_number
|
||||||
|
.concat(
|
||||||
|
" ",
|
||||||
|
technician.first_name,
|
||||||
|
" ",
|
||||||
|
technician.last_name
|
||||||
|
)
|
||||||
|
.trim()
|
||||||
|
)
|
||||||
|
: currentUser.displayName
|
||||||
|
? currentUser.email.concat(" | ", currentUser.displayName)
|
||||||
|
: currentUser.email,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -98,9 +126,14 @@ export function TimeTicektShiftContainer({
|
|||||||
initialValues={{ cost_center: t("timetickets.labels.shift") }}
|
initialValues={{ cost_center: t("timetickets.labels.shift") }}
|
||||||
>
|
>
|
||||||
<TimeTicektShiftComponent form={form} />
|
<TimeTicektShiftComponent form={form} />
|
||||||
<Button htmlType="submit" loading={loading}>
|
<Space wrap>
|
||||||
{t("timetickets.actions.clockin")}
|
<Button htmlType="submit" loading={loading} type="primary">
|
||||||
</Button>
|
{t("timetickets.actions.clockin")}
|
||||||
|
</Button>
|
||||||
|
{isTechConsole === true ? (
|
||||||
|
<TechJobPrintTickets attendacePrint={true} />
|
||||||
|
) : null}
|
||||||
|
</Space>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ export function TimeTicketShiftContainer({
|
|||||||
<TimeTicketShiftActive
|
<TimeTicketShiftActive
|
||||||
timetickets={data ? data.timetickets : []}
|
timetickets={data ? data.timetickets : []}
|
||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
|
isTechConsole={isTechConsole}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<TimeTicketShiftFormContainer
|
<TimeTicketShiftFormContainer
|
||||||
|
|||||||
@@ -6,8 +6,9 @@ import { Link } from "react-router-dom";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import VehicleDetailUpdateJobsComponent from "../vehicle-detail-update-jobs/vehicle-detail-update-jobs.component";
|
import { alphaSort, statusSort } from "../../utils/sorters";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
import VehicleDetailUpdateJobsComponent from "../vehicle-detail-update-jobs/vehicle-detail-update-jobs.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -16,6 +17,14 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
|
export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [selectedJobs, setSelectedJobs] = useState([]);
|
const [selectedJobs, setSelectedJobs] = useState([]);
|
||||||
|
const [state, setState] = useState({
|
||||||
|
sortedInfo: {},
|
||||||
|
filteredInfo: { text: "" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||||
|
};
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -28,6 +37,9 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
|
|||||||
{record.ro_number || t("general.labels.na")}
|
{record.ro_number || t("general.labels.na")}
|
||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
|
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.owner"),
|
title: t("jobs.fields.owner"),
|
||||||
@@ -43,11 +55,17 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
|
|||||||
title: t("jobs.fields.clm_no"),
|
title: t("jobs.fields.clm_no"),
|
||||||
dataIndex: "clm_no",
|
dataIndex: "clm_no",
|
||||||
key: "clm_no",
|
key: "clm_no",
|
||||||
|
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.status"),
|
title: t("jobs.fields.status"),
|
||||||
dataIndex: "status",
|
dataIndex: "status",
|
||||||
key: "status",
|
key: "status",
|
||||||
|
sorter: (a, b) => statusSort(a.status, b.status, bodyshop.md_ro_statuses.statuses),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -57,6 +75,9 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
|
|||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
|
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
|
||||||
),
|
),
|
||||||
|
sorter: (a, b) => a.clm_total - b.clm_total,
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -76,6 +97,7 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
scroll={{ x: true }}
|
scroll={{ x: true }}
|
||||||
dataSource={vehicle.jobs}
|
dataSource={vehicle.jobs}
|
||||||
|
onChange={handleTableChange}
|
||||||
rowSelection={{
|
rowSelection={{
|
||||||
onSelect: (record, selected, selectedRows) => {
|
onSelect: (record, selected, selectedRows) => {
|
||||||
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
|
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ export const INSERT_NEW_BILL = gql`
|
|||||||
insert_bills(objects: $bill) {
|
insert_bills(objects: $bill) {
|
||||||
returning {
|
returning {
|
||||||
id
|
id
|
||||||
|
invoice_number
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export const GET_LINE_TICKET_BY_PK = gql`
|
|||||||
id
|
id
|
||||||
lbr_adjustments
|
lbr_adjustments
|
||||||
converted
|
converted
|
||||||
|
status
|
||||||
}
|
}
|
||||||
joblines(where: { jobid: { _eq: $id }, removed: { _eq: false } }) {
|
joblines(where: { jobid: { _eq: $id }, removed: { _eq: false } }) {
|
||||||
id
|
id
|
||||||
@@ -56,6 +57,7 @@ export const GET_LINE_TICKET_BY_PK = gql`
|
|||||||
actualhrs
|
actualhrs
|
||||||
ciecacode
|
ciecacode
|
||||||
cost_center
|
cost_center
|
||||||
|
created_by
|
||||||
date
|
date
|
||||||
id
|
id
|
||||||
jobid
|
jobid
|
||||||
|
|||||||
@@ -574,7 +574,6 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
est_co_nm
|
est_co_nm
|
||||||
est_ct_fn
|
est_ct_fn
|
||||||
est_ct_ln
|
est_ct_ln
|
||||||
|
|
||||||
est_ph1
|
est_ph1
|
||||||
est_ea
|
est_ea
|
||||||
selling_dealer
|
selling_dealer
|
||||||
@@ -682,6 +681,7 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
date_rentalresp
|
date_rentalresp
|
||||||
date_exported
|
date_exported
|
||||||
date_repairstarted
|
date_repairstarted
|
||||||
|
date_void
|
||||||
status
|
status
|
||||||
owner_owing
|
owner_owing
|
||||||
tax_registration_number
|
tax_registration_number
|
||||||
@@ -745,8 +745,8 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
jobid
|
jobid
|
||||||
amount
|
amount
|
||||||
payer
|
payer
|
||||||
|
paymentnum
|
||||||
created_at
|
created_at
|
||||||
stripeid
|
|
||||||
transactionid
|
transactionid
|
||||||
memo
|
memo
|
||||||
date
|
date
|
||||||
@@ -1078,6 +1078,7 @@ export const UPDATE_JOB = gql`
|
|||||||
scheduled_completion
|
scheduled_completion
|
||||||
actual_in
|
actual_in
|
||||||
date_repairstarted
|
date_repairstarted
|
||||||
|
date_void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1125,6 +1126,7 @@ export const VOID_JOB = gql`
|
|||||||
update_jobs_by_pk(_set: $job, pk_columns: { id: $jobId }) {
|
update_jobs_by_pk(_set: $job, pk_columns: { id: $jobId }) {
|
||||||
id
|
id
|
||||||
date_exported
|
date_exported
|
||||||
|
date_void
|
||||||
status
|
status
|
||||||
alt_transport
|
alt_transport
|
||||||
ro_number
|
ro_number
|
||||||
@@ -1219,10 +1221,10 @@ export const ACTIVE_JOBS_FOR_AUTOCOMPLETE = gql`
|
|||||||
query ACTIVE_JOBS_FOR_AUTOCOMPLETE($statuses: [String!]!) {
|
query ACTIVE_JOBS_FOR_AUTOCOMPLETE($statuses: [String!]!) {
|
||||||
jobs(where: { status: { _in: $statuses } }) {
|
jobs(where: { status: { _in: $statuses } }) {
|
||||||
id
|
id
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
ro_number
|
ro_number
|
||||||
|
|
||||||
vehicleid
|
vehicleid
|
||||||
v_make_desc
|
v_make_desc
|
||||||
v_model_desc
|
v_model_desc
|
||||||
@@ -1250,6 +1252,7 @@ export const SEARCH_JOBS_FOR_AUTOCOMPLETE = gql`
|
|||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
ro_number
|
ro_number
|
||||||
@@ -1266,6 +1269,7 @@ export const SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE = gql`
|
|||||||
query SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE($id: uuid!) {
|
query SEARCH_JOBS_BY_ID_FOR_AUTOCOMPLETE($id: uuid!) {
|
||||||
jobs_by_pk(id: $id) {
|
jobs_by_pk(id: $id) {
|
||||||
id
|
id
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
ro_number
|
ro_number
|
||||||
@@ -1284,6 +1288,7 @@ export const SEARCH_FOR_JOBS = gql`
|
|||||||
search_jobs(args: { search: $search }, limit: 25) {
|
search_jobs(args: { search: $search }, limit: 25) {
|
||||||
id
|
id
|
||||||
ro_number
|
ro_number
|
||||||
|
ownr_co_nm
|
||||||
ownr_fn
|
ownr_fn
|
||||||
ownr_ln
|
ownr_ln
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export const QUERY_OWNER_BY_ID = gql`
|
|||||||
preferred_contact
|
preferred_contact
|
||||||
note
|
note
|
||||||
tax_number
|
tax_number
|
||||||
jobs {
|
jobs(order_by: { date_open: desc }) {
|
||||||
id
|
id
|
||||||
ro_number
|
ro_number
|
||||||
clm_no
|
clm_no
|
||||||
|
|||||||
53
client/src/graphql/payment_response.queries.js
Normal file
53
client/src/graphql/payment_response.queries.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { gql } from "@apollo/client";
|
||||||
|
|
||||||
|
export const INSERT_PAYMENT_RESPONSE = gql`
|
||||||
|
mutation INSERT_PAYMENT_RESPONSE(
|
||||||
|
$paymentResponse: [payment_response_insert_input!]!
|
||||||
|
) {
|
||||||
|
insert_payment_response(objects: $paymentResponse) {
|
||||||
|
returning {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const QUERY_PAYMENT_RESPONSE_BY_PAYMENT_ID = gql`
|
||||||
|
query QUERY_PAYMENT_RESPONSE_BY_PK($paymentid: uuid!) {
|
||||||
|
payment_response(where: { paymentid: { _eq: $paymentid } }) {
|
||||||
|
id
|
||||||
|
jobid
|
||||||
|
bodyshopid
|
||||||
|
paymentid
|
||||||
|
amount
|
||||||
|
declinereason
|
||||||
|
ext_paymentid
|
||||||
|
successful
|
||||||
|
response
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const QUERY_RO_AND_OWNER_BY_JOB_PKS = gql`
|
||||||
|
query QUERY_RO_AND_OWNER_BY_JOB_PKS($jobids: [uuid!]!) {
|
||||||
|
jobs(where: { id: { _in: $jobids } }) {
|
||||||
|
ro_number
|
||||||
|
ownr_fn
|
||||||
|
ownr_ln
|
||||||
|
ownr_ea
|
||||||
|
ownr_zip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const GET_REFUNDABLE_AMOUNT_BY_JOBID = gql`
|
||||||
|
query GET_REFUNDABLE_AMOUNT_BY_JOBID($jobid: uuid!) {
|
||||||
|
payment_response_aggregate(where: { jobid: { _eq: $jobid } }) {
|
||||||
|
aggregate {
|
||||||
|
sum {
|
||||||
|
amount
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -5,6 +5,15 @@ export const INSERT_NEW_PAYMENT = gql`
|
|||||||
insert_payments(objects: $paymentInput) {
|
insert_payments(objects: $paymentInput) {
|
||||||
returning {
|
returning {
|
||||||
id
|
id
|
||||||
|
jobid
|
||||||
|
amount
|
||||||
|
payer
|
||||||
|
created_at
|
||||||
|
transactionid
|
||||||
|
memo
|
||||||
|
date
|
||||||
|
type
|
||||||
|
exportedat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export const QUERY_TIME_TICKETS_IN_RANGE = gql`
|
|||||||
clockon
|
clockon
|
||||||
cost_center
|
cost_center
|
||||||
created_at
|
created_at
|
||||||
|
created_by
|
||||||
date
|
date
|
||||||
id
|
id
|
||||||
rate
|
rate
|
||||||
@@ -80,6 +81,7 @@ export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
|
|||||||
clockon
|
clockon
|
||||||
cost_center
|
cost_center
|
||||||
created_at
|
created_at
|
||||||
|
created_by
|
||||||
date
|
date
|
||||||
id
|
id
|
||||||
rate
|
rate
|
||||||
@@ -112,6 +114,7 @@ export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
|
|||||||
clockon
|
clockon
|
||||||
cost_center
|
cost_center
|
||||||
created_at
|
created_at
|
||||||
|
created_by
|
||||||
date
|
date
|
||||||
id
|
id
|
||||||
rate
|
rate
|
||||||
@@ -151,6 +154,7 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
|
|||||||
clockon
|
clockon
|
||||||
cost_center
|
cost_center
|
||||||
created_at
|
created_at
|
||||||
|
created_by
|
||||||
date
|
date
|
||||||
id
|
id
|
||||||
rate
|
rate
|
||||||
@@ -181,6 +185,7 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
|
|||||||
clockon
|
clockon
|
||||||
cost_center
|
cost_center
|
||||||
created_at
|
created_at
|
||||||
|
created_by
|
||||||
date
|
date
|
||||||
id
|
id
|
||||||
rate
|
rate
|
||||||
@@ -210,6 +215,7 @@ export const INSERT_NEW_TIME_TICKET = gql`
|
|||||||
insert_timetickets(objects: $timeTicketInput) {
|
insert_timetickets(objects: $timeTicketInput) {
|
||||||
returning {
|
returning {
|
||||||
id
|
id
|
||||||
|
created_by
|
||||||
clockon
|
clockon
|
||||||
clockoff
|
clockoff
|
||||||
employeeid
|
employeeid
|
||||||
|
|||||||
@@ -28,11 +28,10 @@ export const QUERY_VEHICLE_BY_ID = gql`
|
|||||||
updated_at
|
updated_at
|
||||||
trim_color
|
trim_color
|
||||||
notes
|
notes
|
||||||
jobs {
|
jobs(order_by: { date_open: desc }) {
|
||||||
id
|
id
|
||||||
ro_number
|
ro_number
|
||||||
ownr_fn
|
ownr_fn
|
||||||
|
|
||||||
ownr_ln
|
ownr_ln
|
||||||
owner {
|
owner {
|
||||||
id
|
id
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import queryString from "query-string";
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useEffect, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { useHistory, useLocation, Link } from "react-router-dom";
|
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import SocketIO from "socket.io-client";
|
import SocketIO from "socket.io-client";
|
||||||
import AlertComponent from "../../components/alert/alert.component";
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
@@ -22,6 +22,7 @@ import DmsCustomerSelector from "../../components/dms-customer-selector/dms-cust
|
|||||||
import DmsLogEvents from "../../components/dms-log-events/dms-log-events.component";
|
import DmsLogEvents from "../../components/dms-log-events/dms-log-events.component";
|
||||||
import DmsPostForm from "../../components/dms-post-form/dms-post-form.component";
|
import DmsPostForm from "../../components/dms-post-form/dms-post-form.component";
|
||||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||||
import { auth } from "../../firebase/firebase.utils";
|
import { auth } from "../../firebase/firebase.utils";
|
||||||
import { QUERY_JOB_EXPORT_DMS } from "../../graphql/jobs.queries";
|
import { QUERY_JOB_EXPORT_DMS } from "../../graphql/jobs.queries";
|
||||||
import {
|
import {
|
||||||
@@ -29,7 +30,6 @@ import {
|
|||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -46,6 +46,7 @@ export const socket = SocketIO(
|
|||||||
process.env.NODE_ENV === "production"
|
process.env.NODE_ENV === "production"
|
||||||
? process.env.REACT_APP_AXIOS_BASE_API_URL
|
? process.env.REACT_APP_AXIOS_BASE_API_URL
|
||||||
: window.location.origin,
|
: window.location.origin,
|
||||||
|
// "http://localhost:4000", // for dev testing,
|
||||||
{
|
{
|
||||||
path: "/ws",
|
path: "/ws",
|
||||||
withCredentials: true,
|
withCredentials: true,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
notification,
|
|
||||||
PageHeader,
|
PageHeader,
|
||||||
Popconfirm,
|
Popconfirm,
|
||||||
Row,
|
Row,
|
||||||
@@ -17,12 +16,14 @@ import {
|
|||||||
Statistic,
|
Statistic,
|
||||||
Switch,
|
Switch,
|
||||||
Typography,
|
Typography,
|
||||||
|
notification,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
//import { useHistory } from "react-router-dom";
|
//import { useHistory } from "react-router-dom";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
|
import Dinero from "dinero.js";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
@@ -37,7 +38,6 @@ import { generateJobLinesUpdatesForInvoicing } from "../../graphql/jobs-lines.qu
|
|||||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import Dinero from "dinero.js";
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
@@ -55,6 +55,11 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
|||||||
{},
|
{},
|
||||||
bodyshop && bodyshop.imexshopid
|
bodyshop && bodyshop.imexshopid
|
||||||
);
|
);
|
||||||
|
const { ClosingPeriod } = useTreatments(
|
||||||
|
["ClosingPeriod"],
|
||||||
|
{},
|
||||||
|
bodyshop && bodyshop.imexshopid
|
||||||
|
);
|
||||||
|
|
||||||
const handleFinish = async ({ removefromproduction, ...values }) => {
|
const handleFinish = async ({ removefromproduction, ...values }) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
@@ -254,12 +259,40 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
|||||||
if (!value || moment(value).isSameOrAfter(moment(), "day")) {
|
if (!value || moment(value).isSameOrAfter(moment(), "day")) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
new Error(t("jobs.labels.dms.invoicedatefuture"))
|
new Error(t("jobs.labels.dms.invoicedatefuture"))
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
({ getFieldValue }) => ({
|
||||||
|
validator(_, value) {
|
||||||
|
if (
|
||||||
|
ClosingPeriod.treatment === "on" &&
|
||||||
|
bodyshop.accountingconfig.ClosingPeriod
|
||||||
|
) {
|
||||||
|
if (
|
||||||
|
moment(value).isSameOrAfter(
|
||||||
|
moment(
|
||||||
|
bodyshop.accountingconfig.ClosingPeriod[0]
|
||||||
|
).startOf("day")
|
||||||
|
) &&
|
||||||
|
moment(value).isSameOrBefore(
|
||||||
|
moment(
|
||||||
|
bodyshop.accountingconfig.ClosingPeriod[1]
|
||||||
|
).endOf("day")
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return Promise.resolve();
|
||||||
|
} else {
|
||||||
|
return Promise.reject(
|
||||||
|
new Error(t("jobs.labels.closingperiod"))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}),
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<DateTimePicker
|
<DateTimePicker
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com
|
|||||||
import PartnerPingComponent from "../../components/partner-ping/partner-ping.component";
|
import PartnerPingComponent from "../../components/partner-ping/partner-ping.component";
|
||||||
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
|
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
|
||||||
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
|
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
|
||||||
import TestComponent from "../../components/_test/test.component";
|
import TestComponent from "../../components/_test/test.page";
|
||||||
import { requestForToken } from "../../firebase/firebase.utils";
|
import { requestForToken } from "../../firebase/firebase.utils";
|
||||||
import {
|
import {
|
||||||
selectBodyshop,
|
selectBodyshop,
|
||||||
@@ -32,6 +32,10 @@ const ManageRootPage = lazy(() =>
|
|||||||
);
|
);
|
||||||
const JobsPage = lazy(() => import("../jobs/jobs.page"));
|
const JobsPage = lazy(() => import("../jobs/jobs.page"));
|
||||||
|
|
||||||
|
const CardPaymentModalContainer = lazy(() =>
|
||||||
|
import("../../components/card-payment-modal/card-payment-modal.container.")
|
||||||
|
);
|
||||||
|
|
||||||
const JobsDetailPage = lazy(() =>
|
const JobsDetailPage = lazy(() =>
|
||||||
import("../jobs-detail/jobs-detail.page.container")
|
import("../jobs-detail/jobs-detail.page.container")
|
||||||
);
|
);
|
||||||
@@ -196,6 +200,8 @@ export function Manage({ match, conflict, bodyshop }) {
|
|||||||
>
|
>
|
||||||
<PaymentModalContainer />
|
<PaymentModalContainer />
|
||||||
|
|
||||||
|
<CardPaymentModalContainer />
|
||||||
|
|
||||||
<BreadCrumbs />
|
<BreadCrumbs />
|
||||||
<BillEnterModalContainer />
|
<BillEnterModalContainer />
|
||||||
<JobCostingModal />
|
<JobCostingModal />
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
import { BackTop, Layout } from "antd";
|
import { BackTop, Layout } from "antd";
|
||||||
import React, { lazy, Suspense, useEffect } from "react";
|
import React, { Suspense, lazy, useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Redirect, Route, Switch } from "react-router-dom";
|
import { Redirect, Route, Switch } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
|
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
|
||||||
|
|
||||||
|
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
||||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||||
import TechHeader from "../../components/tech-header/tech-header.component";
|
import TechHeader from "../../components/tech-header/tech-header.component";
|
||||||
import TechSider from "../../components/tech-sider/tech-sider.component";
|
import TechSider from "../../components/tech-sider/tech-sider.component";
|
||||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
|
||||||
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
|
||||||
import "./tech.page.styles.scss";
|
|
||||||
import UpdateAlert from "../../components/update-alert/update-alert.component";
|
import UpdateAlert from "../../components/update-alert/update-alert.component";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
|
import "./tech.page.styles.scss";
|
||||||
const TimeTicketModalContainer = lazy(() =>
|
const TimeTicketModalContainer = lazy(() =>
|
||||||
import("../../components/time-ticket-modal/time-ticket-modal.container")
|
import("../../components/time-ticket-modal/time-ticket-modal.container")
|
||||||
);
|
);
|
||||||
|
const EmailOverlayContainer = lazy(() =>
|
||||||
|
import("../../components/email-overlay/email-overlay.container.jsx")
|
||||||
|
);
|
||||||
const PrintCenterModalContainer = lazy(() =>
|
const PrintCenterModalContainer = lazy(() =>
|
||||||
import("../../components/print-center-modal/print-center-modal.container")
|
import("../../components/print-center-modal/print-center-modal.container")
|
||||||
);
|
);
|
||||||
@@ -69,6 +72,7 @@ export function TechPage({ technician, match }) {
|
|||||||
>
|
>
|
||||||
<FeatureWrapper featureName="tech-console">
|
<FeatureWrapper featureName="tech-console">
|
||||||
<TimeTicketModalContainer />
|
<TimeTicketModalContainer />
|
||||||
|
<EmailOverlayContainer />
|
||||||
<PrintCenterModalContainer />
|
<PrintCenterModalContainer />
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route
|
<Route
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ const INITIAL_STATE = {
|
|||||||
contractFinder: { ...baseModal },
|
contractFinder: { ...baseModal },
|
||||||
inventoryUpsert: { ...baseModal },
|
inventoryUpsert: { ...baseModal },
|
||||||
ca_bc_eftTableConvert: { ...baseModal },
|
ca_bc_eftTableConvert: { ...baseModal },
|
||||||
|
cardPayment: { ...baseModal },
|
||||||
};
|
};
|
||||||
|
|
||||||
const modalsReducer = (state = INITIAL_STATE, action) => {
|
const modalsReducer = (state = INITIAL_STATE, action) => {
|
||||||
|
|||||||
@@ -79,3 +79,8 @@ export const selectCaBcEtfTableConvert = createSelector(
|
|||||||
[selectModals],
|
[selectModals],
|
||||||
(modals) => modals.ca_bc_eftTableConvert
|
(modals) => modals.ca_bc_eftTableConvert
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const selectCardPayment = createSelector(
|
||||||
|
[selectModals],
|
||||||
|
(modals) => modals.cardPayment
|
||||||
|
);
|
||||||
|
|||||||
@@ -63,7 +63,6 @@
|
|||||||
"scheduledfor": "Scheduled appointment for: ",
|
"scheduledfor": "Scheduled appointment for: ",
|
||||||
"severalerrorsfound": "Several jobs have issues which may prevent accurate smart scheduling. Click to expand.",
|
"severalerrorsfound": "Several jobs have issues which may prevent accurate smart scheduling. Click to expand.",
|
||||||
"smartscheduling": "Smart Scheduling",
|
"smartscheduling": "Smart Scheduling",
|
||||||
"smspaymentreminder": "",
|
|
||||||
"suggesteddates": "Suggested Dates"
|
"suggesteddates": "Suggested Dates"
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
@@ -101,10 +100,11 @@
|
|||||||
"messages": {
|
"messages": {
|
||||||
"admin_jobmarkexported": "ADMIN: Job marked as exported.",
|
"admin_jobmarkexported": "ADMIN: Job marked as exported.",
|
||||||
"admin_jobmarkforreexport": "ADMIN: Job marked for re-export.",
|
"admin_jobmarkforreexport": "ADMIN: Job marked for re-export.",
|
||||||
|
"admin_jobuninvoice": "ADMIN: Job has been uninvoiced.",
|
||||||
"admin_jobunvoid": "ADMIN: Job has been unvoided.",
|
"admin_jobunvoid": "ADMIN: Job has been unvoided.",
|
||||||
"billposted": "Bill with invoice number {{invoice_number}} posted.",
|
"billposted": "Bill with invoice number {{invoice_number}} posted.",
|
||||||
"billupdated": "Bill with invoice number {{invoice_number}} updated.",
|
"billupdated": "Bill with invoice number {{invoice_number}} updated.",
|
||||||
"failedpayment": "",
|
"failedpayment": "Failed payment",
|
||||||
"jobassignmentchange": "Employee {{name}} assigned to {{operation}}",
|
"jobassignmentchange": "Employee {{name}} assigned to {{operation}}",
|
||||||
"jobassignmentremoved": "Employee assignment removed for {{operation}}",
|
"jobassignmentremoved": "Employee assignment removed for {{operation}}",
|
||||||
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
|
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
|
||||||
@@ -222,6 +222,7 @@
|
|||||||
"reexport": "Bill marked for re-export."
|
"reexport": "Bill marked for re-export."
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
"closingperiod": "This Bill Date is outside of the Closing Period.",
|
||||||
"inventoryquantity": "Quantity must be greater than or equal to what has been added to inventory ({{number}}).",
|
"inventoryquantity": "Quantity must be greater than or equal to what has been added to inventory ({{number}}).",
|
||||||
"manualinhouse": "Manual posting to the in house vendor is restricted. ",
|
"manualinhouse": "Manual posting to the in house vendor is restricted. ",
|
||||||
"unique_invoice_number": "This invoice number has already been entered for this vendor."
|
"unique_invoice_number": "This invoice number has already been entered for this vendor."
|
||||||
@@ -261,6 +262,7 @@
|
|||||||
"bill_local_tax_rate": "Bill - Provincial/State Tax Rate %",
|
"bill_local_tax_rate": "Bill - Provincial/State Tax Rate %",
|
||||||
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
|
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
|
||||||
"city": "City",
|
"city": "City",
|
||||||
|
"closingperiod": "Closing Period",
|
||||||
"country": "Country",
|
"country": "Country",
|
||||||
"dailybodytarget": "Scoreboard - Daily Body Target",
|
"dailybodytarget": "Scoreboard - Daily Body Target",
|
||||||
"dailypainttarget": "Scoreboard - Daily Paint Target",
|
"dailypainttarget": "Scoreboard - Daily Paint Target",
|
||||||
@@ -269,6 +271,8 @@
|
|||||||
"templates": "Delivery Templates"
|
"templates": "Delivery Templates"
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
|
"apcontrol": "AP Control Number",
|
||||||
|
"appostingaccount": "AP Posting Account",
|
||||||
"cashierid": "Cashier ID",
|
"cashierid": "Cashier ID",
|
||||||
"default_journal": "Default Journal",
|
"default_journal": "Default Journal",
|
||||||
"disablebillwip": "Disable bill WIP for A/P Posting",
|
"disablebillwip": "Disable bill WIP for A/P Posting",
|
||||||
@@ -486,7 +490,7 @@
|
|||||||
"lam": "Mechanical",
|
"lam": "Mechanical",
|
||||||
"lar": "Refinish",
|
"lar": "Refinish",
|
||||||
"las": "Structural",
|
"las": "Structural",
|
||||||
"lau": "Detail",
|
"lau": "User Defined",
|
||||||
"local_tax": "Local Tax",
|
"local_tax": "Local Tax",
|
||||||
"mapa": "Paint Materials",
|
"mapa": "Paint Materials",
|
||||||
"mash": "Shop Materials",
|
"mash": "Shop Materials",
|
||||||
@@ -1010,6 +1014,7 @@
|
|||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
|
"copied": "Copied!",
|
||||||
"copylink": "Copy Link",
|
"copylink": "Copy Link",
|
||||||
"create": "Create",
|
"create": "Create",
|
||||||
"delete": "Delete",
|
"delete": "Delete",
|
||||||
@@ -1026,6 +1031,7 @@
|
|||||||
"saveandnew": "Save and New",
|
"saveandnew": "Save and New",
|
||||||
"selectall": "Select All",
|
"selectall": "Select All",
|
||||||
"send": "Send",
|
"send": "Send",
|
||||||
|
"sendbysms": "Send by SMS",
|
||||||
"senderrortosupport": "Send Error to Support",
|
"senderrortosupport": "Send Error to Support",
|
||||||
"submit": "Submit",
|
"submit": "Submit",
|
||||||
"tryagain": "Try Again",
|
"tryagain": "Try Again",
|
||||||
@@ -1087,6 +1093,7 @@
|
|||||||
"passwordsdonotmatch": "The passwords you have entered do not match.",
|
"passwordsdonotmatch": "The passwords you have entered do not match.",
|
||||||
"print": "Print",
|
"print": "Print",
|
||||||
"refresh": "Refresh",
|
"refresh": "Refresh",
|
||||||
|
"reports": "Reports",
|
||||||
"required": "Required",
|
"required": "Required",
|
||||||
"saturday": "Saturday",
|
"saturday": "Saturday",
|
||||||
"search": "Search...",
|
"search": "Search...",
|
||||||
@@ -1186,26 +1193,28 @@
|
|||||||
},
|
},
|
||||||
"job_payments": {
|
"job_payments": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"goback": "",
|
"goback": "Go Back",
|
||||||
"proceedtopayment": "",
|
"proceedtopayment": "Proceed to Payment",
|
||||||
"refundpayment": ""
|
"refundpayment": "Refund Payment"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"error": {
|
"error": {
|
||||||
"description": "",
|
"description": "Please try again. Make sure the refund amount does not exceeds the payment amount.",
|
||||||
"title": ""
|
"openingip": "Error connecting to IntelliPay service.",
|
||||||
|
"title": "Error placing refund"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"titles": {
|
"titles": {
|
||||||
"amount": "",
|
"amount": "Amount",
|
||||||
"dateOfPayment": "",
|
"dateOfPayment": "Date of Payment",
|
||||||
"descriptions": "",
|
"descriptions": "Payment Details",
|
||||||
"payer": "",
|
"payer": "Payer",
|
||||||
"payername": "",
|
"payername": "Payer Name",
|
||||||
"paymentid": "",
|
"paymentid": "Payment Reference ID",
|
||||||
"paymenttype": "",
|
"paymentnum": "Payment Number",
|
||||||
"refundamount": "",
|
"paymenttype": "Payment Type",
|
||||||
"transactionid": ""
|
"refundamount": "Refund Amount",
|
||||||
|
"transactionid": "Transaction ID"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"joblines": {
|
"joblines": {
|
||||||
@@ -1437,6 +1446,7 @@
|
|||||||
"date_repairstarted": "Repairs Started",
|
"date_repairstarted": "Repairs Started",
|
||||||
"date_scheduled": "Scheduled",
|
"date_scheduled": "Scheduled",
|
||||||
"date_towin": "Towed In",
|
"date_towin": "Towed In",
|
||||||
|
"date_void": "Void",
|
||||||
"ded_amt": "Deductible",
|
"ded_amt": "Deductible",
|
||||||
"ded_note": "Deductible Note",
|
"ded_note": "Deductible Note",
|
||||||
"ded_status": "Deductible Status",
|
"ded_status": "Deductible Status",
|
||||||
@@ -1452,6 +1462,7 @@
|
|||||||
"cost_dms_acctnumber": "Cost DMS Acct #",
|
"cost_dms_acctnumber": "Cost DMS Acct #",
|
||||||
"dms_make": "DMS Make",
|
"dms_make": "DMS Make",
|
||||||
"dms_model": "DMS Model",
|
"dms_model": "DMS Model",
|
||||||
|
"dms_unsold": "New, Unsold Vehicle",
|
||||||
"dms_wip_acctnumber": "Cost WIP DMS Acct #",
|
"dms_wip_acctnumber": "Cost WIP DMS Acct #",
|
||||||
"id": "DMS ID",
|
"id": "DMS ID",
|
||||||
"inservicedate": "In Service Date",
|
"inservicedate": "In Service Date",
|
||||||
@@ -1683,6 +1694,7 @@
|
|||||||
"checklists": "Checklists",
|
"checklists": "Checklists",
|
||||||
"closeconfirm": "Are you sure you want to close this job? This cannot be easily undone.",
|
"closeconfirm": "Are you sure you want to close this job? This cannot be easily undone.",
|
||||||
"closejob": "Close Job {{ro_number}}",
|
"closejob": "Close Job {{ro_number}}",
|
||||||
|
"closingperiod": "This Invoice Date is outside of the Closing Period.",
|
||||||
"contracts": "CC Contracts",
|
"contracts": "CC Contracts",
|
||||||
"convertedtolabor": "Lines Converted to Labor",
|
"convertedtolabor": "Lines Converted to Labor",
|
||||||
"cost": "Cost",
|
"cost": "Cost",
|
||||||
@@ -1918,7 +1930,7 @@
|
|||||||
"customers": "Customers",
|
"customers": "Customers",
|
||||||
"dashboard": "Dashboard",
|
"dashboard": "Dashboard",
|
||||||
"enterbills": "Enter Bills",
|
"enterbills": "Enter Bills",
|
||||||
"entercardpayment": "",
|
"entercardpayment": "New Card Charge",
|
||||||
"enterpayment": "Enter Payments",
|
"enterpayment": "Enter Payments",
|
||||||
"entertimeticket": "Enter Time Tickets",
|
"entertimeticket": "Enter Time Tickets",
|
||||||
"export": "Export",
|
"export": "Export",
|
||||||
@@ -1930,7 +1942,6 @@
|
|||||||
"newjob": "Create New Job",
|
"newjob": "Create New Job",
|
||||||
"owners": "Owners",
|
"owners": "Owners",
|
||||||
"parts-queue": "Parts Queue",
|
"parts-queue": "Parts Queue",
|
||||||
"paymentremindersms": "",
|
|
||||||
"phonebook": "Phonebook",
|
"phonebook": "Phonebook",
|
||||||
"productionboard": "Production Board - Visual",
|
"productionboard": "Production Board - Visual",
|
||||||
"productionlist": "Production Board - List",
|
"productionlist": "Production Board - List",
|
||||||
@@ -2192,9 +2203,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"payments": {
|
"payments": {
|
||||||
|
"actions": {
|
||||||
|
"generatepaymentlink": "Generate Payment Link"
|
||||||
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"exporting": "Error exporting payment(s). {{error}}",
|
"exporting": "Error exporting payment(s). {{error}}",
|
||||||
"exporting-partner": "Error exporting to partner. Please check the partner interaction log for more errors."
|
"exporting-partner": "Error exporting to partner. Please check the partner interaction log for more errors.",
|
||||||
|
"inserting": "Error inserting payment. {{error}}"
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
"amount": "Amount",
|
"amount": "Amount",
|
||||||
@@ -2217,17 +2232,18 @@
|
|||||||
"external": "External",
|
"external": "External",
|
||||||
"findermodal": "ICBC Payment Finder",
|
"findermodal": "ICBC Payment Finder",
|
||||||
"insurance": "Insurance",
|
"insurance": "Insurance",
|
||||||
|
"markexported": "Mark Exported",
|
||||||
|
"markforreexport": "Mark for Re-export",
|
||||||
"new": "New Payment",
|
"new": "New Payment",
|
||||||
"signup": "Please contact support to sign up for electronic payments.",
|
"signup": "Please contact support to sign up for electronic payments.",
|
||||||
|
"smspaymentreminder": "This is {{shopname}} reminding you about your balance of {{amount}}. To pay, click the following link {{payment_link}}.",
|
||||||
"title": "Payments",
|
"title": "Payments",
|
||||||
"totalpayments": "Total Payments",
|
"totalpayments": "Total Payments"
|
||||||
"markexported": "Mark Exported",
|
|
||||||
"markforreexport": "Mark for Re-export"
|
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
"exported": "Payment(s) exported successfully.",
|
"exported": "Payment(s) exported successfully.",
|
||||||
"markreexported": "Payment marked for re-export successfully",
|
|
||||||
"markexported": "Payment(s) marked exported.",
|
"markexported": "Payment(s) marked exported.",
|
||||||
|
"markreexported": "Payment marked for re-export successfully",
|
||||||
"payment": "Payment created successfully. ",
|
"payment": "Payment created successfully. ",
|
||||||
"stripe": "Credit card transaction charged successfully."
|
"stripe": "Credit card transaction charged successfully."
|
||||||
}
|
}
|
||||||
@@ -2403,6 +2419,7 @@
|
|||||||
"jobs": {
|
"jobs": {
|
||||||
"individual_job_note": "Job Note RO: {{ro_number}}",
|
"individual_job_note": "Job Note RO: {{ro_number}}",
|
||||||
"parts_order": "Parts Order PO: {{ro_number}} - {{name}}",
|
"parts_order": "Parts Order PO: {{ro_number}} - {{name}}",
|
||||||
|
"parts_return_slip": "Parts Return PO: {{ro_number}} - {{name}}",
|
||||||
"sublet_order": "Sublet Order PO: {{ro_number}} - {{name}}"
|
"sublet_order": "Sublet Order PO: {{ro_number}} - {{name}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2570,6 +2587,7 @@
|
|||||||
"jobs_completed_not_invoiced": "Jobs Completed not Invoiced",
|
"jobs_completed_not_invoiced": "Jobs Completed not Invoiced",
|
||||||
"jobs_invoiced_not_exported": "Jobs Invoiced not Exported",
|
"jobs_invoiced_not_exported": "Jobs Invoiced not Exported",
|
||||||
"jobs_reconcile": "Parts/Sublet/Labor Reconciliation",
|
"jobs_reconcile": "Parts/Sublet/Labor Reconciliation",
|
||||||
|
"jobs_scheduled_completion": "Jobs Scheduled Completion",
|
||||||
"lag_time": "Lag Time",
|
"lag_time": "Lag Time",
|
||||||
"open_orders": "Open Orders by Date",
|
"open_orders": "Open Orders by Date",
|
||||||
"open_orders_csr": "Open Orders by CSR",
|
"open_orders_csr": "Open Orders by CSR",
|
||||||
@@ -2618,6 +2636,7 @@
|
|||||||
"timetickets_summary": "Time Tickets Summary",
|
"timetickets_summary": "Time Tickets Summary",
|
||||||
"unclaimed_hrs": "Unclaimed Hours",
|
"unclaimed_hrs": "Unclaimed Hours",
|
||||||
"void_ros": "Void ROs",
|
"void_ros": "Void ROs",
|
||||||
|
"work_in_progress_jobs": "Work in Progress - Jobs",
|
||||||
"work_in_progress_labour": "Work in Progress - Labor",
|
"work_in_progress_labour": "Work in Progress - Labor",
|
||||||
"work_in_progress_payables": "Work in Progress - Payables"
|
"work_in_progress_payables": "Work in Progress - Payables"
|
||||||
}
|
}
|
||||||
@@ -2626,8 +2645,8 @@
|
|||||||
"labels": {
|
"labels": {
|
||||||
"atssummary": "ATS Summary",
|
"atssummary": "ATS Summary",
|
||||||
"employeevacation": "Employee Vacations",
|
"employeevacation": "Employee Vacations",
|
||||||
"ins_co_nm_filter": "Filter by Insurance Company",
|
|
||||||
"estimators": "Filter by Writer/Customer Rep.",
|
"estimators": "Filter by Writer/Customer Rep.",
|
||||||
|
"ins_co_nm_filter": "Filter by Insurance Company",
|
||||||
"intake": "Intake Events",
|
"intake": "Intake Events",
|
||||||
"manual": "Manual Events",
|
"manual": "Manual Events",
|
||||||
"manualevent": "Add Manual Event"
|
"manualevent": "Add Manual Event"
|
||||||
@@ -2719,6 +2738,7 @@
|
|||||||
"clockon": "Clocked In",
|
"clockon": "Clocked In",
|
||||||
"committed": "",
|
"committed": "",
|
||||||
"cost_center": "Cost Center",
|
"cost_center": "Cost Center",
|
||||||
|
"created_by": "Created By",
|
||||||
"date": "Ticket Date",
|
"date": "Ticket Date",
|
||||||
"efficiency": "Efficiency",
|
"efficiency": "Efficiency",
|
||||||
"employee": "Employee",
|
"employee": "Employee",
|
||||||
|
|||||||
@@ -63,7 +63,6 @@
|
|||||||
"scheduledfor": "Cita programada para:",
|
"scheduledfor": "Cita programada para:",
|
||||||
"severalerrorsfound": "",
|
"severalerrorsfound": "",
|
||||||
"smartscheduling": "",
|
"smartscheduling": "",
|
||||||
"smspaymentreminder": "",
|
|
||||||
"suggesteddates": ""
|
"suggesteddates": ""
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
@@ -101,6 +100,7 @@
|
|||||||
"messages": {
|
"messages": {
|
||||||
"admin_jobmarkexported": "",
|
"admin_jobmarkexported": "",
|
||||||
"admin_jobmarkforreexport": "",
|
"admin_jobmarkforreexport": "",
|
||||||
|
"admin_jobuninvoice": "",
|
||||||
"admin_jobunvoid": "",
|
"admin_jobunvoid": "",
|
||||||
"billposted": "",
|
"billposted": "",
|
||||||
"billupdated": "",
|
"billupdated": "",
|
||||||
@@ -222,6 +222,7 @@
|
|||||||
"reexport": ""
|
"reexport": ""
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
"closingperiod": "",
|
||||||
"inventoryquantity": "",
|
"inventoryquantity": "",
|
||||||
"manualinhouse": "",
|
"manualinhouse": "",
|
||||||
"unique_invoice_number": ""
|
"unique_invoice_number": ""
|
||||||
@@ -261,6 +262,7 @@
|
|||||||
"bill_local_tax_rate": "",
|
"bill_local_tax_rate": "",
|
||||||
"bill_state_tax_rate": "",
|
"bill_state_tax_rate": "",
|
||||||
"city": "",
|
"city": "",
|
||||||
|
"closingperiod": "",
|
||||||
"country": "",
|
"country": "",
|
||||||
"dailybodytarget": "",
|
"dailybodytarget": "",
|
||||||
"dailypainttarget": "",
|
"dailypainttarget": "",
|
||||||
@@ -269,6 +271,8 @@
|
|||||||
"templates": ""
|
"templates": ""
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
|
"apcontrol": "",
|
||||||
|
"appostingaccount": "",
|
||||||
"cashierid": "",
|
"cashierid": "",
|
||||||
"default_journal": "",
|
"default_journal": "",
|
||||||
"disablebillwip": "",
|
"disablebillwip": "",
|
||||||
@@ -1010,6 +1014,7 @@
|
|||||||
"cancel": "",
|
"cancel": "",
|
||||||
"clear": "",
|
"clear": "",
|
||||||
"close": "",
|
"close": "",
|
||||||
|
"copied": "",
|
||||||
"copylink": "",
|
"copylink": "",
|
||||||
"create": "",
|
"create": "",
|
||||||
"delete": "Borrar",
|
"delete": "Borrar",
|
||||||
@@ -1026,6 +1031,7 @@
|
|||||||
"saveandnew": "",
|
"saveandnew": "",
|
||||||
"selectall": "",
|
"selectall": "",
|
||||||
"send": "",
|
"send": "",
|
||||||
|
"sendbysms": "",
|
||||||
"senderrortosupport": "",
|
"senderrortosupport": "",
|
||||||
"submit": "",
|
"submit": "",
|
||||||
"tryagain": "",
|
"tryagain": "",
|
||||||
@@ -1087,6 +1093,7 @@
|
|||||||
"passwordsdonotmatch": "",
|
"passwordsdonotmatch": "",
|
||||||
"print": "",
|
"print": "",
|
||||||
"refresh": "",
|
"refresh": "",
|
||||||
|
"reports": "",
|
||||||
"required": "",
|
"required": "",
|
||||||
"saturday": "",
|
"saturday": "",
|
||||||
"search": "Buscar...",
|
"search": "Buscar...",
|
||||||
@@ -1193,6 +1200,7 @@
|
|||||||
"notifications": {
|
"notifications": {
|
||||||
"error": {
|
"error": {
|
||||||
"description": "",
|
"description": "",
|
||||||
|
"openingip": "",
|
||||||
"title": ""
|
"title": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1203,6 +1211,7 @@
|
|||||||
"payer": "",
|
"payer": "",
|
||||||
"payername": "",
|
"payername": "",
|
||||||
"paymentid": "",
|
"paymentid": "",
|
||||||
|
"paymentnum": "",
|
||||||
"paymenttype": "",
|
"paymenttype": "",
|
||||||
"refundamount": "",
|
"refundamount": "",
|
||||||
"transactionid": ""
|
"transactionid": ""
|
||||||
@@ -1437,6 +1446,7 @@
|
|||||||
"date_repairstarted": "",
|
"date_repairstarted": "",
|
||||||
"date_scheduled": "Programado",
|
"date_scheduled": "Programado",
|
||||||
"date_towin": "",
|
"date_towin": "",
|
||||||
|
"date_void": "",
|
||||||
"ded_amt": "Deducible",
|
"ded_amt": "Deducible",
|
||||||
"ded_note": "",
|
"ded_note": "",
|
||||||
"ded_status": "Estado deducible",
|
"ded_status": "Estado deducible",
|
||||||
@@ -1452,6 +1462,7 @@
|
|||||||
"cost_dms_acctnumber": "",
|
"cost_dms_acctnumber": "",
|
||||||
"dms_make": "",
|
"dms_make": "",
|
||||||
"dms_model": "",
|
"dms_model": "",
|
||||||
|
"dms_unsold": "",
|
||||||
"dms_wip_acctnumber": "",
|
"dms_wip_acctnumber": "",
|
||||||
"id": "",
|
"id": "",
|
||||||
"inservicedate": "",
|
"inservicedate": "",
|
||||||
@@ -1683,6 +1694,7 @@
|
|||||||
"checklists": "",
|
"checklists": "",
|
||||||
"closeconfirm": "",
|
"closeconfirm": "",
|
||||||
"closejob": "",
|
"closejob": "",
|
||||||
|
"closingperiod": "",
|
||||||
"contracts": "",
|
"contracts": "",
|
||||||
"convertedtolabor": "",
|
"convertedtolabor": "",
|
||||||
"cost": "",
|
"cost": "",
|
||||||
@@ -1930,7 +1942,6 @@
|
|||||||
"newjob": "",
|
"newjob": "",
|
||||||
"owners": "propietarios",
|
"owners": "propietarios",
|
||||||
"parts-queue": "",
|
"parts-queue": "",
|
||||||
"paymentremindersms": "",
|
|
||||||
"phonebook": "",
|
"phonebook": "",
|
||||||
"productionboard": "",
|
"productionboard": "",
|
||||||
"productionlist": "",
|
"productionlist": "",
|
||||||
@@ -2192,9 +2203,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"payments": {
|
"payments": {
|
||||||
|
"actions": {
|
||||||
|
"generatepaymentlink": ""
|
||||||
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"exporting": "",
|
"exporting": "",
|
||||||
"exporting-partner": ""
|
"exporting-partner": "",
|
||||||
|
"inserting": ""
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
"amount": "",
|
"amount": "",
|
||||||
@@ -2217,14 +2232,18 @@
|
|||||||
"external": "",
|
"external": "",
|
||||||
"findermodal": "",
|
"findermodal": "",
|
||||||
"insurance": "",
|
"insurance": "",
|
||||||
|
"markexported": "",
|
||||||
|
"markforreexport": "",
|
||||||
"new": "",
|
"new": "",
|
||||||
"signup": "",
|
"signup": "",
|
||||||
|
"smspaymentreminder": "",
|
||||||
"title": "",
|
"title": "",
|
||||||
"totalpayments": ""
|
"totalpayments": ""
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
"exported": "",
|
"exported": "",
|
||||||
"markexported": "",
|
"markexported": "",
|
||||||
|
"markreexported": "",
|
||||||
"payment": "",
|
"payment": "",
|
||||||
"stripe": ""
|
"stripe": ""
|
||||||
}
|
}
|
||||||
@@ -2400,6 +2419,7 @@
|
|||||||
"jobs": {
|
"jobs": {
|
||||||
"individual_job_note": "",
|
"individual_job_note": "",
|
||||||
"parts_order": "",
|
"parts_order": "",
|
||||||
|
"parts_return_slip": "",
|
||||||
"sublet_order": ""
|
"sublet_order": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2567,6 +2587,7 @@
|
|||||||
"jobs_completed_not_invoiced": "",
|
"jobs_completed_not_invoiced": "",
|
||||||
"jobs_invoiced_not_exported": "",
|
"jobs_invoiced_not_exported": "",
|
||||||
"jobs_reconcile": "",
|
"jobs_reconcile": "",
|
||||||
|
"jobs_scheduled_completion": "",
|
||||||
"lag_time": "",
|
"lag_time": "",
|
||||||
"open_orders": "",
|
"open_orders": "",
|
||||||
"open_orders_csr": "",
|
"open_orders_csr": "",
|
||||||
@@ -2615,6 +2636,7 @@
|
|||||||
"timetickets_summary": "",
|
"timetickets_summary": "",
|
||||||
"unclaimed_hrs": "",
|
"unclaimed_hrs": "",
|
||||||
"void_ros": "",
|
"void_ros": "",
|
||||||
|
"work_in_progress_jobs": "",
|
||||||
"work_in_progress_labour": "",
|
"work_in_progress_labour": "",
|
||||||
"work_in_progress_payables": ""
|
"work_in_progress_payables": ""
|
||||||
}
|
}
|
||||||
@@ -2623,6 +2645,7 @@
|
|||||||
"labels": {
|
"labels": {
|
||||||
"atssummary": "",
|
"atssummary": "",
|
||||||
"employeevacation": "",
|
"employeevacation": "",
|
||||||
|
"estimators": "",
|
||||||
"ins_co_nm_filter": "",
|
"ins_co_nm_filter": "",
|
||||||
"intake": "",
|
"intake": "",
|
||||||
"manual": "",
|
"manual": "",
|
||||||
@@ -2715,6 +2738,7 @@
|
|||||||
"clockon": "",
|
"clockon": "",
|
||||||
"committed": "",
|
"committed": "",
|
||||||
"cost_center": "",
|
"cost_center": "",
|
||||||
|
"created_by": "",
|
||||||
"date": "",
|
"date": "",
|
||||||
"efficiency": "",
|
"efficiency": "",
|
||||||
"employee": "",
|
"employee": "",
|
||||||
|
|||||||
@@ -63,7 +63,6 @@
|
|||||||
"scheduledfor": "Rendez-vous prévu pour:",
|
"scheduledfor": "Rendez-vous prévu pour:",
|
||||||
"severalerrorsfound": "",
|
"severalerrorsfound": "",
|
||||||
"smartscheduling": "",
|
"smartscheduling": "",
|
||||||
"smspaymentreminder": "",
|
|
||||||
"suggesteddates": ""
|
"suggesteddates": ""
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
@@ -101,6 +100,7 @@
|
|||||||
"messages": {
|
"messages": {
|
||||||
"admin_jobmarkexported": "",
|
"admin_jobmarkexported": "",
|
||||||
"admin_jobmarkforreexport": "",
|
"admin_jobmarkforreexport": "",
|
||||||
|
"admin_jobuninvoice": "",
|
||||||
"admin_jobunvoid": "",
|
"admin_jobunvoid": "",
|
||||||
"billposted": "",
|
"billposted": "",
|
||||||
"billupdated": "",
|
"billupdated": "",
|
||||||
@@ -222,6 +222,7 @@
|
|||||||
"reexport": ""
|
"reexport": ""
|
||||||
},
|
},
|
||||||
"validation": {
|
"validation": {
|
||||||
|
"closingperiod": "",
|
||||||
"inventoryquantity": "",
|
"inventoryquantity": "",
|
||||||
"manualinhouse": "",
|
"manualinhouse": "",
|
||||||
"unique_invoice_number": ""
|
"unique_invoice_number": ""
|
||||||
@@ -261,6 +262,7 @@
|
|||||||
"bill_local_tax_rate": "",
|
"bill_local_tax_rate": "",
|
||||||
"bill_state_tax_rate": "",
|
"bill_state_tax_rate": "",
|
||||||
"city": "",
|
"city": "",
|
||||||
|
"closingperiod": "",
|
||||||
"country": "",
|
"country": "",
|
||||||
"dailybodytarget": "",
|
"dailybodytarget": "",
|
||||||
"dailypainttarget": "",
|
"dailypainttarget": "",
|
||||||
@@ -269,6 +271,8 @@
|
|||||||
"templates": ""
|
"templates": ""
|
||||||
},
|
},
|
||||||
"dms": {
|
"dms": {
|
||||||
|
"apcontrol": "",
|
||||||
|
"appostingaccount": "",
|
||||||
"cashierid": "",
|
"cashierid": "",
|
||||||
"default_journal": "",
|
"default_journal": "",
|
||||||
"disablebillwip": "",
|
"disablebillwip": "",
|
||||||
@@ -1010,6 +1014,7 @@
|
|||||||
"cancel": "",
|
"cancel": "",
|
||||||
"clear": "",
|
"clear": "",
|
||||||
"close": "",
|
"close": "",
|
||||||
|
"copied": "",
|
||||||
"copylink": "",
|
"copylink": "",
|
||||||
"create": "",
|
"create": "",
|
||||||
"delete": "Effacer",
|
"delete": "Effacer",
|
||||||
@@ -1026,6 +1031,7 @@
|
|||||||
"saveandnew": "",
|
"saveandnew": "",
|
||||||
"selectall": "",
|
"selectall": "",
|
||||||
"send": "",
|
"send": "",
|
||||||
|
"sendbysms": "",
|
||||||
"senderrortosupport": "",
|
"senderrortosupport": "",
|
||||||
"submit": "",
|
"submit": "",
|
||||||
"tryagain": "",
|
"tryagain": "",
|
||||||
@@ -1087,6 +1093,7 @@
|
|||||||
"passwordsdonotmatch": "",
|
"passwordsdonotmatch": "",
|
||||||
"print": "",
|
"print": "",
|
||||||
"refresh": "",
|
"refresh": "",
|
||||||
|
"reports": "",
|
||||||
"required": "",
|
"required": "",
|
||||||
"saturday": "",
|
"saturday": "",
|
||||||
"search": "Chercher...",
|
"search": "Chercher...",
|
||||||
@@ -1193,6 +1200,7 @@
|
|||||||
"notifications": {
|
"notifications": {
|
||||||
"error": {
|
"error": {
|
||||||
"description": "",
|
"description": "",
|
||||||
|
"openingip": "",
|
||||||
"title": ""
|
"title": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1203,6 +1211,7 @@
|
|||||||
"payer": "",
|
"payer": "",
|
||||||
"payername": "",
|
"payername": "",
|
||||||
"paymentid": "",
|
"paymentid": "",
|
||||||
|
"paymentnum": "",
|
||||||
"paymenttype": "",
|
"paymenttype": "",
|
||||||
"refundamount": "",
|
"refundamount": "",
|
||||||
"transactionid": ""
|
"transactionid": ""
|
||||||
@@ -1437,6 +1446,7 @@
|
|||||||
"date_repairstarted": "",
|
"date_repairstarted": "",
|
||||||
"date_scheduled": "Prévu",
|
"date_scheduled": "Prévu",
|
||||||
"date_towin": "",
|
"date_towin": "",
|
||||||
|
"date_void": "",
|
||||||
"ded_amt": "Déductible",
|
"ded_amt": "Déductible",
|
||||||
"ded_note": "",
|
"ded_note": "",
|
||||||
"ded_status": "Statut de franchise",
|
"ded_status": "Statut de franchise",
|
||||||
@@ -1452,6 +1462,7 @@
|
|||||||
"cost_dms_acctnumber": "",
|
"cost_dms_acctnumber": "",
|
||||||
"dms_make": "",
|
"dms_make": "",
|
||||||
"dms_model": "",
|
"dms_model": "",
|
||||||
|
"dms_unsold": "",
|
||||||
"dms_wip_acctnumber": "",
|
"dms_wip_acctnumber": "",
|
||||||
"id": "",
|
"id": "",
|
||||||
"inservicedate": "",
|
"inservicedate": "",
|
||||||
@@ -1683,6 +1694,7 @@
|
|||||||
"checklists": "",
|
"checklists": "",
|
||||||
"closeconfirm": "",
|
"closeconfirm": "",
|
||||||
"closejob": "",
|
"closejob": "",
|
||||||
|
"closingperiod": "",
|
||||||
"contracts": "",
|
"contracts": "",
|
||||||
"convertedtolabor": "",
|
"convertedtolabor": "",
|
||||||
"cost": "",
|
"cost": "",
|
||||||
@@ -1930,7 +1942,6 @@
|
|||||||
"newjob": "",
|
"newjob": "",
|
||||||
"owners": "Propriétaires",
|
"owners": "Propriétaires",
|
||||||
"parts-queue": "",
|
"parts-queue": "",
|
||||||
"paymentremindersms": "",
|
|
||||||
"phonebook": "",
|
"phonebook": "",
|
||||||
"productionboard": "",
|
"productionboard": "",
|
||||||
"productionlist": "",
|
"productionlist": "",
|
||||||
@@ -2192,9 +2203,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"payments": {
|
"payments": {
|
||||||
|
"actions": {
|
||||||
|
"generatepaymentlink": ""
|
||||||
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"exporting": "",
|
"exporting": "",
|
||||||
"exporting-partner": ""
|
"exporting-partner": "",
|
||||||
|
"inserting": ""
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
"amount": "",
|
"amount": "",
|
||||||
@@ -2217,14 +2232,18 @@
|
|||||||
"external": "",
|
"external": "",
|
||||||
"findermodal": "",
|
"findermodal": "",
|
||||||
"insurance": "",
|
"insurance": "",
|
||||||
|
"markexported": "",
|
||||||
|
"markforreexport": "",
|
||||||
"new": "",
|
"new": "",
|
||||||
"signup": "",
|
"signup": "",
|
||||||
|
"smspaymentreminder": "",
|
||||||
"title": "",
|
"title": "",
|
||||||
"totalpayments": ""
|
"totalpayments": ""
|
||||||
},
|
},
|
||||||
"successes": {
|
"successes": {
|
||||||
"exported": "",
|
"exported": "",
|
||||||
"markexported": "",
|
"markexported": "",
|
||||||
|
"markreexported": "",
|
||||||
"payment": "",
|
"payment": "",
|
||||||
"stripe": ""
|
"stripe": ""
|
||||||
}
|
}
|
||||||
@@ -2400,6 +2419,7 @@
|
|||||||
"jobs": {
|
"jobs": {
|
||||||
"individual_job_note": "",
|
"individual_job_note": "",
|
||||||
"parts_order": "",
|
"parts_order": "",
|
||||||
|
"parts_return_slip": "",
|
||||||
"sublet_order": ""
|
"sublet_order": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2567,6 +2587,7 @@
|
|||||||
"jobs_completed_not_invoiced": "",
|
"jobs_completed_not_invoiced": "",
|
||||||
"jobs_invoiced_not_exported": "",
|
"jobs_invoiced_not_exported": "",
|
||||||
"jobs_reconcile": "",
|
"jobs_reconcile": "",
|
||||||
|
"jobs_scheduled_completion": "",
|
||||||
"lag_time": "",
|
"lag_time": "",
|
||||||
"open_orders": "",
|
"open_orders": "",
|
||||||
"open_orders_csr": "",
|
"open_orders_csr": "",
|
||||||
@@ -2615,6 +2636,7 @@
|
|||||||
"timetickets_summary": "",
|
"timetickets_summary": "",
|
||||||
"unclaimed_hrs": "",
|
"unclaimed_hrs": "",
|
||||||
"void_ros": "",
|
"void_ros": "",
|
||||||
|
"work_in_progress_jobs": "",
|
||||||
"work_in_progress_labour": "",
|
"work_in_progress_labour": "",
|
||||||
"work_in_progress_payables": ""
|
"work_in_progress_payables": ""
|
||||||
}
|
}
|
||||||
@@ -2623,6 +2645,7 @@
|
|||||||
"labels": {
|
"labels": {
|
||||||
"atssummary": "",
|
"atssummary": "",
|
||||||
"employeevacation": "",
|
"employeevacation": "",
|
||||||
|
"estimators": "",
|
||||||
"ins_co_nm_filter": "",
|
"ins_co_nm_filter": "",
|
||||||
"intake": "",
|
"intake": "",
|
||||||
"manual": "",
|
"manual": "",
|
||||||
@@ -2715,6 +2738,7 @@
|
|||||||
"clockon": "",
|
"clockon": "",
|
||||||
"committed": "",
|
"committed": "",
|
||||||
"cost_center": "",
|
"cost_center": "",
|
||||||
|
"created_by": "",
|
||||||
"date": "",
|
"date": "",
|
||||||
"efficiency": "",
|
"efficiency": "",
|
||||||
"employee": "",
|
"employee": "",
|
||||||
|
|||||||
@@ -36,11 +36,12 @@ const AuditTrailMapping = {
|
|||||||
jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"),
|
jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"),
|
||||||
jobnotedeleted: () => i18n.t("audit_trail.messages.jobnotedeleted"),
|
jobnotedeleted: () => i18n.t("audit_trail.messages.jobnotedeleted"),
|
||||||
admin_jobunvoid: () => i18n.t("audit_trail.messages.admin_jobunvoid"),
|
admin_jobunvoid: () => i18n.t("audit_trail.messages.admin_jobunvoid"),
|
||||||
|
admin_jobuninvoice: () => i18n.t("audit_trail.messages.admin_jobuninvoice"),
|
||||||
admin_jobmarkforreexport: () =>
|
admin_jobmarkforreexport: () =>
|
||||||
i18n.t("audit_trail.messages.admin_jobmarkforreexport"),
|
i18n.t("audit_trail.messages.admin_jobmarkforreexport"),
|
||||||
admin_jobmarkexported: () =>
|
admin_jobmarkexported: () =>
|
||||||
i18n.t("audit_trail.messages.admin_jobmarkexported"),
|
i18n.t("audit_trail.messages.admin_jobmarkexported"),
|
||||||
|
failedpayment: () => i18n.t("audit_trail.messages.failedpayment"),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AuditTrailMapping;
|
export default AuditTrailMapping;
|
||||||
|
|||||||
@@ -606,7 +606,14 @@ export const TemplateList = (type, context) => {
|
|||||||
},
|
},
|
||||||
parts_return_slip: {
|
parts_return_slip: {
|
||||||
title: i18n.t("printcenter.jobs.parts_return_slip"),
|
title: i18n.t("printcenter.jobs.parts_return_slip"),
|
||||||
subject: i18n.t("printcenter.jobs.parts_return_slip"),
|
subject: i18n.t("printcenter.subjects.jobs.parts_return_slip", {
|
||||||
|
ro_number: context && context.job && context.job.ro_number,
|
||||||
|
name: (
|
||||||
|
(context && context.job && context.job.ownr_ln) ||
|
||||||
|
(context && context.job && context.job.ownr_co_nm) ||
|
||||||
|
""
|
||||||
|
).trim(),
|
||||||
|
}),
|
||||||
description: "",
|
description: "",
|
||||||
key: "parts_return_slip",
|
key: "parts_return_slip",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
@@ -1033,7 +1040,7 @@ export const TemplateList = (type, context) => {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
rangeFilter: {
|
rangeFilter: {
|
||||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||||
field: i18n.t("jobs.fields.date_open"),
|
field: i18n.t("jobs.fields.date_invoiced"),
|
||||||
},
|
},
|
||||||
group: "jobs",
|
group: "jobs",
|
||||||
},
|
},
|
||||||
@@ -1128,6 +1135,10 @@ export const TemplateList = (type, context) => {
|
|||||||
key: "timetickets_employee",
|
key: "timetickets_employee",
|
||||||
idtype: "employee",
|
idtype: "employee",
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.timetickets"),
|
||||||
|
field: i18n.t("timetickets.fields.date"),
|
||||||
|
},
|
||||||
group: "payroll",
|
group: "payroll",
|
||||||
},
|
},
|
||||||
attendance_detail: {
|
attendance_detail: {
|
||||||
@@ -1237,7 +1248,7 @@ export const TemplateList = (type, context) => {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
rangeFilter: {
|
rangeFilter: {
|
||||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||||
field: i18n.t("jobs.fields.date_open"),
|
field: i18n.t("jobs.fields.date_void"),
|
||||||
},
|
},
|
||||||
group: "sales",
|
group: "sales",
|
||||||
},
|
},
|
||||||
@@ -1540,6 +1551,19 @@ export const TemplateList = (type, context) => {
|
|||||||
},
|
},
|
||||||
group: "payroll",
|
group: "payroll",
|
||||||
},
|
},
|
||||||
|
work_in_progress_jobs_excel: {
|
||||||
|
title: i18n.t("reportcenter.templates.work_in_progress_jobs"),
|
||||||
|
subject: i18n.t("reportcenter.templates.work_in_progress_jobs"),
|
||||||
|
key: "work_in_progress_jobs_excel",
|
||||||
|
//idtype: "vendor",
|
||||||
|
reporttype: "excel",
|
||||||
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||||
|
field: i18n.t("jobs.fields.date_open"),
|
||||||
|
},
|
||||||
|
group: "jobs",
|
||||||
|
},
|
||||||
work_in_progress_labour: {
|
work_in_progress_labour: {
|
||||||
title: i18n.t("reportcenter.templates.work_in_progress_labour"),
|
title: i18n.t("reportcenter.templates.work_in_progress_labour"),
|
||||||
description: "",
|
description: "",
|
||||||
@@ -1897,6 +1921,18 @@ export const TemplateList = (type, context) => {
|
|||||||
},
|
},
|
||||||
group: "sales",
|
group: "sales",
|
||||||
},
|
},
|
||||||
|
jobs_scheduled_completion: {
|
||||||
|
title: i18n.t("reportcenter.templates.jobs_scheduled_completion"),
|
||||||
|
subject: i18n.t("reportcenter.templates.jobs_scheduled_completion"),
|
||||||
|
key: "jobs_scheduled_completion",
|
||||||
|
//idtype: "vendor",
|
||||||
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||||
|
field: i18n.t("jobs.fields.scheduled_completion"),
|
||||||
|
},
|
||||||
|
group: "jobs",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
...(!type || type === "courtesycarcontract"
|
...(!type || type === "courtesycarcontract"
|
||||||
|
|||||||
@@ -2092,6 +2092,13 @@
|
|||||||
table:
|
table:
|
||||||
name: employee_team_members
|
name: employee_team_members
|
||||||
schema: public
|
schema: public
|
||||||
|
- name: joblines
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on:
|
||||||
|
column: assigned_team
|
||||||
|
table:
|
||||||
|
name: joblines
|
||||||
|
schema: public
|
||||||
insert_permissions:
|
insert_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
@@ -2665,6 +2672,9 @@
|
|||||||
name: joblines
|
name: joblines
|
||||||
schema: public
|
schema: public
|
||||||
object_relationships:
|
object_relationships:
|
||||||
|
- name: employee_team
|
||||||
|
using:
|
||||||
|
foreign_key_constraint_on: assigned_team
|
||||||
- name: job
|
- name: job
|
||||||
using:
|
using:
|
||||||
foreign_key_constraint_on: jobid
|
foreign_key_constraint_on: jobid
|
||||||
@@ -2726,6 +2736,7 @@
|
|||||||
- alt_part_i
|
- alt_part_i
|
||||||
- alt_partm
|
- alt_partm
|
||||||
- alt_partno
|
- alt_partno
|
||||||
|
- assigned_team
|
||||||
- bett_amt
|
- bett_amt
|
||||||
- bett_pctg
|
- bett_pctg
|
||||||
- bett_tax
|
- bett_tax
|
||||||
@@ -2734,6 +2745,7 @@
|
|||||||
- convertedtolbr
|
- convertedtolbr
|
||||||
- convertedtolbr_data
|
- convertedtolbr_data
|
||||||
- created_at
|
- created_at
|
||||||
|
- critical
|
||||||
- db_hrs
|
- db_hrs
|
||||||
- db_price
|
- db_price
|
||||||
- db_ref
|
- db_ref
|
||||||
@@ -2793,6 +2805,7 @@
|
|||||||
- alt_part_i
|
- alt_part_i
|
||||||
- alt_partm
|
- alt_partm
|
||||||
- alt_partno
|
- alt_partno
|
||||||
|
- assigned_team
|
||||||
- bett_amt
|
- bett_amt
|
||||||
- bett_pctg
|
- bett_pctg
|
||||||
- bett_tax
|
- bett_tax
|
||||||
@@ -2872,6 +2885,7 @@
|
|||||||
- alt_part_i
|
- alt_part_i
|
||||||
- alt_partm
|
- alt_partm
|
||||||
- alt_partno
|
- alt_partno
|
||||||
|
- assigned_team
|
||||||
- bett_amt
|
- bett_amt
|
||||||
- bett_pctg
|
- bett_pctg
|
||||||
- bett_tax
|
- bett_tax
|
||||||
@@ -3259,6 +3273,8 @@
|
|||||||
- ca_gst_registrant
|
- ca_gst_registrant
|
||||||
- cat_no
|
- cat_no
|
||||||
- category
|
- category
|
||||||
|
- cieca_pfl
|
||||||
|
- cieca_pft
|
||||||
- cieca_stl
|
- cieca_stl
|
||||||
- cieca_ttl
|
- cieca_ttl
|
||||||
- ciecaid
|
- ciecaid
|
||||||
@@ -3286,6 +3302,7 @@
|
|||||||
- clm_total
|
- clm_total
|
||||||
- clm_zip
|
- clm_zip
|
||||||
- comment
|
- comment
|
||||||
|
- completed_tasks
|
||||||
- converted
|
- converted
|
||||||
- created_at
|
- created_at
|
||||||
- cust_pr
|
- cust_pr
|
||||||
@@ -3299,6 +3316,7 @@
|
|||||||
- date_repairstarted
|
- date_repairstarted
|
||||||
- date_scheduled
|
- date_scheduled
|
||||||
- date_towin
|
- date_towin
|
||||||
|
- date_void
|
||||||
- ded_amt
|
- ded_amt
|
||||||
- ded_note
|
- ded_note
|
||||||
- ded_status
|
- ded_status
|
||||||
@@ -3523,6 +3541,8 @@
|
|||||||
- ca_gst_registrant
|
- ca_gst_registrant
|
||||||
- cat_no
|
- cat_no
|
||||||
- category
|
- category
|
||||||
|
- cieca_pfl
|
||||||
|
- cieca_pft
|
||||||
- cieca_stl
|
- cieca_stl
|
||||||
- cieca_ttl
|
- cieca_ttl
|
||||||
- ciecaid
|
- ciecaid
|
||||||
@@ -3550,6 +3570,7 @@
|
|||||||
- clm_total
|
- clm_total
|
||||||
- clm_zip
|
- clm_zip
|
||||||
- comment
|
- comment
|
||||||
|
- completed_tasks
|
||||||
- converted
|
- converted
|
||||||
- created_at
|
- created_at
|
||||||
- cust_pr
|
- cust_pr
|
||||||
@@ -3563,6 +3584,7 @@
|
|||||||
- date_repairstarted
|
- date_repairstarted
|
||||||
- date_scheduled
|
- date_scheduled
|
||||||
- date_towin
|
- date_towin
|
||||||
|
- date_void
|
||||||
- ded_amt
|
- ded_amt
|
||||||
- ded_note
|
- ded_note
|
||||||
- ded_status
|
- ded_status
|
||||||
@@ -3798,6 +3820,8 @@
|
|||||||
- ca_gst_registrant
|
- ca_gst_registrant
|
||||||
- cat_no
|
- cat_no
|
||||||
- category
|
- category
|
||||||
|
- cieca_pfl
|
||||||
|
- cieca_pft
|
||||||
- cieca_stl
|
- cieca_stl
|
||||||
- cieca_ttl
|
- cieca_ttl
|
||||||
- ciecaid
|
- ciecaid
|
||||||
@@ -3825,6 +3849,7 @@
|
|||||||
- clm_total
|
- clm_total
|
||||||
- clm_zip
|
- clm_zip
|
||||||
- comment
|
- comment
|
||||||
|
- completed_tasks
|
||||||
- converted
|
- converted
|
||||||
- created_at
|
- created_at
|
||||||
- cust_pr
|
- cust_pr
|
||||||
@@ -3838,6 +3863,7 @@
|
|||||||
- date_repairstarted
|
- date_repairstarted
|
||||||
- date_scheduled
|
- date_scheduled
|
||||||
- date_towin
|
- date_towin
|
||||||
|
- date_void
|
||||||
- ded_amt
|
- ded_amt
|
||||||
- ded_note
|
- ded_note
|
||||||
- ded_status
|
- ded_status
|
||||||
@@ -4629,6 +4655,7 @@
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
|
allow_aggregations: true
|
||||||
update_permissions:
|
update_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
@@ -4706,6 +4733,7 @@
|
|||||||
_eq: X-Hasura-User-Id
|
_eq: X-Hasura-User-Id
|
||||||
- active:
|
- active:
|
||||||
_eq: true
|
_eq: true
|
||||||
|
allow_aggregations: true
|
||||||
update_permissions:
|
update_permissions:
|
||||||
- role: user
|
- role: user
|
||||||
permission:
|
permission:
|
||||||
@@ -5534,6 +5562,7 @@
|
|||||||
- committed_at
|
- committed_at
|
||||||
- cost_center
|
- cost_center
|
||||||
- created_at
|
- created_at
|
||||||
|
- created_by
|
||||||
- date
|
- date
|
||||||
- employeeid
|
- employeeid
|
||||||
- flat_rate
|
- flat_rate
|
||||||
@@ -5542,6 +5571,7 @@
|
|||||||
- memo
|
- memo
|
||||||
- productivehrs
|
- productivehrs
|
||||||
- rate
|
- rate
|
||||||
|
- task_name
|
||||||
- ttapprovalqueueid
|
- ttapprovalqueueid
|
||||||
- updated_at
|
- updated_at
|
||||||
select_permissions:
|
select_permissions:
|
||||||
@@ -5557,6 +5587,7 @@
|
|||||||
- committed_at
|
- committed_at
|
||||||
- cost_center
|
- cost_center
|
||||||
- created_at
|
- created_at
|
||||||
|
- created_by
|
||||||
- date
|
- date
|
||||||
- employeeid
|
- employeeid
|
||||||
- flat_rate
|
- flat_rate
|
||||||
@@ -5565,6 +5596,7 @@
|
|||||||
- memo
|
- memo
|
||||||
- productivehrs
|
- productivehrs
|
||||||
- rate
|
- rate
|
||||||
|
- task_name
|
||||||
- ttapprovalqueueid
|
- ttapprovalqueueid
|
||||||
- updated_at
|
- updated_at
|
||||||
filter:
|
filter:
|
||||||
@@ -5589,6 +5621,7 @@
|
|||||||
- committed_at
|
- committed_at
|
||||||
- cost_center
|
- cost_center
|
||||||
- created_at
|
- created_at
|
||||||
|
- created_by
|
||||||
- date
|
- date
|
||||||
- employeeid
|
- employeeid
|
||||||
- flat_rate
|
- flat_rate
|
||||||
@@ -5597,6 +5630,7 @@
|
|||||||
- memo
|
- memo
|
||||||
- productivehrs
|
- productivehrs
|
||||||
- rate
|
- rate
|
||||||
|
- task_name
|
||||||
- ttapprovalqueueid
|
- ttapprovalqueueid
|
||||||
- updated_at
|
- updated_at
|
||||||
filter:
|
filter:
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."joblines" add column "assigned_team" uuid
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."joblines" add column "assigned_team" uuid
|
||||||
|
null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."joblines" drop constraint "joblines_assigned_team_fkey";
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
alter table "public"."joblines"
|
||||||
|
add constraint "joblines_assigned_team_fkey"
|
||||||
|
foreign key ("assigned_team")
|
||||||
|
references "public"."employee_teams"
|
||||||
|
("id") on update restrict on delete restrict;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."jobs" add column "completed_tasks" jsonb
|
||||||
|
-- null default jsonb_build_array();
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."jobs" add column "completed_tasks" jsonb
|
||||||
|
null default jsonb_build_array();
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."jobs" add column "void_date" Timestamp
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."jobs" add column "void_date" Timestamp
|
||||||
|
null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "public"."jobs" ALTER COLUMN "void_date" TYPE timestamp without time zone;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "public"."jobs" ALTER COLUMN "void_date" TYPE timestamptz;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."jobs" rename column "date_void" to "void_date";
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
alter table "public"."jobs" rename column "void_date" to "date_void";
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."timetickets" add column "task_name" text
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."timetickets" add column "task_name" text
|
||||||
|
null;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."parts_dispatch_employeeid";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "parts_dispatch_employeeid" on
|
||||||
|
"public"."parts_dispatch" using btree ("employeeid");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."parts_dispatch_dispatchid";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "parts_dispatch_dispatchid" on
|
||||||
|
"public"."parts_dispatch_lines" using btree ("partsdispatchid");
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
DROP INDEX IF EXISTS "public"."parts_dispatch_line_accepted_at";
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
CREATE INDEX "parts_dispatch_line_accepted_at" on
|
||||||
|
"public"."parts_dispatch_lines" using btree ("accepted_at");
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."timetickets" add column "created_by" text
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."timetickets" add column "created_by" text
|
||||||
|
null;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."jobs" add column "cieca_pfl" jsonb
|
||||||
|
-- null default jsonb_build_object();
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."jobs" add column "cieca_pfl" jsonb
|
||||||
|
null default jsonb_build_object();
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."bodyshops" add column "claimscorpid" text
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."bodyshops" add column "claimscorpid" text
|
||||||
|
null;
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
-- Could not auto-generate a down migration.
|
||||||
|
-- Please write an appropriate down migration for the SQL below:
|
||||||
|
-- alter table "public"."jobs" add column "cieca_pft" jsonb
|
||||||
|
-- null default jsonb_build_object();
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."jobs" add column "cieca_pft" jsonb
|
||||||
|
null default jsonb_build_object();
|
||||||
11095
package-lock.json
generated
11095
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user