Compare commits
45 Commits
release/20
...
feature/no
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5a2be9392 | ||
|
|
df1e15be60 | ||
|
|
274b572915 | ||
|
|
fa4aa5ca8f | ||
|
|
2b537b65dd | ||
|
|
75b2cb18ca | ||
|
|
5167668958 | ||
|
|
1eacf43669 | ||
|
|
77ed64969e | ||
|
|
44ff032acc | ||
|
|
542637edb2 | ||
|
|
f7971ed60c | ||
|
|
ca71b0479a | ||
|
|
515de38fe6 | ||
|
|
113c62b36f | ||
|
|
c0ea5a9818 | ||
|
|
6b13dffe68 | ||
|
|
51d49be16e | ||
|
|
04c3abd65f | ||
|
|
29dab7312b | ||
|
|
01eb68fda1 | ||
|
|
a4c4329253 | ||
|
|
b738fc9007 | ||
|
|
5484358b32 | ||
|
|
b48d7512a2 | ||
|
|
ae3226efb8 | ||
|
|
da9ddfc419 | ||
|
|
901902c1d1 | ||
|
|
79bfb12063 | ||
|
|
c1bf112aac | ||
|
|
ecfb3e91cd | ||
|
|
e25606070b | ||
|
|
28f0d9a4b2 | ||
|
|
c125cd8ca2 | ||
|
|
123f94a0f5 | ||
|
|
d601617819 | ||
|
|
80bd2dc6d8 | ||
|
|
45bd2d3281 | ||
|
|
b4304c743e | ||
|
|
faf9fbb9d8 | ||
|
|
6d1581a4e1 | ||
|
|
28f6c72de1 | ||
|
|
54577ac680 | ||
|
|
c912681793 | ||
|
|
89b515fff4 |
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"env": {
|
|
||||||
"es6": true,
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"extends": "eslint:recommended",
|
|
||||||
"globals": {
|
|
||||||
"Atomics": "readonly",
|
|
||||||
"SharedArrayBuffer": "readonly"
|
|
||||||
},
|
|
||||||
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2018,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"no-console": "off"
|
|
||||||
},
|
|
||||||
"settings": {},
|
|
||||||
"plugins": ["cypress"]
|
|
||||||
}
|
|
||||||
@@ -2354,6 +2354,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>is_credit_memo_short</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>local_tax_rate</name>
|
<name>local_tax_rate</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -3633,6 +3654,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>bill_allow_post_to_closed</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>bill_federal_tax_rate</name>
|
<name>bill_federal_tax_rate</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -4367,6 +4409,27 @@
|
|||||||
</concept_node>
|
</concept_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>last_name_first</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>lastnumberworkingdays</name>
|
<name>lastnumberworkingdays</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -4711,6 +4774,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>private</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>state</name>
|
<name>state</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -4818,6 +4902,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>md_parts_order_comment</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>md_payment_types</name>
|
<name>md_payment_types</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -8822,6 +8927,48 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>qbo_departmentid</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>qbo_usa</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>rbac</name>
|
<name>rbac</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -20229,6 +20376,27 @@
|
|||||||
</concept_node>
|
</concept_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>auto_add_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>
|
<concept_node>
|
||||||
<name>ca_bc_pvrt</name>
|
<name>ca_bc_pvrt</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -23131,6 +23299,27 @@
|
|||||||
</concept_node>
|
</concept_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>rate_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>
|
<concept_node>
|
||||||
<name>rate_la1</name>
|
<name>rate_la1</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -26589,6 +26778,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>parts_received</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>parts_tax_rates</name>
|
<name>parts_tax_rates</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -29881,6 +30091,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>cancelallappointments</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>closejob</name>
|
<name>closejob</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -31189,6 +31420,37 @@
|
|||||||
</folder_node>
|
</folder_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<folder_node>
|
||||||
|
<name>owner</name>
|
||||||
|
<children>
|
||||||
|
<folder_node>
|
||||||
|
<name>labels</name>
|
||||||
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>noownerinfo</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
|
</children>
|
||||||
|
</folder_node>
|
||||||
|
</children>
|
||||||
|
</folder_node>
|
||||||
<folder_node>
|
<folder_node>
|
||||||
<name>owners</name>
|
<name>owners</name>
|
||||||
<children>
|
<children>
|
||||||
@@ -32557,6 +32819,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>notyetordered</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>oec</name>
|
<name>oec</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -34925,6 +35208,27 @@
|
|||||||
</concept_node>
|
</concept_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>lag_time_ro</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>mechanical_authorization</name>
|
<name>mechanical_authorization</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -36487,6 +36791,58 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<folder_node>
|
||||||
|
<name>bodyshop</name>
|
||||||
|
<children>
|
||||||
|
<folder_node>
|
||||||
|
<name>labels</name>
|
||||||
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>qbo_departmentid</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>qbo_usa</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
|
</children>
|
||||||
|
</folder_node>
|
||||||
|
</children>
|
||||||
|
</folder_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>cardsettings</name>
|
<name>cardsettings</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -36844,6 +37200,27 @@
|
|||||||
</translation>
|
</translation>
|
||||||
</translations>
|
</translations>
|
||||||
</concept_node>
|
</concept_node>
|
||||||
|
<concept_node>
|
||||||
|
<name>stickyheader</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
<concept_node>
|
<concept_node>
|
||||||
<name>sublets</name>
|
<name>sublets</name>
|
||||||
<definition_loaded>false</definition_loaded>
|
<definition_loaded>false</definition_loaded>
|
||||||
@@ -42938,6 +43315,63 @@
|
|||||||
</folder_node>
|
</folder_node>
|
||||||
</children>
|
</children>
|
||||||
</folder_node>
|
</folder_node>
|
||||||
|
<folder_node>
|
||||||
|
<name>users</name>
|
||||||
|
<children>
|
||||||
|
<folder_node>
|
||||||
|
<name>errors</name>
|
||||||
|
<children>
|
||||||
|
<folder_node>
|
||||||
|
<name>signinerror</name>
|
||||||
|
<children>
|
||||||
|
<concept_node>
|
||||||
|
<name>auth/user-not-found</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>auth/wrong-password</name>
|
||||||
|
<definition_loaded>false</definition_loaded>
|
||||||
|
<description></description>
|
||||||
|
<comment></comment>
|
||||||
|
<default_text></default_text>
|
||||||
|
<translations>
|
||||||
|
<translation>
|
||||||
|
<language>en-US</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>es-MX</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
<translation>
|
||||||
|
<language>fr-CA</language>
|
||||||
|
<approved>false</approved>
|
||||||
|
</translation>
|
||||||
|
</translations>
|
||||||
|
</concept_node>
|
||||||
|
</children>
|
||||||
|
</folder_node>
|
||||||
|
</children>
|
||||||
|
</folder_node>
|
||||||
|
</children>
|
||||||
|
</folder_node>
|
||||||
<folder_node>
|
<folder_node>
|
||||||
<name>vehicles</name>
|
<name>vehicles</name>
|
||||||
<children>
|
<children>
|
||||||
|
|||||||
@@ -3,83 +3,89 @@
|
|||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"proxy": "http://localhost:4000",
|
"proxy": "http://localhost:4000",
|
||||||
|
"browser": {
|
||||||
|
"fs": false,
|
||||||
|
"path": false,
|
||||||
|
"os": false
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.5.6",
|
"@apollo/client": "^3.5.10",
|
||||||
"@asseinfo/react-kanban": "^2.2.0",
|
"@asseinfo/react-kanban": "^2.2.0",
|
||||||
"@craco/craco": "^6.4.3",
|
"@craco/craco": "^6.4.3",
|
||||||
"@fingerprintjs/fingerprintjs": "^3.3.1",
|
"@fingerprintjs/fingerprintjs": "^3.3.3",
|
||||||
"@sentry/react": "^6.16.1",
|
"@jsreport/browser-client": "^3.1.0",
|
||||||
"@sentry/tracing": "^6.16.1",
|
"@sentry/react": "^6.19.6",
|
||||||
"@splitsoftware/splitio-react": "^1.3.0",
|
"@sentry/tracing": "^6.19.6",
|
||||||
"@stripe/react-stripe-js": "^1.7.0",
|
"@splitsoftware/splitio-react": "^1.4.0",
|
||||||
"@stripe/stripe-js": "^1.22.0",
|
"@stripe/react-stripe-js": "^1.7.1",
|
||||||
"@tanem/react-nprogress": "^3.0.82",
|
"@stripe/stripe-js": "^1.27.0",
|
||||||
"antd": "^4.17.4",
|
"@tanem/react-nprogress": "^5.0.0",
|
||||||
|
"antd": "^4.19.5",
|
||||||
"apollo-link-logger": "^2.0.0",
|
"apollo-link-logger": "^2.0.0",
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.26.1",
|
||||||
"craco-less": "^1.20.0",
|
"craco-less": "^2.0.0",
|
||||||
"dinero.js": "^1.9.1",
|
"dinero.js": "^1.9.1",
|
||||||
"dotenv": "^10.0.0",
|
"dotenv": "^16.0.0",
|
||||||
"enquire-js": "^0.2.1",
|
"enquire-js": "^0.2.1",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"exifr": "^7.1.3",
|
"exifr": "^7.1.3",
|
||||||
"firebase": "^9.6.1",
|
"firebase": "^9.6.10",
|
||||||
"graphql": "^16.2.0",
|
"graphql": "^16.3.0",
|
||||||
"i18next": "^21.6.3",
|
"i18next": "^21.6.16",
|
||||||
"i18next-browser-languagedetector": "^6.1.2",
|
"i18next-browser-languagedetector": "^6.1.4",
|
||||||
"jsoneditor": "^9.5.8",
|
"jsoneditor": "^9.7.4",
|
||||||
"jsreport-browser-client-dist": "^1.3.0",
|
"libphonenumber-js": "^1.9.51",
|
||||||
"libphonenumber-js": "^1.9.44",
|
"logrocket": "^2.2.1",
|
||||||
"logrocket": "^2.1.2",
|
"markerjs2": "^2.21.0",
|
||||||
"markerjs2": "^2.17.2",
|
|
||||||
"moment-business-days": "^1.2.0",
|
"moment-business-days": "^1.2.0",
|
||||||
"moment-timezone": "^0.5.34",
|
"moment-timezone": "^0.5.34",
|
||||||
"phone": "^3.1.10",
|
"phone": "^3.1.15",
|
||||||
"preval.macro": "^5.0.0",
|
"preval.macro": "^5.0.0",
|
||||||
"prop-types": "^15.7.2",
|
"prop-types": "^15.8.1",
|
||||||
"query-string": "^7.0.1",
|
"query-string": "^7.1.1",
|
||||||
"rc-queue-anim": "^2.0.0",
|
"rc-queue-anim": "^2.0.0",
|
||||||
"rc-scroll-anim": "^2.7.6",
|
"rc-scroll-anim": "^2.7.6",
|
||||||
"react": "^17.0.2",
|
"react": "^18.0.0",
|
||||||
"react-big-calendar": "^0.38.2",
|
"react-big-calendar": "^0.40.0",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-cookie": "^4.1.1",
|
"react-cookie": "^4.1.1",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^18.0.0",
|
||||||
"react-drag-listview": "^0.1.8",
|
"react-drag-listview": "^0.1.9",
|
||||||
"react-grid-gallery": "^0.5.5",
|
"react-grid-gallery": "^0.5.5",
|
||||||
"react-grid-layout": "^1.3.0",
|
"react-grid-layout": "^1.3.4",
|
||||||
"react-i18next": "^11.15.1",
|
"react-i18next": "^11.16.6",
|
||||||
"react-icons": "^4.3.1",
|
"react-icons": "^4.3.1",
|
||||||
"react-number-format": "^4.9.0",
|
"react-number-format": "^4.9.1",
|
||||||
"react-redux": "^7.2.6",
|
"react-redux": "^7.2.8",
|
||||||
"react-resizable": "^3.0.4",
|
"react-resizable": "^3.0.4",
|
||||||
"react-router-dom": "^5.3.0",
|
"react-router-dom": "^5.3.0",
|
||||||
"react-scripts": "^4.0.3",
|
"react-scripts": "^4.0.3",
|
||||||
|
"react-sticky": "^6.0.3",
|
||||||
"react-sublime-video": "^0.2.5",
|
"react-sublime-video": "^0.2.5",
|
||||||
"react-virtualized": "^9.22.3",
|
"react-virtualized": "^9.22.3",
|
||||||
"recharts": "^2.1.8",
|
"recharts": "^2.1.9",
|
||||||
"redux": "^4.1.2",
|
"redux": "^4.1.2",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-saga": "^1.1.3",
|
"redux-saga": "^1.1.3",
|
||||||
"redux-state-sync": "^3.1.2",
|
"redux-state-sync": "^3.1.2",
|
||||||
"reselect": "^4.1.5",
|
"reselect": "^4.1.5",
|
||||||
"sass": "^1.45.0",
|
"sass": "^1.50.0",
|
||||||
"socket.io-client": "^4.4.0",
|
"socket.io-client": "^4.4.1",
|
||||||
"styled-components": "^5.3.3",
|
"styled-components": "^5.3.5",
|
||||||
"subscriptions-transport-ws": "^0.11.0",
|
"subscriptions-transport-ws": "^0.11.0",
|
||||||
"web-vitals": "^2.1.2",
|
"web-vitals": "^2.1.4",
|
||||||
"workbox-background-sync": "^6.4.2",
|
"workbox-background-sync": "^6.5.3",
|
||||||
"workbox-broadcast-update": "^6.4.2",
|
"workbox-broadcast-update": "^6.5.3",
|
||||||
"workbox-cacheable-response": "^6.4.2",
|
"workbox-cacheable-response": "^6.5.3",
|
||||||
"workbox-core": "^6.4.2",
|
"workbox-core": "^6.5.3",
|
||||||
"workbox-expiration": "^6.4.2",
|
"workbox-expiration": "^6.5.3",
|
||||||
"workbox-google-analytics": "^6.4.2",
|
"workbox-google-analytics": "^6.5.3",
|
||||||
"workbox-navigation-preload": "^6.4.2",
|
"workbox-navigation-preload": "^6.5.3",
|
||||||
"workbox-precaching": "^6.4.2",
|
"workbox-precaching": "^6.5.3",
|
||||||
"workbox-range-requests": "^6.4.2",
|
"workbox-range-requests": "^6.5.3",
|
||||||
"workbox-routing": "^6.4.2",
|
"workbox-routing": "^6.5.3",
|
||||||
"workbox-strategies": "^6.4.2",
|
"workbox-strategies": "^6.5.3",
|
||||||
"workbox-streams": "^6.4.2",
|
"workbox-streams": "^6.5.3",
|
||||||
"yauzl": "^2.10.0"
|
"yauzl": "^2.10.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -116,11 +122,11 @@
|
|||||||
"react-error-overlay": "6.0.9"
|
"react-error-overlay": "6.0.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sentry/webpack-plugin": "^1.18.3",
|
"@sentry/webpack-plugin": "^1.18.8",
|
||||||
"@testing-library/cypress": "^8.0.2",
|
"@testing-library/cypress": "^8.0.2",
|
||||||
"cypress": "^9.1.1",
|
"cypress": "^9.5.4",
|
||||||
"eslint-plugin-cypress": "^2.12.1",
|
"eslint-plugin-cypress": "^2.12.1",
|
||||||
"react-error-overlay": "6.0.9",
|
"react-error-overlay": "6.0.11",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"source-map-explorer": "^2.5.2"
|
"source-map-explorer": "^2.5.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -76,14 +77,12 @@ export function AccountingPayablesTableComponent({
|
|||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.job.owner ? (
|
return record.job.owner ? (
|
||||||
<Link to={"/manage/owners/" + record.job.owner.id}>
|
<Link to={"/manage/owners/" + record.job.owner.id}>
|
||||||
{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record.job} />
|
||||||
record.job.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span>{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
<span>
|
||||||
record.job.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={record.job} />
|
||||||
}`}</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -162,10 +161,19 @@ export function AccountingPayablesTableComponent({
|
|||||||
const dataSource = state.search
|
const dataSource = state.search
|
||||||
? payments.filter(
|
? payments.filter(
|
||||||
(v) =>
|
(v) =>
|
||||||
(v.vendor.name || "")
|
(v.paymentnum || "")
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(state.search.toLowerCase()) ||
|
.includes(state.search.toLowerCase()) ||
|
||||||
(v.invoice_number || "")
|
((v.job && v.job.ro_number) || "")
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(state.search.toLowerCase()) ||
|
||||||
|
((v.job && v.job.ownr_fn) || "")
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(state.search.toLowerCase()) ||
|
||||||
|
((v.job && v.job.ownr_ln) || "")
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(state.search.toLowerCase()) ||
|
||||||
|
((v.job && v.job.ownr_co_nm) || "")
|
||||||
.toLowerCase()
|
.toLowerCase()
|
||||||
.includes(state.search.toLowerCase())
|
.includes(state.search.toLowerCase())
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||||
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
|
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
|
||||||
import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
|
import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
|
||||||
|
|
||||||
@@ -12,6 +12,9 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
||||||
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
@@ -62,6 +65,18 @@ export function AccountingReceivablesTableComponent({
|
|||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: t("jobs.fields.date_invoiced"),
|
||||||
|
dataIndex: "date_invoiced",
|
||||||
|
key: "date_invoiced",
|
||||||
|
sorter: (a, b) => dateSort(a.date_invoiced, b.date_invoiced),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "date_invoiced" &&
|
||||||
|
state.sortedInfo.order,
|
||||||
|
render: (text, record) => (
|
||||||
|
<DateFormatter>{record.date_invoiced}</DateFormatter>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.owner"),
|
title: t("jobs.fields.owner"),
|
||||||
dataIndex: "owner",
|
dataIndex: "owner",
|
||||||
@@ -72,14 +87,12 @@ export function AccountingReceivablesTableComponent({
|
|||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.owner ? (
|
return record.owner ? (
|
||||||
<Link to={"/manage/owners/" + record.owner.id}>
|
<Link to={"/manage/owners/" + record.owner.id}>
|
||||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<span>
|
||||||
record.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
}`}</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useHistory } from "react-router-dom";
|
import { useLocation, useHistory } from "react-router-dom";
|
||||||
import {
|
import {
|
||||||
|
DELETE_BILL_LINE,
|
||||||
INSERT_NEW_BILL_LINES,
|
INSERT_NEW_BILL_LINES,
|
||||||
UPDATE_BILL_LINE,
|
UPDATE_BILL_LINE,
|
||||||
} from "../../graphql/bill-lines.queries";
|
} from "../../graphql/bill-lines.queries";
|
||||||
@@ -58,6 +59,7 @@ export function BillDetailEditcontainer({
|
|||||||
const [update_bill] = useMutation(UPDATE_BILL);
|
const [update_bill] = useMutation(UPDATE_BILL);
|
||||||
const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES);
|
const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES);
|
||||||
const [updateBillLine] = useMutation(UPDATE_BILL_LINE);
|
const [updateBillLine] = useMutation(UPDATE_BILL_LINE);
|
||||||
|
const [deleteBillLine] = useMutation(DELETE_BILL_LINE);
|
||||||
|
|
||||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||||
.filter((screen) => !!screen[1])
|
.filter((screen) => !!screen[1])
|
||||||
@@ -107,6 +109,20 @@ export function BillDetailEditcontainer({
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//Find bill lines that were deleted.
|
||||||
|
const deletedJobLines = [];
|
||||||
|
|
||||||
|
data.bills_by_pk.billlines.forEach((a) => {
|
||||||
|
const matchingRecord = billlines.find((b) => b.id === a.id);
|
||||||
|
if (!matchingRecord) {
|
||||||
|
deletedJobLines.push(a);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
deletedJobLines.forEach((d) => {
|
||||||
|
updates.push(deleteBillLine({ variables: { id: d.id } }));
|
||||||
|
});
|
||||||
|
|
||||||
billlines.forEach((billline) => {
|
billlines.forEach((billline) => {
|
||||||
const { deductedfromlbr, jobline, ...il } = billline;
|
const { deductedfromlbr, jobline, ...il } = billline;
|
||||||
delete il.__typename;
|
delete il.__typename;
|
||||||
@@ -142,6 +158,7 @@ export function BillDetailEditcontainer({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(updates);
|
await Promise.all(updates);
|
||||||
|
|
||||||
insertAuditTrail({
|
insertAuditTrail({
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export function BillFormComponent({
|
|||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bills.fields.vendor")}
|
label={t("bills.fields.vendor")}
|
||||||
name="vendorid"
|
name="vendorid"
|
||||||
style={{ display: billEdit ? "none" : null }}
|
// style={{ display: billEdit ? "none" : null }}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -229,6 +229,7 @@ export function BillFormComponent({
|
|||||||
({ getFieldValue }) => ({
|
({ getFieldValue }) => ({
|
||||||
validator(rule, value) {
|
validator(rule, value) {
|
||||||
if (
|
if (
|
||||||
|
!bodyshop.bill_allow_post_to_closed &&
|
||||||
(job.status === bodyshop.md_ro_statuses.default_invoiced ||
|
(job.status === bodyshop.md_ro_statuses.default_invoiced ||
|
||||||
job.status === bodyshop.md_ro_statuses.default_exported ||
|
job.status === bodyshop.md_ro_statuses.default_exported ||
|
||||||
job.status === bodyshop.md_ro_statuses.default_void) &&
|
job.status === bodyshop.md_ro_statuses.default_void) &&
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { selectSelectedConversation } from "../../redux/messaging/messaging.sele
|
|||||||
import { TimeAgoFormatter } from "../../utils/DateFormatter";
|
import { TimeAgoFormatter } from "../../utils/DateFormatter";
|
||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
import "./chat-conversation-list.styles.scss";
|
import "./chat-conversation-list.styles.scss";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
selectedConversation: selectSelectedConversation,
|
selectedConversation: selectSelectedConversation,
|
||||||
@@ -40,9 +41,9 @@ export function ChatConversationListComponent({
|
|||||||
{item.job_conversations.length > 0 ? (
|
{item.job_conversations.length > 0 ? (
|
||||||
<div className="chat-name">
|
<div className="chat-name">
|
||||||
{item.job_conversations.map((j, idx) => (
|
{item.job_conversations.map((j, idx) => (
|
||||||
<div key={idx}>{`${j.job.ownr_fn || ""} ${
|
<div key={idx}>
|
||||||
j.job.ownr_ln || ""
|
<OwnerNameDisplay ownerObject={j.job} />
|
||||||
} ${j.job.ownr_co_nm || ""} `}</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import React from "react";
|
|||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
import { REMOVE_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
import { REMOVE_CONVERSATION_TAG } from "../../graphql/job-conversations.queries";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function ChatConversationTitleTags({ jobConversations }) {
|
export default function ChatConversationTitleTags({ jobConversations }) {
|
||||||
const [removeJobConversation] = useMutation(REMOVE_CONVERSATION_TAG);
|
const [removeJobConversation] = useMutation(REMOVE_CONVERSATION_TAG);
|
||||||
@@ -45,9 +46,8 @@ export default function ChatConversationTitleTags({ jobConversations }) {
|
|||||||
onClose={() => handleRemoveTag(item.job.id)}
|
onClose={() => handleRemoveTag(item.job.id)}
|
||||||
>
|
>
|
||||||
<Link to={`/manage/jobs/${item.job.id}`}>
|
<Link to={`/manage/jobs/${item.job.id}`}>
|
||||||
{`${item.job.ro_number || "?"} | ${item.job.ownr_fn || ""} ${
|
{`${item.job.ro_number || "?"} | `}
|
||||||
item.job.ownr_ln || ""
|
<OwnerNameDisplay ownerObject={item.job} />
|
||||||
} ${item.job.ownr_co_nm || ""}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
</Tag>
|
</Tag>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { CloseCircleOutlined, LoadingOutlined } from "@ant-design/icons";
|
import { CloseCircleOutlined, LoadingOutlined } from "@ant-design/icons";
|
||||||
import { Select, Empty, Space } from "antd";
|
import { Empty, Select, Space } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function ChatTagRoComponent({
|
export default function ChatTagRoComponent({
|
||||||
roOptions,
|
roOptions,
|
||||||
@@ -27,9 +28,7 @@ export default function ChatTagRoComponent({
|
|||||||
>
|
>
|
||||||
{roOptions.map((item, idx) => (
|
{roOptions.map((item, idx) => (
|
||||||
<Select.Option key={item.id || idx}>
|
<Select.Option key={item.id || idx}>
|
||||||
{` ${item.ro_number || ""} | ${item.ownr_fn || ""} ${
|
{` ${item.ro_number || ""} | ${OwnerNameDisplayFunction(item)}`}
|
||||||
item.ownr_ln || ""
|
|
||||||
} ${item.ownr_co_nm || ""}`}
|
|
||||||
</Select.Option>
|
</Select.Option>
|
||||||
))}
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import React from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import DataLabel from "../data-label/data-label.component";
|
import DataLabel from "../data-label/data-label.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
export default function ContractJobBlock({ job }) {
|
export default function ContractJobBlock({ job }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
@@ -23,9 +23,7 @@ export default function ContractJobBlock({ job }) {
|
|||||||
} ${(job && job.v_model_desc) || ""}`}
|
} ${(job && job.v_model_desc) || ""}`}
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
<DataLabel label={t("jobs.fields.owner")}>
|
<DataLabel label={t("jobs.fields.owner")}>
|
||||||
{`${(job && job.ownr_fn) || ""} ${(job && job.ownr_ln) || ""} ${
|
<OwnerNameDisplay ownerObject={job} />
|
||||||
(job && job.ownr_co_nm) || ""
|
|
||||||
}`}
|
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React, { useMemo, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function ContractsJobsComponent({
|
export default function ContractsJobsComponent({
|
||||||
loading,
|
loading,
|
||||||
@@ -43,17 +44,7 @@ export default function ContractsJobsComponent({
|
|||||||
width: "25%",
|
width: "25%",
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
render: (text, record) => {
|
render: (text, record) => <OwnerNameDisplay ownerObject={record} />,
|
||||||
return record.owner ? (
|
|
||||||
<span>
|
|
||||||
{record.ownr_fn} {record.ownr_ln} {record.ownr_co_nm || ""}
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<span>{`${record.ownr_fn} ${record.ownr_ln} ${
|
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("jobs.fields.status"),
|
title: t("jobs.fields.status"),
|
||||||
|
|||||||
@@ -12,17 +12,22 @@ import { setModalContext } from "../../redux/modals/modals.actions";
|
|||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||||
setContractFinderContext: (context) =>
|
setContractFinderContext: (context) =>
|
||||||
dispatch(setModalContext({ context: context, modal: "contractFinder" })),
|
dispatch(setModalContext({ context: context, modal: "contractFinder" })),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ContractsList);
|
export default connect(mapStateToProps, mapDispatchToProps)(ContractsList);
|
||||||
|
|
||||||
export function ContractsList({
|
export function ContractsList({
|
||||||
|
bodyshop,
|
||||||
loading,
|
loading,
|
||||||
contracts,
|
contracts,
|
||||||
refetch,
|
refetch,
|
||||||
@@ -72,7 +77,9 @@ export function ContractsList({
|
|||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "driver_ln" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "driver_ln" && state.sortedInfo.order,
|
||||||
render: (text, record) =>
|
render: (text, record) =>
|
||||||
`${record.driver_fn || ""} ${record.driver_ln || ""}`,
|
bodyshop.last_name_first
|
||||||
|
? `${record.driver_ln || ""}, ${record.driver_fn || ""}`
|
||||||
|
: `${record.driver_fn || ""} ${record.driver_ln || ""}`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("contracts.labels.vehicle"),
|
title: t("contracts.labels.vehicle"),
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import { Table, Button, Input, Card, Space } from "antd";
|
import { SyncOutlined } from "@ant-design/icons";
|
||||||
|
import { Button, Card, Input, Space, Table } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import { SyncOutlined } from "@ant-design/icons";
|
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
@@ -97,9 +99,9 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
|||||||
render: (text, record) =>
|
render: (text, record) =>
|
||||||
record.cccontracts.length === 1 ? (
|
record.cccontracts.length === 1 ? (
|
||||||
<Link to={`/manage/jobs/${record.cccontracts[0].job.id}`}>
|
<Link to={`/manage/jobs/${record.cccontracts[0].job.id}`}>
|
||||||
{`${record.cccontracts[0].job.ro_number} - ${
|
{`${
|
||||||
record.cccontracts[0].job.ownr_fn || ""
|
record.cccontracts[0].job.ro_number
|
||||||
} ${record.cccontracts[0].job.ownr_ln || ""} ${record.cccontracts[0].job.ownr_co_nm || ""}`}
|
} - ${OwnerNameDisplayFunction(record.cccontracts[0].job)}`}
|
||||||
</Link>
|
</Link>
|
||||||
) : null,
|
) : null,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function CsiResponseListPaginated({
|
export default function CsiResponseListPaginated({
|
||||||
refetch,
|
refetch,
|
||||||
@@ -48,14 +49,12 @@ export default function CsiResponseListPaginated({
|
|||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.job.owner ? (
|
return record.job.owner ? (
|
||||||
<Link to={"/manage/owners/" + record.job.owner.id}>
|
<Link to={"/manage/owners/" + record.job.owner.id}>
|
||||||
{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record.job} />
|
||||||
record.job.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span>{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
<span>
|
||||||
record.job.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={record.job} />
|
||||||
}`}</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,17 +1,21 @@
|
|||||||
import { useLazyQuery } from "@apollo/client";
|
import { useLazyQuery } from "@apollo/client";
|
||||||
|
import { LoadingOutlined } from "@ant-design/icons";
|
||||||
import { AutoComplete, Divider, Space } from "antd";
|
import { AutoComplete, Divider, Space } from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, useHistory } from "react-router-dom";
|
||||||
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
||||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
import OwnerNameDisplay, {
|
||||||
|
OwnerNameDisplayFunction,
|
||||||
|
} from "../owner-name-display/owner-name-display.component";
|
||||||
export default function GlobalSearch() {
|
export default function GlobalSearch() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const history = useHistory();
|
||||||
const [callSearch, { error, data }] = useLazyQuery(GLOBAL_SEARCH_QUERY);
|
const [callSearch, { loading, error, data }] =
|
||||||
|
useLazyQuery(GLOBAL_SEARCH_QUERY);
|
||||||
|
|
||||||
const executeSearch = (v) => {
|
const executeSearch = (v) => {
|
||||||
if (v && v.variables.search && v.variables.search !== "") callSearch(v);
|
if (v && v.variables.search && v.variables.search !== "") callSearch(v);
|
||||||
@@ -39,9 +43,9 @@ export default function GlobalSearch() {
|
|||||||
<Space size="small" split={<Divider type="vertical" />}>
|
<Space size="small" split={<Divider type="vertical" />}>
|
||||||
<strong>{job.ro_number || t("general.labels.na")}</strong>
|
<strong>{job.ro_number || t("general.labels.na")}</strong>
|
||||||
<span>{`${job.status || ""}`}</span>
|
<span>{`${job.status || ""}`}</span>
|
||||||
<span>{`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
|
<span>
|
||||||
job.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={job} />
|
||||||
}`}</span>
|
</span>
|
||||||
<span>{`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${
|
<span>{`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${
|
||||||
job.v_model_desc || ""
|
job.v_model_desc || ""
|
||||||
}`}</span>
|
}`}</span>
|
||||||
@@ -57,15 +61,13 @@ export default function GlobalSearch() {
|
|||||||
options: data.search_owners.map((owner) => {
|
options: data.search_owners.map((owner) => {
|
||||||
return {
|
return {
|
||||||
key: owner.id,
|
key: owner.id,
|
||||||
value: `${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
|
value: OwnerNameDisplayFunction(owner),
|
||||||
owner.ownr_co_nm || ""
|
|
||||||
}`,
|
|
||||||
label: (
|
label: (
|
||||||
<Link to={`/manage/owners/${owner.id}`}>
|
<Link to={`/manage/owners/${owner.id}`}>
|
||||||
<Space size="small" split={<Divider type="vertical" />} wrap>
|
<Space size="small" split={<Divider type="vertical" />} wrap>
|
||||||
<span>{`${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
|
<span>
|
||||||
owner.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={owner} />
|
||||||
}`}</span>
|
</span>
|
||||||
<PhoneNumberFormatter>
|
<PhoneNumberFormatter>
|
||||||
{owner.ownr_ph1}
|
{owner.ownr_ph1}
|
||||||
</PhoneNumberFormatter>
|
</PhoneNumberFormatter>
|
||||||
@@ -171,8 +173,13 @@ export default function GlobalSearch() {
|
|||||||
<AutoComplete
|
<AutoComplete
|
||||||
options={options}
|
options={options}
|
||||||
onSearch={handleSearch}
|
onSearch={handleSearch}
|
||||||
|
suffixIcon={loading && <LoadingOutlined spin />}
|
||||||
|
defaultActiveFirstOption
|
||||||
placeholder={t("general.labels.globalsearch")}
|
placeholder={t("general.labels.globalsearch")}
|
||||||
allowClear
|
allowClear
|
||||||
|
onSelect={(val, opt) => {
|
||||||
|
history.push(opt.label.props.to);
|
||||||
|
}}
|
||||||
></AutoComplete>
|
></AutoComplete>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import ScheduleManualEvent from "../schedule-manual-event/schedule-manual-event.
|
|||||||
import ScheduleAtChange from "./job-at-change.component";
|
import ScheduleAtChange from "./job-at-change.component";
|
||||||
import ScheduleEventColor from "./schedule-event.color.component";
|
import ScheduleEventColor from "./schedule-event.color.component";
|
||||||
import ScheduleEventNote from "./schedule-event.note.component";
|
import ScheduleEventNote from "./schedule-event.note.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -73,9 +74,9 @@ export function ScheduleEventComponent({
|
|||||||
</Space>
|
</Space>
|
||||||
) : (
|
) : (
|
||||||
<Space>
|
<Space>
|
||||||
<strong>{`${(event.job && event.job.ownr_fn) || ""} ${
|
<strong>
|
||||||
(event.job && event.job.ownr_ln) || ""
|
<OwnerNameDisplay ownerObject={event.job} />
|
||||||
}`}</strong>
|
</strong>
|
||||||
<span style={{ margin: 4 }}>
|
<span style={{ margin: 4 }}>
|
||||||
{`${(event.job && event.job.v_model_yr) || ""} ${
|
{`${(event.job && event.job.v_model_yr) || ""} ${
|
||||||
(event.job && event.job.v_make_desc) || ""
|
(event.job && event.job.v_make_desc) || ""
|
||||||
@@ -256,9 +257,9 @@ export function ScheduleEventComponent({
|
|||||||
<Space>
|
<Space>
|
||||||
{event.note && <AlertFilled className="production-alert" />}
|
{event.note && <AlertFilled className="production-alert" />}
|
||||||
<strong>{`${event.job.ro_number || t("general.labels.na")}`}</strong>
|
<strong>{`${event.job.ro_number || t("general.labels.na")}`}</strong>
|
||||||
<span>{`${(event.job && event.job.ownr_fn) || ""} ${
|
<span>
|
||||||
(event.job && event.job.ownr_ln) || ""
|
<OwnerNameDisplay ownerObject={event.job} />
|
||||||
} ${(event.job && event.job.ownr_co_nm) || ""}`}</span>
|
</span>
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space>
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import { useQuery } from "@apollo/client";
|
||||||
|
import { Row, Col, Timeline, Typography, Space, Divider, Skeleton } from "antd";
|
||||||
|
import React from "react";
|
||||||
|
import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
|
export default function JobLinesExpander({ jobline, jobid }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, {
|
||||||
|
fetchPolicy: "network-only",
|
||||||
|
nextFetchPolicy: "network-only",
|
||||||
|
variables: {
|
||||||
|
joblineid: jobline.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (loading) return <Skeleton />;
|
||||||
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row>
|
||||||
|
<Col md={24} lg={12}>
|
||||||
|
<Typography.Title level={4}>
|
||||||
|
{t("parts_orders.labels.parts_orders")}
|
||||||
|
</Typography.Title>
|
||||||
|
<Timeline>
|
||||||
|
{data.parts_order_lines.length > 0 ? (
|
||||||
|
data.parts_order_lines.map((line) => (
|
||||||
|
<Timeline.Item key={line.id}>
|
||||||
|
<Space split={<Divider type="vertical" />} wrap>
|
||||||
|
<Link
|
||||||
|
to={`/manage/jobs/${jobid}?partsorderid=${line.parts_order.id}`}
|
||||||
|
>
|
||||||
|
{line.parts_order.order_number}
|
||||||
|
</Link>
|
||||||
|
<DateFormatter>{line.parts_order.order_date}</DateFormatter>
|
||||||
|
{line.parts_order.vendor.name}
|
||||||
|
</Space>
|
||||||
|
</Timeline.Item>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<Timeline.Item>
|
||||||
|
{t("parts_orders.labels.notyetordered")}
|
||||||
|
</Timeline.Item>
|
||||||
|
)}
|
||||||
|
</Timeline>
|
||||||
|
</Col>
|
||||||
|
<Col md={24} lg={12}></Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -4,6 +4,8 @@ import {
|
|||||||
SyncOutlined,
|
SyncOutlined,
|
||||||
WarningFilled,
|
WarningFilled,
|
||||||
EditFilled,
|
EditFilled,
|
||||||
|
PlusCircleTwoTone,
|
||||||
|
MinusCircleTwoTone,
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import {
|
import {
|
||||||
@@ -38,9 +40,11 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re
|
|||||||
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
|
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
|
||||||
|
import JobLinesExpander from "./job-lines-expander.component";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
bodyshop: selectBodyshop,
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
technician: selectTechnician,
|
technician: selectTechnician,
|
||||||
});
|
});
|
||||||
@@ -53,6 +57,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function JobLinesComponent({
|
export function JobLinesComponent({
|
||||||
|
bodyshop,
|
||||||
jobRO,
|
jobRO,
|
||||||
technician,
|
technician,
|
||||||
setPartsOrderContext,
|
setPartsOrderContext,
|
||||||
@@ -72,6 +77,9 @@ export function JobLinesComponent({
|
|||||||
filteredInfo: {},
|
filteredInfo: {},
|
||||||
});
|
});
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const jobIsPrivate = bodyshop.md_ins_cos.find(
|
||||||
|
(c) => c.name === job.ins_co_nm
|
||||||
|
)?.private;
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -283,7 +291,7 @@ export function JobLinesComponent({
|
|||||||
key: "actions",
|
key: "actions",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<div>
|
<div>
|
||||||
{record.manual_line && (
|
{(record.manual_line || jobIsPrivate) && (
|
||||||
<Space>
|
<Space>
|
||||||
<Button
|
<Button
|
||||||
disabled={jobRO}
|
disabled={jobRO}
|
||||||
@@ -449,6 +457,19 @@ export function JobLinesComponent({
|
|||||||
scroll={{
|
scroll={{
|
||||||
x: true,
|
x: true,
|
||||||
}}
|
}}
|
||||||
|
expandable={{
|
||||||
|
expandedRowRender: (record) => (
|
||||||
|
<JobLinesExpander jobline={record} jobid={job.id} />
|
||||||
|
),
|
||||||
|
rowExpandable: (record) => true,
|
||||||
|
//expandRowByClick: true,
|
||||||
|
expandIcon: ({ expanded, onExpand, record }) =>
|
||||||
|
expanded ? (
|
||||||
|
<MinusCircleTwoTone onClick={(e) => onExpand(record, e)} />
|
||||||
|
) : (
|
||||||
|
<PlusCircleTwoTone onClick={(e) => onExpand(record, e)} />
|
||||||
|
),
|
||||||
|
}}
|
||||||
onRow={(record, rowIndex) => {
|
onRow={(record, rowIndex) => {
|
||||||
return {
|
return {
|
||||||
onDoubleClick: (event) => {
|
onDoubleClick: (event) => {
|
||||||
|
|||||||
@@ -216,6 +216,7 @@ export function JobLinesUpsertModalComponent({
|
|||||||
rules={[
|
rules={[
|
||||||
({ getFieldValue }) => ({
|
({ getFieldValue }) => ({
|
||||||
validator(rule, value) {
|
validator(rule, value) {
|
||||||
|
console.log(value);
|
||||||
if (!value || getFieldValue("part_type") !== "PAE") {
|
if (!value || getFieldValue("part_type") !== "PAE") {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
@@ -226,7 +227,10 @@ export function JobLinesUpsertModalComponent({
|
|||||||
}),
|
}),
|
||||||
({ getFieldValue }) => ({
|
({ getFieldValue }) => ({
|
||||||
validator(rule, value) {
|
validator(rule, value) {
|
||||||
if (!!getFieldValue("part_type") === !!value) {
|
console.log(value, !!value);
|
||||||
|
if (
|
||||||
|
!!getFieldValue("part_type") === (!!value || value === 0)
|
||||||
|
) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export default function JobReconciliationBillsTable({
|
|||||||
dataIndex: "line_desc",
|
dataIndex: "line_desc",
|
||||||
key: "line_desc",
|
key: "line_desc",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
minWidth: "65rem",
|
width: "10rem",
|
||||||
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
sorter: (a, b) => alphaSort(a.line_desc, b.line_desc),
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
||||||
@@ -72,11 +72,11 @@ export default function JobReconciliationBillsTable({
|
|||||||
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "quantity" && state.sortedInfo.order,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("bills.fields.is_credit_memo"),
|
title: t("bills.fields.is_credit_memo_short"),
|
||||||
dataIndex: "is_credit_memo",
|
dataIndex: "is_credit_memo",
|
||||||
key: "is_credit_memo",
|
key: "is_credit_memo",
|
||||||
sorter: (a, b) => a.bill.is_credit_memo - b.bill.is_credit_memo,
|
sorter: (a, b) => a.bill.is_credit_memo - b.bill.is_credit_memo,
|
||||||
width: "8rem",
|
width: "3rem",
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "is_credit_memo" &&
|
state.sortedInfo.columnKey === "is_credit_memo" &&
|
||||||
state.sortedInfo.order,
|
state.sortedInfo.order,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
SEARCH_JOBS_FOR_AUTOCOMPLETE,
|
SEARCH_JOBS_FOR_AUTOCOMPLETE,
|
||||||
} from "../../graphql/jobs.queries";
|
} from "../../graphql/jobs.queries";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
const JobSearchSelect = (
|
const JobSearchSelect = (
|
||||||
@@ -86,11 +87,9 @@ const JobSearchSelect = (
|
|||||||
<span>
|
<span>
|
||||||
{`${clm_no && o.clm_no ? `${o.clm_no} | ` : ""}${
|
{`${clm_no && o.clm_no ? `${o.clm_no} | ` : ""}${
|
||||||
o.ro_number || t("general.labels.na")
|
o.ro_number || t("general.labels.na")
|
||||||
} | ${o.ownr_ln || ""} ${o.ownr_fn || ""} ${
|
} | ${OwnerNameDisplayFunction(o)} | ${
|
||||||
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""
|
o.v_model_yr || ""
|
||||||
}| ${o.v_model_yr || ""} ${o.v_make_desc || ""} ${
|
} ${o.v_make_desc || ""} ${o.v_model_desc || ""}`}
|
||||||
o.v_model_desc || ""
|
|
||||||
}`}
|
|
||||||
</span>
|
</span>
|
||||||
<Tag>
|
<Tag>
|
||||||
<strong>{o.status}</strong>
|
<strong>{o.status}</strong>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { insertAuditTrail } from "../../redux/application/application.actions";
|
|||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import axios from "axios";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -53,6 +53,12 @@ export function JobsConvertButton({
|
|||||||
variables: { jobId: job.id, ...values },
|
variables: { jobId: job.id, ...values },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (values.ca_gst_registrant) {
|
||||||
|
await axios.post("/job/totalsssu", {
|
||||||
|
id: job.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!res.errors) {
|
if (!res.errors) {
|
||||||
refetch();
|
refetch();
|
||||||
notification["success"]({
|
notification["success"]({
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
Col,
|
Col,
|
||||||
Divider,
|
|
||||||
Form,
|
Form,
|
||||||
Input,
|
Input,
|
||||||
InputNumber,
|
InputNumber,
|
||||||
@@ -23,8 +22,8 @@ import FormItemPhone, {
|
|||||||
} from "../form-items-formatted/phone-form-item.component";
|
} from "../form-items-formatted/phone-form-item.component";
|
||||||
import Car from "../job-damage-visual/job-damage-visual.component";
|
import Car from "../job-damage-visual/job-damage-visual.component";
|
||||||
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.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";
|
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
|
||||||
|
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -220,15 +219,8 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
|||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Divider
|
|
||||||
orientation="left"
|
|
||||||
type="horizontal"
|
|
||||||
style={{ marginTop: ".8rem", float: "right" }}
|
|
||||||
>
|
|
||||||
{t("jobs.forms.appraiserinfo")}
|
|
||||||
</Divider>
|
|
||||||
|
|
||||||
<FormRow noDivider>
|
<FormRow header={t("jobs.forms.appraiserinfo")}>
|
||||||
<Form.Item label={t("jobs.fields.est_co_nm")} name="est_co_nm">
|
<Form.Item label={t("jobs.fields.est_co_nm")} name="est_co_nm">
|
||||||
<Input disabled={jobRO} />
|
<Input disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { connect } from "react-redux";
|
|||||||
import { Link, useHistory } from "react-router-dom";
|
import { Link, useHistory } from "react-router-dom";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { CANCEL_APPOINTMENTS_BY_JOB_ID } from "../../graphql/appointments.queries";
|
||||||
import { DELETE_JOB, UPDATE_JOB, VOID_JOB } from "../../graphql/jobs.queries";
|
import { DELETE_JOB, UPDATE_JOB, VOID_JOB } from "../../graphql/jobs.queries";
|
||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
@@ -56,6 +57,7 @@ export function JobsDetailHeaderActions({
|
|||||||
const [deleteJob] = useMutation(DELETE_JOB);
|
const [deleteJob] = useMutation(DELETE_JOB);
|
||||||
const [updateJob] = useMutation(UPDATE_JOB);
|
const [updateJob] = useMutation(UPDATE_JOB);
|
||||||
const [voidJob] = useMutation(VOID_JOB);
|
const [voidJob] = useMutation(VOID_JOB);
|
||||||
|
const [cancelAllAppointments] = useMutation(CANCEL_APPOINTMENTS_BY_JOB_ID);
|
||||||
const jobInProduction = useMemo(() => {
|
const jobInProduction = useMemo(() => {
|
||||||
return bodyshop.md_ro_statuses.production_statuses.includes(job.status);
|
return bodyshop.md_ro_statuses.production_statuses.includes(job.status);
|
||||||
}, [job, bodyshop.md_ro_statuses.production_statuses]);
|
}, [job, bodyshop.md_ro_statuses.production_statuses]);
|
||||||
@@ -121,6 +123,39 @@ export function JobsDetailHeaderActions({
|
|||||||
>
|
>
|
||||||
{t("jobs.actions.schedule")}
|
{t("jobs.actions.schedule")}
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
<Menu.Item
|
||||||
|
disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled}
|
||||||
|
>
|
||||||
|
<Popconfirm
|
||||||
|
title={t("general.labels.areyousure")}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled}
|
||||||
|
onConfirm={async () => {
|
||||||
|
const jobUpdate = await cancelAllAppointments({
|
||||||
|
variables: {
|
||||||
|
jobid: job.id,
|
||||||
|
job: {
|
||||||
|
date_scheduled: null,
|
||||||
|
scheduled_in: null,
|
||||||
|
scheduled_completion: null,
|
||||||
|
status: bodyshop.md_ro_statuses.default_imported,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (!jobUpdate.errors) {
|
||||||
|
notification["success"]({
|
||||||
|
message: t("appointments.successes.canceled"),
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
getPopupContainer={(trigger) => trigger.parentNode}
|
||||||
|
>
|
||||||
|
{t("menus.jobsactions.cancelallappointments")}
|
||||||
|
</Popconfirm>
|
||||||
|
</Menu.Item>
|
||||||
<Menu.Item
|
<Menu.Item
|
||||||
disabled={
|
disabled={
|
||||||
!!job.intakechecklist ||
|
!!job.intakechecklist ||
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import "./jobs-detail-header.styles.scss";
|
|||||||
import JobsRelatedRos from "../jobs-related-ros/jobs-related-ros.component";
|
import JobsRelatedRos from "../jobs-related-ros/jobs-related-ros.component";
|
||||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
|
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
@@ -63,10 +64,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
|||||||
const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""}
|
const vehicleTitle = `${job.v_model_yr || ""} ${job.v_color || ""}
|
||||||
${job.v_make_desc || ""}
|
${job.v_make_desc || ""}
|
||||||
${job.v_model_desc || ""}`.trim();
|
${job.v_model_desc || ""}`.trim();
|
||||||
console.log(
|
|
||||||
"🚀 ~ file: jobs-detail-header.component.jsx ~ line 64 ~ vehicleTitle",
|
const ownerTitle = OwnerNameDisplayFunction(job).trim();
|
||||||
vehicleTitle.length
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<Row gutter={[16, 16]} style={{ alignItems: "stretch" }}>
|
<Row gutter={[16, 16]} style={{ alignItems: "stretch" }}>
|
||||||
<Col {...colSpan}>
|
<Col {...colSpan}>
|
||||||
@@ -159,9 +159,9 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
|
|||||||
style={{ height: "100%" }}
|
style={{ height: "100%" }}
|
||||||
title={
|
title={
|
||||||
<Link to={disabled ? "#" : `/manage/owners/${job.owner.id}`}>
|
<Link to={disabled ? "#" : `/manage/owners/${job.owner.id}`}>
|
||||||
{`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
|
{ownerTitle.length > 0
|
||||||
job.ownr_co_nm || ""
|
? ownerTitle
|
||||||
}`}
|
: t("owner.labels.noownerinfo")}
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -88,6 +88,33 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
<CABCpvrtCalculator form={form} disabled={jobRO} />
|
||||||
</Space>
|
</Space>
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.auto_add_ats")}
|
||||||
|
name="auto_add_ats"
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
nostyle
|
||||||
|
shouldUpdate={(prev, cur) => prev.auto_add_ats !== cur.auto_add_ats}
|
||||||
|
>
|
||||||
|
{() => {
|
||||||
|
if (form.getFieldValue("auto_add_ats"))
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.rate_ats")}
|
||||||
|
name="rate_ats"
|
||||||
|
initialValue={bodyshop.shoprates.rate_atp}
|
||||||
|
>
|
||||||
|
<CurrencyInput disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
</FormRow>
|
</FormRow>
|
||||||
<FormRow>
|
<FormRow>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
@@ -100,7 +127,13 @@ export function JobsDetailRates({ jobRO, form, job, bodyshop }) {
|
|||||||
label={t("jobs.fields.state_tax_rate")}
|
label={t("jobs.fields.state_tax_rate")}
|
||||||
name="state_tax_rate"
|
name="state_tax_rate"
|
||||||
>
|
>
|
||||||
<InputNumber min={0} max={1} precision={2} disabled={jobRO} autoComplete="new-password"/>
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
max={1}
|
||||||
|
precision={2}
|
||||||
|
disabled={jobRO}
|
||||||
|
autoComplete="new-password"
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.local_tax_rate")}
|
label={t("jobs.fields.local_tax_rate")}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import React from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function JobsFindModalComponent({
|
export default function JobsFindModalComponent({
|
||||||
selectedJob,
|
selectedJob,
|
||||||
@@ -43,15 +44,12 @@ export default function JobsFindModalComponent({
|
|||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.owner ? (
|
return record.owner ? (
|
||||||
<Link to={"/manage/owners/" + record.owner.id}>
|
<Link to={"/manage/owners/" + record.owner.id}>
|
||||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
// t("jobs.errors.noowner")
|
<span>
|
||||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.ownr_co_nm || ""
|
</span>
|
||||||
}`}</span>
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import StartChatButton from "../chat-open-button/chat-open-button.component";
|
import StartChatButton from "../chat-open-button/chat-open-button.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -52,14 +52,12 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
|||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.ownerid ? (
|
return record.ownerid ? (
|
||||||
<Link to={"/manage/owners/" + record.ownerid}>
|
<Link to={"/manage/owners/" + record.ownerid}>
|
||||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<span>
|
||||||
record.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
}`}</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
|||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
import ChatOpenButton from "../chat-open-button/chat-open-button.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -141,14 +142,12 @@ export function JobsList({ bodyshop }) {
|
|||||||
to={"/manage/owners/" + record.owner.id}
|
to={"/manage/owners/" + record.owner.id}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<span>
|
||||||
record.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
}`}</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { QUERY_SEARCH_OWNER_BY_IDX } from "../../graphql/owners.queries";
|
|||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
import OwnerFindModalComponent from "./owner-find-modal.component";
|
import OwnerFindModalComponent from "./owner-find-modal.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function OwnerFindModalContainer({
|
export default function OwnerFindModalContainer({
|
||||||
loading,
|
loading,
|
||||||
@@ -30,9 +31,7 @@ export default function OwnerFindModalContainer({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modalProps.visible && owner) {
|
if (modalProps.visible && owner) {
|
||||||
const s = `${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
|
const s = OwnerNameDisplayFunction(owner);
|
||||||
owner.ownr_co_nm || ""
|
|
||||||
}`;
|
|
||||||
|
|
||||||
setSearchText(s.trim());
|
setSearchText(s.trim());
|
||||||
callSearchowners({ variables: { search: s.trim() } });
|
callSearchowners({ variables: { search: s.trim() } });
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { store } from "../../redux/store";
|
||||||
|
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)(OwnerNameDisplay);
|
||||||
|
|
||||||
|
export function OwnerNameDisplay({ bodyshop, ownerObject }) {
|
||||||
|
const emptyTest =
|
||||||
|
ownerObject.ownr_fn + ownerObject.ownr_ln + ownerObject.ownr_co_nm;
|
||||||
|
|
||||||
|
if (!emptyTest || emptyTest === "null" || emptyTest.trim() === "")
|
||||||
|
return "N/A";
|
||||||
|
|
||||||
|
if (bodyshop.last_name_first)
|
||||||
|
return `${ownerObject.ownr_ln || ""}, ${ownerObject.ownr_fn || ""} ${
|
||||||
|
ownerObject.ownr_co_nm || ""
|
||||||
|
}`.trim();
|
||||||
|
|
||||||
|
return `${ownerObject.ownr_fn || ""} ${ownerObject.ownr_ln || ""} ${
|
||||||
|
ownerObject.ownr_co_nm || ""
|
||||||
|
}`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function OwnerNameDisplayFunction(ownerObject) {
|
||||||
|
const emptyTest =
|
||||||
|
ownerObject.ownr_fn + ownerObject.ownr_ln + ownerObject.ownr_co_nm;
|
||||||
|
|
||||||
|
if (!emptyTest || emptyTest === "null" || emptyTest.trim() === "")
|
||||||
|
return "N/A";
|
||||||
|
|
||||||
|
const rdxStore = store.getState();
|
||||||
|
|
||||||
|
if (rdxStore.user.bodyshop.last_name_first)
|
||||||
|
return `${ownerObject.ownr_ln || ""}, ${ownerObject.ownr_fn || ""} ${
|
||||||
|
ownerObject.ownr_co_nm || ""
|
||||||
|
}`.trim();
|
||||||
|
|
||||||
|
return `${ownerObject.ownr_fn || ""} ${ownerObject.ownr_ln || ""} ${
|
||||||
|
ownerObject.ownr_co_nm || ""
|
||||||
|
}`.trim();
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
SEARCH_OWNERS_FOR_AUTOCOMPLETE,
|
SEARCH_OWNERS_FOR_AUTOCOMPLETE,
|
||||||
} from "../../graphql/owners.queries";
|
} from "../../graphql/owners.queries";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const { Option } = Select;
|
const { Option } = Select;
|
||||||
|
|
||||||
@@ -16,10 +17,8 @@ const OwnerSearchSelect = ({ value, onChange, onBlur, disabled }, ref) => {
|
|||||||
SEARCH_OWNERS_FOR_AUTOCOMPLETE
|
SEARCH_OWNERS_FOR_AUTOCOMPLETE
|
||||||
);
|
);
|
||||||
|
|
||||||
const [
|
const [callIdSearch, { loading: idLoading, error: idError, data: idData }] =
|
||||||
callIdSearch,
|
useLazyQuery(SEARCH_OWNERS_BY_ID_FOR_AUTOCOMPLETE);
|
||||||
{ loading: idLoading, error: idError, data: idData },
|
|
||||||
] = useLazyQuery(SEARCH_OWNERS_BY_ID_FOR_AUTOCOMPLETE);
|
|
||||||
|
|
||||||
const executeSearch = (v) => {
|
const executeSearch = (v) => {
|
||||||
callSearch(v);
|
callSearch(v);
|
||||||
@@ -78,9 +77,7 @@ const OwnerSearchSelect = ({ value, onChange, onBlur, disabled }, ref) => {
|
|||||||
{theOptions
|
{theOptions
|
||||||
? theOptions.map((o) => (
|
? theOptions.map((o) => (
|
||||||
<Option key={o.id} value={o.id}>
|
<Option key={o.id} value={o.id}>
|
||||||
{`${o.ownr_ln || ""} ${o.ownr_fn || ""} ${
|
{`${OwnerNameDisplayFunction(o)} | ${o.ownr_addr1 || ""} `}
|
||||||
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""
|
|
||||||
}| ${o.ownr_addr1 || ""} `}
|
|
||||||
</Option>
|
</Option>
|
||||||
))
|
))
|
||||||
: null}
|
: null}
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import React from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
|
import OwnerNameDisplay, {
|
||||||
|
OwnerNameDisplayFunction,
|
||||||
|
} from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function OwnerTagPopoverComponent({ job }) {
|
export default function OwnerTagPopoverComponent({ job }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const content = (
|
const content = (
|
||||||
@@ -10,9 +14,9 @@ export default function OwnerTagPopoverComponent({ job }) {
|
|||||||
<Row>
|
<Row>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Descriptions title={t("owners.labels.fromclaim")} column={1}>
|
<Descriptions title={t("owners.labels.fromclaim")} column={1}>
|
||||||
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>{`${
|
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>
|
||||||
job.ownr_fn || ""
|
<OwnerNameDisplay ownerObject={job} />
|
||||||
} ${job.ownr_ln || ""} ${job.ownr_co_nm || ""}`}</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph1")}>
|
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph1")}>
|
||||||
<PhoneFormatter>{job.ownr_ph1 || ""}</PhoneFormatter>
|
<PhoneFormatter>{job.ownr_ph1 || ""}</PhoneFormatter>
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
@@ -31,11 +35,9 @@ export default function OwnerTagPopoverComponent({ job }) {
|
|||||||
</Col>
|
</Col>
|
||||||
<Col span={12}>
|
<Col span={12}>
|
||||||
<Descriptions title={t("owners.labels.fromowner")} column={1}>
|
<Descriptions title={t("owners.labels.fromowner")} column={1}>
|
||||||
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>{`${
|
<Descriptions.Item key="1" label={t("jobs.fields.owner")}>
|
||||||
job.owner.ownr_fn || ""
|
<OwnerNameDisplay ownerObject={job.owner} />
|
||||||
} ${job.owner.ownr_ln || ""} ${
|
</Descriptions.Item>
|
||||||
job.owner.ownr_co_nm || ""
|
|
||||||
}`}</Descriptions.Item>
|
|
||||||
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph1")}>
|
<Descriptions.Item key="2" label={t("jobs.fields.ownr_ph1")}>
|
||||||
<PhoneFormatter>{job.owner.ownr_ph1 || ""}</PhoneFormatter>
|
<PhoneFormatter>{job.owner.ownr_ph1 || ""}</PhoneFormatter>
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
@@ -68,9 +70,7 @@ export default function OwnerTagPopoverComponent({ job }) {
|
|||||||
<Popover placement="bottom" content={content}>
|
<Popover placement="bottom" content={content}>
|
||||||
<Tag color="cyan">
|
<Tag color="cyan">
|
||||||
<Link to={`/manage/owners/${job.owner.id}`}>
|
<Link to={`/manage/owners/${job.owner.id}`}>
|
||||||
{job.owner
|
{job.owner ? OwnerNameDisplayFunction(job) : t("jobs.errors.noowner")}
|
||||||
? `${job.ownr_co_nm || ""}${job.ownr_fn || ""} ${job.ownr_ln || ""}`
|
|
||||||
: t("jobs.errors.noowner")}
|
|
||||||
</Link>
|
</Link>
|
||||||
</Tag>
|
</Tag>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import React, { useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
import { Link, useHistory, useLocation } from "react-router-dom";
|
||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function OwnersListComponent({
|
export default function OwnersListComponent({
|
||||||
loading,
|
loading,
|
||||||
@@ -33,9 +34,7 @@ export default function OwnersListComponent({
|
|||||||
key: "name",
|
key: "name",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Link to={"/manage/owners/" + record.id}>
|
<Link to={"/manage/owners/" + record.id}>
|
||||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,13 +1,10 @@
|
|||||||
import { notification } from "antd";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import React, { useEffect } from "react";
|
import React, { useEffect } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { setPartnerVersion } from "../../redux/application/application.actions";
|
import { setPartnerVersion } from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import {store} from '../../redux/store'
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -21,45 +18,48 @@ export default connect(
|
|||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(PartnerPingComponent);
|
)(PartnerPingComponent);
|
||||||
|
|
||||||
export function PartnerPingComponent({ bodyshop, setPartnerVersion }) {
|
export function PartnerPingComponent({ bodyshop, }) {
|
||||||
const { t } = useTranslation();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Create an scoped async function in the hook
|
// Create an scoped async function in the hook
|
||||||
async function checkPartnerStatus() {
|
|
||||||
if (!bodyshop) return;
|
|
||||||
try {
|
|
||||||
//if (process.env.NODE_ENV === "development") return;
|
|
||||||
const PartnerResponse = await axios.post("http://localhost:1337/ping/");
|
|
||||||
const { appver, qbpath } = PartnerResponse.data;
|
|
||||||
setPartnerVersion(appver);
|
|
||||||
console.log({ appver, qbpath });
|
|
||||||
if (
|
|
||||||
!qbpath &&
|
|
||||||
!(
|
|
||||||
bodyshop &&
|
|
||||||
(bodyshop.cdk_dealerid ||
|
|
||||||
bodyshop.pbs_serialnumber ||
|
|
||||||
bodyshop.accountingconfig.qbo)
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
notification["error"]({
|
|
||||||
title: "",
|
|
||||||
message: t("general.messages.noacctfilepath"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
notification["error"]({
|
|
||||||
title: "",
|
|
||||||
message: t("general.messages.partnernotrunning"),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Execute the created function directly
|
// Execute the created function directly
|
||||||
checkPartnerStatus();
|
checkPartnerStatus(bodyshop);
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [bodyshop]);
|
}, [bodyshop]);
|
||||||
|
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function checkPartnerStatus(bodyshop) {
|
||||||
|
if (!bodyshop) return;
|
||||||
|
try {
|
||||||
|
//if (process.env.NODE_ENV === "development") return;
|
||||||
|
const PartnerResponse = await axios.post("http://localhost:1337/ping/");
|
||||||
|
// const {
|
||||||
|
// appver, //qbpath
|
||||||
|
// } = PartnerResponse.data;
|
||||||
|
console.log(PartnerResponse.data)
|
||||||
|
store.dispatch(setPartnerVersion(PartnerResponse.data));
|
||||||
|
// if (
|
||||||
|
// checkAcctPath &&
|
||||||
|
// !qbpath &&
|
||||||
|
// !(
|
||||||
|
// bodyshop &&
|
||||||
|
// (bodyshop.cdk_dealerid ||
|
||||||
|
// bodyshop.pbs_serialnumber ||
|
||||||
|
// bodyshop.accountingconfig.qbo)
|
||||||
|
// )
|
||||||
|
// ) {
|
||||||
|
// notification["error"]({
|
||||||
|
// title: "",
|
||||||
|
// message: i18n.t("general.messages.noacctfilepath"),
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
} catch (error) {
|
||||||
|
console.log("ImEX Online Partner is not running.", error);
|
||||||
|
// notification["error"]({
|
||||||
|
// title: "",
|
||||||
|
// message: i18n.t("general.messages.partnernotrunning"),
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -425,8 +425,6 @@ export function PartsOrderListTableComponent({
|
|||||||
placement="right"
|
placement="right"
|
||||||
onClose={() => handleOnRowClick(null)}
|
onClose={() => handleOnRowClick(null)}
|
||||||
visible={selectedpartsorder}
|
visible={selectedpartsorder}
|
||||||
//getContainer={false}
|
|
||||||
style={{ position: "absolute" }}
|
|
||||||
closable
|
closable
|
||||||
width={drawerPercentage}
|
width={drawerPercentage}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DeleteFilled, WarningFilled } from "@ant-design/icons";
|
import { DeleteFilled, WarningFilled, DownOutlined } from "@ant-design/icons";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import { useTreatments } from "@splitsoftware/splitio-react";
|
||||||
import {
|
import {
|
||||||
Divider,
|
Divider,
|
||||||
@@ -9,6 +9,8 @@ import {
|
|||||||
Space,
|
Space,
|
||||||
Tag,
|
Tag,
|
||||||
Select,
|
Select,
|
||||||
|
Menu,
|
||||||
|
Dropdown,
|
||||||
} from "antd";
|
} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -39,6 +41,7 @@ export function PartsOrderModalComponent({
|
|||||||
isReturn,
|
isReturn,
|
||||||
preferredMake,
|
preferredMake,
|
||||||
job,
|
job,
|
||||||
|
form,
|
||||||
}) {
|
}) {
|
||||||
const [sendType, setSendType] = sendTypeState;
|
const [sendType, setSendType] = sendTypeState;
|
||||||
const { OEConnection } = useTreatments(
|
const { OEConnection } = useTreatments(
|
||||||
@@ -52,6 +55,21 @@ export function PartsOrderModalComponent({
|
|||||||
bodyshop.imexshopid
|
bodyshop.imexshopid
|
||||||
);
|
);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const handleClick = ({ item, key, keyPath }) => {
|
||||||
|
form.setFieldsValue({ comments: item.props.value });
|
||||||
|
};
|
||||||
|
|
||||||
|
const menu = (
|
||||||
|
<div>
|
||||||
|
<Menu onClick={handleClick}>
|
||||||
|
{bodyshop.md_parts_order_comment.map((comment, idx) => (
|
||||||
|
<Menu.Item value={comment.comment} key={idx}>
|
||||||
|
{comment.label}
|
||||||
|
</Menu.Item>
|
||||||
|
))}
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -243,7 +261,23 @@ export function PartsOrderModalComponent({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
<Form.Item name="comments" label={t("parts_orders.fields.comments")}>
|
<Form.Item
|
||||||
|
name="comments"
|
||||||
|
label={
|
||||||
|
<Space>
|
||||||
|
{t("parts_orders.fields.comments")}
|
||||||
|
<Dropdown overlay={menu}>
|
||||||
|
<a
|
||||||
|
className="ant-dropdown-link"
|
||||||
|
href=" #"
|
||||||
|
onClick={(e) => e.preventDefault()}
|
||||||
|
>
|
||||||
|
<DownOutlined />
|
||||||
|
</a>
|
||||||
|
</Dropdown>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
>
|
||||||
<Input.TextArea rows={3} />
|
<Input.TextArea rows={3} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Radio.Group
|
<Radio.Group
|
||||||
|
|||||||
@@ -346,6 +346,7 @@ export function PartsOrderModalContainer({
|
|||||||
<LoadingSpinner />
|
<LoadingSpinner />
|
||||||
) : (
|
) : (
|
||||||
<PartsOrderModalComponent
|
<PartsOrderModalComponent
|
||||||
|
form={form}
|
||||||
vendorList={(data && data.vendors) || []}
|
vendorList={(data && data.vendors) || []}
|
||||||
sendTypeState={sendTypeState}
|
sendTypeState={sendTypeState}
|
||||||
isReturn={isReturn}
|
isReturn={isReturn}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { alphaSort } from "../../utils/sorters";
|
|||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
import CaBcEtfTableModalContainer from "../ca-bc-etf-table-modal/ca-bc-etf-table-modal.container";
|
import CaBcEtfTableModalContainer from "../ca-bc-etf-table-modal/ca-bc-etf-table-modal.container";
|
||||||
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const stripeTestEnv = process.env.REACT_APP_STRIPE_PUBLIC_KEY; //.includes("test");
|
const stripeTestEnv = process.env.REACT_APP_STRIPE_PUBLIC_KEY; //.includes("test");
|
||||||
|
|
||||||
@@ -78,14 +79,12 @@ export function PaymentsListPaginated({
|
|||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.job.owner ? (
|
return record.job.owner ? (
|
||||||
<Link to={"/manage/owners/" + record.job.owner.id}>
|
<Link to={"/manage/owners/" + record.job.owner.id}>
|
||||||
{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.job.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span>{`${record.job.ownr_fn || ""} ${record.job.ownr_ln || ""} ${
|
<span>
|
||||||
record.job.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
}`}</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import ProductionListColumnProductionNote from "../production-list-columns/produ
|
|||||||
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
import ProductionSubletsManageComponent from "../production-sublets-manage/production-sublets-manage.component";
|
||||||
import "./production-board-card.styles.scss";
|
import "./production-board-card.styles.scss";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function ProductionBoardCard(
|
export default function ProductionBoardCard(
|
||||||
technician,
|
technician,
|
||||||
@@ -61,20 +62,22 @@ export default function ProductionBoardCard(
|
|||||||
<PauseCircleOutlined style={{ color: "orangered" }} />
|
<PauseCircleOutlined style={{ color: "orangered" }} />
|
||||||
)}
|
)}
|
||||||
<span style={{ fontWeight: "bolder" }}>
|
<span style={{ fontWeight: "bolder" }}>
|
||||||
{card.ro_number || t("general.labels.na")}
|
<Link
|
||||||
|
to={
|
||||||
|
technician
|
||||||
|
? `/tech/joblookup?selected=${card.id}`
|
||||||
|
: `/manage/jobs/${card.id}`
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{card.ro_number || t("general.labels.na")}
|
||||||
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
extra={
|
extra={
|
||||||
technician ? (
|
<Link to={{ search: `?selected=${card.id}` }}>
|
||||||
<Link to={`/tech/joblookup?selected=${card.id}`}>
|
<EyeFilled />
|
||||||
<EyeFilled />
|
</Link>
|
||||||
</Link>
|
|
||||||
) : (
|
|
||||||
<Link to={`/manage/jobs/${card.id}`}>
|
|
||||||
<EyeFilled />
|
|
||||||
</Link>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<Row>
|
<Row>
|
||||||
@@ -85,9 +88,9 @@ export default function ProductionBoardCard(
|
|||||||
card.ownr_co_nm || ""
|
card.ownr_co_nm || ""
|
||||||
}`}</div>
|
}`}</div>
|
||||||
) : (
|
) : (
|
||||||
<div className="ellipses">{`${card.ownr_ln || ""}, ${
|
<div className="ellipses">
|
||||||
card.ownr_fn || ""
|
<OwnerNameDisplay ownerObject={card} />
|
||||||
} ${card.ownr_co_nm || ""}`}</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -131,6 +131,13 @@ export default function ProductionBoardKanbanCardSettings({
|
|||||||
>
|
>
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
valuePropName="checked"
|
||||||
|
label={t("production.labels.stickyheader")}
|
||||||
|
name="stickyheader"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,26 +1,27 @@
|
|||||||
|
import { SyncOutlined } from "@ant-design/icons";
|
||||||
import { useApolloClient } from "@apollo/client";
|
import { useApolloClient } from "@apollo/client";
|
||||||
import Board, { moveCard } from "@asseinfo/react-kanban";
|
import Board, { moveCard } from "@asseinfo/react-kanban";
|
||||||
//import "@asseinfo/react-kanban/dist/styles.css";
|
import { Button, Grid, notification, PageHeader, Space, Statistic } from "antd";
|
||||||
import "./production-board-kanban.styles.scss";
|
|
||||||
import { SyncOutlined } from "@ant-design/icons";
|
|
||||||
import { Grid, notification, Button, PageHeader, Space, Statistic } from "antd";
|
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
import { Sticky, StickyContainer } from "react-sticky";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import ProductionBoardCard from "../production-board-kanban-card/production-board-kanban-card.component";
|
|
||||||
import { createBoardData } from "./production-board-kanban.utils.js";
|
|
||||||
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
|
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
|
||||||
import ProductionBoardFilters from "../production-board-filters/production-board-filters.component";
|
|
||||||
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";
|
import styled from "styled-components";
|
||||||
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
|
||||||
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
|
||||||
|
import ProductionBoardFilters from "../production-board-filters/production-board-filters.component";
|
||||||
|
import ProductionBoardCard from "../production-board-kanban-card/production-board-kanban-card.component";
|
||||||
|
import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component";
|
||||||
|
import ProductionBoardKanbanCardSettings from "./production-board-kanban.card-settings.component";
|
||||||
|
//import "@asseinfo/react-kanban/dist/styles.css";
|
||||||
|
import "./production-board-kanban.styles.scss";
|
||||||
|
import { createBoardData } from "./production-board-kanban.utils.js";
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
technician: selectTechnician,
|
technician: selectTechnician,
|
||||||
@@ -183,9 +184,52 @@ export function ProductionBoardKanbanComponent({
|
|||||||
: standardSizes[selectedBreakpoint[0]]
|
: standardSizes[selectedBreakpoint[0]]
|
||||||
: "250";
|
: "250";
|
||||||
|
|
||||||
|
const stickyHeader = {
|
||||||
|
renderColumnHeader: ({ title }) => (
|
||||||
|
<Sticky>
|
||||||
|
{({
|
||||||
|
style,
|
||||||
|
|
||||||
|
// the following are also available but unused in this example
|
||||||
|
isSticky,
|
||||||
|
wasSticky,
|
||||||
|
distanceFromTop,
|
||||||
|
distanceFromBottom,
|
||||||
|
calculatedHeight,
|
||||||
|
}) => (
|
||||||
|
<div
|
||||||
|
className="react-kanban-column-header"
|
||||||
|
style={{ ...style, zIndex: "99", backgroundColor: "#ddd" }}
|
||||||
|
>
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Sticky>
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const cardSettings =
|
||||||
|
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,
|
||||||
|
stickyheader: false,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container width={width}>
|
<Container width={width}>
|
||||||
<IndefiniteLoading loading={isMoving} />
|
<IndefiniteLoading loading={isMoving} />
|
||||||
|
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title={
|
title={
|
||||||
<Space>
|
<Space>
|
||||||
@@ -215,34 +259,19 @@ export function ProductionBoardKanbanComponent({
|
|||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<ProductionListDetailComponent jobs={data} />
|
||||||
<Board
|
<StickyContainer>
|
||||||
children={boardLanes}
|
<Board
|
||||||
disableCardDrag={isMoving}
|
style={{ height: "100%" }}
|
||||||
renderCard={(card) =>
|
children={boardLanes}
|
||||||
ProductionBoardCard(
|
disableCardDrag={isMoving}
|
||||||
technician,
|
{...(cardSettings.stickyheader && stickyHeader)}
|
||||||
card,
|
renderCard={(card) =>
|
||||||
bodyshop,
|
ProductionBoardCard(technician, card, bodyshop, cardSettings)
|
||||||
associationSettings &&
|
}
|
||||||
associationSettings.kanban_settings &&
|
onCardDragEnd={handleDragEnd}
|
||||||
Object.keys(associationSettings.kanban_settings).length > 0
|
/>
|
||||||
? associationSettings.kanban_settings
|
</StickyContainer>
|
||||||
: {
|
|
||||||
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}
|
|
||||||
/>
|
|
||||||
</Container>
|
</Container>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import ProductionListColumnStatus from "./production-list-columns.status.compone
|
|||||||
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
import ProductionListColumnCategory from "./production-list-columns.status.category";
|
||||||
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
|
||||||
import ProductionListColumnComment from "./production-list-columns.comment.component";
|
import ProductionListColumnComment from "./production-list-columns.comment.component";
|
||||||
|
import ProductionListColumnPartsReceived from "./production-list-columns.partsreceived.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
||||||
return [
|
return [
|
||||||
@@ -67,11 +69,7 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
dataIndex: "ownr",
|
dataIndex: "ownr",
|
||||||
key: "ownr",
|
key: "ownr",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (text, record) => (
|
render: (text, record) => <OwnerNameDisplay ownerObject={record} />,
|
||||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}</span>
|
|
||||||
),
|
|
||||||
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
|
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
|
||||||
@@ -81,6 +79,13 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
dataIndex: "vehicle",
|
dataIndex: "vehicle",
|
||||||
key: "vehicle",
|
key: "vehicle",
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
|
sorter: (a, b) =>
|
||||||
|
alphaSort(
|
||||||
|
a.v_make_desc + a.v_model_desc,
|
||||||
|
b.v_make_desc + b.v_model_desc
|
||||||
|
),
|
||||||
|
sortOrder:
|
||||||
|
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||||
record.v_model_desc || ""
|
record.v_model_desc || ""
|
||||||
@@ -96,7 +101,7 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "actual_in" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "actual_in" && state.sortedInfo.order,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<ProductionListDate record={record} field="actual_in" time/>
|
<ProductionListDate record={record} field="actual_in" time />
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -477,6 +482,14 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
|
|||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: i18n.t("jobs.labels.parts_received"),
|
||||||
|
dataIndex: "parts_received",
|
||||||
|
key: "parts_received",
|
||||||
|
render: (text, record) => (
|
||||||
|
<ProductionListColumnPartsReceived record={record} />
|
||||||
|
),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
export default r;
|
export default r;
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { useMemo } from "react";
|
||||||
|
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
|
||||||
|
)(ProductionListColumnPartsReceived);
|
||||||
|
|
||||||
|
export function ProductionListColumnPartsReceived({ bodyshop, record }) {
|
||||||
|
const amount = useMemo(() => {
|
||||||
|
const amount = record.joblines_status.reduce(
|
||||||
|
(acc, val) => {
|
||||||
|
acc.total += val.count;
|
||||||
|
acc.received =
|
||||||
|
val.status === bodyshop.md_order_statuses.default_received
|
||||||
|
? acc.received + val.count
|
||||||
|
: acc.received;
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{ total: 0, received: 0 }
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...amount,
|
||||||
|
percent:
|
||||||
|
amount.total !== 0
|
||||||
|
? ((amount.received / amount.total) * 100).toFixed(0) + "%"
|
||||||
|
: "N/A",
|
||||||
|
};
|
||||||
|
}, [record, bodyshop.md_order_statuses]);
|
||||||
|
|
||||||
|
return `${amount.percent} (${amount.received}/${amount.total})`;
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
|||||||
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
|
import ProductionRemoveButton from "../production-remove-button/production-remove-button.component";
|
||||||
import JobAtChange from "../job-at-change/job-at-change.component";
|
import JobAtChange from "../job-at-change/job-at-change.component";
|
||||||
import { PrinterFilled } from "@ant-design/icons";
|
import { PrinterFilled } from "@ant-design/icons";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
@@ -107,9 +107,7 @@ export function ProductionListDetail({ jobs, setPrintCenterContext }) {
|
|||||||
{theJob.ins_co_nm || ""}
|
{theJob.ins_co_nm || ""}
|
||||||
</Descriptions.Item>
|
</Descriptions.Item>
|
||||||
<Descriptions.Item label={t("jobs.fields.owner")}>
|
<Descriptions.Item label={t("jobs.fields.owner")}>
|
||||||
{`${theJob.ownr_fn || ""} ${theJob.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={theJob} />
|
||||||
theJob.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
<StartChatButton
|
<StartChatButton
|
||||||
phone={data.jobs_by_pk.ownr_ph1}
|
phone={data.jobs_by_pk.ownr_ph1}
|
||||||
jobid={data.jobs_by_pk.id}
|
jobid={data.jobs_by_pk.id}
|
||||||
|
|||||||
@@ -88,12 +88,6 @@ export function ProductionListTable({
|
|||||||
);
|
);
|
||||||
|
|
||||||
const handleTableChange = (pagination, filters, sorter) => {
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
console.log(
|
|
||||||
"🚀 ~ file: production-list-table.component.jsx ~ line 91 ~ pagination, filters, sorter",
|
|
||||||
pagination,
|
|
||||||
filters,
|
|
||||||
sorter
|
|
||||||
);
|
|
||||||
setState({
|
setState({
|
||||||
...state,
|
...state,
|
||||||
filteredInfo: filters,
|
filteredInfo: filters,
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { DateTimeFormatter } from "../../utils/DateFormatter";
|
|||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import "./schedule-production-list.styles.scss";
|
import "./schedule-production-list.styles.scss";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
export default function ScheduleProductionList() {
|
export default function ScheduleProductionList() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [callQuery, { loading, error, data }] = useLazyQuery(
|
const [callQuery, { loading, error, data }] = useLazyQuery(
|
||||||
@@ -36,9 +36,7 @@ export default function ScheduleProductionList() {
|
|||||||
<td>
|
<td>
|
||||||
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
<Link to={`/manage/jobs/${j.id}`}>{j.ro_number}</Link>
|
||||||
</td>
|
</td>
|
||||||
<td>{`${j.ownr_fn || ""} ${j.ownr_ln || ""} ${
|
<td><OwnerNameDisplay ownerObject={j} /></td>
|
||||||
j.ownr_co_nm || ""
|
|
||||||
}`}</td>
|
|
||||||
<td>{`${j.v_model_yr || ""} ${j.v_make_desc || ""} ${
|
<td>{`${j.v_model_yr || ""} ${j.v_make_desc || ""} ${
|
||||||
j.v_model_desc || ""
|
j.v_model_desc || ""
|
||||||
}`}</td>
|
}`}</td>
|
||||||
|
|||||||
@@ -163,6 +163,27 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate noStyle>
|
||||||
|
{() => (
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.labels.qbo_usa")}
|
||||||
|
shouldUpdate
|
||||||
|
valuePropName="checked"
|
||||||
|
name={["accountingconfig", "qbo_usa"]}
|
||||||
|
>
|
||||||
|
<Switch
|
||||||
|
disabled={!form.getFieldValue(["accountingconfig", "qbo"])}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.labels.qbo_departmentid")}
|
||||||
|
name={["accountingconfig", "qbo_departmentid"]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bodyshop.labels.accountingtiers")}
|
label={t("bodyshop.labels.accountingtiers")}
|
||||||
rules={[
|
rules={[
|
||||||
@@ -499,7 +520,6 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<CurrencyInput />
|
<CurrencyInput />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={["attach_pdf_to_email"]}
|
name={["attach_pdf_to_email"]}
|
||||||
label={t("bodyshop.fields.attach_pdf_to_email")}
|
label={t("bodyshop.fields.attach_pdf_to_email")}
|
||||||
@@ -538,6 +558,13 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<Switch />
|
<Switch />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={["bill_allow_post_to_closed"]}
|
||||||
|
label={t("bodyshop.fields.bill_allow_post_to_closed")}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
name={["md_ded_notes"]}
|
name={["md_ded_notes"]}
|
||||||
label={t("bodyshop.fields.md_ded_notes")}
|
label={t("bodyshop.fields.md_ded_notes")}
|
||||||
@@ -550,6 +577,13 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<Select mode="tags" />
|
<Select mode="tags" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
name={["last_name_first"]}
|
||||||
|
label={t("bodyshop.fields.last_name_first")}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow grow header={t("bodyshop.labels.messagingpresets")}>
|
<LayoutFormRow grow header={t("bodyshop.labels.messagingpresets")}>
|
||||||
<Form.List name={["md_messaging_presets"]}>
|
<Form.List name={["md_messaging_presets"]}>
|
||||||
@@ -784,14 +818,23 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
>
|
>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Space>
|
<Form.Item
|
||||||
<Form.Item
|
label={t("bodyshop.fields.md_ins_co.zip")}
|
||||||
label={t("bodyshop.fields.md_ins_co.zip")}
|
key={`${index}zip`}
|
||||||
key={`${index}zip`}
|
name={[field.name, "zip"]}
|
||||||
name={[field.name, "zip"]}
|
>
|
||||||
>
|
<Input />
|
||||||
<Input />
|
</Form.Item>
|
||||||
</Form.Item>
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.md_ins_co.private")}
|
||||||
|
key={`${index}private`}
|
||||||
|
name={[field.name, "private"]}
|
||||||
|
valuePropName="checked"
|
||||||
|
>
|
||||||
|
<Switch />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Space wrap>
|
||||||
<DeleteFilled
|
<DeleteFilled
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
remove(field.name);
|
remove(field.name);
|
||||||
@@ -1284,6 +1327,72 @@ export default function ShopInfoGeneral({ form }) {
|
|||||||
}}
|
}}
|
||||||
</Form.List>
|
</Form.List>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
|
<LayoutFormRow grow header={t("bodyshop.fields.md_parts_order_comment")}>
|
||||||
|
<Form.List name={["md_parts_order_comment"]}>
|
||||||
|
{(fields, { add, remove, move }) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<Form.Item key={field.key}>
|
||||||
|
<LayoutFormRow noDivider>
|
||||||
|
<Form.Item
|
||||||
|
label={t("general.labels.label")}
|
||||||
|
key={`${index}label`}
|
||||||
|
name={[field.name, "label"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("parts_orders.fields.comments")}
|
||||||
|
key={`${index}comment`}
|
||||||
|
name={[field.name, "comment"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true,
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Space wrap>
|
||||||
|
<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>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,7 +81,10 @@ export function SignInComponent({
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{signInError ? (
|
{signInError ? (
|
||||||
<AlertComponent type="error" message={signInError.message} />
|
<AlertComponent
|
||||||
|
type="error"
|
||||||
|
message={t(`users.errors.signinerror.${signInError.code}`)}
|
||||||
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<Button
|
<Button
|
||||||
className="login-btn"
|
className="login-btn"
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import AlertComponent from "../alert/alert.component";
|
|||||||
import DataLabel from "../data-label/data-label.component";
|
import DataLabel from "../data-label/data-label.component";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
import TechClockOffButton from "../tech-job-clock-out-button/tech-job-clock-out-button.component";
|
import TechClockOffButton from "../tech-job-clock-out-button/tech-job-clock-out-button.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
technician: selectTechnician,
|
technician: selectTechnician,
|
||||||
@@ -60,11 +61,9 @@ export function TechClockedInList({ technician }) {
|
|||||||
<Card
|
<Card
|
||||||
title={
|
title={
|
||||||
<Link to={`/tech/joblookup?selected=${ticket.job.id}`}>
|
<Link to={`/tech/joblookup?selected=${ticket.job.id}`}>
|
||||||
{`${ticket.job.ro_number || t("general.labels.na")} ${
|
{`${
|
||||||
ticket.job.ownr_fn || ""
|
ticket.job.ro_number || t("general.labels.na")
|
||||||
} ${ticket.job.ownr_ln || ""} ${
|
} ${OwnerNameDisplayFunction(ticket.job)}`}
|
||||||
ticket.job.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
actions={[
|
actions={[
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import { onlyUnique } from "../../utils/arrayHelper";
|
import { onlyUnique } from "../../utils/arrayHelper";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -108,9 +109,9 @@ export function TechLookupJobsList({ bodyshop }) {
|
|||||||
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
ellipsis: true,
|
ellipsis: true,
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<span>
|
||||||
record.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
}`}</span>
|
</span>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ export function TimeTicketModalComponent({
|
|||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
t("timetickets.validation.clockoffwithoutclockon")
|
t("timetickets.validation.clockoffwithoutclockon")
|
||||||
);
|
);
|
||||||
if (!value.isSameOrAfter(clockon))
|
if (value && !value.isSameOrAfter(clockon))
|
||||||
return Promise.reject(
|
return Promise.reject(
|
||||||
t("timetickets.validation.clockoffmustbeafterclockon")
|
t("timetickets.validation.clockoffmustbeafterclockon")
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import VehicleDetailUpdateJobsComponent from "../vehicle-detail-update-jobs/vehicle-detail-update-jobs.component";
|
import VehicleDetailUpdateJobsComponent from "../vehicle-detail-update-jobs/vehicle-detail-update-jobs.component";
|
||||||
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -34,9 +35,7 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
|
|||||||
key: "owner",
|
key: "owner",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Link to={`/manage/owners/${record.owner.id}`}>
|
<Link to={`/manage/owners/${record.owner.id}`}>
|
||||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ export default function VendorsFormComponent({
|
|||||||
formLoading,
|
formLoading,
|
||||||
handleDelete,
|
handleDelete,
|
||||||
responsibilityCenters,
|
responsibilityCenters,
|
||||||
|
selectedvendor,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
@@ -52,7 +53,12 @@ export default function VendorsFormComponent({
|
|||||||
>
|
>
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button type="danger" onClick={handleDelete} loading={formLoading}>
|
<Button
|
||||||
|
type="danger"
|
||||||
|
disabled={selectedvendor === "new"}
|
||||||
|
onClick={handleDelete}
|
||||||
|
loading={formLoading}
|
||||||
|
>
|
||||||
{t("general.actions.delete")}
|
{t("general.actions.delete")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
|||||||
@@ -39,30 +39,30 @@ function VendorsFormContainer({ refetch, bodyshop }) {
|
|||||||
const [insertvendor] = useMutation(INSERT_NEW_VENDOR);
|
const [insertvendor] = useMutation(INSERT_NEW_VENDOR);
|
||||||
const [deleteVendor] = useMutation(DELETE_VENDOR);
|
const [deleteVendor] = useMutation(DELETE_VENDOR);
|
||||||
|
|
||||||
const handleDelete = () => {
|
const handleDelete = async () => {
|
||||||
setFormLoading(true);
|
setFormLoading(true);
|
||||||
deleteVendor({
|
const result = await deleteVendor({
|
||||||
variables: { id: selectedvendor },
|
variables: { id: selectedvendor },
|
||||||
refetchQueries: ["QUERY_ALL_VENDORS"],
|
refetchQueries: ["QUERY_ALL_VENDORS"],
|
||||||
})
|
});
|
||||||
.then((r) => {
|
console.log(result);
|
||||||
notification["success"]({
|
if (result.errors) {
|
||||||
message: t("vendors.successes.deleted"),
|
notification["error"]({
|
||||||
});
|
message: t("vendors.errors.deleting"),
|
||||||
delete search.selectedvendor;
|
|
||||||
history.push({ search: queryString.stringify(search) });
|
|
||||||
if (refetch)
|
|
||||||
refetch().then((r) => {
|
|
||||||
form.resetFields();
|
|
||||||
});
|
|
||||||
setFormLoading(false);
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
notification["error"]({
|
|
||||||
message: t("vendors.errors.deleting"),
|
|
||||||
});
|
|
||||||
setFormLoading(false);
|
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
notification["success"]({
|
||||||
|
message: t("vendors.successes.deleted"),
|
||||||
|
});
|
||||||
|
delete search.selectedvendor;
|
||||||
|
history.push({ search: queryString.stringify(search) });
|
||||||
|
if (refetch)
|
||||||
|
refetch().then((r) => {
|
||||||
|
form.resetFields();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
setFormLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
@@ -139,6 +139,7 @@ function VendorsFormContainer({ refetch, bodyshop }) {
|
|||||||
formLoading={formLoading}
|
formLoading={formLoading}
|
||||||
handleDelete={handleDelete}
|
handleDelete={handleDelete}
|
||||||
responsibilityCenters={bodyshop.md_responsibility_centers || null}
|
responsibilityCenters={bodyshop.md_responsibility_centers || null}
|
||||||
|
selectedvendor={selectedvendor}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
t("vendors.labels.noneselected")
|
t("vendors.labels.noneselected")
|
||||||
|
|||||||
@@ -245,6 +245,27 @@ export const CANCEL_APPOINTMENT_BY_ID = gql`
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
export const CANCEL_APPOINTMENTS_BY_JOB_ID = gql`
|
||||||
|
mutation CANCEL_APPOINTMENTS_BY_JOB_ID($jobid: uuid!, $job: jobs_set_input) {
|
||||||
|
update_appointments(
|
||||||
|
where: { _and: { jobid: { _eq: $jobid }, arrived: { _eq: false } } }
|
||||||
|
_set: { canceled: true }
|
||||||
|
) {
|
||||||
|
returning {
|
||||||
|
id
|
||||||
|
canceled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
update_jobs_by_pk(pk_columns: { id: $jobid }, _set: $job) {
|
||||||
|
date_scheduled
|
||||||
|
id
|
||||||
|
scheduled_in
|
||||||
|
scheduled_completion
|
||||||
|
status
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const QUERY_APPOINTMENTS_BY_JOBID = gql`
|
export const QUERY_APPOINTMENTS_BY_JOBID = gql`
|
||||||
query QUERY_APPOINTMENTS_BY_JOBID($jobid: uuid!) {
|
query QUERY_APPOINTMENTS_BY_JOBID($jobid: uuid!) {
|
||||||
appointments(where: { jobid: { _eq: $jobid } }, order_by: { start: desc }) {
|
appointments(where: { jobid: { _eq: $jobid } }, order_by: { start: desc }) {
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ export const UPDATE_BILL_LINE = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
export const DELETE_BILL_LINE = gql`
|
||||||
|
mutation DELETE_BILL_LINE($id: uuid!) {
|
||||||
|
delete_billlines_by_pk(id: $id) {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export const INSERT_NEW_BILL_LINES = gql`
|
export const INSERT_NEW_BILL_LINES = gql`
|
||||||
mutation INSERT_NEW_BILL_LINES($billLines: [billlines_insert_input!]!) {
|
mutation INSERT_NEW_BILL_LINES($billLines: [billlines_insert_input!]!) {
|
||||||
|
|||||||
@@ -103,6 +103,9 @@ export const QUERY_BODYSHOP = gql`
|
|||||||
timezone
|
timezone
|
||||||
ss_configuration
|
ss_configuration
|
||||||
md_from_emails
|
md_from_emails
|
||||||
|
last_name_first
|
||||||
|
md_parts_order_comment
|
||||||
|
bill_allow_post_to_closed
|
||||||
employees {
|
employees {
|
||||||
user_email
|
user_email
|
||||||
id
|
id
|
||||||
@@ -203,6 +206,9 @@ export const UPDATE_SHOP = gql`
|
|||||||
timezone
|
timezone
|
||||||
ss_configuration
|
ss_configuration
|
||||||
md_from_emails
|
md_from_emails
|
||||||
|
last_name_first
|
||||||
|
md_parts_order_comment
|
||||||
|
bill_allow_post_to_closed
|
||||||
employees {
|
employees {
|
||||||
id
|
id
|
||||||
first_name
|
first_name
|
||||||
|
|||||||
@@ -146,6 +146,11 @@ export const QUERY_EXACT_JOB_IN_PRODUCTION = gql`
|
|||||||
employee_refinish
|
employee_refinish
|
||||||
employee_prep
|
employee_prep
|
||||||
employee_csr
|
employee_csr
|
||||||
|
joblines_status {
|
||||||
|
part_type
|
||||||
|
status
|
||||||
|
count
|
||||||
|
}
|
||||||
labhrs: joblines_aggregate(
|
labhrs: joblines_aggregate(
|
||||||
where: {
|
where: {
|
||||||
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
||||||
@@ -219,6 +224,11 @@ export const QUERY_EXACT_JOBS_IN_PRODUCTION = gql`
|
|||||||
employee_refinish
|
employee_refinish
|
||||||
employee_prep
|
employee_prep
|
||||||
employee_csr
|
employee_csr
|
||||||
|
joblines_status {
|
||||||
|
part_type
|
||||||
|
status
|
||||||
|
count
|
||||||
|
}
|
||||||
labhrs: joblines_aggregate(
|
labhrs: joblines_aggregate(
|
||||||
where: {
|
where: {
|
||||||
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
||||||
@@ -294,6 +304,11 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
|
|||||||
employee_prep
|
employee_prep
|
||||||
employee_csr
|
employee_csr
|
||||||
suspended
|
suspended
|
||||||
|
joblines_status {
|
||||||
|
part_type
|
||||||
|
status
|
||||||
|
count
|
||||||
|
}
|
||||||
labhrs: joblines_aggregate(
|
labhrs: joblines_aggregate(
|
||||||
where: {
|
where: {
|
||||||
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
_and: [{ mod_lbr_ty: { _neq: "LAR" } }, { removed: { _eq: false } }]
|
||||||
@@ -596,6 +611,8 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
ownerid
|
ownerid
|
||||||
ded_note
|
ded_note
|
||||||
materials
|
materials
|
||||||
|
auto_add_ats
|
||||||
|
rate_ats
|
||||||
owner {
|
owner {
|
||||||
id
|
id
|
||||||
ownr_fn
|
ownr_fn
|
||||||
@@ -706,20 +723,6 @@ export const GET_JOB_BY_PK = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parts_order_lines {
|
|
||||||
id
|
|
||||||
parts_order {
|
|
||||||
id
|
|
||||||
order_number
|
|
||||||
comments
|
|
||||||
order_date
|
|
||||||
user_email
|
|
||||||
vendor {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
payments {
|
payments {
|
||||||
id
|
id
|
||||||
@@ -2099,3 +2102,23 @@ export const DELETE_RELATED_RO = gql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
export const GET_JOB_LINE_ORDERS = gql`
|
||||||
|
query GET_JOB_LINE_ORDERS($joblineid: uuid!) {
|
||||||
|
parts_order_lines(where: { job_line_id: { _eq: $joblineid } }) {
|
||||||
|
id
|
||||||
|
act_price
|
||||||
|
parts_order {
|
||||||
|
id
|
||||||
|
order_date
|
||||||
|
order_number
|
||||||
|
orderedby
|
||||||
|
return
|
||||||
|
comments
|
||||||
|
vendor {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import * as Sentry from "@sentry/react";
|
|||||||
import "antd/dist/antd.less";
|
import "antd/dist/antd.less";
|
||||||
import Dinero from "dinero.js";
|
import Dinero from "dinero.js";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ReactDOM from "react-dom";
|
import { createRoot } from "react-dom/client";
|
||||||
import { Provider } from "react-redux";
|
import { Provider } from "react-redux";
|
||||||
import { BrowserRouter } from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import { PersistGate } from "redux-persist/integration/react";
|
import { PersistGate } from "redux-persist/integration/react";
|
||||||
@@ -39,7 +39,9 @@ if (process.env.NODE_ENV !== "development") {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.render(
|
const container = document.getElementById("root");
|
||||||
|
const root = createRoot(container); // createRoot(container!) if you use TypeScript
|
||||||
|
root.render(
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<PersistGate
|
<PersistGate
|
||||||
@@ -49,48 +51,7 @@ ReactDOM.render(
|
|||||||
<AppContainer />
|
<AppContainer />
|
||||||
</PersistGate>
|
</PersistGate>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
</Provider>,
|
</Provider>
|
||||||
document.getElementById("root")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// const onServiceWorkerUpdate = (registration) => {
|
|
||||||
// console.log("onServiceWorkerUpdate", registration);
|
|
||||||
|
|
||||||
// const btn = (
|
|
||||||
// <Space flex>
|
|
||||||
// <Button
|
|
||||||
// onClick={async () => {
|
|
||||||
// window.open("https://imex-online.noticeable.news/", "_blank");
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// {i18n.t("general.actions.viewreleasenotes")}
|
|
||||||
// </Button>
|
|
||||||
// <Button
|
|
||||||
// type="primary"
|
|
||||||
// onClick={async () => {
|
|
||||||
// if (registration && registration.waiting) {
|
|
||||||
// await registration.unregister();
|
|
||||||
// // Makes Workbox call skipWaiting()
|
|
||||||
// registration.waiting.postMessage({ type: "SKIP_WAITING" });
|
|
||||||
// // Once the service worker is unregistered, we can reload the page to let
|
|
||||||
// // the browser download a fresh copy of our app (invalidating the cache)
|
|
||||||
// window.location.reload();
|
|
||||||
// }
|
|
||||||
// }}
|
|
||||||
// >
|
|
||||||
// {i18n.t("general.actions.refresh")}
|
|
||||||
// </Button>
|
|
||||||
// </Space>
|
|
||||||
// );
|
|
||||||
// notification.open({
|
|
||||||
// icon: <AlertOutlined />,
|
|
||||||
// message: i18n.t("general.messages.newversiontitle"),
|
|
||||||
// description: i18n.t("general.messages.newversionmessage"),
|
|
||||||
// duration: 0,
|
|
||||||
// btn,
|
|
||||||
// key: "updateavailable",
|
|
||||||
// });
|
|
||||||
// };
|
|
||||||
|
|
||||||
// serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate });
|
|
||||||
reportWebVitals();
|
reportWebVitals();
|
||||||
|
|||||||
@@ -5,16 +5,19 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import AccountingPayablesTable from "../../components/accounting-payables-table/accounting-payables-table.component";
|
import AccountingPayablesTable from "../../components/accounting-payables-table/accounting-payables-table.component";
|
||||||
import AlertComponent from "../../components/alert/alert.component";
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
|
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||||
import { QUERY_BILLS_FOR_EXPORT } from "../../graphql/accounting.queries";
|
import { QUERY_BILLS_FOR_EXPORT } from "../../graphql/accounting.queries";
|
||||||
import {
|
import {
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
|
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
partnerVersion: selectPartnerVersion,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
@@ -26,6 +29,7 @@ export function AccountingPayablesContainer({
|
|||||||
bodyshop,
|
bodyshop,
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
|
partnerVersion,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -38,7 +42,8 @@ export function AccountingPayablesContainer({
|
|||||||
label: t("titles.bc.accounting-payables"),
|
label: t("titles.bc.accounting-payables"),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
checkPartnerStatus(bodyshop, true);
|
||||||
|
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||||
|
|
||||||
const { loading, error, data } = useQuery(QUERY_BILLS_FOR_EXPORT, {
|
const { loading, error, data } = useQuery(QUERY_BILLS_FOR_EXPORT, {
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -47,9 +52,24 @@ export function AccountingPayablesContainer({
|
|||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
|
|
||||||
|
const noPath =
|
||||||
|
!partnerVersion?.qbpath &&
|
||||||
|
!(
|
||||||
|
bodyshop &&
|
||||||
|
(bodyshop.cdk_dealerid ||
|
||||||
|
bodyshop.pbs_serialnumber ||
|
||||||
|
bodyshop.accountingconfig.qbo)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<RbacWrapper action="accounting:payables">
|
<RbacWrapper action="accounting:payables">
|
||||||
|
{noPath && (
|
||||||
|
<AlertComponent
|
||||||
|
type="error"
|
||||||
|
message={t("general.messages.noacctfilepath")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<AccountingPayablesTable
|
<AccountingPayablesTable
|
||||||
loadaing={loading}
|
loadaing={loading}
|
||||||
bills={data ? data.bills : []}
|
bills={data ? data.bills : []}
|
||||||
|
|||||||
@@ -12,9 +12,12 @@ import {
|
|||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||||
|
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
|
||||||
|
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
partnerVersion: selectPartnerVersion,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
@@ -25,6 +28,7 @@ export function AccountingPaymentsContainer({
|
|||||||
bodyshop,
|
bodyshop,
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
|
partnerVersion,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -37,7 +41,8 @@ export function AccountingPaymentsContainer({
|
|||||||
label: t("titles.bc.accounting-payments"),
|
label: t("titles.bc.accounting-payments"),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
checkPartnerStatus(bodyshop, true);
|
||||||
|
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||||
|
|
||||||
const { loading, error, data } = useQuery(QUERY_PAYMENTS_FOR_EXPORT, {
|
const { loading, error, data } = useQuery(QUERY_PAYMENTS_FOR_EXPORT, {
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -45,10 +50,23 @@ export function AccountingPaymentsContainer({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
|
const noPath =
|
||||||
|
!partnerVersion?.qbpath &&
|
||||||
|
!(
|
||||||
|
bodyshop &&
|
||||||
|
(bodyshop.cdk_dealerid ||
|
||||||
|
bodyshop.pbs_serialnumber ||
|
||||||
|
bodyshop.accountingconfig.qbo)
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<RbacWrapper action="accounting:payments">
|
<RbacWrapper action="accounting:payments">
|
||||||
|
{noPath && (
|
||||||
|
<AlertComponent
|
||||||
|
type="error"
|
||||||
|
message={t("general.messages.noacctfilepath")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<AccountingPaymentsTable
|
<AccountingPaymentsTable
|
||||||
loadaing={loading}
|
loadaing={loading}
|
||||||
payments={data ? data.payments : []}
|
payments={data ? data.payments : []}
|
||||||
|
|||||||
@@ -12,9 +12,12 @@ import {
|
|||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||||
|
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
|
||||||
|
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
partnerVersion: selectPartnerVersion,
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
@@ -25,6 +28,7 @@ export function AccountingReceivablesContainer({
|
|||||||
bodyshop,
|
bodyshop,
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
|
partnerVersion,
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -37,7 +41,8 @@ export function AccountingReceivablesContainer({
|
|||||||
label: t("titles.bc.accounting-receivables"),
|
label: t("titles.bc.accounting-receivables"),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
checkPartnerStatus(bodyshop, true);
|
||||||
|
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||||
|
|
||||||
const { loading, error, data } = useQuery(QUERY_JOBS_FOR_EXPORT, {
|
const { loading, error, data } = useQuery(QUERY_JOBS_FOR_EXPORT, {
|
||||||
variables: {
|
variables: {
|
||||||
@@ -48,9 +53,25 @@ export function AccountingReceivablesContainer({
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
|
|
||||||
|
const noPath =
|
||||||
|
!partnerVersion?.qbpath &&
|
||||||
|
!(
|
||||||
|
bodyshop &&
|
||||||
|
(bodyshop.cdk_dealerid ||
|
||||||
|
bodyshop.pbs_serialnumber ||
|
||||||
|
bodyshop.accountingconfig.qbo)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<RbacWrapper action="accounting:receivables">
|
<RbacWrapper action="accounting:receivables">
|
||||||
|
{noPath && (
|
||||||
|
<AlertComponent
|
||||||
|
type="error"
|
||||||
|
message={t("general.messages.noacctfilepath")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<AccountingReceivablesTable
|
<AccountingReceivablesTable
|
||||||
loadaing={loading}
|
loadaing={loading}
|
||||||
jobs={data ? data.jobs : []}
|
jobs={data ? data.jobs : []}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { SyncOutlined } from "@ant-design/icons";
|
import { SyncOutlined, EditFilled } from "@ant-design/icons";
|
||||||
import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd";
|
import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
@@ -141,7 +141,9 @@ export function BillsListPage({
|
|||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
<Link to={`/manage/bills?billid=${record.id}`}>
|
<Link to={`/manage/bills?billid=${record.id}`}>
|
||||||
<Button>{t("bills.actions.edit")}</Button>
|
<Button>
|
||||||
|
<EditFilled />
|
||||||
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
{
|
{
|
||||||
// <Button
|
// <Button
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import {
|
|||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -143,9 +144,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
|||||||
<Link to={`/manage/jobs/${data && data.jobs_by_pk.id}`}>{`${
|
<Link to={`/manage/jobs/${data && data.jobs_by_pk.id}`}>{`${
|
||||||
data && data.jobs_by_pk && data.jobs_by_pk.ro_number
|
data && data.jobs_by_pk && data.jobs_by_pk.ro_number
|
||||||
}`}</Link>
|
}`}</Link>
|
||||||
{` | ${data.jobs_by_pk.ownr_fn || ""} ${
|
{` | ${OwnerNameDisplayFunction(data.jobs_by_pk)} | ${
|
||||||
data.jobs_by_pk.ownr_ln || ""
|
|
||||||
} ${data.jobs_by_pk.ownr_co_nm || ""} | ${
|
|
||||||
data.jobs_by_pk.v_model_yr || ""
|
data.jobs_by_pk.v_model_yr || ""
|
||||||
} ${data.jobs_by_pk.v_make_desc || ""} ${
|
} ${data.jobs_by_pk.v_make_desc || ""} ${
|
||||||
data.jobs_by_pk.v_model_desc || ""
|
data.jobs_by_pk.v_model_desc || ""
|
||||||
|
|||||||
@@ -3,12 +3,19 @@ import React, { useEffect } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
import JobsAvailableTableContainer from "../../components/jobs-available-table/jobs-available-table.container";
|
import JobsAvailableTableContainer from "../../components/jobs-available-table/jobs-available-table.container";
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||||
import {
|
import {
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
} from "../../redux/application/application.actions";
|
} from "../../redux/application/application.actions";
|
||||||
|
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||||
|
|
||||||
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
partnerVersion: selectPartnerVersion,
|
||||||
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||||
@@ -16,6 +23,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function JobsAvailablePageContainer({
|
export function JobsAvailablePageContainer({
|
||||||
|
partnerVersion,
|
||||||
setBreadcrumbs,
|
setBreadcrumbs,
|
||||||
setSelectedHeader,
|
setSelectedHeader,
|
||||||
}) {
|
}) {
|
||||||
@@ -40,9 +48,18 @@ export function JobsAvailablePageContainer({
|
|||||||
</Link>
|
</Link>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
{!partnerVersion && (
|
||||||
|
<AlertComponent
|
||||||
|
type="warning"
|
||||||
|
message={t("general.messages.partnernotrunning")}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<JobsAvailableTableContainer />
|
<JobsAvailableTableContainer />
|
||||||
</div>
|
</div>
|
||||||
</RbacWrapper>
|
</RbacWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(null, mapDispatchToProps)(JobsAvailablePageContainer);
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(JobsAvailablePageContainer);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import AlertComponent from "../../components/alert/alert.component";
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
|
import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
|
||||||
import NotFound from "../../components/not-found/not-found.component";
|
import NotFound from "../../components/not-found/not-found.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||||
import { GET_JOB_BY_PK, UPDATE_JOB } from "../../graphql/jobs.queries";
|
import { GET_JOB_BY_PK, UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||||
import {
|
import {
|
||||||
@@ -78,11 +79,10 @@ function JobsDetailPageContainer({
|
|||||||
CreateRecentItem(
|
CreateRecentItem(
|
||||||
jobId,
|
jobId,
|
||||||
"job",
|
"job",
|
||||||
`${data.jobs_by_pk.ro_number || t("general.labels.na")} | ${
|
|
||||||
data.jobs_by_pk.ownr_fn || ""
|
`${
|
||||||
} ${data.jobs_by_pk.ownr_ln || ""} ${
|
data.jobs_by_pk.ro_number || t("general.labels.na")
|
||||||
data.jobs_by_pk.ownr_co_nm || ""
|
} | ${OwnerNameDisplayFunction(data.jobs_by_pk)}`,
|
||||||
}`,
|
|
||||||
`/manage/jobs/${jobId}`
|
`/manage/jobs/${jobId}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
import { CreateRecentItem } from "../../utils/create-recent-item";
|
import { CreateRecentItem } from "../../utils/create-recent-item";
|
||||||
import OwnersDetailComponent from "./owners-detail.page.component";
|
import OwnersDetailComponent from "./owners-detail.page.component";
|
||||||
import NotFound from "../../components/not-found/not-found.component";
|
import NotFound from "../../components/not-found/not-found.component";
|
||||||
|
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||||
@@ -38,11 +39,7 @@ export function OwnersDetailContainer({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
document.title = t("titles.owners-detail", {
|
document.title = t("titles.owners-detail", {
|
||||||
name: data
|
name: data ? OwnerNameDisplayFunction(data.owners_by_pk) : "",
|
||||||
? `${(data.owners_by_pk && data.owners_by_pk.ownr_fn) || ""} ${
|
|
||||||
(data.owners_by_pk && data.owners_by_pk.ownr_ln) || ""
|
|
||||||
} ${(data.owners_by_pk && data.owners_by_pk.ownr_co_nm) || ""}`
|
|
||||||
: "",
|
|
||||||
});
|
});
|
||||||
setSelectedHeader("owners");
|
setSelectedHeader("owners");
|
||||||
setBreadcrumbs([
|
setBreadcrumbs([
|
||||||
@@ -50,11 +47,7 @@ export function OwnersDetailContainer({
|
|||||||
{
|
{
|
||||||
link: `/manage/owners/${ownerId}`,
|
link: `/manage/owners/${ownerId}`,
|
||||||
label: t("titles.bc.owner-detail", {
|
label: t("titles.bc.owner-detail", {
|
||||||
name: data
|
name: data ? OwnerNameDisplayFunction(data.owners_by_pk) : "",
|
||||||
? `${(data.owners_by_pk && data.owners_by_pk.ownr_fn) || ""} ${
|
|
||||||
(data.owners_by_pk && data.owners_by_pk.ownr_ln) || ""
|
|
||||||
} ${(data.owners_by_pk && data.owners_by_pk.ownr_co_nm) || ""}`
|
|
||||||
: "",
|
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
@@ -64,9 +57,7 @@ export function OwnersDetailContainer({
|
|||||||
CreateRecentItem(
|
CreateRecentItem(
|
||||||
ownerId,
|
ownerId,
|
||||||
"owner",
|
"owner",
|
||||||
`${data.owners_by_pk.ownr_fn || ""} ${
|
OwnerNameDisplayFunction(data.owners_by_pk),
|
||||||
data.owners_by_pk.ownr_ln || ""
|
|
||||||
} ${data.owners_by_pk.ownr_co_nm || ""}`,
|
|
||||||
`/manage/owners/${ownerId}`
|
`/manage/owners/${ownerId}`
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { alphaSort } from "../../utils/sorters";
|
|||||||
import { useLocation } from "react-router-dom";
|
import { useLocation } from "react-router-dom";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -120,14 +121,12 @@ export function PartsQueuePageComponent({ bodyshop }) {
|
|||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.ownerid ? (
|
return record.ownerid ? (
|
||||||
<Link to={"/manage/owners/" + record.ownerid}>
|
<Link to={"/manage/owners/" + record.ownerid}>
|
||||||
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
record.ownr_co_nm || ""
|
|
||||||
}`}
|
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span>{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
|
<span>
|
||||||
record.ownr_co_nm || ""
|
<OwnerNameDisplay ownerObject={record} />
|
||||||
}`}</span>
|
</span>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
confirmPasswordReset,
|
confirmPasswordReset,
|
||||||
signInWithEmailAndPassword,
|
signInWithEmailAndPassword,
|
||||||
signOut,
|
signOut,
|
||||||
|
sendPasswordResetEmail,
|
||||||
} from "firebase/auth";
|
} from "firebase/auth";
|
||||||
import { doc } from "firebase/firestore";
|
import { doc } from "firebase/firestore";
|
||||||
import i18next from "i18next";
|
import i18next from "i18next";
|
||||||
@@ -223,16 +224,16 @@ export function* signInSuccessSaga({ payload }) {
|
|||||||
export function* onSendPasswordResetStart() {
|
export function* onSendPasswordResetStart() {
|
||||||
yield takeLatest(
|
yield takeLatest(
|
||||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START,
|
||||||
sendPasswordResetEmail
|
sendPasswordResetEmailSaga
|
||||||
);
|
);
|
||||||
yield takeLatest(
|
yield takeLatest(
|
||||||
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
UserActionTypes.SEND_PASSWORD_RESET_EMAIL_START_AGAIN,
|
||||||
sendPasswordResetEmail
|
sendPasswordResetEmailSaga
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export function* sendPasswordResetEmail({ payload }) {
|
export function* sendPasswordResetEmailSaga({ payload }) {
|
||||||
try {
|
try {
|
||||||
yield sendPasswordResetEmail(payload, {
|
yield sendPasswordResetEmail(auth, payload, {
|
||||||
url: "https://imex.online/passwordreset",
|
url: "https://imex.online/passwordreset",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -269,7 +270,7 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
|
|||||||
const userEmail = yield select((state) => state.user.currentUser.email);
|
const userEmail = yield select((state) => state.user.currentUser.email);
|
||||||
try {
|
try {
|
||||||
console.log("Setting shop timezone.");
|
console.log("Setting shop timezone.");
|
||||||
// moment.tz.setDefault(payload.timezone);
|
// moment.tz.setDefault(payload.timezone);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -157,6 +157,7 @@
|
|||||||
"federal_tax_rate": "Federal Tax Rate",
|
"federal_tax_rate": "Federal Tax Rate",
|
||||||
"invoice_number": "Invoice Number",
|
"invoice_number": "Invoice Number",
|
||||||
"is_credit_memo": "Credit Memo?",
|
"is_credit_memo": "Credit Memo?",
|
||||||
|
"is_credit_memo_short": "CM",
|
||||||
"local_tax_rate": "Local Tax Rate",
|
"local_tax_rate": "Local Tax Rate",
|
||||||
"ro_number": "RO Number",
|
"ro_number": "RO Number",
|
||||||
"state_tax_rate": "Provincial/State Tax Rate",
|
"state_tax_rate": "Provincial/State Tax Rate",
|
||||||
@@ -232,6 +233,7 @@
|
|||||||
},
|
},
|
||||||
"appt_length": "Default Appointment Length",
|
"appt_length": "Default Appointment Length",
|
||||||
"attach_pdf_to_email": "Attach PDF copy to sent emails?",
|
"attach_pdf_to_email": "Attach PDF copy to sent emails?",
|
||||||
|
"bill_allow_post_to_closed": "Allow Bills to be posted to Closed Jobs",
|
||||||
"bill_federal_tax_rate": "Bills - Federal Tax Rate %",
|
"bill_federal_tax_rate": "Bills - Federal Tax Rate %",
|
||||||
"bill_local_tax_rate": "Bill - Provincial/State Tax Rate %",
|
"bill_local_tax_rate": "Bill - Provincial/State Tax Rate %",
|
||||||
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
|
"bill_state_tax_rate": "Bill - Provincial/State Tax Rate %",
|
||||||
@@ -274,6 +276,7 @@
|
|||||||
"mapa": "Job Costing - Paint Materials Hourly Cost Rate",
|
"mapa": "Job Costing - Paint Materials Hourly Cost Rate",
|
||||||
"mash": "Job Costing - Shop Materials Hourly Cost Rate"
|
"mash": "Job Costing - Shop Materials Hourly Cost Rate"
|
||||||
},
|
},
|
||||||
|
"last_name_first": "Display Owner Info as <Last>, <First>",
|
||||||
"lastnumberworkingdays": "Scoreboard - Last Number of Working Days",
|
"lastnumberworkingdays": "Scoreboard - Last Number of Working Days",
|
||||||
"logo_img_footer_margin": "Footer Margin (px)",
|
"logo_img_footer_margin": "Footer Margin (px)",
|
||||||
"logo_img_header_margin": "Header Margin (px)",
|
"logo_img_header_margin": "Header Margin (px)",
|
||||||
@@ -293,12 +296,14 @@
|
|||||||
"md_ins_co": {
|
"md_ins_co": {
|
||||||
"city": "City",
|
"city": "City",
|
||||||
"name": "Insurance Company Name",
|
"name": "Insurance Company Name",
|
||||||
|
"private": "Private",
|
||||||
"state": "Province/State",
|
"state": "Province/State",
|
||||||
"street1": "Street 1",
|
"street1": "Street 1",
|
||||||
"street2": "Street 2",
|
"street2": "Street 2",
|
||||||
"zip": "Zip/Postal Code"
|
"zip": "Zip/Postal Code"
|
||||||
},
|
},
|
||||||
"md_jobline_presets": "Jobline Presets",
|
"md_jobline_presets": "Jobline Presets",
|
||||||
|
"md_parts_order_comment": "Parts Orders Comments",
|
||||||
"md_payment_types": "Payment Types",
|
"md_payment_types": "Payment Types",
|
||||||
"md_referral_sources": "Referral Sources",
|
"md_referral_sources": "Referral Sources",
|
||||||
"messaginglabel": "Messaging Preset Label",
|
"messaginglabel": "Messaging Preset Label",
|
||||||
@@ -539,6 +544,8 @@
|
|||||||
"partslocations": "Parts Locations",
|
"partslocations": "Parts Locations",
|
||||||
"printlater": "Print Later",
|
"printlater": "Print Later",
|
||||||
"qbo": "Use QuickBooks Online?",
|
"qbo": "Use QuickBooks Online?",
|
||||||
|
"qbo_departmentid": "QBO Department ID",
|
||||||
|
"qbo_usa": "QBO USA Compatibility",
|
||||||
"rbac": "Role Based Access Control",
|
"rbac": "Role Based Access Control",
|
||||||
"responsibilitycenters": {
|
"responsibilitycenters": {
|
||||||
"costs": "Cost Centers",
|
"costs": "Cost Centers",
|
||||||
@@ -1079,7 +1086,7 @@
|
|||||||
"mod_lbr_ty": "Labor Type",
|
"mod_lbr_ty": "Labor Type",
|
||||||
"notes": "Notes",
|
"notes": "Notes",
|
||||||
"oem_partno": "OEM Part #",
|
"oem_partno": "OEM Part #",
|
||||||
"op_code_desc": "Operation Code Description",
|
"op_code_desc": "Op Code Description",
|
||||||
"part_qty": "Qty.",
|
"part_qty": "Qty.",
|
||||||
"part_type": "Part Type",
|
"part_type": "Part Type",
|
||||||
"part_types": {
|
"part_types": {
|
||||||
@@ -1239,6 +1246,7 @@
|
|||||||
"08": "Left Rear Side",
|
"08": "Left Rear Side",
|
||||||
"09": "Left Side"
|
"09": "Left Side"
|
||||||
},
|
},
|
||||||
|
"auto_add_ats": "Automatically Add/Update ATS",
|
||||||
"ca_bc_pvrt": "PVRT",
|
"ca_bc_pvrt": "PVRT",
|
||||||
"ca_customer_gst": "Customer Portion of GST",
|
"ca_customer_gst": "Customer Portion of GST",
|
||||||
"ca_gst_registrant": "GST Registrant",
|
"ca_gst_registrant": "GST Registrant",
|
||||||
@@ -1386,6 +1394,7 @@
|
|||||||
"production_vars": {
|
"production_vars": {
|
||||||
"note": "Production Note"
|
"note": "Production Note"
|
||||||
},
|
},
|
||||||
|
"rate_ats": "ATS Rate",
|
||||||
"rate_la1": "LA1",
|
"rate_la1": "LA1",
|
||||||
"rate_la2": "LA2",
|
"rate_la2": "LA2",
|
||||||
"rate_la3": "LA3",
|
"rate_la3": "LA3",
|
||||||
@@ -1563,6 +1572,7 @@
|
|||||||
"override_header": "Override estimate header on import?",
|
"override_header": "Override estimate header on import?",
|
||||||
"ownerassociation": "Owner Association",
|
"ownerassociation": "Owner Association",
|
||||||
"parts": "Parts",
|
"parts": "Parts",
|
||||||
|
"parts_received": "Parts Rec.",
|
||||||
"parts_tax_rates": "Parts Tax rates",
|
"parts_tax_rates": "Parts Tax rates",
|
||||||
"partsfilter": "Parts Only",
|
"partsfilter": "Parts Only",
|
||||||
"partssubletstotal": "Parts & Sublets Total",
|
"partssubletstotal": "Parts & Sublets Total",
|
||||||
@@ -1755,6 +1765,7 @@
|
|||||||
},
|
},
|
||||||
"jobsactions": {
|
"jobsactions": {
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
|
"cancelallappointments": "Cancel all appointments",
|
||||||
"closejob": "Close Job",
|
"closejob": "Close Job",
|
||||||
"deletejob": "Delete Job",
|
"deletejob": "Delete Job",
|
||||||
"duplicate": "Duplicate this Job",
|
"duplicate": "Duplicate this Job",
|
||||||
@@ -1842,6 +1853,11 @@
|
|||||||
"updated": "Note updated successfully."
|
"updated": "Note updated successfully."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"owner": {
|
||||||
|
"labels": {
|
||||||
|
"noownerinfo": "No owner information."
|
||||||
|
}
|
||||||
|
},
|
||||||
"owners": {
|
"owners": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"update": "Update Selected Records"
|
"update": "Update Selected Records"
|
||||||
@@ -1930,6 +1946,7 @@
|
|||||||
"email": "Send by Email",
|
"email": "Send by Email",
|
||||||
"inthisorder": "Parts in this Order",
|
"inthisorder": "Parts in this Order",
|
||||||
"newpartsorder": "New Parts Order",
|
"newpartsorder": "New Parts Order",
|
||||||
|
"notyetordered": "This part has not yet been ordered.",
|
||||||
"oec": "Order via OEC",
|
"oec": "Order via OEC",
|
||||||
"orderhistory": "Order History",
|
"orderhistory": "Order History",
|
||||||
"parts_orders": "Parts Orders",
|
"parts_orders": "Parts Orders",
|
||||||
@@ -2078,6 +2095,7 @@
|
|||||||
"labels": "Labels",
|
"labels": "Labels",
|
||||||
"position": "Starting Position"
|
"position": "Starting Position"
|
||||||
},
|
},
|
||||||
|
"lag_time_ro": "Lag Time",
|
||||||
"mechanical_authorization": "Mechanical Authorization",
|
"mechanical_authorization": "Mechanical Authorization",
|
||||||
"mpi_animal_checklist": "MPI - Animal Checklist",
|
"mpi_animal_checklist": "MPI - Animal Checklist",
|
||||||
"mpi_eglass_auth": "MPI - eGlass Auth",
|
"mpi_eglass_auth": "MPI - eGlass Auth",
|
||||||
@@ -2170,6 +2188,12 @@
|
|||||||
"ats": "Alternative Transportation",
|
"ats": "Alternative Transportation",
|
||||||
"bodyhours": "B",
|
"bodyhours": "B",
|
||||||
"bodypriority": "B/P",
|
"bodypriority": "B/P",
|
||||||
|
"bodyshop": {
|
||||||
|
"labels": {
|
||||||
|
"qbo_departmentid": "QBO Department ID",
|
||||||
|
"qbo_usa": "QBO USA"
|
||||||
|
}
|
||||||
|
},
|
||||||
"cardsettings": "Card Settings",
|
"cardsettings": "Card Settings",
|
||||||
"clm_no": "Claim Number",
|
"clm_no": "Claim Number",
|
||||||
"comment": "Comment",
|
"comment": "Comment",
|
||||||
@@ -2187,6 +2211,7 @@
|
|||||||
"refinishhours": "R",
|
"refinishhours": "R",
|
||||||
"scheduled_completion": "Scheduled Completion",
|
"scheduled_completion": "Scheduled Completion",
|
||||||
"selectview": "Select a View",
|
"selectview": "Select a View",
|
||||||
|
"stickyheader": "Sticky Header (BETA)",
|
||||||
"sublets": "Sublets",
|
"sublets": "Sublets",
|
||||||
"totalhours": "Total Hrs ",
|
"totalhours": "Total Hrs ",
|
||||||
"touchtime": "T/T",
|
"touchtime": "T/T",
|
||||||
@@ -2553,6 +2578,14 @@
|
|||||||
"passwordchanged": "Password changed successfully. "
|
"passwordchanged": "Password changed successfully. "
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"users": {
|
||||||
|
"errors": {
|
||||||
|
"signinerror": {
|
||||||
|
"auth/user-not-found": "A user with this email does not exist.",
|
||||||
|
"auth/wrong-password": "The email and password combination you provided is incorrect."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"vehicles": {
|
"vehicles": {
|
||||||
"errors": {
|
"errors": {
|
||||||
"noaccess": "The vehicle does not exist or you do not have access to it.",
|
"noaccess": "The vehicle does not exist or you do not have access to it.",
|
||||||
|
|||||||
@@ -157,6 +157,7 @@
|
|||||||
"federal_tax_rate": "",
|
"federal_tax_rate": "",
|
||||||
"invoice_number": "",
|
"invoice_number": "",
|
||||||
"is_credit_memo": "",
|
"is_credit_memo": "",
|
||||||
|
"is_credit_memo_short": "",
|
||||||
"local_tax_rate": "",
|
"local_tax_rate": "",
|
||||||
"ro_number": "",
|
"ro_number": "",
|
||||||
"state_tax_rate": "",
|
"state_tax_rate": "",
|
||||||
@@ -232,6 +233,7 @@
|
|||||||
},
|
},
|
||||||
"appt_length": "",
|
"appt_length": "",
|
||||||
"attach_pdf_to_email": "",
|
"attach_pdf_to_email": "",
|
||||||
|
"bill_allow_post_to_closed": "",
|
||||||
"bill_federal_tax_rate": "",
|
"bill_federal_tax_rate": "",
|
||||||
"bill_local_tax_rate": "",
|
"bill_local_tax_rate": "",
|
||||||
"bill_state_tax_rate": "",
|
"bill_state_tax_rate": "",
|
||||||
@@ -274,6 +276,7 @@
|
|||||||
"mapa": "",
|
"mapa": "",
|
||||||
"mash": ""
|
"mash": ""
|
||||||
},
|
},
|
||||||
|
"last_name_first": "",
|
||||||
"lastnumberworkingdays": "",
|
"lastnumberworkingdays": "",
|
||||||
"logo_img_footer_margin": "",
|
"logo_img_footer_margin": "",
|
||||||
"logo_img_header_margin": "",
|
"logo_img_header_margin": "",
|
||||||
@@ -293,12 +296,14 @@
|
|||||||
"md_ins_co": {
|
"md_ins_co": {
|
||||||
"city": "",
|
"city": "",
|
||||||
"name": "",
|
"name": "",
|
||||||
|
"private": "",
|
||||||
"state": "",
|
"state": "",
|
||||||
"street1": "",
|
"street1": "",
|
||||||
"street2": "",
|
"street2": "",
|
||||||
"zip": ""
|
"zip": ""
|
||||||
},
|
},
|
||||||
"md_jobline_presets": "",
|
"md_jobline_presets": "",
|
||||||
|
"md_parts_order_comment": "",
|
||||||
"md_payment_types": "",
|
"md_payment_types": "",
|
||||||
"md_referral_sources": "",
|
"md_referral_sources": "",
|
||||||
"messaginglabel": "",
|
"messaginglabel": "",
|
||||||
@@ -539,6 +544,8 @@
|
|||||||
"partslocations": "",
|
"partslocations": "",
|
||||||
"printlater": "",
|
"printlater": "",
|
||||||
"qbo": "",
|
"qbo": "",
|
||||||
|
"qbo_departmentid": "",
|
||||||
|
"qbo_usa": "",
|
||||||
"rbac": "",
|
"rbac": "",
|
||||||
"responsibilitycenters": {
|
"responsibilitycenters": {
|
||||||
"costs": "",
|
"costs": "",
|
||||||
@@ -1239,6 +1246,7 @@
|
|||||||
"08": "",
|
"08": "",
|
||||||
"09": ""
|
"09": ""
|
||||||
},
|
},
|
||||||
|
"auto_add_ats": "",
|
||||||
"ca_bc_pvrt": "",
|
"ca_bc_pvrt": "",
|
||||||
"ca_customer_gst": "",
|
"ca_customer_gst": "",
|
||||||
"ca_gst_registrant": "",
|
"ca_gst_registrant": "",
|
||||||
@@ -1386,6 +1394,7 @@
|
|||||||
"production_vars": {
|
"production_vars": {
|
||||||
"note": ""
|
"note": ""
|
||||||
},
|
},
|
||||||
|
"rate_ats": "",
|
||||||
"rate_la1": "Tarifa LA1",
|
"rate_la1": "Tarifa LA1",
|
||||||
"rate_la2": "Tarifa LA2",
|
"rate_la2": "Tarifa LA2",
|
||||||
"rate_la3": "Tarifa LA3",
|
"rate_la3": "Tarifa LA3",
|
||||||
@@ -1563,6 +1572,7 @@
|
|||||||
"override_header": "¿Anular encabezado estimado al importar?",
|
"override_header": "¿Anular encabezado estimado al importar?",
|
||||||
"ownerassociation": "",
|
"ownerassociation": "",
|
||||||
"parts": "Partes",
|
"parts": "Partes",
|
||||||
|
"parts_received": "",
|
||||||
"parts_tax_rates": "",
|
"parts_tax_rates": "",
|
||||||
"partsfilter": "",
|
"partsfilter": "",
|
||||||
"partssubletstotal": "",
|
"partssubletstotal": "",
|
||||||
@@ -1755,6 +1765,7 @@
|
|||||||
},
|
},
|
||||||
"jobsactions": {
|
"jobsactions": {
|
||||||
"admin": "",
|
"admin": "",
|
||||||
|
"cancelallappointments": "",
|
||||||
"closejob": "",
|
"closejob": "",
|
||||||
"deletejob": "",
|
"deletejob": "",
|
||||||
"duplicate": "",
|
"duplicate": "",
|
||||||
@@ -1842,6 +1853,11 @@
|
|||||||
"updated": "Nota actualizada con éxito."
|
"updated": "Nota actualizada con éxito."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"owner": {
|
||||||
|
"labels": {
|
||||||
|
"noownerinfo": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"owners": {
|
"owners": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"update": ""
|
"update": ""
|
||||||
@@ -1930,6 +1946,7 @@
|
|||||||
"email": "Enviar por correo electrónico",
|
"email": "Enviar por correo electrónico",
|
||||||
"inthisorder": "Partes en este pedido",
|
"inthisorder": "Partes en este pedido",
|
||||||
"newpartsorder": "",
|
"newpartsorder": "",
|
||||||
|
"notyetordered": "",
|
||||||
"oec": "",
|
"oec": "",
|
||||||
"orderhistory": "Historial de pedidos",
|
"orderhistory": "Historial de pedidos",
|
||||||
"parts_orders": "",
|
"parts_orders": "",
|
||||||
@@ -2078,6 +2095,7 @@
|
|||||||
"labels": "",
|
"labels": "",
|
||||||
"position": ""
|
"position": ""
|
||||||
},
|
},
|
||||||
|
"lag_time_ro": "",
|
||||||
"mechanical_authorization": "",
|
"mechanical_authorization": "",
|
||||||
"mpi_animal_checklist": "",
|
"mpi_animal_checklist": "",
|
||||||
"mpi_eglass_auth": "",
|
"mpi_eglass_auth": "",
|
||||||
@@ -2170,6 +2188,12 @@
|
|||||||
"ats": "",
|
"ats": "",
|
||||||
"bodyhours": "",
|
"bodyhours": "",
|
||||||
"bodypriority": "",
|
"bodypriority": "",
|
||||||
|
"bodyshop": {
|
||||||
|
"labels": {
|
||||||
|
"qbo_departmentid": "",
|
||||||
|
"qbo_usa": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"cardsettings": "",
|
"cardsettings": "",
|
||||||
"clm_no": "",
|
"clm_no": "",
|
||||||
"comment": "",
|
"comment": "",
|
||||||
@@ -2187,6 +2211,7 @@
|
|||||||
"refinishhours": "",
|
"refinishhours": "",
|
||||||
"scheduled_completion": "",
|
"scheduled_completion": "",
|
||||||
"selectview": "",
|
"selectview": "",
|
||||||
|
"stickyheader": "",
|
||||||
"sublets": "",
|
"sublets": "",
|
||||||
"totalhours": "",
|
"totalhours": "",
|
||||||
"touchtime": "",
|
"touchtime": "",
|
||||||
@@ -2553,6 +2578,14 @@
|
|||||||
"passwordchanged": ""
|
"passwordchanged": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"users": {
|
||||||
|
"errors": {
|
||||||
|
"signinerror": {
|
||||||
|
"auth/user-not-found": "",
|
||||||
|
"auth/wrong-password": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"vehicles": {
|
"vehicles": {
|
||||||
"errors": {
|
"errors": {
|
||||||
"noaccess": "El vehículo no existe o usted no tiene acceso a él.",
|
"noaccess": "El vehículo no existe o usted no tiene acceso a él.",
|
||||||
|
|||||||
@@ -157,6 +157,7 @@
|
|||||||
"federal_tax_rate": "",
|
"federal_tax_rate": "",
|
||||||
"invoice_number": "",
|
"invoice_number": "",
|
||||||
"is_credit_memo": "",
|
"is_credit_memo": "",
|
||||||
|
"is_credit_memo_short": "",
|
||||||
"local_tax_rate": "",
|
"local_tax_rate": "",
|
||||||
"ro_number": "",
|
"ro_number": "",
|
||||||
"state_tax_rate": "",
|
"state_tax_rate": "",
|
||||||
@@ -232,6 +233,7 @@
|
|||||||
},
|
},
|
||||||
"appt_length": "",
|
"appt_length": "",
|
||||||
"attach_pdf_to_email": "",
|
"attach_pdf_to_email": "",
|
||||||
|
"bill_allow_post_to_closed": "",
|
||||||
"bill_federal_tax_rate": "",
|
"bill_federal_tax_rate": "",
|
||||||
"bill_local_tax_rate": "",
|
"bill_local_tax_rate": "",
|
||||||
"bill_state_tax_rate": "",
|
"bill_state_tax_rate": "",
|
||||||
@@ -274,6 +276,7 @@
|
|||||||
"mapa": "",
|
"mapa": "",
|
||||||
"mash": ""
|
"mash": ""
|
||||||
},
|
},
|
||||||
|
"last_name_first": "",
|
||||||
"lastnumberworkingdays": "",
|
"lastnumberworkingdays": "",
|
||||||
"logo_img_footer_margin": "",
|
"logo_img_footer_margin": "",
|
||||||
"logo_img_header_margin": "",
|
"logo_img_header_margin": "",
|
||||||
@@ -293,12 +296,14 @@
|
|||||||
"md_ins_co": {
|
"md_ins_co": {
|
||||||
"city": "",
|
"city": "",
|
||||||
"name": "",
|
"name": "",
|
||||||
|
"private": "",
|
||||||
"state": "",
|
"state": "",
|
||||||
"street1": "",
|
"street1": "",
|
||||||
"street2": "",
|
"street2": "",
|
||||||
"zip": ""
|
"zip": ""
|
||||||
},
|
},
|
||||||
"md_jobline_presets": "",
|
"md_jobline_presets": "",
|
||||||
|
"md_parts_order_comment": "",
|
||||||
"md_payment_types": "",
|
"md_payment_types": "",
|
||||||
"md_referral_sources": "",
|
"md_referral_sources": "",
|
||||||
"messaginglabel": "",
|
"messaginglabel": "",
|
||||||
@@ -539,6 +544,8 @@
|
|||||||
"partslocations": "",
|
"partslocations": "",
|
||||||
"printlater": "",
|
"printlater": "",
|
||||||
"qbo": "",
|
"qbo": "",
|
||||||
|
"qbo_departmentid": "",
|
||||||
|
"qbo_usa": "",
|
||||||
"rbac": "",
|
"rbac": "",
|
||||||
"responsibilitycenters": {
|
"responsibilitycenters": {
|
||||||
"costs": "",
|
"costs": "",
|
||||||
@@ -1239,6 +1246,7 @@
|
|||||||
"08": "",
|
"08": "",
|
||||||
"09": ""
|
"09": ""
|
||||||
},
|
},
|
||||||
|
"auto_add_ats": "",
|
||||||
"ca_bc_pvrt": "",
|
"ca_bc_pvrt": "",
|
||||||
"ca_customer_gst": "",
|
"ca_customer_gst": "",
|
||||||
"ca_gst_registrant": "",
|
"ca_gst_registrant": "",
|
||||||
@@ -1386,6 +1394,7 @@
|
|||||||
"production_vars": {
|
"production_vars": {
|
||||||
"note": ""
|
"note": ""
|
||||||
},
|
},
|
||||||
|
"rate_ats": "",
|
||||||
"rate_la1": "Taux LA1",
|
"rate_la1": "Taux LA1",
|
||||||
"rate_la2": "Taux LA2",
|
"rate_la2": "Taux LA2",
|
||||||
"rate_la3": "Taux LA3",
|
"rate_la3": "Taux LA3",
|
||||||
@@ -1563,6 +1572,7 @@
|
|||||||
"override_header": "Remplacer l'en-tête d'estimation à l'importation?",
|
"override_header": "Remplacer l'en-tête d'estimation à l'importation?",
|
||||||
"ownerassociation": "",
|
"ownerassociation": "",
|
||||||
"parts": "les pièces",
|
"parts": "les pièces",
|
||||||
|
"parts_received": "",
|
||||||
"parts_tax_rates": "",
|
"parts_tax_rates": "",
|
||||||
"partsfilter": "",
|
"partsfilter": "",
|
||||||
"partssubletstotal": "",
|
"partssubletstotal": "",
|
||||||
@@ -1755,6 +1765,7 @@
|
|||||||
},
|
},
|
||||||
"jobsactions": {
|
"jobsactions": {
|
||||||
"admin": "",
|
"admin": "",
|
||||||
|
"cancelallappointments": "",
|
||||||
"closejob": "",
|
"closejob": "",
|
||||||
"deletejob": "",
|
"deletejob": "",
|
||||||
"duplicate": "",
|
"duplicate": "",
|
||||||
@@ -1842,6 +1853,11 @@
|
|||||||
"updated": "Remarque mise à jour avec succès."
|
"updated": "Remarque mise à jour avec succès."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"owner": {
|
||||||
|
"labels": {
|
||||||
|
"noownerinfo": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"owners": {
|
"owners": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"update": ""
|
"update": ""
|
||||||
@@ -1930,6 +1946,7 @@
|
|||||||
"email": "Envoyé par email",
|
"email": "Envoyé par email",
|
||||||
"inthisorder": "Pièces dans cette commande",
|
"inthisorder": "Pièces dans cette commande",
|
||||||
"newpartsorder": "",
|
"newpartsorder": "",
|
||||||
|
"notyetordered": "",
|
||||||
"oec": "",
|
"oec": "",
|
||||||
"orderhistory": "Historique des commandes",
|
"orderhistory": "Historique des commandes",
|
||||||
"parts_orders": "",
|
"parts_orders": "",
|
||||||
@@ -2078,6 +2095,7 @@
|
|||||||
"labels": "",
|
"labels": "",
|
||||||
"position": ""
|
"position": ""
|
||||||
},
|
},
|
||||||
|
"lag_time_ro": "",
|
||||||
"mechanical_authorization": "",
|
"mechanical_authorization": "",
|
||||||
"mpi_animal_checklist": "",
|
"mpi_animal_checklist": "",
|
||||||
"mpi_eglass_auth": "",
|
"mpi_eglass_auth": "",
|
||||||
@@ -2170,6 +2188,12 @@
|
|||||||
"ats": "",
|
"ats": "",
|
||||||
"bodyhours": "",
|
"bodyhours": "",
|
||||||
"bodypriority": "",
|
"bodypriority": "",
|
||||||
|
"bodyshop": {
|
||||||
|
"labels": {
|
||||||
|
"qbo_departmentid": "",
|
||||||
|
"qbo_usa": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
"cardsettings": "",
|
"cardsettings": "",
|
||||||
"clm_no": "",
|
"clm_no": "",
|
||||||
"comment": "",
|
"comment": "",
|
||||||
@@ -2187,6 +2211,7 @@
|
|||||||
"refinishhours": "",
|
"refinishhours": "",
|
||||||
"scheduled_completion": "",
|
"scheduled_completion": "",
|
||||||
"selectview": "",
|
"selectview": "",
|
||||||
|
"stickyheader": "",
|
||||||
"sublets": "",
|
"sublets": "",
|
||||||
"totalhours": "",
|
"totalhours": "",
|
||||||
"touchtime": "",
|
"touchtime": "",
|
||||||
@@ -2553,6 +2578,14 @@
|
|||||||
"passwordchanged": ""
|
"passwordchanged": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"users": {
|
||||||
|
"errors": {
|
||||||
|
"signinerror": {
|
||||||
|
"auth/user-not-found": "",
|
||||||
|
"auth/wrong-password": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"vehicles": {
|
"vehicles": {
|
||||||
"errors": {
|
"errors": {
|
||||||
"noaccess": "Le véhicule n'existe pas ou vous n'y avez pas accès.",
|
"noaccess": "Le véhicule n'existe pas ou vous n'y avez pas accès.",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { gql } from "@apollo/client";
|
import { gql } from "@apollo/client";
|
||||||
import { notification } from "antd";
|
import { notification } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import jsreport from "jsreport-browser-client-dist";
|
import jsreport from "@jsreport/browser-client";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { auth } from "../firebase/firebase.utils";
|
import { auth } from "../firebase/firebase.utils";
|
||||||
|
|||||||
@@ -464,6 +464,14 @@ export const TemplateList = (type, context) => {
|
|||||||
disabled: false,
|
disabled: false,
|
||||||
group: "post",
|
group: "post",
|
||||||
},
|
},
|
||||||
|
lag_time_ro: {
|
||||||
|
title: i18n.t("printcenter.jobs.lag_time_ro"),
|
||||||
|
description: "CASL Authorization",
|
||||||
|
subject: i18n.t("printcenter.jobs.lag_time_ro"),
|
||||||
|
key: "lag_time_ro",
|
||||||
|
disabled: false,
|
||||||
|
group: "ro",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
...(!type || type === "job_special"
|
...(!type || type === "job_special"
|
||||||
|
|||||||
5204
client/yarn.lock
5204
client/yarn.lock
File diff suppressed because it is too large
Load Diff
1
hasura/metadata/network.yaml
Normal file
1
hasura/metadata/network.yaml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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 "last_name_first" boolean
|
||||||
|
-- not null default 'false';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."bodyshops" add column "last_name_first" boolean
|
||||||
|
not null default 'false';
|
||||||
@@ -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_parts_order_comment" jsonb
|
||||||
|
-- not null default jsonb_build_array();
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."bodyshops" add column "md_parts_order_comment" jsonb
|
||||||
|
not 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"."bodyshops" add column "bill_allow_post_to_closed" boolean
|
||||||
|
-- not null default 'false';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."bodyshops" add column "bill_allow_post_to_closed" boolean
|
||||||
|
not null default 'false';
|
||||||
@@ -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 "auto_add_ats" boolean
|
||||||
|
-- null default 'false';
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."jobs" add column "auto_add_ats" boolean
|
||||||
|
null default 'false';
|
||||||
@@ -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 "rate_ats" numeric
|
||||||
|
-- null;
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
alter table "public"."jobs" add column "rate_ats" numeric
|
||||||
|
null;
|
||||||
2
logs/IM_1234_30032022_080308.xml
Normal file
2
logs/IM_1234_30032022_080308.xml
Normal file
File diff suppressed because one or more lines are too long
2
logs/IM_1234_30032022_080358.xml
Normal file
2
logs/IM_1234_30032022_080358.xml
Normal file
File diff suppressed because one or more lines are too long
30873
logs/oAuthClient-log.log
30873
logs/oAuthClient-log.log
File diff suppressed because one or more lines are too long
5325
package-lock.json
generated
5325
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,8 +3,8 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "12.22.6",
|
"node": "16.14.2",
|
||||||
"npm": "7.17.0"
|
"npm": "8.6.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"setup": "yarn && cd client && yarn",
|
"setup": "yarn && cd client && yarn",
|
||||||
|
|||||||
@@ -611,6 +611,32 @@ exports.default = function ({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//QB USA with GST
|
||||||
|
//This was required for the No. 1 Collision Group.
|
||||||
|
if (
|
||||||
|
bodyshop.accountingconfig &&
|
||||||
|
bodyshop.accountingconfig.qbo &&
|
||||||
|
bodyshop.accountingconfig.qbo_usa &&
|
||||||
|
bodyshop.region_config.includes("CA_")
|
||||||
|
) {
|
||||||
|
InvoiceLineAdd.push({
|
||||||
|
DetailType: "SalesItemLineDetail",
|
||||||
|
Amount: Dinero(jobs_by_pk.job_totals.totals.federal_tax).toFormat(
|
||||||
|
DineroQbFormat
|
||||||
|
),
|
||||||
|
SalesItemLineDetail: {
|
||||||
|
...(jobs_by_pk.class
|
||||||
|
? { ClassRef: { value: classes[jobs_by_pk.class] } }
|
||||||
|
: {}),
|
||||||
|
ItemRef: {
|
||||||
|
value:
|
||||||
|
items[bodyshop.md_responsibility_centers.taxes.federal.accountitem],
|
||||||
|
},
|
||||||
|
Qty: 1,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return InvoiceLineAdd;
|
return InvoiceLineAdd;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -626,7 +652,7 @@ const findTaxCode = ({ local, state, federal }, taxcode) => {
|
|||||||
} else if (t.length > 1) {
|
} else if (t.length > 1) {
|
||||||
return "Multiple Tax Codes Match";
|
return "Multiple Tax Codes Match";
|
||||||
} else {
|
} else {
|
||||||
return "No Tax Code Matches";
|
return "";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
exports.findTaxCode = findTaxCode;
|
exports.findTaxCode = findTaxCode;
|
||||||
|
|||||||
@@ -174,6 +174,55 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor) {
|
|||||||
req
|
req
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const lines = bill.billlines.map((il) =>
|
||||||
|
generateBillLine(
|
||||||
|
il,
|
||||||
|
accounts,
|
||||||
|
bill.job.class,
|
||||||
|
bill.job.bodyshop.md_responsibility_centers.sales_tax_codes,
|
||||||
|
classes,
|
||||||
|
taxCodes,
|
||||||
|
bill.job.bodyshop.md_responsibility_centers.costs
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
//QB USA with GST
|
||||||
|
//This was required for the No. 1 Collision Group.
|
||||||
|
if (
|
||||||
|
bill.job.bodyshop.accountingconfig &&
|
||||||
|
bill.job.bodyshop.accountingconfig.qbo &&
|
||||||
|
bill.job.bodyshop.accountingconfig.qbo_usa &&
|
||||||
|
bill.job.bodyshop.region_config.includes("CA_")
|
||||||
|
) {
|
||||||
|
lines.push({
|
||||||
|
DetailType: "AccountBasedExpenseLineDetail",
|
||||||
|
|
||||||
|
AccountBasedExpenseLineDetail: {
|
||||||
|
...(bill.job.class
|
||||||
|
? { ClassRef: { value: classes[bill.job.class] } }
|
||||||
|
: {}),
|
||||||
|
AccountRef: {
|
||||||
|
value:
|
||||||
|
accounts[
|
||||||
|
bill.job.bodyshop.md_responsibility_centers.taxes.federal
|
||||||
|
.accountdesc
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
Amount: Dinero({
|
||||||
|
amount: Math.round(
|
||||||
|
bill.billlines.reduce((acc, val) => {
|
||||||
|
return acc + val.actual_cost * val.quantity;
|
||||||
|
}, 0) * 100
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.percentage(bill.federal_tax_rate)
|
||||||
|
|
||||||
|
.toFormat(DineroQbFormat),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const billQbo = {
|
const billQbo = {
|
||||||
VendorRef: {
|
VendorRef: {
|
||||||
value: vendor.Id,
|
value: vendor.Id,
|
||||||
@@ -192,17 +241,7 @@ async function InsertBill(oauthClient, qbo_realmId, req, bill, vendor) {
|
|||||||
//...(bill.job.class ? { ClassRef: { Id: classes[bill.job.class] } } : {}),
|
//...(bill.job.class ? { ClassRef: { Id: classes[bill.job.class] } } : {}),
|
||||||
|
|
||||||
PrivateNote: `RO ${bill.job.ro_number || ""}`,
|
PrivateNote: `RO ${bill.job.ro_number || ""}`,
|
||||||
Line: bill.billlines.map((il) =>
|
Line: lines,
|
||||||
generateBillLine(
|
|
||||||
il,
|
|
||||||
accounts,
|
|
||||||
bill.job.class,
|
|
||||||
bill.job.bodyshop.md_responsibility_centers.sales_tax_codes,
|
|
||||||
classes,
|
|
||||||
taxCodes,
|
|
||||||
bill.job.bodyshop.md_responsibility_centers.costs
|
|
||||||
)
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
logger.log("qbo-payable-objectlog", "DEBUG", req.user.email, bill.id, {
|
logger.log("qbo-payable-objectlog", "DEBUG", req.user.email, bill.id, {
|
||||||
billQbo,
|
billQbo,
|
||||||
@@ -282,7 +321,7 @@ async function QueryMetaData(oauthClient, qbo_realmId, req) {
|
|||||||
url: urlBuilder(
|
url: urlBuilder(
|
||||||
qbo_realmId,
|
qbo_realmId,
|
||||||
"query",
|
"query",
|
||||||
`select * From Account where AccountType = 'Cost of Goods Sold'`
|
`select * From Account where AccountType in ('Cost of Goods Sold', 'Other Current Liability')`
|
||||||
),
|
),
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -455,6 +455,25 @@ async function InsertInvoice(
|
|||||||
CustomerRef: {
|
CustomerRef: {
|
||||||
value: parentTierRef.Id,
|
value: parentTierRef.Id,
|
||||||
},
|
},
|
||||||
|
...(bodyshop.accountingconfig.qbo_departmentid &&
|
||||||
|
bodyshop.accountingconfig.qbo_departmentid.trim() !== "" && {
|
||||||
|
DepartmentRef: { value: bodyshop.accountingconfig.qbo_departmentid },
|
||||||
|
}),
|
||||||
|
|
||||||
|
...(bodyshop.accountingconfig &&
|
||||||
|
bodyshop.accountingconfig.qbo &&
|
||||||
|
bodyshop.accountingconfig.qbo_usa &&
|
||||||
|
bodyshop.region_config.includes("CA_") && {
|
||||||
|
TxnTaxDetail: {
|
||||||
|
TxnTaxCodeRef: {
|
||||||
|
value:
|
||||||
|
taxCodes[
|
||||||
|
bodyshop.md_responsibility_centers.taxes.state.accountitem
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
|
||||||
...(bodyshop.accountingconfig.printlater
|
...(bodyshop.accountingconfig.printlater
|
||||||
? { PrintStatus: "NeedToPrint" }
|
? { PrintStatus: "NeedToPrint" }
|
||||||
: {}),
|
: {}),
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ exports.default = async (req, res) => {
|
|||||||
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
|
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
|
||||||
|
|
||||||
const specificShopIds = req.body.bodyshopIds; // ['uuid]
|
const specificShopIds = req.body.bodyshopIds; // ['uuid]
|
||||||
const start = req.body.start; //YYYY-MM-DD
|
const { start, end } = req.body; //YYYY-MM-DD
|
||||||
const allxmlsToUpload = [];
|
const allxmlsToUpload = [];
|
||||||
const allErrors = [];
|
const allErrors = [];
|
||||||
try {
|
try {
|
||||||
@@ -58,6 +58,7 @@ exports.default = async (req, res) => {
|
|||||||
start: start
|
start: start
|
||||||
? moment(start).startOf("day")
|
? moment(start).startOf("day")
|
||||||
: moment().subtract(3, "days").startOf("day"),
|
: moment().subtract(3, "days").startOf("day"),
|
||||||
|
...(end && { end: moment(end).startOf("day") }),
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -167,7 +168,6 @@ exports.default = async (req, res) => {
|
|||||||
sendServerEmail({
|
sendServerEmail({
|
||||||
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
subject: `Autohouse Report ${moment().format("MM-DD-YY")}`,
|
||||||
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||||
|
|
||||||
Uploaded: ${JSON.stringify(
|
Uploaded: ${JSON.stringify(
|
||||||
allxmlsToUpload.map((x) => x.filename),
|
allxmlsToUpload.map((x) => x.filename),
|
||||||
null,
|
null,
|
||||||
@@ -184,6 +184,11 @@ exports.default = async (req, res) => {
|
|||||||
const CreateRepairOrderTag = (job, errorCallback) => {
|
const CreateRepairOrderTag = (job, errorCallback) => {
|
||||||
//Level 2
|
//Level 2
|
||||||
|
|
||||||
|
if (!job.job_totals) {
|
||||||
|
errorCallback({ job, error: { toString: () => "No job totals for RO." } });
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
const repairCosts = CreateCosts(job);
|
const repairCosts = CreateCosts(job);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -749,9 +754,14 @@ const CreateCosts = (job) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
PartsTotalCost: Object.keys(billTotalsByCostCenters).reduce((acc, key) => {
|
PartsTotalCost: Object.keys(billTotalsByCostCenters).reduce((acc, key) => {
|
||||||
if (key !== defaultCosts.PAS && key !== defaultCosts.PASL)
|
if (
|
||||||
|
key !== defaultCosts.PAS &&
|
||||||
|
key !== defaultCosts.PASL &&
|
||||||
|
key !== defaultCosts.MAPA &&
|
||||||
|
key !== defaultCosts.MASH &&
|
||||||
|
key !== defaultCosts.TOW
|
||||||
|
)
|
||||||
return acc.add(billTotalsByCostCenters[key]);
|
return acc.add(billTotalsByCostCenters[key]);
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, Dinero()),
|
}, Dinero()),
|
||||||
PartsOemCost: (billTotalsByCostCenters[defaultCosts.PAN] || Dinero()).add(
|
PartsOemCost: (billTotalsByCostCenters[defaultCosts.PAN] || Dinero()).add(
|
||||||
|
|||||||
@@ -20,6 +20,38 @@ mutation UNARCHIVE_CONVERSATION($id: uuid!) {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports.INSERT_NEW_JOB_LINE = `
|
||||||
|
mutation INSERT_NEW_JOB_LINE($lineInput: [joblines_insert_input!]!) {
|
||||||
|
insert_joblines(objects: $lineInput) {
|
||||||
|
returning {
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports.UPDATE_JOB_LINE = `
|
||||||
|
mutation UPDATE_JOB_LINE($lineId: uuid!, $line: joblines_set_input!) {
|
||||||
|
update_joblines(where: { id: { _eq: $lineId } }, _set: $line) {
|
||||||
|
returning {
|
||||||
|
id
|
||||||
|
notes
|
||||||
|
mod_lbr_ty
|
||||||
|
part_qty
|
||||||
|
db_price
|
||||||
|
act_price
|
||||||
|
line_desc
|
||||||
|
line_no
|
||||||
|
oem_partno
|
||||||
|
notes
|
||||||
|
location
|
||||||
|
status
|
||||||
|
removed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
exports.RECEIVE_MESSAGE = `
|
exports.RECEIVE_MESSAGE = `
|
||||||
mutation RECEIVE_MESSAGE($msg: [messages_insert_input!]!) {
|
mutation RECEIVE_MESSAGE($msg: [messages_insert_input!]!) {
|
||||||
insert_messages(objects: $msg) {
|
insert_messages(objects: $msg) {
|
||||||
@@ -111,6 +143,11 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
|||||||
ro_number
|
ro_number
|
||||||
clm_total
|
clm_total
|
||||||
clm_no
|
clm_no
|
||||||
|
v_model_yr
|
||||||
|
v_model_desc
|
||||||
|
v_make_desc
|
||||||
|
v_vin
|
||||||
|
plate_no
|
||||||
ownerid
|
ownerid
|
||||||
ownr_ln
|
ownr_ln
|
||||||
ownr_fn
|
ownr_fn
|
||||||
@@ -176,6 +213,7 @@ query QUERY_JOBS_FOR_RECEIVABLES_EXPORT($ids: [uuid!]!) {
|
|||||||
bodyshops(where: {associations: {active: {_eq: true}}}) {
|
bodyshops(where: {associations: {active: {_eq: true}}}) {
|
||||||
id
|
id
|
||||||
md_responsibility_centers
|
md_responsibility_centers
|
||||||
|
region_config
|
||||||
accountingconfig
|
accountingconfig
|
||||||
md_ins_cos
|
md_ins_cos
|
||||||
timezone
|
timezone
|
||||||
@@ -389,6 +427,8 @@ query QUERY_BILLS_FOR_PAYABLES_EXPORT($bills: [uuid!]!) {
|
|||||||
bodyshop{
|
bodyshop{
|
||||||
md_responsibility_centers
|
md_responsibility_centers
|
||||||
timezone
|
timezone
|
||||||
|
region_config
|
||||||
|
accountingconfig
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
billlines{
|
billlines{
|
||||||
@@ -550,7 +590,7 @@ exports.QUERY_EMPLOYEE_PIN = `query QUERY_EMPLOYEE_PIN($shopId: uuid!, $employee
|
|||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
|
|
||||||
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshopid: uuid!) {
|
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshopid: uuid!, $end: timestamptz) {
|
||||||
bodyshops_by_pk(id: $bodyshopid){
|
bodyshops_by_pk(id: $bodyshopid){
|
||||||
|
|
||||||
id
|
id
|
||||||
@@ -568,7 +608,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshop
|
|||||||
jc_hourly_rates
|
jc_hourly_rates
|
||||||
timezone
|
timezone
|
||||||
}
|
}
|
||||||
jobs(where: {_and: [{converted: {_eq: true}}, {updated_at: {_gt: $start}}, {shopid: {_eq: $bodyshopid}}]}) {
|
jobs(where: {_and: [{converted: {_eq: true}}, {updated_at: {_gt: $start}}, {updated_at: {_lte: $end}}, {shopid: {_eq: $bodyshopid}}]}) {
|
||||||
id
|
id
|
||||||
ro_number
|
ro_number
|
||||||
status
|
status
|
||||||
@@ -962,6 +1002,8 @@ exports.GET_JOB_BY_PK = ` query GET_JOB_BY_PK($id: uuid!) {
|
|||||||
ca_bc_pvrt
|
ca_bc_pvrt
|
||||||
ca_customer_gst
|
ca_customer_gst
|
||||||
materials
|
materials
|
||||||
|
auto_add_ats
|
||||||
|
rate_ats
|
||||||
joblines(where: { removed: { _eq: false } }){
|
joblines(where: { removed: { _eq: false } }){
|
||||||
id
|
id
|
||||||
line_no
|
line_no
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ exports.totalsSsu = async function (req, res) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const newTotals = await TotalsServerSide(
|
const newTotals = await TotalsServerSide(
|
||||||
{ body: { job: job.jobs_by_pk } },
|
{ body: { job: job.jobs_by_pk, client: client } },
|
||||||
res,
|
res,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@@ -53,7 +53,9 @@ exports.totalsSsu = async function (req, res) {
|
|||||||
|
|
||||||
//IMPORTANT*** These two functions MUST be mirrrored.
|
//IMPORTANT*** These two functions MUST be mirrrored.
|
||||||
async function TotalsServerSide(req, res) {
|
async function TotalsServerSide(req, res) {
|
||||||
const { job } = req.body;
|
const { job, client } = req.body;
|
||||||
|
await AutoAddAtsIfRequired({ job: job, client: client });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let ret = {
|
let ret = {
|
||||||
parts: CalculatePartsTotals(job.joblines),
|
parts: CalculatePartsTotals(job.joblines),
|
||||||
@@ -78,6 +80,16 @@ async function Totals(req, res) {
|
|||||||
jobid: job.id,
|
jobid: job.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const BearerToken = req.headers.authorization;
|
||||||
|
const { id } = req.body;
|
||||||
|
logger.log("job-totals-ssu", "DEBUG", req.user.email, id, null);
|
||||||
|
const client = new GraphQLClient(process.env.GRAPHQL_ENDPOINT, {
|
||||||
|
headers: {
|
||||||
|
Authorization: BearerToken,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await AutoAddAtsIfRequired({ job, client });
|
||||||
try {
|
try {
|
||||||
let ret = {
|
let ret = {
|
||||||
parts: CalculatePartsTotals(job.joblines),
|
parts: CalculatePartsTotals(job.joblines),
|
||||||
@@ -96,6 +108,83 @@ async function Totals(req, res) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function AutoAddAtsIfRequired({ job, client }) {
|
||||||
|
//Check if ATS should be automatically added.
|
||||||
|
if (job.auto_add_ats) {
|
||||||
|
//Get the total sum of hours that should be the ATS amount.
|
||||||
|
//Check to see if an ATS line exists.
|
||||||
|
let atsLineIndex = null;
|
||||||
|
const atsHours = job.joblines.reduce((acc, val, index) => {
|
||||||
|
if (val.line_desc && val.line_desc.toLowerCase() === "ats amount") {
|
||||||
|
atsLineIndex = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
val.mod_lbr_ty !== "LA1" &&
|
||||||
|
val.mod_lbr_ty !== "LA2" &&
|
||||||
|
val.mod_lbr_ty !== "LA3" &&
|
||||||
|
val.mod_lbr_ty !== "LA4" &&
|
||||||
|
val.mod_lbr_ty !== "LAU" &&
|
||||||
|
val.mod_lbr_ty !== "LAG" &&
|
||||||
|
val.mod_lbr_ty !== "LAS" &&
|
||||||
|
val.mod_lbr_ty !== "LAA"
|
||||||
|
) {
|
||||||
|
acc = acc + val.mod_lb_hrs;
|
||||||
|
}
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, 0);
|
||||||
|
|
||||||
|
const atsAmount = atsHours * (job.rate_ats || 0);
|
||||||
|
//If it does, update it in place, and make sure it is updated for local calculations.
|
||||||
|
if (atsLineIndex === null) {
|
||||||
|
const newAtsLine = {
|
||||||
|
jobid: job.id,
|
||||||
|
alt_partm: null,
|
||||||
|
line_no: 35,
|
||||||
|
unq_seq: 0,
|
||||||
|
line_ind: "E",
|
||||||
|
line_desc: "ATS Amount",
|
||||||
|
line_ref: 0.0,
|
||||||
|
part_type: null,
|
||||||
|
oem_partno: null,
|
||||||
|
db_price: 0.0,
|
||||||
|
act_price: atsAmount,
|
||||||
|
part_qty: 1,
|
||||||
|
mod_lbr_ty: null,
|
||||||
|
db_hrs: 0.0,
|
||||||
|
mod_lb_hrs: 0.0,
|
||||||
|
lbr_op: "OP13",
|
||||||
|
lbr_amt: 0.0,
|
||||||
|
op_code_desc: "ADDITIONAL COSTS",
|
||||||
|
status: null,
|
||||||
|
location: null,
|
||||||
|
tax_part: true,
|
||||||
|
db_ref: null,
|
||||||
|
manual_line: true,
|
||||||
|
prt_dsmk_p: 0.0,
|
||||||
|
prt_dsmk_m: 0.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await client.request(queries.INSERT_NEW_JOB_LINE, {
|
||||||
|
lineInput: [newAtsLine],
|
||||||
|
});
|
||||||
|
|
||||||
|
job.joblines.push(newAtsLine);
|
||||||
|
}
|
||||||
|
//If it does not, create one for local calculations and insert it.
|
||||||
|
else {
|
||||||
|
const result = await client.request(queries.UPDATE_JOB_LINE, {
|
||||||
|
line: { act_price: atsAmount },
|
||||||
|
lineId: job.joblines[atsLineIndex].id,
|
||||||
|
});
|
||||||
|
job.joblines[atsLineIndex].act_price = atsAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(job.jobLines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function CalculateRatesTotals(ratesList) {
|
function CalculateRatesTotals(ratesList) {
|
||||||
const jobLines = ratesList.joblines.filter((jl) => !jl.removed);
|
const jobLines = ratesList.joblines.filter((jl) => !jl.removed);
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user