From 88f61c8eaa32a581094b04b5e18c654040dbeb92 Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Tue, 19 Aug 2025 16:00:49 -0500 Subject: [PATCH] feat(ocp): materials contorls and transfer to next lot logic --- .../eom/materialCheck/MaterialCheck.tsx | 3 + .../eom/materialsData/MaterialData.tsx | 211 +++++++++++++++ .../consumption/TransferToNextLot.tsx | 250 ++++++++++++++++++ .../ocp/controller/labeling/labelProcess.ts | 13 +- .../ocp/controller/materials/lotTransfer.ts | 206 +++++++++++++++ .../ocp/controller/materials/mainMaterial.ts | 114 +++++++- server/services/ocp/ocpService.ts | 4 + .../ocp/routes/materials/lotTransfer.ts | 64 +++++ server/services/server/utils/settingsCheck.ts | 14 + .../sqlServer/querys/ocp/mainMaterial.ts | 127 +++++++-- .../sqlServer/querys/warehouse/labelInfo.ts | 44 ++- 11 files changed, 997 insertions(+), 53 deletions(-) create mode 100644 frontend/src/components/eom/materialCheck/MaterialCheck.tsx create mode 100644 frontend/src/components/eom/materialsData/MaterialData.tsx create mode 100644 frontend/src/components/logistics/materialHelper/consumption/TransferToNextLot.tsx create mode 100644 server/services/ocp/controller/materials/lotTransfer.ts create mode 100644 server/services/ocp/routes/materials/lotTransfer.ts diff --git a/frontend/src/components/eom/materialCheck/MaterialCheck.tsx b/frontend/src/components/eom/materialCheck/MaterialCheck.tsx new file mode 100644 index 0000000..bb3b9fc --- /dev/null +++ b/frontend/src/components/eom/materialCheck/MaterialCheck.tsx @@ -0,0 +1,3 @@ +export default function MaterialCheck() { + return
MaterialCheck
; +} diff --git a/frontend/src/components/eom/materialsData/MaterialData.tsx b/frontend/src/components/eom/materialsData/MaterialData.tsx new file mode 100644 index 0000000..4023908 --- /dev/null +++ b/frontend/src/components/eom/materialsData/MaterialData.tsx @@ -0,0 +1,211 @@ +import { LstCard } from "@/components/extendedUI/LstCard"; +import { Button } from "@/components/ui/button"; +import { Calendar } from "@/components/ui/calendar"; +import { Popover, PopoverTrigger } from "@/components/ui/popover"; +import { Skeleton } from "@/components/ui/skeleton"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; +import { useSessionStore } from "@/lib/store/sessionStore"; +import { useModuleStore } from "@/lib/store/useModuleStore"; +import { cn } from "@/lib/utils"; +import { PopoverContent } from "@radix-ui/react-popover"; +import { Link, useRouter } from "@tanstack/react-router"; +import { startOfMonth } from "date-fns"; +import { format } from "date-fns-tz"; +import { CalendarIcon } from "lucide-react"; +import { useState } from "react"; +import { toast } from "sonner"; +import KFP from "../KFP"; + +export default function MaterialData() { + const { modules } = useModuleStore(); + const { user } = useSessionStore(); + const router = useRouter(); + const [date, setDate] = useState(); + + if (!user) { + router.navigate({ to: "/" }); + } + const eomMod = modules.filter((m) => m.name === "eom"); + // the users current role for eom is? + const role: any = + user?.roles.filter((r) => r.module_id === eomMod[0].module_id) || ""; + + const tabs = [ + { + key: "kfp", + label: "Key Figures", + roles: ["admin", "systemAdmin"], + content: , + }, + { + key: "fg", + label: "Finished Goods", + roles: ["admin", "systemAdmin"], + content: , + }, + { + key: "mm", + label: "Main Material", + roles: ["admin", "systemAdmin"], + content: , + }, + { + key: "mb", + label: "Master Batch", + roles: ["admin", "systemAdmin"], + content: , + }, + { + key: "ab", + label: "Additive", + roles: ["admin", "systemAdmin"], + content: , + }, + { + key: "pp", + label: "Purchased Preforms", + roles: ["admin", "systemAdmin"], + content: , + }, + { + key: "pre", + label: "Preforms", + roles: ["admin", "systemAdmin"], + content: , + }, + { + key: "pkg", + label: "Packaging", + roles: ["admin", "systemAdmin"], + content: , + }, + { + key: "ui", + label: "Undefined Items", + roles: ["admin"], + content: , + }, + ]; + return ( +
+
+ + + + + + + + +
+ +
+
+ + + + {tabs.map((tab) => { + if (tab.roles.includes(role[0].role)) + return ( + + {tab.label} + + ); + })} + + {tabs.map((tab) => { + if (tab.roles.includes(role[0].role)) + return ( + + {tab.content} + + ); + })} + +
+ ); +} + +function DummyContent() { + return ( + + + + + Av + Description + Material Type + Waste + Loss / Gain $$ + + + + + {Array(10) + .fill(0) + .map((_, i) => ( + + + + {i} + + + + + + + + + + + + + + + {/* + + */} + + ))} + +
+
+ ); +} diff --git a/frontend/src/components/logistics/materialHelper/consumption/TransferToNextLot.tsx b/frontend/src/components/logistics/materialHelper/consumption/TransferToNextLot.tsx new file mode 100644 index 0000000..b517184 --- /dev/null +++ b/frontend/src/components/logistics/materialHelper/consumption/TransferToNextLot.tsx @@ -0,0 +1,250 @@ +import { LstCard } from "@/components/extendedUI/LstCard"; +import { Button } from "@/components/ui/button"; +import { CardHeader } from "@/components/ui/card"; +import { useAppForm } from "@/utils/formStuff"; +import axios from "axios"; +import { useState } from "react"; +import { toast } from "sonner"; + +export default function TransferToNextLot() { + const [gaylordFilled, setGaylordFilled] = useState([0]); + + const form = useAppForm({ + defaultValues: { + runnungNumber: "", + lotNumber: "", + originalAmount: "", + }, + onSubmit: async ({ value }) => { + //console.log(transferData); + //toast.success("603468: qty: 361, was transfered to lot:24897"); + try { + const res = await axios.post("/api/ocp/materiallottransfer", { + runnungNumber: Number(value.runnungNumber), + lotNumber: Number(value.lotNumber), + originalAmount: Number(value.originalAmount), + level: Number( + gaylordFilled.length === 1 + ? 0.25 + : gaylordFilled.length === 2 + ? 0.5 + : gaylordFilled.length === 3 + ? 0.75 + : gaylordFilled.length === 4 && 0.95 + ), + }); + + if (res.data.success) { + toast.success(`${res.data.message}`); + form.reset(); + } + //console.log(res.data); + + if (!res.data.success) { + toast.error(res.data.message); + } + } catch (error) { + if (error) { + console.log(error); + //toast.error(error) + } + } + }, + }); + return ( +
+ + +

+ Material Transfer to Next lot +

+
+
+
+
+
+ +
+ + + + +
+
+ +
+
+
+
+
+ +
{ + e.preventDefault(); + form.handleSubmit(); + }} + > +
+ ( + + )} + /> +
+
+ ( + + )} + /> +
+ ( + + )} + /> +
+
+
+ + + Transfer To Lot + + +
+
+
+
+
+
+
+ + +

