Compare commits
27 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
affbb3f168 | ||
|
|
cb4d4e4c2c | ||
|
|
225b57fd58 | ||
|
|
268b1ba9c1 | ||
|
|
9c1774c417 | ||
|
|
26b3a43ce5 | ||
|
|
78678dd3dc | ||
|
|
9dc4546b2e | ||
|
|
95aa0e45a6 | ||
|
|
ce9a77efcf | ||
|
|
e9e1e820a7 | ||
|
|
c7fc75aa5c | ||
|
|
b027a4e618 | ||
|
|
98d2372daf | ||
|
|
bf51380167 | ||
|
|
1ec827097f | ||
|
|
ff7dd7d3ea | ||
|
|
8cc4f88fa7 | ||
|
|
7e6ab3a5ff | ||
|
|
34f876f838 | ||
|
|
2f3eccf3d8 | ||
|
|
2b3e64d607 | ||
|
|
05b20505bb | ||
|
|
bddeae945c | ||
|
|
5b267f03b9 | ||
|
|
9aab47d8f8 | ||
|
|
f2f84e2da8 |
30
.vscode/settings.json
vendored
30
.vscode/settings.json
vendored
@@ -8,5 +8,35 @@
|
||||
"pattern": "**/IMEX.xml",
|
||||
"systemId": "logs/IMEX.xsd"
|
||||
}
|
||||
],
|
||||
"cSpell.words": [
|
||||
"antd",
|
||||
"appointmentconfirmation",
|
||||
"appt",
|
||||
"autohouse",
|
||||
"autohouseid",
|
||||
"billlines",
|
||||
"bodyshop",
|
||||
"bodyshopid",
|
||||
"bodyshops",
|
||||
"CIECA",
|
||||
"claimscorp",
|
||||
"claimscorpid",
|
||||
"Dinero",
|
||||
"driveable",
|
||||
"IMEX",
|
||||
"imexshopid",
|
||||
"jobid",
|
||||
"joblines",
|
||||
"Kaizen",
|
||||
"labhrs",
|
||||
"larhrs",
|
||||
"mixdata",
|
||||
"ownr",
|
||||
"promanager",
|
||||
"shopname",
|
||||
"smartscheduling",
|
||||
"timetickets",
|
||||
"touchtime"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<babeledit_project version="1.2" be_version="2.7.1">
|
||||
<babeledit_project be_version="2.7.1" version="1.2">
|
||||
<!--
|
||||
|
||||
BabelEdit project file
|
||||
@@ -11156,6 +11156,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>imexpay</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>insurancecos</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -11198,27 +11219,6 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>intellipay</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>intellipay_cash_discount</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -11747,6 +11747,48 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>ttl_adjustment</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>ttl_tax_adjustment</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
@@ -11775,6 +11817,27 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<concept_node>
|
||||
<name>romepay</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>scheduling</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -20639,6 +20702,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>time</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -21811,6 +21895,48 @@
|
||||
<folder_node>
|
||||
<name>columns</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>average_human_readable</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>average_value</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>duration</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -31746,6 +31872,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>tlos_ind</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>towin</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -36253,6 +36400,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_cust_payable_cash_discount</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_repairs</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -36274,6 +36442,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_repairs_cash_discount</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_sales</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48360,6 +48549,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>tasks_in_view</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>tasks_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48402,6 +48612,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_amount_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_amount_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48444,6 +48675,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_hours_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_hours_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48465,6 +48717,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_jobs_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_jobs_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48507,6 +48780,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_lab_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_lab_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48549,6 +48843,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_lar_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_lar_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48724,6 +49039,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>tasks_in_view</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>tasks_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48766,6 +49102,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_amount_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_amount_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48808,6 +49165,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_hours_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_hours_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48829,6 +49207,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_jobs_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_jobs_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48871,6 +49270,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_lab_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_lab_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -48913,6 +49333,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_lar_in_view</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>total_lar_on_board</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -51761,6 +52202,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>production_not_production_status</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
<description></description>
|
||||
<comment></comment>
|
||||
<default_text></default_text>
|
||||
<translations>
|
||||
<translation>
|
||||
<language>en-US</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>es-MX</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
<translation>
|
||||
<language>fr-CA</language>
|
||||
<approved>false</approved>
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>production_over_time</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -54225,6 +54687,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>created_by</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>description</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
@@ -54487,6 +54970,27 @@
|
||||
</translation>
|
||||
</translations>
|
||||
</concept_node>
|
||||
<concept_node>
|
||||
<name>related_items</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>remind_at</name>
|
||||
<definition_loaded>false</definition_loaded>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { DatePicker } from "antd";
|
||||
import { DatePicker, Space, TimePicker } from "antd";
|
||||
import PropTypes from "prop-types";
|
||||
import React, { useCallback, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
@@ -20,6 +20,7 @@ const DateTimePicker = ({
|
||||
onlyFuture,
|
||||
onlyToday,
|
||||
isDateOnly = false,
|
||||
isSeparatedTime = false,
|
||||
bodyshop,
|
||||
...restProps
|
||||
}) => {
|
||||
@@ -87,24 +88,56 @@ const DateTimePicker = ({
|
||||
|
||||
return (
|
||||
<div onKeyDown={handleKeyDown} id={id} style={{ width: "100%" }}>
|
||||
<DatePicker
|
||||
showTime={
|
||||
isDateOnly
|
||||
? false
|
||||
: {
|
||||
format: "hh:mm a",
|
||||
minuteStep: 15,
|
||||
defaultValue: dayjs(dayjs(), "HH:mm:ss")
|
||||
}
|
||||
}
|
||||
format={isDateOnly ? "MM/DD/YYYY" : "MM/DD/YYYY hh:mm a"}
|
||||
value={value ? dayjs(value) : null}
|
||||
onChange={handleChange}
|
||||
placeholder={isDateOnly ? t("general.labels.date") : t("general.labels.datetime")}
|
||||
onBlur={onBlur || handleBlur}
|
||||
disabledDate={handleDisabledDate}
|
||||
{...restProps}
|
||||
/>
|
||||
{isSeparatedTime && (
|
||||
<Space direction="vertical" style={{ width: "100%" }}>
|
||||
<DatePicker
|
||||
showTime={false}
|
||||
format="MM/DD/YYYY"
|
||||
value={value ? dayjs(value) : null}
|
||||
onChange={handleChange}
|
||||
placeholder={t("general.labels.date")}
|
||||
onBlur={handleBlur}
|
||||
disabledDate={handleDisabledDate}
|
||||
isDateOnly={true}
|
||||
{...restProps}
|
||||
/>
|
||||
{value && (
|
||||
<TimePicker
|
||||
format="hh:mm a"
|
||||
minuteStep={15}
|
||||
defaultOpenValue={dayjs()
|
||||
.minute(Math.floor(dayjs().minute() / 15) * 15)
|
||||
.second(0)}
|
||||
onChange={(value) => {
|
||||
handleChange(value);
|
||||
onBlur();
|
||||
}}
|
||||
placeholder={t("general.labels.time")}
|
||||
{...restProps}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
)}
|
||||
{!isSeparatedTime && (
|
||||
<DatePicker
|
||||
showTime={
|
||||
isDateOnly
|
||||
? false
|
||||
: {
|
||||
format: "hh:mm a",
|
||||
minuteStep: 15,
|
||||
defaultValue: dayjs(dayjs(), "HH:mm:ss")
|
||||
}
|
||||
}
|
||||
format={isDateOnly ? "MM/DD/YYYY" : "MM/DD/YYYY hh:mm a"}
|
||||
value={value ? dayjs(value) : null}
|
||||
onChange={handleChange}
|
||||
placeholder={isDateOnly ? t("general.labels.date") : t("general.labels.datetime")}
|
||||
onBlur={onBlur || handleBlur}
|
||||
disabledDate={handleDisabledDate}
|
||||
{...restProps}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -116,7 +149,8 @@ DateTimePicker.propTypes = {
|
||||
id: PropTypes.string,
|
||||
onlyFuture: PropTypes.bool,
|
||||
onlyToday: PropTypes.bool,
|
||||
isDateOnly: PropTypes.bool
|
||||
isDateOnly: PropTypes.bool,
|
||||
isSeparatedTime: PropTypes.bool
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, null)(DateTimePicker);
|
||||
|
||||
@@ -118,8 +118,7 @@ export function JobLinesComponent({
|
||||
...(record.critical ? { boxShadow: " -.5em 0 0 #FFC107" } : {})
|
||||
}
|
||||
}),
|
||||
sortOrder: state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
|
||||
ellipsis: true
|
||||
sortOrder: state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order
|
||||
},
|
||||
{
|
||||
title: t("joblines.fields.oem_partno"),
|
||||
|
||||
@@ -45,7 +45,8 @@ export default function JobLineNotePopup({ jobline, disabled }) {
|
||||
if (editing)
|
||||
return (
|
||||
<div>
|
||||
<Input
|
||||
<Input.TextArea
|
||||
autoSize
|
||||
autoFocus
|
||||
suffix={loading ? <LoadingSpinner /> : null}
|
||||
value={note}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import { Form, Input, InputNumber, Modal, Select, Switch } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import InputCurrency from "../form-items-formatted/currency-form-item.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import JoblinesPreset from "../job-lines-preset-button/job-lines-preset-button.component";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -61,7 +61,7 @@ export function JobLinesUpsertModalComponent({ bodyshop, open, jobLine, handleCa
|
||||
]}
|
||||
name="line_desc"
|
||||
>
|
||||
<Input />
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
<JoblinesPreset form={form} />
|
||||
</LayoutFormRow>
|
||||
|
||||
@@ -7,6 +7,7 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import JobTotalsCashDiscount from "./jobs-totals.cash-discount-display.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -132,23 +133,41 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
]
|
||||
}),
|
||||
|
||||
{
|
||||
key: t("jobs.labels.total_repairs"),
|
||||
total: job.job_totals.totals.total_repairs,
|
||||
bold: true
|
||||
},
|
||||
...(bodyshop.intellipay_config?.enable_cash_discount
|
||||
? [
|
||||
{
|
||||
key: t("jobs.labels.total_repairs_cash_discount"),
|
||||
total: job.job_totals.totals.total_repairs,
|
||||
bold: true
|
||||
},
|
||||
{
|
||||
key: t("jobs.labels.total_repairs"),
|
||||
render: <JobTotalsCashDiscount amountDinero={job.job_totals.totals.total_repairs} />,
|
||||
bold: true
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
key: t("jobs.labels.total_repairs"),
|
||||
total: job.job_totals.totals.total_repairs,
|
||||
bold: true
|
||||
}
|
||||
]),
|
||||
|
||||
{
|
||||
key: t("jobs.fields.ded_amt"),
|
||||
total: job.job_totals.totals.custPayable.deductible
|
||||
},
|
||||
...(InstanceRenderManager({
|
||||
imex: [{
|
||||
key: t("jobs.fields.federal_tax_payable"),
|
||||
total: job.job_totals.totals.custPayable.federal_tax
|
||||
}],
|
||||
...InstanceRenderManager({
|
||||
imex: [
|
||||
{
|
||||
key: t("jobs.fields.federal_tax_payable"),
|
||||
total: job.job_totals.totals.custPayable.federal_tax
|
||||
}
|
||||
],
|
||||
rome: [],
|
||||
promanager: "USE_ROME"
|
||||
})),
|
||||
}),
|
||||
{
|
||||
key: t("jobs.fields.other_amount_payable"),
|
||||
total: job.job_totals.totals.custPayable.other_customer_amount
|
||||
@@ -158,11 +177,26 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
total: job.job_totals.totals.custPayable.dep_taxes
|
||||
},
|
||||
|
||||
{
|
||||
key: t("jobs.labels.total_cust_payable"),
|
||||
total: job.job_totals.totals.custPayable.total,
|
||||
bold: true
|
||||
},
|
||||
...(bodyshop.intellipay_config?.enable_cash_discount
|
||||
? [
|
||||
{
|
||||
key: t("jobs.labels.total_cust_payable_cash_discount"),
|
||||
total: job.job_totals.totals.custPayable.total,
|
||||
bold: true
|
||||
},
|
||||
{
|
||||
key: t("jobs.labels.total_cust_payable"),
|
||||
render: <JobTotalsCashDiscount amountDinero={job.job_totals.totals.custPayable.total} />,
|
||||
bold: true
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
key: t("jobs.labels.total_cust_payable"),
|
||||
total: job.job_totals.totals.custPayable.total,
|
||||
bold: true
|
||||
}
|
||||
]),
|
||||
{
|
||||
key: t("jobs.labels.net_repairs"),
|
||||
total: job.job_totals.totals.net_repairs,
|
||||
@@ -188,7 +222,7 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
dataIndex: "total",
|
||||
key: "total",
|
||||
align: "right",
|
||||
render: (text, record) => Dinero(record.total).toFormat(),
|
||||
render: (text, record) => (record.render ? record.render : Dinero(record.total).toFormat()),
|
||||
width: "20%",
|
||||
onCell: (record, rowIndex) => {
|
||||
return { style: { fontWeight: record.bold && "bold" } };
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import { notification, Spin } from "antd";
|
||||
import axios from "axios";
|
||||
import Dinero from "dinero.js";
|
||||
import React, { useCallback, useEffect, useState } 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) => ({});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobTotalsCashDiscount);
|
||||
|
||||
export function JobTotalsCashDiscount({ bodyshop, amountDinero }) {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [fee, setFee] = useState(0);
|
||||
|
||||
const fetchData = useCallback(async () => {
|
||||
if (amountDinero && bodyshop) {
|
||||
setLoading(true);
|
||||
let response;
|
||||
try {
|
||||
response = await axios.post("/intellipay/checkfee", {
|
||||
bodyshop: { id: bodyshop.id, imexshopid: bodyshop.imexshopid, state: bodyshop.state },
|
||||
amount: Dinero(amountDinero).toFormat("0.00")
|
||||
});
|
||||
|
||||
if (response?.data?.error) {
|
||||
notification.open({
|
||||
type: "error",
|
||||
message:
|
||||
response.data?.error ||
|
||||
"Error encountered when contacting IntelliPay service to determine cash discounted price."
|
||||
});
|
||||
} else {
|
||||
setFee(response.data?.fee || 0);
|
||||
}
|
||||
} catch (error) {
|
||||
notification.open({
|
||||
type: "error",
|
||||
message:
|
||||
error.response?.data?.error ||
|
||||
"Error encountered when contacting IntelliPay service to determine cash discounted price."
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
}, [amountDinero, bodyshop]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, [fetchData, bodyshop, amountDinero]);
|
||||
|
||||
if (loading) return <Spin size="small" />;
|
||||
return Dinero(amountDinero)
|
||||
.add(Dinero({ amount: Math.round(fee * 100) }))
|
||||
.toFormat();
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||
import FormItemPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
||||
@@ -12,7 +13,6 @@ import Car from "../job-damage-visual/job-damage-visual.component";
|
||||
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
|
||||
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
|
||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
@@ -185,6 +185,9 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
||||
<Form.Item label={t("jobs.fields.towin")} name="towin" valuePropName="checked">
|
||||
<Switch disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item label={t("jobs.fields.tlos_ind")} name="tlos_ind" valuePropName="checked">
|
||||
<Switch disabled={jobRO} />
|
||||
</Form.Item>
|
||||
</FormRow>
|
||||
</Col>
|
||||
<Col {...lossColDamage}>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { Button, Col, Form, Input, Row, Select, Space, Switch, Typography } from "antd";
|
||||
import axios from "axios";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -8,13 +7,14 @@ import { createStructuredSelector } from "reselect";
|
||||
import { calculateScheduleLoad } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import dayjs from "../../utils/day";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
||||
import EmailInput from "../form-items-formatted/email-form-item.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import ScheduleDayViewContainer from "../schedule-day-view/schedule-day-view.container";
|
||||
import ScheduleExistingAppointmentsList from "../schedule-existing-appointments-list/schedule-existing-appointments-list.component";
|
||||
import "./schedule-job-modal.scss";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -84,7 +84,7 @@ export function ScheduleJobModalComponent({
|
||||
}
|
||||
]}
|
||||
>
|
||||
<DateTimePicker onBlur={handleDateBlur} onlyFuture />
|
||||
<DateTimePicker onBlur={handleDateBlur} onlyFuture isSeparatedTime />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="scheduled_completion"
|
||||
|
||||
@@ -142,7 +142,7 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
|
||||
rome: [
|
||||
{
|
||||
key: "intellipay",
|
||||
label: t("bodyshop.labels.intellipay"),
|
||||
label: InstanceRenderManager({ rome: t("bodyshop.labels.romepay"), imex: t("bodyshop.labels.imexpay") }),
|
||||
children: <ShopInfoIntellipay form={form} />
|
||||
}
|
||||
],
|
||||
|
||||
@@ -37,17 +37,6 @@ export function ShopInfoIntellipay({ bodyshop, form }) {
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.intellipay_config.cash_discount_percentage")}
|
||||
valuePropName="checked"
|
||||
dependencies={[["intellipay_config", "enable_cash_discount"]]}
|
||||
name={["intellipay_config", "cash_discount_percentage"]}
|
||||
rules={[
|
||||
({ getFieldsValue }) => ({ required: form.getFieldValue(["intellipay_config", "enable_cash_discount"]) })
|
||||
]}
|
||||
>
|
||||
<InputNumber min={0} max={100} precision={1} suffix='%'/>
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -692,6 +692,7 @@ export const GET_JOB_BY_PK = gql`
|
||||
tax_str_rt
|
||||
tax_sub_rt
|
||||
tax_tow_rt
|
||||
tlos_ind
|
||||
towin
|
||||
towing_payable
|
||||
unit_number
|
||||
|
||||
@@ -665,9 +665,9 @@
|
||||
"employees": "Employees",
|
||||
"estimators": "Estimators",
|
||||
"filehandlers": "Adjusters",
|
||||
"imexpay": "ImEX Pay",
|
||||
"insurancecos": "Insurance Companies",
|
||||
"intakechecklist": "Intake Checklist",
|
||||
"intellipay": "IntelliPay",
|
||||
"intellipay_cash_discount": "Please ensure that cash discounting has been enabled on your merchant account. Reach out to IntelliPay Support if you need assistance. ",
|
||||
"jobstatuses": "Job Statuses",
|
||||
"laborrates": "Labor Rates",
|
||||
@@ -693,11 +693,14 @@
|
||||
"profits": "Profit Centers",
|
||||
"sales_tax_codes": "Sales Tax Codes",
|
||||
"tax_accounts": "Tax Accounts",
|
||||
"title": "Responsibility Centers"
|
||||
"title": "Responsibility Centers",
|
||||
"ttl_adjustment": "",
|
||||
"ttl_tax_adjustment": ""
|
||||
},
|
||||
"roguard": {
|
||||
"title": "RO Guard"
|
||||
},
|
||||
"romepay": "Rome Pay",
|
||||
"scheduling": "SMART Scheduling",
|
||||
"scoreboardsetup": "Scoreboard Setup",
|
||||
"shopinfo": "Shop Information",
|
||||
@@ -1254,6 +1257,7 @@
|
||||
"sunday": "Sunday",
|
||||
"text": "Text",
|
||||
"thursday": "Thursday",
|
||||
"time": "Select Time",
|
||||
"total": "Total",
|
||||
"totals": "Totals",
|
||||
"tuesday": "Tuesday",
|
||||
@@ -1873,6 +1877,7 @@
|
||||
"tax_str_rt": "Storage Tax Rate",
|
||||
"tax_sub_rt": "Sublet Tax Rate",
|
||||
"tax_tow_rt": "Towing Tax Rate",
|
||||
"tlos_ind": "Total Loss Indicator",
|
||||
"towin": "Tow In",
|
||||
"towing_payable": "Towing Payable",
|
||||
"unitnumber": "Unit #",
|
||||
@@ -2107,7 +2112,9 @@
|
||||
"threshhold": "Max Threshold: ${{amount}}",
|
||||
"total_cost": "Total Cost",
|
||||
"total_cust_payable": "Total Customer Amount Payable",
|
||||
"total_cust_payable_cash_discount": "$t(jobs.labels.total_cust_payable) (Cash Discounted)",
|
||||
"total_repairs": "Total Repairs",
|
||||
"total_repairs_cash_discount": "Total Repairs (Cash Discounted)",
|
||||
"total_sales": "Total Sales",
|
||||
"total_sales_tax": "Total Sales Tax",
|
||||
"totals": "Totals",
|
||||
@@ -2850,22 +2857,22 @@
|
||||
"statistics": {
|
||||
"jobs_in_production": "Jobs in Production",
|
||||
"tasks_in_production": "Tasks in Production",
|
||||
"tasks_on_board": "Tasks on Board",
|
||||
"tasks_in_view": "Tasks in View",
|
||||
"tasks_on_board": "Tasks on Board",
|
||||
"total_amount_in_production": "Dollars in Production",
|
||||
"total_amount_on_board": "Dollars on Board",
|
||||
"total_amount_in_view": "Dollars in View",
|
||||
"total_amount_on_board": "Dollars on Board",
|
||||
"total_hours_in_production": "Hours in Production",
|
||||
"total_hours_on_board": "Hours on Board",
|
||||
"total_hours_in_view": "Hours in View",
|
||||
"total_jobs_on_board": "Jobs on Board",
|
||||
"total_hours_on_board": "Hours on Board",
|
||||
"total_jobs_in_view": "Jobs in View",
|
||||
"total_jobs_on_board": "Jobs on Board",
|
||||
"total_lab_in_production": "Body Hours in Production",
|
||||
"total_lab_on_board": "Body Hours on Board",
|
||||
"total_lab_in_view": "Body Hours in View",
|
||||
"total_lab_on_board": "Body Hours on Board",
|
||||
"total_lar_in_production": "Refinish Hours in Production",
|
||||
"total_lar_on_board": "Refinish Hours on Board",
|
||||
"total_lar_in_view": "Refinish Hours in View"
|
||||
"total_lar_in_view": "Refinish Hours in View",
|
||||
"total_lar_on_board": "Refinish Hours on Board"
|
||||
},
|
||||
"statistics_title": "Statistics"
|
||||
},
|
||||
@@ -2876,22 +2883,22 @@
|
||||
"jobs_in_production": "Jobs in Production",
|
||||
"tasks": "Tasks",
|
||||
"tasks_in_production": "Tasks in Production",
|
||||
"tasks_on_board": "Tasks on Board",
|
||||
"tasks_in_view": "Tasks in View",
|
||||
"tasks_on_board": "Tasks on Board",
|
||||
"total_amount_in_production": "Dollars in Production",
|
||||
"total_amount_on_board": "Dollars on Board",
|
||||
"total_amount_in_view": "Dollars in View",
|
||||
"total_amount_on_board": "Dollars on Board",
|
||||
"total_hours_in_production": "Hours in Production",
|
||||
"total_hours_on_board": "Hours on Board",
|
||||
"total_hours_in_view": "Hours in View",
|
||||
"total_jobs_on_board": "Jobs on Board",
|
||||
"total_hours_on_board": "Hours on Board",
|
||||
"total_jobs_in_view": "Jobs in View",
|
||||
"total_jobs_on_board": "Jobs on Board",
|
||||
"total_lab_in_production": "Body Hours in Production",
|
||||
"total_lab_on_board": "Body Hours on Board",
|
||||
"total_lab_in_view": "Body Hours in View",
|
||||
"total_lab_on_board": "Body Hours on Board",
|
||||
"total_lar_in_production": "Refinish Hours in Production",
|
||||
"total_lar_on_board": "Refinish Hours on Board",
|
||||
"total_lar_in_view": "Refinish Hours in View"
|
||||
"total_lar_in_view": "Refinish Hours in View",
|
||||
"total_lar_on_board": "Refinish Hours on Board"
|
||||
},
|
||||
"successes": {
|
||||
"removed": "Job removed from production."
|
||||
|
||||
@@ -665,9 +665,9 @@
|
||||
"employees": "",
|
||||
"estimators": "",
|
||||
"filehandlers": "",
|
||||
"imexpay": "",
|
||||
"insurancecos": "",
|
||||
"intakechecklist": "",
|
||||
"intellipay": "",
|
||||
"intellipay_cash_discount": "",
|
||||
"jobstatuses": "",
|
||||
"laborrates": "",
|
||||
@@ -693,11 +693,14 @@
|
||||
"profits": "",
|
||||
"sales_tax_codes": "",
|
||||
"tax_accounts": "",
|
||||
"title": ""
|
||||
"title": "",
|
||||
"ttl_adjustment": "",
|
||||
"ttl_tax_adjustment": ""
|
||||
},
|
||||
"roguard": {
|
||||
"title": ""
|
||||
},
|
||||
"romepay": "",
|
||||
"scheduling": "",
|
||||
"scoreboardsetup": "",
|
||||
"shopinfo": "",
|
||||
@@ -1254,6 +1257,7 @@
|
||||
"sunday": "",
|
||||
"text": "",
|
||||
"thursday": "",
|
||||
"time": "",
|
||||
"total": "",
|
||||
"totals": "",
|
||||
"tuesday": "",
|
||||
@@ -1873,6 +1877,7 @@
|
||||
"tax_str_rt": "",
|
||||
"tax_sub_rt": "",
|
||||
"tax_tow_rt": "",
|
||||
"tlos_ind": "",
|
||||
"towin": "",
|
||||
"towing_payable": "Remolque a pagar",
|
||||
"unitnumber": "Unidad #",
|
||||
@@ -2107,7 +2112,9 @@
|
||||
"threshhold": "",
|
||||
"total_cost": "",
|
||||
"total_cust_payable": "",
|
||||
"total_cust_payable_cash_discount": "",
|
||||
"total_repairs": "",
|
||||
"total_repairs_cash_discount": "",
|
||||
"total_sales": "",
|
||||
"total_sales_tax": "",
|
||||
"totals": "",
|
||||
@@ -2850,22 +2857,22 @@
|
||||
"statistics": {
|
||||
"jobs_in_production": "",
|
||||
"tasks_in_production": "",
|
||||
"tasks_on_board": "",
|
||||
"tasks_in_view": "",
|
||||
"tasks_on_board": "",
|
||||
"total_amount_in_production": "",
|
||||
"total_amount_on_board": "",
|
||||
"total_amount_in_view": "",
|
||||
"total_amount_on_board": "",
|
||||
"total_hours_in_production": "",
|
||||
"total_hours_on_board": "",
|
||||
"total_hours_in_view": "",
|
||||
"total_jobs_on_board": "",
|
||||
"total_hours_on_board": "",
|
||||
"total_jobs_in_view": "",
|
||||
"total_jobs_on_board": "",
|
||||
"total_lab_in_production": "",
|
||||
"total_lab_on_board": "",
|
||||
"total_lab_in_view": "",
|
||||
"total_lab_on_board": "",
|
||||
"total_lar_in_production": "",
|
||||
"total_lar_on_board": "",
|
||||
"total_lar_in_view": ""
|
||||
"total_lar_in_view": "",
|
||||
"total_lar_on_board": ""
|
||||
},
|
||||
"statistics_title": ""
|
||||
},
|
||||
@@ -2876,22 +2883,22 @@
|
||||
"jobs_in_production": "",
|
||||
"tasks": "",
|
||||
"tasks_in_production": "",
|
||||
"tasks_on_board": "",
|
||||
"tasks_in_view": "",
|
||||
"tasks_on_board": "",
|
||||
"total_amount_in_production": "",
|
||||
"total_amount_on_board": "",
|
||||
"total_amount_in_view": "",
|
||||
"total_amount_on_board": "",
|
||||
"total_hours_in_production": "",
|
||||
"total_hours_on_board": "",
|
||||
"total_hours_in_view": "",
|
||||
"total_jobs_on_board": "",
|
||||
"total_hours_on_board": "",
|
||||
"total_jobs_in_view": "",
|
||||
"total_jobs_on_board": "",
|
||||
"total_lab_in_production": "",
|
||||
"total_lab_on_board": "",
|
||||
"total_lab_in_view": "",
|
||||
"total_lab_on_board": "",
|
||||
"total_lar_in_production": "",
|
||||
"total_lar_on_board": "",
|
||||
"total_lar_in_view": ""
|
||||
"total_lar_in_view": "",
|
||||
"total_lar_on_board": ""
|
||||
},
|
||||
"successes": {
|
||||
"removed": ""
|
||||
|
||||
@@ -665,9 +665,9 @@
|
||||
"employees": "",
|
||||
"estimators": "",
|
||||
"filehandlers": "",
|
||||
"imexpay": "",
|
||||
"insurancecos": "",
|
||||
"intakechecklist": "",
|
||||
"intellipay": "",
|
||||
"intellipay_cash_discount": "",
|
||||
"jobstatuses": "",
|
||||
"laborrates": "",
|
||||
@@ -693,11 +693,14 @@
|
||||
"profits": "",
|
||||
"sales_tax_codes": "",
|
||||
"tax_accounts": "",
|
||||
"title": ""
|
||||
"title": "",
|
||||
"ttl_adjustment": "",
|
||||
"ttl_tax_adjustment": ""
|
||||
},
|
||||
"roguard": {
|
||||
"title": ""
|
||||
},
|
||||
"romepay": "",
|
||||
"scheduling": "",
|
||||
"scoreboardsetup": "",
|
||||
"shopinfo": "",
|
||||
@@ -1254,6 +1257,7 @@
|
||||
"sunday": "",
|
||||
"text": "",
|
||||
"thursday": "",
|
||||
"time": "",
|
||||
"total": "",
|
||||
"totals": "",
|
||||
"tuesday": "",
|
||||
@@ -1873,6 +1877,7 @@
|
||||
"tax_str_rt": "",
|
||||
"tax_sub_rt": "",
|
||||
"tax_tow_rt": "",
|
||||
"tlos_ind": "",
|
||||
"towin": "",
|
||||
"towing_payable": "Remorquage à payer",
|
||||
"unitnumber": "Unité #",
|
||||
@@ -2107,7 +2112,9 @@
|
||||
"threshhold": "",
|
||||
"total_cost": "",
|
||||
"total_cust_payable": "",
|
||||
"total_cust_payable_cash_discount": "",
|
||||
"total_repairs": "",
|
||||
"total_repairs_cash_discount": "",
|
||||
"total_sales": "",
|
||||
"total_sales_tax": "",
|
||||
"totals": "",
|
||||
@@ -2850,22 +2857,22 @@
|
||||
"statistics": {
|
||||
"jobs_in_production": "",
|
||||
"tasks_in_production": "",
|
||||
"tasks_on_board": "",
|
||||
"tasks_in_view": "",
|
||||
"tasks_on_board": "",
|
||||
"total_amount_in_production": "",
|
||||
"total_amount_on_board": "",
|
||||
"total_amount_in_view": "",
|
||||
"total_amount_on_board": "",
|
||||
"total_hours_in_production": "",
|
||||
"total_hours_on_board": "",
|
||||
"total_hours_in_view": "",
|
||||
"total_jobs_on_board": "",
|
||||
"total_hours_on_board": "",
|
||||
"total_jobs_in_view": "",
|
||||
"total_jobs_on_board": "",
|
||||
"total_lab_in_production": "",
|
||||
"total_lab_on_board": "",
|
||||
"total_lab_in_view": "",
|
||||
"total_lab_on_board": "",
|
||||
"total_lar_in_production": "",
|
||||
"total_lar_on_board": "",
|
||||
"total_lar_in_view": ""
|
||||
"total_lar_in_view": "",
|
||||
"total_lar_on_board": ""
|
||||
},
|
||||
"statistics_title": ""
|
||||
},
|
||||
@@ -2876,22 +2883,22 @@
|
||||
"jobs_in_production": "",
|
||||
"tasks": "",
|
||||
"tasks_in_production": "",
|
||||
"tasks_on_board": "",
|
||||
"tasks_in_view": "",
|
||||
"tasks_on_board": "",
|
||||
"total_amount_in_production": "",
|
||||
"total_amount_on_board": "",
|
||||
"total_amount_in_view": "",
|
||||
"total_amount_on_board": "",
|
||||
"total_hours_in_production": "",
|
||||
"total_hours_on_board": "",
|
||||
"total_hours_in_view": "",
|
||||
"total_jobs_on_board": "",
|
||||
"total_hours_on_board": "",
|
||||
"total_jobs_in_view": "",
|
||||
"total_jobs_on_board": "",
|
||||
"total_lab_in_production": "",
|
||||
"total_lab_on_board": "",
|
||||
"total_lab_in_view": "",
|
||||
"total_lab_on_board": "",
|
||||
"total_lar_in_production": "",
|
||||
"total_lar_on_board": "",
|
||||
"total_lar_in_view": ""
|
||||
"total_lar_in_view": "",
|
||||
"total_lar_on_board": ""
|
||||
},
|
||||
"successes": {
|
||||
"removed": ""
|
||||
|
||||
10
hasura/migrations/1731471670370_run_sql_migration/down.sql
Normal file
10
hasura/migrations/1731471670370_run_sql_migration/down.sql
Normal file
@@ -0,0 +1,10 @@
|
||||
-- Could not auto-generate a down migration.
|
||||
-- Please write an appropriate down migration for the SQL below:
|
||||
-- CREATE INDEX jobs_search_gin_ro_number ON jobs USING GIN ((ro_number) gin_trgm_ops);
|
||||
-- CREATE INDEX jobs_search_gin_ownrfn ON jobs USING GIN ((ownr_fn) gin_trgm_ops);
|
||||
-- CREATE INDEX jobs_search_gin_clm_no ON jobs USING GIN ((clm_no) gin_trgm_ops);
|
||||
-- CREATE INDEX jobs_search_gin_plate_no ON jobs USING GIN ((plate_no) gin_trgm_ops);
|
||||
-- CREATE INDEX jobs_search_gin_v_make_desc ON jobs USING GIN (( v_make_desc) gin_trgm_ops);
|
||||
-- CREATE INDEX jobs_search_gin_v_model_desc ON jobs USING GIN (( v_model_desc) gin_trgm_ops);
|
||||
-- CREATE INDEX jobs_search_gin_ownr_ln ON jobs USING GIN (( ownr_ln) gin_trgm_ops);
|
||||
-- CREATE INDEX jobs_search_gin_ownr_co_nm ON jobs USING GIN (( ownr_co_nm) gin_trgm_ops);
|
||||
8
hasura/migrations/1731471670370_run_sql_migration/up.sql
Normal file
8
hasura/migrations/1731471670370_run_sql_migration/up.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
CREATE INDEX jobs_search_gin_ro_number ON jobs USING GIN ((ro_number) gin_trgm_ops);
|
||||
CREATE INDEX jobs_search_gin_ownrfn ON jobs USING GIN ((ownr_fn) gin_trgm_ops);
|
||||
CREATE INDEX jobs_search_gin_clm_no ON jobs USING GIN ((clm_no) gin_trgm_ops);
|
||||
CREATE INDEX jobs_search_gin_plate_no ON jobs USING GIN ((plate_no) gin_trgm_ops);
|
||||
CREATE INDEX jobs_search_gin_v_make_desc ON jobs USING GIN (( v_make_desc) gin_trgm_ops);
|
||||
CREATE INDEX jobs_search_gin_v_model_desc ON jobs USING GIN (( v_model_desc) gin_trgm_ops);
|
||||
CREATE INDEX jobs_search_gin_ownr_ln ON jobs USING GIN (( ownr_ln) gin_trgm_ops);
|
||||
CREATE INDEX jobs_search_gin_ownr_co_nm ON jobs USING GIN (( ownr_co_nm) gin_trgm_ops);
|
||||
@@ -219,6 +219,7 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef,
|
||||
PaymentMethodRef: {
|
||||
value: paymentMethods[payment.type]
|
||||
},
|
||||
PrivateNote: payment.memo.length > 4000 ? payment.memo.substring(0, 4000).trim() : payment.memo.trim(),
|
||||
PaymentRefNum: payment.transactionid,
|
||||
...(invoices && invoices.length === 1 && invoices[0]
|
||||
? {
|
||||
|
||||
@@ -47,7 +47,11 @@ exports.default = async (req, res) => {
|
||||
}
|
||||
|
||||
// Send immediate response and continue processing.
|
||||
res.status(200).send();
|
||||
res.status(202).json({
|
||||
success: true,
|
||||
message: "Processing request ...",
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
try {
|
||||
logger.log("autohouse-start", "DEBUG", "api", null, null);
|
||||
@@ -146,7 +150,7 @@ async function processBatch(batch, start, end) {
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
autuhouseid: bodyshop.autuhouseid,
|
||||
autohouseid: bodyshop.autohouseid,
|
||||
fatal: true,
|
||||
errors: [error.toString()]
|
||||
});
|
||||
@@ -154,7 +158,7 @@ async function processBatch(batch, start, end) {
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
autuhouseid: bodyshop.autuhouseid,
|
||||
autohouseid: bodyshop.autohouseid,
|
||||
errors: erroredJobs.map((ej) => ({
|
||||
ro_number: ej.job?.ro_number,
|
||||
jobid: ej.job?.id,
|
||||
@@ -176,9 +180,8 @@ async function uploadViaSFTP(allxmlsToUpload) {
|
||||
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
try {
|
||||
logger.log("autohouse-sftp-upload", "DEBUG", "api", null, { filename: xmlObj.filename });
|
||||
xmlObj.result = await sftp.put(Buffer.from(xmlObj.xml), `${xmlObj.filename}`);
|
||||
logger.log("autohouse-sftp-upload-result", "DEBUG", "api", null, {
|
||||
logger.log("autohouse-sftp-upload", "DEBUG", "api", null, {
|
||||
filename: xmlObj.filename,
|
||||
result: xmlObj.result
|
||||
});
|
||||
@@ -609,10 +612,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
};
|
||||
return ret;
|
||||
} catch (error) {
|
||||
logger.log("autohouse-job-calculate-error", "ERROR", "api", null, {
|
||||
error
|
||||
});
|
||||
|
||||
logger.log("autohouse-job-calculate-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||
errorCallback({ jobid: job.id, ro_number: job.ro_number, error });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -39,7 +39,11 @@ exports.default = async (req, res) => {
|
||||
}
|
||||
|
||||
// Send immediate response and continue processing.
|
||||
res.status(200).send();
|
||||
res.status(202).json({
|
||||
success: true,
|
||||
message: "Processing request ...",
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
try {
|
||||
logger.log("chatter-start", "DEBUG", "api", null, null);
|
||||
@@ -176,9 +180,8 @@ async function uploadViaSFTP(allcsvsToUpload) {
|
||||
|
||||
for (const csvObj of allcsvsToUpload) {
|
||||
try {
|
||||
logger.log("chatter-sftp-upload", "DEBUG", "api", null, { filename: csvObj.filename });
|
||||
csvObj.result = await sftp.put(Buffer.from(csvObj.csv), `${csvObj.filename}`);
|
||||
logger.log("chatter-sftp-upload-result", "DEBUG", "api", null, {
|
||||
logger.log("chatter-sftp-upload", "DEBUG", "api", null, {
|
||||
filename: csvObj.filename,
|
||||
result: csvObj.result
|
||||
});
|
||||
|
||||
@@ -26,174 +26,184 @@ const ftpSetup = {
|
||||
password: process.env.CLAIMSCORP_PASSWORD,
|
||||
debug: (message, ...data) => logger.log(message, "DEBUG", "api", null, data),
|
||||
algorithms: {
|
||||
serverHostKey: ["ssh-rsa", "ssh-dss"]
|
||||
serverHostKey: ["ssh-rsa", "ssh-dss", "rsa-sha2-256", "rsa-sha2-512", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384"]
|
||||
}
|
||||
};
|
||||
|
||||
const allxmlsToUpload = [];
|
||||
const allErrors = [];
|
||||
|
||||
exports.default = async (req, res) => {
|
||||
// Only process if in production environment.
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
res.sendStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
//Query for the List of Bodyshop Clients.
|
||||
logger.log("claimscorp-start", "DEBUG", "api", null, null);
|
||||
const { bodyshops } = await client.request(queries.GET_CLAIMSCORP_SHOPS);
|
||||
|
||||
const specificShopIds = req.body.bodyshopIds; // ['uuid]
|
||||
const { start, end, skipUpload } = req.body; //YYYY-MM-DD
|
||||
// Only process if the appropriate token is provided.
|
||||
if (req.headers["x-imex-auth"] !== process.env.AUTOHOUSE_AUTH_TOKEN) {
|
||||
res.sendStatus(401);
|
||||
return;
|
||||
}
|
||||
const allxmlsToUpload = [];
|
||||
const allErrors = [];
|
||||
|
||||
// Send immediate response and continue processing.
|
||||
res.status(202).json({
|
||||
success: true,
|
||||
message: "Processing request ...",
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
try {
|
||||
for (const bodyshop of specificShopIds ? bodyshops.filter((b) => specificShopIds.includes(b.id)) : bodyshops) {
|
||||
logger.log("claimscorp-start", "DEBUG", "api", null, null);
|
||||
const { bodyshops } = await client.request(queries.GET_CLAIMSCORP_SHOPS); //Query for the List of Bodyshop Clients.
|
||||
const specificShopIds = req.body.bodyshopIds; // ['uuid];
|
||||
const { start, end, skipUpload } = req.body; //YYYY-MM-DD
|
||||
|
||||
const batchSize = 10;
|
||||
|
||||
const shopsToProcess =
|
||||
specificShopIds?.length > 0 ? bodyshops.filter((shop) => specificShopIds.includes(shop.id)) : bodyshops;
|
||||
logger.log("claimscorp-shopsToProcess-generated", "DEBUG", "api", null, null);
|
||||
|
||||
if (shopsToProcess.length === 0) {
|
||||
logger.log("claimscorp-shopsToProcess-empty", "DEBUG", "api", null, null);
|
||||
return;
|
||||
}
|
||||
const batchPromises = [];
|
||||
for (let i = 0; i < shopsToProcess.length; i += batchSize) {
|
||||
const batch = shopsToProcess.slice(i, i + batchSize);
|
||||
const batchPromise = (async () => {
|
||||
await processBatch(batch, start, end);
|
||||
|
||||
if (skipUpload) {
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
||||
}
|
||||
} else {
|
||||
await uploadViaSFTP(allxmlsToUpload);
|
||||
}
|
||||
})();
|
||||
batchPromises.push(batchPromise);
|
||||
}
|
||||
await Promise.all(batchPromises);
|
||||
await sendServerEmail({
|
||||
subject: `ClaimsCorp Report ${moment().format("MM-DD-YY")}`,
|
||||
text: `Errors:\n${JSON.stringify(allErrors, null, 2)}\n\nUploaded:\n${JSON.stringify(
|
||||
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count, result: x.result })),
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
});
|
||||
|
||||
logger.log("claimscorp-end", "DEBUG", "api", null, null);
|
||||
} catch (error) {
|
||||
logger.log("claimscorp-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||
}
|
||||
};
|
||||
|
||||
async function processBatch(batch, start, end) {
|
||||
for (const bodyshop of batch) {
|
||||
const erroredJobs = [];
|
||||
try {
|
||||
logger.log("claimscorp-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||
shopname: bodyshop.shopname
|
||||
});
|
||||
const erroredJobs = [];
|
||||
try {
|
||||
const { jobs, bodyshops_by_pk } = await client.request(queries.CLAIMSCORP_QUERY, {
|
||||
bodyshopid: bodyshop.id,
|
||||
start: start ? moment(start).startOf("day") : moment().subtract(5, "days").startOf("day"),
|
||||
...(end && { end: moment(end).endOf("day") })
|
||||
});
|
||||
|
||||
const claimsCorpObject = {
|
||||
DataFeed: {
|
||||
ShopInfo: {
|
||||
ShopID: bodyshops_by_pk.claimscorpid,
|
||||
ShopName: bodyshops_by_pk.shopname,
|
||||
RO: jobs.map((j) =>
|
||||
CreateRepairOrderTag({ ...j, bodyshop: bodyshops_by_pk }, function ({ job, error }) {
|
||||
erroredJobs.push({ job: job, error: error.toString() });
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (erroredJobs.length > 0) {
|
||||
logger.log("claimscorp-failed-jobs", "ERROR", "api", bodyshop.id, {
|
||||
count: erroredJobs.length,
|
||||
jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
|
||||
});
|
||||
}
|
||||
|
||||
var ret = builder
|
||||
.create(
|
||||
{
|
||||
// version: "1.0",
|
||||
// encoding: "UTF-8",
|
||||
//keepNullNodes: true,
|
||||
},
|
||||
claimsCorpObject
|
||||
)
|
||||
.end({ allowEmptyTags: true });
|
||||
|
||||
allxmlsToUpload.push({
|
||||
count: claimsCorpObject.DataFeed.ShopInfo.RO.length,
|
||||
xml: ret,
|
||||
filename: `${bodyshop.claimscorpid}-${moment().format("YYYYMMDDTHHMMss")}.xml`
|
||||
});
|
||||
|
||||
logger.log("claimscorp-end-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||
shopname: bodyshop.shopname
|
||||
});
|
||||
} catch (error) {
|
||||
//Error at the shop level.
|
||||
logger.log("claimscorp-error-shop", "ERROR", "api", bodyshop.id, {
|
||||
...error
|
||||
});
|
||||
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
claimscorpid: bodyshop.claimscorpid,
|
||||
fatal: true,
|
||||
errors: [error.toString()]
|
||||
});
|
||||
} finally {
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
claimscorpid: bodyshop.claimscorpid,
|
||||
errors: erroredJobs.map((ej) => ({
|
||||
ro_number: ej.job?.ro_number,
|
||||
jobid: ej.job?.id,
|
||||
error: ej.error
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (skipUpload) {
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
||||
}
|
||||
|
||||
res.json(allxmlsToUpload);
|
||||
sendServerEmail({
|
||||
subject: `ClaimsCorp Report ${moment().format("MM-DD-YY")}`,
|
||||
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||
Uploaded: ${JSON.stringify(
|
||||
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
||||
null,
|
||||
2
|
||||
)}
|
||||
`
|
||||
const { jobs, bodyshops_by_pk } = await client.request(queries.CLAIMSCORP_QUERY, {
|
||||
bodyshopid: bodyshop.id,
|
||||
start: start ? moment(start).startOf("day") : moment().subtract(5, "days").startOf("day"),
|
||||
...(end && { end: moment(end).endOf("day") })
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let sftp = new Client();
|
||||
sftp.on("error", (errors) =>
|
||||
logger.log("claimscorp-sftp-error", "ERROR", "api", null, {
|
||||
...errors
|
||||
})
|
||||
);
|
||||
try {
|
||||
//Connect to the FTP and upload all.
|
||||
const claimsCorpObject = {
|
||||
DataFeed: {
|
||||
ShopInfo: {
|
||||
ShopID: bodyshops_by_pk.claimscorpid,
|
||||
ShopName: bodyshops_by_pk.shopname,
|
||||
RO: jobs.map((j) =>
|
||||
CreateRepairOrderTag({ ...j, bodyshop: bodyshops_by_pk }, function ({ job, error }) {
|
||||
erroredJobs.push({ job: job, error: error.toString() });
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await sftp.connect(ftpSetup);
|
||||
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
logger.log("claimscorp-sftp-upload", "DEBUG", "api", null, {
|
||||
filename: xmlObj.filename
|
||||
});
|
||||
|
||||
const uploadResult = await sftp.put(Buffer.from(xmlObj.xml), `/${xmlObj.filename}`);
|
||||
logger.log("claimscorp-sftp-upload-result", "DEBUG", "api", null, {
|
||||
uploadResult
|
||||
if (erroredJobs.length > 0) {
|
||||
logger.log("claimscorp-failed-jobs", "ERROR", "api", bodyshop.id, {
|
||||
count: erroredJobs.length,
|
||||
jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
|
||||
});
|
||||
}
|
||||
|
||||
//***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml
|
||||
const ret = builder.create({}, claimsCorpObject).end({ allowEmptyTags: true });
|
||||
|
||||
allxmlsToUpload.push({
|
||||
count: claimsCorpObject.DataFeed.ShopInfo.RO.length,
|
||||
xml: ret,
|
||||
filename: `${bodyshop.claimscorpid}-${moment().format("YYYYMMDDTHHMMss")}.xml`
|
||||
});
|
||||
|
||||
logger.log("claimscorp-end-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||
shopname: bodyshop.shopname
|
||||
});
|
||||
} catch (error) {
|
||||
logger.log("claimscorp-sftp-error", "ERROR", "api", null, {
|
||||
...error
|
||||
//Error at the shop level.
|
||||
logger.log("claimscorp-error-shop", "ERROR", "api", bodyshop.id, { error: error.message, stack: error.stack });
|
||||
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
claimscorpid: bodyshop.claimscorpid,
|
||||
fatal: true,
|
||||
errors: [error.toString()]
|
||||
});
|
||||
} finally {
|
||||
sftp.end();
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
claimscorpid: bodyshop.claimscorpid,
|
||||
errors: erroredJobs.map((ej) => ({
|
||||
ro_number: ej.job?.ro_number,
|
||||
jobid: ej.job?.id,
|
||||
error: ej.error
|
||||
}))
|
||||
});
|
||||
}
|
||||
sendServerEmail({
|
||||
subject: `ClaimsCorp Report ${moment().format("MM-DD-YY")}`,
|
||||
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||
Uploaded: ${JSON.stringify(
|
||||
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
||||
null,
|
||||
2
|
||||
)}
|
||||
`
|
||||
});
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
res.status(200).json(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function uploadViaSFTP(allxmlsToUpload) {
|
||||
const sftp = new Client();
|
||||
sftp.on("error", (errors) =>
|
||||
logger.log("claimscorp-sftp-connection-error", "ERROR", "api", null, { error: errors.message, stack: errors.stack })
|
||||
);
|
||||
try {
|
||||
//Connect to the FTP and upload all.
|
||||
await sftp.connect(ftpSetup);
|
||||
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
try {
|
||||
xmlObj.result = await sftp.put(Buffer.from(xmlObj.xml), `${xmlObj.filename}`);
|
||||
logger.log("claimscorp-sftp-upload", "DEBUG", "api", null, {
|
||||
filename: xmlObj.filename,
|
||||
result: xmlObj.result
|
||||
});
|
||||
} catch (error) {
|
||||
logger.log("claimscorp-sftp-upload-error", "ERROR", "api", null, {
|
||||
filename: xmlObj.filename,
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log("claimscorp-sftp-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||
throw error;
|
||||
} finally {
|
||||
sftp.end();
|
||||
}
|
||||
}
|
||||
|
||||
const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
//Level 2
|
||||
@@ -445,10 +455,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
};
|
||||
return ret;
|
||||
} catch (error) {
|
||||
logger.log("claimscorp-job-calculate-error", "ERROR", "api", null, {
|
||||
error
|
||||
});
|
||||
|
||||
logger.log("claimscorp-job-calculate-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||
errorCallback({ jobid: job.id, ro_number: job.ro_number, error });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -16,8 +16,7 @@ const { sendServerEmail } = require("../email/sendemail");
|
||||
const DineroFormat = "0,0.00";
|
||||
const DateFormat = "MM/DD/YYYY";
|
||||
|
||||
const repairOpCodes = ["OP4", "OP9", "OP10"];
|
||||
const replaceOpCodes = ["OP2", "OP5", "OP11", "OP12"];
|
||||
const kaizenShopsIDs = ["SUMMIT", "STRATHMORE", "SUNRIDGE", "SHAW"];
|
||||
|
||||
const ftpSetup = {
|
||||
host: process.env.KAIZEN_HOST,
|
||||
@@ -30,173 +29,179 @@ const ftpSetup = {
|
||||
}
|
||||
};
|
||||
|
||||
const allxmlsToUpload = [];
|
||||
const allErrors = [];
|
||||
|
||||
exports.default = async (req, res) => {
|
||||
// Only process if in production environment.
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
res.sendStatus(403);
|
||||
return;
|
||||
}
|
||||
|
||||
//Query for the List of Bodyshop Clients.
|
||||
logger.log("kaizen-start", "DEBUG", "api", null, null);
|
||||
const kaizenShopsIDs = ["SUMMIT", "STRATHMORE", "SUNRIDGE", "SHAW"];
|
||||
|
||||
const { bodyshops } = await client.request(queries.GET_KAIZEN_SHOPS, {
|
||||
imexshopid: kaizenShopsIDs
|
||||
});
|
||||
|
||||
const specificShopIds = req.body.bodyshopIds; // ['uuid]
|
||||
const { start, end, skipUpload } = req.body; //YYYY-MM-DD
|
||||
// Only process if the appropriate token is provided.
|
||||
if (req.headers["x-imex-auth"] !== process.env.AUTOHOUSE_AUTH_TOKEN) {
|
||||
res.sendStatus(401);
|
||||
return;
|
||||
}
|
||||
const allxmlsToUpload = [];
|
||||
const allErrors = [];
|
||||
|
||||
// Send immediate response and continue processing.
|
||||
res.status(202).json({
|
||||
success: true,
|
||||
message: "Processing request ...",
|
||||
timestamp: new Date().toISOString()
|
||||
});
|
||||
|
||||
try {
|
||||
for (const bodyshop of specificShopIds ? bodyshops.filter((b) => specificShopIds.includes(b.id)) : bodyshops) {
|
||||
logger.log("kaizen-start", "DEBUG", "api", null, null);
|
||||
const { bodyshops } = await client.request(queries.GET_KAIZEN_SHOPS, { imexshopid: kaizenShopsIDs }); //Query for the List of Bodyshop Clients.
|
||||
const specificShopIds = req.body.bodyshopIds; // ['uuid];
|
||||
const { start, end, skipUpload } = req.body; //YYYY-MM-DD
|
||||
|
||||
const batchSize = 10;
|
||||
|
||||
const shopsToProcess =
|
||||
specificShopIds?.length > 0 ? bodyshops.filter((shop) => specificShopIds.includes(shop.id)) : bodyshops;
|
||||
logger.log("kaizen-shopsToProcess-generated", "DEBUG", "api", null, null);
|
||||
|
||||
if (shopsToProcess.length === 0) {
|
||||
logger.log("kaizen-shopsToProcess-empty", "DEBUG", "api", null, null);
|
||||
return;
|
||||
}
|
||||
const batchPromises = [];
|
||||
for (let i = 0; i < shopsToProcess.length; i += batchSize) {
|
||||
const batch = shopsToProcess.slice(i, i + batchSize);
|
||||
const batchPromise = (async () => {
|
||||
await processBatch(batch, start, end);
|
||||
|
||||
if (skipUpload) {
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
||||
}
|
||||
} else {
|
||||
await uploadViaSFTP(allxmlsToUpload);
|
||||
}
|
||||
})();
|
||||
batchPromises.push(batchPromise);
|
||||
}
|
||||
await Promise.all(batchPromises);
|
||||
await sendServerEmail({
|
||||
subject: `Kaizen Report ${moment().format("MM-DD-YY")}`,
|
||||
text: `Errors:\n${JSON.stringify(allErrors, null, 2)}\n\nUploaded:\n${JSON.stringify(
|
||||
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count, result: x.result })),
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
});
|
||||
|
||||
logger.log("kaizen-end", "DEBUG", "api", null, null);
|
||||
} catch (error) {
|
||||
logger.log("kaizen-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||
}
|
||||
};
|
||||
|
||||
async function processBatch(batch, start, end) {
|
||||
for (const bodyshop of batch) {
|
||||
const erroredJobs = [];
|
||||
try {
|
||||
logger.log("kaizen-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||
shopname: bodyshop.shopname
|
||||
});
|
||||
const erroredJobs = [];
|
||||
try {
|
||||
const { jobs, bodyshops_by_pk } = await client.request(queries.KAIZEN_QUERY, {
|
||||
bodyshopid: bodyshop.id,
|
||||
start: start ? moment(start).startOf("day") : moment().subtract(5, "days").startOf("day"),
|
||||
...(end && { end: moment(end).endOf("day") })
|
||||
});
|
||||
|
||||
const kaizenObject = {
|
||||
DataFeed: {
|
||||
ShopInfo: {
|
||||
ShopName: bodyshops_by_pk.shopname,
|
||||
Jobs: jobs.map((j) =>
|
||||
CreateRepairOrderTag({ ...j, bodyshop: bodyshops_by_pk }, function ({ job, error }) {
|
||||
erroredJobs.push({ job: job, error: error.toString() });
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (erroredJobs.length > 0) {
|
||||
logger.log("kaizen-failed-jobs", "ERROR", "api", bodyshop.id, {
|
||||
count: erroredJobs.length,
|
||||
jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
|
||||
});
|
||||
}
|
||||
|
||||
var ret = builder
|
||||
.create(
|
||||
{
|
||||
// version: "1.0",
|
||||
// encoding: "UTF-8",
|
||||
//keepNullNodes: true,
|
||||
},
|
||||
kaizenObject
|
||||
)
|
||||
.end({ allowEmptyTags: true });
|
||||
|
||||
allxmlsToUpload.push({
|
||||
count: kaizenObject.DataFeed.ShopInfo.Jobs.length,
|
||||
xml: ret,
|
||||
filename: `${bodyshop.shopname}-${moment().format("YYYYMMDDTHHMMss")}.xml`
|
||||
});
|
||||
|
||||
logger.log("kaizen-end-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||
shopname: bodyshop.shopname
|
||||
});
|
||||
} catch (error) {
|
||||
//Error at the shop level.
|
||||
logger.log("kaizen-error-shop", "ERROR", "api", bodyshop.id, {
|
||||
...error
|
||||
});
|
||||
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
shopname: bodyshop.shopname,
|
||||
fatal: true,
|
||||
errors: [error.toString()]
|
||||
});
|
||||
} finally {
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
shopname: bodyshop.shopname,
|
||||
errors: erroredJobs.map((ej) => ({
|
||||
ro_number: ej.job?.ro_number,
|
||||
jobid: ej.job?.id,
|
||||
error: ej.error
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (skipUpload) {
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
fs.writeFileSync(`./logs/${xmlObj.filename}`, xmlObj.xml);
|
||||
}
|
||||
|
||||
res.json(allxmlsToUpload);
|
||||
sendServerEmail({
|
||||
subject: `Kaizen Report ${moment().format("MM-DD-YY")}`,
|
||||
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||
Uploaded: ${JSON.stringify(
|
||||
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
||||
null,
|
||||
2
|
||||
)}
|
||||
`
|
||||
const { jobs, bodyshops_by_pk } = await client.request(queries.KAIZEN_QUERY, {
|
||||
bodyshopid: bodyshop.id,
|
||||
start: start ? moment(start).startOf("day") : moment().subtract(5, "days").startOf("day"),
|
||||
...(end && { end: moment(end).endOf("day") })
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let sftp = new Client();
|
||||
sftp.on("error", (errors) =>
|
||||
logger.log("kaizen-sftp-error", "ERROR", "api", null, {
|
||||
...errors
|
||||
})
|
||||
);
|
||||
try {
|
||||
//Connect to the FTP and upload all.
|
||||
const kaizenObject = {
|
||||
DataFeed: {
|
||||
ShopInfo: {
|
||||
ShopName: bodyshops_by_pk.shopname,
|
||||
Jobs: jobs.map((j) =>
|
||||
CreateRepairOrderTag({ ...j, bodyshop: bodyshops_by_pk }, function ({ job, error }) {
|
||||
erroredJobs.push({ job: job, error: error.toString() });
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
await sftp.connect(ftpSetup);
|
||||
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
logger.log("kaizen-sftp-upload", "DEBUG", "api", null, {
|
||||
filename: xmlObj.filename
|
||||
});
|
||||
|
||||
const uploadResult = await sftp.put(Buffer.from(xmlObj.xml), `/${xmlObj.filename}`);
|
||||
logger.log("kaizen-sftp-upload-result", "DEBUG", "api", null, {
|
||||
uploadResult
|
||||
if (erroredJobs.length > 0) {
|
||||
logger.log("kaizen-failed-jobs", "ERROR", "api", bodyshop.id, {
|
||||
count: erroredJobs.length,
|
||||
jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
|
||||
});
|
||||
}
|
||||
|
||||
//***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml
|
||||
const ret = builder.create({}, kaizenObject).end({ allowEmptyTags: true });
|
||||
|
||||
allxmlsToUpload.push({
|
||||
count: kaizenObject.DataFeed.ShopInfo.Jobs.length,
|
||||
xml: ret,
|
||||
filename: `${bodyshop.shopname}-${moment().format("YYYYMMDDTHHMMss")}.xml`
|
||||
});
|
||||
|
||||
logger.log("kaizen-end-shop-extract", "DEBUG", "api", bodyshop.id, {
|
||||
shopname: bodyshop.shopname
|
||||
});
|
||||
} catch (error) {
|
||||
logger.log("kaizen-sftp-error", "ERROR", "api", null, {
|
||||
...error
|
||||
//Error at the shop level.
|
||||
logger.log("kaizen-error-shop", "ERROR", "api", bodyshop.id, { error: error.message, stack: error.stack });
|
||||
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
shopname: bodyshop.shopname,
|
||||
fatal: true,
|
||||
errors: [error.toString()]
|
||||
});
|
||||
} finally {
|
||||
sftp.end();
|
||||
allErrors.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: bodyshop.imexshopid,
|
||||
shopname: bodyshop.shopname,
|
||||
errors: erroredJobs.map((ej) => ({
|
||||
ro_number: ej.job?.ro_number,
|
||||
jobid: ej.job?.id,
|
||||
error: ej.error
|
||||
}))
|
||||
});
|
||||
}
|
||||
sendServerEmail({
|
||||
subject: `Kaizen Report ${moment().format("MM-DD-YY")}`,
|
||||
text: `Errors: ${allErrors.map((e) => JSON.stringify(e, null, 2))}
|
||||
Uploaded: ${JSON.stringify(
|
||||
allxmlsToUpload.map((x) => ({ filename: x.filename, count: x.count })),
|
||||
null,
|
||||
2
|
||||
)}
|
||||
`
|
||||
});
|
||||
res.sendStatus(200);
|
||||
} catch (error) {
|
||||
res.status(200).json(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async function uploadViaSFTP(allxmlsToUpload) {
|
||||
const sftp = new Client();
|
||||
sftp.on("error", (errors) =>
|
||||
logger.log("kaizen-sftp-connection-error", "ERROR", "api", null, { error: errors.message, stack: errors.stack })
|
||||
);
|
||||
try {
|
||||
//Connect to the FTP and upload all.
|
||||
await sftp.connect(ftpSetup);
|
||||
|
||||
for (const xmlObj of allxmlsToUpload) {
|
||||
try {
|
||||
xmlObj.result = await sftp.put(Buffer.from(xmlObj.xml), `${xmlObj.filename}`);
|
||||
logger.log("kaizen-sftp-upload", "DEBUG", "api", null, {
|
||||
filename: xmlObj.filename,
|
||||
result: xmlObj.result
|
||||
});
|
||||
} catch (error) {
|
||||
logger.log("kaizen-sftp-upload-error", "ERROR", "api", null, {
|
||||
filename: xmlObj.filename,
|
||||
error: error.message,
|
||||
stack: error.stack
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log("kaizen-sftp-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||
throw error;
|
||||
} finally {
|
||||
sftp.end();
|
||||
}
|
||||
}
|
||||
|
||||
const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
//Level 2
|
||||
@@ -420,10 +425,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
|
||||
};
|
||||
return ret;
|
||||
} catch (error) {
|
||||
logger.log("kaizen-job-calculate-error", "ERROR", "api", null, {
|
||||
error
|
||||
});
|
||||
|
||||
logger.log("kaizen-job-calculate-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
||||
errorCallback({ jobid: job.id, ro_number: job.ro_number, error });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -149,6 +149,58 @@ exports.generate_payment_url = async (req, res) => {
|
||||
}
|
||||
};
|
||||
|
||||
//Reference: https://intellipay.com/dist/webapi26.html#operation/fee
|
||||
exports.checkfee = async (req, res) => {
|
||||
// Requires amount, bodyshop.imexshopid, and state? to get data.
|
||||
logger.log("intellipay-fee-check", "DEBUG", req.user?.email, null, null);
|
||||
|
||||
//If there's no amount, there can't be a fee. Skip the call.
|
||||
if (!req.body.amount || req.body.amount <= 0) {
|
||||
res.json({ fee: 0 });
|
||||
return;
|
||||
}
|
||||
|
||||
const shopCredentials = await getShopCredentials(req.body.bodyshop);
|
||||
|
||||
try {
|
||||
const options = {
|
||||
method: "POST",
|
||||
headers: { "content-type": "application/x-www-form-urlencoded" },
|
||||
//TODO: Move these to environment variables/database.
|
||||
data: qs.stringify(
|
||||
{
|
||||
method: "fee",
|
||||
...shopCredentials,
|
||||
amount: req.body.amount,
|
||||
paymenttype: `CC`,
|
||||
cardnum: "4111111111111111", //Not needed per documentation, but incorrect values come back without it.
|
||||
state:
|
||||
req.body.bodyshop?.state && req.body.bodyshop.state?.length === 2
|
||||
? req.body.bodyshop.state.toUpperCase()
|
||||
: "ZZ" //Same as above
|
||||
},
|
||||
{ sort: false } //ColdFusion Query Strings depend on order. This preserves it.
|
||||
),
|
||||
url: `https://${domain}.cpteller.com/api/26/webapi.cfc`
|
||||
};
|
||||
|
||||
const response = await axios(options);
|
||||
if (response.data?.error) {
|
||||
res.status(400).json({ error: response.data.error });
|
||||
} else if (response.data < 0) {
|
||||
res.json({ error: "Fee amount negative. Check API credentials & account configuration." });
|
||||
} else {
|
||||
res.json({ fee: response.data });
|
||||
}
|
||||
} catch (error) {
|
||||
//console.log(error);
|
||||
logger.log("intellipay-fee-check-error", "ERROR", req.user?.email, null, {
|
||||
error: error.message
|
||||
});
|
||||
res.status(400).json({ error });
|
||||
}
|
||||
};
|
||||
|
||||
exports.postback = async (req, res) => {
|
||||
try {
|
||||
logger.log("intellipay-postback", "DEBUG", req.user?.email, null, req.body);
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
|
||||
const { lightbox_credentials, payment_refund, generate_payment_url, postback } = require("../intellipay/intellipay");
|
||||
const { lightbox_credentials, payment_refund, generate_payment_url, postback, checkfee } = require("../intellipay/intellipay");
|
||||
|
||||
router.post("/lightbox_credentials", validateFirebaseIdTokenMiddleware, lightbox_credentials);
|
||||
router.post("/payment_refund", validateFirebaseIdTokenMiddleware, payment_refund);
|
||||
router.post("/generate_payment_url", validateFirebaseIdTokenMiddleware, generate_payment_url);
|
||||
router.post("/checkfee", validateFirebaseIdTokenMiddleware, checkfee);
|
||||
router.post("/postback", postback);
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -95,14 +95,14 @@ const createS3Client = () => {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
uploadFileToS3,
|
||||
downloadFileFromS3,
|
||||
listFilesInS3Bucket,
|
||||
deleteFileFromS3,
|
||||
copyFileInS3,
|
||||
fileExistsInS3
|
||||
fileExistsInS3,
|
||||
...s3Client
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user