Add dow_align param to /forecast/revenue and /forecast/rooms
Allows callers to switch between 364-day DOW-aligned prior year and same calendar-date prior year comparison. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
185b2ec163
commit
454f34d390
1 changed files with 16 additions and 8 deletions
|
|
@ -16,18 +16,25 @@ router = APIRouter()
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_prior_year_date(target_date: date) -> date:
|
||||
def get_prior_year_date(target_date: date, dow_align: bool = True) -> date:
|
||||
"""
|
||||
Get prior year date with 364-day offset for day-of-week alignment.
|
||||
52 weeks = 364 days, so Monday aligns with Monday.
|
||||
Get prior year comparison date.
|
||||
dow_align=True: 364-day (52-week) offset keeps same weekday.
|
||||
dow_align=False: same calendar date last year.
|
||||
"""
|
||||
if dow_align:
|
||||
return target_date - timedelta(days=364)
|
||||
try:
|
||||
return target_date.replace(year=target_date.year - 1)
|
||||
except ValueError: # Feb 29 in leap year → Feb 28
|
||||
return target_date.replace(year=target_date.year - 1, day=28)
|
||||
|
||||
|
||||
@router.get("/forecast/rooms")
|
||||
async def get_rooms_forecast(
|
||||
start_date: str = Query(..., description="Start date (YYYY-MM-DD)"),
|
||||
days: int = Query(7, ge=1, le=365, description="Number of days to forecast"),
|
||||
dow_align: bool = Query(True, description="Use 364-day DOW-aligned offset for prior year (false = same calendar date)"),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
api_key: dict = Depends(get_api_key_auth)
|
||||
):
|
||||
|
|
@ -75,7 +82,7 @@ async def get_rooms_forecast(
|
|||
current = start
|
||||
while current <= end:
|
||||
lead_days = (current - today).days if current >= today else 0
|
||||
prior_date = get_prior_year_date(current)
|
||||
prior_date = get_prior_year_date(current, dow_align)
|
||||
total_rooms = available_by_date.get(current, fallback_total_rooms)
|
||||
|
||||
try:
|
||||
|
|
@ -287,6 +294,7 @@ async def get_revenue_forecast(
|
|||
start_date: str = Query(..., description="Start date (YYYY-MM-DD)"),
|
||||
days: int = Query(7, ge=1, le=365, description="Number of days to forecast"),
|
||||
type: str = Query("all", description="Revenue type: all, accom, dry, wet"),
|
||||
dow_align: bool = Query(True, description="Use 364-day DOW-aligned offset for prior year (false = same calendar date)"),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
api_key: dict = Depends(get_api_key_auth)
|
||||
):
|
||||
|
|
@ -340,8 +348,8 @@ async def get_revenue_forecast(
|
|||
actual_by_date = {row.date: row for row in actual_result.fetchall()}
|
||||
|
||||
# Get prior year revenue
|
||||
prior_start = get_prior_year_date(start)
|
||||
prior_end = get_prior_year_date(end)
|
||||
prior_start = get_prior_year_date(start, dow_align)
|
||||
prior_end = get_prior_year_date(end, dow_align)
|
||||
prior_result = await db.execute(
|
||||
text("""
|
||||
SELECT date, accommodation, dry, wet
|
||||
|
|
@ -413,7 +421,7 @@ async def get_revenue_forecast(
|
|||
while current <= end:
|
||||
is_past = current < today
|
||||
lead_days = (current - today).days if current >= today else 0
|
||||
prior_date = get_prior_year_date(current)
|
||||
prior_date = get_prior_year_date(current, dow_align)
|
||||
|
||||
# Prior year actual
|
||||
prior_row = prior_by_date.get(prior_date)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue