FIxed date range overlap
This commit is contained in:
@@ -242,6 +242,9 @@ class FreeRoomsAction(AlpineBitsAction):
|
||||
encountered_standard = False
|
||||
has_categories = False # Tracks if we've seen category reports (no InvCode)
|
||||
has_rooms = False # Tracks if we've seen individual room reports (with InvCode)
|
||||
closing_season_ranges: list[tuple[date, date]] = []
|
||||
# Track date ranges per room/category to detect overlaps
|
||||
inventory_ranges: dict[tuple[str, str | None], list[tuple[date, date]]] = {}
|
||||
|
||||
for inventory in inventories:
|
||||
sac = inventory.status_application_control
|
||||
@@ -255,16 +258,17 @@ class FreeRoomsAction(AlpineBitsAction):
|
||||
|
||||
# Validate closing seasons
|
||||
if is_closing:
|
||||
if inventory.inv_counts is not None:
|
||||
raise FreeRoomsProcessingError(
|
||||
"Closing seasons cannot contain InvCounts data",
|
||||
HttpStatusCode.BAD_REQUEST,
|
||||
)
|
||||
# Closing seasons are only allowed in CompleteSet - fail fast
|
||||
if update_type != "CompleteSet":
|
||||
raise FreeRoomsProcessingError(
|
||||
"Closing seasons are only allowed on CompleteSet updates",
|
||||
HttpStatusCode.BAD_REQUEST,
|
||||
)
|
||||
if inventory.inv_counts is not None:
|
||||
raise FreeRoomsProcessingError(
|
||||
"Closing seasons cannot contain InvCounts data",
|
||||
HttpStatusCode.BAD_REQUEST,
|
||||
)
|
||||
if enforce_closing_order and encountered_standard:
|
||||
raise FreeRoomsProcessingError(
|
||||
"Closing seasons must appear before other inventory entries",
|
||||
@@ -275,8 +279,9 @@ class FreeRoomsAction(AlpineBitsAction):
|
||||
"Closing season entries cannot specify InvTypeCode or InvCode",
|
||||
HttpStatusCode.BAD_REQUEST,
|
||||
)
|
||||
# Validate date range
|
||||
self._parse_date_range(sac.start, sac.end)
|
||||
# Validate and store date range
|
||||
start_date, end_date = self._parse_date_range(sac.start, sac.end)
|
||||
closing_season_ranges.append((start_date, end_date))
|
||||
continue
|
||||
|
||||
# Mark that we've seen a non-closing inventory entry
|
||||
@@ -291,7 +296,32 @@ class FreeRoomsAction(AlpineBitsAction):
|
||||
)
|
||||
|
||||
# Validate date range
|
||||
self._parse_date_range(sac.start, sac.end)
|
||||
start_date, end_date = self._parse_date_range(sac.start, sac.end)
|
||||
|
||||
# Check for overlap with closing seasons
|
||||
for closing_start, closing_end in closing_season_ranges:
|
||||
if self._date_ranges_overlap(start_date, end_date, closing_start, closing_end):
|
||||
raise FreeRoomsProcessingError(
|
||||
f"Inventory entry ({start_date} to {end_date}) overlaps with closing season ({closing_start} to {closing_end})",
|
||||
HttpStatusCode.BAD_REQUEST,
|
||||
)
|
||||
|
||||
# Check for overlap with other inventory entries for the same room/category
|
||||
inv_code = sac.inv_code.strip() if sac.inv_code else None
|
||||
inventory_key = (inv_type_code, inv_code)
|
||||
|
||||
if inventory_key in inventory_ranges:
|
||||
for existing_start, existing_end in inventory_ranges[inventory_key]:
|
||||
if self._date_ranges_overlap(start_date, end_date, existing_start, existing_end):
|
||||
room_desc = f"room '{inv_code}'" if inv_code else f"category '{inv_type_code}'"
|
||||
raise FreeRoomsProcessingError(
|
||||
f"Overlapping date ranges for {room_desc}: ({start_date} to {end_date}) and ({existing_start} to {existing_end})",
|
||||
HttpStatusCode.BAD_REQUEST,
|
||||
)
|
||||
else:
|
||||
inventory_ranges[inventory_key] = []
|
||||
|
||||
inventory_ranges[inventory_key].append((start_date, end_date))
|
||||
|
||||
# Validate that we don't mix categories and individual rooms
|
||||
has_inv_code = sac.inv_code is not None and sac.inv_code.strip() != ""
|
||||
@@ -313,6 +343,15 @@ class FreeRoomsAction(AlpineBitsAction):
|
||||
# Validate counts
|
||||
self._extract_counts(inventory.inv_counts)
|
||||
|
||||
# Check for overlapping closing seasons
|
||||
for i, (start1, end1) in enumerate(closing_season_ranges):
|
||||
for start2, end2 in closing_season_ranges[i + 1:]:
|
||||
if self._date_ranges_overlap(start1, end1, start2, end2):
|
||||
raise FreeRoomsProcessingError(
|
||||
f"Closing seasons overlap: ({start1} to {end1}) and ({start2} to {end2})",
|
||||
HttpStatusCode.BAD_REQUEST,
|
||||
)
|
||||
|
||||
async def _process_complete_set(
|
||||
self,
|
||||
session: AsyncSession,
|
||||
@@ -528,6 +567,15 @@ class FreeRoomsAction(AlpineBitsAction):
|
||||
)
|
||||
return start_date, end_date
|
||||
|
||||
def _date_ranges_overlap(
|
||||
self, start1: date, end1: date, start2: date, end2: date
|
||||
) -> bool:
|
||||
"""Check if two date ranges overlap (inclusive).
|
||||
|
||||
Returns True if the ranges have any dates in common.
|
||||
"""
|
||||
return start1 <= end2 and start2 <= end1
|
||||
|
||||
def _iter_days(self, start_date: date, end_date: date):
|
||||
current = start_date
|
||||
while current <= end_date:
|
||||
|
||||
Reference in New Issue
Block a user