From c25c2d006a491150b37a67d89673ba4228262c0a Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Mon, 14 Apr 2025 22:15:44 -0500 Subject: [PATCH] feat(quality): addpallet and cycle pallets added --- database/schema/qualityRequest.ts | 7 +- .../quality/controller/addNewPallet.ts | 171 ++++++++++++++++++ .../quality/controller/getRequests.ts | 25 +++ .../quality/controller/qualityCycle.ts | 106 +++++++++++ server/services/quality/qualityService.ts | 27 ++- server/services/quality/route/getRequest.ts | 34 ++++ .../services/quality/route/postNewRequest.ts | 73 ++++++++ .../sqlServer/querys/quality/request.ts | 14 ++ 8 files changed, 450 insertions(+), 7 deletions(-) create mode 100644 server/services/quality/controller/addNewPallet.ts create mode 100644 server/services/quality/controller/getRequests.ts create mode 100644 server/services/quality/controller/qualityCycle.ts create mode 100644 server/services/quality/route/getRequest.ts create mode 100644 server/services/quality/route/postNewRequest.ts create mode 100644 server/services/sqlServer/querys/quality/request.ts diff --git a/database/schema/qualityRequest.ts b/database/schema/qualityRequest.ts index 05036ea..a75b52e 100644 --- a/database/schema/qualityRequest.ts +++ b/database/schema/qualityRequest.ts @@ -7,6 +7,7 @@ import { boolean, uuid, uniqueIndex, + integer, } from "drizzle-orm/pg-core"; import { createInsertSchema, createSelectSchema } from "drizzle-zod"; import { z } from "zod"; @@ -23,11 +24,11 @@ export const qualityRequest = pgTable( locationAtRequest: text("locationAtRequest"), warehouseMovedTo: text("warehouseMovedTo"), locationMovedTo: text("locationMovedTo"), - durationToMove: numeric("durationToMove"), + durationToMove: integer("durationToMove"), locationDropOff: text("locationDropOff"), - palletStatus: numeric("palletStatus"), + palletStatus: integer("palletStatus"), palletStatusText: text("palletStatusText"), - palletRequest: numeric("palletRequest"), + palletRequest: integer("palletRequest"), add_date: timestamp("add_date").defaultNow(), add_user: text("add_user").default("LST"), upd_date: timestamp("upd_date").defaultNow(), diff --git a/server/services/quality/controller/addNewPallet.ts b/server/services/quality/controller/addNewPallet.ts new file mode 100644 index 0000000..1dd5593 --- /dev/null +++ b/server/services/quality/controller/addNewPallet.ts @@ -0,0 +1,171 @@ +import { eq, sql } from "drizzle-orm"; +import { db } from "../../../../database/dbclient.js"; +import { qualityRequest } from "../../../../database/schema/qualityRequest.js"; +import { tryCatch } from "../../../globalUtils/tryCatch.js"; +import { query } from "../../sqlServer/prodSqlServer.js"; +import { qrequestQuery } from "../../sqlServer/querys/quality/request.js"; +import { timeZoneFix } from "../../../globalUtils/timeZoneFix.js"; + +export const addNewPallet = async (data: any, user: string) => { + /** + * Post new pallets + */ + + if (parseInt(data.runningNr) <= 0) { + return { + sucess: false, + message: "Please add a valid running number.", + }; + } + const updateQuery = qrequestQuery.replaceAll( + "[runningNumber]", + data.runningNr + ); + const { data: c, error: ce } = await tryCatch( + db + .select() + .from(qualityRequest) + .where(eq(qualityRequest.runningNr, data.runningNr)) + ); + if (ce) { + return { + success: false, + message: "There was an error getting the quality request", + data: ce, + }; + } + + const palletData: any = c; + // if the pallet exist then tell the user to check on it + if ( + (palletData && palletData[0]?.palletStatus === 1) || + palletData[0]?.palletStatus === 4 + ) { + return { + success: false, + message: `Running number ${data.runningNr} is already pending or reactivated please follow up with the warehouse team on status to be moved.`, + }; + } + + if (palletData.length > 0) { + try { + // get the pallet info from stock + const { data: p, error: pe } = await tryCatch( + query(updateQuery, "quality request") + ); + + if (pe) { + return { + success: false, + message: "There was an error getting the pallet from stock", + data: pe, + }; + } + const pData = { + warehouseAtRequest: p[0].warehouseAtRequest, + locationAtRequest: p[0].locationAtRequest, + warehouseMovedTo: null, + locationMovedTo: null, + palletStatus: 4, + durationToMove: 0, + palletStatusText: "reactivated", + palletRequest: palletData[0].palletStatus + 1, + upd_user: user, + upd_date: new Date(timeZoneFix()), + }; + + const { data: u, error } = await tryCatch( + db + .update(qualityRequest) + .set(pData) + .where(eq(qualityRequest.runningNr, data.runningNr)) + ); + + if (error) { + return { + success: false, + message: `Running number: ${data.runningNr} encountered and error reactivated.`, + data: error, + }; + } + + if (data) { + return { + success: true, + message: `Running number: ${data.runningNr} was just reactivated.`, + data: u, + }; + } + } catch (error) { + return { + success: false, + message: + "There was an error updating the pallet in quality request", + data: error, + }; + } + } + + // add new pallet + try { + const { data: p, error: pe } = await tryCatch( + query(updateQuery, "quality request") + ); + + if (p.length === 0) { + return { + success: false, + message: `Running Number ${data.runningNr} dose not exist in stock.`, + }; + } + + if (pe) { + return { + success: false, + message: "There was an error getting the pallet from stock", + data: pe, + }; + } + + const nData = { + article: p[0].article, + description: p[0].description, + runningNr: p[0].runningNr, + lotNr: p[0].lotNr, + warehouseAtRequest: p[0].warehouseAtRequest, + locationAtRequest: p[0].locationAtRequest, + locationDropOff: data.moveTo, + palletStatus: 1, + palletStatusText: "pending", + palletRequest: 1, + add_user: user, + upd_user: user, + }; + + const { data: u, error } = await tryCatch( + db.insert(qualityRequest).values(nData) + ); + + if (error) { + return { + success: false, + message: `Running number: ${data.runningNr} encountered and error reactivated.`, + data: error, + }; + } + + if (data) { + return { + success: true, + message: `Running number: ${data.runningNr} was just added.`, + data: u, + }; + } + } catch (error) { + return { + success: false, + message: "There was an error adding the pallet in quality request", + data: error, + }; + } +}; diff --git a/server/services/quality/controller/getRequests.ts b/server/services/quality/controller/getRequests.ts new file mode 100644 index 0000000..fc98af1 --- /dev/null +++ b/server/services/quality/controller/getRequests.ts @@ -0,0 +1,25 @@ +import { desc } from "drizzle-orm"; +import { db } from "../../../../database/dbclient.js"; +import { qualityRequest } from "../../../../database/schema/qualityRequest.js"; +import { tryCatch } from "../../../globalUtils/tryCatch.js"; +import qualityBlockingMonitor from "../../notifications/controller/notifications/qualityBlocking.js"; + +export const getRequest = async () => { + const { data, error } = await tryCatch( + db.select().from(qualityRequest).orderBy(desc(qualityRequest.add_date)) + ); + + if (error) { + return { + success: false, + message: "There was an error getting the quality request", + data: error, + }; + } + + return { + success: true, + message: "Quality request pallets.", + data, + }; +}; diff --git a/server/services/quality/controller/qualityCycle.ts b/server/services/quality/controller/qualityCycle.ts new file mode 100644 index 0000000..c4c7932 --- /dev/null +++ b/server/services/quality/controller/qualityCycle.ts @@ -0,0 +1,106 @@ +import { eq, inArray } from "drizzle-orm"; +import { db } from "../../../../database/dbclient.js"; +import { qualityRequest } from "../../../../database/schema/qualityRequest.js"; +import { tryCatch } from "../../../globalUtils/tryCatch.js"; +import { createLog } from "../../logger/logger.js"; +import { qrequestQuery } from "../../sqlServer/querys/quality/request.js"; +import { query } from "../../sqlServer/prodSqlServer.js"; +import { differenceInMinutes } from "date-fns"; +import { timeZoneFix } from "../../../globalUtils/timeZoneFix.js"; + +export const qualityCycle = async () => { + /** + * Cycles the pallets in the quality request to see whats been moved or changed. + */ + + // pallet request check interval 5min check to start + //setInterval(async () => { + // create the date stuff + const currentTime = new Date(Date.now()); + + // pull in all current pallets from our db + const { data, error } = await tryCatch( + db + .select() + .from(qualityRequest) + .where(inArray(qualityRequest.palletStatus, [1, 4, 5])) + ); + + if (error) { + createLog( + "error", + "lst", + "quality", + `There was an error getting quality request data: ${error}` + ); + return { + success: false, + message: "There was an error getting quality request data", + }; + } + const lstQData: any = data; + // get the pallets that currentStat is moved + // const res = await runQuery(palletMoveCheck, "palletCheck"); + + if (lstQData.length != 0) { + for (let i = 0; i < lstQData.length; i++) { + // run the pallet query we will compare the data. + // console.log(lstQData[i]); + //update query with plant token + + // change the update the pallet number + const qPalletNumber = qrequestQuery.replaceAll( + "[runningNumber]", + lstQData[i].runningNr + ); + let prodData: any = []; + + prodData = await query(qPalletNumber, "Quality update check"); + + if ( + lstQData[i]?.locationAtRequest != prodData[0]?.locationAtRequest + ) { + // time to do the pallet update stuff + const qDataPost = { + warehouseMovedTo: prodData[0]?.warehouseAtRequest, + locationMovedTo: prodData[0]?.locationAtRequest, + durationToMove: differenceInMinutes( + timeZoneFix(), + lstQData[i].upd_date + ), + palletStatus: 2, + palletStatusText: "moved", + upd_date: new Date(timeZoneFix()), + upd_user: "LST_System", + }; + + const updatePallet = await db + .update(qualityRequest) + .set(qDataPost) + .where(eq(qualityRequest.runningNr, lstQData[i].runningNr)); + + createLog( + "info", + "lst", + "quality", + `Pallet ${lstQData[i].runningNr} was updated` + ); + } else { + createLog( + "debug", + "lst", + "quality", + `Pallet ${ + lstQData[i].runningNr + } has not been moved yet it has been pending for ${differenceInMinutes( + timeZoneFix(), + lstQData[i].upd_date + )} min(s)` + ); + } + } + } else { + createLog("debug", "lst", "quality", "nothing to update"); + } + //}, 5 * 60 * 1000); // every 5 min +}; diff --git a/server/services/quality/qualityService.ts b/server/services/quality/qualityService.ts index b87ae85..900383d 100644 --- a/server/services/quality/qualityService.ts +++ b/server/services/quality/qualityService.ts @@ -1,9 +1,19 @@ import { OpenAPIHono } from "@hono/zod-openapi"; -import { qualityRequest } from "../../../database/schema/qualityRequest.js"; -import { db } from "../../../database/dbclient.js"; +import { qualityCycle } from "./controller/qualityCycle.js"; +import request from "./route/getRequest.js"; +import postReq from "./route/postNewRequest.js"; + +// pallet status data. +export const statusOptions = [ + { name: "pending", uid: "1" }, + { name: "moved", uid: "2" }, + { name: "removed", uid: "3" }, + { name: "reactivated", uid: "4" }, + { name: "canceled", uid: "5" }, +]; const app = new OpenAPIHono(); -const routes = [] as const; +const routes = [request, postReq] as const; const appRoutes = routes.forEach((route) => { app.route("/quality", route); @@ -15,6 +25,15 @@ app.all("/quality/*", (c) => { }); }); -await db.select().from(qualityRequest); +/** + * Initial and run the cycle up for checking the pallet moves for quality + */ +setTimeout(() => { + qualityCycle(); +}, 1000 * 5); + +setInterval(() => { + qualityCycle(); +}, 1000 * 60); export default app; diff --git a/server/services/quality/route/getRequest.ts b/server/services/quality/route/getRequest.ts new file mode 100644 index 0000000..afc17a9 --- /dev/null +++ b/server/services/quality/route/getRequest.ts @@ -0,0 +1,34 @@ +// an external way to creating logs +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { responses } from "../../../globalUtils/routeDefs/responses.js"; +import { getRequest } from "../controller/getRequests.js"; +import { tryCatch } from "../../../globalUtils/tryCatch.js"; + +const app = new OpenAPIHono({ strict: false }); + +app.openapi( + createRoute({ + tags: ["quality"], + summary: "Returns all pallets requested", + method: "get", + path: "/getrequest", + responses: responses(), + }), + async (c) => { + const { data, error } = await tryCatch(getRequest()); + + if (error) { + return c.json({ + success: false, + message: "There was an error getting the printers", + }); + } + + return c.json({ + success: data.success, + message: data.message, + data: data.data, + }); + } +); +export default app; diff --git a/server/services/quality/route/postNewRequest.ts b/server/services/quality/route/postNewRequest.ts new file mode 100644 index 0000000..427787d --- /dev/null +++ b/server/services/quality/route/postNewRequest.ts @@ -0,0 +1,73 @@ +// an external way to creating logs +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { responses } from "../../../globalUtils/routeDefs/responses.js"; +import { getRequest } from "../controller/getRequests.js"; +import { tryCatch } from "../../../globalUtils/tryCatch.js"; +import { authMiddleware } from "../../auth/middleware/authMiddleware.js"; +import { addNewPallet } from "../controller/addNewPallet.js"; +import { verify } from "hono/jwt"; + +const app = new OpenAPIHono({ strict: false }); +const Body = z.object({ + runningNr: z.number().openapi({ example: 1528 }), + moveTo: z.string().openapi({ example: "rework" }), +}); +app.openapi( + createRoute({ + tags: ["quality"], + summary: "Returns all pallets requested", + method: "post", + path: "/newrequest", + middleware: authMiddleware, + request: { + body: { + content: { + "application/json": { schema: Body }, + }, + }, + }, + responses: responses(), + }), + async (c) => { + const authHeader = c.req.header("Authorization"); + const token = authHeader?.split("Bearer ")[1] || ""; + + const payload = await verify(token, process.env.JWT_SECRET!); + const user: any = payload.user; + + const { data: b, error: e } = await tryCatch(c.req.json()); + + if (e) { + return c.json({ + success: false, + message: "Missing Data", + }); + } + const body: any = b; + // console.log(body); + // if (!body.runningNr) { + // return c.json({ + // success: false, + // message: "Missing mandatory data.", + // }); + // } + + const { data, error } = await tryCatch( + addNewPallet(body, user?.username) + ); + + if (error) { + return c.json({ + success: false, + message: "There was an error adding the new pallet", + }); + } + + return c.json({ + success: data?.success, + message: data?.message, + data: data?.data, + }); + } +); +export default app; diff --git a/server/services/sqlServer/querys/quality/request.ts b/server/services/sqlServer/querys/quality/request.ts new file mode 100644 index 0000000..7311eb6 --- /dev/null +++ b/server/services/sqlServer/querys/quality/request.ts @@ -0,0 +1,14 @@ +export const qrequestQuery = ` +select IdArtikelVarianten as article, +ArtikelVariantenBez as description, +Lfdnr as runningNr, +Produktionslos as lotNr, +IdWarenlager as idWarehouse, +WarenLagerKurzBez as warehouseAtRequest, +IdLagerAbteilung as idLocation, +LagerAbteilungKurzBez as locationAtRequest, +BewegungsDatumMax as lastMove +from AlplaPROD_test1.dbo.V_LagerPositionenBarcodes (nolock) + +where /* VerfuegbareMengeSum = 0 and */ IdLagerAbteilung not in (0, 20000, 21000) and lfdnr = [runningNumber] +`;