from sqlalchemy import select from sqlalchemy.orm import Session from app.core.errors import AppError from app.models.catalog import Event, TicketType, Venue from app.models.enums import TicketTypeStatus from app.schemas.admin import ( EventCreate, EventUpdate, TicketTypeCreate, TicketTypeUpdate, VenueCreate, VenueUpdate, ) def list_venues_admin(db: Session) -> list[Venue]: return list(db.scalars(select(Venue).order_by(Venue.name.asc())).all()) def create_venue(db: Session, body: VenueCreate) -> Venue: if db.scalar(select(Venue.id).where(Venue.slug == body.slug)): raise AppError("Venue slug already exists", status_code=409) venue = Venue(**body.model_dump()) db.add(venue) db.commit() db.refresh(venue) return venue def update_venue(db: Session, venue_id: int, body: VenueUpdate) -> Venue: venue = db.get(Venue, venue_id) if not venue: raise AppError("Venue not found", status_code=404) data = body.model_dump(exclude_unset=True) if "slug" in data and data["slug"] != venue.slug: if db.scalar(select(Venue.id).where(Venue.slug == data["slug"])): raise AppError("Venue slug already exists", status_code=409) for key, value in data.items(): setattr(venue, key, value) db.commit() db.refresh(venue) return venue def list_events_admin(db: Session) -> list[Event]: return list(db.scalars(select(Event).order_by(Event.starts_at.desc())).all()) def create_event(db: Session, body: EventCreate) -> Event: if not db.get(Venue, body.venue_id): raise AppError("Venue not found", status_code=400) if db.scalar(select(Event.id).where(Event.slug == body.slug)): raise AppError("Event slug already exists", status_code=409) event = Event(**body.model_dump()) db.add(event) db.commit() db.refresh(event) return event def update_event(db: Session, event_id: int, body: EventUpdate) -> Event: event = db.get(Event, event_id) if not event: raise AppError("Event not found", status_code=404) data = body.model_dump(exclude_unset=True) if "venue_id" in data and not db.get(Venue, data["venue_id"]): raise AppError("Venue not found", status_code=400) if "slug" in data and data["slug"] != event.slug: if db.scalar(select(Event.id).where(Event.slug == data["slug"])): raise AppError("Event slug already exists", status_code=409) for key, value in data.items(): setattr(event, key, value) db.commit() db.refresh(event) return event def ticket_type_to_admin(tier: TicketType) -> dict: return { "id": tier.id, "event_id": tier.event_id, "name": tier.name, "description": tier.description, "price_paise": tier.price_paise, "quantity_total": tier.quantity_total, "quantity_sold": tier.quantity_sold, "remaining": max(tier.quantity_total - tier.quantity_sold, 0), "status": tier.status, "sort_order": tier.sort_order, } def list_ticket_types(db: Session, event_id: int | None = None) -> list[dict]: query = select(TicketType).order_by(TicketType.event_id.asc(), TicketType.sort_order.asc()) if event_id is not None: query = query.where(TicketType.event_id == event_id) return [ticket_type_to_admin(row) for row in db.scalars(query).all()] def create_ticket_type(db: Session, body: TicketTypeCreate) -> TicketType: if not db.get(Event, body.event_id): raise AppError("Event not found", status_code=400) tier = TicketType(**body.model_dump()) db.add(tier) db.commit() db.refresh(tier) return tier def update_ticket_type(db: Session, tier_id: int, body: TicketTypeUpdate) -> TicketType: tier = db.get(TicketType, tier_id) if not tier: raise AppError("Ticket type not found", status_code=404) data = body.model_dump(exclude_unset=True) if "quantity_total" in data and data["quantity_total"] < tier.quantity_sold: raise AppError("Total quantity cannot be less than sold count", status_code=400) for key, value in data.items(): setattr(tier, key, value) if tier.quantity_sold >= tier.quantity_total: tier.status = TicketTypeStatus.sold_out elif tier.status == TicketTypeStatus.sold_out and tier.quantity_sold < tier.quantity_total: tier.status = TicketTypeStatus.active db.commit() db.refresh(tier) return tier