From f0d4fb3beb27c0d103b0200ec4de07aca3052f9c Mon Sep 17 00:00:00 2001 From: jtricerolph Date: Mon, 20 Jul 2026 12:37:28 +0000 Subject: [PATCH] Use occupied_rooms from occupancy report for past-date OTB, excluding overflow Co-Authored-By: Claude Sonnet 4.6 --- backend/api/public.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/backend/api/public.py b/backend/api/public.py index 538a437..41e2387 100644 --- a/backend/api/public.py +++ b/backend/api/public.py @@ -53,10 +53,12 @@ async def get_rooms_forecast( row = result.fetchone() fallback_total_rooms = int(row.config_value) if row and row.config_value else 30 - # Pre-fetch available rooms per day using is_included flag from room categories settings + # Pre-fetch available and occupied rooms per day using is_included flag from room category settings occ_result = await db.execute( text(""" - SELECT o.date, SUM(COALESCE(o.available, 0) - COALESCE(o.maintenance, 0)) AS available_rooms + SELECT o.date, + SUM(COALESCE(o.available, 0) - COALESCE(o.maintenance, 0)) AS available_rooms, + SUM(COALESCE(o.occupied, 0)) AS occupied_rooms FROM newbook_occupancy_report_data o JOIN newbook_room_categories c ON o.category_id = c.site_id WHERE o.date >= :start_date AND o.date <= :end_date @@ -65,7 +67,9 @@ async def get_rooms_forecast( """), {"start_date": start, "end_date": end} ) - available_by_date = {row.date: int(row.available_rooms) for row in occ_result.fetchall() if row.available_rooms} + occ_by_date = {row.date: row for row in occ_result.fetchall()} + available_by_date = {d: int(r.available_rooms) for d, r in occ_by_date.items() if r.available_rooms} + occupied_by_date = {d: int(r.occupied_rooms) for d, r in occ_by_date.items() if r.occupied_rooms} data = [] current = start @@ -120,16 +124,17 @@ async def get_rooms_forecast( pickup_guests = round(pickup_rooms * guests_per_room) forecast_guests = otb_guests + pickup_guests else: - # Past date - get actuals from stats + # Past date - use occupied count from occupancy report (is_included only, no overflow) + otb_rooms = occupied_by_date.get(current, 0) + # Guest count still comes from stats (no per-category guest breakdown available) stats_result = await db.execute( text(""" - SELECT booking_count, guests_count FROM newbook_bookings_stats + SELECT guests_count FROM newbook_bookings_stats WHERE date = :target_date """), {"target_date": current} ) stats_row = stats_result.fetchone() - otb_rooms = stats_row.booking_count if stats_row else 0 otb_guests = stats_row.guests_count if stats_row and stats_row.guests_count else 0 forecast_rooms = otb_rooms forecast_guests = otb_guests