From 44507d41c42f07cf3ab4825a848821dde4cf892d Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Tue, 1 Apr 2025 16:20:18 -0500 Subject: [PATCH] feat(datamart): initial get active query migrated --- server/globalUtils/freightClass.ts | 69 ++++++++ server/index.ts | 4 + .../dataMart/controller/getActiveArticles.ts | 13 ++ server/services/dataMart/dataMartService.ts | 13 ++ .../dataMart/route/getActiveArticles.ts | 47 ++++++ .../services/eom/controller/addHistorical.ts | 139 ++++++++++++++++ .../eom/controller/removeHistorical.ts | 15 ++ server/services/eom/eomService.ts | 10 +- server/services/eom/route/invHistory.ts | 41 +++++ server/services/eom/route/stats.ts | 41 +++++ .../querys/notifications/ti/getHeaders.ts | 25 +++ .../querys/notifications/ti/getOrderToSend.ts | 149 ++++++++++++++++++ 12 files changed, 565 insertions(+), 1 deletion(-) create mode 100644 server/globalUtils/freightClass.ts create mode 100644 server/services/dataMart/controller/getActiveArticles.ts create mode 100644 server/services/dataMart/dataMartService.ts create mode 100644 server/services/dataMart/route/getActiveArticles.ts create mode 100644 server/services/eom/controller/addHistorical.ts create mode 100644 server/services/eom/controller/removeHistorical.ts create mode 100644 server/services/eom/route/invHistory.ts create mode 100644 server/services/eom/route/stats.ts create mode 100644 server/services/sqlServer/querys/notifications/ti/getHeaders.ts create mode 100644 server/services/sqlServer/querys/notifications/ti/getOrderToSend.ts diff --git a/server/globalUtils/freightClass.ts b/server/globalUtils/freightClass.ts new file mode 100644 index 0000000..85ac027 --- /dev/null +++ b/server/globalUtils/freightClass.ts @@ -0,0 +1,69 @@ +export const freightClass = ( + weight: number, + length: number, + width: number, + height: number +) => { + // mm to in conversion + const convertMM = 25.4; + + const convertKG = 2.20462; + // Inputs + const weightPounds = weight * convertKG; + const lengthInches = length / convertMM; + const widthInches = width / convertMM; + const heightInches = height / convertMM; + + // Calculate volume in cubic inches + const volumeCubicInches = lengthInches * widthInches * heightInches; + + // Convert cubic inches to cubic feet + const volumeCubicFeet = volumeCubicInches / 1728; + + // Calculate density + const density = weightPounds / volumeCubicFeet; + + // Determine freight class + let freightClass; + + if (density >= 50) { + freightClass = 50; + } else if (density >= 35) { + freightClass = 55; + } else if (density >= 30) { + freightClass = 60; + } else if (density >= 22.5) { + freightClass = 65; + } else if (density >= 15) { + freightClass = 70; + } else if (density >= 13.5) { + freightClass = 77.5; + } else if (density >= 12) { + freightClass = 85; + } else if (density >= 10.5) { + freightClass = 92.5; + } else if (density >= 9) { + freightClass = 100; + } else if (density >= 8) { + freightClass = 110; + } else if (density >= 7) { + freightClass = 125; + } else if (density >= 6) { + freightClass = 150; + } else if (density >= 5) { + freightClass = 175; + } else if (density >= 4) { + freightClass = 200; + } else if (density >= 3) { + freightClass = 250; + } else if (density >= 2) { + freightClass = 300; + } else if (density >= 1) { + freightClass = 400; + } else { + freightClass = 500; + } + + // Output the freight class + return freightClass; +}; diff --git a/server/index.ts b/server/index.ts index 2741067..e45e2c0 100644 --- a/server/index.ts +++ b/server/index.ts @@ -25,6 +25,8 @@ import os from "os"; import { tryCatch } from "./globalUtils/tryCatch.js"; import { sendEmail } from "./services/notifications/controller/sendMail.js"; import notify from "./services/notifications/notifyService.js"; +import eom from "./services/eom/eomService.js"; +import dataMart from "./services/dataMart/dataMartService.js"; // create the main prodlogin here const username = "lst_user"; @@ -100,6 +102,8 @@ const routes = [ loggerService, ocpService, notify, + eom, + dataMart, ] as const; const appRoutes = routes.forEach((route) => { diff --git a/server/services/dataMart/controller/getActiveArticles.ts b/server/services/dataMart/controller/getActiveArticles.ts new file mode 100644 index 0000000..c09a321 --- /dev/null +++ b/server/services/dataMart/controller/getActiveArticles.ts @@ -0,0 +1,13 @@ +import { query } from "../../sqlServer/prodSqlServer.js"; +import { activeArticle } from "../../sqlServer/querys/dataMart/article.js"; + +export const getActiveAv = async () => { + let articles: any = []; + try { + articles = await query(activeArticle, "Get active articles"); + } catch (error) { + articles = error; + } + + return articles; +}; diff --git a/server/services/dataMart/dataMartService.ts b/server/services/dataMart/dataMartService.ts new file mode 100644 index 0000000..4578526 --- /dev/null +++ b/server/services/dataMart/dataMartService.ts @@ -0,0 +1,13 @@ +import { OpenAPIHono } from "@hono/zod-openapi"; + +import getArticles from "./route/getActiveArticles.js"; + +const app = new OpenAPIHono(); + +const routes = [getArticles] as const; + +const appRoutes = routes.forEach((route) => { + app.route("/datamart", route); +}); + +export default app; diff --git a/server/services/dataMart/route/getActiveArticles.ts b/server/services/dataMart/route/getActiveArticles.ts new file mode 100644 index 0000000..301e8b8 --- /dev/null +++ b/server/services/dataMart/route/getActiveArticles.ts @@ -0,0 +1,47 @@ +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { apiHit } from "../../../globalUtils/apiHits.js"; +import { responses } from "../../../globalUtils/routeDefs/responses.js"; +import { getActiveAv } from "../controller/getActiveArticles.js"; + +const app = new OpenAPIHono({ strict: false }); +const EomStat = z.object({ + plant: z.string().openapi({ example: "Salt Lake City" }), + userRan: z.string().openapi({ example: "smith034" }), + eomSheetVersion: z.string().openapi({ example: "0.0.223" }), +}); + +app.openapi( + createRoute({ + tags: ["dataMart"], + summary: "Returns all the Active articles.", + method: "get", + path: "/getarticles", + + responses: responses(), + }), + async (c) => { + //const body = await c.req.json(); + // make sure we have a vaid user being accessed thats really logged in + //apiHit(c, { endpoint: `api/logger/logs/id` }); + try { + return c.json( + { + success: true, + message: "Current active Articles", + data: await getActiveAv(), + }, + 200 + ); + } catch (error) { + return c.json( + { + success: false, + message: "There was an error posting the eom stat.", + data: error, + }, + 400 + ); + } + } +); +export default app; diff --git a/server/services/eom/controller/addHistorical.ts b/server/services/eom/controller/addHistorical.ts new file mode 100644 index 0000000..9444924 --- /dev/null +++ b/server/services/eom/controller/addHistorical.ts @@ -0,0 +1,139 @@ +// import cron from "node-cron"; +// import {runQuery, prisma, totalInvNoRn, activeArticle, getShiftTime, historicalInv} from "database"; +// import {createLog} from "logging"; +// import {deleteHistory} from "./deleteHistory.js"; + +// export const historyInv = async (date) => { +// //console.log(date); +// if (!date) { +// return `Missing Data`; +// } +// // date should be sent over as a string IE: 2024-01-01 +// let inv = []; +// try { +// inv = await prisma.historyInventory.findMany({where: {histDate: date}}); +// console.log(inv.length); +// // if the date returns nothing we need to pull the historical data +// if (inv.length === 0) { +// const result = await prisma.settings.findFirst({where: {name: "plantToken"}}); +// try { +// const plantUpdate = historicalInv.replaceAll("test1", result.value); +// const queryDate = plantUpdate.replaceAll("[date]", date); +// inv = await runQuery(queryDate, "Get histical inv"); + +// return inv; +// } catch (error) { +// createLog("general/eom", "error", "There was an error getting the historical inv."); +// return error; +// } +// } else { +// return inv; +// } +// //return inv; +// } catch (error) { +// console.log(error); +// return error; +// } +// }; + +// // start the cron job for getting the hostrical inv based on the plants shift time +// export const startCronHist = () => { +// let shiftTime = ["06", "00", "00"]; +// const startProcess = async () => { +// let inv = []; +// let articles = []; +// let plantToken = "test1"; +// const date = new Date(); +// const dateString = date.toISOString().split("T")[0]; +// date.setDate(date.getDate() - 30); +// const oldDate = date.toISOString().split("T")[0]; + +// // checking if even need to run this +// // before adding more make sure we dont already have data +// const checkInv = await prisma.historyInventory.findFirst({where: {histDate: dateString}}); +// if (checkInv) { +// createLog( +// "general/eom", +// "warn", +// `There seems to already be inventory added for ${dateString}, no new data will be added` +// ); +// return; +// } +// // get plant token +// try { +// const result = await prisma.settings.findFirst({where: {name: "plantToken"}}); +// plantToken = result.value; +// } catch (error) { +// createLog("general/eom", "error", "failed to get planttoken"); +// } +// //get shift time +// try { +// const result = await runQuery(getShiftTime.replaceAll("test1", plantToken), "GettingShift time"); +// shiftTime = result[0].shiftStartTime.split(":"); +// } catch (error) { +// createLog("general/eom", "error", `Error running getShift Query: ${error}`); +// } + +// // get inventory +// try { +// const result = await runQuery(totalInvNoRn.replaceAll("test1", plantToken), "getting inventory"); +// inv = result; +// } catch (error) { +// createLog("general/eom", "error", `Error running get inventory Query: ${error}`); +// } + +// // get active articles +// try { +// const result = await runQuery(activeArticle.replaceAll("test1", plantToken), "Get active articles"); +// articles = result; +// } catch (error) { +// createLog("general/eom", "error", `Error running get article: ${error}`); +// } + +// //add the inventory to the historical table +// try { +// let hist = Object.entries(inv).map(([key, value]) => { +// // remove the values we dont want in the historical view +// const {total_Pallets, avalible_Pallets, coa_Pallets, held_Pallets, ...histData} = value; + +// // get av tyep +// const avType = articles.filter((a) => (a.IdArtikelvarianten = inv[key].av))[0].TypeOfMaterial; +// // add in the new fields +// const hist = { +// ...histData, +// histDate: dateString, //new Date(Date.now()).toISOString().split("T")[0], +// avType, +// }; +// return hist; +// }); + +// try { +// const addHistData = await prisma.historyInventory.createMany({data: hist}); +// createLog( +// "general/eom", +// "info", +// `${addHistData.count} were just added to the historical inventory for date ${dateString}` +// ); +// } catch (error) { +// createLog("general/eom", "error", `Adding new historical inventory error: ${error}`); +// } + +// // delete the older inventory +// deleteHistory(oldDate); +// } catch (error) { +// createLog("general/eom", "error", `Adding new historical inventory error: ${error}`); +// } +// }; + +// // actaully run the process once after restaart just to make sure we have inventory +// startProcess(); + +// // setup the cron stuff +// const startHour = shiftTime[0]; +// const startMin = shiftTime[1]; +// createLog("general/eom", "info", `Historical Data will run at ${shiftTime[0]}:${shiftTime[1]} daily`); +// cron.schedule(`${startMin} ${startHour} * * *`, () => { +// createLog("general/eom", "info", "Running historical invnetory."); +// startProcess(); +// }); +// }; diff --git a/server/services/eom/controller/removeHistorical.ts b/server/services/eom/controller/removeHistorical.ts new file mode 100644 index 0000000..bd99b88 --- /dev/null +++ b/server/services/eom/controller/removeHistorical.ts @@ -0,0 +1,15 @@ +// import {prisma} from "database"; +// import {createLog} from "logging"; + +// export const deleteHistory = async (date: string) => { +// // delete the inventory if it equals this date +// try { +// const remove = await prisma.$executeRaw` +// DELETE FROM historyInventory +// WHERE histDate < ${date} +// `; +// createLog("general/eom", "info", `${remove} were just remove from the historical inventory for date: ${date}`); +// } catch (error) { +// createLog("general/eom", "error", `Removing historical inventory error: ${error}`); +// } +// }; diff --git a/server/services/eom/eomService.ts b/server/services/eom/eomService.ts index b23f7d7..1fb67d7 100644 --- a/server/services/eom/eomService.ts +++ b/server/services/eom/eomService.ts @@ -1,5 +1,13 @@ -import {OpenAPIHono} from "@hono/zod-openapi"; +import { OpenAPIHono } from "@hono/zod-openapi"; const app = new OpenAPIHono(); +import stats from "./route/stats.js"; +import history from "./route/invHistory.js"; +const routes = [stats, history] as const; + +const appRoutes = routes.forEach((route) => { + app.route("/eom", route); +}); + export default app; diff --git a/server/services/eom/route/invHistory.ts b/server/services/eom/route/invHistory.ts new file mode 100644 index 0000000..661877e --- /dev/null +++ b/server/services/eom/route/invHistory.ts @@ -0,0 +1,41 @@ +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { apiHit } from "../../../globalUtils/apiHits.js"; +import { responses } from "../../../globalUtils/routeDefs/responses.js"; + +const app = new OpenAPIHono({ strict: false }); +const EomStat = z.object({ + plant: z.string().openapi({ example: "Salt Lake City" }), + userRan: z.string().openapi({ example: "smith034" }), + eomSheetVersion: z.string().openapi({ example: "0.0.223" }), +}); + +app.openapi( + createRoute({ + tags: ["eom"], + summary: "Gets the correct eom history.", + method: "post", + path: "/histinv", + request: { + params: EomStat, + }, + responses: responses(), + }), + async (c) => { + //const body = await c.req.json(); + // make sure we have a vaid user being accessed thats really logged in + //apiHit(c, { endpoint: `api/logger/logs/id` }); + try { + return c.json({ success: true, message: "", data: [] }, 200); + } catch (error) { + return c.json( + { + success: false, + message: "There was an error posting the eom stat.", + data: error, + }, + 400 + ); + } + } +); +export default app; diff --git a/server/services/eom/route/stats.ts b/server/services/eom/route/stats.ts new file mode 100644 index 0000000..6e11792 --- /dev/null +++ b/server/services/eom/route/stats.ts @@ -0,0 +1,41 @@ +import { createRoute, OpenAPIHono, z } from "@hono/zod-openapi"; +import { apiHit } from "../../../globalUtils/apiHits.js"; +import { responses } from "../../../globalUtils/routeDefs/responses.js"; + +const app = new OpenAPIHono({ strict: false }); +const EomStat = z.object({ + plant: z.string().openapi({ example: "Salt Lake City" }), + userRan: z.string().openapi({ example: "smith034" }), + eomSheetVersion: z.string().openapi({ example: "0.0.223" }), +}); + +app.openapi( + createRoute({ + tags: ["eom"], + summary: "Adds in the stats for the eom.", + method: "post", + path: "/stats", + request: { + params: EomStat, + }, + responses: responses(), + }), + async (c) => { + //const body = await c.req.json(); + // make sure we have a vaid user being accessed thats really logged in + apiHit(c, { endpoint: `api/logger/logs/id` }); + try { + return c.json({ success: true, message: "", data: [] }, 200); + } catch (error) { + return c.json( + { + success: false, + message: "There was an error posting the eom stat.", + data: error, + }, + 400 + ); + } + } +); +export default app; diff --git a/server/services/sqlServer/querys/notifications/ti/getHeaders.ts b/server/services/sqlServer/querys/notifications/ti/getHeaders.ts new file mode 100644 index 0000000..01780fd --- /dev/null +++ b/server/services/sqlServer/querys/notifications/ti/getHeaders.ts @@ -0,0 +1,25 @@ +export let getHeaders = ` +select AuftragsNummer as header, +IdAuftragsAbruf as releaseNumber, +AbrufLiefertermin as delDate +FROM alplaprod_test1.dbo.V_TrackerAuftragsAbrufe (nolock) b + +left join +( +select IdAdressen addressID, +x.Bezeichnung as name, +c.Bezeichnung as deliveryCondition, +c.Kurzbezeichnung as Abbreviation +from AlplaPROD_test1.dbo.t_Adressen (nolock) x +left join +AlplaPROD_test1.[dbo].[T_Lieferkonditionen] (nolock) c +on x.IdLieferkondition = c.IdLieferkondition +) x + +on b.IdAdresse = x.addressID + +WHERE AbrufStatus = 1 and +AbrufLiefertermin between DATEADD(HOUR, -[from], GETDATE()) and DATEADD(HOUR, [to], GETDATE()) -- this number will be grabbed from the db with a default of 24hours +and x.Abbreviation not in ('exw') +and IdAuftragsAbruf not in ([exclude]) +`; diff --git a/server/services/sqlServer/querys/notifications/ti/getOrderToSend.ts b/server/services/sqlServer/querys/notifications/ti/getOrderToSend.ts new file mode 100644 index 0000000..fcee01c --- /dev/null +++ b/server/services/sqlServer/querys/notifications/ti/getOrderToSend.ts @@ -0,0 +1,149 @@ +export let getOrderToSend = ` +select * from ( +Select IdAdresse as addressId, +LieferAdressBez as addressAlias, +LEFT(ArtikelVariantenAlias, charindex(' ', ArtikelVariantenAlias) - 1) item, +IdArtikelVarianten as article, +ArtikelVariantenAlias as articleAlias, +IdAuftragsAbruf as releaseNumber, +AuftragsNummer AS Header, +AuftragsNummer as CustomerLineItemNo, +AbrufNummer AS CustomerReleaseNumber, +AbrufMengeVPK AS Pallets, +AbrufMenge AS QTY, +IdAdresse AS CUSTOMERID, +AbrufLadeDatum AS LoadingDate, +AbrufLiefertermin AS DeliveryDate +,carrierAV +,singleTrip +,roundTrip +,countryAv +,zipCode +,streetAddress +,city -- split on here by , +--,OrderStatus = 'loading' +,ac.costCenter -- also called pfc +,pkg.pkgHeight +,pkg.pkgLengh +,pkg.pkgWidth +,ROUND((ac.weight * pkg.palletCount / 1000) + pkg.totalPKGWeight,2)as pkgWeight +,AbrufStatus as status +,remark +,ac.artileType +--,* +FROM alplaprod_test1.dbo.V_TrackerAuftragsAbrufe (nolock) x + +--av info +left join +(SELECT [IdArtikelvarianten] as article + ,[FibuKontenKontoNr] as costCenter + ,ArtikelGewicht as weight, + s.pkgId + ,artikelvariantentypbez as artileType + FROM [AlplaPROD_test1].[dbo].[V_Artikelvarianten_BASIS] (nolock) x + + left join + ( + select * from (select +ROW_NUMBER() OVER(PARTITION BY [IdArtikelvarianten] ORDER BY gueltigabDatum DESC) AS rn +,[IdArtikelvarianten] as article +,IdVpkVorschrift as pkgId +from [AlplaPROD_test1].[dbo].[T_HistoryVK] (nolock)) a where rn = 1 + ) as s +on +x.[IdArtikelvarianten] = s.article +) as ac +on +x.IdArtikelVarianten = ac.article + +-- transport part of query +left join +(SELECT [IdHistoryTransportkosten] + ,[IdLieferadresse] as customerAddressAV + ,[IdSpediteuradresse] as carrierAV + ,[GueltigabDatum] as validDate + ,[Einzelfahrtkosten] as singleTrip + ,[Rundfahrtkosten] as roundTrip + ,[EinzelfahrtkostenProKubikmeter] as singletripCostsperCubicMeter + ,[RundfahrtkostenProKubikmeter] as roundSingletripCostsperCubicMeter + ,[Standard] as standard + ,[Aktiv] as active + --,[FWEinzelfahrtkosten] + --,[FWRundfahrtkosten] + --,[FWEinzelfahrtkostenProKubikmeter] + --,[FWRundfahrtkostenProKubikmeter] +FROM [AlplaPROD_test1].[dbo].[T_HistoryTransportkosten] (nolock) + +where Standard = 1 and Aktiv = 1) as carrier + +on x.IdAdresse = carrier.customerAddressAV + +-- address stuff +left join +(SELECT [IdAdressen] as addressAV + ,[IdAdressentyp] as addressType -- 1 customer,2 supplier, 4 transport + --,[IdZahlKond] + --,[IdMwst] + ,[Bezeichnung] as addressName + ,[IdStaaten] as countryAv + ,[PLZ] as zipCode + ,[Strasse] as streetAddress + ,[PLZPostfach] as poBox + ,[Postfach] as mailbox + ,[Ort] as city + ,[Tel] as customerPhone + ,[DebNr] as debitorNr + ,xy.[Bonus] as bonus + ,[Bemerkung] as remark + ,[Aktiv] as active + ,Entfernung as distanceKM + ,Transportzeit as transportTime + ,IdLieferkondition as deliveryCondtionAV + ,delc.deliveryContionAlias + ,delc.deliveryContionAbv + --,ac.costCenter + FROM [AlplaPROD_test1].[dbo].[T_Adressen] (nolock) xy + + --delivery condtion details + left join + (SELECT [IdLieferkondition] as deliveryCondtionAV + ,[Bezeichnung] as deliveryContionAlias + ,[Kurzbezeichnung] as deliveryContionAbv + ,[Bemerkung] as deliveryContionRemark + ,[Aktiv] as active + FROM [AlplaPROD_test1].[dbo].[T_Lieferkonditionen] (nolock)) as delC + + on xy.IdLieferkondition = delC.deliveryCondtionAV +) as del +on +x.IdAdresse = del.addressAV + +-- pkg info +left join +( +SELECT [IdVpkVorschrift] as pkgId + ,[Aktiv] as active + ,[Bezeichnung] as alias + ,[AnzahlAVProVpk] as palletCount + ,[AnzahlVpkProLKW] as totalTruck + ,[AnzahlKistenProKarton] + ,[BruttoGewicht] / 1000 as totalPKGWeight + --,[AnzahlAVProHE] + ,[VpkDimensionenHoehe] as pkgHeight + ,[VpkDimensionenBreite] as pkgWidth + ,[VpkDimensionenTiefe] as pkgLengh + FROM [AlplaPROD_test1].[dbo].[V_Vpk_BASIS] +)as pkg + +on +ac.pkgId = pkg.pkgId + +WHERE AbrufStatus = 1 +and AbrufLiefertermin between DATEADD(HOUR, -[from], getdate()) and DATEADD(HOUR, [to], getdate())-- this number will be grabbed from the db with a default of 24hours +and deliveryContionAbv not in ('EXW') + +--ORDER BY AbrufLiefertermin) +) a + +where releaseNumber = [releaseToProcess] +`;