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