This commit is contained in:
2026-03-25 23:57:47 +01:00
parent 2ff7e6f8ce
commit 6e76977ace
4 changed files with 492 additions and 273 deletions

View File

@@ -139,3 +139,53 @@ export function aggregateDayIngredientsBySlot(dayPlan) {
});
return blocks;
}
export function countDayShortfalls(dayPlan, pantry) {
const lines = mergeIngredientLines(flattenDayIngredientLines(dayPlan));
let count = 0;
for (const line of lines) {
if ((Number(pantry[line.ingredientId]) || 0) < line.amount) count++;
}
return count;
}
/**
* Kumulatywna prognoza zużycia spiżarni: od startDate przez lookAheadDays dni.
* Zwraca tablicę dni (tylko te z posiłkami), każdy z listą składników i informacją
* ile jest w spiżarni (po odjęciu zużycia z poprzednich dni) i ile brakuje.
*/
export function computeFullForecast(plans, pantry, startDate, lookAheadDays = 8) {
const running = { ...pantry };
const days = [];
for (let i = 0; i < lookAheadDays; i++) {
const day = addDays(startDate, i);
const dayPlan = getDayPlan(plans, day);
const lines = mergeIngredientLines(flattenDayIngredientLines(dayPlan));
if (lines.length === 0) continue;
const items = lines.map((line) => {
const def = INGREDIENTS[line.ingredientId];
const have = Math.round((Number(running[line.ingredientId]) || 0) * 10) / 10;
const miss = Math.max(0, Math.round((line.amount - have) * 10) / 10);
return {
...line,
pantryQty: have,
shortfall: miss,
enough: miss <= 0,
pantryUnit: def
? def.pantryUnit === 'szt' ? 'szt.' : def.pantryUnit
: line.unit,
};
});
for (const line of lines) {
const have = Number(running[line.ingredientId]) || 0;
running[line.ingredientId] = Math.max(0, Math.round((have - line.amount) * 10) / 10);
}
days.push({ date: day, dayIndex: i, items, hasShortfall: items.some((it) => !it.enough) });
}
return days;
}