"""Matrice poste × créneau d'une édition : source de l'écran principal.""" from fastapi import APIRouter, Depends from sqlalchemy import func from sqlmodel import Session, select from app.api.deps import get_edition from app.api.schemas import MatrixPosition, MatrixResponse, MatrixShift from app.auth.deps import require_staff from app.db import get_session from app.models import Account, Assignment, Edition, Position, Shift router = APIRouter(prefix="/editions/{edition_id}/matrix", tags=["matrix"]) @router.get("", response_model=MatrixResponse) def get_matrix( edition: Edition = Depends(get_edition), _guard: Account = Depends(require_staff), session: Session = Depends(get_session), ) -> MatrixResponse: positions = list( session.exec( select(Position) .where(Position.edition_id == edition.id) .order_by(Position.name) ) ) shifts = list( session.exec( select(Shift) .where(Shift.edition_id == edition.id) .order_by(Shift.starts_at) ) ) counts = { shift_id: total for shift_id, total in session.exec( select(Assignment.shift_id, func.count()) .where(Assignment.edition_id == edition.id) .group_by(Assignment.shift_id) ) } shifts_by_position: dict = {} for shift in shifts: shifts_by_position.setdefault(shift.position_id, []).append( MatrixShift( shift_id=shift.id, starts_at=shift.starts_at, ends_at=shift.ends_at, min_staff=shift.min_staff, ideal_staff=shift.ideal_staff, assigned=counts.get(shift.id, 0), ) ) return MatrixResponse( edition_id=edition.id, positions=[ MatrixPosition( id=position.id, name=position.name, category=position.category, location=position.location, shifts=shifts_by_position.get(position.id, []), ) for position in positions ], )