feat: Sauvegarde des compétences d'un élève [#16]

This commit is contained in:
N3WT DE COMPET
2025-05-20 17:31:50 +02:00
parent c9c7e7715e
commit 05136035ab
19 changed files with 269 additions and 137 deletions

View File

@ -116,6 +116,22 @@ class PaymentMode(models.Model):
def __str__(self):
return f"{self.mode.label} - {self.get_type_display()}"
class Competency(models.Model):
name = models.TextField()
end_of_cycle = models.BooleanField(default=False, null=True, blank=True)
level = models.CharField(max_length=50, null=True, blank=True)
category = models.ForeignKey('Common.Category', on_delete=models.CASCADE, related_name='competencies')
establishments = models.ManyToManyField(
'Establishment.Establishment',
through='School.EstablishmentCompetency',
related_name='competencies',
blank=True
)
def __str__(self):
return self.name
class EstablishmentCompetency(models.Model):
"""
Relation entre un établissement et une compétence.
@ -123,7 +139,7 @@ class EstablishmentCompetency(models.Model):
"""
establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE)
competency = models.ForeignKey(
'Common.Competency', on_delete=models.CASCADE, null=True, blank=True,
'School.Competency', on_delete=models.CASCADE, null=True, blank=True,
help_text="Compétence de référence (optionnelle si custom)"
)
custom_name = models.TextField(null=True, blank=True, help_text="Nom de la compétence custom")

View File

@ -9,7 +9,8 @@ from .models import (
Fee,
PaymentPlan,
PaymentMode,
EstablishmentCompetency
EstablishmentCompetency,
Competency
)
from Auth.models import Profile, ProfileRole
from Subscriptions.models import Student
@ -19,6 +20,12 @@ from N3wtSchool import settings
from django.utils import timezone
import pytz
class CompetencySerializer(serializers.ModelSerializer):
class Meta:
model = Competency
fields = '__all__'
class EstablishmentCompetencySerializer(serializers.ModelSerializer):
class Meta:
model = EstablishmentCompetency

View File

@ -9,6 +9,7 @@ from .views import (
DiscountListCreateView, DiscountDetailView,
PaymentPlanListCreateView, PaymentPlanDetailView,
PaymentModeListCreateView, PaymentModeDetailView,
CompetencyListCreateView, CompetencyDetailView,
EstablishmentCompetencyListCreateView, EstablishmentCompetencyDetailView,
)
@ -37,6 +38,9 @@ urlpatterns = [
re_path(r'^paymentModes$', PaymentModeListCreateView.as_view(), name="payment_mode_list_create"),
re_path(r'^paymentModes/(?P<id>[0-9]+)$', PaymentModeDetailView.as_view(), name="payment_mode_detail"),
re_path(r'^competencies$', CompetencyListCreateView.as_view(), name="competency_list_create"),
re_path(r'^competencies/(?P<id>[0-9]+)$', CompetencyDetailView.as_view(), name="competency_detail"),
re_path(r'^establishmentCompetencies$', EstablishmentCompetencyListCreateView.as_view(), name="establishment_competency_list_create"),
re_path(r'^establishmentCompetencies/(?P<id>[0-9]+)$', EstablishmentCompetencyDetailView.as_view(), name="establishment_competency_detail"),
]

View File

@ -13,7 +13,8 @@ from .models import (
Fee,
PaymentPlan,
PaymentMode,
EstablishmentCompetency
EstablishmentCompetency,
Competency
)
from .serializers import (
TeacherSerializer,
@ -24,12 +25,14 @@ from .serializers import (
FeeSerializer,
PaymentPlanSerializer,
PaymentModeSerializer,
EstablishmentCompetencySerializer
EstablishmentCompetencySerializer,
CompetencySerializer
)
from Common.models import Domain, Category, Competency
from Common.models import Domain, Category
from N3wtSchool.bdd import delete_object, getAllObjects, getObject
from django.db.models import Q
from collections import defaultdict
from Subscriptions.models import Student, StudentCompetency
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
@ -417,6 +420,60 @@ class PaymentModeDetailView(APIView):
def delete(self, request, id):
return delete_object(PaymentMode, id)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class CompetencyListCreateView(APIView):
def get(self, request):
cycle = request.GET.get('cycle')
if cycle is None:
return JsonResponse({'error': 'cycle est requis'}, safe=False, status=status.HTTP_400_BAD_REQUEST)
competencies_list = getAllObjects(Competency)
competencies_list = competencies_list.filter(
category__domain__cycle=cycle
).distinct()
serializer = CompetencySerializer(competencies_list, many=True)
return JsonResponse(serializer.data, safe=False)
def post(self, request):
data = JSONParser().parse(request)
serializer = CompetencySerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, safe=False, status=status.HTTP_201_CREATED)
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class CompetencyDetailView(APIView):
def get(self, request, id):
try:
competency = Competency.objects.get(id=id)
serializer = CompetencySerializer(competency)
return JsonResponse(serializer.data, safe=False)
except Competency.DoesNotExist:
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
def put(self, request, id):
try:
competency = Competency.objects.get(id=id)
except Competency.DoesNotExist:
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
data = JSONParser().parse(request)
serializer = CompetencySerializer(competency, data=data, partial=True)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, safe=False)
return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, id):
try:
competency = Competency.objects.get(id=id)
competency.delete()
return JsonResponse({'message': 'Deleted'}, safe=False)
except Competency.DoesNotExist:
return JsonResponse({'error': 'No object found'}, status=status.HTTP_404_NOT_FOUND)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class EstablishmentCompetencyListCreateView(APIView):
@ -541,6 +598,14 @@ class EstablishmentCompetencyListCreateView(APIView):
custom_category=category,
is_required=False
)
# Associer à tous les élèves de l'établissement
students = Student.objects.filter(associated_class__establishment_id=establishment_id)
for student in students:
StudentCompetency.objects.get_or_create(
student=student,
establishment_competency=ec
)
created.append({
"competence_id": ec.id,
"nom": ec.custom_name,
@ -558,6 +623,7 @@ class EstablishmentCompetencyListCreateView(APIView):
def delete(self, request):
"""
Supprime une ou plusieurs compétences custom (EstablishmentCompetency) à partir d'une liste d'IDs.
Supprime aussi les StudentCompetency associés.
Attendu dans le body :
{
"ids": [1, 2, 3, ...]
@ -571,6 +637,8 @@ class EstablishmentCompetencyListCreateView(APIView):
for ec_id in ids:
try:
ec = EstablishmentCompetency.objects.get(id=ec_id)
# Supprimer les StudentCompetency associés
StudentCompetency.objects.filter(establishment_competency=ec).delete()
ec.delete()
deleted.append(ec_id)
except EstablishmentCompetency.DoesNotExist: