export const buildInventoryTimeline = ( weeklyDemand: Array<{ MaterialHumanReadableId: string; WeekStart: string; WeeklyDemand: number; }>, opening: Record, weeklyPurchases?: Array<{ MaterialHumanReadableId: string; WeekStart: string; WeeklyPurchase: number; }>, ) => { // group weekly demand by material const groupedDemand: Record< string, Array<{ WeekStart: string; Demand: number }> > = {}; for (const d of weeklyDemand) { const mat = d.MaterialHumanReadableId; groupedDemand[mat] ??= []; groupedDemand[mat].push({ WeekStart: d.WeekStart, Demand: Number(d.WeeklyDemand), }); } // group weekly purchases by material const groupedPurchases: Record< string, Array<{ WeekStart: string; Purchase: number }> > = {}; if (weeklyPurchases) { for (const p of weeklyPurchases) { const mat = p.MaterialHumanReadableId; groupedPurchases[mat] ??= []; groupedPurchases[mat].push({ WeekStart: p.WeekStart, Purchase: Number(p.WeeklyPurchase), }); } } // sort both chronologically for (const mat of Object.keys(groupedDemand)) { groupedDemand[mat].sort( (a, b) => new Date(a.WeekStart).getTime() - new Date(b.WeekStart).getTime(), ); } for (const mat of Object.keys(groupedPurchases)) { groupedPurchases[mat].sort( (a, b) => new Date(a.WeekStart).getTime() - new Date(b.WeekStart).getTime(), ); } const result: Array<{ MaterialHumanReadableId: string; WeekStart: string; OpeningInventory: number; Purchases: number; Consumption: number; ClosingInventory: number; }> = []; for (const [mat, weeks] of Object.entries(groupedDemand)) { let inv = opening[mat] ?? 0; const purchasesForMaterial = groupedPurchases[mat] ?? []; for (const week of weeks) { const demand = Number(week.Demand); const purchase = purchasesForMaterial.find((p) => p.WeekStart === week.WeekStart) ?.Purchase ?? 0; const openingInv = inv; const adjustedInv = openingInv + purchase; const closingInv = adjustedInv - demand; result.push({ MaterialHumanReadableId: mat, WeekStart: week.WeekStart, OpeningInventory: Number(openingInv.toFixed(2)), Purchases: Number(purchase.toFixed(2)), Consumption: Number(demand.toFixed(2)), ClosingInventory: Number(closingInv.toFixed(2)), }); inv = closingInv; } } return result; };