From e9899ce7d56ae6f76cccc55f918bd5df33aac794 Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Tue, 21 Jul 2026 17:33:09 +0000 Subject: [PATCH] Fix worksheet past-date display: pickup, dry/wet, and room cap Past dates: zero out pickup (override ignored), use actuals for dry/wet (fall back to override/forecast only if no actual exists), lock dry/wet inputs read-only. Pickup + OTB total is now capped at available rooms so occupancy can't exceed 100%. Totals row also excludes past pickup. Co-Authored-By: Claude Sonnet 4.6 --- frontend/src/pages/DirectorsForecast.tsx | 27 ++++++++++++++---------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/frontend/src/pages/DirectorsForecast.tsx b/frontend/src/pages/DirectorsForecast.tsx index 5ad2688e..d71b23fc 100644 --- a/frontend/src/pages/DirectorsForecast.tsx +++ b/frontend/src/pages/DirectorsForecast.tsx @@ -123,15 +123,20 @@ function WorksheetTab({ year, month }: { year: number; month: number }) { } function computedDay(day: WorksheetDay) { - const ovr = overrides[day.date] || {} - const pickup = parseInt(ovr.pickup_rooms || '0') || 0 - const rate = parseFloat(ovr.pickup_avg_rate || '') || parseFloat(sessionRate) || 135 - const total = day.otb_rooms + pickup - const occ = day.available > 0 ? (total / day.available) * 100 : null - let accomm = day.otb_net_rev + pickup * rate + const ovr = overrides[day.date] || {} + const pickup = day.is_past ? 0 : (parseInt(ovr.pickup_rooms || '0') || 0) + const rate = parseFloat(ovr.pickup_avg_rate || '') || parseFloat(sessionRate) || 135 + const rawTotal = day.otb_rooms + pickup + const total = day.available > 0 ? Math.min(rawTotal, day.available) : rawTotal + const occ = day.available > 0 ? (total / day.available) * 100 : null + let accomm = day.otb_net_rev + pickup * rate if (day.is_past && day.actual_accomm != null) accomm = day.actual_accomm - const dry = ovr.dry_override !== '' ? parseFloat(ovr.dry_override) : day.forecast_dry - const wet = ovr.wet_override !== '' ? parseFloat(ovr.wet_override) : day.forecast_wet + const dry = day.is_past && day.actual_dry != null + ? day.actual_dry + : (ovr.dry_override !== '' ? parseFloat(ovr.dry_override) : day.forecast_dry) + const wet = day.is_past && day.actual_wet != null + ? day.actual_wet + : (ovr.wet_override !== '' ? parseFloat(ovr.wet_override) : day.forecast_wet) return { total, occ, accomm, dry: dry || 0, wet: wet || 0 } } @@ -140,7 +145,7 @@ function WorksheetTab({ year, month }: { year: number; month: number }) { const totals = data.days.reduce((acc, day) => { const c = computedDay(day) - const p = parseInt(overrides[day.date]?.pickup_rooms || '0') || 0 + const p = day.is_past ? 0 : (parseInt(overrides[day.date]?.pickup_rooms || '0') || 0) return { available: acc.available + day.available, otb: acc.otb + day.otb_rooms, @@ -233,7 +238,7 @@ function WorksheetTab({ year, month }: { year: number; month: number }) { {c.occ != null ? `${c.occ.toFixed(1)}%` : '—'} {fmtCcy(c.accomm)} - {canEdit ? ( + {canEdit && !day.is_past ? ( {fmtCcy(c.dry)}} - {canEdit ? ( + {canEdit && !day.is_past ? (