From 096cc18477e4194af72a4837dfa0af0b076141eb Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Tue, 30 Dec 2025 07:12:38 -0600 Subject: [PATCH] refactor(datamart): psi work --- lstV2/database/schema/historicalINV.ts | 58 ++++----- .../dataMart/controller/psiForecastData.ts | 42 +++++++ .../dataMart/controller/psiGetInventory.ts | 117 +++++++++++------- .../services/dataMart/dataMartService.ts | 2 + .../services/dataMart/route/getPsiForecast.ts | 65 ++++++++++ .../dataMart/route/getPsiinventory.ts | 100 +++++++-------- lstV2/server/services/eom/eomService.ts | 80 ++++++------ .../services/eom/utils/historicalInv.ts | 5 +- .../sqlServer/querys/dataMart/totalINV.ts | 8 ++ 9 files changed, 315 insertions(+), 162 deletions(-) create mode 100644 lstV2/server/services/dataMart/controller/psiForecastData.ts create mode 100644 lstV2/server/services/dataMart/route/getPsiForecast.ts diff --git a/lstV2/database/schema/historicalINV.ts b/lstV2/database/schema/historicalINV.ts index b9d357b..a316758 100644 --- a/lstV2/database/schema/historicalINV.ts +++ b/lstV2/database/schema/historicalINV.ts @@ -1,36 +1,38 @@ import { - date, - integer, - pgTable, - text, - timestamp, - uuid, + date, + integer, + pgTable, + text, + timestamp, + uuid, } from "drizzle-orm/pg-core"; import { createSelectSchema } from "drizzle-zod"; export const invHistoricalData = pgTable( - "invHistoricalData", - { - inv_id: uuid("inv_id").defaultRandom().primaryKey(), - histDate: date("histDate").notNull(), // this date should always be yesterday when we post it. - plantToken: text("plantToken"), - article: text("article").notNull(), - articleDescription: text("articleDescription").notNull(), - materialType: text("materialType"), - total_QTY: text("total_QTY"), - avaliable_QTY: text("avaliable_QTY"), - coa_QTY: text("coa_QTY"), - held_QTY: text("held_QTY"), - lot_Number: text("lot_number"), - consignment: text("consignment"), - location: text("location"), - upd_user: text("upd_user").default("lst"), - upd_date: timestamp("upd_date").defaultNow(), - } - // (table) => [ - // // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`), - // uniqueIndex("role_name").on(table.name), - // ] + "invHistoricalData", + { + inv_id: uuid("inv_id").defaultRandom().primaryKey(), + histDate: date("histDate").notNull(), // this date should always be yesterday when we post it. + plantToken: text("plantToken"), + article: text("article").notNull(), + articleDescription: text("articleDescription").notNull(), + materialType: text("materialType"), + total_QTY: text("total_QTY"), + avaliable_QTY: text("avaliable_QTY"), + coa_QTY: text("coa_QTY"), + held_QTY: text("held_QTY"), + lot_Number: text("lot_number"), + consignment: text("consignment"), + location: text("location"), + whseId: text("whse_id").default(""), + whseName: text("whse_name").default("missing whseName"), + upd_user: text("upd_user").default("lst"), + upd_date: timestamp("upd_date").defaultNow(), + }, + // (table) => [ + // // uniqueIndex('emailUniqueIndex').on(sql`lower(${table.email})`), + // uniqueIndex("role_name").on(table.name), + // ] ); // Schema for inserting a user - can be used to validate API requests diff --git a/lstV2/server/services/dataMart/controller/psiForecastData.ts b/lstV2/server/services/dataMart/controller/psiForecastData.ts new file mode 100644 index 0000000..f1394ce --- /dev/null +++ b/lstV2/server/services/dataMart/controller/psiForecastData.ts @@ -0,0 +1,42 @@ +import { tryCatch } from "../../../globalUtils/tryCatch.js"; +import { createLog } from "../../logger/logger.js"; +import { query } from "../../sqlServer/prodSqlServer.js"; +import { forecastData } from "../../sqlServer/querys/psiReport/forecast.js"; + +// type ArticleData = { +// id: string +// } +export const getGetPSIForecastData = async (customer: string) => { + let articles: any = []; + let queryData = forecastData; + console.log(customer); + if (customer) { + queryData = forecastData.replace("[customer]", customer); + } + + const { data, error } = (await tryCatch( + query(queryData, "PSI forecast info"), + )) as any; + + if (error) { + createLog( + "error", + "datamart", + "datamart", + `There was an error getting the forecast info: ${JSON.stringify(error)}`, + ); + return { + success: false, + messsage: `There was an error getting the forecast info`, + data: error, + }; + } + + articles = data.data; + + return { + success: true, + message: "PSI forecast Data", + data: articles, + }; +}; diff --git a/lstV2/server/services/dataMart/controller/psiGetInventory.ts b/lstV2/server/services/dataMart/controller/psiGetInventory.ts index e4a5933..10f3aff 100644 --- a/lstV2/server/services/dataMart/controller/psiGetInventory.ts +++ b/lstV2/server/services/dataMart/controller/psiGetInventory.ts @@ -1,4 +1,4 @@ -import { and, between, inArray, sql } from "drizzle-orm"; +import { and, between, inArray, notInArray, sql } from "drizzle-orm"; import { db } from "../../../../database/dbclient.js"; import { invHistoricalData } from "../../../../database/schema/historicalINV.js"; import { tryCatch } from "../../../globalUtils/tryCatch.js"; @@ -8,56 +8,79 @@ import { createLog } from "../../logger/logger.js"; // id: string // } export const psiGetInventory = async ( - avs: string, - startDate: string, - endDate: string + avs: string, + startDate: string, + endDate: string, + whseToInclude: string, + exludeLanes: string ) => { - let articles: any = []; + let articles: any = []; - if (!avs) { - return { - success: false, - message: `Missing av's please send at least one over`, - data: [], - }; - } + if (!avs) { + return { + success: false, + message: `Missing av's please send at least one over`, + data: [], + }; + } - const ids = avs.split(",").map((id) => id.trim()); + const ids = avs.split(",").map((id) => id.trim()); + const whse = whseToInclude + ? whseToInclude + .split(",") + .map((w) => w.trim()) + .filter(Boolean) + : []; - const { data, error } = (await tryCatch( - db - .select() - .from(invHistoricalData) - .where( - and( - inArray(invHistoricalData.article, ids), - between(invHistoricalData.histDate, startDate, endDate) - ) - ) - //.limit(100) - )) as any; + const locations = exludeLanes + ? exludeLanes.split(",").map((l) => l.trim()).filter(Boolean) + : []; - if (error) { - createLog( - "error", - "datamart", - "datamart", - `There was an error getting the planning info: ${JSON.stringify( - error - )}` - ); - return { - success: false, - messsage: `There was an error getting the planning info`, - data: error, - }; - } + const conditions = [ + inArray(invHistoricalData.article, ids), + between(invHistoricalData.histDate, startDate, endDate), + ]; - articles = data; - console.log(articles.length); - return { - success: true, - message: "PSI planning Data", - data: articles, - }; + // only add the warehouse condition if there are any whse values + if (whse.length > 0) { + console.log("adding whse to include in"); + conditions.push(inArray(invHistoricalData.whseId, whse)); + } + + // locations we dont want in the system + if (locations.length > 0) { + console.log("adding excluded lanes in ",locations); + + conditions.push(notInArray(invHistoricalData.location, locations)); +} + + const query = db + .select() + .from(invHistoricalData) + .where(and(...conditions)); + + // optional tryCatch or await as you had + const { data, error } = (await tryCatch(query)) as any; + + if (error) { + createLog( + "error", + "datamart", + "datamart", + `There was an error getting the planning info: ${JSON.stringify(error)}`, + ); + return { + success: false, + messsage: `There was an error getting the planning info`, + data: error, + }; + } + + articles = data; + console.log(articles.length); + return { + success: true, + message: "PSI planning Data", + data: articles, + }; }; diff --git a/lstV2/server/services/dataMart/dataMartService.ts b/lstV2/server/services/dataMart/dataMartService.ts index 5c3273c..32c3719 100644 --- a/lstV2/server/services/dataMart/dataMartService.ts +++ b/lstV2/server/services/dataMart/dataMartService.ts @@ -13,6 +13,7 @@ import getInhouseDeliveryByDate from "./route/getInHouseDeliveryDateByRange.js"; import currentInv from "./route/getInventory.js"; import getOpenOrders from "./route/getOpenOrders.js"; import psiArticleData from "./route/getPsiArticleData.js"; +import psiForecastData from "./route/getPsiForecast.js"; import psiInventory from "./route/getPsiinventory.js"; import psiPlanningData from "./route/getPsiPlanningData.js"; import psiProductionData from "./route/getPsiProductionData.js"; @@ -37,6 +38,7 @@ const routes = [ psiPlanningData, psiProductionData, psiInventory, + psiForecastData, ] as const; const appRoutes = routes.forEach((route) => { diff --git a/lstV2/server/services/dataMart/route/getPsiForecast.ts b/lstV2/server/services/dataMart/route/getPsiForecast.ts new file mode 100644 index 0000000..28877be --- /dev/null +++ b/lstV2/server/services/dataMart/route/getPsiForecast.ts @@ -0,0 +1,65 @@ +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { apiHit } from "../../../globalUtils/apiHits.js"; +import { responses } from "../../../globalUtils/routeDefs/responses.js"; +import { tryCatch } from "../../../globalUtils/tryCatch.js"; +import { getGetPSIForecastData } from "../controller/psiForecastData.js"; + +const app = new OpenAPIHono({ strict: false }); +const Body = z.object({ + includeRunnningNumbers: z.string().openapi({ example: "x" }), +}); +app.openapi( + createRoute({ + tags: ["dataMart"], + summary: "Returns the psiforecastdata.", + method: "get", + path: "/psiforecastdata", + request: { + body: { + content: { + "application/json": { schema: Body }, + }, + }, + }, + responses: responses(), + }), + async (c) => { + const customer: any = c.req.queries(); + + // make sure we have a vaid user being accessed thats really logged in + apiHit(c, { endpoint: "/psiforecastdata" }); + //console.log(articles["avs"][0]); + + let customeArticle = null; + if (customer) { + customeArticle = customer["customer"][0]; + } + const { data, error } = await tryCatch( + getGetPSIForecastData(customeArticle), + ); + + if (error) { + console.log(error); + return c.json( + { + success: false, + message: "There was an error getting the articles.", + data: error, + }, + 400, + ); + } + + //console.log(data); + + return c.json( + { + success: data.success, + message: data.message, + data: data.data, + }, + data.success ? 200 : 400, + ); + }, +); +export default app; diff --git a/lstV2/server/services/dataMart/route/getPsiinventory.ts b/lstV2/server/services/dataMart/route/getPsiinventory.ts index 3b77951..5d3b453 100644 --- a/lstV2/server/services/dataMart/route/getPsiinventory.ts +++ b/lstV2/server/services/dataMart/route/getPsiinventory.ts @@ -1,64 +1,66 @@ import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { apiHit } from "../../../globalUtils/apiHits.js"; import { responses } from "../../../globalUtils/routeDefs/responses.js"; import { tryCatch } from "../../../globalUtils/tryCatch.js"; -import { apiHit } from "../../../globalUtils/apiHits.js"; import { psiGetInventory } from "../controller/psiGetInventory.js"; const app = new OpenAPIHono({ strict: false }); const Body = z.object({ - includeRunnningNumbers: z.string().openapi({ example: "x" }), + includeRunnningNumbers: z.string().openapi({ example: "x" }), }); app.openapi( - createRoute({ - tags: ["dataMart"], - summary: "Returns the getPsiinventory.", - method: "get", - path: "/getpsiinventory", - request: { - body: { - content: { - "application/json": { schema: Body }, - }, - }, - }, - responses: responses(), - }), - async (c) => { - const q: any = c.req.queries(); + createRoute({ + tags: ["dataMart"], + summary: "Returns the getPsiinventory.", + method: "get", + path: "/getpsiinventory", + request: { + body: { + content: { + "application/json": { schema: Body }, + }, + }, + }, + responses: responses(), + }), + async (c) => { + const q: any = c.req.queries(); - // make sure we have a vaid user being accessed thats really logged in - apiHit(c, { endpoint: "/getpsiinventory" }); - //console.log(articles["avs"][0]); - const { data, error } = await tryCatch( - psiGetInventory( - q["avs"] ? q["avs"][0] : null, - q["startDate"] ? q["startDate"][0] : null, - q["endDate"] ? q["endDate"][0] : null - ) - ); + // make sure we have a vaid user being accessed thats really logged in + apiHit(c, { endpoint: "/getpsiinventory" }); + //console.log(articles["avs"][0]); + const { data, error } = await tryCatch( + psiGetInventory( + q["avs"] ? q["avs"][0] : null, + q["startDate"] ? q["startDate"][0] : null, + q["endDate"] ? q["endDate"][0] : null, + q["whseToInclude"] ? q["whseToInclude"][0] : null, + q["exludeLanes"] ? q["exludeLanes"][0] : null, + ), + ); - if (error) { - console.log(error); - return c.json( - { - success: false, - message: "There was an error getting the production.", - data: error, - }, - 400 - ); - } + if (error) { + console.log(error); + return c.json( + { + success: false, + message: "There was an error getting the production.", + data: error, + }, + 400, + ); + } - //console.log(data); + //console.log(data); - return c.json( - { - success: data.success, - message: data.message, - data: data.data, - }, - data.success ? 200 : 400 - ); - } + return c.json( + { + success: data.success, + message: data.message, + data: data.data, + }, + data.success ? 200 : 400, + ); + }, ); export default app; diff --git a/lstV2/server/services/eom/eomService.ts b/lstV2/server/services/eom/eomService.ts index cd33658..b274ac2 100644 --- a/lstV2/server/services/eom/eomService.ts +++ b/lstV2/server/services/eom/eomService.ts @@ -2,65 +2,71 @@ import { OpenAPIHono } from "@hono/zod-openapi"; const app = new OpenAPIHono(); -import stats from "./route/stats.js"; -import history from "./route/invHistory.js"; -import { createJob } from "../notifications/utils/processNotifications.js"; -import { historicalInvIMmport } from "./utils/historicalInv.js"; import { tryCatch } from "../../globalUtils/tryCatch.js"; +import { createLog } from "../logger/logger.js"; +import { createJob } from "../notifications/utils/processNotifications.js"; import { query } from "../sqlServer/prodSqlServer.js"; import { shiftChange } from "../sqlServer/querys/misc/shiftChange.js"; -import { createLog } from "../logger/logger.js"; +import gpData from "./route/getGpData.js"; import lastPurch from "./route/getLastPurchPrice.js"; import lastSales from "./route/getLastSalesPrice.js"; -import gpData from "./route/getGpData.js"; import consumptionData from "./route/getProductionConsumption.js"; +import purchased from "./route/getPurchased.js"; import regrind from "./route/getregrind.js"; import soldItems from "./route/getSoldItems.js"; -import purchased from "./route/getPurchased.js"; +import history from "./route/invHistory.js"; +import stats from "./route/stats.js"; +import { historicalInvIMmport } from "./utils/historicalInv.js"; const routes = [ - stats, - history, - lastPurch, - lastSales, - gpData, - consumptionData, - regrind, - soldItems, - purchased, + stats, + history, + lastPurch, + lastSales, + gpData, + consumptionData, + regrind, + soldItems, + purchased, ] as const; const appRoutes = routes.forEach((route) => { - app.route("/eom", route); + app.route("/eom", route); }); setTimeout(async () => { - const { data: shift, error: shiftError } = (await tryCatch( - query(shiftChange, "shift change from material.") - )) as any; + const { data: shift, error: shiftError } = (await tryCatch( + query(shiftChange, "shift change from material."), + )) as any; - if (shiftError) { - createLog( - "error", - "eom", - "eom", - "There was an error getting the shift times will use fallback times" - ); - } + if (shiftError) { + createLog( + "error", + "eom", + "eom", + "There was an error getting the shift times will use fallback times", + ); + } - // shift split - const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":"); + // shift split + const shiftTimeSplit = shift?.data[0]?.shiftChange.split(":"); - const cronSetup = `${ - shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[1])}` : "0" - } ${ - shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[0])}` : "7" - } * * *`; + const cronSetup = `${ + shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[1])}` : "0" + } ${ + shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[0])}` : "7" + } * * *`; - //console.log(cronSetup); - createJob("eom_historical_inv", cronSetup, historicalInvIMmport); + //console.log(cronSetup); + createJob("eom_historical_inv", cronSetup, historicalInvIMmport); }, 5 * 1000); // the time we want to run the hostircal data should be the same time the historical data run on the server // getting this from the shift time +if (process.env.NODE_ENV?.trim() !== "production") { + setTimeout(() => { + historicalInvIMmport(); + }, 15 * 1000); +} + export default app; diff --git a/lstV2/server/services/eom/utils/historicalInv.ts b/lstV2/server/services/eom/utils/historicalInv.ts index f08b766..488f896 100644 --- a/lstV2/server/services/eom/utils/historicalInv.ts +++ b/lstV2/server/services/eom/utils/historicalInv.ts @@ -76,7 +76,10 @@ export const historicalInvIMmport = async () => { coa_QTY: i.COA_QTY, held_QTY: i.Held_QTY, consignment: i.Consigment, - lot_Number: i.lot, + lot_Number: i.Lot, + location: i.location, + whseId: i.warehouseID, + whseName: i.warehouseName, }; }); diff --git a/lstV2/server/services/sqlServer/querys/dataMart/totalINV.ts b/lstV2/server/services/sqlServer/querys/dataMart/totalINV.ts index d146b0a..701da00 100644 --- a/lstV2/server/services/sqlServer/querys/dataMart/totalINV.ts +++ b/lstV2/server/services/sqlServer/querys/dataMart/totalINV.ts @@ -17,6 +17,10 @@ x.ArtikelVariantenAlias as Alias ,IdProdPlanung as Lot ----,IdAdressen, ,x.AdressBez +,x.IdLagerAbteilung as 'location' +,x.LagerAbteilungKurzBez +,x.IdWarenlager as warehouseID +,x.WarenLagerKurzBez as warehouseName --,* from [AlplaPROD_test1].dbo.[V_LagerPositionenBarcodes] (nolock) x @@ -39,6 +43,10 @@ group by x.idartikelVarianten, ArtikelVariantenAlias, c.Description --,IdAdressen ,x.AdressBez ,IdProdPlanung +,x.IdLagerAbteilung +,x.LagerAbteilungKurzBez +,x.IdWarenlager +,x.WarenLagerKurzBez --, x.Lfdnr order by x.IdArtikelVarianten