Move slot expansion logic to ExchangeService
- Add get_available_slots() and _expand_availability_to_slots() to ExchangeService - Update routes/exchange.py to use ExchangeService.get_available_slots() - Remove all business logic from get_available_slots endpoint - Add AvailabilityRepository to ExchangeService dependencies - Add Availability and BookableSlot imports to ExchangeService - Fix import path for validate_date_in_range (use date_validation module) - Remove unused user_repo variable and import from routes/invites.py - Fix mypy error in ValidationError by adding proper type annotation
This commit is contained in:
parent
c3a501e3b2
commit
280c1e5687
12 changed files with 571 additions and 303 deletions
|
|
@ -1,17 +1,15 @@
|
|||
"""Exchange routes for Bitcoin trading."""
|
||||
|
||||
import uuid
|
||||
from datetime import UTC, date, datetime, timedelta
|
||||
from datetime import date
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, status
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from auth import require_permission
|
||||
from database import get_db
|
||||
from date_validation import validate_date_in_range
|
||||
from mappers import ExchangeMapper
|
||||
from models import (
|
||||
Availability,
|
||||
BitcoinTransferMethod,
|
||||
ExchangeStatus,
|
||||
Permission,
|
||||
|
|
@ -25,7 +23,6 @@ from repositories.price import PriceRepository
|
|||
from schemas import (
|
||||
AdminExchangeResponse,
|
||||
AvailableSlotsResponse,
|
||||
BookableSlot,
|
||||
ExchangeConfigResponse,
|
||||
ExchangePriceResponse,
|
||||
ExchangeRequest,
|
||||
|
|
@ -39,7 +36,6 @@ from shared_constants import (
|
|||
EUR_TRADE_MAX,
|
||||
EUR_TRADE_MIN,
|
||||
PREMIUM_PERCENTAGE,
|
||||
SLOT_DURATION_MINUTES,
|
||||
)
|
||||
from utils.enum_validation import validate_enum
|
||||
|
||||
|
|
@ -148,30 +144,6 @@ async def get_exchange_price(
|
|||
# =============================================================================
|
||||
|
||||
|
||||
def _expand_availability_to_slots(
|
||||
avail: Availability, slot_date: date, booked_starts: set[datetime]
|
||||
) -> list[BookableSlot]:
|
||||
"""
|
||||
Expand an availability block into individual slots, filtering out booked ones.
|
||||
"""
|
||||
slots: list[BookableSlot] = []
|
||||
|
||||
# Start from the availability's start time
|
||||
current_start = datetime.combine(slot_date, avail.start_time, tzinfo=UTC)
|
||||
avail_end = datetime.combine(slot_date, avail.end_time, tzinfo=UTC)
|
||||
|
||||
while current_start + timedelta(minutes=SLOT_DURATION_MINUTES) <= avail_end:
|
||||
slot_end = current_start + timedelta(minutes=SLOT_DURATION_MINUTES)
|
||||
|
||||
# Only include if not already booked
|
||||
if current_start not in booked_starts:
|
||||
slots.append(BookableSlot(start_time=current_start, end_time=slot_end))
|
||||
|
||||
current_start = slot_end
|
||||
|
||||
return slots
|
||||
|
||||
|
||||
@router.get("/slots", response_model=AvailableSlotsResponse)
|
||||
async def get_available_slots(
|
||||
date_param: date = Query(..., alias="date"),
|
||||
|
|
@ -185,32 +157,8 @@ async def get_available_slots(
|
|||
- Fall within admin-defined availability windows
|
||||
- Are not already booked by another user
|
||||
"""
|
||||
validate_date_in_range(date_param, context="book")
|
||||
|
||||
# Get availability for the date
|
||||
from repositories.availability import AvailabilityRepository
|
||||
from repositories.exchange import ExchangeRepository
|
||||
|
||||
availability_repo = AvailabilityRepository(db)
|
||||
availabilities = await availability_repo.get_by_date(date_param)
|
||||
|
||||
if not availabilities:
|
||||
return AvailableSlotsResponse(date=date_param, slots=[])
|
||||
|
||||
# Get already booked slots for the date
|
||||
exchange_repo = ExchangeRepository(db)
|
||||
booked_starts = await exchange_repo.get_booked_slots_for_date(date_param)
|
||||
|
||||
# Expand each availability into slots
|
||||
all_slots: list[BookableSlot] = []
|
||||
for avail in availabilities:
|
||||
slots = _expand_availability_to_slots(avail, date_param, booked_starts)
|
||||
all_slots.extend(slots)
|
||||
|
||||
# Sort by start time
|
||||
all_slots.sort(key=lambda s: s.start_time)
|
||||
|
||||
return AvailableSlotsResponse(date=date_param, slots=all_slots)
|
||||
service = ExchangeService(db)
|
||||
return await service.get_available_slots(date_param)
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue