refactor: Utilisation d'une application "Common" pour tous les modèles

de référence
This commit is contained in:
N3WT DE COMPET
2025-05-18 15:42:21 +02:00
parent 7fe53465ac
commit e65e31014d
24 changed files with 491 additions and 277 deletions

View File

@ -4,7 +4,6 @@ from django.conf import settings
from django.utils.translation import gettext_lazy as _
from datetime import datetime
from School.models import PaymentModeType, PaymentPlanType
import os
@ -85,7 +84,7 @@ class Student(models.Model):
last_name = models.CharField(max_length=200, default="")
first_name = models.CharField(max_length=200, default="")
gender = models.IntegerField(choices=StudentGender, default=StudentGender.NONE, blank=True)
level = models.IntegerField(choices=StudentLevel, default=StudentLevel.NONE, blank=True)
level = models.ForeignKey('Common.Level', on_delete=models.SET_NULL, null=True, blank=True, related_name='students')
nationality = models.CharField(max_length=200, default="", blank=True)
address = models.CharField(max_length=200, default="", blank=True)
birth_date = models.DateField(null=True, blank=True)
@ -247,10 +246,10 @@ class RegistrationForm(models.Model):
blank=True)
establishment = models.ForeignKey('Establishment.Establishment', on_delete=models.CASCADE, related_name='register_forms')
registration_payment = models.ForeignKey('School.PaymentModeType', on_delete=models.SET_NULL, null=True, blank=True, related_name='registration_payment_modes_forms')
tuition_payment = models.ForeignKey('School.PaymentModeType', on_delete=models.SET_NULL, null=True, blank=True, related_name='tuition_payment_modes_forms')
registration_payment_plan = models.ForeignKey('School.PaymentPlanType', on_delete=models.SET_NULL, null=True, blank=True, related_name='registration_payment_plans_forms')
tuition_payment_plan = models.ForeignKey('School.PaymentPlanType', on_delete=models.SET_NULL, null=True, blank=True, related_name='tuition_payment_plans_forms')
registration_payment = models.ForeignKey('School.PaymentMode', on_delete=models.SET_NULL, null=True, blank=True, related_name='registration_payment_modes_forms')
tuition_payment = models.ForeignKey('School.PaymentMode', on_delete=models.SET_NULL, null=True, blank=True, related_name='tuition_payment_modes_forms')
registration_payment_plan = models.ForeignKey('School.PaymentPlan', on_delete=models.SET_NULL, null=True, blank=True, related_name='registration_payment_plans_forms')
tuition_payment_plan = models.ForeignKey('School.PaymentPlan', on_delete=models.SET_NULL, null=True, blank=True, related_name='tuition_payment_plans_forms')
def __str__(self):
return "RF_" + self.student.last_name + "_" + self.student.first_name
@ -323,6 +322,18 @@ class RegistrationSchoolFileTemplate(models.Model):
filenames.append(reg_file.file.path)
return filenames
class StudentCompetency(models.Model):
student = models.ForeignKey('Subscriptions.Student', on_delete=models.CASCADE, related_name='competency_scores')
competency = models.ForeignKey('Common.Competency', on_delete=models.CASCADE, related_name='student_scores')
score = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)
comment = models.TextField(blank=True, null=True)
class Meta:
unique_together = ('student', 'competency')
def __str__(self):
return f"{self.student} - {self.competency.name} - Score: {self.score}"
####### Parent files templates (par dossier d'inscription) #######
class RegistrationParentFileTemplate(models.Model):
master = models.ForeignKey(RegistrationParentFileMaster, on_delete=models.CASCADE, related_name='parent_file_templates', blank=True)

View File

