Automated Action 9e56bda916 Implement Multimodal Ticketing System with FastAPI and SQLite
This commit includes:
- Project structure and FastAPI setup
- SQLAlchemy models for users, vehicles, schedules, and tickets
- Alembic migrations
- User authentication and management
- Vehicle and schedule management
- Ticket purchase and cancellation with time restrictions
- Comprehensive API documentation
2025-06-17 11:08:42 +00:00

97 lines
3.2 KiB
Python

import uuid
from datetime import datetime, timedelta
from typing import Optional
from fastapi import HTTPException, status
from sqlalchemy.orm import Session
from app.models.ticket import Ticket, TicketStatus
from app.models.vehicle import Schedule, VehicleType
def generate_ticket_number() -> str:
"""Generate a unique ticket number."""
return str(uuid.uuid4())
def validate_purchase_time(schedule: Schedule) -> None:
"""
Validate that a ticket can be purchased based on departure time.
Args:
schedule: The schedule for which the ticket is being purchased
Raises:
HTTPException: If ticket cannot be purchased due to time restrictions
"""
now = datetime.utcnow()
# Check if it's less than 10 minutes to departure
if schedule.departure_time - now < timedelta(minutes=10):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Cannot purchase ticket less than 10 minutes before departure",
)
def validate_cancellation_time(ticket: Ticket) -> None:
"""
Validate that a ticket can be cancelled based on departure time.
Args:
ticket: The ticket to be cancelled
Raises:
HTTPException: If ticket cannot be cancelled due to time restrictions
"""
now = datetime.utcnow()
# Check if it's less than 3 minutes to departure
if ticket.schedule.departure_time - now < timedelta(minutes=3):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Cannot cancel ticket less than 3 minutes before departure",
)
# Check if ticket is already used, cancelled, or expired
if ticket.status != TicketStatus.ACTIVE:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Cannot cancel ticket with status {ticket.status}",
)
def assign_seat_number(db: Session, schedule: Schedule, vehicle_type: VehicleType) -> Optional[str]:
"""
Assign a seat number for a ticket if vehicle is a train.
For cars and buses, seat number is None.
Args:
db: Database session
schedule: The schedule for which the ticket is being purchased
vehicle_type: Type of vehicle
Returns:
Seat number string for trains, None for other vehicle types
"""
if vehicle_type != VehicleType.TRAIN:
return None
# For trains, find the next available seat number
# Get all occupied seats for this schedule
occupied_seats = db.query(Ticket.seat_number).filter(
Ticket.schedule_id == schedule.id,
Ticket.status == TicketStatus.ACTIVE,
Ticket.seat_number.isnot(None)
).all()
occupied_seat_numbers = [int(seat[0]) for seat in occupied_seats if seat[0] and seat[0].isdigit()]
# Find the first available seat
for seat_num in range(1, schedule.vehicle.capacity + 1):
if seat_num not in occupied_seat_numbers:
return str(seat_num)
# This should not happen if available_seats is managed correctly
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="No available seats",
)