Compare commits

...

16 Commits

Author SHA1 Message Date
90610c4ce2 feat(servers): cru added in to the server and dynamically updates vms036 2025-10-07 06:46:02 -05:00
d49c8807d0 chore(auth): cleanup unused imports 2025-10-07 06:45:12 -05:00
e31552374e fix(forecast button): added in energizer forcast 2025-10-07 06:44:37 -05:00
e16b26e313 chore(lstv2): cleanup to the main file 2025-10-07 06:44:11 -05:00
265dd8ca7a fix(printers): when reverting back to 90 seconds had a typo on what var to call 2025-10-07 06:43:47 -05:00
62e78d2a30 refactor(savexml): changes to the date section to look more clean 2025-10-07 06:43:17 -05:00
68e577c476 refactor(lots): rounded the time needed to print due to a weird issue with a decimal 2025-10-07 06:42:48 -05:00
2a05046bfd fix(labelprocessing): some strange lot issues to catch 2025-10-07 06:40:34 -05:00
6f4e987ec4 fix(xml saving): if the stirng has
\r we now flatten it so its proper and not create a new folder
2025-10-03 15:00:14 -05:00
92043d8118 fix(gp data): parsed the av instead of passing over as a string 2025-10-03 14:59:11 -05:00
63e09347bf refactor(printer delays): reduced the time formula from .9 to .7 to give a little more freedom 2025-10-03 14:58:40 -05:00
a7e1fcd3be feat(printer delay): printer delay option to grab the delay based off cycle time 2025-10-03 14:57:57 -05:00
356dd5a578 fix(ti imports): correction to the xml data with incorrect symbols passed over 2025-10-03 14:57:24 -05:00
7ed29e7432 feat(lstv2): energizer forecast added with new format 2025-10-02 08:58:43 -05:00
7e1a93512b fix(lottransfer): error in timing it would only allow for a 3min window 2025-10-02 07:48:33 -05:00
71713937c7 refactor(histoircal data): cahnge to not look at yestrday 2025-10-01 10:17:12 -05:00
35 changed files with 671 additions and 76 deletions

View File

@@ -0,0 +1,30 @@
meta {
name: Login
type: http
seq: 1
}
post {
url: {{urlv2}}/api/auth/login
body: json
auth: inherit
}
headers {
Content-Type: application/json
}
body:json {
{
"username": "matthes01",
"password": "{{v2Password}}"
}
}
script:post-response {
bru.setEnvVar("jwtV2",res.body.token)
}
settings {
encodeUrl: true
}

View File

@@ -0,0 +1,8 @@
meta {
name: Auth
seq: 2
}
auth {
mode: inherit
}

View File

@@ -0,0 +1,20 @@
meta {
name: Forecast
type: http
seq: 1
}
post {
url: {{urlv2}}/api/logistics/postforecastin
body: multipartForm
auth: inherit
}
body:multipart-form {
postForecast: @file(C:\Users\matthes01\Downloads\Rolling Forecast .xlsx)
fileType: energizer
}
settings {
encodeUrl: true
}

View File

@@ -0,0 +1,8 @@
meta {
name: DM
seq: 1
}
auth {
mode: inherit
}

View File

@@ -0,0 +1,15 @@
meta {
name: Active notifications
type: http
seq: 1
}
get {
url: {{urlv2}}/api/notify/activenotifications
body: none
auth: inherit
}
settings {
encodeUrl: true
}

View File

@@ -0,0 +1,8 @@
meta {
name: Notifcations
seq: 3
}
auth {
mode: inherit
}

View File

@@ -0,0 +1,12 @@
meta {
name: LstV2
seq: 3
}
auth {
mode: bearer
}
auth:bearer {
token: {{jwtV2}}
}

View File

