M18: implement operational workspaces
This commit is contained in:
@@ -2,9 +2,10 @@ from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from datetime import UTC, datetime
|
||||
from typing import Literal
|
||||
|
||||
from fastapi import APIRouter, Depends, Header, HTTPException, Query, Response
|
||||
from sqlalchemy import func, or_, select
|
||||
from sqlalchemy import case, func, or_, select
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.api.deps import get_current_user, get_db
|
||||
@@ -52,12 +53,16 @@ def list_bookings(
|
||||
status: str | None = Query(default=None),
|
||||
vehicle_ref: str | None = Query(default=None),
|
||||
query: str | None = Query(default=None, min_length=1, max_length=100),
|
||||
starts_from: datetime | None = Query(default=None),
|
||||
starts_to: datetime | None = Query(default=None),
|
||||
location: str | None = Query(default=None, min_length=1, max_length=120),
|
||||
sort: Literal["operational", "starts_asc", "starts_desc"] = Query(default="operational"),
|
||||
page: int | None = Query(default=None, ge=1),
|
||||
page_size: int = Query(default=25, ge=1, le=25),
|
||||
db: Session = Depends(get_db),
|
||||
_user: CurrentUser = Depends(get_current_user),
|
||||
) -> list[BookingOut] | BookingPageOut:
|
||||
stmt = select(Booking).order_by(Booking.starts_at.desc())
|
||||
stmt = select(Booking)
|
||||
if status:
|
||||
stmt = stmt.where(Booking.status == status)
|
||||
if vehicle_ref:
|
||||
@@ -65,20 +70,42 @@ def list_bookings(
|
||||
if vehicle is None:
|
||||
return []
|
||||
stmt = stmt.where(Booking.vehicle_id == vehicle.id)
|
||||
if starts_from:
|
||||
stmt = stmt.where(Booking.ends_at >= starts_from)
|
||||
if starts_to:
|
||||
stmt = stmt.where(Booking.starts_at < starts_to)
|
||||
if query or location:
|
||||
stmt = stmt.join(Customer, Booking.customer_id == Customer.id).join(
|
||||
Vehicle, Booking.vehicle_id == Vehicle.id
|
||||
)
|
||||
if location:
|
||||
stmt = stmt.where(Vehicle.location.ilike(location.strip()))
|
||||
if query:
|
||||
term = f"%{query.strip()}%"
|
||||
stmt = (
|
||||
stmt.join(Customer, Booking.customer_id == Customer.id)
|
||||
.join(Vehicle, Booking.vehicle_id == Vehicle.id)
|
||||
.where(
|
||||
or_(
|
||||
Booking.public_ref.ilike(term),
|
||||
Customer.first_name.ilike(term),
|
||||
Customer.last_name.ilike(term),
|
||||
Vehicle.public_ref.ilike(term),
|
||||
)
|
||||
stmt = stmt.where(
|
||||
or_(
|
||||
Booking.public_ref.ilike(term),
|
||||
Customer.first_name.ilike(term),
|
||||
Customer.last_name.ilike(term),
|
||||
Vehicle.public_ref.ilike(term),
|
||||
)
|
||||
)
|
||||
if sort == "starts_asc":
|
||||
stmt = stmt.order_by(Booking.starts_at.asc())
|
||||
elif sort == "starts_desc":
|
||||
stmt = stmt.order_by(Booking.starts_at.desc())
|
||||
else:
|
||||
now = datetime.now(UTC)
|
||||
operational_bucket = case(
|
||||
(Booking.status == "active", 0),
|
||||
(Booking.starts_at >= now, 1),
|
||||
else_=2,
|
||||
)
|
||||
stmt = stmt.order_by(
|
||||
operational_bucket,
|
||||
case((Booking.starts_at >= now, Booking.starts_at)).asc().nulls_last(),
|
||||
Booking.starts_at.desc(),
|
||||
)
|
||||
total = db.scalar(select(func.count()).select_from(stmt.subquery())) or 0
|
||||
page_number = page or 1
|
||||
bookings = db.scalars(
|
||||
@@ -164,9 +191,7 @@ def checkout_booking(
|
||||
db: Session = Depends(get_db),
|
||||
user: CurrentUser = Depends(get_current_user),
|
||||
) -> CheckoutBookingResult:
|
||||
booking = db.scalar(
|
||||
select(Booking).where(Booking.public_ref == public_ref).with_for_update()
|
||||
)
|
||||
booking = db.scalar(select(Booking).where(Booking.public_ref == public_ref).with_for_update())
|
||||
if booking is None:
|
||||
raise HTTPException(status_code=404, detail="Booking not found")
|
||||
if booking.status != "reserved":
|
||||
@@ -324,9 +349,7 @@ def cancel_booking(
|
||||
db: Session = Depends(get_db),
|
||||
user: CurrentUser = Depends(get_current_user),
|
||||
) -> BookingOut:
|
||||
booking = db.scalar(
|
||||
select(Booking).where(Booking.public_ref == public_ref).with_for_update()
|
||||
)
|
||||
booking = db.scalar(select(Booking).where(Booking.public_ref == public_ref).with_for_update())
|
||||
if booking is None:
|
||||
raise HTTPException(status_code=404, detail="Booking not found")
|
||||
if booking.status != "reserved":
|
||||
|
||||
Reference in New Issue
Block a user