+ Moving material to the next lot. +

+
+ +
+
    +
  1. + 1. Grab the gaylord running number + from the gaylord at the line/next to + the tschritter +
  2. +
  3. + 2. Grab the next lot number you are + going to be running (or the one that + state no Main material prepared) +
  4. +
  5. + 3. Enter the total gaylord weight + (this is how much the gaylord + weighed when it came in from the + supplier.) +
  6. +
  7. + 4. *Click the level of the gaylord + (this is just an estimate to move to + the next lot.) +
  8. +
  9. + 5. type in running number on the + gaylord. +
  10. +
  11. 6. Type in the new lot number.
  12. +
  13. 7. Press "Transfer To Lot"
  14. +
+

+

+ * to reduce the time needed to get the + lot going we will use an estimate of how + full the gaylord is. +

+

+ NOTE: This is not the return process, + this process will just get the gaylord + to the next lot. +

+
+
+
+
+
+
+
+ ); +} diff --git a/server/services/ocp/controller/labeling/labelProcess.ts b/server/services/ocp/controller/labeling/labelProcess.ts index 04b4a80..2da4e2d 100644 --- a/server/services/ocp/controller/labeling/labelProcess.ts +++ b/server/services/ocp/controller/labeling/labelProcess.ts @@ -170,20 +170,15 @@ export const labelingProcess = async ({ }; } - // check mm is good + // check the material... mm,color (auto and manual combined), pkg const mmStaged = await isMainMatStaged(filteredLot[0]); - if (!mmStaged) { - createLog( - "error", - "labeling", - "ocp", - `Main material is not prepaired for lot ${filteredLot[0].lot}` - ); + if (!mmStaged.success) { + createLog("error", "labeling", "ocp", mmStaged.message); return { success: false, - message: `Main material is not prepaired for lot ${filteredLot[0].lot}`, + message: mmStaged.message, }; } diff --git a/server/services/ocp/controller/materials/lotTransfer.ts b/server/services/ocp/controller/materials/lotTransfer.ts new file mode 100644 index 0000000..b115267 --- /dev/null +++ b/server/services/ocp/controller/materials/lotTransfer.ts @@ -0,0 +1,206 @@ +import { eq } from "drizzle-orm"; +import { db } from "../../../../../database/dbclient.js"; +import { printerData } from "../../../../../database/schema/printers.js"; +import { runProdApi } from "../../../../globalUtils/runProdApi.js"; +import { tryCatch } from "../../../../globalUtils/tryCatch.js"; +import { createLog } from "../../../logger/logger.js"; +import { query } from "../../../sqlServer/prodSqlServer.js"; +import { labelInfo } from "../../../sqlServer/querys/warehouse/labelInfo.js"; + +type NewLotData = { + runnungNumber: number; + lotNumber: number; + originalAmount: number; + level: number; +}; + +/** + * Move manual material to a new lot. + * + * The data sent over should be + * Running number + * Lot number + * Orignal Quantity + * level of gaylord + */ +export const lotMaterialTransfer = async (data: NewLotData) => { + // get the barcode, and layoutID from the running number + const { data: label, error: labelError } = (await tryCatch( + query( + labelInfo.replace("[runningNr]", `${data.runnungNumber}`), + "Get label info" + ) + )) as any; + + if (labelError) { + createLog( + "error", + "materials", + "ocp", + "There was an error getting the label info" + ); + return { + success: false, + message: "There was an error getting the label info", + data: labelError, + }; + } + + // if ( + // label.data[0]?.stockStatus === "notOnStock" || + // label.data.length === 0 + // ) { + // createLog( + // "error", + // "materials", + // "ocp", + // `${data.runnungNumber}: dose not exist or no longer in stock.` + // ); + // return { + // success: false, + // message: `${data.runnungNumber}: dose not exist or no longer in stock.`, + // data: [], + // }; + // } + + if (label.data[0]?.stockStatus === "onStock") { + createLog( + "error", + "materials", + "ocp", + `${data.runnungNumber}: currently in stock and not consumed to a lot.` + ); + return { + success: false, + message: `${data.runnungNumber}: currently in stock and not consumed to a lot.`, + data: [], + }; + } + + // get the pdf24 printer id + const { data: printer, error: printerError } = (await tryCatch( + db.select().from(printerData).where(eq(printerData.name, "PDF24")) + )) as any; + + if (printerError) { + createLog( + "error", + "materials", + "ocp", + "There was an error the printer info" + ); + return { + success: false, + message: "There was an error the printer info", + data: printerError, + }; + } + // calculate the remaining amount bascially it will be orignal number * level sent over + // level should be sent in a decimal .25 .5 .75 .95 the 95 will allow basically the what looks to be a full gaylord but we always want to consume something + const newQty = (data.originalAmount * data.level).toFixed(0); + + // reprint the label and send it to pdf24 + const reprintData = { + clientId: 999, + runningNo: label?.data[0].runnungNumber, + printerId: printer[0].humanReadableId, + layoutId: label?.data[0].labelLayout, + noOfCopies: 0, + quantity: newQty, + } as any; + + const { data: reprint, error: reprintError } = (await tryCatch( + runProdApi({ + endpoint: "/public/v1.0/ProductionLabelling/ReprintLabel", + data: [reprintData], + }) + )) as any; + + if (!reprint.success) { + createLog( + "error", + "materials", + "ocp", + `RN:${data.runnungNumber}, Error: ${reprint.data.data.message}` + ); + return { + success: false, + message: `RN:${data.runnungNumber}, Error: ${reprint.data.data.message}`, + data: reprint, + }; + } + // return the label back to fm1 lane id 10001 + + const matReturnData = { + barcode: label?.data[0].Barcode, + laneId: 10001, + }; + const { data: matReturn, error: matReturError } = (await tryCatch( + runProdApi({ + endpoint: + "/public/v1.0/IssueMaterial/ReturnPartiallyConsumedManualMaterial", + data: [matReturnData], + }) + )) as any; + + if (!matReturn.success) { + createLog( + "error", + "materials", + "ocp", + `RN:${data.runnungNumber}, Error ${matReturn.data.data.errors[0].message}` + ); + return { + success: false, + message: `RN:${data.runnungNumber}, Error ${matReturn.data.data.errors[0].message}`, + data: matReturn, + }; + } + // consume to the lot provided. + const consumeLot = { + productionLot: data.lotNumber, + barcode: label?.data[0].Barcode, + }; + const { data: matConsume, error: matConsumeError } = (await tryCatch( + runProdApi({ + endpoint: + "/public/v1.0/IssueMaterial/ConsumeNonPreparedManualMaterial", + data: [consumeLot], + }) + )) as any; + + if (!matConsume.success) { + createLog( + "error", + "materials", + "ocp", + `RN:${data.runnungNumber}, Error ${matConsume.data.data.errors[0].message}` + ); + return { + success: false, + message: `RN:${data.runnungNumber}, Error ${matConsume.data.data.errors[0].message}`, + data: matConsume, + }; + } + + createLog( + "info", + "materials", + "ocp", + `RN:${data.runnungNumber}: qty: ${newQty}, was transfered to lot:${data.lotNumber}` + ); + return { + success: true, + message: `RN:${data.runnungNumber}: qty: ${newQty}, was transfered to lot:${data.lotNumber}`, + data: [], + }; +}; + +// setTimeout(async () => { +// lotMaterialTransfer({ +// runnungNumber: 603468, +// lotNumber: 24897, +// originalAmount: 380, +// level: 0.95, +// }); +// }, 5000); diff --git a/server/services/ocp/controller/materials/mainMaterial.ts b/server/services/ocp/controller/materials/mainMaterial.ts index cbe69b6..c47f660 100644 --- a/server/services/ocp/controller/materials/mainMaterial.ts +++ b/server/services/ocp/controller/materials/mainMaterial.ts @@ -1,12 +1,14 @@ import { tryCatch } from "../../../../globalUtils/tryCatch.js"; import { createLog } from "../../../logger/logger.js"; +import { serverSettings } from "../../../server/controller/settings/getSettings.js"; import { query } from "../../../sqlServer/prodSqlServer.js"; import { machineCheck } from "../../../sqlServer/querys/ocp/machineId.js"; import { mmQuery } from "../../../sqlServer/querys/ocp/mainMaterial.js"; export const isMainMatStaged = async (lot: any) => { + const set = serverSettings.length === 0 ? [] : serverSettings; // make staged false by deefault and error logged if theres an issue - let isStaged = false; + let isStaged = { message: "Material is staged", success: true }; const { data, error } = (await tryCatch( query( @@ -26,7 +28,10 @@ export const isMainMatStaged = async (lot: any) => { "ocp", `The machine dose not require mm to print and book in.` ); - return true; + return { + message: "Machine dose not require material to be staged", + success: true, + }; } // strangly the lot is not always sending over in slc so adding this in for now to see what line is cauing this issue @@ -51,20 +56,101 @@ export const isMainMatStaged = async (lot: any) => { const res: any = r.data; - createLog( - "info", - "mainMaterial", - "ocp", - `MainMaterial results: ${JSON.stringify(res)}` - ); - - if (res[0].Staged >= 1) { - isStaged = true; - } - - // if (res[0].noShortage === "good") { + // if (res[0].Staged >= 1) { // isStaged = true; // } + + createLog("info", "mainMaterial", "ocp", `Maint material query ran.`); + + const mainMateiral = res.filter((n: any) => n.IsMainMaterial); + + if (mainMateiral[0]?.noMaterialShortage === "no") { + isStaged = { + message: `Main material: ${mainMateiral[0].MaterialHumanReadableId} - ${mainMateiral[0].MaterialDescription}: is not staged for ${lot.lot} `, + success: false, + }; + } + + // we need to filter the color stuff and then look for includes instead of a standard name. this way we can capture a everything and not a single type + // for manual consume color if active to check colors + const checkColorSetting = set.filter((n) => n.name === "checkColor"); + + if (checkColorSetting[0].value === "1") { + const autoConsumeColor = res.filter( + (n: any) => !n.IsMainMaterial && !n.isManual + ); + if ( + autoConsumeColor.some( + (n: any) => n.autoConsumeCheck === "autoConsumeNOK" + ) + ) { + const onlyNOK = autoConsumeColor.filter( + (n: any) => n.autoConsumeCheck === "autoConsumeNOK" + ); + isStaged = { + message: `lot: ${lot.lot}, is missing: ${onlyNOK + .map( + (o: any) => + `${o.MaterialHumanReadableId} - ${o.MaterialDescription}` + ) + .join(",\n ")} for autoconsume`, + success: false, + }; + } + + // // for manual consume color + const manualConsumeColor = res.filter( + (n: any) => !n.IsMainMaterial && n.isManual + ); + if ( + manualConsumeColor.some( + (n: any) => n.noMaterialShortage === "yes" + ) + ) { + isStaged = { + message: `lot: ${lot.lot}, is missing: ${manualConsumeColor + .map( + (o: any) => + `${o.MaterialHumanReadableId} - ${o.MaterialDescription}` + ) + .join(",\n ")} for manual Material`, + success: false, + }; + } + } else { + createLog( + "info", + "mainMaterial", + "ocp", + "Color check is not active." + ); + } + + // // if we want to check the packaging + const checkPKGSetting = set.filter((n) => n.name === "checkPKG"); + if (checkPKGSetting[0].value === "1") { + const packagingCheck = res.filter( + (n: any) => !n.IsMainMaterial && n.isManual + ); + if (packagingCheck.some((n: any) => n.noPKGShortage === "noPkg")) { + isStaged = { + message: `lot: ${lot.lot}, is missing: ${packagingCheck + .map( + (o: any) => + `${o.MaterialHumanReadableId} - ${o.MaterialDescription}` + ) + .join(",\n ")} for pkg`, + success: false, + }; + } + } else { + createLog( + "info", + "mainMaterial", + "ocp", + "PKG check is not active." + ); + } } catch (err) { createLog( "error", diff --git a/server/services/ocp/ocpService.ts b/server/services/ocp/ocpService.ts index fafa6f5..0cc18ac 100644 --- a/server/services/ocp/ocpService.ts +++ b/server/services/ocp/ocpService.ts @@ -24,6 +24,7 @@ import { deleteLabels } from "../../globalUtils/dbCleanUp/labelCleanUp.js"; import bookInLabel from "./routes/labeling/bookIn.js"; import labelRatio from "./routes/labeling/getLabelRatio.js"; import resetRatio from "./routes/labeling/resetLabelRatio.js"; +import materialTransferLot from "./routes/materials/lotTransfer.js"; const app = new OpenAPIHono(); @@ -47,6 +48,8 @@ const routes = [ //dyco dycoCon, dycoClose, + // materials + materialTransferLot, ] as const; const setting = await db.select().from(settings); @@ -101,4 +104,5 @@ setInterval(() => { setInterval(() => { updatePrinters(); }, 1000 * 60 * 60 * 24); + export default app; diff --git a/server/services/ocp/routes/materials/lotTransfer.ts b/server/services/ocp/routes/materials/lotTransfer.ts new file mode 100644 index 0000000..34b8b21 --- /dev/null +++ b/server/services/ocp/routes/materials/lotTransfer.ts @@ -0,0 +1,64 @@ +// an external way to creating logs +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { responses } from "../../../../globalUtils/routeDefs/responses.js"; +import { tryCatch } from "../../../../globalUtils/tryCatch.js"; +import { apiHit } from "../../../../globalUtils/apiHits.js"; + +import { lotMaterialTransfer } from "../../controller/materials/lotTransfer.js"; + +const app = new OpenAPIHono({ strict: false }); + +const LotTransfer = z.object({ + runnungNumber: z.number().openapi({ example: 1234 }), + lotNumber: z.number().openapi({ example: 1235 }), + originalAmount: z.number().openapi({ example: 457 }), + level: z.number().openapi({ examples: [0.24, 0.5, 0.75, 0.95] }), +}); + +app.openapi( + createRoute({ + tags: ["ocp"], + summary: "Transfers a gaylord of material to provided lot", + method: "post", + path: "/materiallottransfer", + request: { + body: { content: { "application/json": { schema: LotTransfer } } }, + }, + responses: responses(), + }), + async (c) => { + //const hours = c.req.query("hours"); + const { data: bodyData, error: bodyError } = await tryCatch( + c.req.json() + ); + apiHit(c, { endpoint: "/materiallottransfer", lastBody: bodyData }); + + if (bodyError) { + return c.json({ + success: false, + message: "You are missing data", + }); + } + + const { data: transferMaterial, error: transferError } = await tryCatch( + lotMaterialTransfer(bodyData) + ); + + if (transferError) { + console.log(transferError); + return c.json({ + success: false, + message: + "There was an error transfering the material to the next lot.", + data: transferError, + }); + } + + return c.json({ + success: transferMaterial.success, + message: transferMaterial.message, + data: transferMaterial.data, + }); + } +); +export default app; diff --git a/server/services/server/utils/settingsCheck.ts b/server/services/server/utils/settingsCheck.ts index ea3d9ce..377d6ce 100644 --- a/server/services/server/utils/settingsCheck.ts +++ b/server/services/server/utils/settingsCheck.ts @@ -245,6 +245,20 @@ const newSettings = [ roleToChange: "admin", }, // temp settings can be deleted at a later date once that code is removed + { + name: "checkColor", + value: `0`, + description: "Checks autoconsume and manual consume color", + serviceBelowsTo: "admin", + roleToChange: "admin", + }, + { + name: "checkPKG", + value: `0`, + description: "Checks checks if we have enough packaging or not", + serviceBelowsTo: "admin", + roleToChange: "admin", + }, { name: "siloAdjMigrations", value: `0`, diff --git a/server/services/sqlServer/querys/ocp/mainMaterial.ts b/server/services/sqlServer/querys/ocp/mainMaterial.ts index 019e77e..fc6e3e1 100644 --- a/server/services/sqlServer/querys/ocp/mainMaterial.ts +++ b/server/services/sqlServer/querys/ocp/mainMaterial.ts @@ -1,22 +1,117 @@ +// export const mmQuery = ` +// SELECT lot.ProductionLotHumanReadableId, +// case when SourcingState in (1, 2) then 1 +// when x.ProvidedAmount > 0 then 1 +// when x.EffectiveConsumption > 0 then 1 +// else 0 end as Staged, +// x.ProvidedAmount as Provided, +// x.EffectiveConsumption as consumption, +// x.TotalDemand as totalNeeded, +// /* remaining needed to complete the lot */ +// x.TotalDemand - x.EffectiveConsumption as remainingNeeded, +// /* do we have enough staged or scanned to the lot? */ +// case when (case when x.ProvidedAmount <> 0 then x.ProvidedAmount else x.EffectiveConsumption end) > x.TotalDemand then 'good' else 'bad' end as noShortage , +// x.IsManualProcess as isManual, +// MaterialHumanReadableId +// FROM [test1_AlplaPROD2.0_Read].[issueMaterial].[MaterialDemand] x (nolock) +// left join +// [test1_AlplaPROD2.0_Read].[issueMaterial].[ProductionLot] as lot on +// x.ProductionLotId = lot.Id +// where lot.ProductionLotHumanReadableId = [lotNumber] +// and IsMainMaterial = 1 +// `; + export const mmQuery = ` -SELECT lot.ProductionLotHumanReadableId, - case when SourcingState in (1, 2) then 1 - when x.ProvidedAmount > 0 then 1 - when x.EffectiveConsumption > 0 then 1 - else 0 end as Staged, - x.ProvidedAmount as Provided, - x.EffectiveConsumption as consumption, - x.TotalDemand as totalNeeded, +use [test1_AlplaPROD2.0_Read] +/* +checks all needed material including pkg + +we only want to monitor the manual materials and the mm materail to make sure they are good. + +for auto consume materails this will be compared with another query. + +*/ +SELECT lot.ProductionLotHumanReadableId +,MaterialHumanReadableId +,MaterialDescription + --IsMainMaterial, + --case when SourcingState in (1, 2) then 1 + --when x.ProvidedAmount > 0 then 1 + --when x.EffectiveConsumption > 0 then 1 + --else 0 end as Staged, + ,x.ProvidedAmount as Provided + ,x.EffectiveConsumption as consumption + ,x.TotalDemand as totalDemand , + case when cp.Pieces = 1 then (lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces else + (a.Weight *(cp.Percentage / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 end totalNeeded + ,l.qty as invForAutoConsume /* remaining needed to complete the lot */ - x.TotalDemand - x.EffectiveConsumption as remainingNeeded, + --,x.TotalDemand - x.EffectiveConsumption as remainingNeeded /* do we have enough staged or scanned to the lot? */ - case when (case when x.ProvidedAmount <> 0 then x.ProvidedAmount else x.EffectiveConsumption end) > x.TotalDemand then 'good' else 'bad' end as noShortage , - x.IsManualProcess as isManual, - MaterialHumanReadableId -FROM [test1_AlplaPROD2.0_Read].[issueMaterial].[MaterialDemand] x (nolock) + ,case when (case when x.ProvidedAmount <> 0 + then x.ProvidedAmount else x.EffectiveConsumption end) > + case when cp.Pieces = 1 then (lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces else + (a.Weight *(cp.Percentage / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 end + then 'good' + else 'no' end as noMaterialShortage + -- pkg check + ,case when pkg.QuantityPosition is null then null else + (case when l.qty > (lot.TotalProducedLoadingUnits+1) * pkg.QuantityPosition then 'pkgGood' else 'noPkg' end) end as noPKGShortage + + ,case when cp.Percentage is null then + case when l.qty > ((lot.TotalProducedLoadingUnits +1) * pkg.QuantityPosition) then 'autoConsumeOk' else 'autoConsumeNOK' end else + (case when l.qty > (a.Weight *(cp.Percentage / 100) * ((lot.TotalProducedLoadingUnits+1) * p.LoadingUnitPieces)) / 1000 and IsManualProcess = 0 + then 'autoConsumeOk' else 'autoConsumeNOK' end) end as autoConsumeCheck + ,x.IsManualProcess as isManual + ,IsMainMaterial + ,lot.TotalPlannedLoadingUnits + ,lot.TotalProducedLoadingUnits + ,lot.TotalPlannedLoadingUnits - lot.TotalProducedLoadingUnits as remainingPallets + ,cp.Percentage + ,case when cp.Pieces is not null then cp.Pieces else pkg.QuantityPosition end as peices +FROM [issueMaterial].[MaterialDemand] x (nolock) + left join - [test1_AlplaPROD2.0_Read].[issueMaterial].[ProductionLot] as lot on - x.ProductionLotId = lot.Id + [productionControlling].[ProducedLot] as lot on + lot.Id = x.ProductionLotId + +/* av data */ +left join + [masterData].[Article] as a on + a.id = lot.ArticleId + +/* compound*/ +left join +[masterData].[CompoundPosition] as cp on +cp.CompoundId = a.CompoundId +and cp.ArticleId = x.MaterialId + +/* packagaing */ +left join +[masterData].[PackagingInstructionPosition] as pkg on +pkg.PackagingInstructionId = lot.PackagingId +and pkg.ArticleId = x.MaterialId + +-- get the pkg stuff so we have the total amount per pallet. +left join +[masterData].[PackagingInstruction] as p on +p.id = lot.PackagingId + +/* current stock info for auto consumption*/ +left join +(select +IdArtikelVarianten +,ArtikelVariantenBez +,sum(VerfuegbareMengeSum) as qty + +from AlplaPROD_test1.dbo.V_LagerPositionenBarcodes as i (nolock) + +left join +AlplaPROD_test1.dbo.V_LagerAbteilungen as l (nolock) on +l.IdLagerAbteilung = i.IdLagerAbteilung +where autoverbrauch = 1 and aktiv = 1 +group by IdArtikelVarianten,ArtikelVariantenBez +) as l on +l.IdArtikelVarianten = MaterialHumanReadableId where lot.ProductionLotHumanReadableId = [lotNumber] - and IsMainMaterial = 1 `; diff --git a/server/services/sqlServer/querys/warehouse/labelInfo.ts b/server/services/sqlServer/querys/warehouse/labelInfo.ts index cb07a53..beea16c 100644 --- a/server/services/sqlServer/querys/warehouse/labelInfo.ts +++ b/server/services/sqlServer/querys/warehouse/labelInfo.ts @@ -1,20 +1,36 @@ export const labelInfo = ` -select top(500) e.Barcode, -e.IdArtikelvarianten as av, -e.lfdnr as rn, -IdEtikettenLayout as labelLayout, -AnzStkJePalette, -Sonstiges_9,AnzStkJeKarton -,case when EinlagerungsMengeSum IS NULL then 'notOnStock' else 'onStock' end as stockStatus -,EinlagerungsMengeSum ---,* -from [AlplaPROD_test1].dbo.[T_EtikettenGedruckt] e (nolock) +declare @runningNumber nvarchar(max) = [runningNr] + +select e.Barcode, +e.RunningNumber as runnungNumber, +externalRunningNumber= null, +e.ArticleHumanReadableId as av, +e.LabelManagementHumanReadableId as labelLayout, +case when EinlagerungsMengeSum IS NULL then 'notOnStock' else 'onStock' end as stockStatus +from [test1_AlplaPROD2.0_Read].[labelling].[InternalLabel] (nolock) as e left join -[AlplaPROD_test1].dbo.V_LagerPositionenBarcodes as l on -e.LfdNr = l.Lfdnr +alplaprod_test1.dbo.V_LagerPositionenBarcodes (nolock) as l on +e.RunningNumber = l.Lfdnr -where e.LfdNr in ([runningNr]) +WHERE e.RunningNumber IN (@runningNumber) -order by add_date desc +union all + +select ext.Barcode +,RunningNumber as runnungNumber +,SsccEanRunningNumber as externalRunningNumber +,ArticleHumanReadableId +,case when LabelManagementHumanReadableId is null then (select HumanReadableId from [test1_AlplaPROD2.0_Read].[masterData].[LabelManagement] (nolock) where LabelMarkerId = 7) else LabelManagementHumanReadableId end as labelLayout +,case when EinlagerungsMengeSum IS NULL then 'notOnStock' else 'onStock' end as stockStatus +from [test1_AlplaPROD2.0_Read].[labelling].[ExternalLabel] (nolock) as ext + +left join +alplaprod_test1.dbo.V_LagerPositionenBarcodes (nolock) as l on +ext.RunningNumber = l.Lfdnr + +WHERE ext.SsccEanRunningNumber IN (@runningNumber) and +ext.RunningNumber NOT IN ( + SELECT RunningNumber FROM [test1_AlplaPROD2.0_Read].[labelling].[InternalLabel] WHERE RunningNumber IN (@runningNumber) + ) `;