166 lines
6.8 KiB
Python
166 lines
6.8 KiB
Python
from typing import List, Optional, Tuple
|
|
from datetime import date
|
|
from sqlalchemy import and_, or_
|
|
from models import db, Student, StudentEnrollment, Assessment
|
|
from repositories.base_repository import BaseRepository
|
|
|
|
|
|
class TemporalStudentRepository(BaseRepository[Student]):
|
|
"""Repository pour gérer les étudiants avec logique temporelle."""
|
|
|
|
def __init__(self):
|
|
super().__init__(Student)
|
|
|
|
def find_enrolled_in_class_at_date(self, class_group_id: int, check_date: date) -> List[Student]:
|
|
"""Trouve les étudiants inscrits dans une classe à une date donnée."""
|
|
from sqlalchemy import func
|
|
return db.session.query(Student)\
|
|
.join(StudentEnrollment)\
|
|
.filter(
|
|
StudentEnrollment.class_group_id == class_group_id,
|
|
StudentEnrollment.enrollment_date <= check_date,
|
|
or_(
|
|
StudentEnrollment.departure_date.is_(None),
|
|
StudentEnrollment.departure_date >= check_date
|
|
)
|
|
)\
|
|
.order_by(func.lower(Student.last_name), func.lower(Student.first_name))\
|
|
.all()
|
|
|
|
def find_eligible_for_assessment(self, assessment: Assessment) -> List[Student]:
|
|
"""Trouve les étudiants éligibles pour une évaluation donnée."""
|
|
if not assessment.date:
|
|
return []
|
|
|
|
return self.find_enrolled_in_class_at_date(assessment.class_group_id, assessment.date)
|
|
|
|
def find_current_students_in_class(self, class_group_id: int) -> List[Student]:
|
|
"""Trouve les étudiants actuellement inscrits dans une classe."""
|
|
from sqlalchemy import func
|
|
return db.session.query(Student)\
|
|
.join(StudentEnrollment)\
|
|
.filter(
|
|
StudentEnrollment.class_group_id == class_group_id,
|
|
StudentEnrollment.departure_date.is_(None)
|
|
)\
|
|
.order_by(func.lower(Student.last_name), func.lower(Student.first_name))\
|
|
.all()
|
|
|
|
def get_enrollment_history(self, student_id: int) -> List[StudentEnrollment]:
|
|
"""Récupère l'historique complet des inscriptions d'un élève."""
|
|
return StudentEnrollment.query\
|
|
.filter_by(student_id=student_id)\
|
|
.order_by(StudentEnrollment.enrollment_date.desc())\
|
|
.all()
|
|
|
|
def find_students_with_movements_in_period(self, start_date: date, end_date: date) -> List[Tuple[Student, List[StudentEnrollment]]]:
|
|
"""Trouve les étudiants qui ont eu des mouvements (arrivée/départ) dans une période avec leurs inscriptions."""
|
|
# Récupérer les étudiants qui ont eu des mouvements dans la période
|
|
students_with_movements = db.session.query(Student)\
|
|
.join(StudentEnrollment)\
|
|
.filter(
|
|
or_(
|
|
# Arrivées dans la période
|
|
and_(
|
|
StudentEnrollment.enrollment_date >= start_date,
|
|
StudentEnrollment.enrollment_date <= end_date
|
|
),
|
|
# Départs dans la période
|
|
and_(
|
|
StudentEnrollment.departure_date >= start_date,
|
|
StudentEnrollment.departure_date <= end_date
|
|
)
|
|
)
|
|
)\
|
|
.distinct()\
|
|
.order_by(Student.last_name, Student.first_name)\
|
|
.all()
|
|
|
|
# Pour chaque étudiant, récupérer ses mouvements dans la période
|
|
result = []
|
|
for student in students_with_movements:
|
|
movements = StudentEnrollment.query\
|
|
.filter_by(student_id=student.id)\
|
|
.filter(
|
|
or_(
|
|
# Arrivées dans la période
|
|
and_(
|
|
StudentEnrollment.enrollment_date >= start_date,
|
|
StudentEnrollment.enrollment_date <= end_date
|
|
),
|
|
# Départs dans la période
|
|
and_(
|
|
StudentEnrollment.departure_date >= start_date,
|
|
StudentEnrollment.departure_date <= end_date
|
|
)
|
|
)
|
|
)\
|
|
.order_by(StudentEnrollment.enrollment_date.desc())\
|
|
.all()
|
|
|
|
if movements:
|
|
result.append((student, movements))
|
|
|
|
return result
|
|
|
|
def create_enrollment(self, student_id: int, class_group_id: int,
|
|
enrollment_date: date, enrollment_reason: str = None) -> StudentEnrollment:
|
|
"""Crée une nouvelle inscription pour un élève."""
|
|
# Vérifier s'il y a déjà une inscription active
|
|
active_enrollment = StudentEnrollment.query.filter_by(
|
|
student_id=student_id,
|
|
departure_date=None
|
|
).first()
|
|
|
|
if active_enrollment:
|
|
raise ValueError("L'élève a déjà une inscription active")
|
|
|
|
# Créer la nouvelle inscription
|
|
enrollment = StudentEnrollment(
|
|
student_id=student_id,
|
|
class_group_id=class_group_id,
|
|
enrollment_date=enrollment_date,
|
|
enrollment_reason=enrollment_reason
|
|
)
|
|
|
|
db.session.add(enrollment)
|
|
return enrollment
|
|
|
|
def end_enrollment(self, student_id: int, departure_date: date,
|
|
departure_reason: str = None) -> Optional[StudentEnrollment]:
|
|
"""Termine l'inscription active d'un élève."""
|
|
active_enrollment = StudentEnrollment.query.filter_by(
|
|
student_id=student_id,
|
|
departure_date=None
|
|
).first()
|
|
|
|
if not active_enrollment:
|
|
return None
|
|
|
|
active_enrollment.departure_date = departure_date
|
|
active_enrollment.departure_reason = departure_reason
|
|
|
|
return active_enrollment
|
|
|
|
def transfer_student(self, student_id: int, new_class_group_id: int,
|
|
transfer_date: date, transfer_reason: str = None) -> tuple[StudentEnrollment, StudentEnrollment]:
|
|
"""Transfère un élève d'une classe à une autre."""
|
|
# Terminer l'inscription actuelle
|
|
old_enrollment = self.end_enrollment(
|
|
student_id,
|
|
transfer_date,
|
|
f"Transfert: {transfer_reason}" if transfer_reason else "Transfert"
|
|
)
|
|
|
|
if not old_enrollment:
|
|
raise ValueError("Aucune inscription active trouvée pour cet élève")
|
|
|
|
# Créer la nouvelle inscription
|
|
new_enrollment = self.create_enrollment(
|
|
student_id,
|
|
new_class_group_id,
|
|
transfer_date,
|
|
f"Transfert: {transfer_reason}" if transfer_reason else "Transfert"
|
|
)
|
|
|
|
return old_enrollment, new_enrollment |