IO-594 Create schedulable AH export.

This commit is contained in:
Patrick Fic
2021-07-20 16:25:08 -07:00
parent 3e1663bf18
commit 3b992edc21
11 changed files with 233 additions and 65 deletions

View File

@@ -1 +1 @@
client_max_body_size 15M;
client_max_body_size 50M;

View File

@@ -11700,6 +11700,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>pdfcopywillbeattached</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>preview</name>
<definition_loaded>false</definition_loaded>

View File

@@ -1,5 +1,5 @@
import { UploadOutlined } from "@ant-design/icons";
import { Divider, Form, Input, Select, Tabs, Upload } from "antd";
import { Divider, Form, Input, Select, Tabs, Typography, Upload } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import EmailDocumentsComponent from "../email-documents/email-documents.component";
@@ -37,6 +37,8 @@ export default function EmailOverlayComponent({ form, selectedMediaState }) {
</Form.Item>
<Divider>{t("emails.labels.preview")}</Divider>
<strong>{t("emails.labels.pdfcopywillbeattached")}</strong>
<Form.Item shouldUpdate>
{() => {
return (

View File

@@ -743,6 +743,7 @@
"attachments": "Attachments",
"documents": "Documents",
"generatingemail": "Generating email...",
"pdfcopywillbeattached": "A PDF copy of this email will be attached when it is sent.",
"preview": "Email Preview"
},
"successes": {

View File

@@ -743,6 +743,7 @@
"attachments": "",
"documents": "",
"generatingemail": "",
"pdfcopywillbeattached": "",
"preview": ""
},
"successes": {

View File

@@ -743,6 +743,7 @@
"attachments": "",
"documents": "",
"generatingemail": "",
"pdfcopywillbeattached": "",
"preview": ""
},
"successes": {

View File

@@ -39,6 +39,7 @@
"phone": "^2.4.20",
"soap": "^0.39.0",
"socket.io": "^4.1.2",
"ssh2-sftp-client": "^7.0.0",
"stripe": "^8.148.0",
"twilio": "^3.62.0",
"xmlbuilder2": "^2.4.1"

View File

@@ -139,7 +139,7 @@ app.post("/qbo/authorize", qbo.authorize);
app.get("/qbo/callback", qbo.callback);
var data = require("./server/data/data");
app.get("/data/ah", data.autohouse);
app.post("/data/ah", data.autohouse);
var ioevent = require("./server/ioevent/ioevent");
app.post("/ioevent", ioevent.default);

View File

@@ -11,21 +11,42 @@ require("dotenv").config({
`.env.${process.env.NODE_ENV || "development"}`
),
});
let Client = require("ssh2-sftp-client");
const client = require("../graphql-client/graphql-client").client;
const AHDineroFormat = "0.00";
const AhDateFormat = "MMDDYYYY";
exports.default = async (req, res) => {
//Get Client Dataset.
const { jobs } = await client.request(queries.AUTOHOUSE_QUERY);
const repairOpCodes = ["OP4", "OP9", "OP10"];
const replaceOpCodes = ["OP2", "OP5", "OP11", "OP12"];
const ftpSetup = {
host: process.env.AUTOHOUSE_HOST,
port: process.env.AUTOHOUSE_PORT,
username: process.env.AUTOHOUSE_USER,
password: process.env.AUTOHOUSE_PASSWORD,
//debug: console.log,
};
exports.default = async (req, res) => {
//Query for the List of Bodyshop Clients.
const { bodyshops } = await client.request(queries.GET_AUTOHOUSE_SHOPS);
const allxmlsToUpload = [];
const allErrors = [];
for (const bodyshop of bodyshops) {
const erroredJobs = [];
try {
const { jobs } = await client.request(queries.AUTOHOUSE_QUERY, {
bodyshopid: bodyshop.id,
});
const autoHouseObject = {
AutoHouseExport: {
RepairOrder: jobs.map((j) =>
CreateRepairOrderTag(j, (job, error) => {
erroredJobs.push({ job, error });
CreateRepairOrderTag({ ...j, bodyshop }, function ({ job, error }) {
erroredJobs.push({ job: job, error: error.toString() });
})
),
},
@@ -34,8 +55,9 @@ exports.default = async (req, res) => {
console.log(
"***Number of Failed jobs***: ",
erroredJobs.length,
JSON.stringify(erroredJobs.map((x) => x.error))
JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
);
var ret = builder
.create(autoHouseObject, {
version: "1.0",
@@ -43,10 +65,55 @@ exports.default = async (req, res) => {
})
.end({ pretty: true, allowEmptyTags: true });
allxmlsToUpload.push({
xml: ret,
filename: `IM_${bodyshop.imexshopid}_${moment().format(
"DDMMYYYY_HHMMSS"
)}.xml`,
});
} catch (error) {
//Error at the shop level.
allErrors.push({
bodyshopid: bodyshop.id,
imexshopid: bodyshop.imexshopid,
fatal: true,
errors: [error.toString()],
});
} finally {
allErrors.push({
bodyshopid: bodyshop.id,
imexshopid: bodyshop.imexshopid,
errors: erroredJobs,
});
}
}
let sftp = new Client();
try {
//Connect to the FTP and upload all.
await sftp.connect(ftpSetup);
for (const xmlObj of allxmlsToUpload) {
console.log("Uploading", xmlObj.filename);
const uploadResult = await sftp.put(
Buffer.from(xmlObj.xml),
`/${xmlObj.filename}`
);
console.log(
"🚀 ~ file: autohouse.js ~ line 94 ~ uploadResult",
uploadResult
);
}
//***TODO Change filing naming when creating the cron job. IM_ShopInternalName_DDMMYYYY_HHMMSS.xml
res.type("application/xml");
//res.sendFile(ret);
res.send(ret);
} catch (error) {
console.log("Error when connecting to FTP", error);
} finally {
sftp.end();
}
res.sendStatus(200);
};
const CreateRepairOrderTag = (job, errorCallback) => {
@@ -410,7 +477,7 @@ const CreateRepairOrderTag = (job, errorCallback) => {
return ret;
} catch (error) {
console.log("Error calculating job", error);
errorCallback(job, error);
errorCallback({ job, error });
}
};
@@ -611,6 +678,3 @@ const generateNullDetailLine = () => {
EstimateAmount: null,
};
};
const repairOpCodes = ["OP4", "OP9", "OP10"];
const replaceOpCodes = ["OP2", "OP5", "OP11", "OP12"];

View File

@@ -357,8 +357,8 @@ exports.QUERY_EMPLOYEE_PIN = `query QUERY_EMPLOYEE_PIN($shopId: uuid!, $employee
}
}`;
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
jobs(where: {_and: [{updated_at: {_gt: $start}}, {bodyshop: {autohouseid: {_is_null: false}}}]}) {
exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz, $bodyshopid: uuid!) {
jobs(where: {_and: [{updated_at: {_gt: $start}}, {shopid: {_eq: $bodyshopid}}]}) {
id
ro_number
status
@@ -436,7 +436,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
md_responsibility_centers
jc_hourly_rates
}
joblines (where:{removed: {_eq:false}}){
joblines(where: {removed: {_eq: false}}) {
id
line_no
status
@@ -454,19 +454,19 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
lbr_op
profitcenter_part
profitcenter_labor
billlines (order_by:{bill:{date:desc_nulls_last}}) {
billlines(order_by: {bill: {date: desc_nulls_last}}) {
actual_cost
actual_price
quantity
bill {
vendor{
vendor {
name
}
invoice_number
}
}
} bills {
}
bills {
id
federal_tax_rate
local_tax_rate
@@ -507,6 +507,7 @@ exports.AUTOHOUSE_QUERY = `query AUTOHOUSE_EXPORT($start: timestamptz) {
}
}
}
`;
exports.UPDATE_JOB = `
@@ -906,3 +907,24 @@ exports.INSERT_IOEVENT = ` mutation INSERT_IOEVENT($event: ioevents_insert_input
}
}
`;
exports.GET_AUTOHOUSE_SHOPS = `query GET_AUTOHOUSE_SHOPS {
bodyshops(where: {autohouseid: {_is_null: false}}){
id
shopname
address1
city
state
zip_post
country
phone
md_ro_statuses
md_order_statuses
autohouseid
md_responsibility_centers
jc_hourly_rates
imexshopid
}
}
`;

View File

@@ -529,7 +529,7 @@ asap@^2.0.0:
resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
asn1@~0.2.3:
asn1@^0.2.4, asn1@~0.2.3:
version "0.2.4"
resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
@@ -644,7 +644,7 @@ batch@^0.6.1:
resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
bcrypt-pbkdf@^1.0.0:
bcrypt-pbkdf@^1.0.0, bcrypt-pbkdf@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
@@ -915,6 +915,16 @@ concat-stream@^1.4.7:
readable-stream "^2.2.2"
typedarray "^0.0.6"
concat-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1"
integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==
dependencies:
buffer-from "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.0.2"
typedarray "^0.0.6"
concurrently@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.0.2.tgz#4ecdfc78a72a6f626a3a5d3c2a7a81962f3663e3"
@@ -999,6 +1009,13 @@ cors@2.8.5, cors@~2.8.5:
object-assign "^4"
vary "^1"
cpu-features@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/cpu-features/-/cpu-features-0.0.2.tgz#9f636156f1155fd04bdbaa028bb3c2fbef3cea7a"
integrity sha512-/2yieBqvMcRj8McNzkycjW2v3OIUOibBfd2dLEJ0nWts8NobAxwiyw9phVNS6oDL8x8tz9F7uNVFEVpJncQpeA==
dependencies:
nan "^2.14.1"
cross-fetch@^3.0.6:
version "3.1.4"
resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.4.tgz#9723f3a3a247bf8b89039f3a380a9244e8fa2f39"
@@ -1345,6 +1362,11 @@ entities@^2.0.0:
resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
err-code@^2.0.2:
version "2.0.3"
resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9"
integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==
error-ex@^1.3.1:
version "1.3.2"
resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
@@ -2839,6 +2861,11 @@ ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
nan@^2.14.1, nan@^2.14.2:
version "2.14.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.2.tgz#f5376400695168f4cc694ac9393d0c9585eeea19"
integrity sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
@@ -3136,6 +3163,14 @@ progress@^2.0.0:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
promise-retry@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22"
integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==
dependencies:
err-code "^2.0.2"
retry "^0.12.0"
protobufjs@^6.10.2, protobufjs@^6.8.6:
version "6.10.2"
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.10.2.tgz#b9cb6bd8ec8f87514592ba3fdfd28e93f33a469b"
@@ -3347,7 +3382,7 @@ readable-stream@2, readable-stream@^2.2.2, readable-stream@^2.3.5, readable-stre
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198"
integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
@@ -3431,7 +3466,7 @@ retry-request@^4.0.0, retry-request@^4.1.1:
dependencies:
debug "^4.1.1"
retry@0.12.0:
retry@0.12.0, retry@^0.12.0:
version "0.12.0"
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
@@ -3766,6 +3801,26 @@ sprintf-js@~1.0.2:
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
ssh2-sftp-client@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/ssh2-sftp-client/-/ssh2-sftp-client-7.0.0.tgz#38c3420319156d030a80ac9db1df7459d2ba42a0"
integrity sha512-o++ryEeSbAQ6GzjuXs6BHnST6zsoWUZYt9cLy6XQ4+WdL6jNuU6UjyQzvg1J3IgN4LpCSAI+9EyTeKeIb0AfSQ==
dependencies:
concat-stream "^2.0.0"
promise-retry "^2.0.1"
ssh2 "^1.1.0"
ssh2@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/ssh2/-/ssh2-1.1.0.tgz#43dd24930e15e317687f519d6b40270d9cd00d00"
integrity sha512-CidQLG2ZacoT0Z7O6dOyisj4JdrOrLVJ4KbHjVNz9yI1vO08FAYQPcnkXY9BP8zeYo+J/nBgY6Gg4R7w4WFWtg==
dependencies:
asn1 "^0.2.4"
bcrypt-pbkdf "^1.0.2"
optionalDependencies:
cpu-features "0.0.2"
nan "^2.14.2"
sshpk@^1.7.0:
version "1.16.1"
resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"