170 lines
6.2 KiB
Python
170 lines
6.2 KiB
Python
"""
|
|
Repository pour la gestion des appréciations du conseil de classe.
|
|
"""
|
|
from typing import List, Optional
|
|
from sqlalchemy.orm import joinedload
|
|
from models import CouncilAppreciation, db
|
|
from repositories.base_repository import BaseRepository
|
|
|
|
|
|
class AppreciationRepository(BaseRepository[CouncilAppreciation]):
|
|
"""Repository pour les appréciations du conseil de classe."""
|
|
|
|
def __init__(self):
|
|
super().__init__(CouncilAppreciation)
|
|
|
|
def find_by_class_trimester(self, class_group_id: int, trimester: int) -> List[CouncilAppreciation]:
|
|
"""Trouve toutes les appréciations d'une classe pour un trimestre."""
|
|
return CouncilAppreciation.query.filter_by(
|
|
class_group_id=class_group_id,
|
|
trimester=trimester
|
|
).options(
|
|
joinedload(CouncilAppreciation.student),
|
|
joinedload(CouncilAppreciation.class_group)
|
|
).all()
|
|
|
|
def find_by_student_trimester(
|
|
self,
|
|
student_id: int,
|
|
class_group_id: int,
|
|
trimester: int
|
|
) -> Optional[CouncilAppreciation]:
|
|
"""Trouve l'appréciation d'un élève pour un trimestre."""
|
|
return CouncilAppreciation.query.filter_by(
|
|
student_id=student_id,
|
|
class_group_id=class_group_id,
|
|
trimester=trimester
|
|
).options(
|
|
joinedload(CouncilAppreciation.student),
|
|
joinedload(CouncilAppreciation.class_group)
|
|
).first()
|
|
|
|
def find_by_student_all_trimesters(
|
|
self,
|
|
student_id: int,
|
|
class_group_id: int
|
|
) -> List[CouncilAppreciation]:
|
|
"""Trouve toutes les appréciations d'un élève pour tous les trimestres."""
|
|
return CouncilAppreciation.query.filter_by(
|
|
student_id=student_id,
|
|
class_group_id=class_group_id
|
|
).options(
|
|
joinedload(CouncilAppreciation.student),
|
|
joinedload(CouncilAppreciation.class_group)
|
|
).order_by(CouncilAppreciation.trimester).all()
|
|
|
|
def count_with_content_by_class_trimester(
|
|
self,
|
|
class_group_id: int,
|
|
trimester: int
|
|
) -> int:
|
|
"""Compte le nombre d'appréciations avec contenu pour une classe/trimestre."""
|
|
return CouncilAppreciation.query.filter(
|
|
CouncilAppreciation.class_group_id == class_group_id,
|
|
CouncilAppreciation.trimester == trimester,
|
|
db.or_(
|
|
CouncilAppreciation.general_appreciation.isnot(None),
|
|
CouncilAppreciation.strengths.isnot(None),
|
|
CouncilAppreciation.areas_for_improvement.isnot(None)
|
|
)
|
|
).count()
|
|
|
|
def get_completion_stats(self, class_group_id: int, trimester: int) -> dict:
|
|
"""Statistiques de completion des appréciations pour une classe/trimestre."""
|
|
from models import Student
|
|
|
|
# Nombre total d'élèves dans la classe
|
|
total_students = Student.query.filter_by(class_group_id=class_group_id).count()
|
|
|
|
# Nombre d'appréciations existantes
|
|
total_appreciations = CouncilAppreciation.query.filter_by(
|
|
class_group_id=class_group_id,
|
|
trimester=trimester
|
|
).count()
|
|
|
|
# Nombre d'appréciations avec contenu
|
|
completed_appreciations = self.count_with_content_by_class_trimester(
|
|
class_group_id, trimester
|
|
)
|
|
|
|
# Nombre d'appréciations finalisées
|
|
finalized_appreciations = CouncilAppreciation.query.filter_by(
|
|
class_group_id=class_group_id,
|
|
trimester=trimester,
|
|
status='finalized'
|
|
).count()
|
|
|
|
return {
|
|
'total_students': total_students,
|
|
'total_appreciations': total_appreciations,
|
|
'completed_appreciations': completed_appreciations,
|
|
'finalized_appreciations': finalized_appreciations,
|
|
'completion_percentage': (completed_appreciations / total_students * 100) if total_students > 0 else 0,
|
|
'finalization_percentage': (finalized_appreciations / total_students * 100) if total_students > 0 else 0
|
|
}
|
|
|
|
def create_or_update(
|
|
self,
|
|
student_id: int,
|
|
class_group_id: int,
|
|
trimester: int,
|
|
data: dict
|
|
) -> CouncilAppreciation:
|
|
"""Crée ou met à jour une appréciation."""
|
|
existing = self.find_by_student_trimester(student_id, class_group_id, trimester)
|
|
|
|
if existing:
|
|
# Mise à jour
|
|
for key, value in data.items():
|
|
if hasattr(existing, key):
|
|
setattr(existing, key, value)
|
|
self.commit()
|
|
return existing
|
|
else:
|
|
# Création
|
|
appreciation_data = {
|
|
'student_id': student_id,
|
|
'class_group_id': class_group_id,
|
|
'trimester': trimester,
|
|
**data
|
|
}
|
|
appreciation = CouncilAppreciation(**appreciation_data)
|
|
self.save(appreciation)
|
|
self.commit()
|
|
return appreciation
|
|
|
|
def delete_by_student_trimester(
|
|
self,
|
|
student_id: int,
|
|
class_group_id: int,
|
|
trimester: int
|
|
) -> bool:
|
|
"""Supprime une appréciation spécifique."""
|
|
appreciation = self.find_by_student_trimester(student_id, class_group_id, trimester)
|
|
if appreciation:
|
|
self.delete(appreciation)
|
|
return True
|
|
return False
|
|
|
|
def get_students_without_appreciation(
|
|
self,
|
|
class_group_id: int,
|
|
trimester: int
|
|
) -> List:
|
|
"""Retourne la liste des élèves sans appréciation pour un trimestre."""
|
|
from models import Student
|
|
|
|
# Sous-requête pour les élèves qui ont déjà une appréciation
|
|
students_with_appreciation = db.session.query(CouncilAppreciation.student_id).filter_by(
|
|
class_group_id=class_group_id,
|
|
trimester=trimester
|
|
).subquery()
|
|
|
|
# Élèves sans appréciation
|
|
students_without = Student.query.filter_by(
|
|
class_group_id=class_group_id
|
|
).filter(
|
|
~Student.id.in_(students_with_appreciation)
|
|
).order_by(Student.last_name, Student.first_name).all()
|
|
|
|
return students_without |