Compare commits
60 Commits
feature/pb
...
release/20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef18cf0718 | ||
|
|
e98f9763fd | ||
|
|
46abf01366 | ||
|
|
45ab7543d5 | ||
|
|
fed16efd10 | ||
|
|
49bf461c36 | ||
|
|
696781c857 | ||
|
|
5540872f62 | ||
|
|
69690f0184 | ||
|
|
f11a4c93ac | ||
|
|
9eed33b5f2 | ||
|
|
55b7715e1c | ||
|
|
c129b5ba8c | ||
|
|
efc2844d99 | ||
|
|
ab38f85d38 | ||
|
|
81eccba393 | ||
|
|
b3b49fd4ca | ||
|
|
b7a08db4e7 | ||
|
|
2d63c3d576 | ||
|
|
5f4a2392af | ||
|
|
f6fe8be7c4 | ||
|
|
89af6d23e8 | ||
|
|
7e1431d65e | ||
|
|
d50e845ba0 | ||
|
|
6796c35e5b | ||
|
|
4a68a10005 | ||
|
|
17088b3025 | ||
|
|
4e3c659b6d | ||
|
|
6afcf82cc4 | ||
|
|
f4ddb40bde | ||
|
|
6017e2172e | ||
|
|
bef9e64bf8 | ||
|
|
e8d95bdb68 | ||
|
|
10fb7d9d96 | ||
|
|
2ec196e664 | ||
|
|
1f38b98bfd | ||
|
|
a7c76386bc | ||
|
|
042b67c531 | ||
|
|
2e72ed3698 | ||
|
|
bc01f46388 | ||
|
|
74f791541f | ||
|
|
84c7fdba5a | ||
|
|
630fa23f6c | ||
|
|
8f58f09c8c | ||
|
|
a0922f2944 | ||
|
|
b8f001625b | ||
|
|
53394efebf | ||
|
|
d8296e1d01 | ||
|
|
2c00e5ee79 | ||
|
|
34e220dcad | ||
|
|
fa1fffd8b9 | ||
|
|
67eb430ff9 | ||
|
|
ff53355b4a | ||
|
|
331b2c517b | ||
|
|
05d9f20a66 | ||
|
|
9e3a2e920d | ||
|
|
1511b87959 | ||
|
|
9c3e4b7b83 | ||
|
|
b718f49071 | ||
|
|
e7157119ae |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -112,3 +112,4 @@ firebase/.env
|
||||
.elasticbeanstalk/*
|
||||
!.elasticbeanstalk/*.cfg.yml
|
||||
!.elasticbeanstalk/*.global.yml
|
||||
logs/oAuthClient-log.log
|
||||
|
||||
@@ -8103,6 +8103,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>filehandlers</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>insurancecos</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -8664,6 +8685,27 @@
|
||||
<folder_node>
|
||||
<name>validation</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>centermustexist</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>larsplit</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -17491,6 +17533,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>changefilehandler</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>changelaborrate</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -19737,6 +19800,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>date_next_contact</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>date_open</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -29272,6 +29356,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>noattachedjobs</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>
|
||||
@@ -29424,6 +29529,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>recentonly</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>selectmedia</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -30627,6 +30753,27 @@
|
||||
<folder_node>
|
||||
<name>errors</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>associatedbills</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>backordering</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -32874,6 +33021,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>ab_proof_of_loss</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>appointment_confirmation</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -33231,6 +33399,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<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>
|
||||
<name>invoice_customer_payable</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -34050,6 +34239,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>worksheet_sorted_by_operation_type</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
@@ -34662,6 +34872,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>settings</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>
|
||||
@@ -34730,6 +34961,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>ats</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>bodyhours</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -34772,6 +35024,69 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>cardsettings</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>clm_no</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>compact</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<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>detailpriority</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -34793,6 +35108,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>employeeassignments</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>employeesearch</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -34814,6 +35150,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>ins_co_nm</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>jobdetail</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -34835,6 +35192,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>laborhrs</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>note</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -34856,6 +35234,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>ownr_nm</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>paintpriority</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -34877,6 +35276,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>production_note</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>refinishhours</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -34898,6 +35318,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>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>
|
||||
<name>selectview</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -36465,6 +36906,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>open_orders_status</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>parts_backorder</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -2,74 +2,74 @@
|
||||
"name": "bodyshop",
|
||||
"version": "0.1.1",
|
||||
"private": true,
|
||||
"proxy": "http://localhost:5000",
|
||||
"proxy": "http://localhost:4000",
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.4.16",
|
||||
"@apollo/client": "^3.4.17",
|
||||
"@asseinfo/react-kanban": "^2.2.0",
|
||||
"@craco/craco": "^6.4.0",
|
||||
"@fingerprintjs/fingerprintjs": "^3.3.0",
|
||||
"@lourenci/react-kanban": "^2.1.0",
|
||||
"@openreplay/tracker": "^3.4.4",
|
||||
"@openreplay/tracker": "^3.4.7",
|
||||
"@openreplay/tracker-assist": "^3.4.4",
|
||||
"@openreplay/tracker-graphql": "^3.0.0",
|
||||
"@openreplay/tracker-redux": "^3.0.0",
|
||||
"@sentry/react": "^6.13.3",
|
||||
"@sentry/tracing": "^6.13.3",
|
||||
"@sentry/react": "^6.14.3",
|
||||
"@sentry/tracing": "^6.14.3",
|
||||
"@splitsoftware/splitio-react": "^1.3.0",
|
||||
"@stripe/react-stripe-js": "^1.6.0",
|
||||
"@stripe/stripe-js": "^1.20.2",
|
||||
"@tanem/react-nprogress": "^3.0.81",
|
||||
"@stripe/stripe-js": "^1.21.1",
|
||||
"@tanem/react-nprogress": "^3.0.82",
|
||||
"antd": "^4.16.13",
|
||||
"apollo-link-logger": "^2.0.0",
|
||||
"axios": "^0.23.0",
|
||||
"axios": "^0.24.0",
|
||||
"craco-less": "^1.20.0",
|
||||
"dinero.js": "^1.9.1",
|
||||
"dotenv": "^10.0.0",
|
||||
"enquire-js": "^0.2.1",
|
||||
"env-cmd": "^10.1.0",
|
||||
"exifr": "^7.1.3",
|
||||
"firebase": "^9.1.3",
|
||||
"graphql": "^15.6.1",
|
||||
"i18next": "^21.3.3",
|
||||
"firebase": "^9.4.1",
|
||||
"graphql": "^16.0.1",
|
||||
"i18next": "^21.4.2",
|
||||
"i18next-browser-languagedetector": "^6.1.2",
|
||||
"jsoneditor": "^9.5.6",
|
||||
"jsoneditor": "^9.5.7",
|
||||
"jsreport-browser-client-dist": "^1.3.0",
|
||||
"libphonenumber-js": "^1.9.38",
|
||||
"libphonenumber-js": "^1.9.42",
|
||||
"logrocket": "^2.1.1",
|
||||
"markerjs2": "^2.15.0",
|
||||
"markerjs2": "^2.17.0",
|
||||
"moment-business-days": "^1.2.0",
|
||||
"phone": "^3.1.8",
|
||||
"phone": "^3.1.9",
|
||||
"preval.macro": "^5.0.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"query-string": "^7.0.1",
|
||||
"rc-queue-anim": "^2.0.0",
|
||||
"rc-scroll-anim": "^2.7.6",
|
||||
"react": "^17.0.1",
|
||||
"react-big-calendar": "^0.38.0",
|
||||
"react-big-calendar": "^0.38.1",
|
||||
"react-color": "^2.19.3",
|
||||
"react-cookie": "^4.1.1",
|
||||
"react-dom": "^17.0.1",
|
||||
"react-drag-listview": "^0.1.8",
|
||||
"react-grid-gallery": "^0.5.5",
|
||||
"react-grid-layout": "^1.3.0",
|
||||
"react-i18next": "^11.12.0",
|
||||
"react-i18next": "^11.14.2",
|
||||
"react-icons": "^4.3.1",
|
||||
"react-number-format": "^4.7.3",
|
||||
"react-redux": "^7.2.5",
|
||||
"react-number-format": "^4.8.0",
|
||||
"react-redux": "^7.2.6",
|
||||
"react-resizable": "^3.0.4",
|
||||
"react-router-dom": "^5.3.0",
|
||||
"react-scripts": "^4.0.3",
|
||||
"react-sublime-video": "^0.2.5",
|
||||
"react-virtualized": "^9.22.3",
|
||||
"recharts": "^2.1.5",
|
||||
"redux": "^4.1.1",
|
||||
"recharts": "^2.1.6",
|
||||
"redux": "^4.1.2",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-saga": "^1.1.3",
|
||||
"redux-state-sync": "^3.1.2",
|
||||
"reselect": "^4.0.0",
|
||||
"sass": "^1.43.3",
|
||||
"reselect": "^4.1.2",
|
||||
"sass": "^1.43.4",
|
||||
"socket.io-client": "^4.3.2",
|
||||
"styled-components": "^5.3.3",
|
||||
"subscriptions-transport-ws": "^0.9.18",
|
||||
"subscriptions-transport-ws": "^0.11.0",
|
||||
"web-vitals": "^2.1.2",
|
||||
"workbox-background-sync": "^6.3.0",
|
||||
"workbox-broadcast-update": "^6.3.0",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ShrinkOutlined } from "@ant-design/icons";
|
||||
import { Col, Row, Typography } from "antd";
|
||||
import { ShrinkOutlined, InfoCircleOutlined } from "@ant-design/icons";
|
||||
import { Col, Row, Tooltip, Typography } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -31,6 +31,9 @@ export function ChatPopupComponent({
|
||||
{t("messaging.labels.messaging")}
|
||||
</Typography.Title>
|
||||
<ChatNewConversation />
|
||||
<Tooltip title={t("messaging.labels.recentonly")}>
|
||||
<InfoCircleOutlined />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<ShrinkOutlined
|
||||
onClick={() => toggleChatVisible()}
|
||||
|
||||
@@ -42,7 +42,6 @@ export default function ContractFormComponent({
|
||||
<ContractStatusSelector />
|
||||
</Form.Item>
|
||||
)}
|
||||
|
||||
<Form.Item
|
||||
label={t("contracts.fields.start")}
|
||||
name="start"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Button, Table, Col , Checkbox} from "antd";
|
||||
import { Button, Table, Col, Checkbox } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -23,15 +23,26 @@ export function DmsCustomerSelector({ bodyshop }) {
|
||||
const [customerList, setcustomerList] = useState([]);
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [selectedCustomer, setSelectedCustomer] = useState(null);
|
||||
const [dmsType, setDmsType] = useState("cdk");
|
||||
|
||||
socket.on("cdk-select-customer", (customerList, callback) => {
|
||||
setVisible(true);
|
||||
setDmsType("cdk");
|
||||
setcustomerList(customerList);
|
||||
});
|
||||
socket.on("pbs-select-customer", (customerList, callback) => {
|
||||
setVisible(true);
|
||||
setDmsType("pbs");
|
||||
setcustomerList(customerList);
|
||||
console.log(
|
||||
"🚀 ~ file: dms-customer-selector.component.jsx ~ line 37 ~ socket.on ~ customerList",
|
||||
customerList
|
||||
);
|
||||
});
|
||||
|
||||
const onUseSelected = () => {
|
||||
setVisible(false);
|
||||
socket.emit("cdk-selected-customer", selectedCustomer);
|
||||
socket.emit(`${dmsType}-selected-customer`, selectedCustomer);
|
||||
setSelectedCustomer(null);
|
||||
};
|
||||
|
||||
@@ -50,7 +61,7 @@ export function DmsCustomerSelector({ bodyshop }) {
|
||||
setSelectedCustomer(null);
|
||||
};
|
||||
|
||||
const columns = [
|
||||
const cdkColumns = [
|
||||
{
|
||||
title: t("jobs.fields.dms.id"),
|
||||
dataIndex: ["id", "value"],
|
||||
@@ -60,13 +71,14 @@ export function DmsCustomerSelector({ bodyshop }) {
|
||||
title: t("jobs.fields.dms.vinowner"),
|
||||
dataIndex: "vinOwner",
|
||||
key: "vinOwner",
|
||||
render: (text, record) => <Checkbox disabled checked={record.vinOwner}/>
|
||||
render: (text, record) => <Checkbox disabled checked={record.vinOwner} />,
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.dms.name1"),
|
||||
dataIndex: ["name1", "fullName"],
|
||||
key: "name1",
|
||||
sorter: (a, b) => alphaSort(a.name1?.fullName, b.name1?.fullName),
|
||||
sorter: (a, b) =>
|
||||
alphaSort(a.name1 && a.name1.fullName, b.name1 && b.name1.fullName),
|
||||
},
|
||||
|
||||
{
|
||||
@@ -74,11 +86,43 @@ export function DmsCustomerSelector({ bodyshop }) {
|
||||
//dataIndex: ["name2", "fullName"],
|
||||
key: "address",
|
||||
render: (record, value) =>
|
||||
`${record?.address?.addressLine[0]}, ${record.address?.city} ${record.address?.stateOrProvince} ${record.address?.postalCode}`,
|
||||
`${record.address && record.address.addressLine[0]}, ${
|
||||
record.address && record.address.city
|
||||
} ${record.address && record.address.stateOrProvince} ${
|
||||
record.address && record.address.postalCode
|
||||
}`,
|
||||
},
|
||||
];
|
||||
|
||||
if (!visible) return <></>;
|
||||
const pbsColumns = [
|
||||
{
|
||||
title: t("jobs.fields.dms.id"),
|
||||
dataIndex: "ContactId",
|
||||
key: "ContactId",
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.dms.vinowner"),
|
||||
dataIndex: "vinOwner",
|
||||
key: "vinOwner",
|
||||
render: (text, record) => <Checkbox disabled checked={record.vinOwner} />,
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.dms.name1"),
|
||||
key: "name1",
|
||||
sorter: (a, b) => alphaSort(a.LastName, b.LastName),
|
||||
render: (text, record) =>
|
||||
`${record.FirstName || ""} ${record.LastName || ""}`,
|
||||
},
|
||||
|
||||
{
|
||||
title: t("jobs.fields.dms.address"),
|
||||
key: "address",
|
||||
render: (record, value) =>
|
||||
`${record.Address}, ${record.City} ${record.State} ${record.ZipCode}`,
|
||||
},
|
||||
];
|
||||
|
||||
if (!visible) return null;
|
||||
return (
|
||||
<Col span={24}>
|
||||
<Table
|
||||
@@ -104,13 +148,17 @@ export function DmsCustomerSelector({ bodyshop }) {
|
||||
</div>
|
||||
)}
|
||||
pagination={{ position: "top" }}
|
||||
columns={columns}
|
||||
rowKey={(record) => record.id.value}
|
||||
columns={dmsType === "cdk" ? cdkColumns : pbsColumns}
|
||||
rowKey={(record) =>
|
||||
dmsType === "cdk" ? record.id.value : record.ContactId
|
||||
}
|
||||
dataSource={customerList}
|
||||
//onChange={handleTableChange}
|
||||
rowSelection={{
|
||||
onSelect: (props) => {
|
||||
setSelectedCustomer(props.id.value);
|
||||
onSelect: (record) => {
|
||||
setSelectedCustomer(
|
||||
dmsType === "cdk" ? record.id.value : record.ContactId
|
||||
);
|
||||
},
|
||||
type: "radio",
|
||||
selectedRowKeys: [selectedCustomer],
|
||||
|
||||
@@ -119,33 +119,35 @@ export function DmsPostForm({ bodyshop, socket, job }) {
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
|
||||
<LayoutFormRow style={{ justifyContent: "center" }} grow>
|
||||
<Form.Item
|
||||
name="dms_make"
|
||||
label={t("jobs.fields.dms.dms_make")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="dms_model"
|
||||
label={t("jobs.fields.dms.dms_model")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
{bodyshop.cdk_dealerid && (
|
||||
<LayoutFormRow style={{ justifyContent: "center" }} grow>
|
||||
<Form.Item
|
||||
name="dms_make"
|
||||
label={t("jobs.fields.dms.dms_make")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="dms_model"
|
||||
label={t("jobs.fields.dms.dms_model")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
|
||||
<DmsCdkMakes form={form} socket={socket} job={job} />
|
||||
<DmsCdkMakesRefetch />
|
||||
</LayoutFormRow>
|
||||
<DmsCdkMakes form={form} socket={socket} job={job} />
|
||||
<DmsCdkMakesRefetch />
|
||||
</LayoutFormRow>
|
||||
)}
|
||||
<Form.Item
|
||||
name="story"
|
||||
label={t("jobs.fields.dms.story")}
|
||||
@@ -157,6 +159,7 @@ export function DmsPostForm({ bodyshop, socket, job }) {
|
||||
>
|
||||
<Input.TextArea maxLength={240} />
|
||||
</Form.Item>
|
||||
|
||||
<Divider />
|
||||
<Form.List name={["payers"]}>
|
||||
{(fields, { add, remove }) => {
|
||||
|
||||
@@ -1,15 +1,71 @@
|
||||
import { UploadOutlined } from "@ant-design/icons";
|
||||
import { Divider, Form, Input, Select, Tabs, Upload } from "antd";
|
||||
import { UploadOutlined, UserAddOutlined } from "@ant-design/icons";
|
||||
import {
|
||||
Divider,
|
||||
Form,
|
||||
Input,
|
||||
Select,
|
||||
Tabs,
|
||||
Upload,
|
||||
Space,
|
||||
Menu,
|
||||
Dropdown,
|
||||
} from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import EmailDocumentsComponent from "../email-documents/email-documents.component";
|
||||
import _ from "lodash";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(EmailOverlayComponent);
|
||||
|
||||
export default function EmailOverlayComponent({ form, selectedMediaState }) {
|
||||
export function EmailOverlayComponent({ form, selectedMediaState, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
const handleClick = ({ item, key, keyPath }) => {
|
||||
const email = item.props.value;
|
||||
form.setFieldsValue({ to: _.uniq([...form.getFieldValue("to"), email]) });
|
||||
};
|
||||
|
||||
const menu = (
|
||||
<div>
|
||||
<Menu onClick={handleClick}>
|
||||
{bodyshop.employees
|
||||
.filter((e) => e.user_email)
|
||||
.map((e, idx) => (
|
||||
<Menu.Item value={e.user_email} key={idx}>
|
||||
{`${e.first_name} ${e.last_name}`}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form.Item
|
||||
label={t("emails.fields.to")}
|
||||
label={
|
||||
<Space>
|
||||
{t("emails.fields.to")}
|
||||
<Dropdown overlay={menu}>
|
||||
<a
|
||||
className="ant-dropdown-link"
|
||||
href=" #"
|
||||
onClick={(e) => e.preventDefault()}
|
||||
>
|
||||
<UserAddOutlined />
|
||||
</a>
|
||||
</Dropdown>
|
||||
</Space>
|
||||
}
|
||||
name="to"
|
||||
rules={[
|
||||
{
|
||||
|
||||
@@ -7,10 +7,12 @@ import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import moment from "moment";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setEmailOptions: (e) => dispatch(setEmailOptions(e)),
|
||||
});
|
||||
@@ -24,9 +26,20 @@ export function EmailTestComponent({ currentUser, setEmailOptions }) {
|
||||
{
|
||||
name: values.key,
|
||||
variables: {
|
||||
...(values.start
|
||||
? {
|
||||
start: moment(values.start).startOf("day").format("YYYY-MM-DD"),
|
||||
}
|
||||
: {}),
|
||||
...(values.end
|
||||
? { end: moment(values.end).endOf("day").format("YYYY-MM-DD") }
|
||||
: {}),
|
||||
...(values.start
|
||||
? { starttz: moment(values.start).startOf("day") }
|
||||
: {}),
|
||||
...(values.end ? { endtz: moment(values.end).endOf("day") } : {}),
|
||||
|
||||
...(values.id ? { id: values.id } : {}),
|
||||
...(values.start ? { start: values.start } : {}),
|
||||
...(values.end ? { end: values.end } : {}),
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -46,12 +46,16 @@ import {
|
||||
} from "../../redux/application/application.selectors";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { signOutStart } from "../../redux/user/user.actions";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
recentItems: selectRecentItems,
|
||||
selectedHeader: selectSelectedHeader,
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
@@ -69,6 +73,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
function Header({
|
||||
handleMenuClick,
|
||||
currentUser,
|
||||
bodyshop,
|
||||
selectedHeader,
|
||||
signOutStart,
|
||||
setBillEnterContext,
|
||||
@@ -237,16 +242,26 @@ function Header({
|
||||
{t("menus.header.accounting-receivables")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="payables">
|
||||
<Link to="/manage/accounting/payables">
|
||||
{t("menus.header.accounting-payables")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.Item key="payments">
|
||||
<Link to="/manage/accounting/payments">
|
||||
{t("menus.header.accounting-payments")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
{!(
|
||||
(bodyshop && bodyshop.cdk_dealerid) ||
|
||||
(bodyshop && bodyshop.pbs_serialnumber)
|
||||
) && (
|
||||
<Menu.Item key="payables">
|
||||
<Link to="/manage/accounting/payables">
|
||||
{t("menus.header.accounting-payables")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
)}
|
||||
{!(
|
||||
(bodyshop && bodyshop.cdk_dealerid) ||
|
||||
(bodyshop && bodyshop.pbs_serialnumber)
|
||||
) && (
|
||||
<Menu.Item key="payments">
|
||||
<Link to="/manage/accounting/payments">
|
||||
{t("menus.header.accounting-payments")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
)}
|
||||
<Menu.Item key="export-logs">
|
||||
<Link to="/manage/accounting/exportlogs">
|
||||
{t("menus.header.export-logs")}
|
||||
|
||||
@@ -73,7 +73,7 @@ export const reconcileByPrice = (
|
||||
|
||||
jobLines.forEach((jl) => {
|
||||
const matchingBillLineIds = billLines
|
||||
.filter((bl) => bl.actual_price === jl.act_price && !jl.removed)
|
||||
.filter((bl) => bl.actual_price === jl.act_price && bl.quantity === jl.part_qty && !jl.removed)
|
||||
.map((bl) => bl.id);
|
||||
|
||||
if (matchingBillLineIds.length > 1) {
|
||||
|
||||
@@ -61,7 +61,7 @@ export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
|
||||
);
|
||||
};
|
||||
|
||||
const overlay = bodyshop.cdk_dealerid && (
|
||||
const overlay = (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Menu onClick={handleMenuClick}>
|
||||
{bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => (
|
||||
<Menu.Item key={mapping.name}>{mapping.name}</Menu.Item>
|
||||
@@ -69,7 +69,7 @@ export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
|
||||
</Menu>
|
||||
);
|
||||
|
||||
return bodyshop.cdk_dealerid ? (
|
||||
return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? (
|
||||
<Dropdown overlay={overlay}>
|
||||
<Button disabled={disabled}>{t("jobs.actions.dmsautoallocate")}</Button>
|
||||
</Dropdown>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { DownOutlined } from "@ant-design/icons";
|
||||
import { Dropdown, Menu } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
@@ -11,8 +10,6 @@ const mapStateToProps = createStructuredSelector({
|
||||
});
|
||||
|
||||
export function JobsDetailChangeEstimator({ disabled, form, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleClick = ({ item, key, keyPath }) => {
|
||||
const est = item.props.value;
|
||||
form.setFieldsValue(est);
|
||||
@@ -37,7 +34,7 @@ export function JobsDetailChangeEstimator({ disabled, form, bodyshop }) {
|
||||
href=" #"
|
||||
onClick={(e) => e.preventDefault()}
|
||||
>
|
||||
{t("jobs.actions.changestimator")} <DownOutlined />
|
||||
<DownOutlined />
|
||||
</a>
|
||||
</Dropdown>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { DownOutlined } from "@ant-design/icons";
|
||||
import { Dropdown, Menu } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
export function JobsDetailChangeFilehandler({ disabled, form, bodyshop }) {
|
||||
const handleClick = ({ item, key, keyPath }) => {
|
||||
const est = item.props.value;
|
||||
form.setFieldsValue(est);
|
||||
};
|
||||
|
||||
const menu = (
|
||||
<div>
|
||||
<Menu onClick={handleClick}>
|
||||
{bodyshop.md_filehandlers.map((est, idx) => (
|
||||
<Menu.Item value={est} key={idx}>
|
||||
{`${est.ins_ct_fn} ${est.ins_ct_ln}`}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Dropdown overlay={menu} disabled={disabled}>
|
||||
<a
|
||||
className="ant-dropdown-link"
|
||||
href=" #"
|
||||
onClick={(e) => e.preventDefault()}
|
||||
>
|
||||
<DownOutlined />
|
||||
</a>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(JobsDetailChangeFilehandler);
|
||||
@@ -75,6 +75,12 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
|
||||
>
|
||||
<DateTimePicker />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.date_next_contact")}
|
||||
name="date_next_contact"
|
||||
>
|
||||
<DateTimePicker />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.scheduled_completion")}
|
||||
name="scheduled_completion"
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
InputNumber,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Switch,
|
||||
} from "antd";
|
||||
import React from "react";
|
||||
@@ -23,7 +24,7 @@ import FormItemPhone, {
|
||||
import Car from "../job-damage-visual/job-damage-visual.component";
|
||||
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
|
||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||
|
||||
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -85,7 +86,15 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
<Form.Item label={t("jobs.fields.ins_city")} name="ins_city">
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.ins_ct_ln")} name="ins_ct_ln">
|
||||
<Form.Item
|
||||
label={
|
||||
<Space>
|
||||
{t("jobs.fields.ins_ct_ln")}
|
||||
<JobsDetailChangeFileHandler form={form} disabled={jobRO} />
|
||||
</Space>
|
||||
}
|
||||
name="ins_ct_ln"
|
||||
>
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.ins_ct_fn")} name="ins_ct_fn">
|
||||
@@ -135,7 +144,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
label={t("jobs.fields.referral_source_extra")}
|
||||
name="referral_source_extra"
|
||||
>
|
||||
<Input />
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.alt_transport")} name="alt_transport">
|
||||
<Select disabled={jobRO} allowClear>
|
||||
@@ -219,12 +228,19 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
{t("jobs.forms.appraiserinfo")}
|
||||
</Divider>
|
||||
|
||||
<JobsDetailChangeEstimator form={form} disabled={jobRO} />
|
||||
<FormRow noDivider>
|
||||
<Form.Item label={t("jobs.fields.est_co_nm")} name="est_co_nm">
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.est_ct_fn")} name="est_ct_fn">
|
||||
<Form.Item
|
||||
label={
|
||||
<Space>
|
||||
{t("jobs.fields.est_ct_fn")}
|
||||
<JobsDetailChangeEstimator form={form} disabled={jobRO} />
|
||||
</Space>
|
||||
}
|
||||
name="est_ct_fn"
|
||||
>
|
||||
<Input disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.est_ct_ln")} name="est_ct_ln">
|
||||
|
||||
@@ -3,17 +3,17 @@ import { notification } from "antd";
|
||||
import React, { useState } from "react";
|
||||
//import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import {
|
||||
DELETE_NOTE,
|
||||
QUERY_NOTES_BY_JOB_PK,
|
||||
} from "../../graphql/notes.queries";
|
||||
import JobNotesComponent from "./jobs.notes.component";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import JobNotesComponent from "./jobs.notes.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -63,6 +63,7 @@ export function JobNotesContainer({ jobId, insertAuditTrail }) {
|
||||
refetch={refetch}
|
||||
deleteLoading={deleteLoading}
|
||||
handleNoteDelete={handleNoteDelete}
|
||||
ro_number={data ? data.jobs_by_pk.ro_number : null}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container";
|
||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
@@ -33,8 +35,12 @@ export function JobNotesComponent({
|
||||
jobId,
|
||||
setNoteUpsertContext,
|
||||
deleteLoading,
|
||||
ro_number,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const Templates = TemplateList("job_special", {
|
||||
ro_number,
|
||||
});
|
||||
|
||||
const columns = [
|
||||
{
|
||||
@@ -107,6 +113,18 @@ export function JobNotesComponent({
|
||||
>
|
||||
<EditFilled />
|
||||
</Button>
|
||||
<PrintWrapperComponent
|
||||
emailOnly
|
||||
templateObject={{
|
||||
name: Templates.individual_job_note.key,
|
||||
|
||||
variables: { id: record.id },
|
||||
}}
|
||||
messageObject={{
|
||||
subject: Templates.individual_job_note.subject,
|
||||
}}
|
||||
id={record.id}
|
||||
/>
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -119,7 +119,7 @@ export function PartsOrderListTableComponent({
|
||||
</Button>
|
||||
<Popconfirm
|
||||
title={t("parts_orders.labels.confirmdelete")}
|
||||
disabled={jobRO || !record.return}
|
||||
disabled={jobRO}
|
||||
onConfirm={async () => {
|
||||
//Delete the parts return.!
|
||||
|
||||
@@ -139,7 +139,7 @@ export function PartsOrderListTableComponent({
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Button disabled={jobRO || !record.return}>
|
||||
<Button disabled={jobRO}>
|
||||
<DeleteFilled />
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
|
||||
@@ -8,6 +8,7 @@ export default function PrintWrapperComponent({
|
||||
messageObject = {},
|
||||
children,
|
||||
id,
|
||||
emailOnly = false,
|
||||
}) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handlePrint = async (type) => {
|
||||
@@ -19,7 +20,7 @@ export default function PrintWrapperComponent({
|
||||
return (
|
||||
<Space>
|
||||
{children || null}
|
||||
<PrinterFilled onClick={() => handlePrint("p")} />
|
||||
{!emailOnly && <PrinterFilled onClick={() => handlePrint("p")} />}
|
||||
<MailFilled onClick={() => handlePrint("e")} />
|
||||
{loading && <Spin />}
|
||||
</Space>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Input, PageHeader, Space, Spin } from "antd";
|
||||
import { Input, Space, Spin } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -26,8 +26,7 @@ export function ProductionBoardFilters({
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<PageHeader
|
||||
extra={
|
||||
|
||||
<Space wrap>
|
||||
{loading && <Spin />}
|
||||
<Input.Search
|
||||
@@ -46,7 +45,6 @@ export function ProductionBoardFilters({
|
||||
allowClear
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
></PageHeader>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,106 +1,171 @@
|
||||
import { CalendarOutlined, EyeFilled } from "@ant-design/icons";
|
||||
import { Card, Col, Row, Space } from "antd";
|
||||
import React from "react";
|
||||
import { Card, Row, Col, Dropdown } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import ProductionAlert from "../production-list-columns/production-list-columns.alert.component";
|
||||
import { EyeFilled } from "@ant-design/icons";
|
||||
import { Link } from "react-router-dom";
|
||||
import "./production-board-card.styles.scss";
|
||||
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
||||
import ProductionListColumnProductionNote from "../production-list-columns/production-list-columns.productionnote.component";
|
||||
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
||||
import "./production-board-card.styles.scss";
|
||||
|
||||
export default function ProductionBoardCard(technician, card) {
|
||||
export default function ProductionBoardCard(
|
||||
technician,
|
||||
card,
|
||||
bodyshop,
|
||||
cardSettings
|
||||
) {
|
||||
const { t } = useTranslation();
|
||||
const menu = (
|
||||
<div>
|
||||
<Card title={t("general.labels.actions")}>
|
||||
<ProductionRemoveButton jobId={card.id} />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
||||
let employee_body, employee_prep, employee_refinish; //employee_csr;
|
||||
if (card.employee_body) {
|
||||
employee_body = bodyshop.employees.find((e) => e.id === card.employee_body);
|
||||
}
|
||||
if (card.employee_prep) {
|
||||
employee_prep = bodyshop.employees.find((e) => e.id === card.employee_prep);
|
||||
}
|
||||
if (card.employee_refinish) {
|
||||
employee_refinish = bodyshop.employees.find(
|
||||
(e) => e.id === card.employee_refinish
|
||||
);
|
||||
}
|
||||
// if (card.employee_csr) {
|
||||
// employee_csr = bodyshop.employees.find((e) => e.id === card.employee_csr);
|
||||
// }
|
||||
|
||||
return (
|
||||
<Dropdown overlay={menu} trigger={["contextMenu"]}>
|
||||
<Card
|
||||
className="react-kanban-card imex-kanban-card tight-antd-rows"
|
||||
//style={{ margin: ".2rem 0rem" }}
|
||||
title={`${card.ro_number || t("general.labels.na")} - ${
|
||||
card.v_model_yr
|
||||
} ${card.v_make_desc || ""} ${card.v_model_desc || ""}`}
|
||||
>
|
||||
<Row>
|
||||
<Card
|
||||
className="react-kanban-card imex-kanban-card"
|
||||
size="small"
|
||||
title={
|
||||
<Space>
|
||||
<ProductionAlert record={card} key="alert" />
|
||||
<span style={{ fontWeight: "bolder" }}>
|
||||
{card.ro_number || t("general.labels.na")}
|
||||
</span>
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
technician ? (
|
||||
<Link to={`/tech/joblookup?selected=${card.id}`}>
|
||||
<EyeFilled />
|
||||
</Link>
|
||||
) : (
|
||||
<Link to={`/manage/jobs/${card.id}`}>
|
||||
<EyeFilled />
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
>
|
||||
<Row>
|
||||
{cardSettings && cardSettings.ownr_nm && (
|
||||
<Col span={24}>
|
||||
<div className="ellipses">{`${card.ownr_fn || ""} ${
|
||||
card.ownr_ln || ""
|
||||
} ${card.ownr_co_nm || ""}`}</div>
|
||||
{cardSettings && cardSettings.compact ? (
|
||||
<div className="ellipses">{`${card.ownr_ln || ""} ${
|
||||
card.ownr_co_nm || ""
|
||||
}`}</div>
|
||||
) : (
|
||||
<div className="ellipses">{`${card.ownr_ln || ""}, ${
|
||||
card.ownr_fn || ""
|
||||
} ${card.ownr_co_nm || ""}`}</div>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={12}>
|
||||
<div className="ellipses">{card.clm_no || ""}</div>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
)}
|
||||
<Col span={24}>
|
||||
<div className="ellipses">{`${card.v_model_yr || ""} ${
|
||||
card.v_make_desc || ""
|
||||
} ${card.v_model_desc || ""}`}</div>
|
||||
</Col>
|
||||
{cardSettings && cardSettings.ins_co_nm && card.ins_co_nm && (
|
||||
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
|
||||
<div className="ellipses">{card.ins_co_nm || ""}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
)}
|
||||
{cardSettings && cardSettings.clm_no && card.clm_no && (
|
||||
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
|
||||
<div className="ellipses">{card.clm_no || ""}</div>
|
||||
</Col>
|
||||
)}
|
||||
|
||||
{cardSettings && cardSettings.employeeassignments && (
|
||||
<Col span={24}>
|
||||
<div className="imex-flex-row imex-flex-row__flex-space-around">
|
||||
<div className="mex-flex-row__margin">
|
||||
<div>{`B: ${card.labhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
|
||||
<div>{`R: ${card.larhrs.aggregate.sum.mod_lb_hrs || "?"}`}</div>
|
||||
</div>
|
||||
<div className="mex-flex-row__margin">
|
||||
<div>{`B: ${
|
||||
card.employee_body_rel
|
||||
? `${card.employee_body_rel.first_name} ${card.employee_body_rel.last_name}`
|
||||
: ""
|
||||
}`}</div>
|
||||
<div>{`P: ${
|
||||
card.employee_prep_rel
|
||||
? `${card.employee_prep_rel.first_name} ${card.employee_prep_rel.last_name}`
|
||||
: ""
|
||||
}`}</div>
|
||||
<div>{`R: ${
|
||||
card.employee_refinish_rel
|
||||
? `${card.employee_refinish_rel.first_name} ${card.employee_refinish_rel.last_name}`
|
||||
: ""
|
||||
}`}</div>
|
||||
<div>{`CSR: ${
|
||||
card.employee_csr_rel
|
||||
? `${card.employee_csr_rel.first_name} ${card.employee_csr_rel.last_name}`
|
||||
: ""
|
||||
}`}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Row>
|
||||
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`B: ${
|
||||
employee_body
|
||||
? `${employee_body.first_name.substr(
|
||||
0,
|
||||
3
|
||||
)} ${employee_body.last_name.charAt(0)}`
|
||||
: ""
|
||||
} ${card.labhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
|
||||
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`P: ${
|
||||
employee_prep
|
||||
? `${employee_prep.first_name.substr(
|
||||
0,
|
||||
3
|
||||
)} ${employee_prep.last_name.charAt(0)}`
|
||||
: ""
|
||||
}`}</Col>
|
||||
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`R: ${
|
||||
employee_refinish
|
||||
? `${employee_refinish.first_name.substr(
|
||||
0,
|
||||
3
|
||||
)} ${employee_refinish.last_name.charAt(0)}`
|
||||
: ""
|
||||
} ${card.larhrs.aggregate.sum.mod_lb_hrs || "?"}h`}</Col>
|
||||
{/* <Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`C: ${
|
||||
employee_csr
|
||||
? `${employee_csr.first_name} ${employee_csr.last_name}`
|
||||
: ""
|
||||
}`}</Col> */}
|
||||
</Row>
|
||||
</Col>
|
||||
</Row>
|
||||
<Row>
|
||||
<Col span={18}>
|
||||
<DateTimeFormatter>{card.scheduled_completion}</DateTimeFormatter>
|
||||
)}
|
||||
{/* {cardSettings && cardSettings.laborhrs && (
|
||||
<Col span={24}>
|
||||
<Row>
|
||||
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`B: ${
|
||||
card.labhrs.aggregate.sum.mod_lb_hrs || "?"
|
||||
} hrs`}</Col>
|
||||
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>{`R: ${
|
||||
card.larhrs.aggregate.sum.mod_lb_hrs || "?"
|
||||
} hrs`}</Col>
|
||||
</Row>
|
||||
</Col>
|
||||
<Col span={6}>
|
||||
)} */}
|
||||
{cardSettings &&
|
||||
cardSettings.scheduled_completion &&
|
||||
card.scheduled_completion && (
|
||||
<Col span={cardSettings && cardSettings.compact ? 24 : 12}>
|
||||
<Space>
|
||||
<CalendarOutlined />
|
||||
<DateTimeFormatter format="MM/DD">
|
||||
{card.scheduled_completion}
|
||||
</DateTimeFormatter>
|
||||
</Space>
|
||||
</Col>
|
||||
)}
|
||||
{cardSettings && cardSettings.ats && card.alt_transport && (
|
||||
<Col span={12}>
|
||||
<div>{card.alt_transport || ""}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<div>
|
||||
<ProductionListColumnProductionNote record={card} />
|
||||
</div>
|
||||
<div className="imex-flex-row imex-flex-row__flex-space-around">
|
||||
<ProductionAlert record={card} key="alert" />
|
||||
<ProductionSubletsManageComponent subletJobLines={card.subletLines} />
|
||||
{technician ? (
|
||||
<Link to={`/tech/joblookup?selected=${card.id}`}>
|
||||
<EyeFilled />
|
||||
</Link>
|
||||
) : (
|
||||
<Link to={`/manage/jobs/${card.id}`}>
|
||||
<EyeFilled />
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</Dropdown>
|
||||
)}
|
||||
{cardSettings && cardSettings.sublets && (
|
||||
<Col span={12}>
|
||||
<ProductionSubletsManageComponent
|
||||
subletJobLines={card.subletLines}
|
||||
/>
|
||||
</Col>
|
||||
)}
|
||||
{cardSettings && cardSettings.production_note && (
|
||||
<Col span={24}>
|
||||
{cardSettings && cardSettings.production_note && (
|
||||
<ProductionListColumnProductionNote record={card} />
|
||||
)}
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
Col,
|
||||
Form,
|
||||
notification,
|
||||
Popover,
|
||||
Row,
|
||||
Switch,
|
||||
} from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
||||
|
||||
export default function ProductionBoardKanbanCardSettings({
|
||||
associationSettings,
|
||||
}) {
|
||||
const [form] = Form.useForm();
|
||||
const [visible, setVisible] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [updateKbSettings] = useMutation(UPDATE_KANBAN_SETTINGS);
|
||||
|
||||
useEffect(() => {
|
||||
form.setFieldsValue(
|
||||
associationSettings && associationSettings.kanban_settings
|
||||
);
|
||||
}, [form, associationSettings, visible]);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
const result = await updateKbSettings({
|
||||
variables: {
|
||||
id: associationSettings && associationSettings.id,
|
||||
ks: values,
|
||||
},
|
||||
});
|
||||
if (result.errors) {
|
||||
notification.open({
|
||||
type: "error",
|
||||
message: t("production.errors.settings", {
|
||||
error: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
setVisible(false);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
const overlay = (
|
||||
<div>
|
||||
<Card>
|
||||
<Form form={form} onFinish={handleFinish} layout="vertical">
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
label={t("production.labels.compact")}
|
||||
name="compact"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.ownr_nm")}
|
||||
name="ownr_nm"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.clm_no")}
|
||||
name="clm_no"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.ins_co_nm")}
|
||||
name="ins_co_nm"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
{/* <Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.laborhrs")}
|
||||
name="laborhrs"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item> */}
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.employeeassignments")}
|
||||
name="employeeassignments"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.scheduled_completion")}
|
||||
name="scheduled_completion"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.ats")}
|
||||
name="ats"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.production_note")}
|
||||
name="production_note"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
{/* <Form.Item
|
||||
valuePropName='checked' label={t("production.labels.alert")} name="alert">
|
||||
<Switch/>
|
||||
</Form.Item> */}
|
||||
<Form.Item
|
||||
valuePropName="checked"
|
||||
label={t("production.labels.sublets")}
|
||||
name="sublets"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
<Button
|
||||
onClick={() => {
|
||||
form.submit();
|
||||
}}
|
||||
>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<Popover content={overlay} visible={visible}>
|
||||
<Button loading={loading} onClick={() => setVisible(true)}>
|
||||
{t("production.labels.cardsettings")}
|
||||
</Button>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
import { useApolloClient } from "@apollo/client";
|
||||
import Board, { moveCard } from "@lourenci/react-kanban";
|
||||
import "@lourenci/react-kanban/dist/styles.css";
|
||||
import { notification } from "antd";
|
||||
import Board, { moveCard } from "@asseinfo/react-kanban";
|
||||
//import "@asseinfo/react-kanban/dist/styles.css";
|
||||
import "./production-board-kanban.styles.scss";
|
||||
import { Grid, notification, PageHeader, Space, Statistic } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -16,6 +17,8 @@ import ProductionBoardFilters from "../production-board-filters/production-board
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-settings.component";
|
||||
import styled from "styled-components";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -32,6 +35,7 @@ export function ProductionBoardKanbanComponent({
|
||||
bodyshop,
|
||||
technician,
|
||||
insertAuditTrail,
|
||||
associationSettings,
|
||||
}) {
|
||||
const [boardLanes, setBoardLanes] = useState({
|
||||
columns: [{ id: "Loading...", title: "Loading...", cards: [] }],
|
||||
@@ -116,6 +120,7 @@ export function ProductionBoardKanbanComponent({
|
||||
newChildCard ? newChildCard.id : null,
|
||||
newChildCardNewParent
|
||||
),
|
||||
// TODO: optimisticResponse
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: card.id,
|
||||
@@ -131,21 +136,112 @@ export function ProductionBoardKanbanComponent({
|
||||
}
|
||||
};
|
||||
|
||||
const totalHrs = data
|
||||
.reduce(
|
||||
(acc, val) =>
|
||||
acc +
|
||||
(val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0) +
|
||||
(val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0),
|
||||
0
|
||||
)
|
||||
.toFixed(1);
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
.filter((screen) => !!screen[1])
|
||||
.slice(-1)[0];
|
||||
|
||||
const standardSizes = {
|
||||
xs: "250",
|
||||
sm: "250",
|
||||
md: "250",
|
||||
lg: "250",
|
||||
xl: "250",
|
||||
xxl: "250",
|
||||
};
|
||||
const compactSizes = {
|
||||
xs: "150",
|
||||
sm: "150",
|
||||
md: "150",
|
||||
lg: "150",
|
||||
xl: "155",
|
||||
xxl: "155",
|
||||
};
|
||||
|
||||
const width = selectedBreakpoint
|
||||
? associationSettings &&
|
||||
associationSettings.kanban_settings &&
|
||||
associationSettings.kanban_settings.compact
|
||||
? compactSizes[selectedBreakpoint[0]]
|
||||
: standardSizes[selectedBreakpoint[0]]
|
||||
: "250";
|
||||
|
||||
const Container = styled.div`
|
||||
.react-kanban-card-skeleton,
|
||||
.react-kanban-card,
|
||||
.react-kanban-card-adder-form {
|
||||
box-sizing: border-box;
|
||||
max-width: ${width}px;
|
||||
min-width: ${width}px;
|
||||
}
|
||||
`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Container>
|
||||
<IndefiniteLoading loading={isMoving} />
|
||||
<ProductionBoardFilters
|
||||
filter={filter}
|
||||
setFilter={setFilter}
|
||||
loading={isMoving}
|
||||
<PageHeader
|
||||
title={
|
||||
<Space>
|
||||
<Statistic
|
||||
title={t("dashboard.titles.productionhours")}
|
||||
value={totalHrs}
|
||||
/>
|
||||
<Statistic
|
||||
title={t("appointments.labels.inproduction")}
|
||||
value={data && data.length}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
<Space wrap>
|
||||
<ProductionBoardFilters
|
||||
filter={filter}
|
||||
setFilter={setFilter}
|
||||
loading={isMoving}
|
||||
/>
|
||||
<ProductionBoardKanbanCardSettings
|
||||
associationSettings={associationSettings}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
<Board
|
||||
children={boardLanes}
|
||||
disableCardDrag={isMoving}
|
||||
renderCard={(card) => ProductionBoardCard(technician, card)}
|
||||
renderCard={(card) =>
|
||||
ProductionBoardCard(
|
||||
technician,
|
||||
card,
|
||||
bodyshop,
|
||||
associationSettings &&
|
||||
associationSettings.kanban_settings &&
|
||||
Object.keys(associationSettings.kanban_settings).length > 0
|
||||
? associationSettings.kanban_settings
|
||||
: {
|
||||
ats: true,
|
||||
clm_no: true,
|
||||
compact: false,
|
||||
ownr_nm: true,
|
||||
sublets: true,
|
||||
ins_co_nm: true,
|
||||
production_note: true,
|
||||
employeeassignments: true,
|
||||
scheduled_completion: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
onCardDragEnd={handleDragEnd}
|
||||
/>
|
||||
</div>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
export default connect(
|
||||
|
||||
@@ -1,25 +1,40 @@
|
||||
import { useSubscription } from "@apollo/client";
|
||||
import { useQuery, useSubscription } from "@apollo/client";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { SUBSCRIPTION_JOBS_IN_PRODUCTION } from "../../graphql/jobs.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { QUERY_KANBAN_SETTINGS } from "../../graphql/user.queries";
|
||||
import {
|
||||
selectBodyshop,
|
||||
selectCurrentUser,
|
||||
} from "../../redux/user/user.selectors";
|
||||
import ProductionBoardKanbanComponent from "./production-board-kanban.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
currentUser: selectCurrentUser,
|
||||
});
|
||||
|
||||
export function ProductionBoardKanbanContainer({ bodyshop }) {
|
||||
export function ProductionBoardKanbanContainer({ bodyshop, currentUser }) {
|
||||
const { loading, data } = useSubscription(
|
||||
SUBSCRIPTION_JOBS_IN_PRODUCTION,
|
||||
{}
|
||||
);
|
||||
|
||||
const { loading: associationSettingsLoading, data: associationSettings } =
|
||||
useQuery(QUERY_KANBAN_SETTINGS, {
|
||||
variables: { email: currentUser.email },
|
||||
});
|
||||
|
||||
return (
|
||||
<ProductionBoardKanbanComponent
|
||||
loading={loading}
|
||||
loading={loading || associationSettingsLoading}
|
||||
data={data ? data.jobs : []}
|
||||
associationSettings={
|
||||
associationSettings && associationSettings.associations[0]
|
||||
? associationSettings.associations[0]
|
||||
: null
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
.react-kanban-board {
|
||||
padding: 5px;
|
||||
}
|
||||
.react-kanban-card {
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
padding: 4px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
// .react-kanban-card-skeleton,
|
||||
// .react-kanban-card,
|
||||
// .react-kanban-card-adder-form {
|
||||
// box-sizing: border-box;
|
||||
// max-width: 145px;
|
||||
// min-width: 145px;
|
||||
// }
|
||||
|
||||
.react-kanban-card--dragging {
|
||||
box-shadow: 2px 2px grey;
|
||||
}
|
||||
.react-kanban-card__description {
|
||||
padding-top: 10px;
|
||||
}
|
||||
.react-kanban-card__title {
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 5px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.react-kanban-column {
|
||||
padding: 10px;
|
||||
border-radius: 2px;
|
||||
background-color: #eee;
|
||||
margin: 5px;
|
||||
}
|
||||
.react-kanban-column input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.react-kanban-card-adder-form {
|
||||
border-radius: 3px;
|
||||
background-color: #fff;
|
||||
padding: 10px;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
.react-kanban-card-adder-form input {
|
||||
border: 0px;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
}
|
||||
.react-kanban-card-adder-button {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
background-color: transparent;
|
||||
cursor: pointer;
|
||||
border: 1px solid #ccc;
|
||||
transition: 0.3s;
|
||||
border-radius: 3px;
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.react-kanban-card-adder-button:hover {
|
||||
background-color: #ccc;
|
||||
}
|
||||
.react-kanban-card-adder-form__title {
|
||||
font-weight: bold;
|
||||
border-bottom: 1px solid #eee;
|
||||
padding-bottom: 5px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
padding: 0px;
|
||||
}
|
||||
.react-kanban-card-adder-form__title:focus {
|
||||
outline: none;
|
||||
}
|
||||
.react-kanban-card-adder-form__description {
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.react-kanban-card-adder-form__description:focus {
|
||||
outline: none;
|
||||
}
|
||||
.react-kanban-card-adder-form__button {
|
||||
background-color: #eee;
|
||||
border: none;
|
||||
padding: 5px;
|
||||
width: 45%;
|
||||
margin-top: 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.react-kanban-card-adder-form__button:hover {
|
||||
transition: 0.3s;
|
||||
cursor: pointer;
|
||||
background-color: #ccc;
|
||||
}
|
||||
.react-kanban-column-header {
|
||||
padding-bottom: 10px;
|
||||
font-weight: bold;
|
||||
}
|
||||
.react-kanban-column-header input:focus {
|
||||
outline: none;
|
||||
}
|
||||
.react-kanban-column-header__button {
|
||||
color: #333333;
|
||||
background-color: #ffffff;
|
||||
border-color: #cccccc;
|
||||
}
|
||||
.react-kanban-column-header__button:hover,
|
||||
.react-kanban-column-header__button:focus,
|
||||
.react-kanban-column-header__button:active {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
.react-kanban-column-adder-button {
|
||||
border: 2px dashed #eee;
|
||||
height: 132px;
|
||||
margin: 5px;
|
||||
}
|
||||
.react-kanban-column-adder-button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import i18n from "i18next";
|
||||
import moment from "moment";
|
||||
import React from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
@@ -11,11 +12,11 @@ import ProductionListColumnBodyPriority from "./production-list-columns.bodyprio
|
||||
import ProductionListDate from "./production-list-columns.date.component";
|
||||
import ProductionListColumnDetailPriority from "./production-list-columns.detailpriority.component";
|
||||
import ProductionListEmployeeAssignment from "./production-list-columns.empassignment.component";
|
||||
import ProductionListLastContacted from "./production-list-columns.lastcontacted.component";
|
||||
import ProductionListColumnPaintPriority from "./production-list-columns.paintpriority.component";
|
||||
import ProductionListColumnNote from "./production-list-columns.productionnote.component";
|
||||
import ProductionListColumnStatus from "./production-list-columns.status.component";
|
||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
||||
import ProductionListLastContacted from "./production-list-columns.lastcontacted.component";
|
||||
|
||||
const r = ({ technician, state, activeStatuses }) => {
|
||||
return [
|
||||
@@ -109,6 +110,29 @@ const r = ({ technician, state, activeStatuses }) => {
|
||||
state.sortedInfo.order,
|
||||
render: (text, record) => <ProductionListLastContacted record={record} />,
|
||||
},
|
||||
{
|
||||
title: i18n.t("jobs.fields.date_next_contact"),
|
||||
dataIndex: "date_next_contact",
|
||||
key: "date_next_contact",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => dateSort(a.date_next_contact, b.date_next_contact),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "date_next_contact" &&
|
||||
state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<span
|
||||
style={{
|
||||
color:
|
||||
record.date_next_contact &&
|
||||
moment(record.date_next_contact).isBefore(moment())
|
||||
? "red"
|
||||
: "",
|
||||
}}
|
||||
>
|
||||
<ProductionListDate record={record} field="date_next_contact" time />
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: i18n.t("jobs.fields.scheduled_delivery"),
|
||||
dataIndex: "scheduled_delivery",
|
||||
@@ -332,7 +356,7 @@ const r = ({ technician, state, activeStatuses }) => {
|
||||
render: (text, record) => (
|
||||
<ProductionListEmployeeAssignment
|
||||
record={record}
|
||||
type="employee_body_rel"
|
||||
type="employee_body"
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -343,7 +367,7 @@ const r = ({ technician, state, activeStatuses }) => {
|
||||
render: (text, record) => (
|
||||
<ProductionListEmployeeAssignment
|
||||
record={record}
|
||||
type="employee_prep_rel"
|
||||
type="employee_prep"
|
||||
/>
|
||||
),
|
||||
},
|
||||
@@ -352,10 +376,7 @@ const r = ({ technician, state, activeStatuses }) => {
|
||||
dataIndex: "employee_csr",
|
||||
key: "employee_csr",
|
||||
render: (text, record) => (
|
||||
<ProductionListEmployeeAssignment
|
||||
record={record}
|
||||
type="employee_csr_rel"
|
||||
/>
|
||||
<ProductionListEmployeeAssignment record={record} type="employee_csr" />
|
||||
),
|
||||
},
|
||||
{
|
||||
@@ -365,7 +386,7 @@ const r = ({ technician, state, activeStatuses }) => {
|
||||
render: (text, record) => (
|
||||
<ProductionListEmployeeAssignment
|
||||
record={record}
|
||||
type="employee_refinish_rel"
|
||||
type="employee_refinish"
|
||||
/>
|
||||
),
|
||||
},
|
||||
|
||||
@@ -49,7 +49,7 @@ export function ProductionListEmpAssignment({
|
||||
const result = await updateJob({
|
||||
variables: { jobId: record.id, job: { [empAssignment]: employeeid } },
|
||||
|
||||
awaitRefetchQueries: true,
|
||||
// awaitRefetchQueries: true,
|
||||
});
|
||||
|
||||
insertAuditTrail({
|
||||
@@ -145,13 +145,18 @@ export function ProductionListEmpAssignment({
|
||||
</Row>
|
||||
);
|
||||
|
||||
let theEmployee;
|
||||
|
||||
if (record[type])
|
||||
theEmployee = bodyshop.employees.find((e) => e.id === record[type]);
|
||||
|
||||
return (
|
||||
<Popover destroyTooltipOnHide content={popContent} visible={visibility}>
|
||||
<Spin spinning={loading}>
|
||||
{record[type] ? (
|
||||
<div>
|
||||
<span>{`${record[type].first_name || ""} ${
|
||||
record[type].last_name || ""
|
||||
<span>{`${theEmployee.first_name || ""} ${
|
||||
theEmployee.last_name || ""
|
||||
}`}</span>
|
||||
<DeleteFilled
|
||||
style={iconStyle}
|
||||
@@ -174,13 +179,13 @@ export function ProductionListEmpAssignment({
|
||||
|
||||
const determineFieldName = (operation) => {
|
||||
switch (operation) {
|
||||
case "employee_body_rel":
|
||||
case "employee_body":
|
||||
return "employee_body";
|
||||
case "employee_prep_rel":
|
||||
case "employee_prep":
|
||||
return "employee_prep";
|
||||
case "employee_refinish_rel":
|
||||
case "employee_refinish":
|
||||
return "employee_refinish";
|
||||
case "employee_csr_rel":
|
||||
case "employee_csr":
|
||||
return "employee_csr";
|
||||
default:
|
||||
return null;
|
||||
|
||||
@@ -29,7 +29,11 @@ export function ProductionLastContacted({ currentUser, record }) {
|
||||
const [visible, setVisible] = useState(false);
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const handleFinish = async ({ date_last_contacted, note }) => {
|
||||
const handleFinish = async ({
|
||||
date_last_contacted,
|
||||
date_next_contact,
|
||||
note,
|
||||
}) => {
|
||||
logImEXEvent("production_last_contacted");
|
||||
|
||||
//e.stopPropagation();
|
||||
@@ -38,6 +42,7 @@ export function ProductionLastContacted({ currentUser, record }) {
|
||||
jobId: record.id,
|
||||
job: {
|
||||
date_last_contacted,
|
||||
...(date_next_contact ? { date_next_contact } : {}),
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -98,7 +103,16 @@ export function ProductionLastContacted({ currentUser, record }) {
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Form form={form} onFinish={handleFinish} layout="vertical">
|
||||
<Form.Item name="date_last_contacted">
|
||||
<Form.Item
|
||||
name="date_last_contacted"
|
||||
label={t("jobs.fields.date_last_contacted")}
|
||||
>
|
||||
<FormDateTimePickerComponent />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="date_next_contact"
|
||||
label={t("jobs.fields.date_next_contact")}
|
||||
>
|
||||
<FormDateTimePickerComponent />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("notes.labels.notetoadd")} name="note">
|
||||
|
||||
@@ -182,10 +182,16 @@ export function ProductionListTable({
|
||||
<div>
|
||||
<PageHeader
|
||||
title={
|
||||
<Statistic
|
||||
title={t("dashboard.titles.productionhours")}
|
||||
value={totalHrs}
|
||||
/>
|
||||
<Space>
|
||||
<Statistic
|
||||
title={t("dashboard.titles.productionhours")}
|
||||
value={totalHrs}
|
||||
/>
|
||||
<Statistic
|
||||
title={t("appointments.labels.inproduction")}
|
||||
value={dataSource && dataSource.length}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
extra={
|
||||
<Space wrap>
|
||||
|
||||
@@ -56,7 +56,10 @@ export default function ProductionSubletsManageComponent({ subletJobLines }) {
|
||||
<Button
|
||||
key="complete"
|
||||
loading={loading}
|
||||
onClick={() => handleSubletMark(s, "complete")}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleSubletMark(s, "complete");
|
||||
}}
|
||||
type={s.sublet_completed ? "primary" : "ghost"}
|
||||
>
|
||||
<CheckCircleFilled
|
||||
@@ -66,7 +69,10 @@ export default function ProductionSubletsManageComponent({ subletJobLines }) {
|
||||
<Button
|
||||
key="sublet"
|
||||
loading={loading}
|
||||
onClick={() => handleSubletMark(s, "ignore")}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleSubletMark(s, "ignore");
|
||||
}}
|
||||
type={s.sublet_ignored ? "primary" : "ghost"}
|
||||
>
|
||||
<EyeInvisibleFilled
|
||||
|
||||
@@ -5,9 +5,8 @@ import {
|
||||
Input,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Switch,
|
||||
Typography,
|
||||
Space, Switch,
|
||||
Typography
|
||||
} from "antd";
|
||||
import axios from "axios";
|
||||
import moment from "moment";
|
||||
@@ -75,6 +74,12 @@ export function ScheduleJobModalComponent({
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
<Space>
|
||||
<Typography.Title level={3}>{lbrHrsData?.jobs_by_pk?.ro_number}</Typography.Title>
|
||||
<Typography.Title
|
||||
level={4}
|
||||
>{`B/R Hrs:${lbrHrsData?.jobs_by_pk.labhrs?.aggregate.sum.mod_lb_hrs}/${lbrHrsData?.jobs_by_pk.larhrs?.aggregate.sum.mod_lb_hrs}`}</Typography.Title>
|
||||
</Space>
|
||||
<LayoutFormRow grow>
|
||||
<Form.Item
|
||||
name="start"
|
||||
|
||||
@@ -848,6 +848,88 @@ export default function ShopInfoGeneral({ form }) {
|
||||
}}
|
||||
</Form.List>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow header={t("bodyshop.labels.filehandlers")}>
|
||||
<Form.List name={["md_filehandlers"]}>
|
||||
{(fields, { add, remove, move }) => {
|
||||
return (
|
||||
<div>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item key={field.key}>
|
||||
<LayoutFormRow noDivider>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ins_ct_fn")}
|
||||
key={`${index}ins_ct_fn`}
|
||||
name={[field.name, "ins_ct_fn"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ins_ct_ln")}
|
||||
key={`${index}ins_ct_ln`}
|
||||
name={[field.name, "ins_ct_ln"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ins_ph1")}
|
||||
key={`${index}ins_ph1`}
|
||||
name={[field.name, "ins_ph1"]}
|
||||
rules={[
|
||||
({ getFieldValue }) =>
|
||||
PhoneItemFormatterValidation(getFieldValue, [
|
||||
field.name,
|
||||
"ins_ph",
|
||||
]),
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.ins_ea")}
|
||||
key={`${index}ins_ea`}
|
||||
name={[field.name, "ins_ea"]}
|
||||
rules={[
|
||||
{
|
||||
type: "email",
|
||||
message: "This is not a valid email address.",
|
||||
},
|
||||
]}
|
||||
>
|
||||
<FormItemEmail
|
||||
email={form.getFieldValue([field.name, "ins_ea"])}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Space>
|
||||
<DeleteFilled
|
||||
onClick={() => {
|
||||
remove(field.name);
|
||||
}}
|
||||
/>
|
||||
<FormListMoveArrows
|
||||
move={move}
|
||||
index={index}
|
||||
total={fields.length}
|
||||
/>
|
||||
</Space>
|
||||
</LayoutFormRow>
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => {
|
||||
add();
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{t("general.actions.add")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
</LayoutFormRow>
|
||||
<LayoutFormRow grow header={t("bodyshop.fields.md_ccc_rates")}>
|
||||
<Form.List name={["md_ccc_rates"]}>
|
||||
{(fields, { add, remove, move }) => {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -98,7 +98,9 @@ export const QUERY_BODYSHOP = gql`
|
||||
md_ded_notes
|
||||
pbs_configuration
|
||||
pbs_serialnumber
|
||||
md_filehandlers
|
||||
employees {
|
||||
user_email
|
||||
id
|
||||
active
|
||||
first_name
|
||||
@@ -192,6 +194,7 @@ export const UPDATE_SHOP = gql`
|
||||
md_ded_notes
|
||||
pbs_configuration
|
||||
pbs_serialnumber
|
||||
md_filehandlers
|
||||
employees {
|
||||
id
|
||||
first_name
|
||||
@@ -199,6 +202,7 @@ export const UPDATE_SHOP = gql`
|
||||
last_name
|
||||
employee_number
|
||||
rates
|
||||
user_email
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { gql } from "@apollo/client";
|
||||
|
||||
export const QUERY_EMPLOYEES = gql`
|
||||
query QUERY_EMPLOYEES {
|
||||
employees {
|
||||
employees(order_by: { employee_number: asc }) {
|
||||
last_name
|
||||
id
|
||||
first_name
|
||||
|
||||
@@ -125,6 +125,7 @@ export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
|
||||
scheduled_completion
|
||||
scheduled_delivery
|
||||
date_last_contacted
|
||||
date_next_contact
|
||||
ins_co_nm
|
||||
clm_total
|
||||
ownr_ph1
|
||||
@@ -134,39 +135,10 @@ export const SUBSCRIPTION_JOBS_IN_PRODUCTION = gql`
|
||||
production_vars
|
||||
kanbanparent
|
||||
alt_transport
|
||||
joblines_status {
|
||||
part_type
|
||||
count
|
||||
status
|
||||
}
|
||||
employee_body
|
||||
employee_body_rel {
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
employee_refinish
|
||||
employee_refinish_rel {
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
employee_prep
|
||||
employee_prep_rel {
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
employee_csr_rel {
|
||||
id
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
partcount: joblines_aggregate(where: { removed: { _eq: false } }) {
|
||||
nodes {
|
||||
status
|
||||
}
|
||||
}
|
||||
employee_csr
|
||||
labhrs: joblines_aggregate(
|
||||
where: {
|
||||
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
||||
@@ -208,6 +180,7 @@ export const QUERY_LBR_HRS_BY_PK = gql`
|
||||
query QUERY_LBR_HRS_BY_PK($id: uuid!) {
|
||||
jobs_by_pk(id: $id) {
|
||||
id
|
||||
ro_number
|
||||
labhrs: joblines_aggregate(
|
||||
where: {
|
||||
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
||||
@@ -518,6 +491,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
date_scheduled
|
||||
date_invoiced
|
||||
date_last_contacted
|
||||
date_next_contact
|
||||
date_exported
|
||||
status
|
||||
owner_owing
|
||||
@@ -535,6 +509,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
unq_seq
|
||||
line_ind
|
||||
line_desc
|
||||
line_ref
|
||||
part_type
|
||||
oem_partno
|
||||
db_price
|
||||
@@ -760,6 +735,7 @@ export const QUERY_JOB_CARD_DETAILS = gql`
|
||||
scheduled_delivery
|
||||
date_invoiced
|
||||
date_last_contacted
|
||||
date_next_contact
|
||||
date_open
|
||||
date_exported
|
||||
|
||||
@@ -846,6 +822,7 @@ export const QUERY_TECH_JOB_DETAILS = gql`
|
||||
scheduled_delivery
|
||||
date_invoiced
|
||||
date_last_contacted
|
||||
date_next_contact
|
||||
date_open
|
||||
date_exported
|
||||
voided
|
||||
|
||||
@@ -14,6 +14,7 @@ export const QUERY_NOTES_BY_JOB_PK = gql`
|
||||
query QUERY_NOTES_BY_JOB_PK($id: uuid!) {
|
||||
jobs_by_pk(id: $id) {
|
||||
id
|
||||
ro_number
|
||||
notes {
|
||||
created_at
|
||||
created_by
|
||||
|
||||
@@ -69,3 +69,25 @@ export const UPDATE_FCM_TOKEN = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_KANBAN_SETTINGS = gql`
|
||||
query QUERY_KANBAN_SETTINGS($email: String!) {
|
||||
associations(
|
||||
where: { _and: { useremail: { _eq: $email }, active: { _eq: true } } }
|
||||
) {
|
||||
id
|
||||
kanban_settings
|
||||
}
|
||||
}
|
||||
`;
|
||||
export const UPDATE_KANBAN_SETTINGS = gql`
|
||||
mutation UPDATE_KANBAN_SETTINGS($id: uuid!, $ks: jsonb) {
|
||||
update_associations_by_pk(
|
||||
pk_columns: { id: $id }
|
||||
_set: { kanban_settings: $ks }
|
||||
) {
|
||||
id
|
||||
kanban_settings
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Button, Col, PageHeader, Row } from "antd";
|
||||
import { Button, Col, PageHeader, Row, Space, Form, Switch } from "antd";
|
||||
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ContractCarsContainer from "../../components/contract-cars/contract-cars.container";
|
||||
@@ -13,14 +14,25 @@ export default function ContractCreatePageComponent({
|
||||
const { t } = useTranslation();
|
||||
|
||||
const CreateButton = (
|
||||
<Button
|
||||
disabled={!selectedJobState[0] || !selectedCarState[0]}
|
||||
type="primary"
|
||||
onClick={() => form.submit()}
|
||||
loading={loading}
|
||||
>
|
||||
{t("general.actions.create")}
|
||||
</Button>
|
||||
<Space size="large">
|
||||
{selectedJobState[0] && selectedCarState[0] && (
|
||||
<Form.Item
|
||||
label={t("jobs.actions.addtoproduction")}
|
||||
name="addtoproduction"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Button
|
||||
disabled={!selectedJobState[0] || !selectedCarState[0]}
|
||||
type="primary"
|
||||
onClick={() => form.submit()}
|
||||
loading={loading}
|
||||
>
|
||||
{t("general.actions.create")}
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -7,6 +7,7 @@ import { useHistory, useLocation } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import { INSERT_NEW_CONTRACT } from "../../graphql/cccontracts.queries";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import {
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
@@ -37,8 +38,9 @@ export function ContractCreatePageContainer({
|
||||
(location.state && location.state.jobId) || null
|
||||
);
|
||||
const [insertContract] = useMutation(INSERT_NEW_CONTRACT);
|
||||
const [intakeJob] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
const handleFinish = async ({ addtoproduction, ...values }) => {
|
||||
if (!!selectedCarState[0] && !!selectedJobState[0]) {
|
||||
setLoading(true);
|
||||
const result = await insertContract({
|
||||
@@ -54,12 +56,35 @@ export function ContractCreatePageContainer({
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!result.errors) {
|
||||
//Update the courtesy car to have the damage.
|
||||
notification["success"]({
|
||||
message: t("contracts.successes.saved"),
|
||||
});
|
||||
|
||||
//Intake the job if required
|
||||
if (addtoproduction) {
|
||||
const result2 = await intakeJob({
|
||||
variables: {
|
||||
jobId: selectedJobState[0],
|
||||
job: {
|
||||
actual_in: new Date(),
|
||||
inproduction: true,
|
||||
status: bodyshop.md_ro_statuses.default_arrived,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (result2.errors) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.saving", {
|
||||
error: JSON.stringify(!result2.errors),
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
history.push(
|
||||
|
||||
@@ -120,7 +120,11 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (!jobId || !bodyshop.cdk_dealerid || !(data && data.jobs_by_pk))
|
||||
if (
|
||||
!jobId ||
|
||||
!(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) ||
|
||||
!(data && data.jobs_by_pk)
|
||||
)
|
||||
return <Result status="404" />;
|
||||
|
||||
return (
|
||||
|
||||
@@ -208,7 +208,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} />
|
||||
</Form.Item>
|
||||
{bodyshop.cdk_dealerid && (
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmin")}
|
||||
name="kmin"
|
||||
@@ -221,7 +221,7 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
|
||||
<InputNumber precision={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{bodyshop.cdk_dealerid && (
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmout")}
|
||||
name="kmout"
|
||||
|
||||
@@ -503,6 +503,7 @@
|
||||
"emaillater": "Email Later",
|
||||
"employees": "Employees",
|
||||
"estimators": "Estimators",
|
||||
"filehandlers": "File Handlers",
|
||||
"insurancecos": "Insurance Companies",
|
||||
"intakechecklist": "Intake Checklist",
|
||||
"jobstatuses": "Job Statuses",
|
||||
@@ -535,6 +536,7 @@
|
||||
"save": "Shop configuration saved successfully. "
|
||||
},
|
||||
"validation": {
|
||||
"centermustexist": "The chosen responsibility center does not exist.",
|
||||
"larsplit": "Refinish hour split must add up to 1.",
|
||||
"useremailmustexist": "This email is not a valid user."
|
||||
}
|
||||
@@ -1091,6 +1093,7 @@
|
||||
"addtoscoreboard": "Add to Scoreboard",
|
||||
"allocate": "Allocate",
|
||||
"autoallocate": "Auto Allocate",
|
||||
"changefilehandler": "Change File Handler",
|
||||
"changelaborrate": "Change Labor Rate",
|
||||
"changestatus": "Change Status",
|
||||
"changestimator": "Change Estimator",
|
||||
@@ -1205,6 +1208,7 @@
|
||||
"date_exported": "Exported",
|
||||
"date_invoiced": "Invoiced",
|
||||
"date_last_contacted": "Last Contacted Date",
|
||||
"date_next_contact": "Next Contact Date",
|
||||
"date_open": "Open",
|
||||
"date_scheduled": "Scheduled",
|
||||
"ded_amt": "Deductible",
|
||||
@@ -1725,7 +1729,8 @@
|
||||
"new": "New Conversation"
|
||||
},
|
||||
"errors": {
|
||||
"invalidphone": "The phone number is invalid. Unable to open conversation. "
|
||||
"invalidphone": "The phone number is invalid. Unable to open conversation. ",
|
||||
"noattachedjobs": "No jobs have been associated to this conversation. "
|
||||
},
|
||||
"labels": {
|
||||
"archive": "Archive",
|
||||
@@ -1735,6 +1740,7 @@
|
||||
"nojobs": "Not associated to any job.",
|
||||
"phonenumber": "Phone #",
|
||||
"presets": "Presets",
|
||||
"recentonly": "Only your most recent 50 conversations will be shown here. If you are looking for an older conversation, find the related contact and click their phone number to view the conversation.",
|
||||
"selectmedia": "Select Media",
|
||||
"sentby": "Sent by {{by}} at {{time}}",
|
||||
"typeamessage": "Send a message...",
|
||||
@@ -1824,6 +1830,7 @@
|
||||
"receivebill": "Receive Bill"
|
||||
},
|
||||
"errors": {
|
||||
"associatedbills": "This parts order cannot",
|
||||
"backordering": "Error backordering part {{message}}.",
|
||||
"creating": "Error encountered when creating parts order. "
|
||||
},
|
||||
@@ -1849,7 +1856,7 @@
|
||||
},
|
||||
"labels": {
|
||||
"allpartsto": "All Parts Location",
|
||||
"confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. ",
|
||||
"confirmdelete": "Are you sure you want to delete this item? It cannot be recovered. Job line statuses will not be updated and may require manual review. ",
|
||||
"email": "Send by Email",
|
||||
"inthisorder": "Parts in this Order",
|
||||
"newpartsorder": "New Parts Order",
|
||||
@@ -1968,6 +1975,7 @@
|
||||
"zip": "Postal Code/Zip"
|
||||
},
|
||||
"3rdpartypayer": "Invoice to Third Party Payer",
|
||||
"ab_proof_of_loss": "AB - Proof of Loss",
|
||||
"appointment_confirmation": "Appointment Confirmation",
|
||||
"appointment_reminder": "Appointment Reminder",
|
||||
"casl_authorization": "CASL Authorization",
|
||||
@@ -1985,6 +1993,7 @@
|
||||
"fippa_authorization": "FIPPA Authorization",
|
||||
"glass_express_checklist": "Glass Express Checklist",
|
||||
"guarantee": "Repair Guarantee",
|
||||
"individual_job_note": "Job Note RO # {{ro_number}}",
|
||||
"invoice_customer_payable": "Invoice (Customer Payable)",
|
||||
"invoice_total_payable": "Invoice (Total Payable)",
|
||||
"iou_form": "IOU Form",
|
||||
@@ -2023,7 +2032,8 @@
|
||||
"worksheet_by_line_number": "Worksheet by Line Number",
|
||||
"worksheet_sorted_by_operation": "Worksheet by Operation",
|
||||
"worksheet_sorted_by_operation_no_hours": "Worksheet by Operation (No Hours)",
|
||||
"worksheet_sorted_by_operation_part_type": "Worksheet by Operation & Part Type"
|
||||
"worksheet_sorted_by_operation_part_type": "Worksheet by Operation & Part Type",
|
||||
"worksheet_sorted_by_operation_type": "Worksheet by Operation Type"
|
||||
},
|
||||
"labels": {
|
||||
"groups": {
|
||||
@@ -2068,20 +2078,31 @@
|
||||
},
|
||||
"errors": {
|
||||
"boardupdate": "Error encountered updating job. {{message}}",
|
||||
"removing": "Error removing from production board. {{error}}"
|
||||
"removing": "Error removing from production board. {{error}}",
|
||||
"settings": "Error saving board settings: {{error}}"
|
||||
},
|
||||
"labels": {
|
||||
"alert": "Alert",
|
||||
"alertoff": "Remove alert from job",
|
||||
"alerton": "Add alert to job",
|
||||
"ats": "Alternative Transportation",
|
||||
"bodyhours": "B",
|
||||
"bodypriority": "B/P",
|
||||
"cardsettings": "Card Settings",
|
||||
"clm_no": "Claim Number",
|
||||
"compact": "Compact Cards",
|
||||
"detailpriority": "D/P",
|
||||
"employeeassignments": "Employee Assignments",
|
||||
"employeesearch": "Employee Search",
|
||||
"ins_co_nm": "Insurance Company Name",
|
||||
"jobdetail": "Job Details",
|
||||
"laborhrs": "Labor Hours",
|
||||
"note": "Production Note",
|
||||
"ownr_nm": "Owner Name",
|
||||
"paintpriority": "P/P",
|
||||
"production_note": "Production Note",
|
||||
"refinishhours": "R",
|
||||
"scheduled_completion": "Scheduled Completion",
|
||||
"selectview": "Select a View",
|
||||
"sublets": "Sublets",
|
||||
"totalhours": "Total Hrs ",
|
||||
@@ -2176,6 +2197,7 @@
|
||||
"open_orders_csr": "Open Orders by CSR",
|
||||
"open_orders_estimator": "Open Orders by Estimator",
|
||||
"open_orders_ins_co": "Open Orders by Insurance Company",
|
||||
"open_orders_status": "Open Orders by Status",
|
||||
"parts_backorder": "Backordered Parts",
|
||||
"parts_not_recieved": "Parts Not Received",
|
||||
"payments_by_date": "Payments by Date",
|
||||
|
||||
@@ -503,6 +503,7 @@
|
||||
"emaillater": "",
|
||||
"employees": "",
|
||||
"estimators": "",
|
||||
"filehandlers": "",
|
||||
"insurancecos": "",
|
||||
"intakechecklist": "",
|
||||
"jobstatuses": "",
|
||||
@@ -535,6 +536,7 @@
|
||||
"save": ""
|
||||
},
|
||||
"validation": {
|
||||
"centermustexist": "",
|
||||
"larsplit": "",
|
||||
"useremailmustexist": ""
|
||||
}
|
||||
@@ -1091,6 +1093,7 @@
|
||||
"addtoscoreboard": "",
|
||||
"allocate": "",
|
||||
"autoallocate": "",
|
||||
"changefilehandler": "",
|
||||
"changelaborrate": "",
|
||||
"changestatus": "Cambiar Estado",
|
||||
"changestimator": "",
|
||||
@@ -1205,6 +1208,7 @@
|
||||
"date_exported": "Exportado",
|
||||
"date_invoiced": "Facturado",
|
||||
"date_last_contacted": "",
|
||||
"date_next_contact": "",
|
||||
"date_open": "Abierto",
|
||||
"date_scheduled": "Programado",
|
||||
"ded_amt": "Deducible",
|
||||
@@ -1725,7 +1729,8 @@
|
||||
"new": ""
|
||||
},
|
||||
"errors": {
|
||||
"invalidphone": ""
|
||||
"invalidphone": "",
|
||||
"noattachedjobs": ""
|
||||
},
|
||||
"labels": {
|
||||
"archive": "",
|
||||
@@ -1735,6 +1740,7 @@
|
||||
"nojobs": "",
|
||||
"phonenumber": "",
|
||||
"presets": "",
|
||||
"recentonly": "",
|
||||
"selectmedia": "",
|
||||
"sentby": "",
|
||||
"typeamessage": "Enviar un mensaje...",
|
||||
@@ -1824,6 +1830,7 @@
|
||||
"receivebill": ""
|
||||
},
|
||||
"errors": {
|
||||
"associatedbills": "",
|
||||
"backordering": "",
|
||||
"creating": "Se encontró un error al crear el pedido de piezas."
|
||||
},
|
||||
@@ -1968,6 +1975,7 @@
|
||||
"zip": ""
|
||||
},
|
||||
"3rdpartypayer": "",
|
||||
"ab_proof_of_loss": "",
|
||||
"appointment_confirmation": "",
|
||||
"appointment_reminder": "",
|
||||
"casl_authorization": "",
|
||||
@@ -1985,6 +1993,7 @@
|
||||
"fippa_authorization": "",
|
||||
"glass_express_checklist": "",
|
||||
"guarantee": "",
|
||||
"individual_job_note": "",
|
||||
"invoice_customer_payable": "",
|
||||
"invoice_total_payable": "",
|
||||
"iou_form": "",
|
||||
@@ -2023,7 +2032,8 @@
|
||||
"worksheet_by_line_number": "",
|
||||
"worksheet_sorted_by_operation": "",
|
||||
"worksheet_sorted_by_operation_no_hours": "",
|
||||
"worksheet_sorted_by_operation_part_type": ""
|
||||
"worksheet_sorted_by_operation_part_type": "",
|
||||
"worksheet_sorted_by_operation_type": ""
|
||||
},
|
||||
"labels": {
|
||||
"groups": {
|
||||
@@ -2068,20 +2078,31 @@
|
||||
},
|
||||
"errors": {
|
||||
"boardupdate": "",
|
||||
"removing": ""
|
||||
"removing": "",
|
||||
"settings": ""
|
||||
},
|
||||
"labels": {
|
||||
"alert": "",
|
||||
"alertoff": "",
|
||||
"alerton": "",
|
||||
"ats": "",
|
||||
"bodyhours": "",
|
||||
"bodypriority": "",
|
||||
"cardsettings": "",
|
||||
"clm_no": "",
|
||||
"compact": "",
|
||||
"detailpriority": "",
|
||||
"employeeassignments": "",
|
||||
"employeesearch": "",
|
||||
"ins_co_nm": "",
|
||||
"jobdetail": "",
|
||||
"laborhrs": "",
|
||||
"note": "",
|
||||
"ownr_nm": "",
|
||||
"paintpriority": "",
|
||||
"production_note": "",
|
||||
"refinishhours": "",
|
||||
"scheduled_completion": "",
|
||||
"selectview": "",
|
||||
"sublets": "",
|
||||
"totalhours": "",
|
||||
@@ -2176,6 +2197,7 @@
|
||||
"open_orders_csr": "",
|
||||
"open_orders_estimator": "",
|
||||
"open_orders_ins_co": "",
|
||||
"open_orders_status": "",
|
||||
"parts_backorder": "",
|
||||
"parts_not_recieved": "",
|
||||
"payments_by_date": "",
|
||||
|
||||
@@ -503,6 +503,7 @@
|
||||
"emaillater": "",
|
||||
"employees": "",
|
||||
"estimators": "",
|
||||
"filehandlers": "",
|
||||
"insurancecos": "",
|
||||
"intakechecklist": "",
|
||||
"jobstatuses": "",
|
||||
@@ -535,6 +536,7 @@
|
||||
"save": ""
|
||||
},
|
||||
"validation": {
|
||||
"centermustexist": "",
|
||||
"larsplit": "",
|
||||
"useremailmustexist": ""
|
||||
}
|
||||
@@ -1091,6 +1093,7 @@
|
||||
"addtoscoreboard": "",
|
||||
"allocate": "",
|
||||
"autoallocate": "",
|
||||
"changefilehandler": "",
|
||||
"changelaborrate": "",
|
||||
"changestatus": "Changer le statut",
|
||||
"changestimator": "",
|
||||
@@ -1205,6 +1208,7 @@
|
||||
"date_exported": "Exportés",
|
||||
"date_invoiced": "Facturé",
|
||||
"date_last_contacted": "",
|
||||
"date_next_contact": "",
|
||||
"date_open": "Ouvrir",
|
||||
"date_scheduled": "Prévu",
|
||||
"ded_amt": "Déductible",
|
||||
@@ -1725,7 +1729,8 @@
|
||||
"new": ""
|
||||
},
|
||||
"errors": {
|
||||
"invalidphone": ""
|
||||
"invalidphone": "",
|
||||
"noattachedjobs": ""
|
||||
},
|
||||
"labels": {
|
||||
"archive": "",
|
||||
@@ -1735,6 +1740,7 @@
|
||||
"nojobs": "",
|
||||
"phonenumber": "",
|
||||
"presets": "",
|
||||
"recentonly": "",
|
||||
"selectmedia": "",
|
||||
"sentby": "",
|
||||
"typeamessage": "Envoyer un message...",
|
||||
@@ -1824,6 +1830,7 @@
|
||||
"receivebill": ""
|
||||
},
|
||||
"errors": {
|
||||
"associatedbills": "",
|
||||
"backordering": "",
|
||||
"creating": "Erreur rencontrée lors de la création de la commande de pièces."
|
||||
},
|
||||
@@ -1968,6 +1975,7 @@
|
||||
"zip": ""
|
||||
},
|
||||
"3rdpartypayer": "",
|
||||
"ab_proof_of_loss": "",
|
||||
"appointment_confirmation": "",
|
||||
"appointment_reminder": "",
|
||||
"casl_authorization": "",
|
||||
@@ -1985,6 +1993,7 @@
|
||||
"fippa_authorization": "",
|
||||
"glass_express_checklist": "",
|
||||
"guarantee": "",
|
||||
"individual_job_note": "",
|
||||
"invoice_customer_payable": "",
|
||||
"invoice_total_payable": "",
|
||||
"iou_form": "",
|
||||
@@ -2023,7 +2032,8 @@
|
||||
"worksheet_by_line_number": "",
|
||||
"worksheet_sorted_by_operation": "",
|
||||
"worksheet_sorted_by_operation_no_hours": "",
|
||||
"worksheet_sorted_by_operation_part_type": ""
|
||||
"worksheet_sorted_by_operation_part_type": "",
|
||||
"worksheet_sorted_by_operation_type": ""
|
||||
},
|
||||
"labels": {
|
||||
"groups": {
|
||||
@@ -2068,20 +2078,31 @@
|
||||
},
|
||||
"errors": {
|
||||
"boardupdate": "",
|
||||
"removing": ""
|
||||
"removing": "",
|
||||
"settings": ""
|
||||
},
|
||||
"labels": {
|
||||
"alert": "",
|
||||
"alertoff": "",
|
||||
"alerton": "",
|
||||
"ats": "",
|
||||
"bodyhours": "",
|
||||
"bodypriority": "",
|
||||
"cardsettings": "",
|
||||
"clm_no": "",
|
||||
"compact": "",
|
||||
"detailpriority": "",
|
||||
"employeeassignments": "",
|
||||
"employeesearch": "",
|
||||
"ins_co_nm": "",
|
||||
"jobdetail": "",
|
||||
"laborhrs": "",
|
||||
"note": "",
|
||||
"ownr_nm": "",
|
||||
"paintpriority": "",
|
||||
"production_note": "",
|
||||
"refinishhours": "",
|
||||
"scheduled_completion": "",
|
||||
"selectview": "",
|
||||
"sublets": "",
|
||||
"totalhours": "",
|
||||
@@ -2176,6 +2197,7 @@
|
||||
"open_orders_csr": "",
|
||||
"open_orders_estimator": "",
|
||||
"open_orders_ins_co": "",
|
||||
"open_orders_status": "",
|
||||
"parts_backorder": "",
|
||||
"parts_not_recieved": "",
|
||||
"payments_by_date": "",
|
||||
|
||||
@@ -12,7 +12,9 @@ export function DateFormatter(props) {
|
||||
|
||||
export function DateTimeFormatter(props) {
|
||||
return props.children
|
||||
? moment(props.children).format("MM/DD/YYYY hh:mm a")
|
||||
? moment(props.children).format(
|
||||
props.format ? props.format : "MM/DD/YYYY hh:mm a"
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -182,6 +182,18 @@ export const TemplateList = (type, context) => {
|
||||
disabled: false,
|
||||
group: "worksheet",
|
||||
},
|
||||
worksheet_sorted_by_operation_type: {
|
||||
title: i18n.t(
|
||||
"printcenter.jobs.worksheet_sorted_by_operation_type"
|
||||
),
|
||||
description: "All Jobs Notes",
|
||||
subject: i18n.t(
|
||||
"printcenter.jobs.worksheet_sorted_by_operation_type"
|
||||
),
|
||||
key: "worksheet_sorted_by_operation_type",
|
||||
disabled: false,
|
||||
group: "worksheet",
|
||||
},
|
||||
worksheet_sorted_by_operation: {
|
||||
title: i18n.t("printcenter.jobs.worksheet_sorted_by_operation"),
|
||||
description: "All Jobs Notes",
|
||||
@@ -407,6 +419,17 @@ export const TemplateList = (type, context) => {
|
||||
CA_MB: true,
|
||||
},
|
||||
},
|
||||
ab_proof_of_loss: {
|
||||
title: i18n.t("printcenter.jobs.ab_proof_of_loss"),
|
||||
description: "Thank You Letter by RO",
|
||||
key: "ab_proof_of_loss",
|
||||
subject: i18n.t("printcenter.jobs.ab_proof_of_loss"),
|
||||
disabled: false,
|
||||
group: "pre",
|
||||
regions: {
|
||||
CA_AB: true,
|
||||
},
|
||||
},
|
||||
// parts_label_multi: {
|
||||
// title: i18n.t("printcenter.jobs.parts_label_multi"),
|
||||
// description: "Thank You Letter by RO",
|
||||
@@ -440,6 +463,15 @@ export const TemplateList = (type, context) => {
|
||||
subject: i18n.t("printcenter.jobs.csi_invitation_action"),
|
||||
disabled: false,
|
||||
},
|
||||
individual_job_note: {
|
||||
title: i18n.t("printcenter.jobs.individual_job_note"),
|
||||
description: "CSI invite",
|
||||
key: "individual_job_note",
|
||||
subject: i18n.t("printcenter.jobs.individual_job_note", {
|
||||
ro_number: (context && context.ro_number) || "",
|
||||
}),
|
||||
disabled: false,
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
...(!type || type === "appointment"
|
||||
@@ -1181,6 +1213,19 @@ export const TemplateList = (type, context) => {
|
||||
},
|
||||
group: "jobs",
|
||||
},
|
||||
open_orders_status: {
|
||||
title: i18n.t("reportcenter.templates.open_orders_status"),
|
||||
description: "",
|
||||
subject: i18n.t("reportcenter.templates.open_orders_status"),
|
||||
key: "open_orders_status",
|
||||
//idtype: "vendor",
|
||||
disabled: false,
|
||||
rangeFilter: {
|
||||
object: i18n.t("reportcenter.labels.objects.jobs"),
|
||||
field: i18n.t("jobs.fields.date_open"),
|
||||
},
|
||||
group: "jobs",
|
||||
},
|
||||
open_orders_csr: {
|
||||
title: i18n.t("reportcenter.templates.open_orders_csr"),
|
||||
description: "",
|
||||
|
||||
2144
client/yarn.lock
2144
client/yarn.lock
File diff suppressed because it is too large
Load Diff
@@ -203,6 +203,7 @@
|
||||
- authlevel
|
||||
- default_prod_list_view
|
||||
- id
|
||||
- kanban_settings
|
||||
- qbo_realmId
|
||||
- shopid
|
||||
- useremail
|
||||
@@ -217,6 +218,7 @@
|
||||
- active
|
||||
- authlevel
|
||||
- default_prod_list_view
|
||||
- kanban_settings
|
||||
- qbo_realmId
|
||||
filter:
|
||||
bodyshop:
|
||||
@@ -828,6 +830,7 @@
|
||||
- md_classes
|
||||
- md_ded_notes
|
||||
- md_estimators
|
||||
- md_filehandlers
|
||||
- md_hour_split
|
||||
- md_ins_cos
|
||||
- md_jobline_presets
|
||||
@@ -906,6 +909,7 @@
|
||||
- md_classes
|
||||
- md_ded_notes
|
||||
- md_estimators
|
||||
- md_filehandlers
|
||||
- md_hour_split
|
||||
- md_ins_cos
|
||||
- md_jobline_presets
|
||||
@@ -2590,6 +2594,7 @@
|
||||
- date_exported
|
||||
- date_invoiced
|
||||
- date_last_contacted
|
||||
- date_next_contact
|
||||
- date_open
|
||||
- date_scheduled
|
||||
- ded_amt
|
||||
@@ -2841,6 +2846,7 @@
|
||||
- date_exported
|
||||
- date_invoiced
|
||||
- date_last_contacted
|
||||
- date_next_contact
|
||||
- date_open
|
||||
- date_scheduled
|
||||
- ded_amt
|
||||
@@ -3102,6 +3108,7 @@
|
||||
- date_exported
|
||||
- date_invoiced
|
||||
- date_last_contacted
|
||||
- date_next_contact
|
||||
- date_open
|
||||
- date_scheduled
|
||||
- ded_amt
|
||||
|
||||
@@ -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 "md_filehandlers" jsonb
|
||||
-- null default jsonb_build_array();
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."bodyshops" add column "md_filehandlers" 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 "date_next_contact" timestamptz
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."jobs" add column "date_next_contact" timestamptz
|
||||
null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."jobs" alter column "date_next_contact" drop not null;
|
||||
alter table "public"."jobs" add column "date_next_contact" timestamptz;
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."jobs" drop column "date_next_contact" cascade;
|
||||
@@ -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 "date_next_contact" timestamptz
|
||||
-- null;
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."jobs" add column "date_next_contact" timestamptz
|
||||
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"."associations" add column "kanban_settings" jsonb
|
||||
-- null default jsonb_build_object();
|
||||
@@ -0,0 +1,2 @@
|
||||
alter table "public"."associations" add column "kanban_settings" jsonb
|
||||
null default jsonb_build_object();
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."associations" alter column "kanban_settings" set default jsonb_build_object();
|
||||
@@ -0,0 +1 @@
|
||||
alter table "public"."associations" alter column "kanban_settings" set default '{"ats": true, "clm_no": true, "compact": false, "ownr_nm": true, "sublets": true, "ins_co_nm": true, "production_note": true, "employeeassignments": true, "scheduled_completion": true}';
|
||||
File diff suppressed because one or more lines are too long
20
package.json
20
package.json
@@ -17,7 +17,8 @@
|
||||
"start": "node server.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"aws-sdk": "^2.1013.0",
|
||||
"aws-sdk": "^2.1028.0",
|
||||
"axios": "^0.24.0",
|
||||
"bluebird": "^3.7.2",
|
||||
"body-parser": "^1.18.3",
|
||||
"cloudinary": "^1.27.1",
|
||||
@@ -28,25 +29,24 @@
|
||||
"dinero.js": "^1.9.1",
|
||||
"dotenv": "10.0.0",
|
||||
"express": "^4.16.4",
|
||||
"firebase-admin": "^9.12.0",
|
||||
"graphql": "^15.6.1",
|
||||
"firebase-admin": "^10.0.0",
|
||||
"graphql": "^16.0.1",
|
||||
"graphql-request": "^3.6.1",
|
||||
"graylog2": "^0.2.1",
|
||||
"inline-css": "^3.0.0",
|
||||
"intuit-oauth": "^4.0.0",
|
||||
"lodash": "^4.17.21",
|
||||
"moment": "^2.29.1",
|
||||
"node-fetch": "^2.6.1",
|
||||
"node-mailjet": "^3.3.4",
|
||||
"node-quickbooks": "^2.0.39",
|
||||
"nodemailer": "^6.7.0",
|
||||
"phone": "^3.1.8",
|
||||
"nodemailer": "^6.7.1",
|
||||
"phone": "^3.1.9",
|
||||
"query-string": "^7.0.1",
|
||||
"soap": "^0.42.0",
|
||||
"socket.io": "^4.3.1",
|
||||
"soap": "^0.43.0",
|
||||
"socket.io": "^4.3.2",
|
||||
"ssh2-sftp-client": "^7.1.0",
|
||||
"stripe": "^8.184.0",
|
||||
"twilio": "^3.70.0",
|
||||
"stripe": "^8.188.0",
|
||||
"twilio": "^3.71.1",
|
||||
"uuid": "^8.3.2",
|
||||
"xmlbuilder2": "^3.0.2"
|
||||
},
|
||||
|
||||
@@ -5,7 +5,6 @@ const path = require("path");
|
||||
const compression = require("compression");
|
||||
const twilio = require("twilio");
|
||||
const logger = require("./server/utils/logger");
|
||||
global.fetch = require("node-fetch");
|
||||
var fb = require("./server/firebase/firebase-handler");
|
||||
var cookieParser = require("cookie-parser");
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ require("dotenv").config({
|
||||
`.env.${process.env.NODE_ENV || "development"}`
|
||||
),
|
||||
});
|
||||
const CdkBase = require("../web-sockets/web-socket");
|
||||
|
||||
const IMEX_PBS_USER = process.env.IMEX_PBS_USER,
|
||||
IMEX_PBS_PASSWORD = process.env.IMEX_PBS_PASSWORD;
|
||||
@@ -19,3 +18,13 @@ exports.PBS_CREDENTIALS = PBS_CREDENTIALS;
|
||||
// process.env.NODE_ENV === "production"
|
||||
// ? "https://3pa.dmotorworks.com"
|
||||
// : "https://uat-3pa.dmotorworks.com";
|
||||
|
||||
const pbsDomain = `https://partnerhub.pbsdealers.com/json/reply`;
|
||||
exports.PBS_ENDPOINTS = {
|
||||
AccountGet: `${pbsDomain}/AccountGet`,
|
||||
ContactGet: `${pbsDomain}/ContactGet`,
|
||||
VehicleGet: `${pbsDomain}/VehicleGet`,
|
||||
AccountingPostingChange: `${pbsDomain}/AccountingPostingChange`,
|
||||
ContactChange: `${pbsDomain}/ContactChange`,
|
||||
VehicleChange: `${pbsDomain}/VehicleChange`,
|
||||
};
|
||||
|
||||
@@ -6,25 +6,48 @@ require("dotenv").config({
|
||||
),
|
||||
});
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
const soap = require("soap");
|
||||
const axios = require("axios").default;
|
||||
const queries = require("../../graphql-client/queries");
|
||||
const CdkBase = require("../../web-sockets/web-socket");
|
||||
const { PBS_ENDPOINTS, PBS_CREDENTIALS } = require("./pbs-constants");
|
||||
|
||||
//const { CDK_CREDENTIALS, CheckCdkResponseForError } = require("./cdk-wsdl");
|
||||
//const CalcualteAllocations = require("./cdk-calculate-allocations").default;
|
||||
|
||||
const CalculateAllocations =
|
||||
require("../../cdk/cdk-calculate-allocations").default;
|
||||
const CdkBase = require("../../web-sockets/web-socket");
|
||||
const moment = require("moment");
|
||||
|
||||
exports.default = async function (socket, jobid) {
|
||||
exports.default = async function (socket, { txEnvelope, jobid }) {
|
||||
socket.logEvents = [];
|
||||
socket.recordid = jobid;
|
||||
|
||||
socket.txEnvelope = txEnvelope;
|
||||
try {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Received Job export request for id ${jobid}`
|
||||
);
|
||||
|
||||
const JobData = await QueryJobData(socket, jobid);
|
||||
socket.JobData = JobData;
|
||||
|
||||
//Query for the Vehicle record to get the associated customer.
|
||||
// socket.DmsVeh = await QueryVehicleFromDms(socket);
|
||||
//Todo: Need to validate the lines and methods below.
|
||||
if (socket.DmsVeh && socket.DmsVeh.CustomerRef) {
|
||||
//Get the associated customer from the Vehicle Record.
|
||||
socket.DMSVehCustomer = await QueryCustomerBycodeFromDms(
|
||||
socket,
|
||||
socket.DmsVeh.CustomerRef
|
||||
);
|
||||
}
|
||||
socket.DMSCustList = await QueryCustomersFromDms(socket);
|
||||
|
||||
socket.emit("pbs-select-customer", [
|
||||
...(socket.DMSVehCustomer
|
||||
? [{ ...socket.DMSVehCustomer, vinOwner: true }]
|
||||
: []),
|
||||
...socket.DMSCustList,
|
||||
]);
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
@@ -33,3 +56,570 @@ exports.default = async function (socket, jobid) {
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
exports.PbsSelectedCustomer = async function PbsSelectedCustomer(
|
||||
socket,
|
||||
selectedCustomerId
|
||||
) {
|
||||
try {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`User selected customer ${selectedCustomerId || "NEW"}`
|
||||
);
|
||||
|
||||
//Upsert the contact information as per Wafaa's Email.
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Upserting contact information to DMS for ${socket.JobData.ownr_fn} ${socket.JobData.ownr_ln} ${socket.JobData.ownr_co_nm}`
|
||||
);
|
||||
const ownerRef = await UpsertContactData(socket, selectedCustomerId);
|
||||
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Upserting vehicle information to DMS for ${socket.JobData.v_vin}`
|
||||
);
|
||||
await UpsertVehicleData(socket, ownerRef.ReferenceId);
|
||||
CdkBase.createLogEvent(socket, "DEBUG", `Inserting account data.`);
|
||||
await InsertAccountPostingData(socket);
|
||||
CdkBase.createLogEvent(socket, "DEBUG", `Marking job as exported.`);
|
||||
// await MarkJobExported(socket, socket.JobData.id);
|
||||
|
||||
socket.emit("export-success", socket.JobData.id);
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error encountered in CdkSelectedCustomer. ${error}`
|
||||
);
|
||||
await InsertFailedExportLog(socket, error);
|
||||
}
|
||||
};
|
||||
|
||||
async function CheckForErrors(socket, response) {
|
||||
if (response.WasSuccessful === undefined || response.WasSuccessful === true) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Succesful response from DMS. ${response.Message || ""}`
|
||||
);
|
||||
} else {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error received from DMS: ${response.Message}`
|
||||
);
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`Error received from DMS: ${JSON.stringify(response)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
async function QueryJobData(socket, jobid) {
|
||||
CdkBase.createLogEvent(socket, "DEBUG", `Querying job data for id ${jobid}`);
|
||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
|
||||
const result = await client
|
||||
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
||||
.request(queries.QUERY_JOBS_FOR_PBS_EXPORT, { id: jobid });
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`Job data query result ${JSON.stringify(result, null, 2)}`
|
||||
);
|
||||
return result.jobs_by_pk;
|
||||
}
|
||||
|
||||
async function QueryVehicleFromDms(socket) {
|
||||
try {
|
||||
const { data: VehicleGetResponse } = await axios.post(
|
||||
PBS_ENDPOINTS.VehicleGet,
|
||||
{
|
||||
SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
|
||||
// VehicleId: "00000000000000000000000000000000",
|
||||
// Year: "String",
|
||||
// Make: "String",
|
||||
// Model: "String",
|
||||
// Trim: "String",
|
||||
// ModelNumber: "String",
|
||||
// StockNumber: "String",
|
||||
VIN: socket.JobData.v_vin,
|
||||
// LicenseNumber: "String",
|
||||
// Lot: "String",
|
||||
// Status: "String",
|
||||
// StatusList: ["String"],
|
||||
// OwnerRef: "00000000000000000000000000000000",
|
||||
// ModifiedSince: "0001-01-01T00:00:00.0000000Z",
|
||||
// ModifiedUntil: "0001-01-01T00:00:00.0000000Z",
|
||||
// LastSaleSince: "0001-01-01T00:00:00.0000000Z",
|
||||
// VehicleIDList: ["00000000000000000000000000000000"],
|
||||
// IncludeInactive: false,
|
||||
// IncludeBuildVehicles: false,
|
||||
// ShortVIN: "String",
|
||||
},
|
||||
{ auth: PBS_CREDENTIALS }
|
||||
);
|
||||
CheckForErrors(socket, VehicleGetResponse);
|
||||
return VehicleGetResponse;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in QueryVehicleFromDms - ${error}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
async function QueryCustomersFromDms(socket) {
|
||||
try {
|
||||
const { data: CustomerGetResponse } = await axios.post(
|
||||
PBS_ENDPOINTS.ContactGet,
|
||||
{
|
||||
SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
|
||||
//ContactId: "00000000000000000000000000000000",
|
||||
ContactCode: socket.JobData.owner.accountingid,
|
||||
FirstName: socket.JobData.ownr_co_nm
|
||||
? socket.JobData.ownr_co_nm
|
||||
: socket.JobData.ownr_fn,
|
||||
LastName: socket.JobData.ownr_ln,
|
||||
PhoneNumber: socket.JobData.ownr_ph1,
|
||||
// EmailAddress: "String",
|
||||
// ModifiedSince: "0001-01-01T00:00:00.0000000Z",
|
||||
// ModifiedUntil: "0001-01-01T00:00:00.0000000Z",
|
||||
// ContactIdList: ["00000000000000000000000000000000"],
|
||||
// IncludeInactive: false,
|
||||
// PayableAccount: "String",
|
||||
// ReceivableAccount: "String",
|
||||
// DriverLicense: "String",
|
||||
// ZipCode: "String",
|
||||
},
|
||||
{ auth: PBS_CREDENTIALS }
|
||||
);
|
||||
CheckForErrors(socket, CustomerGetResponse);
|
||||
return CustomerGetResponse && CustomerGetResponse.Contacts;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in QueryCustomersFromDms - ${error}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
async function QueryCustomerBycodeFromDms(socket, CustomerRef) {
|
||||
try {
|
||||
const { data: CustomerGetResponse } = await axios.post(
|
||||
PBS_ENDPOINTS.ContactGet,
|
||||
{
|
||||
SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
|
||||
ContactId: CustomerRef,
|
||||
//ContactCode: socket.JobData.owner.accountingid,
|
||||
//FirstName: socket.JobData.ownr_co_nm
|
||||
// ? socket.JobData.ownr_co_nm
|
||||
// : socket.JobData.ownr_fn,
|
||||
//LastName: socket.JobData.ownr_ln,
|
||||
//PhoneNumber: socket.JobData.ownr_ph1,
|
||||
// EmailAddress: "String",
|
||||
// ModifiedSince: "0001-01-01T00:00:00.0000000Z",
|
||||
// ModifiedUntil: "0001-01-01T00:00:00.0000000Z",
|
||||
// ContactIdList: ["00000000000000000000000000000000"],
|
||||
// IncludeInactive: false,
|
||||
// PayableAccount: "String",
|
||||
// ReceivableAccount: "String",
|
||||
// DriverLicense: "String",
|
||||
// ZipCode: "String",
|
||||
},
|
||||
{ auth: PBS_CREDENTIALS }
|
||||
);
|
||||
CheckForErrors(socket, CustomerGetResponse);
|
||||
return CustomerGetResponse && CustomerGetResponse.Contacts;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in QueryCustomersFromDms - ${error}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function UpsertContactData(socket, selectedCustomerId) {
|
||||
try {
|
||||
const { data: ContactChangeResponse } = await axios.post(
|
||||
PBS_ENDPOINTS.ContactChange,
|
||||
{
|
||||
ContactInfo: {
|
||||
// Id: socket.JobData.owner.id,
|
||||
...(selectedCustomerId ? { ContactId: selectedCustomerId } : {}),
|
||||
SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
|
||||
Code: socket.JobData.owner.accountingid,
|
||||
...(socket.JobData.ownr_co_nm
|
||||
? {
|
||||
//LastName: socket.JobData.ownr_ln,
|
||||
FirstName: socket.JobData.ownr_co_nm,
|
||||
IsBusiness: true,
|
||||
}
|
||||
: {
|
||||
LastName: socket.JobData.ownr_ln,
|
||||
FirstName: socket.JobData.ownr_fn,
|
||||
IsBusiness: false,
|
||||
}),
|
||||
|
||||
//Salutation: "String",
|
||||
//MiddleName: "String",
|
||||
//ContactName: "String",
|
||||
IsInactive: false,
|
||||
|
||||
//ApartmentNumber: "String",
|
||||
Address: socket.JobData.ownr_addr1,
|
||||
City: socket.JobData.ownr_city,
|
||||
//County: socket.JobData.ownr_addr1,
|
||||
State: socket.JobData.ownr_st,
|
||||
ZipCode: socket.JobData.ownr_zip,
|
||||
//BusinessPhone: "String",
|
||||
//BusinessPhoneExt: "String",
|
||||
HomePhone: socket.JobData.ownr_ph2,
|
||||
CellPhone: socket.JobData.ownr_ph1,
|
||||
//BusinessPhoneRawReverse: "String",
|
||||
//HomePhoneRawReverse: "String",
|
||||
//CellPhoneRawReverse: "String",
|
||||
//FaxNumber: "String",
|
||||
EmailAddress: socket.JobData.ownr_ea,
|
||||
//Notes: "String",
|
||||
//CriticalMemo: "String",
|
||||
//BirthDate: "0001-01-01T00:00:00.0000000Z",
|
||||
// Gender: "String",
|
||||
// DriverLicense: "String",
|
||||
//PreferredContactMethods: ["String"],
|
||||
// LastUpdate: "0001-01-01T00:00:00.0000000Z",
|
||||
// CustomFields: [{ Key: "String", Value: "String", Type: "String" }],
|
||||
// FleetType: "String",
|
||||
// CommunicationPreferences: {
|
||||
// Email: "String",
|
||||
// Phone: "String",
|
||||
// TextMessage: "String",
|
||||
// Letter: "String",
|
||||
// Preferred: "String",
|
||||
// },
|
||||
// SalesRepRef: "00000000000000000000000000000000",
|
||||
// Language: "String",
|
||||
// PayableAccount: "String",
|
||||
// ReceivableAccount: "String",
|
||||
// IsStatic: false,
|
||||
// PrimaryImageRef: "00000000000000000000000000000000",
|
||||
// PayableAccounts: [{ SerialNumber: "String", Account: "String" }],
|
||||
// ReceivableAccounts: [{ SerialNumber: "String", Account: "String" }],
|
||||
// ManufacturerLoyaltyNumber: "String",
|
||||
},
|
||||
IsAsynchronous: false,
|
||||
// UserRequest: "String",
|
||||
// UserRef: "00000000000000000000000000000000",
|
||||
},
|
||||
{ auth: PBS_CREDENTIALS }
|
||||
);
|
||||
CheckForErrors(socket, ContactChangeResponse);
|
||||
return ContactChangeResponse;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in UpsertContactData - ${error}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function UpsertVehicleData(socket, ownerRef) {
|
||||
try {
|
||||
const { data: VehicleChangeResponse } = await axios.post(
|
||||
PBS_ENDPOINTS.VehicleChange,
|
||||
{
|
||||
VehicleInfo: {
|
||||
//Id: "string/00000000-0000-0000-0000-000000000000",
|
||||
//VehicleId: "00000000000000000000000000000000",
|
||||
SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
|
||||
//StockNumber: "String",
|
||||
VIN: socket.JobData.v_vin,
|
||||
LicenseNumber: socket.JobData.plate_no,
|
||||
//FleetNumber: "String",
|
||||
//Status: "String",
|
||||
OwnerRef: ownerRef, // "00000000000000000000000000000000",
|
||||
//ModelNumber: "String",
|
||||
Make: socket.JobData.v_make_desc,
|
||||
Model: socket.JobData.v_model_desc,
|
||||
//Trim: "String",
|
||||
//VehicleType: "String",
|
||||
Year: socket.JobData.v_model_yr,
|
||||
Odometer: socket.JobData.kmin,
|
||||
ExteriorColor: {
|
||||
Code: socket.JobData.v_color,
|
||||
//Description: "String",
|
||||
},
|
||||
// InteriorColor: { Code: "String", Description: "String" },
|
||||
//Engine: "String",
|
||||
// Cylinders: "String",
|
||||
// Transmission: "String",
|
||||
// DriveWheel: "String",
|
||||
// Fuel: "String",
|
||||
// Weight: 0,
|
||||
// InServiceDate: "0001-01-01T00:00:00.0000000Z",
|
||||
// LastServiceDate: "0001-01-01T00:00:00.0000000Z",
|
||||
// LastServiceMileage: 0,
|
||||
// Lot: "String",
|
||||
// LotDescription: "String",
|
||||
// Category: "String",
|
||||
// Options: [
|
||||
// {
|
||||
// Group: "String",
|
||||
// Code: "String",
|
||||
// Description: "String",
|
||||
// AdditionalInfo: "String",
|
||||
// Price: 0,
|
||||
// Cost: 0,
|
||||
// Residual: 0,
|
||||
// },
|
||||
// ],
|
||||
// Refurbishments: [
|
||||
// {
|
||||
// ReferenceNumber: "String",
|
||||
// Description: "String",
|
||||
// Price: 0,
|
||||
// Cost: 0,
|
||||
// Date: "0001-01-01T00:00:00.0000000Z",
|
||||
// ApplicationModel: "String",
|
||||
// },
|
||||
// ],
|
||||
// Order: {
|
||||
// InvoiceNumber: "String",
|
||||
// Price: 0,
|
||||
// Status: "String",
|
||||
// Eta: "String",
|
||||
// EstimatedCost: 0,
|
||||
// OrderDate: "String",
|
||||
// StatusDate: "String",
|
||||
// IgnitionKeyCode: "String",
|
||||
// DoorKeyCode: "String",
|
||||
// Description: "String",
|
||||
// LocationStatus: "String",
|
||||
// LocationStatusDate: "0001-01-01T00:00:00.0000000Z",
|
||||
// },
|
||||
// MSR: 0,
|
||||
// BaseMSR: 0,
|
||||
// Retail: 0,
|
||||
// DateReceived: "0001-01-01T00:00:00.0000000Z",
|
||||
// InternetPrice: 0,
|
||||
// Lotpack: 0,
|
||||
// Holdback: 0,
|
||||
// InternetNotes: "String",
|
||||
// Notes: "String",
|
||||
// CriticalMemo: "String",
|
||||
// IsCertified: false,
|
||||
// LastSaleDate: "0001-01-01T00:00:00.0000000Z",
|
||||
// LastUpdate: "0001-01-01T00:00:00.0000000Z",
|
||||
// AppraisedValue: 0,
|
||||
// Warranties: [
|
||||
// {
|
||||
// Type: "String",
|
||||
// CompanyName: "String",
|
||||
// CoveragePlan: "String",
|
||||
// Description: "String",
|
||||
// Price: 0,
|
||||
// Cost: 0,
|
||||
// Term: "String",
|
||||
// Deductible: 0,
|
||||
// PolicyNumber: "String",
|
||||
// StartDate: "String",
|
||||
// StartMileage: 0,
|
||||
// ExpirationDate: "String",
|
||||
// ExpirationMileage: 0,
|
||||
// },
|
||||
// ],
|
||||
// Freight: 0,
|
||||
// Air: 0,
|
||||
// Inventory: 0,
|
||||
// IsInactive: false,
|
||||
// CustomFields: [{ Key: "String", Value: "String", Type: "String" }],
|
||||
// FloorPlanCode: "String",
|
||||
// FloorPlanAmount: 0,
|
||||
// Insurance: {
|
||||
// Company: "String",
|
||||
// Policy: "String",
|
||||
// ExpiryDate: "0001-01-01T00:00:00.0000000Z",
|
||||
// AgentName: "String",
|
||||
// AgentPhoneNumber: "String",
|
||||
// },
|
||||
// Body: "String",
|
||||
// ShortVIN: "String",
|
||||
// AdditionalDrivers: ["00000000000000000000000000000000"],
|
||||
// OrderDetails: { Distributor: "String" },
|
||||
// PrimaryImageRef: "00000000000000000000000000000000",
|
||||
// Hold: {
|
||||
// VehicleRef: "00000000000000000000000000000000",
|
||||
// HoldFrom: "0001-01-01T00:00:00.0000000Z",
|
||||
// HoldUntil: "0001-01-01T00:00:00.0000000Z",
|
||||
// UserRef: "00000000000000000000000000000000",
|
||||
// ContactRef: "00000000000000000000000000000000",
|
||||
// Comments: "String",
|
||||
// },
|
||||
// SeatingCapacity: "String",
|
||||
// DeliveryDate: "0001-01-01T00:00:00.0000000Z",
|
||||
// WarrantyExpiry: "0001-01-01T00:00:00.0000000Z",
|
||||
// IsConditionallySold: false,
|
||||
// SalesDivision: 0,
|
||||
// StyleRef: "String",
|
||||
},
|
||||
IsAsynchronous: false,
|
||||
// UserRequest: "String",
|
||||
// UserRef: "00000000000000000000000000000000",
|
||||
},
|
||||
{ auth: PBS_CREDENTIALS }
|
||||
);
|
||||
CheckForErrors(socket, VehicleChangeResponse);
|
||||
return VehicleChangeResponse;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in UpsertVehicleData - ${error}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
async function InsertAccountPostingData(socket) {
|
||||
try {
|
||||
const allocations = await CalculateAllocations(socket, socket.JobData.id);
|
||||
|
||||
const wips = [];
|
||||
allocations.forEach((alloc) => {
|
||||
//Add the sale item from each allocation.
|
||||
if (alloc.sale.getAmount() > 0 && !alloc.tax) {
|
||||
const item = {
|
||||
Account: alloc.profitCenter.dms_acctnumber,
|
||||
ControlNumber: socket.JobData.ro_number,
|
||||
Amount: alloc.sale.multiply(-1).toFormat("0.0"),
|
||||
//Comment: "String",
|
||||
//AdditionalInfo: "String",
|
||||
InvoiceNumber: socket.JobData.ro_number,
|
||||
InvoiceDate: moment(socket.JobData.date_invoiced).toISOString(),
|
||||
};
|
||||
wips.push(item);
|
||||
}
|
||||
|
||||
//Add the cost Item.
|
||||
if (alloc.cost.getAmount() > 0 && !alloc.tax) {
|
||||
const item = {
|
||||
Account: alloc.costCenter.dms_acctnumber,
|
||||
ControlNumber: socket.JobData.ro_number,
|
||||
Amount: alloc.cost.toFormat("0.0"),
|
||||
//Comment: "String",
|
||||
//AdditionalInfo: "String",
|
||||
InvoiceNumber: socket.JobData.ro_number,
|
||||
InvoiceDate: moment(socket.JobData.date_invoiced).toISOString(),
|
||||
};
|
||||
wips.push(item);
|
||||
|
||||
const itemWip = {
|
||||
Account: alloc.costCenter.dms_wip_acctnumber,
|
||||
ControlNumber: socket.JobData.ro_number,
|
||||
Amount: alloc.cost.multiply(-1).toFormat("0.0"),
|
||||
//Comment: "String",
|
||||
//AdditionalInfo: "String",
|
||||
InvoiceNumber: socket.JobData.ro_number,
|
||||
InvoiceDate: moment(socket.JobData.date_invoiced).toISOString(),
|
||||
};
|
||||
wips.push(itemWip);
|
||||
//Add to the WIP account.
|
||||
}
|
||||
|
||||
if (alloc.tax) {
|
||||
if (alloc.sale.getAmount() > 0) {
|
||||
const item2 = {
|
||||
Account: alloc.profitCenter.dms_acctnumber,
|
||||
ControlNumber: socket.JobData.ro_number,
|
||||
Amount: alloc.sale.multiply(-1).toFormat("0.0"),
|
||||
//Comment: "String",
|
||||
//AdditionalInfo: "String",
|
||||
InvoiceNumber: socket.JobData.ro_number,
|
||||
InvoiceDate: moment(socket.JobData.date_invoiced).toISOString(),
|
||||
};
|
||||
wips.push(item2);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const { data: AccountPostingChange } = await axios.post(
|
||||
PBS_ENDPOINTS.AccountingPostingChange,
|
||||
{
|
||||
SerialNumber: socket.JobData.bodyshop.pbs_serialnumber,
|
||||
Posting: {
|
||||
Reference: socket.JobData.ro_number,
|
||||
JournalCode: socket.txEnvelope.journal,
|
||||
TransactionDate: moment(socket.JobData.date_invoiced).toISOString(), //"0001-01-01T00:00:00.0000000Z",
|
||||
Description: socket.txEnvelope.story,
|
||||
//AdditionalInfo: "String",
|
||||
Source: "ImEX Online",
|
||||
Lines: wips,
|
||||
},
|
||||
},
|
||||
{ auth: PBS_CREDENTIALS }
|
||||
);
|
||||
|
||||
CheckForErrors(socket, AccountPostingChange);
|
||||
return AccountPostingChange;
|
||||
} catch (error) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"ERROR",
|
||||
`Error in InsertAccountPostingData - ${error}`
|
||||
);
|
||||
throw new Error(error);
|
||||
}
|
||||
}
|
||||
|
||||
async function MarkJobExported(socket, jobid) {
|
||||
CdkBase.createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`Marking job as exported for id ${jobid}`
|
||||
);
|
||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
|
||||
const result = await client
|
||||
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
||||
.request(queries.MARK_JOB_EXPORTED, {
|
||||
jobId: jobid,
|
||||
job: {
|
||||
status:
|
||||
socket.JobData.bodyshop.md_ro_statuses.default_exported ||
|
||||
"Exported*",
|
||||
date_exported: new Date(),
|
||||
},
|
||||
log: {
|
||||
bodyshopid: socket.JobData.bodyshop.id,
|
||||
jobid: jobid,
|
||||
successful: true,
|
||||
useremail: socket.user.email,
|
||||
},
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
async function InsertFailedExportLog(socket, error) {
|
||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {});
|
||||
const result = await client
|
||||
.setHeaders({ Authorization: `Bearer ${socket.handshake.auth.token}` })
|
||||
.request(queries.INSERT_EXPORT_LOG, {
|
||||
log: {
|
||||
bodyshopid: socket.JobData.bodyshop.id,
|
||||
jobid: socket.JobData.id,
|
||||
successful: false,
|
||||
message: [error],
|
||||
useremail: socket.user.email,
|
||||
},
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -76,7 +76,12 @@ exports.default = function ({
|
||||
{
|
||||
local: false,
|
||||
federal: true,
|
||||
state: jobline.tax_part,
|
||||
state:
|
||||
jobs_by_pk.state_tax_rate === 0
|
||||
? false
|
||||
: jobline.db_ref === "900511" || jobline.db_ref === "900510"
|
||||
? true
|
||||
: jobline.tax_part,
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -142,7 +147,7 @@ exports.default = function ({
|
||||
{
|
||||
local: false,
|
||||
federal: true,
|
||||
state: true,
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -204,7 +209,7 @@ exports.default = function ({
|
||||
{
|
||||
local: false,
|
||||
federal: true,
|
||||
state: true,
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -267,7 +272,7 @@ exports.default = function ({
|
||||
{
|
||||
local: false,
|
||||
federal: true,
|
||||
state: true,
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -346,7 +351,7 @@ exports.default = function ({
|
||||
{
|
||||
local: false,
|
||||
federal: true,
|
||||
state: true,
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -394,7 +399,7 @@ exports.default = function ({
|
||||
{
|
||||
local: false,
|
||||
federal: true,
|
||||
state: true,
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
@@ -445,7 +450,7 @@ exports.default = function ({
|
||||
{
|
||||
local: false,
|
||||
federal: true,
|
||||
state: true,
|
||||
state: jobs_by_pk.state_tax_rate === 0 ? false : true,
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const urlBuilder = require("./qbo").urlBuilder;
|
||||
const StandardizeName = require("./qbo").StandardizeName;
|
||||
const path = require("path");
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
@@ -114,7 +115,9 @@ async function QueryVendorRecord(oauthClient, qbo_realmId, req, bill) {
|
||||
url: urlBuilder(
|
||||
qbo_realmId,
|
||||
"query",
|
||||
`select * From vendor where DisplayName = '${bill.vendor.name}'`
|
||||
`select * From vendor where DisplayName = '${StandardizeName(
|
||||
bill.vendor.name
|
||||
)}'`
|
||||
),
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -152,7 +155,7 @@ async function InsertVendorRecord(oauthClient, qbo_realmId, req, bill) {
|
||||
body: JSON.stringify(Vendor),
|
||||
});
|
||||
setNewRefreshToken(req.user.email, result);
|
||||
return result && result.Vendor;
|
||||
return result && result.json && result.json.Vendor;
|
||||
} catch (error) {
|
||||
logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, {
|
||||
error:
|
||||
@@ -180,9 +183,9 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor) {
|
||||
DocNumber: bill.invoice_number,
|
||||
...(bill.job.class ? { ClassRef: { Id: classes[bill.job.class] } } : {}),
|
||||
|
||||
Memo: `RO ${bill.job.ro_number || ""} OWNER ${bill.job.ownr_fn || ""} ${
|
||||
bill.job.ownr_ln || ""
|
||||
} ${bill.job.ownr_co_nm || ""}`,
|
||||
PrivateNote: `RO ${bill.job.ro_number || ""} OWNER ${
|
||||
bill.job.ownr_fn || ""
|
||||
} ${bill.job.ownr_ln || ""} ${bill.job.ownr_co_nm || ""}`,
|
||||
Line: bill.billlines.map((il) =>
|
||||
generateBillLine(
|
||||
il,
|
||||
@@ -211,7 +214,7 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor) {
|
||||
body: JSON.stringify(billQbo),
|
||||
});
|
||||
setNewRefreshToken(req.user.email, result);
|
||||
return result && result.Bill;
|
||||
return result && result.json && result.json.Bill;
|
||||
} catch (error) {
|
||||
logger.log("qbo-payables-error", "DEBUG", req.user.email, bill.id, {
|
||||
error:
|
||||
@@ -245,6 +248,8 @@ const generateBillLine = (
|
||||
costCenters
|
||||
) => {
|
||||
const account = costCenters.find((c) => c.name === billLine.cost_center);
|
||||
|
||||
console.log(account.accountname, accounts[account.accountname]);
|
||||
return {
|
||||
DetailType: "AccountBasedExpenseLineDetail",
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ const {
|
||||
} = require("../qbo/qbo-receivables");
|
||||
const { urlBuilder } = require("./qbo");
|
||||
const { DineroQbFormat } = require("../accounting-constants");
|
||||
const { findTaxCode } = require("../qb-receivables-lines");
|
||||
|
||||
exports.default = async (req, res) => {
|
||||
const oauthClient = new OAuthClient({
|
||||
@@ -135,7 +136,17 @@ exports.default = async (req, res) => {
|
||||
);
|
||||
}
|
||||
|
||||
await InsertPayment(oauthClient, qbo_realmId, req, payment, jobTier);
|
||||
if (payment.amount > 0) {
|
||||
await InsertPayment(oauthClient, qbo_realmId, req, payment, jobTier);
|
||||
} else {
|
||||
await InsertCreditMemo(
|
||||
oauthClient,
|
||||
qbo_realmId,
|
||||
req,
|
||||
payment,
|
||||
jobTier
|
||||
);
|
||||
}
|
||||
ret.push({ paymentid: payment.id, success: true });
|
||||
} catch (error) {
|
||||
logger.log("qbo-payment-create-error", "ERROR", req.user.email, {
|
||||
@@ -173,7 +184,8 @@ async function InsertPayment(
|
||||
oauthClient,
|
||||
qbo_realmId,
|
||||
req,
|
||||
payment.job.ro_number
|
||||
payment.job.ro_number,
|
||||
false
|
||||
);
|
||||
|
||||
if (invoices && invoices.length !== 1) {
|
||||
@@ -235,7 +247,13 @@ async function InsertPayment(
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number) {
|
||||
async function QueryMetaData(
|
||||
oauthClient,
|
||||
qbo_realmId,
|
||||
req,
|
||||
ro_number,
|
||||
isCreditMemo
|
||||
) {
|
||||
const invoice = await oauthClient.makeApiCall({
|
||||
url: urlBuilder(
|
||||
qbo_realmId,
|
||||
@@ -288,8 +306,50 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number) {
|
||||
// classes.json.QueryResponse.Class.forEach((t) => {
|
||||
// accountMapping[t.Name] = t.Id;
|
||||
// });
|
||||
let ret = {};
|
||||
|
||||
if (isCreditMemo) {
|
||||
const taxCodes = await oauthClient.makeApiCall({
|
||||
url: urlBuilder(qbo_realmId, "query", `select * From TaxCode`),
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
const items = await oauthClient.makeApiCall({
|
||||
url: urlBuilder(qbo_realmId, "query", `select * From Item`),
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
setNewRefreshToken(req.user.email, items);
|
||||
|
||||
const itemMapping = {};
|
||||
|
||||
items.json &&
|
||||
items.json.QueryResponse &&
|
||||
items.json.QueryResponse.Item &&
|
||||
items.json.QueryResponse.Item.forEach((t) => {
|
||||
itemMapping[t.Name] = t.Id;
|
||||
});
|
||||
const taxCodeMapping = {};
|
||||
|
||||
taxCodes.json &&
|
||||
taxCodes.json.QueryResponse &&
|
||||
taxCodes.json.QueryResponse.TaxCode &&
|
||||
taxCodes.json.QueryResponse.TaxCode.forEach((t) => {
|
||||
taxCodeMapping[t.Name] = t.Id;
|
||||
});
|
||||
ret = {
|
||||
...ret,
|
||||
items: itemMapping,
|
||||
taxCodes: taxCodeMapping,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...ret,
|
||||
paymentMethods: paymentMethodMapping,
|
||||
invoices:
|
||||
invoice.json &&
|
||||
@@ -297,3 +357,87 @@ async function QueryMetaData(oauthClient, qbo_realmId, req, ro_number) {
|
||||
invoice.json.QueryResponse.Invoice,
|
||||
};
|
||||
}
|
||||
async function InsertCreditMemo(
|
||||
oauthClient,
|
||||
qbo_realmId,
|
||||
req,
|
||||
payment,
|
||||
parentRef
|
||||
) {
|
||||
const { paymentMethods, invoices, items, taxCodes } = await QueryMetaData(
|
||||
oauthClient,
|
||||
qbo_realmId,
|
||||
req,
|
||||
payment.job.ro_number,
|
||||
true
|
||||
);
|
||||
|
||||
if (invoices && invoices.length !== 1) {
|
||||
throw new Error(
|
||||
`More than 1 invoice with DocNumber ${payment.ro_number} found.`
|
||||
);
|
||||
}
|
||||
|
||||
const paymentQbo = {
|
||||
CustomerRef: {
|
||||
value: parentRef.Id,
|
||||
},
|
||||
TxnDate: moment(payment.date).format("YYYY-MM-DD"),
|
||||
DocNumber: payment.paymentnum,
|
||||
...(invoices && invoices[0]
|
||||
? { InvoiceRef: { value: invoices[0].Id } }
|
||||
: {}),
|
||||
Line: [
|
||||
{
|
||||
DetailType: "SalesItemLineDetail",
|
||||
Amount: Dinero({ amount: Math.round(payment.amount * -100) }).toFormat(
|
||||
DineroQbFormat
|
||||
),
|
||||
SalesItemLineDetail: {
|
||||
ItemRef: {
|
||||
value:
|
||||
items[
|
||||
payment.job.bodyshop.md_responsibility_centers.refund
|
||||
.accountitem
|
||||
],
|
||||
},
|
||||
Qty: 1,
|
||||
TaxCodeRef: {
|
||||
value:
|
||||
taxCodes[
|
||||
findTaxCode(
|
||||
{
|
||||
local: false,
|
||||
federal: false,
|
||||
state: false,
|
||||
},
|
||||
payment.job.bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
)
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
logger.log("qbo-payments-objectlog", "DEBUG", req.user.email, payment.id, {
|
||||
paymentQbo,
|
||||
});
|
||||
try {
|
||||
const result = await oauthClient.makeApiCall({
|
||||
url: urlBuilder(qbo_realmId, "creditmemo"),
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(paymentQbo),
|
||||
});
|
||||
setNewRefreshToken(req.user.email, result);
|
||||
return result && result.Bill;
|
||||
} catch (error) {
|
||||
logger.log("qbo-payables-error", "DEBUG", req.user.email, payment.id, {
|
||||
error: error && error.message,
|
||||
method: "InsertCreditMemo",
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
const urlBuilder = require("./qbo").urlBuilder;
|
||||
const StandardizeName = require("./qbo").StandardizeName;
|
||||
|
||||
const path = require("path");
|
||||
require("dotenv").config({
|
||||
path: path.resolve(
|
||||
@@ -166,7 +168,9 @@ async function QueryInsuranceCo(oauthClient, qbo_realmId, req, job) {
|
||||
url: urlBuilder(
|
||||
qbo_realmId,
|
||||
"query",
|
||||
`select * From Customer where DisplayName = '${job.ins_co_nm}'`
|
||||
`select * From Customer where DisplayName = '${StandardizeName(
|
||||
job.ins_co_nm
|
||||
)}'`
|
||||
),
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -228,7 +232,9 @@ async function QueryOwner(oauthClient, qbo_realmId, req, job) {
|
||||
url: urlBuilder(
|
||||
qbo_realmId,
|
||||
"query",
|
||||
`select * From Customer where DisplayName = '${ownerName}'`
|
||||
`select * From Customer where DisplayName = '${StandardizeName(
|
||||
ownerName
|
||||
)}'`
|
||||
),
|
||||
method: "POST",
|
||||
headers: {
|
||||
@@ -458,7 +464,7 @@ async function InsertInvoice(
|
||||
body: JSON.stringify(invoiceObj),
|
||||
});
|
||||
setNewRefreshToken(req.user.email, result);
|
||||
return result && result.Invoice;
|
||||
return result && result.json && result.json.Invoice;
|
||||
} catch (error) {
|
||||
logger.log("qbo-receivables-error", "DEBUG", req.user.email, job.id, {
|
||||
error,
|
||||
|
||||
@@ -14,7 +14,12 @@ function urlBuilder(realmId, object, query = null) {
|
||||
}`;
|
||||
}
|
||||
|
||||
function StandardizeName(str) {
|
||||
return str.replace(new RegExp(/'/g), "\\'");
|
||||
}
|
||||
|
||||
exports.urlBuilder = urlBuilder;
|
||||
exports.StandardizeName = StandardizeName;
|
||||
exports.callback = require("./qbo-callback").default;
|
||||
exports.authorize = require("./qbo-authorize").default;
|
||||
exports.refresh = require("./qbo-callback").refresh;
|
||||
|
||||
@@ -37,7 +37,6 @@ exports.default = async function ReloadCdkMakes(req, res) {
|
||||
const BearerToken = req.headers.authorization;
|
||||
//Query all CDK Models
|
||||
const newList = await GetCdkMakes(req, cdk_dealerid);
|
||||
console.log("🚀 ~ file: cdk-get-makes.js ~ line 40 ~ newList", newList);
|
||||
|
||||
//Clear out the existing records
|
||||
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||
@@ -69,10 +68,6 @@ exports.default = async function ReloadCdkMakes(req, res) {
|
||||
};
|
||||
}),
|
||||
});
|
||||
console.log(
|
||||
"🚀 ~ file: cdk-get-makes.js ~ line 66 ~ insertResult",
|
||||
insertResult
|
||||
);
|
||||
|
||||
logger.log(
|
||||
"cdk-replace-makes-models-success",
|
||||
@@ -121,9 +116,28 @@ async function GetCdkMakes(req, cdk_dealerid) {
|
||||
);
|
||||
|
||||
CheckCdkResponseForError(null, soapResponseVehicleSearch);
|
||||
const [
|
||||
result, //rawResponse, soapheader, rawRequest
|
||||
] = soapResponseVehicleSearch;
|
||||
const [result, rawResponse, , rawRequest] = soapResponseVehicleSearch;
|
||||
logger.log(
|
||||
"cdk-replace-makes-models-request",
|
||||
"ERROR",
|
||||
req.user.email,
|
||||
null,
|
||||
{
|
||||
cdk_dealerid,
|
||||
xml: rawRequest,
|
||||
}
|
||||
);
|
||||
|
||||
logger.log(
|
||||
"cdk-replace-makes-models-response",
|
||||
"ERROR",
|
||||
req.user.email,
|
||||
null,
|
||||
{
|
||||
cdk_dealerid,
|
||||
xml: rawResponse,
|
||||
}
|
||||
);
|
||||
|
||||
return result.return;
|
||||
} catch (error) {
|
||||
|
||||
@@ -15,7 +15,7 @@ const CalcualteAllocations = require("./cdk-calculate-allocations").default;
|
||||
|
||||
const moment = require("moment");
|
||||
|
||||
const replaceSpecialRegex = `[^a-zA-Z0-9 .,\n #]+/g`;
|
||||
const replaceSpecialRegex = /[^a-zA-Z0-9 .,\n #]+/g;
|
||||
|
||||
exports.default = async function (socket, { txEnvelope, jobid }) {
|
||||
socket.logEvents = [];
|
||||
@@ -180,7 +180,7 @@ async function CdkSelectedCustomer(socket, selectedCustomerId) {
|
||||
`{5} Updating Service Vehicle History.`
|
||||
);
|
||||
socket.DMSVehHistory = await InsertServiceVehicleHistory(socket);
|
||||
socket.emit("export-success", socket.JobData.id);
|
||||
// socket.emit("export-success", socket.JobData.id);
|
||||
} else {
|
||||
//Get the error code
|
||||
CdkBase.createLogEvent(
|
||||
@@ -584,15 +584,21 @@ async function InsertDmsCustomer(socket, newCustomerNumber) {
|
||||
addressLine:
|
||||
socket.JobData.ownr_addr1 &&
|
||||
socket.JobData.ownr_addr1.replace(replaceSpecialRegex, ""),
|
||||
city: socket.JobData.ownr_city&& socket.JobData.ownr_city.replace(replaceSpecialRegex, ""),
|
||||
country: null,
|
||||
city:
|
||||
socket.JobData.ownr_city &&
|
||||
socket.JobData.ownr_city.replace(replaceSpecialRegex, ""),
|
||||
country:
|
||||
socket.JobData.ownr_ctry &&
|
||||
socket.JobData.ownr_ctry.replace(replaceSpecialRegex, ""),
|
||||
postalCode:
|
||||
socket.JobData.ownr_zip &&
|
||||
socket.JobData.ownr_zip //TODO Need to remove for US Based customers.
|
||||
.toUpperCase()
|
||||
.replace(/\W/g, "")
|
||||
.replace(/(...)/, "$1 "),
|
||||
stateOrProvince: socket.JobData.ownr_st&&socket.JobData.ownr_st.replace(replaceSpecialRegex, ""),
|
||||
stateOrProvince:
|
||||
socket.JobData.ownr_st &&
|
||||
socket.JobData.ownr_st.replace(replaceSpecialRegex, ""),
|
||||
},
|
||||
contactInfo: {
|
||||
mainTelephoneNumber: {
|
||||
@@ -601,23 +607,33 @@ async function InsertDmsCustomer(socket, newCustomerNumber) {
|
||||
},
|
||||
email: {
|
||||
desc: socket.JobData.ownr_ea ? "Other" : "CustomerDeclined",
|
||||
value: socket.JobData.ownr_ea ? "Other" : null,
|
||||
value: socket.JobData.ownr_ea ? socket.JobData.ownr_ea : null,
|
||||
},
|
||||
},
|
||||
demographics: null,
|
||||
name1: {
|
||||
companyname:
|
||||
companyName:
|
||||
socket.JobData.ownr_co_nm &&
|
||||
socket.JobData.ownr_co_nm.replace(replaceSpecialRegex, ""),
|
||||
socket.JobData.ownr_co_nm
|
||||
.replace(replaceSpecialRegex, "")
|
||||
.toUpperCase(),
|
||||
|
||||
firstName:
|
||||
socket.JobData.ownr_fn &&
|
||||
socket.JobData.ownr_fn.replace(replaceSpecialRegex, ""),
|
||||
socket.JobData.ownr_fn
|
||||
.replace(replaceSpecialRegex, "")
|
||||
.toUpperCase(),
|
||||
fullname: null,
|
||||
lastName:
|
||||
socket.JobData.ownr_ln &&
|
||||
socket.JobData.ownr_ln.replace(replaceSpecialRegex, ""),
|
||||
socket.JobData.ownr_ln
|
||||
.replace(replaceSpecialRegex, "")
|
||||
.toUpperCase(),
|
||||
middleName: null,
|
||||
nameType: "Person",
|
||||
nameType:
|
||||
socket.JobData.ownr_co_nm && socket.JobData.ownr_co_nm
|
||||
? "Business"
|
||||
: "Person",
|
||||
suffix: null,
|
||||
title: null,
|
||||
},
|
||||
@@ -694,6 +710,7 @@ async function InsertDmsVehicle(socket) {
|
||||
manufacturer: {},
|
||||
vehicle: {
|
||||
deliveryDate: moment().format("YYYYMMDD"),
|
||||
licensePlateNo: socket.JobData.plate_no,
|
||||
make: socket.txEnvelope.dms_make,
|
||||
modelAbrev: socket.txEnvelope.dms_model,
|
||||
modelYear: socket.JobData.v_model_yr,
|
||||
@@ -752,6 +769,31 @@ async function UpdateDmsVehicle(socket) {
|
||||
CdkWsdl.VehicleInsertUpdate
|
||||
);
|
||||
|
||||
let ids = [];
|
||||
|
||||
const existingOwnerinVeh = socket.DMSVeh.owners.filter(
|
||||
(o) => o.id.value === socket.DMSCust.id.value
|
||||
);
|
||||
|
||||
if (existingOwnerinVeh) {
|
||||
ids = socket.DMSVeh.owners.filter(
|
||||
(o) => o.id.value === socket.DMSCust.id.value
|
||||
);
|
||||
} else {
|
||||
ids = [
|
||||
{
|
||||
assigningPartyId: "CURRENT",
|
||||
value: socket.DMSCust.id.value,
|
||||
},
|
||||
...socket.DMSVeh.owners.map((o) => {
|
||||
return {
|
||||
assigningPartyId: "PREVIOUS",
|
||||
value: o.id.value,
|
||||
};
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
const soapResponseVehicleInsertUpdate =
|
||||
await soapClientVehicleInsertUpdate.updateAsync({
|
||||
arg0: CDK_CREDENTIALS,
|
||||
@@ -770,12 +812,7 @@ async function UpdateDmsVehicle(socket) {
|
||||
socket.DMSVeh.vehicle.deliveryDate
|
||||
).toISOString(),
|
||||
},
|
||||
owners: {
|
||||
id: {
|
||||
assigningPartyId: "CURRENT",
|
||||
value: socket.DMSCust.id.value,
|
||||
},
|
||||
},
|
||||
owners: { ids: ids },
|
||||
},
|
||||
arg3: "VEHICLES",
|
||||
});
|
||||
@@ -829,9 +866,9 @@ async function InsertServiceVehicleHistory(socket) {
|
||||
roNumber: socket.JobData.ro_number.match(/\d+/g),
|
||||
mileage: socket.txEnvelope.kmout,
|
||||
openDate: moment(socket.JobData.actual_in).format("YYYY-MM-DD"),
|
||||
openTime: moment(socket.JobData.actual_in).format("HH:MM:SS"),
|
||||
openTime: moment(socket.JobData.actual_in).format("HH:MM:ss"),
|
||||
closeDate: moment(socket.JobData.invoice_date).format("YYYY-MM-DD"),
|
||||
closeTime: moment(socket.JobData.invoice_date).format("HH:MM:SS"),
|
||||
closeTime: moment(socket.JobData.invoice_date).format("HH:MM:ss"),
|
||||
comments: socket.txEnvelope.story,
|
||||
cashierID: socket.JobData.bodyshop.cdk_configuration.cashierid,
|
||||
},
|
||||
|
||||
@@ -70,11 +70,15 @@ exports.default = async (req, res) => {
|
||||
}
|
||||
|
||||
var ret = builder
|
||||
.create(autoHouseObject, {
|
||||
version: "1.0",
|
||||
encoding: "UTF-8",
|
||||
})
|
||||
.end({ pretty: true, allowEmptyTags: true });
|
||||
.create(
|
||||
{
|
||||
version: "1.0",
|
||||
encoding: "UTF-8",
|
||||
keepNullNodes: true,
|
||||
},
|
||||
autoHouseObject
|
||||
)
|
||||
.end({ allowEmptyTags: true });
|
||||
|
||||
allxmlsToUpload.push({
|
||||
xml: ret,
|
||||
@@ -107,6 +111,11 @@ exports.default = async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
res.sendStatus(200);
|
||||
return;
|
||||
}
|
||||
|
||||
let sftp = new Client();
|
||||
sftp.on("error", (errors) =>
|
||||
logger.log("autohouse-sftp-error", "ERROR", "api", null, {
|
||||
@@ -239,7 +248,8 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
ReferralDate: null,
|
||||
EstimateAppointmentDate: null,
|
||||
SecondFollowUpDate: null,
|
||||
AssignedDate: null,
|
||||
AssignedDate:
|
||||
job.asgn_date && moment(job.asgn_date).format(AhDateFormat),
|
||||
EstComplete: null,
|
||||
CustomerAuthorizationDate: null,
|
||||
InsuranceAuthorizationDate: null,
|
||||
@@ -248,7 +258,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
job.scheduled_in && moment(job.scheduled_in).format(AhDateFormat),
|
||||
CarinShop: job.actual_in && moment(job.actual_in).format(AhDateFormat),
|
||||
InsInspDate: null,
|
||||
StartDate: null,
|
||||
StartDate: job.actual_in && moment(job.actual_in).format(AhDateFormat),
|
||||
PartsOrder: null,
|
||||
TeardownHold: null,
|
||||
SupplementSubmittedDate: null,
|
||||
@@ -287,7 +297,10 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
StructuralRate: job.rate_las,
|
||||
PMRate: job.rate_mapa,
|
||||
BMRate: job.rate_mash,
|
||||
TaxRate: null,
|
||||
TaxRate:
|
||||
job.parts_tax_rates &&
|
||||
job.parts_tax_rates.PAN &&
|
||||
job.parts_tax_rates.PAN.prt_tax_rt,
|
||||
StorageRateperDay: null,
|
||||
DaysStored: null,
|
||||
},
|
||||
@@ -389,39 +402,45 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
job.job_totals.parts.parts.list.PAA.total
|
||||
).toFormat(AHDineroFormat),
|
||||
PartsAMCost: repairCosts.PartsAMCost.toFormat(AHDineroFormat),
|
||||
PartsReconditioned: null,
|
||||
PartsReconditioned:
|
||||
repairCosts.PartsReconditionedCost.toFormat(AHDineroFormat),
|
||||
PartsReconditionedCost:
|
||||
repairCosts.PartsReconditionedCost.toFormat(AHDineroFormat),
|
||||
PartsRecycled: Dinero(
|
||||
job.job_totals.parts.parts.list.PAR &&
|
||||
job.job_totals.parts.parts.list.PAR.total
|
||||
).toFormat(AHDineroFormat),
|
||||
PartsRecycledCost: null,
|
||||
PartsRecycledCost:
|
||||
repairCosts.PartsRecycledCost.toFormat(AHDineroFormat),
|
||||
PartsOther: Dinero(
|
||||
job.job_totals.parts.parts.list.PAO &&
|
||||
job.job_totals.parts.parts.list.PAO.total
|
||||
).toFormat(AHDineroFormat),
|
||||
PartsOtherCost: null,
|
||||
PartsOtherCost: repairCosts.PartsOtherCost.toFormat(AHDineroFormat),
|
||||
SubletTotal: Dinero(job.job_totals.parts.sublets.total).toFormat(
|
||||
AHDineroFormat
|
||||
),
|
||||
SubletTotalCost: 0,
|
||||
SubletTotalCost: repairCosts.SubletTotalCost.toFormat(AHDineroFormat),
|
||||
BodyLaborTotal: Dinero(job.job_totals.rates.lab.total).toFormat(
|
||||
AHDineroFormat
|
||||
),
|
||||
BodyLaborTotalCost: 0,
|
||||
BodyLaborTotalCost:
|
||||
repairCosts.BodyLaborTotalCost.toFormat(AHDineroFormat),
|
||||
RefinishLaborTotal: Dinero(job.job_totals.rates.lar.total).toFormat(
|
||||
AHDineroFormat
|
||||
),
|
||||
RefinishLaborTotalCost: 0,
|
||||
RefinishLaborTotalCost:
|
||||
repairCosts.RefinishLaborTotalCost.toFormat(AHDineroFormat),
|
||||
MechanicalLaborTotal: Dinero(job.job_totals.rates.lam.total).toFormat(
|
||||
AHDineroFormat
|
||||
),
|
||||
MechanicalLaborTotalCost: 0,
|
||||
MechanicalLaborTotalCost:
|
||||
repairCosts.MechanicalLaborTotalCost.toFormat(AHDineroFormat),
|
||||
StructuralLaborTotal: Dinero(job.job_totals.rates.las.total).toFormat(
|
||||
AHDineroFormat
|
||||
),
|
||||
StructuralLaborTotalCost: null,
|
||||
StructuralLaborTotalCost:
|
||||
repairCosts.StructuralLaborTotalCost.toFormat(AHDineroFormat),
|
||||
MiscellaneousChargeTotal: null,
|
||||
MiscellaneousChargeTotalCost: null,
|
||||
PMTotal: Dinero(job.job_totals.rates.mapa.total).toFormat(
|
||||
@@ -437,11 +456,11 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
TowingTotal: Dinero(job.job_totals.additional.towing).toFormat(
|
||||
AHDineroFormat
|
||||
),
|
||||
TowingTotalCost: null,
|
||||
TowingTotalCost: repairCosts.TowingTotalCost.toFormat(AHDineroFormat),
|
||||
StorageTotal: Dinero(job.job_totals.additional.storage).toFormat(
|
||||
AHDineroFormat
|
||||
),
|
||||
StorageTotalCost: null,
|
||||
StorageTotalCost: repairCosts.StorageTotalCost.toFormat(AHDineroFormat),
|
||||
DetailTotal: null,
|
||||
DetailTotalCost: null,
|
||||
SalesTaxTotal: Dinero(job.job_totals.totals.local_tax)
|
||||
@@ -472,7 +491,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
Hub50Comment: null,
|
||||
DateofChange: null,
|
||||
BodyTechName: null,
|
||||
TotalLossYN: null,
|
||||
TotalLossYN: job.tlos_ind ? "Y" : "N",
|
||||
InsScreenCommentsLine1: null,
|
||||
InsScreenCommentsLine2: null,
|
||||
AssignmentCaller: null,
|
||||
@@ -483,7 +502,9 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
PaintTechName: null,
|
||||
ImportType: null,
|
||||
ImportFile: null,
|
||||
GSTTax: null,
|
||||
GSTTax: Dinero(job.job_totals.totals.federal_tax).toFormat(
|
||||
AHDineroFormat
|
||||
),
|
||||
RepairDelayStatusCode: null,
|
||||
RepairDelaycomment: null,
|
||||
AgentMktgID: null,
|
||||
|
||||
@@ -126,6 +126,7 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
||||
towing_payable
|
||||
storage_payable
|
||||
adjustment_bottom_line
|
||||
state_tax_rate
|
||||
owner {
|
||||
accountingid
|
||||
}
|
||||
@@ -168,12 +169,14 @@ query QUERY_JOBS_FOR_CDK_EXPORT($id: uuid!) {
|
||||
ownerid
|
||||
ownr_ln
|
||||
ownr_fn
|
||||
ownr_co_nm
|
||||
ownr_addr1
|
||||
ownr_addr2
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_zip
|
||||
ownr_city
|
||||
ownr_ctry
|
||||
ownr_st
|
||||
ownr_ea
|
||||
ins_co_nm
|
||||
@@ -241,6 +244,94 @@ query QUERY_JOBS_FOR_CDK_EXPORT($id: uuid!) {
|
||||
}
|
||||
`;
|
||||
|
||||
exports.QUERY_JOBS_FOR_PBS_EXPORT = `
|
||||
query QUERY_JOBS_FOR_PBS_EXPORT($id: uuid!) {
|
||||
jobs_by_pk(id: $id) {
|
||||
id
|
||||
job_totals
|
||||
date_invoiced
|
||||
ro_number
|
||||
clm_total
|
||||
clm_no
|
||||
invoice_allocation
|
||||
ownerid
|
||||
ownr_ln
|
||||
ownr_fn
|
||||
ownr_addr1
|
||||
ownr_addr2
|
||||
ownr_ph1
|
||||
ownr_ph2
|
||||
ownr_zip
|
||||
ownr_city
|
||||
ownr_ctry
|
||||
ownr_st
|
||||
ownr_ea
|
||||
ins_co_nm
|
||||
job_totals
|
||||
rate_la1
|
||||
rate_la2
|
||||
rate_la3
|
||||
rate_la4
|
||||
rate_laa
|
||||
rate_lab
|
||||
rate_lad
|
||||
rate_lae
|
||||
rate_laf
|
||||
rate_lag
|
||||
rate_lam
|
||||
rate_lar
|
||||
rate_las
|
||||
rate_lau
|
||||
rate_ma2s
|
||||
rate_ma2t
|
||||
rate_ma3s
|
||||
rate_mabl
|
||||
rate_macs
|
||||
rate_mahw
|
||||
rate_mapa
|
||||
rate_mash
|
||||
rate_matd
|
||||
class
|
||||
ca_bc_pvrt
|
||||
plate_no
|
||||
plate_st
|
||||
v_vin
|
||||
v_model_yr
|
||||
v_model_desc
|
||||
v_make_desc
|
||||
v_color
|
||||
ca_customer_gst
|
||||
bodyshop {
|
||||
id
|
||||
md_ro_statuses
|
||||
md_responsibility_centers
|
||||
accountingconfig
|
||||
pbs_serialnumber
|
||||
pbs_configuration
|
||||
}
|
||||
owner {
|
||||
id
|
||||
accountingid
|
||||
}
|
||||
joblines(where:{removed: {_eq:false}}) {
|
||||
id
|
||||
line_desc
|
||||
part_type
|
||||
act_price
|
||||
mod_lb_hrs
|
||||
mod_lbr_ty
|
||||
part_qty
|
||||
op_code_desc
|
||||
profitcenter_labor
|
||||
profitcenter_part
|
||||
db_ref
|
||||
prt_dsmk_p
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
`;
|
||||
|
||||
exports.QUERY_BILLS_FOR_PAYABLES_EXPORT = `
|
||||
query QUERY_BILLS_FOR_PAYABLES_EXPORT($bills: [uuid!]!) {
|
||||
bills(where: {id: {_in: $bills}}) {
|
||||
@@ -464,6 +555,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshop
|
||||
rate_mash
|
||||
job_totals
|
||||
driveable
|
||||
parts_tax_rates
|
||||
bodyshop {
|
||||
id
|
||||
shopname
|
||||
@@ -797,6 +889,7 @@ exports.GET_JOB_BY_PK = ` query GET_JOB_BY_PK($id: uuid!) {
|
||||
line_ind
|
||||
line_desc
|
||||
part_type
|
||||
line_ref
|
||||
oem_partno
|
||||
db_price
|
||||
act_price
|
||||
|
||||
@@ -486,7 +486,9 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
Dinero({ amount: Math.round((val.act_price || 0) * 100) })
|
||||
.multiply(val.part_qty || 0)
|
||||
.add(
|
||||
val.prt_dsmk_m && val.prt_dsmk_m !== 0
|
||||
val.prt_dsmk_m &&
|
||||
val.prt_dsmk_m !== 0 &&
|
||||
DiscountNotAlreadyCounted(val, job.joblines)
|
||||
? Dinero({ amount: Math.round(val.prt_dsmk_m * 100) })
|
||||
: Dinero({
|
||||
amount: Math.round(val.act_price * 100),
|
||||
@@ -566,3 +568,9 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
}
|
||||
|
||||
exports.default = Totals;
|
||||
|
||||
function DiscountNotAlreadyCounted(jobline, joblines) {
|
||||
if (jobline.db_ref !== "900510") return true;
|
||||
const ParentLine = joblines.find((j) => j.unq_seq === jobline.line_ref);
|
||||
return ParentLine && !(ParentLine.prt_dsmk_m && ParentLine.prt_dsmk_m !== 0);
|
||||
}
|
||||
|
||||
@@ -78,15 +78,17 @@ exports.receive = async (req, res) => {
|
||||
});
|
||||
}
|
||||
try {
|
||||
const r2 = await client.request(queries.RECEIVE_MESSAGE, {
|
||||
msg: newMessage,
|
||||
});
|
||||
if (response.bodyshops[0].conversations[0]) {
|
||||
const r3 = await client.request(queries.INSERT_MESSAGE, {
|
||||
id:
|
||||
msg: newMessage,
|
||||
conversationid:
|
||||
response.bodyshops[0].conversations[0] &&
|
||||
response.bodyshops[0].conversations[0].id,
|
||||
});
|
||||
} else {
|
||||
const r2 = await client.request(queries.RECEIVE_MESSAGE, {
|
||||
msg: newMessage,
|
||||
});
|
||||
}
|
||||
|
||||
logger.log("sms-inbound-success", "DEBUG", "api", null, {
|
||||
|
||||
@@ -17,7 +17,7 @@ const CdkCalculateAllocations =
|
||||
require("../cdk/cdk-calculate-allocations").default;
|
||||
const { isArray } = require("lodash");
|
||||
const logger = require("../utils/logger");
|
||||
const PbsExportJob = require("../accounting/pbs/pbs-job-export");
|
||||
const {default: PbsExportJob, PbsSelectedCustomer} = require("../accounting/pbs/pbs-job-export");
|
||||
|
||||
io.use(function (socket, next) {
|
||||
try {
|
||||
@@ -99,9 +99,29 @@ io.on("connection", (socket) => {
|
||||
//END CDK
|
||||
|
||||
//PBS
|
||||
socket.on("pbs-calculate-allocations", async (jobid, callback) => {
|
||||
const allocations = await CdkCalculateAllocations(socket, jobid);
|
||||
createLogEvent(socket, "DEBUG", `Allocations calculated.`);
|
||||
createLogEvent(
|
||||
socket,
|
||||
"TRACE",
|
||||
`Allocations calculated. ${JSON.stringify(allocations, null, 2)}`
|
||||
);
|
||||
|
||||
callback(allocations);
|
||||
});
|
||||
socket.on("pbs-export-job", (jobid) => {
|
||||
PbsExportJob(socket, jobid);
|
||||
});
|
||||
socket.on("pbs-selected-customer", (selectedCustomerId) => {
|
||||
createLogEvent(
|
||||
socket,
|
||||
"DEBUG",
|
||||
`User selected customer ID ${selectedCustomerId}`
|
||||
);
|
||||
socket.selectedCustomerId = selectedCustomerId;
|
||||
PbsSelectedCustomer(socket, selectedCustomerId);
|
||||
});
|
||||
//End PBS
|
||||
|
||||
socket.on("disconnect", () => {
|
||||
|
||||
118
yarn.lock
118
yarn.lock
@@ -600,10 +600,10 @@ atob@2.1.2:
|
||||
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
|
||||
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
|
||||
|
||||
aws-sdk@^2.1013.0:
|
||||
version "2.1013.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1013.0.tgz#85babc473b0bc90cc1160eb48baf616ddb86e346"
|
||||
integrity sha512-TXxkp/meAdofpC15goFpNuur7fvh/mcMRfHJoP1jYzTtD0wcoB4FK16GLcny0uDYgkQgZuiO9QYv3Rq5bhGCqQ==
|
||||
aws-sdk@^2.1028.0:
|
||||
version "2.1028.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sdk/-/aws-sdk-2.1028.0.tgz#ce076076174afa9bd311406b8186ea90163e3331"
|
||||
integrity sha512-OmR0NcpU8zsDcUOZhM+eZ6CzlUFtuaEuRyjm6mxDO0KI7lJAp7/NzB6tcellRrgWxL+NO7b5TSxi+m28qu5ocQ==
|
||||
dependencies:
|
||||
buffer "4.9.2"
|
||||
events "1.1.1"
|
||||
@@ -625,12 +625,12 @@ aws4@^1.8.0:
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
|
||||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
|
||||
|
||||
axios-ntlm@^1.1.6:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/axios-ntlm/-/axios-ntlm-1.1.7.tgz#996f87be748595519c7de93f8c93eacdb65465dc"
|
||||
integrity sha512-wWsjWHreHpzfhTPL6cD/H7SfUWDr5u8RQjdxsLg7byP2ozgnDvN9q/w5ozngwcTKAy4fmv6QOfzNxsLkzIIUMQ==
|
||||
axios-ntlm@^1.2.0:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/axios-ntlm/-/axios-ntlm-1.2.1.tgz#8facad74cdf5a53eab34fa2fe91c8d4358950ed4"
|
||||
integrity sha512-M8qLdkOjVSrYmzOs7sxc/Ynu54yT2YHVOLFiTxicwPnll0H+sP3fkEQHGgEzpBcH4UA/ovRgTioR/vjelUG35A==
|
||||
dependencies:
|
||||
axios "^0.21.1"
|
||||
axios "^0.21.3"
|
||||
|
||||
axios@^0.21.1:
|
||||
version "0.21.1"
|
||||
@@ -639,13 +639,20 @@ axios@^0.21.1:
|
||||
dependencies:
|
||||
follow-redirects "^1.10.0"
|
||||
|
||||
axios@^0.21.4:
|
||||
axios@^0.21.3, axios@^0.21.4:
|
||||
version "0.21.4"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
|
||||
integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
|
||||
dependencies:
|
||||
follow-redirects "^1.14.0"
|
||||
|
||||
axios@^0.24.0:
|
||||
version "0.24.0"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.24.0.tgz#804e6fa1e4b9c5288501dd9dff56a7a0940d20d6"
|
||||
integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==
|
||||
dependencies:
|
||||
follow-redirects "^1.14.4"
|
||||
|
||||
balanced-match@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||
@@ -1146,7 +1153,7 @@ debug@2.6.9:
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@4, debug@^4.0.1, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@~4.3.1, debug@~4.3.2:
|
||||
debug@4, debug@^4.0.1, debug@^4.1.1, debug@^4.3.2, debug@~4.3.1, debug@~4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
|
||||
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
|
||||
@@ -1694,10 +1701,10 @@ finalhandler@~1.1.2:
|
||||
statuses "~1.5.0"
|
||||
unpipe "~1.0.0"
|
||||
|
||||
firebase-admin@^9.12.0:
|
||||
version "9.12.0"
|
||||
resolved "https://registry.yarnpkg.com/firebase-admin/-/firebase-admin-9.12.0.tgz#d7e889e97c9c31610efbcd131bb6d06a783af757"
|
||||
integrity sha512-AtA7OH5RbIFGoc0gZOQgaYC6cdjdhZv4w3XgWoupkPKO1HY+0GzixOuXDa75kFeoVyhIyo4PkLg/GAC1dC1P6w==
|
||||
firebase-admin@^10.0.0:
|
||||
version "10.0.0"
|
||||
resolved "https://registry.yarnpkg.com/firebase-admin/-/firebase-admin-10.0.0.tgz#0638cd50d2395fddc9d8af4e1699d0a10b1b22d8"
|
||||
integrity sha512-EOAk5ZaqXhBBvx9ZyXd28kw8glMTt3xl0g3BepGRCy0RSSUPGOzfAqjGhc65guSKgFOpT5mAUycYcJbqullKUQ==
|
||||
dependencies:
|
||||
"@firebase/database-compat" "^0.1.1"
|
||||
"@firebase/database-types" "^0.7.2"
|
||||
@@ -1743,6 +1750,11 @@ follow-redirects@^1.14.0:
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.4.tgz#838fdf48a8bbdd79e52ee51fb1c94e3ed98b9379"
|
||||
integrity sha512-zwGkiSXC1MUJG/qmeIFH2HBJx9u0V46QGUe3YR1fXG8bXQxq7fLj0RjLZQ5nubr9qNJUZrH+xUcwXEoXNpfS+g==
|
||||
|
||||
follow-redirects@^1.14.4:
|
||||
version "1.14.5"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.14.5.tgz#f09a5848981d3c772b5392309778523f8d85c381"
|
||||
integrity sha512-wtphSXy7d4/OR+MvIFbCVBDzZ5520qV8XfPklSN5QtxuMUJZ+b0Wnst1e1lCDocfzuCkHqj8k0FpZqO+UIaKNA==
|
||||
|
||||
forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
@@ -1973,10 +1985,10 @@ graphql-request@^3.6.1:
|
||||
extract-files "^9.0.0"
|
||||
form-data "^3.0.0"
|
||||
|
||||
graphql@^15.6.1:
|
||||
version "15.6.1"
|
||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.6.1.tgz#9125bdf057553525da251e19e96dab3d3855ddfc"
|
||||
integrity sha512-3i5lu0z6dRvJ48QP9kFxBkJ7h4Kso7PS8eahyTFz5Jm6CvQfLtNIE8LX9N6JLnXTuwR+sIYnXzaWp6anOg0QQw==
|
||||
graphql@^16.0.1:
|
||||
version "16.0.1"
|
||||
resolved "https://registry.yarnpkg.com/graphql/-/graphql-16.0.1.tgz#93a13cd4e0e38ca8d0832e79614c8578bfd34f10"
|
||||
integrity sha512-oPvCuu6dlLdiz8gZupJ47o1clgb72r1u8NDBcQYjcV6G/iEdmE11B1bBlkhXRvV0LisP/SXRFP7tT6AgaTjpzg==
|
||||
|
||||
graylog2@^0.2.1:
|
||||
version "0.2.1"
|
||||
@@ -2103,19 +2115,6 @@ http-signature@~1.2.0:
|
||||
jsprim "^1.2.2"
|
||||
sshpk "^1.7.0"
|
||||
|
||||
httpntlm@^1.5.2:
|
||||
version "1.7.7"
|
||||
resolved "https://registry.yarnpkg.com/httpntlm/-/httpntlm-1.7.7.tgz#51b914f18e5de2868d4bfe50aeecdb1db23218a1"
|
||||
integrity sha512-Pv2Rvrz8H0qv1Dne5mAdZ9JegG1uc6Vu5lwLflIY6s8RKHdZQbW39L4dYswSgqMDT0pkJILUTKjeyU0VPNRZjA==
|
||||
dependencies:
|
||||
httpreq ">=0.4.22"
|
||||
underscore "~1.12.1"
|
||||
|
||||
httpreq@>=0.4.22:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/httpreq/-/httpreq-0.5.2.tgz#be6777292fa1038d7771d7c01d9a5e1219de951c"
|
||||
integrity sha512-2Jm+x9WkExDOeFRrdBCBSpLPT5SokTcRHkunV3pjKmX/cx6av8zQ0WtHUMDrYb6O4hBFzNU6sxJEypvRUVYKnw==
|
||||
|
||||
https-proxy-agent@5, https-proxy-agent@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2"
|
||||
@@ -2822,10 +2821,10 @@ node-quickbooks@^2.0.39:
|
||||
util "0.10.3"
|
||||
uuid "^3.1.0"
|
||||
|
||||
nodemailer@^6.7.0:
|
||||
version "6.7.0"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.0.tgz#86614722c4e0c33d1b5b02aecb90d6d629932b0d"
|
||||
integrity sha512-AtiTVUFHLiiDnMQ43zi0YgkzHOEWUkhDgPlBXrsDzJiJvB29Alo4OKxHQ0ugF3gRqRQIneCLtZU3yiUo7pItZw==
|
||||
nodemailer@^6.7.1:
|
||||
version "6.7.1"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.1.tgz#09f72f8b375f7b259291757007bcd902c0174c6e"
|
||||
integrity sha512-E1C8G3rnXrGjznwGP1k+OrW5k4rl0XtqTEB19f7vtJAMYwfxZVSsAu2iY5xJkrZsbVYr6PwwAwRmFlakPoFC0A==
|
||||
|
||||
nth-check@~1.0.1:
|
||||
version "1.0.2"
|
||||
@@ -2975,10 +2974,10 @@ performance-now@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
|
||||
integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
|
||||
|
||||
phone@^3.1.8:
|
||||
version "3.1.8"
|
||||
resolved "https://registry.yarnpkg.com/phone/-/phone-3.1.8.tgz#6e348512539c9df81bf07fddb3ed3e2ec7e0c66e"
|
||||
integrity sha512-eyneQKbBwhy6PLYgkioO4CcocMUrFHh4WEfYl1A3PpiQK9tiP0ABKU4yhs7F1URKDbp+oeI8rbJU0+8uMgWfBQ==
|
||||
phone@^3.1.9:
|
||||
version "3.1.9"
|
||||
resolved "https://registry.yarnpkg.com/phone/-/phone-3.1.9.tgz#692d70061c0d7391ebcd67f30bee4364b52264e5"
|
||||
integrity sha512-u5jPSlbB4lq9W2ptznEb4eBBKnr3y8xAL4Dsn4uFzUl2gWZE6QiQgxMUMelHq3VUUzFq1QM579SkTxJ+k++igg==
|
||||
|
||||
pick-util@^1.1.3:
|
||||
version "1.1.3"
|
||||
@@ -3509,18 +3508,17 @@ snakeize@^0.1.0:
|
||||
resolved "https://registry.yarnpkg.com/snakeize/-/snakeize-0.1.0.tgz#10c088d8b58eb076b3229bb5a04e232ce126422d"
|
||||
integrity sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=
|
||||
|
||||
soap@^0.42.0:
|
||||
version "0.42.0"
|
||||
resolved "https://registry.yarnpkg.com/soap/-/soap-0.42.0.tgz#33f6ce109f9e6fdc9b61c3665c592c6d0e18e0ab"
|
||||
integrity sha512-7q4tYAkK0+KIeYRK0n/JBFP7XdZChqfGUfcDQRXt5uvKkRtj0gxTEc7WbfLnOqjyif86v5/MosE/4K+8ZYaB1Q==
|
||||
soap@^0.43.0:
|
||||
version "0.43.0"
|
||||
resolved "https://registry.yarnpkg.com/soap/-/soap-0.43.0.tgz#3172b7de12011dfc6981db99be9bc1df2a05a94a"
|
||||
integrity sha512-Dgp6TD9f3NXvKhBy95XXphiSlNIU2RSc9PP1NEgBOE1laUWP+bdF+8uT1lf1tFadFEAYurFg6/s2tNil6rlltw==
|
||||
dependencies:
|
||||
axios "^0.21.1"
|
||||
axios-ntlm "^1.1.6"
|
||||
axios-ntlm "^1.2.0"
|
||||
content-type-parser "^1.0.2"
|
||||
debug "^4.3.1"
|
||||
debug "^4.3.2"
|
||||
formidable "^1.2.2"
|
||||
get-stream "^6.0.1"
|
||||
httpntlm "^1.5.2"
|
||||
lodash "^4.17.21"
|
||||
sax ">=0.6"
|
||||
strip-bom "^3.0.0"
|
||||
@@ -3541,10 +3539,10 @@ socket.io-parser@~4.0.4:
|
||||
component-emitter "~1.3.0"
|
||||
debug "~4.3.1"
|
||||
|
||||
socket.io@^4.3.1:
|
||||
version "4.3.1"
|
||||
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.3.1.tgz#c0aa14f3f916a8ab713e83a5bd20c16600245763"
|
||||
integrity sha512-HC5w5Olv2XZ0XJ4gOLGzzHEuOCfj3G0SmoW3jLHYYh34EVsIr3EkW9h6kgfW+K3TFEcmYy8JcPWe//KUkBp5jA==
|
||||
socket.io@^4.3.2:
|
||||
version "4.3.2"
|
||||
resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.3.2.tgz#85ae0cf5cf18acbce648ac9f48aba66df8cea6bf"
|
||||
integrity sha512-6S5tV4jcY6dbZ/lLzD6EkvNWI3s81JO6ABP/EpvOlK1NPOcIj3AS4khi6xXw6JlZCASq82HQV4SapfmVMMl2dg==
|
||||
dependencies:
|
||||
accepts "~1.3.4"
|
||||
base64id "~2.0.0"
|
||||
@@ -3751,10 +3749,10 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006"
|
||||
integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||
|
||||
stripe@^8.184.0:
|
||||
version "8.184.0"
|
||||
resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.184.0.tgz#ea68470ca6045bb47516c4fea3b775fd6ce15a36"
|
||||
integrity sha512-ZUdvyX+sizTxXLEbUjgTShrulSWSkMIt7hIKdAkhnajYrHdzVtdmhBJl8sQbR9chMVox3Ig5ohilyeIrvcCE2g==
|
||||
stripe@^8.188.0:
|
||||
version "8.188.0"
|
||||
resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.188.0.tgz#1d892c2f9000847c627db06a374529e7fbd2b83e"
|
||||
integrity sha512-AW5IOKq4y+ENfHddJPrLL/GSvGj1MnBvUe6QMI1z27x/4pMNrU7v0ZqzRSJCihWqP0tUuCmQibSYSbsV4XJ3zA==
|
||||
dependencies:
|
||||
"@types/node" ">=8.1.0"
|
||||
qs "^6.6.0"
|
||||
@@ -3918,10 +3916,10 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0:
|
||||
resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
|
||||
integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
|
||||
|
||||
twilio@^3.70.0:
|
||||
version "3.70.0"
|
||||
resolved "https://registry.yarnpkg.com/twilio/-/twilio-3.70.0.tgz#9e6a96f0c46e8256d74bce918baeb7e678c4c1aa"
|
||||
integrity sha512-GhohvQfP3aHEwiCb6MWqDJ/KeSyFmFwCQtoSuHEwevE7GCxCq6spK36HlCNg3UyTTZNvfdIhN9Sf1wDWeDIbOg==
|
||||
twilio@^3.71.1:
|
||||
version "3.71.1"
|
||||
resolved "https://registry.yarnpkg.com/twilio/-/twilio-3.71.1.tgz#15bbb4b51c75d91cc07a8149378c4af330e543cc"
|
||||
integrity sha512-P/KFvm33UW15EnpHJKgdTxUa1u6MlR/u+sCVnL4ie2TDRv6t7kX+ieIGQMpH7bP/z7FXkTjEt0lz4M+XJ/XWOg==
|
||||
dependencies:
|
||||
axios "^0.21.4"
|
||||
dayjs "^1.8.29"
|
||||
@@ -3981,7 +3979,7 @@ uid-safe@2.1.5:
|
||||
dependencies:
|
||||
random-bytes "~1.0.0"
|
||||
|
||||
underscore@1.12.1, underscore@~1.12.1:
|
||||
underscore@1.12.1:
|
||||
version "1.12.1"
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e"
|
||||
integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==
|
||||
|
||||
Reference in New Issue
Block a user