Compare commits

...

3 Commits

7 changed files with 471 additions and 270 deletions

View File

@@ -0,0 +1,22 @@
meta {
name: PSI -planning data
type: http
seq: 2
}
get {
url: {{url}}/lst/old/api/datamart/psiplanningdata?avs=118,120&startDate=12/1/2025&endDate=12/31/2026
body: none
auth: inherit
}
params:query {
avs: 118,120
startDate: 12/1/2025
endDate: 12/31/2026
}
settings {
encodeUrl: true
timeout: 0
}

View File

@@ -1,5 +1,5 @@
vars { vars {
url: https://bow1prod.alpla.net url: http://localhost:4200
session_cookie: session_cookie:
urlv2: http://usbow1vms006:3000 urlv2: http://usbow1vms006:3000
jwtV2: jwtV2:

View File

@@ -30,6 +30,7 @@ import { useSettingStore } from "../../../-lib/store/useSettings";
const printReason = [ const printReason = [
{ key: "printerIssue", label: "Printer Related" }, { key: "printerIssue", label: "Printer Related" },
{ key: "missingRfidTag", label: "Missing or incorrect tag" }, { key: "missingRfidTag", label: "Missing or incorrect tag" },
{ key: "multipleTags", label: "More than one tag on pallet." },
{ key: "rfidMissScan", label: "Missed Scan from RFID reader" }, { key: "rfidMissScan", label: "Missed Scan from RFID reader" },
{ key: "strapper", label: "Strapper Error" }, { key: "strapper", label: "Strapper Error" },
{ key: "manualCheck", label: "20th pallet check" }, { key: "manualCheck", label: "20th pallet check" },

View File

@@ -2,6 +2,7 @@ import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { createLog } from "../../logger/logger.js"; import { createLog } from "../../logger/logger.js";
import { query } from "../../sqlServer/prodSqlServer.js"; import { query } from "../../sqlServer/prodSqlServer.js";
import { planningNumbersByAVDate } from "../../sqlServer/querys/psiReport/planningNumbersByAv.js"; import { planningNumbersByAVDate } from "../../sqlServer/querys/psiReport/planningNumbersByAv.js";
import { improvedPsiPlanningInfo } from "./psiPlanningDataImproved.js";
// type ArticleData = { // type ArticleData = {
// id: string // id: string
@@ -9,7 +10,7 @@ import { planningNumbersByAVDate } from "../../sqlServer/querys/psiReport/planni
export const psiGetPlanningData = async ( export const psiGetPlanningData = async (
avs: string, avs: string,
startDate: string, startDate: string,
endDate: string endDate: string,
) => { ) => {
let articles: any = []; let articles: any = [];
@@ -27,18 +28,21 @@ export const psiGetPlanningData = async (
.replace("[articles]", avs) .replace("[articles]", avs)
.replace("[startDate]", startDate) .replace("[startDate]", startDate)
.replace("[endDate]", endDate), .replace("[endDate]", endDate),
"PSI planning info" "PSI planning info",
) ),
)) as any; )) as any;
// improvedPsiPlanningInfo({
// avs,
// startDate,
// endDate,
// });
if (error) { if (error) {
createLog( createLog(
"error", "error",
"datamart", "datamart",
"datamart", "datamart",
`There was an error getting the planning info: ${JSON.stringify( `There was an error getting the planning info: ${JSON.stringify(error)}`,
error
)}`
); );
return { return {
success: false, success: false,
@@ -52,12 +56,17 @@ export const psiGetPlanningData = async (
return { return {
success: true, success: true,
message: "PSI planning Data", message: "PSI planning Data",
data: articles.map((n: any) => { data: await improvedPsiPlanningInfo({
if (n.PalDay) { avs,
return { ...n, PalDay: n.PalDay.toFixed(2) }; startDate,
} endDate,
return n;
}), }),
// data: articles.map((n: any) => {
// if (n.PalDay) {
// return { ...n, PalDay: n.PalDay.toFixed(2) };
// }
// return n;
// }),
}; };
}; };

View File

@@ -0,0 +1,170 @@
import { format } from "date-fns-tz";
import { tryCatch } from "../../../globalUtils/tryCatch.js";
import { query } from "../../sqlServer/prodSqlServer.js";
const improvedQuery = `
DECLARE @StartDate DATE = '[startDate]' -- 2025-1-1
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
SELECT
[RunningNumber] as lot
,[ProfitCentreDescription]
,[MachineDescription]
,[ArticleHumanReadableId]
,[ArticleDescription]
,[DeliveryAddressHumanReadableId]
,[DeliveryAddressDescription]
,[MouldHumanReadableId]
,[BlowheadHumanReadableId1]
,[PackagingInstructionHumanReadableId]
,[PackagingInstructionDescription]
,[MainMaterialHumanReadableId]
,[MainMaterialDescription]
,[CompoundHumanReadableId]
,[CompoundDescription]
,[ProductionLotState]
,[PlanType]
,[ProducedQuantityLoadingUnit]
,[ProducedQuantityPieces]
,[PlanStart]
,[PlanEnd]
,[ProdStart]
,[TheoreticEnd]
,[ProdDuration]
,[SetupDuration]
,[StartupDuration]
,[NetEquipmentEfficiency]
,[UtilisationDuration]
,[CycleTime]
,[Cavities]
,[FixedQuantity]
,[ProducedQuantityTrucks]
,[ProducedQuantityTradeUnit]
,[MaxRegrind]
,[Conflict]
,[ProductionOrderHumanReadableId]
,[ProductionDataImportSource]
,[Remark]
,[BlowheadDescription1]
,[MouldDescription]
,[ProcessLossPercentage]
,[SetupTypeNumberOfPersons]
,[UnplannedDowntimePercentage]
,[PlanQuantityLoadingUnit]
,[PlanQuantityPieces]
,[PlanQuantityTradeUnit]
,[PlanQuantityTrucks]
,[PublishState]
,[LastChange]
,[MaterialConsumed]
,[MaterialStaged]
,[MachineLocation]
,[HasPrioritization]
,[ArticleAlias]
FROM [test1_AlplaPROD2.0_Read].[productionScheduling].[ProductionLot] with (nolock)
where TheoreticEnd between @StartDate and @EndDate
and ArticleHumanReadableId in ([articles])
and PublishState = 1
order by PlanStart
`;
export const improvedPsiPlanningInfo = async (something: any) => {
const { data, error } = (await tryCatch(
query(
improvedQuery
.replace("[articles]", something.avs)
.replace("[startDate]", something.startDate)
.replace("[endDate]", something.endDate),
"PSI planning info",
),
)) as any;
// add error handling in later here
return splitProduction(data.data);
};
const splitProduction = (runs: any) => {
const results: any = [];
const WORKDAY_START_HOUR = 7; // 07:00 start well later get this from the shift def
runs.forEach((e: any) => {
const {
PlanStart,
PlanEnd,
PlanQuantityPieces,
ArticleHumanReadableId,
ProdDuration,
} = e;
const prodStart: any = new Date(PlanStart);
const prodEnd: any = new Date(PlanEnd);
const prodDuration = ProdDuration
? ProdDuration * 60 * 60 * 1000
: prodEnd - prodStart;
// get the prod date the production falls under
function getProdDayStart(date: Date) {
const d = new Date(date);
d.setHours(WORKDAY_START_HOUR, 0, 0, 0);
if (date.getHours() < WORKDAY_START_HOUR) {
// before 07:00, belongs to previous calendar day
d.setDate(d.getDate() - 1);
}
return d;
}
// current pointer starts at the work-day start that contains our start time
let currentStart = new Date(prodStart);
let prodDayStart = getProdDayStart(currentStart);
while (prodDayStart < prodEnd) {
// 1⃣ The next days start = prodDayStart + 1 day at 07:00
const nextProdDayStart = new Date(prodDayStart);
nextProdDayStart.setDate(nextProdDayStart.getDate() + 1);
// 2⃣ Segment end is either the next work-day start or the actual end, whichever is sooner
const segmentEnd = new Date(
Math.min(nextProdDayStart.getTime(), prodEnd.getTime()),
);
// 3⃣ Determine overlap window within (startTime..endTime)
const segStart: any = new Date(
Math.max(prodDayStart.getTime(), prodStart.getTime()),
);
const segEnd: any = segmentEnd;
if (segEnd > segStart) {
const segMs = segEnd - segStart;
const proportion = segMs / prodDuration;
const qty = PlanQuantityPieces * proportion;
const pal = e.PlanQuantityLoadingUnit * proportion;
results.push({
Article: ArticleHumanReadableId,
Description: e.ArticleAlias,
MachineId: e.MachineLocation,
MachineName: e.MachineDescription,
LotNumber: e.lot,
ProductionDay: format(prodDayStart, "M/d/yyyy"),
TotalPlanned: e.PlanQuantityPieces,
// PlanEnd,
// TheoreticEnd,
QTYPerDay: parseInt(qty.toFixed(0)),
PalDay: parseFloat(pal.toFixed(2)),
finished: e.ProductionLotState === 3 ? 1 : 0,
//prodDuration,
});
}
// move to next production-day window
prodDayStart = nextProdDayStart;
}
});
return results;
};

View File

@@ -1,12 +1,12 @@
import { eq } from "drizzle-orm";
import sql from "mssql"; import sql from "mssql";
import { prodSqlConfig } from "./utils/prodServerConfig.js";
import { createLog } from "../logger/logger.js";
import { db } from "../../../database/dbclient.js"; import { db } from "../../../database/dbclient.js";
import { settings } from "../../../database/schema/settings.js"; import { settings } from "../../../database/schema/settings.js";
import { eq } from "drizzle-orm";
import { installed } from "../../index.js";
import { checkHostnamePort } from "../../globalUtils/pingServer.js"; import { checkHostnamePort } from "../../globalUtils/pingServer.js";
import { installed } from "../../index.js";
import { createLog } from "../logger/logger.js";
import { serverSettings } from "../server/controller/settings/getSettings.js"; import { serverSettings } from "../server/controller/settings/getSettings.js";
import { prodSqlConfig } from "./utils/prodServerConfig.js";
let pool: any; let pool: any;
let connected: boolean = false; let connected: boolean = false;
@@ -16,7 +16,7 @@ export const initializeProdPool = async () => {
"info", "info",
"lst", "lst",
"sqlProd", "sqlProd",
"The server was not installed will reconnect in 5 seconds" "The server was not installed will reconnect in 5 seconds",
); );
setTimeout(() => { setTimeout(() => {
initializeProdPool(); initializeProdPool();
@@ -31,7 +31,7 @@ export const initializeProdPool = async () => {
// the move to the go version for settings // the move to the go version for settings
const dbServer = serverSettings.filter( const dbServer = serverSettings.filter(
(n: any) => n.name === "dbServer" (n: any) => n.name === "dbServer",
) as any; ) as any;
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`); const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`);
@@ -41,12 +41,12 @@ export const initializeProdPool = async () => {
"error", "error",
"lst", "lst",
"server", "server",
`The sql ${dbServer[0].value} is not reachable` `The sql ${dbServer[0].value} is not reachable`,
); );
closePool() // closePool()
setTimeout(() => { // setTimeout(() => {
initializeProdPool(); // initializeProdPool();
}, 2*1000); // }, 2*1000);
return { return {
success: false, success: false,
message: `The sql ${dbServer[0].value} is not reachable`, message: `The sql ${dbServer[0].value} is not reachable`,
@@ -61,7 +61,7 @@ export const initializeProdPool = async () => {
// .where(eq(settings.name, "dbServer")); // .where(eq(settings.name, "dbServer"));
const serverLoc = serverSettings.filter( const serverLoc = serverSettings.filter(
(n: any) => n.name === "dbServer" (n: any) => n.name === "dbServer",
) as any; ) as any;
if ( if (
serverLoc[0].value === "localhost" && serverLoc[0].value === "localhost" &&
@@ -71,7 +71,7 @@ export const initializeProdPool = async () => {
"error", "error",
"lst", "lst",
"sqlProd", "sqlProd",
"The server is set to localhost, and you are not in development mode." "The server is set to localhost, and you are not in development mode.",
); );
return { return {
success: false, success: false,
@@ -94,7 +94,7 @@ export const initializeProdPool = async () => {
"info", "info",
"lst", "lst",
"sqlProd", "sqlProd",
`Connected to ${config?.server}, and looking at ${config?.database}` `Connected to ${config?.server}, and looking at ${config?.database}`,
); );
connected = true; connected = true;
return { return {
@@ -106,19 +106,17 @@ export const initializeProdPool = async () => {
"error", "error",
"lst", "lst",
"sqlProd", "sqlProd",
`${JSON.stringify( `${JSON.stringify(error)}, "There was an error connecting to the pool."`,
error
)}, "There was an error connecting to the pool."`
); );
closePool() // closePool()
setTimeout(() => { // setTimeout(() => {
initializeProdPool(); // initializeProdPool();
}, 2*1000); // }, 2*1000);
return { return {
success: true, success: true,
message: "The sql server connection has been closed", message: "The sql server connection has been closed",
} };
//throw new Error("There was an error closing the sql connection"); //throw new Error("There was an error closing the sql connection");
} }
}; };
@@ -129,7 +127,7 @@ export const closePool = async () => {
"error", "error",
"lst", "lst",
"sqlProd", "sqlProd",
"There is no connection a connection." "There is no connection a connection.",
); );
return { success: false, message: "There is already a connection." }; return { success: false, message: "There is already a connection." };
} }
@@ -147,8 +145,8 @@ export const closePool = async () => {
"lst", "lst",
"sqlProd", "sqlProd",
`${JSON.stringify( `${JSON.stringify(
error error,
)}, "There was an error closing the sql connection"` )}, "There was an error closing the sql connection"`,
); );
throw new Error("There was an error closing the sql connection"); throw new Error("There was an error closing the sql connection");
} }
@@ -164,7 +162,7 @@ export async function query(queryToRun: string, name: string) {
// .where(eq(settings.name, "dbServer")); // .where(eq(settings.name, "dbServer"));
const dbServer = serverSettings.filter( const dbServer = serverSettings.filter(
(n: any) => n.name === "dbServer" (n: any) => n.name === "dbServer",
) as any; ) as any;
const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`); const serverUp = await checkHostnamePort(`${dbServer[0].value}:1433`);
@@ -173,7 +171,7 @@ export async function query(queryToRun: string, name: string) {
"error", "error",
"lst", "lst",
"server", "server",
`The sql ${dbServer[0].value} is not reachable` `The sql ${dbServer[0].value} is not reachable`,
); );
return { return {
success: false, success: false,
@@ -187,7 +185,7 @@ export async function query(queryToRun: string, name: string) {
"error", "error",
"lst", "lst",
"server", "server",
`The sql ${dbServer[0].value} is not connected` `The sql ${dbServer[0].value} is not connected`,
); );
return { return {
@@ -204,7 +202,7 @@ export async function query(queryToRun: string, name: string) {
// .from(settings) // .from(settings)
// .where(eq(settings.name, "plantToken")); // .where(eq(settings.name, "plantToken"));
const plantToken = serverSettings.filter( const plantToken = serverSettings.filter(
(n: any) => n.name === "plantToken" (n: any) => n.name === "plantToken",
) as any; ) as any;
const query = queryToRun.replaceAll("test1", plantToken[0].value); const query = queryToRun.replaceAll("test1", plantToken[0].value);
@@ -222,9 +220,7 @@ export async function query(queryToRun: string, name: string) {
"error", "error",
"lst", "lst",
"sqlProd", "sqlProd",
`${JSON.stringify( `${JSON.stringify(error)}, ${name} did not run due to a timeout.`,
error
)}, ${name} did not run due to a timeout.`
); );
//throw new Error(`${name} query did not run due to a timeout.`); //throw new Error(`${name} query did not run due to a timeout.`);
return { return {

View File

@@ -155,6 +155,8 @@ and DeliveredQuantity > 0
export const deliveryByDateRangeAndAv = ` export const deliveryByDateRangeAndAv = `
use [test1_AlplaPROD2.0_Read] use [test1_AlplaPROD2.0_Read]
DECLARE @StartDate DATE = '[startDate]' -- 2025-1-1
DECLARE @EndDate DATE = '[endDate]' -- 2025-1-31
SELECT SELECT
r.[ArticleHumanReadableId] r.[ArticleHumanReadableId]
,[ReleaseNumber] ,[ReleaseNumber]
@@ -163,7 +165,7 @@ r.[ArticleHumanReadableId]
,[CustomerReleaseNumber] ,[CustomerReleaseNumber]
,[ReleaseState] ,[ReleaseState]
,[DeliveryState] ,[DeliveryState]
,ea.JournalNummer ,ea.JournalNummer as BOL_Number
,[ReleaseConfirmationState] ,[ReleaseConfirmationState]
,[PlanningState] ,[PlanningState]
--,format(r.[OrderDate], 'yyyy-MM-dd HH:mm') as OrderDate --,format(r.[OrderDate], 'yyyy-MM-dd HH:mm') as OrderDate
@@ -188,6 +190,7 @@ r.[ArticleHumanReadableId]
,[Irradiated] ,[Irradiated]
,r.[CreatedByEdi] ,r.[CreatedByEdi]
,[DeliveryAddressHumanReadableId] ,[DeliveryAddressHumanReadableId]
,DeliveryAddressDescription
,[CustomerArtNo] ,[CustomerArtNo]
,[TotalPrice] ,[TotalPrice]
,r.[ArticleAlias] ,r.[ArticleAlias]
@@ -221,8 +224,8 @@ where
r.ArticleHumanReadableId in ([articles]) r.ArticleHumanReadableId in ([articles])
--r.ReleaseNumber = 1452 --r.ReleaseNumber = 1452
and r.DeliveryDate between '[startDate]' and '[endDate]' and r.DeliveryDate between @StartDate AND @EndDate
--and DeliveredQuantity > 0
order by DeliveryDate desc --and Journalnummer = 169386
`; `;