Files
AdamThomasandClaude Sonnet 5 464635656a Étape 9 : suppression du statut d'affectation (plus de confirmation)
Une affectation est valide dès sa création ; la retirer = supprimer la ligne.

- Modèle : suppression de AssignmentStatus, ACTIVE_ASSIGNMENT_STATUSES et de
  Assignment.status ; migration 0003 (drop_column, alembic check vert)
- Loader de validation : toutes les affectations du bénévole comptent, plus de
  filtre par statut
- API : AssignmentCreate/Update/Read sans status ; création → validation
  toujours exécutée (blocage si violation bloquante) ; PATCH ne porte plus que
  source/locked
- Matrice : MatrixShift.{confirmed, proposed} → {assigned} (compte unique)
- Seed : affectations sans statut, résumé « Affectations » (260)
- Tests mis à jour (matrice, loader, modèle, API) ; 128 tests au total
- CLAUDE.md : glossaire, modèle, sémantique de validation, périmètre

Frontend : les références au statut (propositions, badges confirmé/proposé,
écran de confirmation mobile, mock, schema.ts) restent à retirer séparément.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017uUsRg7XzopkCPWimwg9ZM
2026-09-10 07:36:06 +02:00

71 lines
2.1 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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
],
)