Compare commits
48 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6f2b5e4c55 | ||
|
|
9ac27b6090 | ||
|
|
3d79be06de | ||
|
|
11ab7cd67e | ||
|
|
ec5258a431 | ||
|
|
fbc7168bde | ||
|
|
f2d9626888 | ||
|
|
2304e0bf02 | ||
|
|
289a666b6d | ||
|
|
b8836c7ae1 | ||
|
|
eca31c5618 | ||
|
|
7fdbedefce | ||
|
|
7140b8d585 | ||
|
|
5eed8d9809 | ||
|
|
57fe5b4c46 | ||
|
|
f266ee1cfe | ||
|
|
9550de5131 | ||
|
|
1f76ff882c | ||
|
|
749f73a272 | ||
|
|
9c1774c417 | ||
|
|
e363dca3f0 | ||
|
|
26b3a43ce5 | ||
|
|
78678dd3dc | ||
|
|
9dc4546b2e | ||
|
|
95aa0e45a6 | ||
|
|
ce9a77efcf | ||
|
|
e9e1e820a7 | ||
|
|
b027a4e618 | ||
|
|
c7fc75aa5c | ||
|
|
98d2372daf | ||
|
|
bf51380167 | ||
|
|
1ec827097f | ||
|
|
ff7dd7d3ea | ||
|
|
8cc4f88fa7 | ||
|
|
7e6ab3a5ff | ||
|
|
34f876f838 | ||
|
|
2f3eccf3d8 | ||
|
|
2b3e64d607 | ||
|
|
05b20505bb | ||
|
|
bddeae945c | ||
|
|
5b267f03b9 | ||
|
|
cb80b79e1d | ||
|
|
9aab47d8f8 | ||
|
|
f2f84e2da8 | ||
|
|
94641ae01d | ||
|
|
9bb36d2223 | ||
|
|
1205e71ea6 | ||
|
|
f8e65ada76 |
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>
|
||||
@@ -48360,6 +48528,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 +48591,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 +48654,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 +48696,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 +48759,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 +48822,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 +49018,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 +49081,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 +49144,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 +49186,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 +49249,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 +49312,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 +52181,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 +54666,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 +54949,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,57 @@ 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(value)
|
||||
.hour(dayjs().hour())
|
||||
.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 +150,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);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Button, Form, notification, Popover, Tooltip } from "antd";
|
||||
import { Button, Checkbox, Form, notification, Popover, Tooltip } from "antd";
|
||||
import axios from "axios";
|
||||
import { t } from "i18next";
|
||||
import React, { useState } from "react";
|
||||
@@ -60,24 +60,26 @@ export function JobLinesPartPriceChange({ job, line, refetch, technician }) {
|
||||
}
|
||||
};
|
||||
|
||||
const popcontent = !technician && InstanceRenderManager({
|
||||
imex: null,
|
||||
rome: (
|
||||
<Form layout="vertical" onFinish={handleFinish} initialValues={{ act_price: line.act_price }}>
|
||||
<Form.Item name="act_price" label={t("jobs.labels.act_price_ppc")} rules={[{ required: true }]}>
|
||||
<CurrencyFormItemComponent />
|
||||
</Form.Item>
|
||||
<Button
|
||||
disabled={InstanceRenderManager({ imex: true, rome: false, promanager: true })}
|
||||
loading={loading}
|
||||
htmlType="primary"
|
||||
>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
</Form>
|
||||
),
|
||||
promanager: null
|
||||
});
|
||||
const popcontent =
|
||||
!technician &&
|
||||
InstanceRenderManager({
|
||||
imex: null,
|
||||
rome: (
|
||||
<Form layout="vertical" onFinish={handleFinish} initialValues={{ act_price: line.act_price }}>
|
||||
<Form.Item name="act_price" label={t("jobs.labels.act_price_ppc")} rules={[{ required: true }]}>
|
||||
<CurrencyFormItemComponent />
|
||||
</Form.Item>
|
||||
<Button
|
||||
disabled={InstanceRenderManager({ imex: true, rome: false, promanager: true })}
|
||||
loading={loading}
|
||||
htmlType="primary"
|
||||
>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
</Form>
|
||||
),
|
||||
promanager: null
|
||||
});
|
||||
|
||||
return (
|
||||
<JobLineConvertToLabor jobline={line} job={job}>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -22,6 +22,14 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
|
||||
const data = useMemo(() => {
|
||||
return [
|
||||
...(job.job_totals?.totals?.ttl_adjustment
|
||||
? [
|
||||
{
|
||||
key: `Subtotal Adj.`,
|
||||
total: job.job_totals?.totals?.ttl_adjustment
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
key: t("jobs.labels.subtotal"),
|
||||
total: job.job_totals.totals.subtotal,
|
||||
@@ -102,7 +110,7 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty4Tax
|
||||
},
|
||||
{
|
||||
key: `${bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 || "TT"} - ${[
|
||||
key: `${bodyshop.md_responsibility_centers.taxes.tax_ty5?.tax_type5 || "Adj."} - ${[
|
||||
job.cieca_pft.ty5_rate1,
|
||||
job.cieca_pft.ty5_rate2,
|
||||
job.cieca_pft.ty5_rate3,
|
||||
@@ -113,6 +121,14 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
.join(", ")}%`,
|
||||
total: job.job_totals.totals.us_sales_tax_breakdown.ty5Tax
|
||||
},
|
||||
...(job.job_totals?.totals?.ttl_tax_adjustment
|
||||
? [
|
||||
{
|
||||
key: `Tax Adj.`,
|
||||
total: job.job_totals?.totals?.ttl_tax_adjustment
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
key: t("jobs.labels.total_sales_tax"),
|
||||
bold: true,
|
||||
@@ -121,6 +137,7 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
.add(Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty3Tax))
|
||||
.add(Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty4Tax))
|
||||
.add(Dinero(job.job_totals.totals.us_sales_tax_breakdown.ty5Tax))
|
||||
.add(Dinero(job.job_totals.totals.ttl_tax_adjustment))
|
||||
.toJSON()
|
||||
}
|
||||
].filter((item) => item.total.amount !== 0)
|
||||
@@ -141,14 +158,16 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
||||
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,32 @@ 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"),
|
||||
total: Dinero(job.job_totals.totals.custPayable.total)
|
||||
.add(
|
||||
Dinero(job.job_totals.totals.custPayable.total).percentage(
|
||||
bodyshop.intellipay_config?.cash_discount_percentage || 0
|
||||
)
|
||||
)
|
||||
.toJSON(),
|
||||
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,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { gql, useApolloClient, useLazyQuery, useMutation, useQuery } from "@apollo/client";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import { Col, Row, notification } from "antd";
|
||||
import { Col, Row, notification } from "antd"; //import { Button, Col, Row, notification } from "antd";
|
||||
import Axios from "axios";
|
||||
import _ from "lodash";
|
||||
import queryString from "query-string";
|
||||
@@ -408,26 +408,25 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail
|
||||
updateSchComp={updateSchComp}
|
||||
setSchComp={setSchComp}
|
||||
/>
|
||||
{
|
||||
// currentUser.email.includes("@rome.") ||
|
||||
// currentUser.email.includes("@imex.") ? (
|
||||
// <Button
|
||||
// onClick={async () => {
|
||||
// for (const record of data.available_jobs) {
|
||||
// //Query the data
|
||||
// console.log("Start Job", record.id);
|
||||
// const {data} = await loadEstData({
|
||||
// variables: {id: record.id},
|
||||
// });
|
||||
// console.log("Query has been awaited and is complete");
|
||||
// await onOwnerFindModalOk(data);
|
||||
// }
|
||||
// }}
|
||||
// >
|
||||
// Add all jobs as new.
|
||||
// </Button>
|
||||
// ) : null
|
||||
}
|
||||
{/* {
|
||||
currentUser.email.includes("@rome.") || currentUser.email.includes("@imex.") ? (
|
||||
<Button
|
||||
onClick={async () => {
|
||||
for (const record of data.available_jobs) {
|
||||
//Query the data
|
||||
console.log("Start Job", record.id);
|
||||
const { data } = await loadEstData({
|
||||
variables: { id: record.id }
|
||||
});
|
||||
console.log("Query has been awaited and is complete");
|
||||
await onOwnerFindModalOk(data);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Add all jobs as new.
|
||||
</Button>
|
||||
) : null
|
||||
} */}
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<JobsAvailableTableComponent
|
||||
@@ -617,6 +616,7 @@ function ResolveCCCLineIssues(estData, bodyshop) {
|
||||
// ` | Act Price delete. (prev act price = ${estData.joblines.data[indexInEstData].act_price})`;
|
||||
estData.joblines.data[indexInEstData].act_price = 0;
|
||||
estData.joblines.data[indexInEstData].db_price = 0;
|
||||
estData.joblines.data[indexInEstData].part_type = null;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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} />
|
||||
}
|
||||
],
|
||||
|
||||
@@ -676,7 +676,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Input.TextArea rows={3} />
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
<Space wrap>
|
||||
<DeleteFilled
|
||||
@@ -737,7 +737,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Input.TextArea rows={3} />
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
<Space wrap>
|
||||
<DeleteFilled
|
||||
@@ -1187,7 +1187,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
||||
key={`${index}line_desc`}
|
||||
name={[field.name, "line_desc"]}
|
||||
>
|
||||
<Input />
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("joblines.fields.mod_lbr_ty")}
|
||||
@@ -1330,7 +1330,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
<Input.TextArea autoSize />
|
||||
</Form.Item>
|
||||
|
||||
<Space wrap>
|
||||
|
||||
@@ -4334,6 +4334,70 @@ export function ShopInfoResponsibilityCenterComponent({ bodyshop, form }) {
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
|
||||
{InstanceRenderManager({
|
||||
promanager: "USE_ROME",
|
||||
rome: (
|
||||
<LayoutFormRow header={<div>Adjustments</div>} id="refund">
|
||||
{bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? (
|
||||
<>
|
||||
<Form.Item
|
||||
label={t("bodyshop.labels.responsibilitycenters.ttl_adjustment")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_responsibility_centers", "ttl_adjustment", "dms_acctnumber"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.labels.responsibilitycenters.ttl_tax_adjustment")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_responsibility_centers", "ttl_tax_adjustment", "dms_acctnumber"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Form.Item
|
||||
label={t("bodyshop.labels.responsibilitycenters.ttl_adjustment")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_responsibility_centers", "ttl_adjustment", "accountitem"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("bodyshop.labels.responsibilitycenters.ttl_tax_adjustment")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
}
|
||||
]}
|
||||
name={["md_responsibility_centers", "ttl_tax_adjustment", "accountitem"]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</>
|
||||
)}
|
||||
</LayoutFormRow>
|
||||
)
|
||||
})}
|
||||
|
||||
{Qb_Multi_Ar.treatment === "on" && (
|
||||
<LayoutFormRow header={<div>Multiple Payers Item</div>} id="accountitem">
|
||||
<Form.Item
|
||||
|
||||
@@ -39,14 +39,13 @@ export function ShopInfoIntellipay({ bodyshop, form }) {
|
||||
</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='%'/>
|
||||
<InputNumber min={0} max={100} precision={1} suffix="%" />
|
||||
</Form.Item>
|
||||
</LayoutFormRow>
|
||||
</>
|
||||
|
||||
@@ -81,14 +81,14 @@ export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
|
||||
user: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
|
||||
...additionalParams
|
||||
};
|
||||
axios.post("/ioevent", {
|
||||
useremail: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
|
||||
bodyshopid: (state.user && state.user.bodyshop && state.user.bodyshop.id) || null,
|
||||
operationName: eventName,
|
||||
variables: additionalParams,
|
||||
dbevent: false,
|
||||
env: `master-AIO|${import.meta.env.VITE_APP_GIT_SHA_DATE}`
|
||||
});
|
||||
// axios.post("/ioevent", {
|
||||
// useremail: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
|
||||
// bodyshopid: (state.user && state.user.bodyshop && state.user.bodyshop.id) || null,
|
||||
// operationName: eventName,
|
||||
// variables: additionalParams,
|
||||
// dbevent: false,
|
||||
// env: `master-AIO|${import.meta.env.VITE_APP_GIT_SHA_DATE}`
|
||||
// });
|
||||
// console.log(
|
||||
// "%c[Analytics]",
|
||||
// "background-color: green ;font-weight:bold;",
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
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);
|
||||
@@ -1,14 +1,12 @@
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
const Dinero = require("dinero.js");
|
||||
const { gql } = require("graphql-request");
|
||||
const queries = require("./server/graphql-client/queries");
|
||||
const GraphQLClient = require("graphql-request").GraphQLClient;
|
||||
const logger = require("./server/utils/logger");
|
||||
const AxiosLib = require("axios").default;
|
||||
const axios = AxiosLib.create();
|
||||
const pLimit = require("p-limit");
|
||||
const converter = require("json-2-csv");
|
||||
|
||||
// Dinero.defaultCurrency = "USD";
|
||||
// Dinero.globalLocale = "en-CA";
|
||||
Dinero.globalRoundingMode = "HALF_EVEN";
|
||||
const client = require("./server/graphql-client/graphql-client").client;
|
||||
require("dotenv").config({
|
||||
@@ -16,8 +14,9 @@ require("dotenv").config({
|
||||
});
|
||||
|
||||
async function RunTheTest() {
|
||||
const bodyshopids = ["b501bb82-22b2-493a-8a0f-152938194869"];
|
||||
const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImJhNjI1OTZmNTJmNTJlZDQ0MDQ5Mzk2YmU3ZGYzNGQyYzY0ZjQ1M2UiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUm9tZSBEZXZlbG9wbWVudCIsImh0dHBzOi8vaGFzdXJhLmlvL2p3dC9jbGFpbXMiOnsieC1oYXN1cmEtZGVmYXVsdC1yb2xlIjoidXNlciIsIngtaGFzdXJhLWFsbG93ZWQtcm9sZXMiOlsidXNlciJdLCJ4LWhhc3VyYS11c2VyLWlkIjoidDZZbTFORGxDRE9QWnIzRjliZ3VXSDRMaFNYMiJ9LCJpb2FkbWluIjp0cnVlLCJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vcm9tZS1wcm9kLTEiLCJhdWQiOiJyb21lLXByb2QtMSIsImF1dGhfdGltZSI6MTcxMDk1MTg1MCwidXNlcl9pZCI6InQ2WW0xTkRsQ0RPUFpyM0Y5Ymd1V0g0TGhTWDIiLCJzdWIiOiJ0NlltMU5EbENET1BacjNGOWJndVdINExoU1gyIiwiaWF0IjoxNzExNTczODI1LCJleHAiOjE3MTE1Nzc0MjUsImVtYWlsIjoicGF0cmlja0Byb21lLmRldiIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwiZmlyZWJhc2UiOnsiaWRlbnRpdGllcyI6eyJlbWFpbCI6WyJwYXRyaWNrQHJvbWUuZGV2Il19LCJzaWduX2luX3Byb3ZpZGVyIjoicGFzc3dvcmQifX0.0kBySA9tJznLYj8TtncHGVWJO0IcmLKP2G1UyyXwaj45kTa25bjT9RWjM-NslX_zjOvrvmQZzisFAb6M1Jf6geNjOMLIqb8bhihhzEZK4CcRfvjT6cpZxnOO2Dp_1Y5OePbvOBS_GlfdsovVWa84OLuhYC5G_3QwHT8_2Cttz4CbrC6M_vd7QsGODJYBbVKMhOdZhzpNq7AbOUh3749WRjLMMobpnZDrmQlsyg3PAqtX1FHO25WQS2rma9QahGDSY736JfbkuZJ2XbNn0axEGpK7RQLUcuRkFUlfKqYplNbR_e1Q3kEfRAZpxBPXZysrDcbDNhbkWCoTmJ3fle55OA`;
|
||||
const bodyshopids = ["71f8494c-89f0-43e0-8eb2-820b52d723bc"];
|
||||
const bearerToken = `Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImI4Y2FjOTViNGE1YWNkZTBiOTY1NzJkZWU4YzhjOTVlZWU0OGNjY2QiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoiUGF0cmljayBGaWMgKERFVikiLCJodHRwczovL2hhc3VyYS5pby9qd3QvY2xhaW1zIjp7IngtaGFzdXJhLWRlZmF1bHQtcm9sZSI6InVzZXIiLCJ4LWhhc3VyYS1hbGxvd2VkLXJvbGVzIjpbInVzZXIiXSwieC1oYXN1cmEtdXNlci1pZCI6ImhOSjhBRHB0REhRQkRFcXNCOFFNWVRqaURuZjEifSwiaXNzIjoiaHR0cHM6Ly9zZWN1cmV0b2tlbi5nb29nbGUuY29tL2ltZXgtZGV2IiwiYXVkIjoiaW1leC1kZXYiLCJhdXRoX3RpbWUiOjE3MzAxMzIwMjksInVzZXJfaWQiOiJoTko4QURwdERIUUJERXFzQjhRTVlUamlEbmYxIiwic3ViIjoiaE5KOEFEcHRESFFCREVxc0I4UU1ZVGppRG5mMSIsImlhdCI6MTczMDg0MTc2NSwiZXhwIjoxNzMwODQ1MzY1LCJlbWFpbCI6InBhdHJpY2tAaW1leC5kZXYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsicGF0cmlja0BpbWV4LmRldiJdfSwic2lnbl9pbl9wcm92aWRlciI6InBhc3N3b3JkIn19.npQWkyB5cB4wmkaBsQiY3JbvBM9vKPqf3e22nVHnSydGcQi0p9M2mca9FcDtdcWvQlShUM63FF-6KkzpovC92sHauNmzCSXRInaaCPEussUUNSJEe2gEV03tYX447LkkSmFQbJ5V6qLTIDelm25fF0MoEDVnLTgythK_9927f8cxKZH1kEow0ymDeMaWey1sRyu7n15OJMcu692mfuQnBAArGTHGJ4YmReI7tMmdrV438MLxuVpH5CLb6uzlUdZoJ__7yh0kz0lkZEeHQAL8yq-0fISbPeZ5uXuMzYGrHuuKsIPRoeShVSVnF7ov8yTT3_YrCkhYbxl0eSTfBB5OdQ`;
|
||||
|
||||
const { jobs } = await client.request(
|
||||
gql`
|
||||
query GET_JOBS($bodyshopids: [uuid!]!) {
|
||||
@@ -36,69 +35,98 @@ async function RunTheTest() {
|
||||
|
||||
const results = [];
|
||||
|
||||
for (const [index, job] of jobs.entries()) {
|
||||
process.stdout.cursorTo(0);
|
||||
process.stdout.write(
|
||||
`Processing job ${index + 1} of ${jobs.length}. Failed jobs: ${results.filter((r) => r.result !== "PASS").length}`
|
||||
);
|
||||
const limit = pLimit(5); // Set concurrency limit to 3
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
`http://localhost:4000/job/totalsssu`,
|
||||
{ id: job.id },
|
||||
{ headers: { Authorization: bearerToken } }
|
||||
const tasks = jobs.map((job, index) => {
|
||||
return limit(async () => {
|
||||
process.stdout.cursorTo(0);
|
||||
process.stdout.write(
|
||||
`Processing job ${index + 1} of ${jobs.length}. Failed jobs: ${results.filter((r) => r.overallTotalCorrect !== "PASS").length}. Correct jobs because of adjustment: ${results.filter((r) => r.correctJobsBecauseOfAdjustment).length}`
|
||||
);
|
||||
const { jobs_by_pk: newjob } = await client.request(
|
||||
gql`
|
||||
query GET_JOBS($id: uuid!) {
|
||||
jobs_by_pk(id: $id) {
|
||||
id
|
||||
ro_number
|
||||
cieca_ttl
|
||||
job_totals
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
ins_co_nm
|
||||
comment
|
||||
|
||||
try {
|
||||
await axios.post(
|
||||
`http://localhost:4000/job/totalsssu`,
|
||||
{ id: job.id },
|
||||
{ headers: { Authorization: bearerToken } }
|
||||
);
|
||||
const { jobs_by_pk: newjob } = await client.request(
|
||||
gql`
|
||||
query GET_JOBS($id: uuid!) {
|
||||
jobs_by_pk(id: $id) {
|
||||
id
|
||||
ro_number
|
||||
cieca_ttl
|
||||
job_totals
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
ins_co_nm
|
||||
comment
|
||||
}
|
||||
}
|
||||
`,
|
||||
{
|
||||
id: job.id
|
||||
}
|
||||
`,
|
||||
{
|
||||
id: job.id
|
||||
);
|
||||
|
||||
const result = {
|
||||
id: newjob.id,
|
||||
owner: `${newjob.ownr_fn} ${newjob.ownr_ln} ${job.ownr_co_nm || ""}`,
|
||||
ins_co: newjob.ins_co_nm,
|
||||
comment: newjob.comment,
|
||||
imexsubtotal: Dinero(newjob.job_totals.totals.subtotal).toFormat("0.00"),
|
||||
imextotalrepair: Dinero(newjob.job_totals.totals.total_repairs).toFormat("0.00"),
|
||||
g_tax: newjob.cieca_ttl.data.g_tax,
|
||||
n_ttl_amt: newjob.cieca_ttl.data.n_ttl_amt,
|
||||
g_ttl_amt: newjob.cieca_ttl.data.g_ttl_amt
|
||||
};
|
||||
|
||||
const calcTotal = newjob.job_totals.totals.total_repairs.amount;
|
||||
const ttlTotal = newjob.cieca_ttl.data.g_ttl_amt * 100;
|
||||
result.difference = (calcTotal - ttlTotal) / 100;
|
||||
|
||||
if (Math.abs(calcTotal - ttlTotal) > 3) {
|
||||
result.overallTotalCorrect = "***FAIL***";
|
||||
} else {
|
||||
result.overallTotalCorrect = "PASS";
|
||||
}
|
||||
);
|
||||
result.ttl_adjustment = Dinero(newjob.job_totals.totals.ttl_adjustment).toFormat();
|
||||
result.ttl_tax_adjustment = Dinero(newjob.job_totals.totals.ttl_tax_adjustment).toFormat();
|
||||
|
||||
const result = {
|
||||
id: newjob.id,
|
||||
owner: `${newjob.ownr_fn} ${newjob.ownr_ln} ${job.ownr_co_nm || ""}`,
|
||||
ins_co: newjob.ins_co_nm,
|
||||
comment: newjob.comment
|
||||
};
|
||||
const calcTaxDinero = Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty1Tax)
|
||||
.add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty2Tax))
|
||||
.add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty3Tax))
|
||||
.add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty4Tax))
|
||||
.add(Dinero(newjob.job_totals.totals.us_sales_tax_breakdown.ty5Tax))
|
||||
.add(Dinero(newjob.job_totals.totals.ttl_tax_adjustment));
|
||||
result.calcTax = calcTaxDinero.toFormat("0.00");
|
||||
const calcTax = calcTaxDinero.getAmount() / 100;
|
||||
const emsTax = newjob.cieca_ttl.data.g_tax;
|
||||
result.taxDifference = calcTax - emsTax;
|
||||
|
||||
const calcTotal = newjob.job_totals.totals.total_repairs.amount;
|
||||
const ttlTotal = newjob.cieca_ttl.data.g_ttl_amt * 100;
|
||||
result.difference = (calcTotal - ttlTotal) / 100;
|
||||
if (Math.abs(calcTax - emsTax) > 3) {
|
||||
result.taxCorrect = "***FAIL***";
|
||||
} else {
|
||||
result.taxCorrect = "PASS";
|
||||
}
|
||||
|
||||
if (Math.abs(calcTotal - ttlTotal) > 3) {
|
||||
//Diff is greater than 5 cents. Fail it.
|
||||
result.result = "***FAIL***";
|
||||
} else {
|
||||
result.result = "PASS";
|
||||
results.push(result);
|
||||
} catch (error) {
|
||||
results.push({
|
||||
ro_number: job.ro_number,
|
||||
id: job.id,
|
||||
result: error.message
|
||||
});
|
||||
}
|
||||
// console.log(`${result.result} => RO ${job.ro_number} - ${job.id} `);
|
||||
});
|
||||
});
|
||||
|
||||
results.push(result);
|
||||
} catch (error) {
|
||||
results.push({
|
||||
ro_number: job.ro_number,
|
||||
id: job.id,
|
||||
result: "**503 FAILURE**"
|
||||
});
|
||||
}
|
||||
}
|
||||
await Promise.all(tasks);
|
||||
|
||||
console.table(results.filter((r) => r.result !== "PASS"));
|
||||
console.table(results.filter((r) => r.overallTotalCorrect !== "PASS"));
|
||||
console.log("=======================================");
|
||||
const summary = results.reduce(
|
||||
(acc, val) => {
|
||||
if (val.result === "PASS") {
|
||||
@@ -110,18 +138,12 @@ async function RunTheTest() {
|
||||
{ pass: 0, fail: 0 }
|
||||
);
|
||||
console.log("Pass Rate: ", ((summary.pass / (summary.fail + summary.pass)) * 100).toFixed(1));
|
||||
|
||||
const ret = converter.json2csv(results, { emptyFieldValue: "" });
|
||||
|
||||
fs.writeFile(`./logs/totalstest-${Date.now()}.csv`, ret, (error) => console.log(error));
|
||||
}
|
||||
|
||||
RunTheTest();
|
||||
|
||||
// mutation {
|
||||
// delete_jobs(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
|
||||
// affected_rows
|
||||
// }
|
||||
// delete_owners(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
|
||||
// affected_rows
|
||||
// }
|
||||
// delete_vehicles(where: {shopid: {_eq: "a7ee1503-ee05-4a02-b80e-bdb11d1cc8ac"}}) {
|
||||
// affected_rows
|
||||
// }
|
||||
// }
|
||||
RunTheTest().catch((error) => {
|
||||
console.log("Error in RunTheTest: ", error);
|
||||
});
|
||||
|
||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -65,6 +65,7 @@
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"p-limit": "^3.1.0",
|
||||
"prettier": "^3.3.3",
|
||||
"source-map-explorer": "^2.5.2"
|
||||
},
|
||||
@@ -7706,7 +7707,8 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
|
||||
"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
|
||||
"optional": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"yocto-queue": "^0.1.0"
|
||||
},
|
||||
@@ -9700,7 +9702,8 @@
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
|
||||
"optional": true,
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
"devDependencies": {
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"p-limit": "^3.1.0",
|
||||
"prettier": "^3.3.3",
|
||||
"source-map-explorer": "^2.5.2"
|
||||
}
|
||||
|
||||
@@ -548,6 +548,61 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
}
|
||||
}
|
||||
|
||||
if (jobs_by_pk.job_totals.totals?.ttl_adjustment) {
|
||||
// Do not need to check for ImEX or Rome because ImEX uses a different totals calculation that will never set this field.
|
||||
if (qbo) {
|
||||
const taxAccountCode = findTaxCode(
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state: jobs_by_pk.tax_lbr_rt === 0 ? false : true
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
|
||||
const QboTaxId = InstanceManager({
|
||||
imex: taxCodes[taxAccountCode],
|
||||
rome: CheckQBOUSATaxID({
|
||||
// jobline: jobline,
|
||||
type: "adjustment",
|
||||
job: jobs_by_pk
|
||||
})
|
||||
});
|
||||
|
||||
InvoiceLineAdd.push({
|
||||
DetailType: "SalesItemLineDetail",
|
||||
Amount: Dinero(jobs_by_pk.job_totals.totals?.ttl_adjustment).toFormat(DineroQbFormat),
|
||||
SalesItemLineDetail: {
|
||||
...(jobs_by_pk.class ? { ClassRef: { value: classes[jobs_by_pk.class] } } : {}),
|
||||
ItemRef: {
|
||||
value: items[responsibilityCenters.ttl_adjustment?.accountitem]
|
||||
},
|
||||
TaxCodeRef: {
|
||||
value: QboTaxId
|
||||
},
|
||||
Qty: 1
|
||||
}
|
||||
});
|
||||
} else {
|
||||
InvoiceLineAdd.push({
|
||||
ItemRef: {
|
||||
FullName: responsibilityCenters.ttl_adjustment?.accountitem
|
||||
},
|
||||
Desc: "Adjustment",
|
||||
Quantity: 1,
|
||||
Amount: Dinero(jobs_by_pk.job_totals.totals?.ttl_adjustment).toFormat(DineroQbFormat),
|
||||
SalesTaxCodeRef: InstanceManager({
|
||||
imex: {
|
||||
FullName: "E"
|
||||
},
|
||||
rome: {
|
||||
FullName: bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON"
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//Add tax lines
|
||||
const job_totals = jobs_by_pk.job_totals;
|
||||
const federal_tax = Dinero(job_totals.totals.federal_tax);
|
||||
@@ -824,7 +879,60 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
|
||||
}
|
||||
}
|
||||
}
|
||||
if (jobs_by_pk.job_totals.totals.ttl_tax_adjustment) {
|
||||
// Do not need to check for ImEX or Rome because ImEX uses a different totals calculation that will never set this field.
|
||||
if (qbo) {
|
||||
const taxAccountCode = findTaxCode(
|
||||
{
|
||||
local: false,
|
||||
federal: InstanceManager({ imex: true, rome: false }),
|
||||
state: jobs_by_pk.tax_lbr_rt === 0 ? false : true
|
||||
},
|
||||
bodyshop.md_responsibility_centers.sales_tax_codes
|
||||
);
|
||||
|
||||
const QboTaxId = InstanceManager({
|
||||
imex: taxCodes[taxAccountCode],
|
||||
rome: CheckQBOUSATaxID({
|
||||
// jobline: jobline,
|
||||
type: "adjustment",
|
||||
job: jobs_by_pk
|
||||
})
|
||||
});
|
||||
|
||||
InvoiceLineAdd.push({
|
||||
DetailType: "SalesItemLineDetail",
|
||||
Amount: Dinero(jobs_by_pk.job_totals.totals?.ttl_tax_adjustment).toFormat(DineroQbFormat),
|
||||
SalesItemLineDetail: {
|
||||
...(jobs_by_pk.class ? { ClassRef: { value: classes[jobs_by_pk.class] } } : {}),
|
||||
ItemRef: {
|
||||
value: items[responsibilityCenters.ttl_tax_adjustment?.accountitem]
|
||||
},
|
||||
TaxCodeRef: {
|
||||
value: QboTaxId
|
||||
},
|
||||
Qty: 1
|
||||
}
|
||||
});
|
||||
} else {
|
||||
InvoiceLineAdd.push({
|
||||
ItemRef: {
|
||||
FullName: responsibilityCenters.ttl_tax_adjustment?.accountitem
|
||||
},
|
||||
Desc: "Tax Adjustment",
|
||||
Quantity: 1,
|
||||
Amount: Dinero(jobs_by_pk.job_totals.totals?.ttl_tax_adjustment).toFormat(DineroQbFormat),
|
||||
SalesTaxCodeRef: InstanceManager({
|
||||
imex: {
|
||||
FullName: "E"
|
||||
},
|
||||
rome: {
|
||||
FullName: bodyshop.md_responsibility_centers.taxes.itemexemptcode || "NON"
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!qbo && InvoiceLineAdd.length === 0) {
|
||||
//Handle the scenario where there is a $0 sale invoice.
|
||||
InvoiceLineAdd.push({
|
||||
|
||||
@@ -219,6 +219,11 @@ async function InsertPayment(oauthClient, qbo_realmId, req, payment, parentRef,
|
||||
PaymentMethodRef: {
|
||||
value: paymentMethods[payment.type]
|
||||
},
|
||||
PrivateNote: payment.memo
|
||||
? payment.memo.length > 4000
|
||||
? payment.memo.substring(0, 4000).trim()
|
||||
: payment.memo.trim()
|
||||
: "",
|
||||
PaymentRefNum: payment.transactionid,
|
||||
...(invoices && invoices.length === 1 && invoices[0]
|
||||
? {
|
||||
|
||||
@@ -352,6 +352,7 @@ function calculateAllocations(connectionData, job) {
|
||||
// console.log("NO MASH ACCOUNT FOUND!!");
|
||||
}
|
||||
}
|
||||
|
||||
if (InstanceManager({ rome: true })) {
|
||||
//profile level adjustments for parts
|
||||
Object.keys(job.job_totals.parts.adjustments).forEach((key) => {
|
||||
@@ -427,6 +428,41 @@ function calculateAllocations(connectionData, job) {
|
||||
} else {
|
||||
return { ...taxAllocations[key], tax: key };
|
||||
}
|
||||
})
|
||||
}),
|
||||
|
||||
...(job.job_totals.totals.ttl_adjustment
|
||||
? [
|
||||
{
|
||||
center: "SUB ADJ",
|
||||
sale: Dinero(job.job_totals.totals.ttl_adjustment),
|
||||
cost: Dinero(),
|
||||
profitCenter: {
|
||||
name: "SUB ADJ",
|
||||
accountdesc: "SUB ADJ",
|
||||
accountitem: "SUB ADJ",
|
||||
accountname: "SUB ADJ",
|
||||
dms_acctnumber: bodyshop.md_responsibility_centers.ttl_adjustment.dms_acctnumber
|
||||
},
|
||||
costCenter: {}
|
||||
}
|
||||
]
|
||||
: []),
|
||||
...(job.job_totals.totals.ttl_tax_adjustment
|
||||
? [
|
||||
{
|
||||
center: "TAX ADJ",
|
||||
sale: Dinero(job.job_totals.totals.ttl_tax_adjustment),
|
||||
cost: Dinero(),
|
||||
profitCenter: {
|
||||
name: "TAX ADJ",
|
||||
accountdesc: "TAX ADJ",
|
||||
accountitem: "TAX ADJ",
|
||||
accountname: "TAX ADJ",
|
||||
dms_acctnumber: bodyshop.md_responsibility_centers.ttl_tax_adjustment.dms_acctnumber
|
||||
},
|
||||
costCenter: {}
|
||||
}
|
||||
]
|
||||
: [])
|
||||
];
|
||||
}
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1365,6 +1365,7 @@ exports.GET_JOB_BY_PK = `query GET_JOB_BY_PK($id: uuid!) {
|
||||
cieca_pfl
|
||||
cieca_pft
|
||||
cieca_pfo
|
||||
cieca_ttl
|
||||
vehicle {
|
||||
id
|
||||
notes
|
||||
|
||||
@@ -849,6 +849,41 @@ function GenerateCostingData(job) {
|
||||
gppercent: formatGpPercent(0)
|
||||
});
|
||||
}
|
||||
//Push adjustments to bottom line.
|
||||
if (job.job_totals?.totals?.ttl_adjustment) {
|
||||
//Add to totals.
|
||||
const Adjustment = Dinero(job.job_totals.totals.ttl_adjustment); //Need to invert, since this is being assigned as a cost.
|
||||
summaryData.totalAdditionalSales = summaryData.totalAdditionalSales.add(Adjustment);
|
||||
summaryData.totalSales = summaryData.totalSales.add(Adjustment);
|
||||
//Add to lines.
|
||||
costCenterData.push({
|
||||
id: "AdjEst",
|
||||
cost_center: "Adjustment (Est. Match)",
|
||||
sale_labor: Dinero().toFormat(),
|
||||
sale_labor_dinero: Dinero(),
|
||||
sale_parts: Dinero().toFormat(),
|
||||
sale_parts_dinero: Dinero(),
|
||||
sale_additional: Adjustment.toFormat(),
|
||||
sale_additional_dinero: Adjustment,
|
||||
sale_sublet: Dinero(),
|
||||
sale_sublet_dinero: Dinero(),
|
||||
sales: Adjustment.toFormat(),
|
||||
sales_dinero: Adjustment,
|
||||
cost_parts: Dinero().toFormat(),
|
||||
cost_parts_dinero: Dinero(),
|
||||
cost_labor: Dinero().toFormat(), //Adjustment.toFormat(),
|
||||
cost_labor_dinero: Dinero(), // Adjustment,
|
||||
cost_additional: Dinero(),
|
||||
cost_additional_dinero: Dinero(),
|
||||
cost_sublet: Dinero(),
|
||||
cost_sublet_dinero: Dinero(),
|
||||
costs: Dinero().toFormat(),
|
||||
costs_dinero: Dinero(),
|
||||
gpdollars_dinero: Dinero(),
|
||||
gpdollars: Dinero().toFormat(),
|
||||
gppercent: formatGpPercent(0)
|
||||
});
|
||||
}
|
||||
|
||||
//Final summary data massaging.
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ exports.totalsSsu = async function (req, res) {
|
||||
} catch (error) {
|
||||
logger.log("job-totals-ssu-USA-error", "ERROR", req?.user?.email, id, {
|
||||
jobid: id,
|
||||
error
|
||||
error: error.message
|
||||
});
|
||||
res.status(503).send();
|
||||
}
|
||||
@@ -68,6 +68,54 @@ async function TotalsServerSide(req, res) {
|
||||
ret.additional = CalculateAdditional(job);
|
||||
ret.totals = CalculateTaxesTotals(job, ret);
|
||||
|
||||
// Sub total scrubbbing.
|
||||
const emsTotal =
|
||||
job.cieca_ttl.data.n_ttl_amt === job.cieca_ttl.data.g_ttl_amt //It looks like sometimes, gross and net are the same, but they shouldn't be.
|
||||
? job.cieca_ttl.data.n_ttl_amt - job.cieca_ttl.data.g_tax
|
||||
: job.cieca_ttl.data.g_ttl_amt - job.cieca_ttl.data.g_tax; //If they are, adjust the gross total down by the tax amount.
|
||||
const ttlDifference =
|
||||
emsTotal -
|
||||
ret.totals.subtotal
|
||||
.add(
|
||||
Dinero({
|
||||
amount: Math.round((job.adjustment_bottom_line || 0) * 100)
|
||||
}).multiply(-1) //Add back in the adjustment to the subtotal. We don't want to scrub it twice.
|
||||
)
|
||||
.getAmount() /
|
||||
100;
|
||||
|
||||
if (Math.abs(ttlDifference) > 0.0) {
|
||||
//If difference is greater than a pennny, we need to adjust it.
|
||||
ret.totals.ttl_adjustment = Dinero({ amount: Math.round(ttlDifference * 100) });
|
||||
ret.totals.subtotal = ret.totals.subtotal.add(ret.totals.ttl_adjustment);
|
||||
ret.totals.total_repairs = ret.totals.total_repairs.add(ret.totals.ttl_adjustment);
|
||||
ret.totals.net_repairs = ret.totals.net_repairs.add(ret.totals.ttl_adjustment);
|
||||
logger.log("job-totals-USA-ttl-adj", "DEBUG", null, job.id, {
|
||||
adjAmount: ttlDifference
|
||||
});
|
||||
}
|
||||
|
||||
//Taxes Scrubbing
|
||||
const emsTaxTotal = job.cieca_ttl.data.g_tax;
|
||||
const totalUsTaxes =
|
||||
(ret.totals.us_sales_tax_breakdown.ty1Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty2Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty3Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty4Tax.getAmount() +
|
||||
ret.totals.us_sales_tax_breakdown.ty5Tax.getAmount()) /
|
||||
100;
|
||||
const ttlTaxDifference = emsTaxTotal - totalUsTaxes;
|
||||
|
||||
if (Math.abs(ttlTaxDifference) > 0.0) {
|
||||
//If difference is greater than a pennny, we need to adjust it.
|
||||
ret.totals.ttl_tax_adjustment = Dinero({ amount: Math.round(ttlTaxDifference * 100) });
|
||||
ret.totals.total_repairs = ret.totals.total_repairs.add(ret.totals.ttl_tax_adjustment);
|
||||
ret.totals.net_repairs = ret.totals.net_repairs.add(ret.totals.ttl_tax_adjustment);
|
||||
logger.log("job-totals-USA-ttl-tax-adj", "DEBUG", null, job.id, {
|
||||
adjAmount: ttlTaxDifference
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
} catch (error) {
|
||||
logger.log("job-totals-ssu-USA-error", "ERROR", req.user?.email, job.id, {
|
||||
@@ -842,17 +890,21 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
}
|
||||
});
|
||||
//Add towing and storage taxable amounts
|
||||
const stlTowing = job.cieca_stl?.data.find((c) => c.ttl_typecd === "OTTW");
|
||||
const stlStorage = job.cieca_stl?.data.find((c) => c.ttl_typecd === "OTST");
|
||||
const stlTowing = job.cieca_stl?.data.find((c) => c.ttl_typecd === "OTTW" || c.ttl_type === "OTTW");
|
||||
const stlStorage = job.cieca_stl?.data.find((c) => c.ttl_typecd === "OTST" || c.ttl_type === "OTST");
|
||||
|
||||
if (stlTowing)
|
||||
taxableAmounts.TOW = Dinero({
|
||||
amount: Math.round(stlTowing.t_amt * 100)
|
||||
});
|
||||
taxableAmounts.TOW = taxableAmounts.TOW.add(
|
||||
Dinero({
|
||||
amount: Math.round(stlTowing.t_amt * 100)
|
||||
})
|
||||
);
|
||||
if (stlStorage)
|
||||
taxableAmounts.TOW = Dinero({
|
||||
amount: Math.round(stlStorage.t_amt * 100)
|
||||
});
|
||||
taxableAmounts.TOW = taxableAmounts.TOW.add(
|
||||
(taxableAmounts.TOW = Dinero({
|
||||
amount: Math.round(stlStorage.t_amt * 100)
|
||||
}))
|
||||
);
|
||||
|
||||
const pfp = job.parts_tax_rates;
|
||||
|
||||
@@ -959,7 +1011,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log("job-totals-USA Key with issue", "error", null, null, {
|
||||
logger.log("job-totals-USA Key with issue", "error", null, job.id, {
|
||||
key
|
||||
});
|
||||
}
|
||||
@@ -989,7 +1041,7 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
for (let threshCounter = 1; threshCounter <= 5; threshCounter++) {
|
||||
const thresholdAmount = parseFloat(job.cieca_pft[`ty${tyCounter}_thres${threshCounter}`]) || 0;
|
||||
const thresholdTaxRate = parseFloat(job.cieca_pft[`ty${tyCounter}_rate${threshCounter}`]) || 0;
|
||||
|
||||
// console.log(taxTierKey, tyCounter, threshCounter, thresholdAmount, thresholdTaxRate);
|
||||
let taxableAmountInThisThreshold;
|
||||
if (
|
||||
thresholdAmount === 9999.99 ||
|
||||
@@ -1013,11 +1065,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
taxableAmountInThisThreshold = Dinero({
|
||||
amount: Math.round(thresholdAmount * 100)
|
||||
});
|
||||
remainingTaxableAmounts[taxTierKey] = remainingTaxableAmounts[taxTierKey].subtract(
|
||||
Dinero({
|
||||
amount: Math.round(taxableAmountInThisThreshold * 100)
|
||||
})
|
||||
);
|
||||
remainingTaxableAmounts[taxTierKey] =
|
||||
remainingTaxableAmounts[taxTierKey].subtract(taxableAmountInThisThreshold);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1026,8 +1075,8 @@ function CalculateTaxesTotals(job, otherTotals) {
|
||||
totalTaxByTier[taxTierKey] = totalTaxByTier[taxTierKey].add(taxAmountToAdd);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.log("job-totals-USA - PFP Calculation Error", "error", null, null, {
|
||||
error
|
||||
logger.log("job-totals-USA - PFP Calculation Error", "error", null, job.id, {
|
||||
error: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -95,14 +95,14 @@ const createS3Client = () => {
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
uploadFileToS3,
|
||||
downloadFileFromS3,
|
||||
listFilesInS3Bucket,
|
||||
deleteFileFromS3,
|
||||
copyFileInS3,
|
||||
fileExistsInS3
|
||||
fileExistsInS3,
|
||||
...s3Client
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user