All checks were successful
Build and Push LST Docker Image / docker (push) Successful in 1m32s
183 lines
4.6 KiB
TypeScript
183 lines
4.6 KiB
TypeScript
import XLSX from "xlsx";
|
|
import { runDatamartQuery } from "../datamart/datamart.controller.js";
|
|
import { db } from "../db/db.controller.js";
|
|
import { settings } from "../db/schema/settings.schema.js";
|
|
import {
|
|
type SqlQuery,
|
|
sqlQuerySelector,
|
|
} from "../prodSql/prodSqlQuerySelector.utils.js";
|
|
import { excelDateStuff } from "../utils/excelToDate.utils.js";
|
|
import { returnFunc } from "../utils/returnHelper.utils.js";
|
|
import { tryCatch } from "../utils/trycatch.utils.js";
|
|
import { postData } from "./logistics.dm.postData.js";
|
|
|
|
export const pNgForecast = async (data: any, user: any) => {
|
|
/**
|
|
* Post a standard forecast based on the standard template.
|
|
*/
|
|
|
|
const { data: s, error: e } = await tryCatch(db.select().from(settings));
|
|
|
|
if (e) {
|
|
return {
|
|
sucess: false,
|
|
message: `Error getting settings`,
|
|
data: e,
|
|
};
|
|
}
|
|
|
|
const pNg = s.filter((n: any) => n.name === "pNgAddress");
|
|
|
|
const avSQLQuery = sqlQuerySelector(`datamart.activeArticles`) as SqlQuery;
|
|
|
|
if (!avSQLQuery.success) {
|
|
return returnFunc({
|
|
success: false,
|
|
level: "error",
|
|
module: "logistics",
|
|
subModule: "forecast",
|
|
message: `Error getting Article info`,
|
|
data: [avSQLQuery.message],
|
|
notify: true,
|
|
});
|
|
}
|
|
|
|
const { data: a, error: ae } = await tryCatch(
|
|
runDatamartQuery({ name: "activeArticles", options: {} }),
|
|
);
|
|
|
|
if (ae) {
|
|
return {
|
|
success: false,
|
|
message: "Error getting active av",
|
|
data: [],
|
|
};
|
|
}
|
|
|
|
const article: any = a?.data;
|
|
|
|
const buffer = Buffer.from(data.buffer);
|
|
|
|
const workbook = XLSX.read(buffer, { type: "buffer" });
|
|
|
|
//const sheet: any = workbook.Sheets[sheetName];
|
|
const sheet: any = workbook.Sheets["SchedAgreementUIConfigSpreadshe"];
|
|
const range = XLSX.utils.decode_range(sheet["!ref"]);
|
|
|
|
const headers = [];
|
|
for (let C = range.s.c; C <= range.e.c; ++C) {
|
|
const cellAddress = XLSX.utils.encode_cell({ r: 0, c: C }); // row 0 = Excel row 1
|
|
const cell = sheet[cellAddress];
|
|
headers.push(cell ? cell.v : undefined);
|
|
}
|
|
|
|
//console.log(headers);
|
|
const forecastData: any = XLSX.utils.sheet_to_json(sheet, {
|
|
defval: "",
|
|
header: headers,
|
|
range: 1,
|
|
});
|
|
|
|
const groupedByCustomer: any = forecastData.reduce((acc: any, item: any) => {
|
|
const id = item.CustomerID;
|
|
if (!acc[id]) {
|
|
acc[id] = [];
|
|
}
|
|
acc[id].push(item);
|
|
return acc;
|
|
}, {});
|
|
|
|
const foreCastData: any = [];
|
|
|
|
for (const [customerID, forecast] of Object.entries(groupedByCustomer)) {
|
|
//console.log(`Running for Customer ID: ${customerID}`);
|
|
const newForecast: any = forecast;
|
|
|
|
const predefinedObject = {
|
|
receivingPlantId: process.env.PROD_PLANT_TOKEN ?? "test1",
|
|
documentName: `ForecastFromLST-${new Date(Date.now()).toLocaleString(
|
|
"en-US",
|
|
)}`,
|
|
sender: user.username || "lst-system",
|
|
customerId: pNg[0]?.value,
|
|
positions: [],
|
|
};
|
|
|
|
// map everything out for each order
|
|
const nForecast = newForecast.map((o: any) => {
|
|
// const invoice = i.filter(
|
|
// (i: any) => i.deliveryAddress === parseInt(customerID)
|
|
// );
|
|
// if (!invoice) {
|
|
// return;
|
|
// }
|
|
|
|
return {
|
|
customerArticleNo: parseInt(o["Customer Item No."] ?? "0", 10),
|
|
requirementDate: excelDateStuff(parseInt(o["Request Date"] ?? "0", 10)),
|
|
quantity: o["Remaining Qty to be Shipped"],
|
|
};
|
|
});
|
|
|
|
// check to make sure the av belongs in this plant.
|
|
const onlyNumbers = nForecast.filter((n: any) => n.quantity > 0);
|
|
const filteredForecast: any = [];
|
|
|
|
for (let i = 0; i < nForecast.length; i++) {
|
|
//console.log(nForecast[i].customerArticleNo);
|
|
const activeAV = article.filter(
|
|
(c: any) =>
|
|
c?.CustomerArticleNumber ===
|
|
nForecast[i]?.customerArticleNo.toString() &&
|
|
// validate it works via the default address
|
|
c?.IdAdresse === parseInt(pNg[0]?.value ?? "139", 10),
|
|
);
|
|
|
|
if (activeAV.length > 0) {
|
|
filteredForecast.push(onlyNumbers[i]);
|
|
}
|
|
}
|
|
|
|
if (filteredForecast.length === 0) {
|
|
console.log("Nothing to post");
|
|
return {
|
|
success: true,
|
|
message: "No forecast to be posted",
|
|
data: foreCastData,
|
|
};
|
|
}
|
|
|
|
// do that fun combining thing
|
|
const updatedPredefinedObject = {
|
|
...predefinedObject,
|
|
positions: [...predefinedObject.positions, ...filteredForecast],
|
|
};
|
|
|
|
//console.log(updatedPredefinedObject);
|
|
|
|
// post the orders to the server
|
|
const posting: any = await postData(
|
|
{
|
|
type: "forecast",
|
|
endpoint: "/public/v1.0/DemandManagement/DELFOR",
|
|
data: updatedPredefinedObject as any,
|
|
},
|
|
user,
|
|
);
|
|
|
|
foreCastData.push({
|
|
customer: customerID,
|
|
//totalOrders: orders?.length(),
|
|
success: posting.success,
|
|
message: posting.message,
|
|
data: posting.data,
|
|
});
|
|
}
|
|
|
|
return {
|
|
success: foreCastData[0].success,
|
|
message: foreCastData[0].message,
|
|
data: foreCastData,
|
|
};
|
|
};
|