diff --git a/Back-End/Auth/views.py b/Back-End/Auth/views.py
index 8cd4fd3..1e0a876 100644
--- a/Back-End/Auth/views.py
+++ b/Back-End/Auth/views.py
@@ -223,7 +223,7 @@ def makeToken(user):
"""
try:
# Récupérer tous les rôles de l'utilisateur actifs
- roles = ProfileRole.objects.filter(profile=user, is_active=True).values('role_type', 'establishment__id', 'establishment__name')
+ roles = ProfileRole.objects.filter(profile=user, is_active=True).values('role_type', 'establishment__id', 'establishment__name', 'establishment__evaluation_frequency')
# Générer le JWT avec la bonne syntaxe datetime
access_payload = {
diff --git a/Back-End/Establishment/models.py b/Back-End/Establishment/models.py
index df5ad80..0440e0c 100644
--- a/Back-End/Establishment/models.py
+++ b/Back-End/Establishment/models.py
@@ -7,11 +7,17 @@ class StructureType(models.IntegerChoices):
PRIMAIRE = 2, _('Primaire')
SECONDAIRE = 3, _('Secondaire')
+class EvaluationFrequency(models.IntegerChoices):
+ TRIMESTER = 1, _("Trimestre")
+ SEMESTER = 2, _("Semestre")
+ YEAR = 3, _("Année")
+
class Establishment(models.Model):
name = models.CharField(max_length=255, unique=True)
address = models.CharField(max_length=255)
total_capacity = models.IntegerField()
establishment_type = ArrayField(models.IntegerField(choices=StructureType.choices))
+ evaluation_frequency = models.IntegerField(choices=EvaluationFrequency.choices, default=EvaluationFrequency.TRIMESTER)
licence_code = models.CharField(max_length=100, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
diff --git a/Back-End/Subscriptions/models.py b/Back-End/Subscriptions/models.py
index 8c5488d..4699d00 100644
--- a/Back-End/Subscriptions/models.py
+++ b/Back-End/Subscriptions/models.py
@@ -56,7 +56,23 @@ def registration_photo_upload_to(instance, filename):
return f"registration_files/dossier_rf_{instance.pk}/parent/{filename}"
def registration_bilan_form_upload_to(instance, filename):
- return f"registration_files/dossier_rf_{instance.pk}/bilan/{filename}"
+ # On récupère le RegistrationForm lié à l'élève
+ register_form = getattr(instance.student, 'registrationform', None)
+ if register_form:
+ pk = register_form.pk
+ else:
+ # fallback sur l'id de l'élève si pas de registrationform
+ pk = instance.student.pk
+ return f"registration_files/dossier_rf_{pk}/bilan/{filename}"
+
+class BilanCompetence(models.Model):
+ student = models.ForeignKey('Subscriptions.Student', on_delete=models.CASCADE, related_name='bilans')
+ file = models.FileField(upload_to=registration_bilan_form_upload_to, null=True, blank=True)
+ period = models.CharField(max_length=20, help_text="Période ex: T1-2024_2025, S1-2024_2025, A-2024_2025")
+ created_at = models.DateTimeField(auto_now_add=True)
+
+ def __str__(self):
+ return f"{self.student} - {self.period}"
class Student(models.Model):
"""
@@ -94,7 +110,6 @@ class Student(models.Model):
birth_place = models.CharField(max_length=200, default="", blank=True)
birth_postal_code = models.IntegerField(default=0, blank=True)
attending_physician = models.CharField(max_length=200, default="", blank=True)
- bilan_form = models.FileField(null=True,blank=True, upload_to=registration_bilan_form_upload_to)
# Many-to-Many Relationship
profiles = models.ManyToManyField('Auth.Profile', blank=True)
@@ -187,6 +202,15 @@ class Student(models.Model):
return self.birth_date.strftime('%d-%m-%Y')
return None
+class BilanCompetence(models.Model):
+ student = models.ForeignKey('Subscriptions.Student', on_delete=models.CASCADE, related_name='bilans')
+ file = models.FileField(upload_to=registration_bilan_form_upload_to, null=True, blank=True)
+ period = models.CharField(max_length=20, help_text="Période ex: T1-2024_2025, S1-2024_2025, A-2024_2025")
+ created_at = models.DateTimeField(auto_now_add=True)
+
+ def __str__(self):
+ return f"{self.student} - {self.period}"
+
class RegistrationFileGroup(models.Model):
name = models.CharField(max_length=255, default="")
description = models.TextField(blank=True, null=True)
@@ -331,16 +355,22 @@ class StudentCompetency(models.Model):
establishment_competency = models.ForeignKey('School.EstablishmentCompetency', on_delete=models.CASCADE, related_name='student_scores')
score = models.IntegerField(null=True, blank=True)
comment = models.TextField(blank=True, null=True)
+ period = models.CharField(
+ max_length=20,
+ help_text="Période d'évaluation ex: T1-2024_2025, S1-2024_2025, A-2024_2025",
+ default="",
+ blank=True
+ )
class Meta:
- unique_together = ('student', 'establishment_competency')
+ unique_together = ('student', 'establishment_competency', 'period')
indexes = [
- models.Index(fields=['student', 'establishment_competency']),
+ models.Index(fields=['student', 'establishment_competency', 'period']),
]
def __str__(self):
- return f"{self.student} - {self.establishment_competency} - Score: {self.score}"
+ return f"{self.student} - {self.establishment_competency} - Score: {self.score} - Period: {self.period}"
####### Parent files templates (par dossier d'inscription) #######
class RegistrationParentFileTemplate(models.Model):
diff --git a/Back-End/Subscriptions/serializers.py b/Back-End/Subscriptions/serializers.py
index a886840..ea4d524 100644
--- a/Back-End/Subscriptions/serializers.py
+++ b/Back-End/Subscriptions/serializers.py
@@ -10,18 +10,16 @@ from .models import (
RegistrationSchoolFileTemplate,
RegistrationParentFileMaster,
RegistrationParentFileTemplate,
- AbsenceManagement
+ AbsenceManagement,
+ BilanCompetence
)
from School.models import SchoolClass, Fee, Discount, FeeType
-from School.serializers import FeeSerializer, DiscountSerializer
from Auth.models import ProfileRole, Profile
from Auth.serializers import ProfileSerializer, ProfileRoleSerializer
-from GestionMessagerie.models import Messagerie
from GestionNotification.models import Notification
from N3wtSchool import settings
from django.utils import timezone
import pytz
-from datetime import datetime
import Subscriptions.util as util
class AbsenceManagementSerializer(serializers.ModelSerializer):
@@ -415,20 +413,26 @@ class GuardianByDICreationSerializer(serializers.ModelSerializer):
return obj.profile_role.profile.id # Retourne l'ID du profil associé
return None
+class BilanCompetenceSerializer(serializers.ModelSerializer):
+ class Meta:
+ model = BilanCompetence
+ fields = ['id', 'file', 'period', 'created_at']
+
class StudentByRFCreationSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
guardians = GuardianByDICreationSerializer(many=True, required=False)
associated_class_name = serializers.SerializerMethodField()
+ bilans = BilanCompetenceSerializer(many=True, read_only=True)
class Meta:
model = Student
- fields = ['id', 'last_name', 'first_name', 'guardians', 'level', 'associated_class_name', 'photo']
+ fields = ['id', 'last_name', 'first_name', 'guardians', 'level', 'associated_class_name', 'photo', 'bilans']
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
diff --git a/Back-End/Subscriptions/templates/pdfs/bilan_competences.html b/Back-End/Subscriptions/templates/pdfs/bilan_competences.html
index 13478c0..6e64148 100644
--- a/Back-End/Subscriptions/templates/pdfs/bilan_competences.html
+++ b/Back-End/Subscriptions/templates/pdfs/bilan_competences.html
@@ -33,6 +33,7 @@
Élève : {{ student.last_name }} {{ student.first_name }}
Niveau : {{ student.level }}
Classe : {{ student.class_name }}
+ Période : {{ period }}
Date : {{ date }}
@@ -70,5 +71,42 @@
{% endfor %}
+
+