Restructure weekly actuals charts — Sales History section + month cumulative

Backend:
- Always fetch full calendar month (not truncated at week ending)
- Add month_daily[] to response (per-day TY/LY by dept, is_actual flag)

Frontend:
- New 'Sales History' section with:
  - Monthly dept line chart: 12-month x-axis, TY vs prior year per dept
    (Rooms/Dry/Wet solid, LY dashed — same colour per dept)
  - Rolling 12-month average trend (moved from Month Progress)
- Month Progress section gains cumulative line chart:
  - X-axis = day of month, 6 lines (3 TY solid + 3 LY dashed)
  - TY lines stop at week ending; LY spans full month

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
jtricerolph 2026-07-20 14:03:51 +00:00
parent 7f0d1057c1
commit ffa13d6e57
3 changed files with 165 additions and 65 deletions

View file

@ -88,9 +88,9 @@ export async function weeklyActualRoutes(fastify) {
// 5-week window: start 4 weeks before this week's Sunday
const fiveWeekStart = addDays(weekStartDate, -28)
// Month to date: 1st of month → week ending date
const monthStart = new Date(year, month - 1, 1)
const monthDays = Math.round((weekEndDate - monthStart) / 86400000) + 1
// Full calendar month (needed for daily chart — month progress filters by date)
const monthStart = new Date(year, month - 1, 1)
const daysInMonth = new Date(year, month, 0).getDate()
// 36 months of raw totals needed to compute rolling 12-month averages for
// 12 display points (indices 2335) plus their LY equivalents (indices 023)
@ -106,10 +106,8 @@ export async function weeklyActualRoutes(fastify) {
fcFetch(`/forecast/revenue?start_date=${toDateStr(fiveWeekStart)}&days=35&type=all`),
// This week rooms (for occupancy table)
fcFetch(`/forecast/rooms?start_date=${toDateStr(weekStartDate)}&days=7`),
// Month to date revenue
monthDays > 0
? fcFetch(`/forecast/revenue?start_date=${toDateStr(monthStart)}&days=${monthDays}&type=all`)
: Promise.resolve({ data: [] }),
// Full month revenue (used for month progress totals + daily chart)
fcFetch(`/forecast/revenue?start_date=${toDateStr(monthStart)}&days=${daysInMonth}&type=all`),
// 12 monthly trend revenue calls
...trendMonths.map(({ year: y, month: m }) => {
const firstDay = new Date(y, m - 1, 1)
@ -118,11 +116,11 @@ export async function weeklyActualRoutes(fastify) {
}),
])
const [fiveWeekRevRaw, thisWeekRoomsRaw, monthRevRaw, ...trendRevRaw] = results
const [fiveWeekRevRaw, thisWeekRoomsRaw, fullMonthRevRaw, ...trendRevRaw] = results
const fiveWeekRevMap = buildDayMap(fiveWeekRevRaw)
const fiveWeekRevMap = buildDayMap(fiveWeekRevRaw)
const thisWeekRoomsMap = buildDayMap(thisWeekRoomsRaw)
const monthRevMap = buildDayMap(monthRevRaw)
const fullMonthRevMap = buildDayMap(fullMonthRevRaw)
// ── Five week summaries ────────────────────────────────────────────────────
const fiveWeeks = [0, 1, 2, 3, 4].map(w => {
@ -181,11 +179,11 @@ export async function weeklyActualRoutes(fastify) {
let mBud = { rooms: 0, dry: 0, wet: 0 }
let mLy = { rooms: 0, dry: 0, wet: 0 }
for (let i = 0; i < monthDays; i++) {
for (let i = 0; i < daysInMonth; i++) {
const d = addDays(monthStart, i)
if (d > weekEndDate) break
const dateStr = toDateStr(d)
const rev = monthRevMap[dateStr] || {}
const rev = fullMonthRevMap[dateStr] || {}
mNet.rooms += parseFloat(rev.accom?.otb ?? 0)
mNet.dry += parseFloat(rev.dry?.otb ?? 0)
@ -224,6 +222,26 @@ export async function weeklyActualRoutes(fastify) {
},
}
// ── Month daily (for cumulative progress line chart) ──────────────────────
const weekEndStr = toDateStr(weekEndDate)
const month_daily = []
for (let i = 0; i < daysInMonth; i++) {
const d = addDays(monthStart, i)
const dateStr = toDateStr(d)
const rev = fullMonthRevMap[dateStr] || {}
month_daily.push({
day: i + 1,
date: dateStr,
ty_rooms: parseFloat(rev.accom?.otb ?? 0),
ty_dry: parseFloat(rev.dry?.otb ?? 0),
ty_wet: parseFloat(rev.wet?.otb ?? 0),
ly_rooms: parseFloat(rev.accom?.prior_final ?? 0),
ly_dry: parseFloat(rev.dry?.prior_final ?? 0),
ly_wet: parseFloat(rev.wet?.prior_final ?? 0),
is_actual: dateStr <= weekEndStr,
})
}
// ── Monthly trend (rolling 12-month average) ──────────────────────────────
// Build raw monthly totals for all 36 months
const allMonthTotals = trendMonths.map((_, i) => {
@ -279,6 +297,7 @@ export async function weeklyActualRoutes(fastify) {
five_weeks: fiveWeeks,
occupancy,
month_progress,
month_daily,
monthly_trend,
monthly_split,
}