@ -1,5 +1,17 @@
from rest_framework import serializers
from .models import RegistrationFileGroup, RegistrationForm, Student, Guardian, Sibling, Language, RegistrationSchoolFileMaster, RegistrationSchoolFileTemplate, RegistrationParentFileMaster, RegistrationParentFileTemplate, AbsenceManagement
from .models import (
RegistrationFileGroup,
RegistrationForm,
Student,
Guardian,
Sibling,
Language,
RegistrationSchoolFileMaster,
RegistrationSchoolFileTemplate,
RegistrationParentFileMaster,
RegistrationParentFileTemplate,
AbsenceManagement
)
from School.models import SchoolClass, Fee, Discount, FeeType
from School.serializers import FeeSerializer, DiscountSerializer
from Auth.models import ProfileRole, Profile
@ -406,15 +418,19 @@ class GuardianByDICreationSerializer(serializers.ModelSerializer):
class StudentByRFCreationSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
guardians = GuardianByDICreationSerializer(many=True, required=False)
associated_class_name = serializers.SerializerMethodField()
class Meta:
model = Student
fields = ['id', 'last_name', 'first_name', 'guardians', 'level']
fields = ['id', 'last_name', 'first_name', 'guardians', 'level', 'associated_class_name']
def __init__(self, *args, **kwargs):
super(StudentByRFCreationSerializer, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
def get_associated_class_name(self, obj):
return obj.associated_class.atmosphere_name if obj.associated_class else None
class NotificationSerializer(serializers.ModelSerializer):
notification_type_label = serializers.ReadOnlyField()

View File

@ -35,7 +35,10 @@ def getTuitionPaymentMethod(pk):
@register.filter
def getStudentLevel(pk):
registerForm = RegistrationForm.objects.get(student=pk)
return Student.StudentLevel(int(registerForm.student.level)).label
level = registerForm.student.level
if level:
return level.name
return ""
@register.filter
def getStudentGender(pk):

View File

@ -17,7 +17,9 @@ from .views import (
RegistrationParentFileTemplateSimpleView,
RegistrationParentFileTemplateView,
AbsenceManagementListCreateView,
AbsenceManagementDetailView
AbsenceManagementDetailView,
StudentCompetencyListCreateView,
StudentCompetencySimpleView
)
from .views import RegistrationFileGroupView, RegistrationFileGroupSimpleView, get_registration_files_by_group
@ -63,4 +65,7 @@ urlpatterns = [
re_path(r'^absences$', AbsenceManagementListCreateView.as_view(), name="absence_list_create"),
re_path(r'^absences/(?P<id>[0-9]+)$', AbsenceManagementDetailView.as_view(), name="absence_detail"),
re_path(r'^studentCompetencies$', StudentCompetencyListCreateView.as_view(), name="student_competency_list_create"),
re_path(r'^studentCompetencies/(?P<id>[0-9]+)$', StudentCompetencySimpleView.as_view(), name="student_competency_detail"),
]

View File

@ -13,6 +13,7 @@ from .registration_file_group_views import RegistrationFileGroupView, Registrati
from .student_views import StudentView, StudentListView, ChildrenListView
from .guardian_views import GuardianView, DissociateGuardianView
from .absences_views import AbsenceManagementDetailView, AbsenceManagementListCreateView
from .student_competencies_views import StudentCompetencyListCreateView, StudentCompetencySimpleView
__all__ = [
'RegisterFormView',
@ -39,5 +40,7 @@ __all__ = [
'GuardianView',
'DissociateGuardianView',
'AbsenceManagementDetailView',
'AbsenceManagementListCreateView'
'AbsenceManagementListCreateView',
'StudentCompetencyListCreateView',
'StudentCompetencySimpleView'
]

View File

@ -16,10 +16,22 @@ import Subscriptions.util as util
from Subscriptions.serializers import RegistrationFormSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileTemplateSerializer
from Subscriptions.pagination import CustomSubscriptionPagination
from Subscriptions.models import Student, Guardian, RegistrationForm, RegistrationSchoolFileTemplate, RegistrationFileGroup, RegistrationParentFileTemplate
from Subscriptions.models import (
Student,
Guardian,
RegistrationForm,
RegistrationSchoolFileTemplate,
RegistrationFileGroup,
RegistrationParentFileTemplate,
StudentCompetency
)
from Subscriptions.automate import updateStateMachine
from Common.models import Competency
from N3wtSchool import settings, bdd
from django.db.models import Q
import logging
logger = logging.getLogger(__name__)
@ -236,7 +248,6 @@ class RegisterFormWithIdView(APIView):
studentForm_data = request.data.get('data', '{}')
try:
data = json.loads(studentForm_data)
print(f'data : {data}')
except json.JSONDecodeError:
return JsonResponse({"error": "Invalid JSON format in 'data'"}, status=status.HTTP_400_BAD_REQUEST)
@ -366,6 +377,26 @@ class RegisterFormWithIdView(APIView):
save=True
)
# Valorisation des StudentCompetency pour l'élève
try:
student = registerForm.student
cycle = None
if student.level:
cycle = student.level.cycle.number
if cycle:
competencies = Competency.objects.filter(
category__domain__cycle=cycle
).filter(
Q(end_of_cycle=True) | Q(level=student.level.name)
)
for comp in competencies:
StudentCompetency.objects.get_or_create(
student=student,
competency=comp
)
except Exception as e:
logger.error(f"Erreur lors de la valorisation des StudentCompetency: {e}")
updateStateMachine(registerForm, 'EVENT_VALIDATE')
# Retourner les données mises à jour

View File

@ -0,0 +1,91 @@
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 drf_yasg import openapi
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, Competency
from N3wtSchool.bdd import delete_object
@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')
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)
student_competencies = StudentCompetency.objects.filter(student=student).select_related('competency', 'competency__category', 'competency__category__domain')
# On ne garde que les IDs des compétences de l'élève
student_competency_ids = set(sc.competency_id for sc in student_competencies)
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:
comp = sc.competency
if comp.category_id == categorie.id:
categorie_dict["competences"].append({
"competence_id": comp.id,
"nom": comp.name,
"score": sc.score,
"comment": sc.comment 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 post(self, request):
# serializer = AbsenceManagementSerializer(data=request.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 StudentCompetencySimpleView(APIView):
def get(self, request, id):
return JsonResponse("ok", safe=False, status=status.HTTP_200_OK)
# def put(self, request, id):
# try:
# absence = AbsenceManagement.objects.get(id=id)
# serializer = AbsenceManagementSerializer(absence, data=request.data)
# if serializer.is_valid():
# serializer.save()
# return JsonResponse(serializer.data, safe=False, status=status.HTTP_200_OK)
# return JsonResponse(serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
# except AbsenceManagement.DoesNotExist:
# return JsonResponse({"error": "Absence not found"}, safe=False, status=status.HTTP_404_NOT_FOUND)
# def delete(self, request, id):
# return delete_object(AbsenceManagement, id)