Monthly forecast: repeat last full actual week to end of month instead of single 7-day lookback

Fixes an edge case where days more than 7 days past the actual cutoff had no
valid prior-week source day (itself a forecast day), silently contributing
£0. Now walks back in 7-day steps until landing on an actual day, so the
last complete actual week tiles forward for the rest of the month.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-23 17:19:10 +00:00
parent 84f5d38b10
commit 9e7f4030d2

View file

@ -21,6 +21,12 @@ function fmtDisplay(dateStr: string): string {
function budgetColour(pct: number): string {
return pct <= 100 ? 'var(--app-primary)' : pct <= 110 ? '#b45309' : '#dc2626'
}
// Baseline forecast: repeat the last full actual week's pattern forward to end of month
function repeatingPriorCost(days: Record<string, { cost: number }>, dateStr: string, cutoffStr: string): number {
let probe = dateStr
while (probe > cutoffStr) probe = fmt(addDays(new Date(probe + 'T00:00:00'), -7))
return days[probe]?.cost ?? 0
}
const DEPT_COLORS = ['#065f46','#059669','#0891b2','#7c3aed','#c2410c','#b45309','#0f766e','#4338ca','#be185d','#15803d']
@ -154,9 +160,7 @@ export default function Monthly() {
for (let day = 1; day <= dim; day++) {
const dateStr = `${monthStr}-${String(day).padStart(2, '0')}`
if (dateStr <= yesterdayStr) continue
const priorStr = fmt(addDays(new Date(dateStr + 'T00:00:00'), -7))
const priorCost = dep.days[priorStr]?.cost
if (priorCost != null) forecastRem += priorCost
forecastRem += repeatingPriorCost(dep.days, dateStr, yesterdayStr)
}
}
@ -211,8 +215,7 @@ export default function Monthly() {
if (dateStr <= cutoff) {
deptCost += srcDep?.days[dateStr]?.cost ?? 0
} else {
const priorStr = fmt(addDays(new Date(dateStr + 'T00:00:00'), -7))
deptCost += srcDep?.days[priorStr]?.cost ?? 0
deptCost += repeatingPriorCost(srcDep?.days ?? {}, dateStr, cutoff)
}
}
entry[dep.department_name] = deptCost