feat(datamart): psi data has been added :D

This commit is contained in:
2026-04-15 07:29:35 -05:00
parent 52a6c821f4
commit e0d0ac2077
22 changed files with 4153 additions and 51 deletions

View File

@@ -71,7 +71,8 @@
"prodlabels", "prodlabels",
"prolink", "prolink",
"Skelly", "Skelly",
"trycatch" "trycatch",
"whse"
], ],
"gitea.token": "8456def90e1c651a761a8711763d6ef225d6b2db", "gitea.token": "8456def90e1c651a761a8711763d6ef225d6b2db",
"gitea.instanceURL": "https://git.tuffraid.net", "gitea.instanceURL": "https://git.tuffraid.net",

View File

@@ -13,6 +13,10 @@
* *
* when a criteria is password over we will handle it by counting how many were passed up to 3 then deal with each one respectively * when a criteria is password over we will handle it by counting how many were passed up to 3 then deal with each one respectively
*/ */
import { and, between, inArray, notInArray } from "drizzle-orm";
import { db } from "../db/db.controller.js";
import { invHistoricalData } from "../db/schema/historicalInv.schema.js";
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js"; import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
import { import {
type SqlQuery, type SqlQuery,
@@ -29,8 +33,68 @@ type Data = {
howManyOptionsRequired?: number; howManyOptionsRequired?: number;
}; };
const lstDbRun = async (data: Data) => {
if (data.options) {
if (data.name === "psiInventory") {
const ids = data.options.articles.split(",").map((id: any) => id.trim());
const whse = data.options.whseToInclude
? data.options.whseToInclude
.split(",")
.map((w: any) => w.trim())
.filter(Boolean)
: [];
const locations = data.options.exludeLanes
? data.options.exludeLanes
.split(",")
.map((l: any) => l.trim())
.filter(Boolean)
: [];
const conditions = [
inArray(invHistoricalData.article, ids),
between(
invHistoricalData.histDate,
data.options.startDate,
data.options.endDate,
),
];
// only add the warehouse condition if there are any whse values
if (whse.length > 0) {
conditions.push(inArray(invHistoricalData.whseId, whse));
}
// locations we dont want in the system
if (locations.length > 0) {
conditions.push(notInArray(invHistoricalData.location, locations));
}
return await db
.select()
.from(invHistoricalData)
.where(and(...conditions));
}
}
return [];
};
export const runDatamartQuery = async (data: Data) => { export const runDatamartQuery = async (data: Data) => {
// search the query db for the query by name // search the query db for the query by name
const considerLstDBRuns = ["psiInventory"];
if (considerLstDBRuns.includes(data.name)) {
const lstDB = await lstDbRun(data);
return returnFunc({
success: true,
level: "info",
module: "datamart",
subModule: "lstDBrn",
message: `Data for: ${data.name}`,
data: lstDB,
notify: false,
});
}
const sqlQuery = sqlQuerySelector(`datamart.${data.name}`) as SqlQuery; const sqlQuery = sqlQuerySelector(`datamart.${data.name}`) as SqlQuery;
const getDataMartInfo = datamartData.filter((x) => x.endpoint === data.name); const getDataMartInfo = datamartData.filter((x) => x.endpoint === data.name);
@@ -103,13 +167,26 @@ export const runDatamartQuery = async (data: Data) => {
`${data.options.includeRunningNumbers ? `,l.RunningNumber` : `--,l.RunningNumber`}`, `${data.options.includeRunningNumbers ? `,l.RunningNumber` : `--,l.RunningNumber`}`,
) )
.replaceAll( .replaceAll(
"--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber", "--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber as lot",
`${data.options.lots ? `,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber` : `--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber`}`, `${data.options.lots ? `,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber as lot` : `--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber as lot`}`,
) )
.replaceAll( .replaceAll(
"--,l.WarehouseDescription,l.LaneDescription", "--,l.WarehouseDescription,l.LaneDescription",
`${data.options.locations ? `,l.WarehouseDescription,l.LaneDescription` : `--,l.WarehouseDescription,l.LaneDescription`}`, `${data.options.locations ? `,l.WarehouseDescription,l.LaneDescription` : `--,l.WarehouseDescription,l.LaneDescription`}`,
); );
// adding in a test for historical check.
if (data.options.historical) {
datamartQuery = datamartQuery
.replace(
"--,l.ProductionLotRunningNumber as lot,l.warehousehumanreadableid as warehouseId,l.WarehouseDescription as warehouseDescription,l.lanehumanreadableid as locationId,l.lanedescription as laneDescription",
",l.ProductionLotRunningNumber as lot,l.warehousehumanreadableid as warehouseId,l.WarehouseDescription as warehouseDescription,l.lanehumanreadableid as locationId,l.lanedescription as laneDescription",
)
.replace(
"--,l.ProductionLotRunningNumber,l.warehousehumanreadableid,l.WarehouseDescription,l.lanehumanreadableid,l.lanedescription",
",l.ProductionLotRunningNumber,l.warehousehumanreadableid,l.WarehouseDescription,l.lanehumanreadableid,l.lanedescription",
);
}
break; break;
case "fakeEDIUpdate": case "fakeEDIUpdate":
datamartQuery = datamartQuery.replace( datamartQuery = datamartQuery.replace(
@@ -118,6 +195,58 @@ export const runDatamartQuery = async (data: Data) => {
); );
break; break;
case "forecast":
datamartQuery = datamartQuery.replace(
"where DeliveryAddressHumanReadableId in ([customers])",
data.options.customers
? `where DeliveryAddressHumanReadableId in (${data.options.customers})`
: "--where DeliveryAddressHumanReadableId in ([customers])",
);
break;
case "activeArticles2":
datamartQuery = datamartQuery.replace(
"and a.HumanReadableId in ([articles])",
data.options.articles
? `and a.HumanReadableId in (${data.options.articles})`
: "--and a.HumanReadableId in ([articles])",
);
break;
case "psiDeliveryData":
datamartQuery = datamartQuery
.replace("[startDate]", `${data.options.startDate}`)
.replace("[endDate]", `${data.options.endDate}`)
.replace(
"and IdArtikelVarianten in ([articles])",
data.options.articles
? `and IdArtikelVarianten in (${data.options.articles})`
: "--and IdArtikelVarianten in ([articles])",
);
break;
case "productionData":
datamartQuery = datamartQuery
.replace("[startDate]", `${data.options.startDate}`)
.replace("[endDate]", `${data.options.endDate}`)
.replace(
"and ArticleHumanReadableId in ([articles])",
data.options.articles
? `and ArticleHumanReadableId in (${data.options.articles})`
: "--and ArticleHumanReadableId in ([articles])",
);
break;
case "psiPlanningData":
datamartQuery = datamartQuery
.replace("[startDate]", `${data.options.startDate}`)
.replace("[endDate]", `${data.options.endDate}`)
.replace(
"and p.IdArtikelvarianten in ([articles])",
data.options.articles
? `and p.IdArtikelvarianten in (${data.options.articles})`
: "--and p.IdArtikelvarianten in ([articles])",
);
break;
default: default:
return returnFunc({ return returnFunc({
success: false, success: false,

View File

@@ -49,4 +49,12 @@ export const datamartData = [
description: `Returns all open orders to correct and resubmit via lst demand mgt, leaving blank will get everything putting an address only returns the specified address. \nNOTE: only orders that were created via edi will populate here.`, description: `Returns all open orders to correct and resubmit via lst demand mgt, leaving blank will get everything putting an address only returns the specified address. \nNOTE: only orders that were created via edi will populate here.`,
options: "address", options: "address",
}, },
{
name: "Production Data",
endpoint: "productionData",
description: `Returns all production data from the date range with the option to have 1 to many avs to search by.`,
options: "startDate,endDate,articles",
optionsRequired: true,
howManyOptionsRequired: 2,
},
]; ];

View File

@@ -0,0 +1,30 @@
import { date, pgTable, text, timestamp, uuid } from "drizzle-orm/pg-core";
import { createInsertSchema, createSelectSchema } from "drizzle-zod";
import type z from "zod";
export const invHistoricalData = pgTable("inv_historical_data", {
inv: uuid("id").defaultRandom().primaryKey(),
histDate: date("hist_date").notNull(), // this date should always be yesterday when we post it.
plantToken: text("plant_token"),
article: text("article").notNull(),
articleDescription: text("article_description").notNull(),
materialType: text("material_type"),
total_QTY: text("total_QTY"),
available_QTY: text("available_QTY"),
coa_QTY: text("coa_QTY"),
held_QTY: text("held_QTY"),
consignment_QTY: text("consignment_qty"),
lot_Number: text("lot_number"),
locationId: text("location_id"),
location: text("location"),
whseId: text("whse_id").default(""),
whseName: text("whse_name").default("missing whseName"),
upd_user: text("upd_user").default("lst-system"),
upd_date: timestamp("upd_date").defaultNow(),
});
export const invHistoricalDataSchema = createSelectSchema(invHistoricalData);
export const newInvHistoricalDataSchema = createInsertSchema(invHistoricalData);
export type InvHistoricalData = z.infer<typeof invHistoricalDataSchema>;
export type NewInvHistoricalData = z.infer<typeof newInvHistoricalDataSchema>;

View File

@@ -0,0 +1,220 @@
import { format } from "date-fns";
import { eq, sql } from "drizzle-orm";
import { runDatamartQuery } from "../datamart/datamart.controller.js";
import { db } from "../db/db.controller.js";
import { invHistoricalData } from "../db/schema/historicalInv.schema.js";
import { prodQuery } from "../prodSql/prodSqlQuery.controller.js";
import {
type SqlQuery,
sqlQuerySelector,
} from "../prodSql/prodSqlQuerySelector.utils.js";
import { createCronJob } from "../utils/croner.utils.js";
import { returnFunc } from "../utils/returnHelper.utils.js";
import { tryCatch } from "../utils/trycatch.utils.js";
type Inventory = {
article: string;
alias: string;
materialType: string;
total_palletQTY: string;
available_QTY: string;
coa_QTY: string;
held_QTY: string;
consignment_qty: string;
lot: string;
locationId: string;
laneDescription: string;
warehouseId: string;
warehouseDescription: string;
};
const historicalInvImport = async () => {
const today = new Date();
const { data, error } = await tryCatch(
db
.select()
.from(invHistoricalData)
.where(eq(invHistoricalData.histDate, format(today, "yyyy-MM-dd"))),
);
if (error) {
return returnFunc({
success: false,
level: "error",
module: "system",
subModule: "query",
message: `Error getting historical inv info`,
data: error as any,
notify: false,
});
}
if (data?.length === 0) {
const avSQLQuery = sqlQuerySelector(`datamart.activeArticles`) as SqlQuery;
if (!avSQLQuery.success) {
return returnFunc({
success: false,
level: "error",
module: "logistics",
subModule: "inv",
message: `Error getting Article info`,
data: [avSQLQuery.message],
notify: true,
});
}
const { data: inv, error: invError } = await tryCatch(
//prodQuery(sqlQuery.query, "Inventory data"),
runDatamartQuery({ name: "inventory", options: { historical: "x" } }),
);
const { data: av, error: avError } = (await tryCatch(
runDatamartQuery({ name: "activeArticles", options: {} }),
)) as any;
if (invError) {
return returnFunc({
success: false,
level: "error",
module: "logistics",
subModule: "inv",
message: `Error getting inventory info from prod query`,
data: invError as any,
notify: false,
});
}
if (avError) {
return returnFunc({
success: false,
level: "error",
module: "logistics",
subModule: "inv",
message: `Error getting article info from prod query`,
data: invError as any,
notify: false,
});
}
// shape the data to go into our table
const plantToken = process.env.PROD_PLANT_TOKEN ?? "test1";
const importInv = (inv.data ? inv.data : []) as Inventory[];
const importData = importInv.map((i) => {
return {
histDate: sql`(NOW())::date`,
plantToken: plantToken,
article: i.article,
articleDescription: i.alias,
materialType:
av.data.filter((a: any) => a.article === i.article).length > 0
? av.data.filter((a: any) => a.article === i.article)[0]
?.TypeOfMaterial
: "Item not defined",
total_QTY: i.total_palletQTY ?? "0.00",
available_QTY: i.available_QTY ?? "0.00",
coa_QTY: i.coa_QTY ?? "0.00",
held_QTY: i.held_QTY ?? "0.00",
consignment_QTY: i.consignment_qty ?? "0.00",
lot_Number: i.lot ?? "0",
locationId: i.locationId ?? "0",
location: i.laneDescription ?? "Missing lane",
whseId: i.warehouseId ?? "0",
whseName: i.warehouseDescription ?? "Missing warehouse",
};
});
const { data: dataImport, error: errorImport } = await tryCatch(
db.insert(invHistoricalData).values(importData),
);
if (errorImport) {
return returnFunc({
success: false,
level: "error",
module: "logistics",
subModule: "inv",
message: `Error adding historical data to lst db`,
data: errorImport as any,
notify: true,
});
}
if (dataImport) {
return returnFunc({
success: false,
level: "info",
module: "logistics",
subModule: "inv",
message: `Historical data was added to lst :D`,
data: [],
notify: false,
});
}
} else {
return returnFunc({
success: false,
level: "info",
module: "logistics",
subModule: "inv",
message: `Historical Data for: ${format(today, "yyyy-MM-dd")}, is already added and nothing to do.`,
data: [],
notify: false,
});
}
return returnFunc({
success: false,
level: "info",
module: "logistics",
subModule: "inv",
message: `Some weird crazy error just happened and didnt get captured during the historical inv check.`,
data: [],
notify: true,
});
};
export const historicalSchedule = async () => {
// running the history in case my silly ass dose an update around the shift change time lol, this will prevent loss data. it might be off a little but no one cares
historicalInvImport();
const sqlQuery = sqlQuerySelector(`shiftChange`) as SqlQuery;
if (!sqlQuery.success) {
return returnFunc({
success: false,
level: "error",
module: "logistics",
subModule: "query",
message: `Error getting shiftChange sql file`,
data: [sqlQuery.message],
notify: false,
});
}
const { data, error } = await tryCatch(
prodQuery(sqlQuery.query, "Shift Change data"),
);
if (error) {
return returnFunc({
success: false,
level: "error",
module: "logistics",
subModule: "query",
message: `Error getting shiftChange info`,
data: error as any,
notify: false,
});
}
// shift split
const shiftTimeSplit = data?.data[0]?.shiftChange.split(":");
const cronSetup = `0 ${
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[1])}` : "0"
} ${
shiftTimeSplit?.length > 0 ? `${parseInt(shiftTimeSplit[0])}` : "7"
} * * *`;
createCronJob("historicalInv", cronSetup, () => historicalInvImport());
};

View File

@@ -1,6 +1,6 @@
use AlplaPROD_test1 use AlplaPROD_test1
SELECT V_Artikel.IdArtikelvarianten, SELECT V_Artikel.IdArtikelvarianten as article,
V_Artikel.Bezeichnung, V_Artikel.Bezeichnung,
V_Artikel.ArtikelvariantenTypBez, V_Artikel.ArtikelvariantenTypBez,
V_Artikel.PreisEinheitBez, V_Artikel.PreisEinheitBez,

View File

@@ -0,0 +1,43 @@
/**
This will be replacing activeArticles once all data is remapped into this query.
make a note in the docs this activeArticles will go stale sooner or later.
**/
use [test1_AlplaPROD2.0_Read]
select a.Id,
a.HumanReadableId as av,
a.Alias as alias,
p.LoadingUnitsPerTruck as loadingUnitsPerTruck,
p.LoadingUnitsPerTruck * p.LoadingUnitPieces as qtyPerTruck,
p.LoadingUnitPieces,
case when i.MinQuantity IS NOT NULL then round(cast(i.MinQuantity as float), 2) else 0 end as min,
case when i.MaxQuantity IS NOT NULL then round(cast(i.MaxQuantity as float),2) else 0 end as max
from masterData.Article (nolock) as a
/* sales price */
left join
(select *
from (select
id,
PackagingId,
ArticleId,
DefaultCustomer,
ROW_NUMBER() OVER (PARTITION BY ArticleId ORDER BY ValidAfter DESC) AS RowNum
from masterData.SalesPrice (nolock)
where DefaultCustomer = 1) as x
where RowNum = 1
) as s
on a.id = s.ArticleId
/* pkg instructions */
left join
masterData.PackagingInstruction (nolock) as p
on s.PackagingId = p.id
/* stock limits */
left join
masterData.StockLimit (nolock) as i
on a.id = i.ArticleId
where a.active = 1
and a.HumanReadableId in ([articles])

View File

@@ -0,0 +1,8 @@
SELECT format(RequirementDate, 'yyyy-MM-dd') as requirementDate
,ArticleHumanReadableId
,CustomerArticleNumber
,ArticleDescription
,Quantity
FROM [test1_AlplaPROD2.0_Read].[forecast].[Forecast]
where DeliveryAddressHumanReadableId in ([customers])
order by RequirementDate

View File

@@ -1,22 +1,32 @@
use [test1_AlplaPROD2.0_Read]
select select
ArticleHumanReadableId as av ArticleHumanReadableId as article
,ArticleAlias as alias ,ArticleAlias as alias
,round(sum(QuantityLoadingUnits),0) total_pallets ,round(sum(QuantityLoadingUnits),2) total_pallets
,round(sum(Quantity),0) as total_palletQTY ,round(sum(Quantity),2) as total_palletQTY
,round(sum(case when State = 0 then QuantityLoadingUnits else 0 end),0) avalible_Pallets ,round(sum(case when State = 0 then QuantityLoadingUnits else 0 end),2) available_Pallets
,round(sum(case when State = 0 then Quantity else 0 end),0) available_QTY ,round(sum(case when State = 0 then Quantity else 0 end),2) available_QTY
,sum(case when b.HumanReadableId = 864 then QuantityLoadingUnits else 0 end) as coa_Pallets ,round(sum(case when b.HumanReadableId = 864 then QuantityLoadingUnits else 0 end),2) as coa_Pallets
,sum(case when b.HumanReadableId = 864 then Quantity else 0 end) as coa_QTY ,round(sum(case when b.HumanReadableId = 864 then Quantity else 0 end),2) as coa_QTY
,sum(case when b.HumanReadableId <> 864 then QuantityLoadingUnits else 0 end) as held_Pallets ,round(sum(case when b.HumanReadableId <> 864 then QuantityLoadingUnits else 0 end),2) as held_Pallets
,sum(case when b.HumanReadableId <> 864 then Quantity else 0 end) as held_QTY ,round(sum(case when b.HumanReadableId <> 864 then Quantity else 0 end),2) as held_QTY
,round(sum(case when w.type = 7 then QuantityLoadingUnits else 0 end),2) as consignment_Pallets
,round(sum(case when w.type = 7 then Quantity else 0 end),2) as consignment_qty
--,l.RunningNumber --,l.RunningNumber
/** should be in line **/
--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber /** datamart include lot number **/
/** should be in line **/ --,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber as lot
/** data mart include location data **/
--,l.WarehouseDescription,l.LaneDescription --,l.WarehouseDescription,l.LaneDescription
/** historical section **/
--,l.ProductionLotRunningNumber as lot,l.warehousehumanreadableid as warehouseId,l.WarehouseDescription as warehouseDescription,l.lanehumanreadableid as locationId,l.lanedescription as laneDescription
,articleTypeName ,articleTypeName
FROM [test1_AlplaPROD2.0_Read].[warehousing].[WarehouseUnit] as l FROM [warehousing].[WarehouseUnit] as l (nolock)
left join left join
( (
SELECT [Id] SELECT [Id]
@@ -24,21 +34,31 @@ SELECT [Id]
,d.[Description] ,d.[Description]
,[DefectGroupId] ,[DefectGroupId]
,[IsActive] ,[IsActive]
FROM [test1_AlplaPROD2.0_Read].[blocking].[BlockingDefect] as g FROM [blocking].[BlockingDefect] as g (nolock)
left join left join
[AlplaPROD_test1].dbo.[T_BlockingDefects] as d (nolock) on [AlplaPROD_test1].dbo.[T_BlockingDefects] as d (nolock) on
d.IdGlobalBlockingDefect = g.HumanReadableId d.IdGlobalBlockingDefect = g.HumanReadableId
) as b on ) as b on
b.id = l.MainDefectId b.id = l.MainDefectId
left join
[warehousing].[warehouse] as w (nolock) on
w.id = l.warehouseid
where LaneHumanReadableId not in (20000,21000) where LaneHumanReadableId not in (20000,21000)
group by ArticleHumanReadableId, group by ArticleHumanReadableId,
ArticleAlias, ArticleAlias,
ArticleTypeName ArticleTypeName
--,l.RunningNumber --,l.RunningNumber
/** should be in line **/
/** datamart include lot number **/
--,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber --,l.MachineLocation,l.MachineName,l.ProductionLotRunningNumber
/** should be in line **/
/** data mart include location data **/
--,l.WarehouseDescription,l.LaneDescription --,l.WarehouseDescription,l.LaneDescription
/** historical section **/
--,l.ProductionLotRunningNumber,l.warehousehumanreadableid,l.WarehouseDescription,l.lanehumanreadableid,l.lanedescription
order by ArticleHumanReadableId order by ArticleHumanReadableId

View File

@@ -0,0 +1,19 @@
use [test1_AlplaPROD2.0_Reporting]
declare @startDate nvarchar(30) = '[startDate]' --'2024-12-30'
declare @endDate nvarchar(30) = '[endDate]' --'2025-08-09'
select MachineLocation,
ArticleHumanReadableId as article,
sum(Quantity) as Produced,
count(Quantity) as palletsProdued,
FORMAT(convert(date, ProductionDay), 'M/d/yyyy') as ProductionDay,
ProductionLotHumanReadableId as productionLot
from [reporting_productionControlling].[ScannedUnit] (nolock)
where convert(date, ProductionDay) between @startDate and @endDate
and ArticleHumanReadableId in ([articles])
and BookedOut is null
group by MachineLocation, ArticleHumanReadableId,ProductionDay, ProductionLotHumanReadableId

View File

@@ -0,0 +1,23 @@
use AlplaPROD_test1
/**
move this over to the delivery date range query once we have the shift data mapped over correctly.
update the psi stuff on this as well.
**/
declare @start_date nvarchar(30) = '[startDate]' --'2025-01-01'
declare @end_date nvarchar(30) = '[endDate]' --'2025-08-09'
select IdArtikelVarianten,
ArtikelVariantenBez,
sum(Menge) totalDelivered,
case when convert(time, upd_date) between '00:00' and '07:00' then convert(date, upd_date - 1) else convert(date, upd_date) end as ShippingDate
from dbo.V_LadePlanungenLadeAuftragAbruf (nolock)
where upd_date between CONVERT(datetime, @start_date + ' 7:00') and CONVERT(datetime, @end_date + ' 7:00')
and IdArtikelVarianten in ([articles])
group by IdArtikelVarianten, upd_date,
ArtikelVariantenBez

View File

@@ -0,0 +1,32 @@
use AlplaPROD_test1
declare @start_date nvarchar(30) = '[startDate]' --'2025-01-01'
declare @end_date nvarchar(30) = '[endDate]' --'2025-08-09'
/*
articles will need to be passed over as well as the date structure we want to see
*/
select x.IdArtikelvarianten As Article,
ProduktionAlias as Description,
standort as MachineId,
MaschinenBezeichnung as MachineName,
--MaschZyklus as PlanningCycleTime,
x.IdProdPlanung as LotNumber,
FORMAT(ProdTag, 'MM/dd/yyyy') as ProductionDay,
x.planMenge as TotalPlanned,
ProduktionMenge as QTYPerDay,
round(ProduktionMengeVPK, 2) PalDay,
Status as finished
--MaschStdAuslastung as nee
from dbo.V_ProdLosProduktionJeProdTag_PLANNING (nolock) as x
left join
dbo.V_ProdPlanung (nolock) as p on
x.IdProdPlanung = p.IdProdPlanung
where ProdTag between @start_date and @end_date
and p.IdArtikelvarianten in ([articles])
--and V_ProdLosProduktionJeProdTag_PLANNING.IdKunde = 10
--and IdProdPlanung = 18442
order by ProdTag desc

View File

@@ -0,0 +1,4 @@
select top(1) convert(varchar(8) ,
convert(time,startdate), 108) as shiftChange
from [test1_AlplaPROD2.0_Read].[masterData].[ShiftDefinition]
where teamNumber = 1

View File

@@ -6,6 +6,7 @@ import { dbCleanup } from "./db/dbCleanup.controller.js";
import { type Setting, settings } from "./db/schema/settings.schema.js"; import { type Setting, settings } from "./db/schema/settings.schema.js";
import { connectGPSql } from "./gpSql/gpSqlConnection.controller.js"; import { connectGPSql } from "./gpSql/gpSqlConnection.controller.js";
import { createLogger } from "./logger/logger.controller.js"; import { createLogger } from "./logger/logger.controller.js";
import { historicalSchedule } from "./logistics/logistics.historicalInv.js";
import { startNotifications } from "./notification/notification.controller.js"; import { startNotifications } from "./notification/notification.controller.js";
import { createNotifications } from "./notification/notifications.master.js"; import { createNotifications } from "./notification/notifications.master.js";
import { printerSync } from "./ocp/ocp.printer.manage.js"; import { printerSync } from "./ocp/ocp.printer.manage.js";
@@ -64,6 +65,7 @@ const start = async () => {
dbCleanup("jobs", 30), dbCleanup("jobs", 30),
); );
createCronJob("logsCleanup", "0 15 5 * * *", () => dbCleanup("logs", 120)); createCronJob("logsCleanup", "0 15 5 * * *", () => dbCleanup("logs", 120));
historicalSchedule();
// one shots only needed to run on server startups // one shots only needed to run on server startups
createNotifications(); createNotifications();

View File

@@ -3,6 +3,7 @@ import { eq } from "drizzle-orm";
import { db } from "../db/db.controller.js"; import { db } from "../db/db.controller.js";
import { jobAuditLog } from "../db/schema/auditLog.schema.js"; import { jobAuditLog } from "../db/schema/auditLog.schema.js";
import { createLogger } from "../logger/logger.controller.js"; import { createLogger } from "../logger/logger.controller.js";
import type { ReturnHelper } from "./returnHelper.utils.js";
// example createJob // example createJob
// createCronJob("test Cron", "*/5 * * * * *", async () => { // createCronJob("test Cron", "*/5 * * * * *", async () => {
@@ -45,7 +46,7 @@ const cronStats: Record<string, { created: number; replaced: number }> = {};
export const createCronJob = async ( export const createCronJob = async (
name: string, name: string,
schedule: string, // cron string with 8 8 IE: */5 * * * * * every 5th second schedule: string, // cron string with 8 8 IE: */5 * * * * * every 5th second
task: () => Promise<void>, // what function are we passing over task: () => Promise<void | ReturnHelper>, // what function are we passing over
source = "unknown", source = "unknown",
) => { ) => {
// get the timezone based on the os timezone set // get the timezone based on the os timezone set

View File

@@ -1,7 +1,7 @@
import type { Response } from "express"; import type { Response } from "express";
import { createLogger } from "../logger/logger.controller.js"; import { createLogger } from "../logger/logger.controller.js";
interface Data<T = unknown[]> { export interface ReturnHelper<T = unknown[]> {
success: boolean; success: boolean;
module: module:
| "system" | "system"
@@ -13,31 +13,10 @@ interface Data<T = unknown[]> {
| "notification" | "notification"
| "email" | "email"
| "purchase" | "purchase"
| "tcp"; | "tcp"
subModule: | "logistics";
| "db" subModule: string;
| "labeling"
| "printer"
| "prodSql"
| "query"
| "sendmail"
| "auth"
| "datamart"
| "jobs"
| "apt"
| "settings"
| "get"
| "update"
| "delete"
| "post"
| "notification"
| "delete"
| "printing"
| "gpSql"
| "email"
| "gpChecks"
| "prodEndpoint"
| "create_server";
level: "info" | "error" | "debug" | "fatal" | "warn"; level: "info" | "error" | "debug" | "fatal" | "warn";
message: string; message: string;
room?: string; room?: string;
@@ -59,7 +38,7 @@ interface Data<T = unknown[]> {
* data: [] the data that will be passed back * data: [] the data that will be passed back
* notify: false by default this is to send a notification to a users email to alert them of an issue. * notify: false by default this is to send a notification to a users email to alert them of an issue.
*/ */
export const returnFunc = (data: Data) => { export const returnFunc = (data: ReturnHelper) => {
const notify = data.notify ? data.notify : false; const notify = data.notify ? data.notify : false;
const room = data.room ?? data.room; const room = data.room ?? data.room;
const log = createLogger({ module: data.module, subModule: data.subModule }); const log = createLogger({ module: data.module, subModule: data.subModule });
@@ -92,7 +71,7 @@ export const returnFunc = (data: Data) => {
export function apiReturn( export function apiReturn(
res: Response, res: Response,
opts: Data & { status?: number }, opts: ReturnHelper & { status?: number },
optional?: unknown, // leave this as unknown so we can pass an object or an array over. optional?: unknown, // leave this as unknown so we can pass an object or an array over.
): Response { ): Response {
const result = returnFunc(opts); const result = returnFunc(opts);

View File

@@ -5,13 +5,17 @@ meta {
} }
get { get {
url: {{url}}/api/datamart/:name url: {{url}}/api/datamart/:name?historical=x
body: none body: none
auth: inherit auth: inherit
} }
params:query {
historical: x
}
params:path { params:path {
name: activeArticles name: inventory
} }
settings { settings {

View File

@@ -0,0 +1,20 @@
CREATE TABLE "inv_historical_data" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"hist_date" date NOT NULL,
"plant_token" text,
"article" text NOT NULL,
"article_description" text NOT NULL,
"material_type" text,
"total_QTY" text,
"available_QTY" text,
"coa_QTY" text,
"held_QTY" text,
"consignment_qty" text,
"lot_number" text,
"location_id" text,
"location" text,
"whse_id" text DEFAULT '',
"whse_name" text DEFAULT 'missing whseName',
"upd_user" text DEFAULT 'lst',
"upd_date" timestamp DEFAULT now()
);

View File

@@ -0,0 +1 @@
ALTER TABLE "inv_historical_data" ALTER COLUMN "upd_user" SET DEFAULT 'lst-system';

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -225,6 +225,20 @@
"when": 1776098377074, "when": 1776098377074,
"tag": "0031_numerous_the_phantom", "tag": "0031_numerous_the_phantom",
"breakpoints": true "breakpoints": true
},
{
"idx": 32,
"version": "7",
"when": 1776245938243,
"tag": "0032_tranquil_onslaught",
"breakpoints": true
},
{
"idx": 33,
"version": "7",
"when": 1776256060808,
"tag": "0033_elite_adam_warlock",
"breakpoints": true
} }
] ]
} }