From dfc863250c329074601314c69e1521c417fc5f46 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Thu, 6 Aug 2026 07:51:07 +0000 Subject: [PATCH] Compare full-week forecast against a full prev week, not a partial one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Prev wk" figure shown under Forecast Full Week was reusing prevCost, which is deliberately scoped to "same elapsed days as WTD" (e.g. only Mon-Wed of last week if today's Wednesday) — correct for the per-department table's WTD-vs-WTD "vs Prev Wk" column, but wrong paired with totalForecast, which projects a full 7 days. Comparing a full-week projection against a few days of last week made prev week look artificially low and the delta look inflated. Added prevFullCost (full Mon-Sun of the prior week — already present in the 14-day actuals fetch) for the full-week comparison specifically; left prevCost/totalPrev untouched for the table's WTD comparisons. --- frontend/src/pages/Weekly.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/Weekly.tsx b/frontend/src/pages/Weekly.tsx index 67e0a9e..8139f70 100644 --- a/frontend/src/pages/Weekly.tsx +++ b/frontend/src/pages/Weekly.tsx @@ -198,7 +198,8 @@ export default function Weekly() { department_name: string wtdCost: number // actual WTD (or full week for past weeks) forecastFull: number // full week forecast via prior-week same-day actuals - prevCost: number // prev week same elapsed days (or full prev week for past weeks) + prevCost: number // prev week same elapsed days (or full prev week for past weeks) — for WTD-vs-WTD comparisons + prevFullCost: number // full prev week (Mon-Sun) — for comparing against the full-week forecast } const deptRows: DeptRow[] = depts.map(dep => { const wtdCost = Object.entries(dep.days) @@ -223,12 +224,17 @@ export default function Weekly() { .filter(([d]) => d >= prevWeekFrom && d <= prevCutoff) .reduce((s, [, v]) => s + v.cost, 0) - return { department_id: dep.department_id, department_name: dep.department_name, wtdCost, forecastFull, prevCost } + const prevFullCost = Object.entries(dep.days) + .filter(([d]) => d >= prevWeekFrom && d <= prevWeekTo) + .reduce((s, [, v]) => s + v.cost, 0) + + return { department_id: dep.department_id, department_name: dep.department_name, wtdCost, forecastFull, prevCost, prevFullCost } }).sort((a, b) => b.forecastFull - a.forecastFull) const totalWTD = deptRows.reduce((s, d) => s + d.wtdCost, 0) const totalForecast = deptRows.reduce((s, d) => s + d.forecastFull, 0) const totalPrev = deptRows.reduce((s, d) => s + d.prevCost, 0) + const totalPrevFull = deptRows.reduce((s, d) => s + d.prevFullCost, 0) const totalPyWages = pyWages ?? 0 const pctBudgWTD = budgetWTD != null && budgetWTD > 0 ? (totalWTD / budgetWTD) * 100 : null @@ -320,7 +326,7 @@ export default function Weekly() {
Forecast Full Week
{fmtMoney(totalForecast)}
- {totalPrev > 0 &&
Prev wk {fmtMoney(totalPrev)}{pyPct(totalForecast, totalPrev)}
} + {totalPrevFull > 0 &&
Prev wk {fmtMoney(totalPrevFull)}{pyPct(totalForecast, totalPrevFull)}
}
Budget Full Week