207 lines
6.5 KiB
JavaScript
207 lines
6.5 KiB
JavaScript
const queries = require("../graphql-client/queries");
|
|
const moment = require("moment-timezone");
|
|
const converter = require("json-2-csv");
|
|
const logger = require("../utils/logger");
|
|
const fs = require("fs");
|
|
|
|
let Client = require("ssh2-sftp-client");
|
|
|
|
const client = require("../graphql-client/graphql-client").client;
|
|
const { sendServerEmail } = require("../email/sendemail");
|
|
|
|
const ftpSetup = {
|
|
host: process.env.PODIUM_HOST,
|
|
port: process.env.PODIUM_PORT,
|
|
username: process.env.PODIUM_USER,
|
|
password: process.env.PODIUM_PASSWORD,
|
|
debug:
|
|
process.env.NODE_ENV !== "production"
|
|
? (message, ...data) => logger.log(message, "DEBUG", "api", null, data)
|
|
: () => {},
|
|
algorithms: {
|
|
serverHostKey: ["ssh-rsa", "ssh-dss", "rsa-sha2-256", "rsa-sha2-512", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384"]
|
|
}
|
|
};
|
|
|
|
exports.default = async (req, res) => {
|
|
// Only process if in production environment.
|
|
if (process.env.NODE_ENV !== "production") {
|
|
return res.sendStatus(403);
|
|
}
|
|
// Only process if the appropriate token is provided.
|
|
if (req.headers["x-imex-auth"] !== process.env.AUTOHOUSE_AUTH_TOKEN) {
|
|
return res.sendStatus(401);
|
|
}
|
|
|
|
// Send immediate response and continue processing.
|
|
res.status(202).json({
|
|
success: true,
|
|
message: "Processing request ...",
|
|
timestamp: new Date().toISOString()
|
|
});
|
|
|
|
try {
|
|
logger.log("podium-start", "DEBUG", "api", null, null);
|
|
const allCSVResults = [];
|
|
const allErrors = [];
|
|
|
|
const { bodyshops } = await client.request(queries.GET_PODIUM_SHOPS); //Query for the List of Bodyshop Clients.
|
|
const specificShopIds = req.body.bodyshopIds; // ['uuid];
|
|
const { start, end, skipUpload } = req.body; //YYYY-MM-DD
|
|
|
|
const shopsToProcess =
|
|
specificShopIds?.length > 0 ? bodyshops.filter((shop) => specificShopIds.includes(shop.id)) : bodyshops;
|
|
logger.log("podium-shopsToProcess-generated", "DEBUG", "api", null, null);
|
|
|
|
if (shopsToProcess.length === 0) {
|
|
logger.log("podium-shopsToProcess-empty", "DEBUG", "api", null, null);
|
|
return;
|
|
}
|
|
|
|
await processShopData(shopsToProcess, start, end, skipUpload, allCSVResults, allErrors);
|
|
|
|
await sendServerEmail({
|
|
subject: `Podium Report ${moment().format("MM-DD-YY")}`,
|
|
text: `Errors:\n${JSON.stringify(allErrors, null, 2)}\n\nUploaded:\n${JSON.stringify(
|
|
allCSVResults.map((x) => ({
|
|
imexshopid: x.imexshopid,
|
|
filename: x.filename,
|
|
count: x.count,
|
|
result: x.result
|
|
})),
|
|
null,
|
|
2
|
|
)}`
|
|
});
|
|
|
|
logger.log("podium-end", "DEBUG", "api", null, null);
|
|
} catch (error) {
|
|
logger.log("podium-error", "ERROR", "api", null, { error: error.message, stack: error.stack });
|
|
}
|
|
};
|
|
|
|
async function processShopData(shopsToProcess, start, end, skipUpload, allCSVResults, allErrors) {
|
|
for (const bodyshop of shopsToProcess) {
|
|
const erroredJobs = [];
|
|
try {
|
|
logger.log("podium-start-shop-extract", "DEBUG", "api", bodyshop.id, {
|
|
shopname: bodyshop.shopname
|
|
});
|
|
|
|
const { jobs, bodyshops_by_pk } = await client.request(queries.PODIUM_QUERY, {
|
|
bodyshopid: bodyshop.id,
|
|
start: start ? moment(start).startOf("day") : moment().subtract(2, "days").startOf("day"),
|
|
...(end && { end: moment(end).endOf("day") })
|
|
});
|
|
|
|
const podiumObject = jobs.map((j) => {
|
|
return {
|
|
"Podium Account ID": bodyshops_by_pk.podiumid,
|
|
"First Name": j.ownr_co_nm ? null : j.ownr_fn,
|
|
"Last Name": j.ownr_co_nm ? j.ownr_co_nm : j.ownr_ln,
|
|
"SMS Number": null,
|
|
"Phone 1": j.ownr_ph1,
|
|
"Phone 2": j.ownr_ph2,
|
|
Email: j.ownr_ea,
|
|
"Delivered Date":
|
|
(j.actual_delivery && moment(j.actual_delivery).tz(bodyshop.timezone).format("MM/DD/YYYY")) || ""
|
|
};
|
|
});
|
|
|
|
if (erroredJobs.length > 0) {
|
|
logger.log("podium-failed-jobs", "ERROR", "api", bodyshop.id, {
|
|
count: erroredJobs.length,
|
|
jobs: JSON.stringify(erroredJobs.map((j) => j.job.ro_number))
|
|
});
|
|
}
|
|
|
|
const csvObj = {
|
|
bodyshopid: bodyshop.id,
|
|
imexshopid: bodyshop.imexshopid,
|
|
csv: converter.json2csv(podiumObject, { emptyFieldValue: "" }),
|
|
filename: `${bodyshop.podiumid}-${moment().format("YYYYMMDDTHHMMss")}.csv`,
|
|
count: podiumObject.length
|
|
};
|
|
|
|
if (skipUpload) {
|
|
fs.writeFileSync(`./logs/${csvObj.filename}`, csvObj.csv);
|
|
} else {
|
|
await uploadViaSFTP(csvObj);
|
|
}
|
|
|
|
allCSVResults.push({
|
|
bodyshopid: bodyshop.id,
|
|
imexshopid: bodyshop.imexshopid,
|
|
podiumid: bodyshop.podiumid,
|
|
count: csvObj.count,
|
|
filename: csvObj.filename,
|
|
result: csvObj.result
|
|
});
|
|
|
|
logger.log("podium-end-shop-extract", "DEBUG", "api", bodyshop.id, {
|
|
shopname: bodyshop.shopname
|
|
});
|
|
} catch (error) {
|
|
//Error at the shop level.
|
|
logger.log("podium-error-shop", "ERROR", "api", bodyshop.id, { error: error.message, stack: error.stack });
|
|
|
|
allErrors.push({
|
|
bodyshopid: bodyshop.id,
|
|
imexshopid: bodyshop.imexshopid,
|
|
podiumid: bodyshop.podiumid,
|
|
fatal: true,
|
|
errors: [error.toString()]
|
|
});
|
|
} finally {
|
|
allErrors.push({
|
|
bodyshopid: bodyshop.id,
|
|
imexshopid: bodyshop.imexshopid,
|
|
podiumid: bodyshop.podiumid,
|
|
errors: erroredJobs.map((ej) => ({
|
|
ro_number: ej.job?.ro_number,
|
|
jobid: ej.job?.id,
|
|
error: ej.error
|
|
}))
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
async function uploadViaSFTP(csvObj) {
|
|
const sftp = new Client();
|
|
sftp.on("error", (errors) =>
|
|
logger.log("podium-sftp-connection-error", "ERROR", "api", csvObj.bodyshopid, {
|
|
error: errors.message,
|
|
stack: errors.stack
|
|
})
|
|
);
|
|
try {
|
|
//Connect to the FTP and upload all.
|
|
await sftp.connect(ftpSetup);
|
|
|
|
try {
|
|
csvObj.result = await sftp.put(Buffer.from(csvObj.csv), `${csvObj.filename}`);
|
|
logger.log("podium-sftp-upload", "DEBUG", "api", csvObj.bodyshopid, {
|
|
imexshopid: csvObj.imexshopid,
|
|
filename: csvObj.filename,
|
|
result: csvObj.result
|
|
});
|
|
} catch (error) {
|
|
logger.log("podium-sftp-upload-error", "ERROR", "api", csvObj.bodyshopid, {
|
|
filename: csvObj.filename,
|
|
error: error.message,
|
|
stack: error.stack
|
|
});
|
|
throw error;
|
|
}
|
|
} catch (error) {
|
|
logger.log("podium-sftp-error", "ERROR", "api", csvObj.bodyshopid, {
|
|
error: error.message,
|
|
stack: error.stack
|
|
});
|
|
throw error;
|
|
} finally {
|
|
sftp.end();
|
|
}
|
|
}
|