@@ -10,12 +10,16 @@ post {
auth: inherit auth: inherit
} }
headers {
Cookie: {{session_cookie}}
}
body:json { body:json {
{ {
"name": "Test Server", "name": "Bethlehem",
"serverDNS": "USMCD1VMS036", "serverDNS": "USBET1VMS006",
"plantToken": "test3", "plantToken": "usbet1",
"ipAddress": "10.193.0.56", "ipAddress": "10.204.0.26",
"greatPlainsPlantCode": 0, "greatPlainsPlantCode": 0,
"lstServerPort": 4000, "lstServerPort": 4000,
"serverLoc": "E$\\LST" "serverLoc": "E$\\LST"

View File

@@ -5,11 +5,22 @@ meta {
} }
patch { patch {
url: {{url}}/lst/api/admin/server url: {{url}}/lst/api/admin/server/:token
body: none body: json
auth: inherit auth: inherit
} }
params:path {
token: usbet1
}
body:json {
{
"zipcode": 45247
}
}
settings { settings {
encodeUrl: true encodeUrl: true
} }

View File

@@ -1,4 +1,9 @@
vars { vars {
url: https://usmcd1vms036.alpla.net url: http://localhost:4200
session_cookie: session_cookie:
urlv2: http://usksc1vms006:3000
jwtV2:
} }
vars:secret [
v2Password
]

View File

@@ -1,3 +1,4 @@
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
import express from "express"; import express from "express";
import morgan from "morgan"; import morgan from "morgan";
import { createServer } from "http"; import { createServer } from "http";

View File

@@ -5,9 +5,13 @@ import { requireAuth } from "../../pkg/middleware/authMiddleware.js";
import users from "./routes/getUserRoles.js"; import users from "./routes/getUserRoles.js";
import grantRoles from "./routes/grantRole.js"; import grantRoles from "./routes/grantRole.js";
import servers from "./routes/servers/serverRoutes.js"; import servers from "./routes/servers/serverRoutes.js";
import { restrictToHosts } from "../../pkg/middleware/restrictToHosts.js";
export const setupAdminRoutes = (app: Express, basePath: string) => { export const setupAdminRoutes = (app: Express, basePath: string) => {
app.use(
basePath + "/api/admin/server", // will pass bc system admin but this is just telling us we need this
servers
);
app.use( app.use(
basePath + "/api/admin/users", basePath + "/api/admin/users",
requireAuth("user", ["systemAdmin"]), // will pass bc system admin but this is just telling us we need this requireAuth("user", ["systemAdmin"]), // will pass bc system admin but this is just telling us we need this
@@ -18,11 +22,4 @@ export const setupAdminRoutes = (app: Express, basePath: string) => {
requireAuth("user", ["systemAdmin", "admin"]), // will pass bc system admin but this is just telling us we need this requireAuth("user", ["systemAdmin", "admin"]), // will pass bc system admin but this is just telling us we need this
grantRoles grantRoles
); );
app.use(
basePath + "/api/admin/server",
requireAuth("user", ["systemAdmin", "admin"]), // will pass bc system admin but this is just telling us we need this
restrictToHosts(["usmcd1vms036", "USMCD1VMS036"]), // what servers are allowed to see the server section
servers
);
}; };

View File

@@ -9,6 +9,7 @@ import { tryCatch } from "../../../../pkg/utils/tryCatch.js";
import type { DrizzleError } from "drizzle-orm"; import type { DrizzleError } from "drizzle-orm";
import axios from "axios"; import axios from "axios";
import { createLogger } from "../../../../pkg/logger/logger.js"; import { createLogger } from "../../../../pkg/logger/logger.js";
import https from "https";
const router = Router(); const router = Router();
@@ -43,6 +44,28 @@ router.post("/", async (req: Request, res: Response) => {
if (req.hostname === "localhost" && process.env.MAIN_SERVER) { if (req.hostname === "localhost" && process.env.MAIN_SERVER) {
log.info({}, "Running in dev server about to add in a new server"); log.info({}, "Running in dev server about to add in a new server");
const axiosInstance = axios.create({
httpsAgent: new https.Agent({ rejectUnauthorized: false }),
baseURL: process.env.MAIN_SERVER, // e.g. "https://example.com"
withCredentials: true,
});
const loginRes = await axiosInstance.post(
`${process.env.MAIN_SERVER}/lst/api/auth/sign-in/username`,
{
username: process.env.MAIN_SERVER_USERNAME,
password: process.env.MAIN_SERVER_PASSWORD,
},
{
headers: { "Content-Type": "application/json" },
}
);
const setCookie = loginRes.headers["set-cookie"];
if (!setCookie) {
throw new Error("Did not receive a Set-Cookie header from login");
}
const { data, error } = await tryCatch( const { data, error } = await tryCatch(
axios.post( axios.post(
`${process.env.MAIN_SERVER}/lst/api/admin/server`, `${process.env.MAIN_SERVER}/lst/api/admin/server`,
@@ -50,7 +73,7 @@ router.post("/", async (req: Request, res: Response) => {
{ {
headers: { headers: {
"Content-Type": "application/json", "Content-Type": "application/json",
Cookie: req.headers.cookie ?? "", Cookie: setCookie.join("; "),
}, },
withCredentials: true, withCredentials: true,
} }
@@ -63,7 +86,10 @@ router.post("/", async (req: Request, res: Response) => {
"There was an error adding the server to Main Server" "There was an error adding the server to Main Server"
); );
} }
log.info({ stack: data }, "A new Server was just added to the server."); log.info(
{ stack: data?.data },
"A new Server was just added to the server."
);
} }
return res return res

View File

@@ -8,11 +8,21 @@ import { and, asc, eq } from "drizzle-orm";
const router = Router(); const router = Router();
router.get("/", async (req: Request, res: Response) => { router.get("/", async (req: Request, res: Response) => {
const token = req.query.token;
const conditions = [];
if (token !== undefined) {
conditions.push(eq(serverData.plantToken, `${token}`));
}
conditions.push(eq(serverData.active, true));
const { data, error } = await tryCatch( const { data, error } = await tryCatch(
db db
.select() .select()
.from(serverData) .from(serverData)
.where(eq(serverData.active, true)) .where(and(...conditions))
.orderBy(asc(serverData.name)) .orderBy(asc(serverData.name))
); );

View File

@@ -2,11 +2,31 @@ import { Router } from "express";
import addServer from "./addServer.js"; import addServer from "./addServer.js";
import getServers from "./getServers.js"; import getServers from "./getServers.js";
import updateServer from "./updateServer.js"; import updateServer from "./updateServer.js";
import { restrictToHosts } from "../../../../pkg/middleware/restrictToHosts.js";
import { requireAuth } from "../../../../pkg/middleware/authMiddleware.js";
const router = Router(); const router = Router();
router.get("/", getServers); router.use("/", getServers);
router.post("/", addServer); router.use(
router.patch("/", updateServer); "/",
requireAuth("user", ["systemAdmin", "admin"]),
restrictToHosts([
"usmcd1vms036",
"USMCD1VMS036",
"https://usmcd1vms036.alpla.net",
]),
addServer
);
router.use(
"/",
requireAuth("user", ["systemAdmin", "admin"]),
restrictToHosts([
"usmcd1vms036",
"USMCD1VMS036",
"https://usmcd1vms036.alpla.net",
]),
updateServer
);
export default router; export default router;

View File

@@ -1,11 +1,135 @@
import { Router } from "express"; import { Router } from "express";
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import { db } from "../../../../pkg/db/db.js";
import { serverData } from "../../../../pkg/db/schema/servers.js";
import { eq } from "drizzle-orm";
import { tryCatch } from "../../../../pkg/utils/tryCatch.js";
import axios from "axios";
import { createLogger } from "../../../../pkg/logger/logger.js";
import https from "https";
const router = Router(); const router = Router();
router.patch("/", async (req: Request, res: Response) => { router.patch("/:token", async (req: Request, res: Response) => {
const log = createLogger({ module: "admin", subModule: "update server" });
// when a server is updated and is posted from localhost or 127.0.0.1 we also want to post it to the test server so we can see it from there, we want to insert with update on conflict. // when a server is updated and is posted from localhost or 127.0.0.1 we also want to post it to the test server so we can see it from there, we want to insert with update on conflict.
res.status(200).json({ message: "Server added" }); const token = req.params.token;
const updates: Record<string, any> = {};
if (req.body?.name !== undefined) {
updates.name = req.body.name;
}
if (req.body?.serverDNS !== undefined) {
updates.serverDNS = req.body.serverDNS;
}
if (req.body?.ipAddress !== undefined) {
updates.ipAddress = req.body.ipAddress;
}
if (req.body?.greatPlainsPlantCode !== undefined) {
updates.greatPlainsPlantCode = req.body.greatPlainsPlantCode;
}
if (req.body?.lstServerPort !== undefined) {
updates.lstServerPort = req.body.lstServerPort;
}
if (req.body?.serverLoc !== undefined) {
updates.serverLoc = req.body.serverLoc;
}
if (req.body?.streetAddress !== undefined) {
updates.streetAddress = req.body.streetAddress;
}
if (req.body?.cityState !== undefined) {
updates.cityState = req.body.cityState;
}
if (req.body?.zipcode !== undefined) {
updates.zipcode = req.body.zipcode;
}
if (req.body?.contactEmail !== undefined) {
updates.contactEmail = req.body.contactEmail;
}
if (req.body?.contactPhone !== undefined) {
updates.contactPhone = req.body.contactPhone;
}
if (req.body?.customerTiAcc !== undefined) {
updates.customerTiAcc = req.body.customerTiAcc;
}
if (req.body?.active !== undefined) {
updates.active = req.body.active;
}
try {
if (Object.keys(updates).length > 0) {
await db
.update(serverData)
.set(updates)
.where(eq(serverData.plantToken, token));
}
if (req.hostname === "localhost" && process.env.MAIN_SERVER) {
log.info({}, "Running in dev server about to add in a new server");
const axiosInstance = axios.create({
httpsAgent: new https.Agent({ rejectUnauthorized: false }),
baseURL: process.env.MAIN_SERVER,
withCredentials: true,
});
const loginRes = await axiosInstance.post(
`${process.env.MAIN_SERVER}/lst/api/auth/sign-in/username`,
{
username: process.env.MAIN_SERVER_USERNAME,
password: process.env.MAIN_SERVER_PASSWORD,
},
{
headers: { "Content-Type": "application/json" },
}
);
const setCookie = loginRes.headers["set-cookie"];
if (!setCookie) {
throw new Error(
"Did not receive a Set-Cookie header from login"
);
}
const { data, error } = await tryCatch(
axios.post(
`${process.env.MAIN_SERVER}/lst/api/admin/server/${token}`,
updates,
{
headers: {
"Content-Type": "application/json",
Cookie: setCookie.join("; "),
},
withCredentials: true,
}
)
);
if (error) {
log.error(
{ stack: error },
"There was an error adding the server to Main Server"
);
}
log.info(
{ stack: data?.data },
"A new Server was just added to the server."
);
}
res.status(200).json({ message: `${token} Server was just updated` });
} catch (error) {
console.log(error);
res.status(400).json({ message: "Error Server updated", error });
}
}); });
export default router; export default router;

View File

@@ -1,12 +1,8 @@
import { Router } from "express"; import { Router } from "express";
import type { Request, Response } from "express"; import type { Request, Response } from "express";
import z from "zod";
import { db } from "../../../pkg/db/db.js"; import { db } from "../../../pkg/db/db.js";
import { userRoles } from "../../../pkg/db/schema/user_roles.js"; import { userRoles } from "../../../pkg/db/schema/user_roles.js";
import { DrizzleError, eq } from "drizzle-orm"; import { DrizzleError, eq } from "drizzle-orm";
import { requireAuth } from "../../../pkg/middleware/authMiddleware.js";
import { auth } from "../../../pkg/auth/auth.js";
import { authClient } from "../../../pkg/auth/auth-client.js";
const router = Router(); const router = Router();

View File

@@ -23,6 +23,10 @@ export default function DMButtons() {
/> />
<ForecastImport fileType={"loreal"} name={"VMI Import"} /> <ForecastImport fileType={"loreal"} name={"VMI Import"} />
<ForecastImport fileType={"pg"} name={"P&G"} /> <ForecastImport fileType={"pg"} name={"P&G"} />
<ForecastImport
fileType={"energizer"}
name={"Energizer Forecast"}
/>
</div> </div>
)} )}
{plantToken[0]?.value === "usday1" && ( {plantToken[0]?.value === "usday1" && (
@@ -35,6 +39,10 @@ export default function DMButtons() {
fileType={"energizer"} fileType={"energizer"}
name={"Energizer Truck List"} name={"Energizer Truck List"}
/> />
<ForecastImport
fileType={"energizer"}
name={"Energizer Forecast"}
/>
</div> </div>
)} )}
{plantToken[0]?.value === "usflo1" && ( {plantToken[0]?.value === "usflo1" && (

View File

@@ -19,10 +19,7 @@ import rfid from "./services/rfid/rfidService.js";
import printers from "./services/printers/printerService.js"; import printers from "./services/printers/printerService.js";
import loggerService from "./services/logger/loggerService.js"; import loggerService from "./services/logger/loggerService.js";
import ocpService from "./services/ocp/ocpService.js"; import ocpService from "./services/ocp/ocpService.js";
import { db } from "../database/dbclient.js";
import { settings } from "../database/schema/settings.js";
import os from "os"; import os from "os";
import { tryCatch } from "./globalUtils/tryCatch.js";
import { sendEmail } from "./services/notifications/controller/sendMail.js"; import { sendEmail } from "./services/notifications/controller/sendMail.js";
import notify from "./services/notifications/notifyService.js"; import notify from "./services/notifications/notifyService.js";
import eom from "./services/eom/eomService.js"; import eom from "./services/eom/eomService.js";
@@ -33,7 +30,6 @@ import {
getSettings, getSettings,
serverSettings, serverSettings,
} from "./services/server/controller/settings/getSettings.js"; } from "./services/server/controller/settings/getSettings.js";
import type { Settings } from "./types/settings.js";
// create the main prodlogin here // create the main prodlogin here
const username = "lst_user"; const username = "lst_user";

View File

@@ -26,7 +26,7 @@ export const historicalInvIMmport = async () => {
} }
// check if we have data already for today this way we dont duplicate anything. // check if we have data already for today this way we dont duplicate anything.
const today = new Date(); const today = new Date();
today.setDate(today.getDate() - 1); //today.setDate(today.getDate() - 1);
const dateCheck = data?.filter( const dateCheck = data?.filter(
(i: any) => i.histDate === format(today, "yyyy-MM-dd") (i: any) => i.histDate === format(today, "yyyy-MM-dd")
@@ -62,7 +62,8 @@ export const historicalInvIMmport = async () => {
const importInv = inv.data ? inv.data : []; const importInv = inv.data ? inv.data : [];
const eomImportData = importInv.map((i: any) => { const eomImportData = importInv.map((i: any) => {
return { return {
histDate: sql`(NOW() - INTERVAL '1 day')::date`, //histDate: sql`(NOW() - INTERVAL '1 day')::date`,
histDate: sql`(NOW())::date`,
plantToken: plantToken[0].value, plantToken: plantToken[0].value,
article: i.av, article: i.av,
articleDescription: i.Alias, articleDescription: i.Alias,

View File

@@ -1,3 +1,4 @@
import { energizerForecast } from "./mappings/energizer.js";
import { lorealForecast } from "./mappings/loralForecast.js"; import { lorealForecast } from "./mappings/loralForecast.js";
import { pNgForecast } from "./mappings/pNgForecast.js"; import { pNgForecast } from "./mappings/pNgForecast.js";
import { standardForecast } from "./mappings/standardForcast.js"; import { standardForecast } from "./mappings/standardForcast.js";
@@ -40,6 +41,14 @@ export const forecastIn = async (data: any, user: any) => {
orderData = pg.data; orderData = pg.data;
} }
if (data["fileType"] === "energizer") {
//run the standard forecast in
const eg = await energizerForecast(data["postForecast"], user);
success = eg.success ?? false;
message = eg.message ?? "Error posting standard forecast";
orderData = eg.data;
}
return { return {
success, success,
message, message,

View File

@@ -0,0 +1,95 @@
import { db } from "../../../../../../../database/dbclient.js";
import { settings } from "../../../../../../../database/schema/settings.js";
import { tryCatch } from "../../../../../../globalUtils/tryCatch.js";
import XLSX from "xlsx";
import { postForecast } from "../postForecast.js";
import { query } from "../../../../../sqlServer/prodSqlServer.js";
import { activeArticle } from "../../../../../sqlServer/querys/dataMart/article.js";
import { addDays } from "date-fns";
import { sendEmail } from "../../../../../notifications/controller/sendMail.js";
import { createLog } from "../../../../../logger/logger.js";
export const energizerForecast = 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 {
success: false,
message: `Error getting settings`,
data: e,
};
}
const plantToken = s.filter((s) => s.name === "plantToken");
const arrayBuffer = await data.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const workbook = XLSX.read(buffer, { type: "buffer" });
const sheet: any = workbook.Sheets["Sheet1"];
const range = XLSX.utils.decode_range(sheet["!ref"]);
const headers = [
"CustomerArticleNumber",
"Quantity",
"RequirementDate",
"CustomerID",
];
// formatting the data
const rows = XLSX.utils.sheet_to_json(sheet, { header: 1 }) as any;
const posting: any = [];
const customerId = 44;
for (let i = 1; i < rows.length; i++) {
const row: any = rows[i];
const material = row[0];
if (material == undefined) continue;
for (let j = 1; j < row.length; j++) {
const qty = row[j];
if (qty && qty !== 0) {
const requirementDate = rows[0][j]; // first row is dates
posting.push({
customerArticleNo: material,
quantity: qty,
requirementDate: new Date(requirementDate),
});
}
}
}
// the predefined data that will never change
const predefinedObject = {
receivingPlantId: plantToken[0].value,
documentName: `ForecastFromLST-${new Date(Date.now()).toLocaleString(
"en-US"
)}`,
sender: user.username || "lst-system",
customerId: customerId,
positions: [],
};
// add the new forecast to the predefined data
let updatedPredefinedObject = {
...predefinedObject,
positions: [...predefinedObject.positions, ...posting],
};
//post it
const forecastData: any = await postForecast(updatedPredefinedObject, user);
return {
success: forecastData.success,
message: forecastData.message,
data: forecastData.data,
};
};

View File

@@ -8,6 +8,7 @@ export const postForecast = async (data: any, user: any) => {
); );
//console.log(endpoint); //console.log(endpoint);
//console.log(req.body.orders[0]); //console.log(req.body.orders[0]);
try { try {
const results = await axios({ const results = await axios({

View File

@@ -55,7 +55,7 @@ export const consumeMaterial = async (data: Data) => {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
}); });
//console.log(results);
const { data: commandL, error: ce } = await tryCatch( const { data: commandL, error: ce } = await tryCatch(
db.insert(commandLog).values({ db.insert(commandLog).values({
commandUsed: "consumeMaterial", commandUsed: "consumeMaterial",
@@ -68,6 +68,7 @@ export const consumeMaterial = async (data: Data) => {
status: results.status, status: results.status,
}; };
} catch (error: any) { } catch (error: any) {
console.log(error);
return { return {
success: false, success: false,
status: 200, status: 200,

View File

@@ -1,4 +1,5 @@
import { freightClass } from "../../../../../globalUtils/freightClass.js"; import { freightClass } from "../../../../../globalUtils/freightClass.js";
import { escapeXml } from "../../../utils/xmlCharFixes.js";
export const loadItems = async (data: any) => { export const loadItems = async (data: any) => {
let itemGroups = ""; let itemGroups = "";
@@ -21,7 +22,9 @@ export const loadItems = async (data: any) => {
data[i].pkgHeight / 25.4 data[i].pkgHeight / 25.4
).toFixed(2)}</Dimension> ).toFixed(2)}</Dimension>
</Dimensions> </Dimensions>
<Description>${`av ${data[i].article} ${data[i].articleAlias}`}</Description> <Description>${`av ${data[i].article} ${escapeXml(
data[i].articleAlias
)}`}</Description>
<FreightClasses> <FreightClasses>
<FreightClass type="">${freightClass( <FreightClass type="">${freightClass(
data[i].pkgWeight, data[i].pkgWeight,

View File

@@ -14,6 +14,7 @@ import { loadItems } from "./loadItems.js";
import { dateCorrection } from "./dateCorrection.js"; import { dateCorrection } from "./dateCorrection.js";
import { scacCheck } from "./scacCodeCheck.js"; import { scacCheck } from "./scacCodeCheck.js";
import { postToTi } from "./postToTI.js"; import { postToTi } from "./postToTI.js";
import { escapeXml } from "../../../utils/xmlCharFixes.js";
export const tiImport = async () => { export const tiImport = async () => {
// get the plant token // get the plant token
@@ -224,21 +225,39 @@ export const tiImport = async () => {
// shipper info // shipper info
payload = payload payload = payload
.replaceAll("[plantName]", `Alpla ${plantI[0]?.sName!}`) .replaceAll("[plantName]", escapeXml(`Alpla ${plantI[0]?.sName!}`))
.replaceAll("[plantStreetAddress]", plantI[0]?.streetAddress!) .replaceAll(
.replaceAll("[plantCity]", plantI[0]?.cityState!.split(",")[0]) "[plantStreetAddress]",
.replaceAll("[plantState]", plantI[0]?.cityState!.split(",")[1]) escapeXml(plantI[0]?.streetAddress!)
.replaceAll("[plantZipCode]", plantI[0]?.zipcode!) )
.replaceAll("[contactNum]", plantI[0]?.contactPhone!) .replaceAll(
.replaceAll("[contactEmail]", plantI[0]?.contactEmail!) "[plantCity]",
escapeXml(plantI[0]?.cityState!.split(",")[0])
)
.replaceAll(
"[plantState]",
escapeXml(plantI[0]?.cityState!.split(",")[1])
)
.replaceAll("[plantZipCode]", escapeXml(plantI[0]?.zipcode!))
.replaceAll("[contactNum]", escapeXml(plantI[0]?.contactPhone!))
.replaceAll("[contactEmail]", escapeXml(plantI[0]?.contactEmail!))
// customer info // customer info
.replaceAll("[customerName]", orderData[0].addressAlias) .replaceAll("[customerName]", escapeXml(orderData[0].addressAlias))
.replaceAll("[customerStreetAddress]", orderData[0].streetAddress) .replaceAll(
.replaceAll("[customerCity]", orderData[0].city.split(",")[0]) "[customerStreetAddress]",
.replaceAll("[customerState]", orderData[0].city.split(",")[1]) escapeXml(orderData[0].streetAddress)
.replaceAll("[customerZip]", orderData[0].zipCode) )
.replaceAll("[customerPO]", orderData[0].Header) .replaceAll(
"[customerCity]",
escapeXml(orderData[0].city.split(",")[0])
)
.replaceAll(
"[customerState]",
escapeXml(orderData[0].city.split(",")[1])
)
.replaceAll("[customerZip]", escapeXml(orderData[0].zipCode))
.replaceAll("[customerPO]", escapeXml(orderData[0].Header))
// .replaceAll( // .replaceAll(
// "[glCoding]", // "[glCoding]",
// `52410-${ // `52410-${

View File

@@ -2,21 +2,27 @@ import fs from "fs";
import path from "path"; import path from "path";
import { createLog } from "../../logger/logger.js"; import { createLog } from "../../logger/logger.js";
const cleanStringForFilename = (str: string) => {
// Remove CRLF and LF newlines
return str.replace(/(\r\n|\n|\r)/gm, " "); // or "" if you want no space at all
};
/** /**
* Save XML string to /xml/ with timestamp in name * Save XML string to /xml/ with timestamp in name
* @param xmlContent The XML string * @param xmlContent The XML string
* @param prefix File prefix (ex: request or response) * @param prefix File prefix (ex: request or response)
*/ */
export const saveXml = (xmlContent: string, prefix: string = "request") => { export const saveXml = (xmlContent: string, nameString: string = "request") => {
const prefix = cleanStringForFilename(nameString);
try { try {
const now = new Date(); const now = new Date();
// Format YYYYMMDDHHmm // Format YYYYMMDDHHmm
const timestamp = `${now.getFullYear()}${String( const timestamp = `${now.getFullYear()}-${String(
now.getMonth() + 1 now.getMonth() + 1
).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}-${String( ).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}-${String(
now.getHours() now.getHours()
).padStart(2, "0")}-${String(now.getMinutes()).padStart(2, "0")}`; ).padStart(2, "0")}${String(now.getMinutes()).padStart(2, "0")}`;
// Ensure xml folder path is always relative to project root // Ensure xml folder path is always relative to project root
const xmlDir = path.resolve(process.cwd(), "xml"); const xmlDir = path.resolve(process.cwd(), "xml");

View File

@@ -0,0 +1,9 @@
export const escapeXml = (str: string) => {
if (!str) return "";
return str
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&apos;");
};

View File

@@ -62,7 +62,7 @@ export const labelingProcess = async ({
(l: any) => l.MachineID === macId[0]?.HumanReadableId (l: any) => l.MachineID === macId[0]?.HumanReadableId
); );
if (filteredLot.length === 0) { if (filteredLot?.length === 0) {
createLog( createLog(
"error", "error",
"labeling", "labeling",
@@ -85,7 +85,7 @@ export const labelingProcess = async ({
(l: any) => l.MachineID === macId[0]?.HumanReadableId (l: any) => l.MachineID === macId[0]?.HumanReadableId
); );
if (!filteredLot || filteredLot.length === 0) { if (!filteredLot || filteredLot?.length === 0) {
createLog( createLog(
"error", "error",
"labeling", "labeling",
@@ -138,7 +138,7 @@ export const labelingProcess = async ({
let dualPrinting = settingData.filter((d) => d.name === "dualPrinting")[0] let dualPrinting = settingData.filter((d) => d.name === "dualPrinting")[0]
?.value; ?.value;
if (filteredLot.length > 1 && dualPrinting === "0") { if (filteredLot?.length > 1 && dualPrinting === "0") {
createLog( createLog(
"error", "error",
"labeling", "labeling",
@@ -151,7 +151,7 @@ export const labelingProcess = async ({
}; };
} }
if (filteredLot.length > 1 && dualPrinting === "1") { if (filteredLot?.length > 1 && dualPrinting === "1") {
// send over for dual printing processing // send over for dual printing processing
createLog( createLog(
"info", "info",
@@ -193,7 +193,7 @@ export const labelingProcess = async ({
} }
// check if we actaully have a lot passed over so we do not error out again. // check if we actaully have a lot passed over so we do not error out again.
if (filteredLot.length === 0) { if (filteredLot?.length === 0) {
createLog( createLog(
"error", "error",
"labeling", "labeling",
@@ -234,8 +234,8 @@ export const labelingProcess = async ({
// do we want to over run // do we want to over run
if ( if (
filteredLot[0].overPrinting === "no" && filteredLot[0]?.overPrinting === "no" &&
filteredLot[0].Remaining <= 0 filteredLot[0]?.Remaining <= 0
) { ) {
createLog( createLog(
"error", "error",

View File

@@ -88,7 +88,7 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
// shift split // shift split
const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":"); const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":");
//console.log(shiftTimeSplit); console.log(parseInt(shiftTimeSplit[0]) - 1);
// Current time // Current time
const now = new Date(); const now = new Date();
@@ -97,12 +97,14 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
now.getFullYear(), now.getFullYear(),
now.getMonth(), now.getMonth(),
1, //now.getDate(), 1, //now.getDate(),
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[0]) - 1 : 5, // this will parse the hour to remove teh zero shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[0]) : 5, // this will parse the hour to remove teh zero
shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) + 3 : 3, shiftTimeSplit.length > 0 ? parseInt(shiftTimeSplit[1]) : 3,
0, 0,
0 0
); );
console.log("target", target.toLocaleString(), "Now", now.toLocaleString());
// to early time // to early time
const early = new Date( const early = new Date(
now.getFullYear(), now.getFullYear(),
@@ -114,6 +116,8 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
0 0
); );
console.log("early", early.toLocaleString(), "Now", now.toLocaleString());
// next month just to be here // next month just to be here
const nextMonth = new Date( const nextMonth = new Date(
now.getFullYear(), now.getFullYear(),
@@ -125,6 +129,13 @@ export const lotMaterialTransfer = async (data: NewLotData) => {
0 0
); );
console.log(
"nextMonth",
nextMonth.toLocaleString(),
"Now",
now.toLocaleString()
);
// console.log(early, target); // console.log(early, target);
// if we are to early return early only if we are sending over eom // if we are to early return early only if we are sending over eom
if (data.type === "eom" && (early > now || target < now)) { if (data.type === "eom" && (early > now || target < now)) {

View File

@@ -6,11 +6,13 @@ import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { getLots } from "../controller/lots/lots.js"; import { getLots } from "../controller/lots/lots.js";
import { getPrinters } from "../controller/printers/getPrinters.js"; import { getPrinters } from "../controller/printers/getPrinters.js";
import { createLog } from "../../logger/logger.js"; import { createLog } from "../../logger/logger.js";
import { printerDelayByLot } from "./printerDelayByLot.js";
export const assignedPrinters = async () => { export const assignedPrinters = async () => {
createLog("debug", "ocp", "ocp", "Lot assignment check"); createLog("debug", "ocp", "ocp", "Lot assignment check");
const { data: lot, error: lotError } = await tryCatch(getLots()); const { data: lot, error: lotError } = await tryCatch(getLots());
const l: any = lot; const l: any = lot;
if (lotError) { if (lotError) {
return { return {
success: false, success: false,
@@ -41,6 +43,9 @@ export const assignedPrinters = async () => {
data: [], data: [],
}; };
} }
// update the printers if we have the setting checked
printerDelayByLot(l.data);
const { data: print, error: printerError } = await tryCatch(getPrinters()); const { data: print, error: printerError } = await tryCatch(getPrinters());
if (printerError) { if (printerError) {

View File

@@ -0,0 +1,111 @@
import { eq, sql } from "drizzle-orm";
import { db } from "../../../../database/dbclient.js";
import { printerData } from "../../../../database/schema/printers.js";
import { settings } from "../../../../database/schema/settings.js";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { createLog } from "../../logger/logger.js";
import { delay } from "../../../globalUtils/delay.js";
import { getPrinters } from "../controller/printers/getPrinters.js";
//**The logic here will be when the setting is active to utilize the lots times it will update the printDelay in the printer data table */
export const printerDelayByLot = async (lot: any) => {
const { data: settingData, error: settingError } = await tryCatch(
db.select().from(settings)
);
if (settingError) {
return {
success: false,
message: "There was an error getting the settings.",
settingError,
};
}
// get the plantToken
const printDelay = settingData.filter((n) => n.name === "lotPrintDelay");
const ignorePrinters = [
"Autolabeler",
"pdf24",
"PDF24",
"zecchetti_1",
"zecchetti2",
];
const printers = (await getPrinters()) as any;
const p = printers.data;
if (printDelay[0].value === "0") {
for (let i = 0; i < p.length; i++) {
if (p[i].printDelay > 90) {
if (ignorePrinters.includes(p[i].name)) continue;
const { data, error } = await tryCatch(
db
.update(printerData)
.set({
printDelay: "90",
upd_date: sql`NOW()`,
})
.where(
eq(printerData.humanReadableId, lot[i].printerID)
)
);
// if (data) {
// createLog(
// "info",
// "printers",
// "ocp",
// `${printerData.name} had its delay time updated to 90 seconds `
// );
// }
// if (error) {
// createLog(
// "error",
// "printers",
// "ocp",
// `${printerData.name} encountered an error updating the printer delay time `
// );
// }
await delay(500);
}
}
}
if (printDelay[0].value === "1") {
for (let i = 0; i < lot.length; i++) {
if (ignorePrinters.includes(lot[i].PrinterName)) continue;
const { data, error } = await tryCatch(
db
.update(printerData)
.set({
printDelay: lot[i].timeTOmakeInSeconds,
upd_date: sql`NOW()`,
})
.where(eq(printerData.humanReadableId, lot[i].printerID))
);
// if (data) {
// createLog(
// "info",
// "printers",
// "ocp",
// `${lot[i].PrinterName} had its delay time updated to ${lot[
// i
// ].timeTOmakeInSeconds.toFixed(2)} seconds `
// );
// }
// if (error) {
// createLog(
// "error",
// "printers",
// "ocp",
// `${lot[i].PrinterName} encountered an error updating the printer delay time `
// );
// }
await delay(500);
}
}
};

View File

@@ -280,6 +280,14 @@ const newSettings = [
serviceBelowsTo: "admin", serviceBelowsTo: "admin",
roleToChange: "admin", roleToChange: "admin",
}, },
{
name: "lotPrintDelay",
value: `0`,
description:
"Changes the print delay to be based on the pallet completion time",
serviceBelowsTo: "admin",
roleToChange: "admin",
},
]; ];
export const areSettingsIn = async () => { export const areSettingsIn = async () => {
// get the roles // get the roles

View File

@@ -81,10 +81,11 @@ export const runGPQuery = async (gpCheck: GPCheck) => {
PO: n.PO.trim(), PO: n.PO.trim(),
Supplier: n.Supplier.trim(), Supplier: n.Supplier.trim(),
Item: n.Item.trim(), Item: n.Item.trim(),
article: // article:
n.Item.split("-").length > 1 // n.Item.split("-").length > 1
? n.Item.split("-")[1].trim() // ? n.Item.split("-")[1].trim()
: "No article", // : 0,
article: Number.parseInt(n.Item.split("-")[1]) || 0,
Type: n.Type.trim(), Type: n.Type.trim(),
Location: n.Location.trim(), Location: n.Location.trim(),
Date_Recived: format(n.Date_Recived, "M/d/yyyy"), Date_Recived: format(n.Date_Recived, "M/d/yyyy"),

View File

@@ -1,14 +1,14 @@
export const lotQuery = ` export const lotQuery = `
select IdMaschinen_ProdPlanung as LabelOnlineID, select IdMaschinen_ProdPlanung as LabelOnlineID,
IdMaschine as machineID, x.IdMaschine as machineID,
MaschinenStandort as MachineLocation, MaschinenStandort as MachineLocation,
MaschinenBez as MachineDescription, MaschinenBez as MachineDescription,
IdProdPlanung as lot, x.IdProdPlanung as lot,
prolink.lot as ProlinkLot, prolink.lot as ProlinkLot,
IdArtikelvarianten as AV, x.IdArtikelvarianten as AV,
ArtikelVariantenBez as Alias, x.ArtikelVariantenBez as Alias,
convert(varchar, add_date, 20) as Add_Date, convert(varchar, x.add_date, 20) as Add_Date,
Add_user, x.Add_user,
idEtikettenDrucker as printerID, idEtikettenDrucker as printerID,
b.name as PrinterName, b.name as PrinterName,
CAST(TotalPlannedLoadingUnits as float) as PlannedQTY, CAST(TotalPlannedLoadingUnits as float) as PlannedQTY,
@@ -23,21 +23,26 @@ select IdMaschinen_ProdPlanung as LabelOnlineID,
else 'no' end as overPrinting, else 'no' end as overPrinting,
CustomerHumanReadableId as CustomerId, CustomerHumanReadableId as CustomerId,
CustomerName as CustomerName, CustomerName as CustomerName,
idMaschine as MachineID, x.idMaschine as MachineID,
prolink.lastProlinkUpdate as lastProlinkUpdate, prolink.lastProlinkUpdate as lastProlinkUpdate,
IdEtikettenLayoutPalette as palletLabel, IdEtikettenLayoutPalette as palletLabel,
AnzahlKopienPalette as pallerCopies, AnzahlKopienPalette as pallerCopies,
IdEtikettenLayoutKarton as cartonLabel, IdEtikettenLayoutKarton as cartonLabel,
AnzahlKopienKarton as cartonCopies, AnzahlKopienKarton as cartonCopies,
IsTechnicallyReleased IsTechnicallyReleased,
DruckStatus as allowPrinting,
p.MaschZyklus as cycleTime,
x.StueckzahlJePalette,
p.WerkzeugKavität,
ROUND((((x.StueckzahlJePalette /p.WerkzeugKavität) * p.MaschZyklus) * (p.MaschAuslastung/100)) * .75,0) as timeTOmakeInSeconds
--* --*
from AlplaPROD_test1.dbo.V_Maschinen_ProdPlanungen x (nolock) from AlplaPROD_test1.dbo.V_Maschinen_ProdPlanungen x (nolock)
join join
[test1_AlplaPROD2.0_Read].[productionControlling].[ProducedLot] on [test1_AlplaPROD2.0_Read].[productionControlling].[ProducedLot](nolock) on
x.IdProdPlanung = x.IdProdPlanung =
[test1_AlplaPROD2.0_Read].[productionControlling].[ProducedLot].ProductionLotHumanReadableId [test1_AlplaPROD2.0_Read].[productionControlling].[ProducedLot].ProductionLotHumanReadableId
left join left join
[test1_AlplaPROD2.0_Read].masterData.Printer as b on [test1_AlplaPROD2.0_Read].masterData.Printer (nolock) as b on
x.IdEtikettenDrucker = b.HumanReadableId x.IdEtikettenDrucker = b.HumanReadableId
-- adding in prolink lot -- adding in prolink lot
left join left join
@@ -51,5 +56,16 @@ select IdMaschinen_ProdPlanung as LabelOnlineID,
) as prolink on ) as prolink on
x.idMaschine = prolink.prolinkMachineId x.idMaschine = prolink.prolinkMachineId
where IsTechnicallyReleased = 1 ----packagin info
--left join
--[test1_AlplaPROD2.0_Read].[masterData].[PackagingInstruction] (nolock) pkg on
--pkg.HumanReadableId = x.IdVpkVorschrift
-- cycle time info
left join
AlplaPROD_test1.dbo.V_ProdPlanung (nolock) as p on
p.IdProdPlanung = x.IdProdPlanung
where IsTechnicallyReleased = 1 and DruckStatus = 1
`; `;