refactor(psi): planning numbers refactored to deal with a bad downsync that caused negative numbers
This commit is contained in:
@@ -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
|
||||||
|
}
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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;
|
||||||
|
// }),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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 day’s 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;
|
||||||
|
};
|
||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user