mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
219 lines
9.5 KiB
Python
219 lines
9.5 KiB
Python
from django.http.response import JsonResponse
|
|
from rest_framework.views import APIView
|
|
from rest_framework import status
|
|
from drf_yasg.utils import swagger_auto_schema
|
|
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
|
|
from django.utils.decorators import method_decorator
|
|
from Subscriptions.models import StudentCompetency, Student
|
|
from Common.models import Domain
|
|
from Subscriptions.models import BilanCompetence
|
|
from datetime import date
|
|
from N3wtSchool.renderers import render_to_pdf
|
|
from django.core.files import File
|
|
from io import BytesIO
|
|
import os
|
|
import logging
|
|
from django.conf import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
@method_decorator(csrf_protect, name='dispatch')
|
|
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
|
class StudentCompetencyListCreateView(APIView):
|
|
def get(self, request):
|
|
student_id = request.GET.get('student_id')
|
|
period = request.GET.get('period')
|
|
if not student_id:
|
|
return JsonResponse({'error': 'student_id requis'}, status=400)
|
|
try:
|
|
student = Student.objects.get(id=student_id)
|
|
except Student.DoesNotExist:
|
|
return JsonResponse({'error': 'Élève introuvable'}, status=404)
|
|
|
|
# Filtrer par student ET period si period est fourni
|
|
filter_kwargs = {'student': student}
|
|
if period:
|
|
filter_kwargs['period'] = period
|
|
|
|
student_competencies = StudentCompetency.objects.filter(**filter_kwargs).select_related(
|
|
'establishment_competency',
|
|
'establishment_competency__competency',
|
|
'establishment_competency__competency__category',
|
|
'establishment_competency__competency__category__domain',
|
|
'establishment_competency__custom_category',
|
|
'establishment_competency__custom_category__domain',
|
|
)
|
|
|
|
result = []
|
|
total_competencies = 0
|
|
domaines = Domain.objects.all()
|
|
for domaine in domaines:
|
|
domaine_dict = {
|
|
"domaine_id": domaine.id,
|
|
"domaine_nom": domaine.name,
|
|
"categories": []
|
|
}
|
|
categories = domaine.categories.all()
|
|
for categorie in categories:
|
|
categorie_dict = {
|
|
"categorie_id": categorie.id,
|
|
"categorie_nom": categorie.name,
|
|
"competences": []
|
|
}
|
|
# On ne boucle que sur les compétences du student pour cette catégorie
|
|
for sc in student_competencies:
|
|
ec = sc.establishment_competency
|
|
# Cas compétence de référence
|
|
if ec.competency and ec.competency.category_id == categorie.id:
|
|
comp = ec.competency
|
|
categorie_dict["competences"].append({
|
|
"competence_id": ec.id, # <-- retourne l'id de l'EstablishmentCompetency
|
|
"nom": comp.name,
|
|
"score": sc.score,
|
|
"comment": sc.comment or "",
|
|
"period":sc.period or ""
|
|
})
|
|
total_competencies += 1
|
|
# Cas compétence custom
|
|
elif ec.competency is None and ec.custom_category_id == categorie.id:
|
|
categorie_dict["competences"].append({
|
|
"competence_id": ec.id, # <-- retourne l'id de l'EstablishmentCompetency
|
|
"nom": ec.custom_name,
|
|
"score": sc.score,
|
|
"comment": sc.comment or "",
|
|
"period":sc.period or ""
|
|
})
|
|
total_competencies += 1
|
|
if categorie_dict["competences"]:
|
|
domaine_dict["categories"].append(categorie_dict)
|
|
if domaine_dict["categories"]:
|
|
result.append(domaine_dict)
|
|
|
|
return JsonResponse({
|
|
"count": total_competencies,
|
|
"data": result
|
|
}, safe=False, status=200)
|
|
|
|
def put(self, request):
|
|
"""
|
|
Met à jour en masse les notes des compétences d'un élève.
|
|
Attend une liste d'objets {"competenceId": ..., "grade": ...}
|
|
"""
|
|
data = request.data
|
|
if not isinstance(data, list):
|
|
return JsonResponse({"error": "Une liste est attendue."}, status=400)
|
|
updated = []
|
|
errors = []
|
|
for item in data:
|
|
comp_id = item.get("competenceId")
|
|
grade = item.get("grade")
|
|
student_id = item.get('studentId')
|
|
period = item.get('period')
|
|
if comp_id is None or grade is None:
|
|
errors.append({"competenceId": comp_id, "error": "champ manquant"})
|
|
continue
|
|
try:
|
|
# Ajoute le filtre student_id
|
|
sc = StudentCompetency.objects.get(
|
|
establishment_competency_id=comp_id,
|
|
student_id=student_id,
|
|
period=period
|
|
)
|
|
sc.score = grade
|
|
sc.save()
|
|
updated.append(comp_id)
|
|
except StudentCompetency.DoesNotExist:
|
|
errors.append({"competenceId": comp_id, "error": "not found"})
|
|
|
|
# Génération du PDF si au moins une compétence a été mise à jour
|
|
if updated:
|
|
student = Student.objects.get(id=student_id)
|
|
# Reconstituer la structure "domaines" pour la période concernée uniquement
|
|
student_competencies = StudentCompetency.objects.filter(student=student, period=period).select_related(
|
|
'establishment_competency',
|
|
'establishment_competency__competency',
|
|
'establishment_competency__competency__category',
|
|
'establishment_competency__competency__category__domain',
|
|
'establishment_competency__custom_category',
|
|
'establishment_competency__custom_category__domain',
|
|
)
|
|
result = []
|
|
domaines = Domain.objects.all()
|
|
for domaine in domaines:
|
|
domaine_dict = {
|
|
"nom": domaine.name,
|
|
"categories": []
|
|
}
|
|
categories = domaine.categories.all()
|
|
for categorie in categories:
|
|
categorie_dict = {
|
|
"nom": categorie.name,
|
|
"competences": []
|
|
}
|
|
for sc in student_competencies:
|
|
ec = sc.establishment_competency
|
|
if ec.competency and ec.competency.category_id == categorie.id:
|
|
comp = ec.competency
|
|
categorie_dict["competences"].append({
|
|
"nom": comp.name,
|
|
"score": sc.score,
|
|
"comment": sc.comment or "",
|
|
})
|
|
elif ec.competency is None and ec.custom_category_id == categorie.id:
|
|
categorie_dict["competences"].append({
|
|
"nom": ec.custom_name,
|
|
"score": sc.score,
|
|
"comment": sc.comment or "",
|
|
})
|
|
if categorie_dict["competences"]:
|
|
domaine_dict["categories"].append(categorie_dict)
|
|
if domaine_dict["categories"]:
|
|
result.append(domaine_dict)
|
|
|
|
context = {
|
|
"student": {
|
|
"first_name": student.first_name,
|
|
"last_name": student.last_name,
|
|
"level": student.level,
|
|
"class_name": student.associated_class.atmosphere_name,
|
|
},
|
|
"period": period,
|
|
"date": date.today().strftime("%d/%m/%Y"),
|
|
"domaines": result,
|
|
}
|
|
|
|
pdf_result = render_to_pdf('pdfs/bilan_competences.html', context)
|
|
|
|
|
|
try:
|
|
filename = f"bilan_competences_{student.last_name}_{student.first_name}_{period}.pdf"
|
|
# Vérifier si un bilan existe déjà pour cet élève et cette période
|
|
existing_bilan = BilanCompetence.objects.filter(student=student, period=period).first()
|
|
if existing_bilan:
|
|
# Supprimer le fichier physique si présent
|
|
if existing_bilan.file and existing_bilan.file.name:
|
|
file_path = existing_bilan.file.path
|
|
if os.path.exists(file_path):
|
|
os.remove(file_path)
|
|
existing_bilan.delete()
|
|
|
|
bilan = BilanCompetence.objects.create(
|
|
student=student,
|
|
period=period
|
|
)
|
|
bilan.file.save(
|
|
os.path.basename(filename),
|
|
File(BytesIO(pdf_result.content)),
|
|
save=True
|
|
)
|
|
except Exception as e:
|
|
logger.error(f"Erreur lors de la sauvegarde du fichier PDF : {e}")
|
|
raise
|
|
|
|
return JsonResponse({"updated": updated, "errors": errors}, status=200)
|
|
|
|
@method_decorator(csrf_protect, name='dispatch')
|
|
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
|
class StudentCompetencySimpleView(APIView):
|
|
def get(self, request, id):
|
|
return JsonResponse("ok", safe=False, status=status.HTTP_200_OK) |