refactor: Traduction en anglais des modules "GestionInscription" et

"GestionLogin"
This commit is contained in:
N3WT DE COMPET
2025-01-12 10:07:06 +01:00
parent 830d9a48c0
commit 2b414b8391
69 changed files with 1393 additions and 1551 deletions

View File

@ -3,5 +3,5 @@ from django.db.models.signals import post_migrate
class GestionloginConfig(AppConfig): class GestionloginConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = 'django.db.models.BigAutoField'
name = 'GestionLogin' name = 'Auth'

View File

@ -1,20 +1,20 @@
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend from django.contrib.auth.backends import ModelBackend
from GestionLogin.models import Profil from Auth.models import Profile
from N3wtSchool import bdd from N3wtSchool import bdd
class EmailBackend(ModelBackend): class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs): def authenticate(self, request, username=None, password=None, **kwargs):
if username is None: if username is None:
username = kwargs.get(Profil.USERNAME_FIELD) username = kwargs.get(Profile.USERNAME_FIELD)
try: try:
user = Profil.objects.get(email=username) user = Profile.objects.get(email=username)
# Vérifie le mot de passe de l'utilisateur # Vérifie le mot de passe de l'utilisateur
if user.check_password(password): if user.check_password(password):
return user return user
except Profil.DoesNotExist: except Profile.DoesNotExist:
return None return None

View File

@ -3,7 +3,7 @@ from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.core.validators import EmailValidator from django.core.validators import EmailValidator
class Profil(AbstractUser): class Profile(AbstractUser):
class Droits(models.IntegerChoices): class Droits(models.IntegerChoices):
PROFIL_UNDEFINED = -1, _('NON DEFINI') PROFIL_UNDEFINED = -1, _('NON DEFINI')
PROFIL_ECOLE = 0, _('ECOLE') PROFIL_ECOLE = 0, _('ECOLE')

View File

@ -1,18 +1,18 @@
from rest_framework import serializers from rest_framework import serializers
from GestionLogin.models import Profil from Auth.models import Profile
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
class ProfilSerializer(serializers.ModelSerializer): class ProfileSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False) id = serializers.IntegerField(required=False)
password = serializers.CharField(write_only=True) password = serializers.CharField(write_only=True)
class Meta: class Meta:
model = Profil model = Profile
fields = ['id', 'password', 'email', 'code', 'datePeremption', 'estConnecte', 'droit', 'username', 'is_active'] fields = ['id', 'password', 'email', 'code', 'datePeremption', 'estConnecte', 'droit', 'username', 'is_active']
extra_kwargs = {'password': {'write_only': True}} extra_kwargs = {'password': {'write_only': True}}
def create(self, validated_data): def create(self, validated_data):
user = Profil( user = Profile(
username=validated_data['username'], username=validated_data['username'],
email=validated_data['email'], email=validated_data['email'],
is_active=validated_data['is_active'], is_active=validated_data['is_active'],
@ -29,7 +29,7 @@ class ProfilSerializer(serializers.ModelSerializer):
class ProfilUpdateSerializer(serializers.ModelSerializer): class ProfilUpdateSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Profil model = Profile
fields = ['id', 'password', 'email', 'code', 'datePeremption', 'estConnecte', 'droit', 'username', 'is_active'] fields = ['id', 'password', 'email', 'code', 'datePeremption', 'estConnecte', 'droit', 'username', 'is_active']
extra_kwargs = { extra_kwargs = {
'password': {'write_only': True, 'required': False} 'password': {'write_only': True, 'required': False}

22
Back-End/Auth/urls.py Normal file
View File

@ -0,0 +1,22 @@
from django.urls import path, re_path
from . import views
import Auth.views
from Auth.views import ProfileView, ProfileListView, SessionView, LoginView, SubscribeView, NewPasswordView, ResetPasswordView
urlpatterns = [
re_path(r'^csrf$', Auth.views.csrf, name='csrf'),
re_path(r'^login$', LoginView.as_view(), name="login"),
re_path(r'^subscribe$', SubscribeView.as_view(), name='subscribe'),
re_path(r'^newPassword$', NewPasswordView.as_view(), name='newPassword'),
re_path(r'^resetPassword/([a-zA-Z]+)$', ResetPasswordView.as_view(), name='resetPassword'),
re_path(r'^infoSession$', Auth.views.infoSession, name='infoSession'),
re_path(r'^profiles$', ProfileListView.as_view(), name="profile"),
re_path(r'^profile$', ProfileView.as_view(), name="profile"),
re_path(r'^profile/([0-9]+)$', ProfileView.as_view(), name="profile"),
# Test SESSION VIEW
re_path(r'^session$', SessionView.as_view(), name="session"),
]

View File

@ -15,13 +15,13 @@ import jwt
import json import json
from . import validator from . import validator
from .models import Profil from .models import Profile
from GestionLogin.serializers import ProfilSerializer, ProfilUpdateSerializer from Auth.serializers import ProfileSerializer, ProfilUpdateSerializer
from GestionInscriptions.models import FicheInscription from Subscriptions.models import RegistrationForm
from GestionInscriptions.signals import clear_cache from Subscriptions.signals import clear_cache
import GestionInscriptions.mailManager as mailer import Subscriptions.mailManager as mailer
import GestionInscriptions.util as util import Subscriptions.util as util
from N3wtSchool import bdd, error from N3wtSchool import bdd, error
@ -38,7 +38,7 @@ class SessionView(APIView):
decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256']) decoded_token = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
print(f'decode : {decoded_token}') print(f'decode : {decoded_token}')
user_id = decoded_token.get('id') user_id = decoded_token.get('id')
user = Profil.objects.get(id=user_id) user = Profile.objects.get(id=user_id)
response_data = { response_data = {
'user': { 'user': {
@ -53,24 +53,24 @@ class SessionView(APIView):
except jwt.InvalidTokenError: except jwt.InvalidTokenError:
return JsonResponse({"error": "Invalid token"}, status=status.HTTP_401_UNAUTHORIZED) return JsonResponse({"error": "Invalid token"}, status=status.HTTP_401_UNAUTHORIZED)
class ListProfilView(APIView): class ProfileListView(APIView):
def get(self, request): def get(self, request):
profilsList = bdd.getAllObjects(_objectName=Profil) profilsList = bdd.getAllObjects(_objectName=Profile)
profils_serializer = ProfilSerializer(profilsList, many=True) profils_serializer = ProfileSerializer(profilsList, many=True)
return JsonResponse(profils_serializer.data, safe=False) return JsonResponse(profils_serializer.data, safe=False)
@method_decorator(csrf_protect, name='dispatch') @method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch')
class ProfilView(APIView): class ProfileView(APIView):
def get(self, request, _id): def get(self, request, _id):
profil=bdd.getObject(Profil, "id", _id) profil=bdd.getObject(Profile, "id", _id)
profil_serializer=ProfilSerializer(profil) profil_serializer=ProfileSerializer(profil)
return JsonResponse(profil_serializer.data, safe=False) return JsonResponse(profil_serializer.data, safe=False)
def post(self, request): def post(self, request):
profil_data=JSONParser().parse(request) profil_data=JSONParser().parse(request)
print(f'{profil_data}') print(f'{profil_data}')
profil_serializer = ProfilSerializer(data=profil_data) profil_serializer = ProfileSerializer(data=profil_data)
if profil_serializer.is_valid(): if profil_serializer.is_valid():
profil_serializer.save() profil_serializer.save()
@ -82,7 +82,7 @@ class ProfilView(APIView):
def put(self, request, _id): def put(self, request, _id):
data=JSONParser().parse(request) data=JSONParser().parse(request)
profil = Profil.objects.get(id=_id) profil = Profile.objects.get(id=_id)
profil_serializer = ProfilUpdateSerializer(profil, data=data) profil_serializer = ProfilUpdateSerializer(profil, data=data)
if profil_serializer.is_valid(): if profil_serializer.is_valid():
profil_serializer.save() profil_serializer.save()
@ -95,7 +95,7 @@ def infoSession(request):
if profilCache: if profilCache:
return JsonResponse({"cacheSession":True,"typeProfil":profilCache.droit, "username":profilCache.email}, safe=False) return JsonResponse({"cacheSession":True,"typeProfil":profilCache.droit, "username":profilCache.email}, safe=False)
else: else:
return JsonResponse({"cacheSession":False,"typeProfil":Profil.Droits.PROFIL_UNDEFINED, "username":""}, safe=False) return JsonResponse({"cacheSession":False,"typeProfil":Profile.Droits.PROFIL_UNDEFINED, "username":""}, safe=False)
@method_decorator(csrf_protect, name='dispatch') @method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch')
@ -170,7 +170,7 @@ class SubscribeView(APIView):
if validationOk: if validationOk:
# On vérifie que l'email existe : si ce n'est pas le cas, on retourne une erreur # On vérifie que l'email existe : si ce n'est pas le cas, on retourne une erreur
profil = bdd.getProfile(Profil.objects.all(), newProfilConnection.get('email')) profil = bdd.getProfile(Profile.objects.all(), newProfilConnection.get('email'))
if profil == None: if profil == None:
retourErreur = error.returnMessage[error.PROFIL_NOT_EXISTS] retourErreur = error.returnMessage[error.PROFIL_NOT_EXISTS]
else: else:
@ -214,7 +214,7 @@ class NewPasswordView(APIView):
validationOk, errorFields = validatorNewPassword.validate() validationOk, errorFields = validatorNewPassword.validate()
if validationOk: if validationOk:
profil = bdd.getProfile(Profil.objects.all(), newProfilConnection.get('email')) profil = bdd.getProfile(Profile.objects.all(), newProfilConnection.get('email'))
if profil == None: if profil == None:
retourErreur = error.returnMessage[error.PROFIL_NOT_EXISTS] retourErreur = error.returnMessage[error.PROFIL_NOT_EXISTS]
else: else:
@ -247,7 +247,7 @@ class ResetPasswordView(APIView):
validatorResetPassword = validator.ValidatorResetPassword(data=newProfilConnection) validatorResetPassword = validator.ValidatorResetPassword(data=newProfilConnection)
validationOk, errorFields = validatorResetPassword.validate() validationOk, errorFields = validatorResetPassword.validate()
profil = bdd.getObject(Profil, "code", _uuid) profil = bdd.getObject(Profile, "code", _uuid)
if profil: if profil:
if datetime.strptime(util.convertToStr(util._now(), '%d-%m-%Y %H:%M'), '%d-%m-%Y %H:%M') > datetime.strptime(profil.datePeremption, '%d-%m-%Y %H:%M'): if datetime.strptime(util.convertToStr(util._now(), '%d-%m-%Y %H:%M'), '%d-%m-%Y %H:%M') > datetime.strptime(profil.datePeremption, '%d-%m-%Y %H:%M'):

View File

@ -1 +0,0 @@
default_app_config = 'GestionEnseignants.apps.GestionenseignantsConfig'

View File

@ -1,14 +0,0 @@
from django.apps import AppConfig
from django.db.models.signals import post_migrate
def create_specialite(sender, **kwargs):
from .models import Specialite
if not Specialite.objects.filter(nom='GROUPE').exists():
Specialite.objects.create(nom='GROUPE', codeCouleur='#FF0000')
class GestionenseignantsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'GestionEnseignants'
def ready(self):
post_migrate.connect(create_specialite, sender=self)

View File

@ -1,68 +0,0 @@
from django.db import models
from GestionLogin.models import Profil
from django.db.models import JSONField
from django.dispatch import receiver
from django.contrib.postgres.fields import ArrayField
NIVEAU_CHOICES = [
(1, 'Très Petite Section (TPS)'),
(2, 'Petite Section (PS)'),
(3, 'Moyenne Section (MS)'),
(4, 'Grande Section (GS)'),
(5, 'Cours Préparatoire (CP)'),
(6, 'Cours Élémentaire 1 (CE1)'),
(7, 'Cours Élémentaire 2 (CE2)'),
(8, 'Cours Moyen 1 (CM1)'),
(9, 'Cours Moyen 2 (CM2)')
]
class Specialite(models.Model):
nom = models.CharField(max_length=100)
dateCreation = models.DateTimeField(auto_now=True)
codeCouleur = models.CharField(max_length=7, default='#FFFFFF')
def __str__(self):
return self.nom
class Enseignant(models.Model):
nom = models.CharField(max_length=100)
prenom = models.CharField(max_length=100)
mail = models.EmailField(unique=True)
specialites = models.ManyToManyField(Specialite, related_name='enseignants')
profilAssocie = models.ForeignKey(Profil, on_delete=models.CASCADE, null=True, blank=True)
dateCreation = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.nom} {self.prenom}"
class Classe(models.Model):
PLANNING_TYPE_CHOICES = [
(1, 'Annuel'),
(2, 'Semestriel'),
(3, 'Trimestriel')
]
nom_ambiance = models.CharField(max_length=255, null=True, blank=True)
tranche_age = models.JSONField()
nombre_eleves = models.PositiveIntegerField()
langue_enseignement = models.CharField(max_length=255)
annee_scolaire = models.CharField(max_length=9)
dateCreation = models.DateTimeField(auto_now_add=True)
enseignants = models.ManyToManyField(Enseignant, related_name='classes')
niveaux = ArrayField(models.IntegerField(choices=NIVEAU_CHOICES), default=list)
type = models.IntegerField(choices=PLANNING_TYPE_CHOICES, default=1)
plage_horaire = models.JSONField(default=list)
jours_ouverture = ArrayField(models.IntegerField(), default=list)
def __str__(self):
return self.nom_ambiance
class Planning(models.Model):
niveau = models.IntegerField(choices=NIVEAU_CHOICES, null=True, blank=True)
classe = models.ForeignKey(Classe, null=True, blank=True, related_name='plannings', on_delete=models.CASCADE)
emploiDuTemps = JSONField(default=dict)
def __str__(self):
return f'Planning de {self.niveau} pour {self.classe.nom_ambiance}'

View File

@ -1,236 +0,0 @@
from rest_framework import serializers
from .models import Enseignant, Specialite, Classe, Planning, NIVEAU_CHOICES
from GestionInscriptions.models import FicheInscription
from GestionInscriptions.serializers import EleveSerializer
from GestionLogin.serializers import ProfilSerializer
from GestionLogin.models import Profil
from N3wtSchool import settings, bdd
from django.utils import timezone
import pytz
class SpecialiteSerializer(serializers.ModelSerializer):
dateCreation_formattee = serializers.SerializerMethodField()
class Meta:
model = Specialite
fields = '__all__'
def get_dateCreation_formattee(self, obj):
utc_time = timezone.localtime(obj.dateCreation) # Convertir en heure locale
local_tz = pytz.timezone(settings.TZ_APPLI)
local_time = utc_time.astimezone(local_tz)
return local_time.strftime("%d-%m-%Y %H:%M")
class EnseignantDetailSerializer(serializers.ModelSerializer):
specialites = SpecialiteSerializer(many=True, read_only=True)
class Meta:
model = Enseignant
fields = ['id', 'nom', 'prenom', 'mail', 'specialites']
class EnseignantSerializer(serializers.ModelSerializer):
specialites = SpecialiteSerializer(many=True, read_only=True)
specialites_ids = serializers.PrimaryKeyRelatedField(queryset=Specialite.objects.all(), many=True, source='specialites')
profilAssocie_id = serializers.PrimaryKeyRelatedField(queryset=Profil.objects.all(), source='profilAssocie', write_only=False, read_only=False)
classes_principal = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='classes')
profilAssocie = ProfilSerializer(read_only=True)
DroitLabel = serializers.SerializerMethodField()
DroitValue = serializers.SerializerMethodField()
dateCreation_formattee = serializers.SerializerMethodField()
class Meta:
model = Enseignant
fields = ['id', 'nom', 'prenom', 'mail', 'specialites', 'specialites_ids', 'classes_principal', 'profilAssocie', 'profilAssocie_id', 'DroitLabel', 'DroitValue', 'dateCreation', 'dateCreation_formattee']
def create(self, validated_data):
specialites_data = validated_data.pop('specialites', None)
profilAssocie = validated_data.pop('profilAssocie', None)
enseignant = Enseignant.objects.create(**validated_data)
enseignant.specialites.set(specialites_data)
if profilAssocie:
enseignant.profilAssocie = profilAssocie
enseignant.save()
return enseignant
def update(self, instance, validated_data):
specialites_data = validated_data.pop('specialites', [])
instance.nom = validated_data.get('nom', instance.nom)
instance.prenom = validated_data.get('prenom', instance.prenom)
instance.mail = validated_data.get('mail', instance.mail)
instance.profilAssocie = validated_data.get('profilAssocie', instance.profilAssocie)
instance.save()
instance.specialites.set(specialites_data)
return instance
def get_DroitLabel(self, obj):
return obj.profilAssocie.get_droit_display() if obj.profilAssocie else None
def get_DroitValue(self, obj):
return obj.profilAssocie.droit if obj.profilAssocie else None
def get_dateCreation_formattee(self, obj):
utc_time = timezone.localtime(obj.dateCreation) # Convertir en heure locale
local_tz = pytz.timezone(settings.TZ_APPLI)
local_time = utc_time.astimezone(local_tz)
return local_time.strftime("%d-%m-%Y %H:%M")
class PlanningSerializer(serializers.ModelSerializer):
# emploiDuTemps = serializers.SerializerMethodField()
class Meta:
model = Planning
fields = ['id', 'niveau', 'emploiDuTemps']
# def get_emploiDuTemps(self, obj):
# emploi_du_temps = obj.emploiDuTemps
# if obj.classe:
# enseignants = obj.classe.enseignants.all() # Récupérer tous les enseignants associés à la classe
# # Dictionnaire pour accéder rapidement aux spécialités des enseignants
# specialite_enseignants = {}
# for enseignant in enseignants:
# for specialite in enseignant.specialites.all():
# if specialite.nom not in specialite_enseignants:
# specialite_enseignants[specialite.nom] = []
# specialite_enseignants[specialite.nom].append(f"{enseignant.prenom} {enseignant.nom}")
# if obj.classe.type == 1: # Planning annuel
# for day, events in emploi_du_temps.items():
# for event in events:
# # Ajouter les enseignants associés à la spécialité
# event['teachers'] = specialite_enseignants.get(event['matiere'], [])
# # Ajouter la couleur de la spécialité
# event['color'] = next(
# (specialite.codeCouleur for enseignant in enseignants for specialite in enseignant.specialites.all() if specialite.nom == event['matiere']),
# "#FFFFFF" # Couleur par défaut si non trouvée
# )
# elif obj.classe.type in [2, 3]: # Planning semestriel ou trimestriel
# for period_key, period_value in emploi_du_temps.items():
# for day, events in period_value.items():
# if day in ['DateDebut', 'DateFin']:
# continue # Ignorer les clés DateDebut et DateFin
# for event in events:
# print(f'event : {event}')
# # Ajouter les enseignants associés à la spécialité
# event['teachers'] = specialite_enseignants.get(event['matiere'], [])
# # Ajouter la couleur de la spécialité
# event['color'] = next(
# (specialite.codeCouleur for enseignant in enseignants for specialite in enseignant.specialites.all() if specialite.nom == event['matiere']),
# "#FFFFFF" # Couleur par défaut si non trouvée
# )
# return emploi_du_temps
def to_internal_value(self, data):
internal_value = super().to_internal_value(data)
internal_value['emploiDuTemps'] = data.get('emploiDuTemps', {})
return internal_value
class ClasseSerializer(serializers.ModelSerializer):
dateCreation_formattee = serializers.SerializerMethodField()
enseignants = EnseignantSerializer(many=True, read_only=True)
enseignants_ids = serializers.PrimaryKeyRelatedField(queryset=Enseignant.objects.all(), many=True, source='enseignants')
eleves = serializers.SerializerMethodField()
niveaux = serializers.ListField(child=serializers.ChoiceField(choices=NIVEAU_CHOICES))
plannings_read = serializers.SerializerMethodField()
plannings = PlanningSerializer(many=True, write_only=True)
class Meta:
model = Classe
fields = [
'id', 'nom_ambiance', 'tranche_age', 'nombre_eleves', 'langue_enseignement',
'enseignants', 'enseignants_ids', 'annee_scolaire', 'dateCreation',
'dateCreation_formattee', 'eleves', 'niveaux', 'type', 'plage_horaire',
'jours_ouverture', 'plannings', 'plannings_read'
]
def create(self, validated_data):
enseignants_data = validated_data.pop('enseignants', [])
niveaux_data = validated_data.pop('niveaux', [])
plannings_data = validated_data.pop('plannings', [])
classe = Classe.objects.create(
nom_ambiance=validated_data.get('nom_ambiance', ''),
tranche_age=validated_data.get('tranche_age', []),
nombre_eleves=validated_data.get('nombre_eleves', 0),
langue_enseignement=validated_data.get('langue_enseignement', ''),
annee_scolaire=validated_data.get('annee_scolaire', ''),
niveaux=niveaux_data,
type=validated_data.get('type', 1), # Ajouté ici
plage_horaire=validated_data.get('plage_horaire', ['08:30', '17:30']), # Ajouté ici
jours_ouverture=validated_data.get('jours_ouverture', [1, 2, 4, 5]) # Ajouté ici
)
classe.enseignants.set(enseignants_data)
for planning_data in plannings_data:
Planning.objects.create(
classe=classe,
niveau=planning_data['niveau'],
emploiDuTemps=planning_data.get('emploiDuTemps', {})
)
return classe
def update(self, instance, validated_data):
enseignants_data = validated_data.pop('enseignants', [])
niveaux_data = validated_data.pop('niveaux', [])
plannings_data = validated_data.pop('plannings', [])
instance.nom_ambiance = validated_data.get('nom_ambiance', instance.nom_ambiance)
instance.tranche_age = validated_data.get('tranche_age', instance.tranche_age)
instance.nombre_eleves = validated_data.get('nombre_eleves', instance.nombre_eleves)
instance.langue_enseignement = validated_data.get('langue_enseignement', instance.langue_enseignement)
instance.annee_scolaire = validated_data.get('annee_scolaire', instance.annee_scolaire)
instance.niveaux = niveaux_data
instance.type = validated_data.get('type', instance.type) # Ajouté ici
instance.plage_horaire = validated_data.get('plage_horaire', instance.plage_horaire) # Ajouté ici
instance.jours_ouverture = validated_data.get('jours_ouverture', instance.jours_ouverture) # Ajouté ici
instance.save()
instance.enseignants.set(enseignants_data)
existing_plannings = {planning.niveau: planning for planning in instance.plannings.all()}
for planning_data in plannings_data:
niveau = planning_data['niveau']
if niveau in existing_plannings:
# Mettre à jour le planning existant
planning = existing_plannings[niveau]
planning.emploiDuTemps = planning_data.get('emploiDuTemps', planning.emploiDuTemps)
planning.save()
else:
# Créer un nouveau planning si niveau non existant
Planning.objects.create(
classe=instance,
niveau=niveau,
emploiDuTemps=planning_data.get('emploiDuTemps', {})
)
return instance
def get_dateCreation_formattee(self, obj):
utc_time = timezone.localtime(obj.dateCreation)
local_tz = pytz.timezone(settings.TZ_APPLI)
local_time = utc_time.astimezone(local_tz)
return local_time.strftime("%d-%m-%Y %H:%M")
def get_eleves(self, obj):
elevesList = obj.eleves.all()
filtered_eleves = []
for eleve in elevesList:
ficheInscription = bdd.getObject(FicheInscription, "eleve__id", eleve.id)
if ficheInscription.etat == ficheInscription.EtatDossierInscription.DI_VALIDE:
filtered_eleves.append(eleve)
return EleveSerializer(filtered_eleves, many=True, read_only=True).data
def get_plannings_read(self, obj):
plannings = obj.plannings.all()
niveaux_dict = {niveau: {'niveau': niveau, 'planning': None} for niveau in obj.niveaux}
for planning in plannings:
if planning.niveau in niveaux_dict:
niveaux_dict[planning.niveau]['planning'] = PlanningSerializer(planning).data
return list(niveaux_dict.values())

View File

@ -1,21 +0,0 @@
from django.urls import path, re_path
from GestionEnseignants.views import EnseignantsView, EnseignantView, SpecialitesView, SpecialiteView, ClassesView, ClasseView, PlanningsView, PlanningView
urlpatterns = [
re_path(r'^enseignants$', EnseignantsView.as_view(), name="enseignants"),
re_path(r'^enseignant$', EnseignantView.as_view(), name="enseignant"),
re_path(r'^enseignant/([0-9]+)$', EnseignantView.as_view(), name="enseignant"),
re_path(r'^specialites$', SpecialitesView.as_view(), name="specialites"),
re_path(r'^specialite$', SpecialiteView.as_view(), name="specialite"),
re_path(r'^specialite/([0-9]+)$', SpecialiteView.as_view(), name="specialite"),
re_path(r'^classes$', ClassesView.as_view(), name="classes"),
re_path(r'^classe$', ClasseView.as_view(), name="classe"),
re_path(r'^classe/([0-9]+)$', ClasseView.as_view(), name="classe"),
re_path(r'^plannings$', PlanningsView.as_view(), name="plannings"),
re_path(r'^planning$', PlanningView.as_view(), name="planning"),
re_path(r'^planning/([0-9]+)$', PlanningView.as_view(), name="planning"),
]

View File

@ -1 +0,0 @@
default_app_config = 'GestionInscriptions.apps.GestionInscriptionsConfig'

View File

@ -1,45 +0,0 @@
# state_machine.py
import json
from GestionInscriptions.models import FicheInscription
from GestionInscriptions.signals import clear_cache
state_mapping = {
"ABSENT": FicheInscription.EtatDossierInscription.DI_ABSENT,
"CREE": FicheInscription.EtatDossierInscription.DI_CREE,
"ENVOYE": FicheInscription.EtatDossierInscription.DI_ENVOYE,
"EN_VALIDATION": FicheInscription.EtatDossierInscription.DI_EN_VALIDATION,
"A_RELANCER": FicheInscription.EtatDossierInscription.DI_A_RELANCER,
"VALIDE": FicheInscription.EtatDossierInscription.DI_VALIDE,
"ARCHIVE": FicheInscription.EtatDossierInscription.DI_ARCHIVE
}
def load_config(config_file):
with open(config_file, 'r') as file:
config = json.load(file)
return config
def getStateMachineObject(etat) :
return Automate_DI_Inscription(etat)
def getStateMachineObjectState(etat):
return Automate_DI_Inscription(etat).state
def updateStateMachine(di, transition) :
automateModel = load_config('GestionInscriptions/Configuration/automate.json')
state_machine = getStateMachineObject(di.etat)
print(f'etat DI : {state_machine.state}')
if state_machine.trigger(transition, automateModel):
di.etat = state_machine.state
di.save()
clear_cache()
class Automate_DI_Inscription:
def __init__(self, initial_state):
self.state = initial_state
def trigger(self, transition_name, config):
for transition in config["transitions"]:
if transition["name"] == transition_name and self.state == state_mapping[transition["from"]]:
self.state = state_mapping[transition["to"]]
return True
return False

View File

@ -1,179 +0,0 @@
from django.db import models
from django.utils.timezone import now
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from GestionLogin.models import Profil
from GestionEnseignants.models import Classe
from datetime import datetime
class FraisInscription(models.Model):
class OptionsPaiements(models.IntegerChoices):
PAIEMENT_1_FOIS = 0, _('Paiement en une seule fois')
PAIEMENT_MENSUEL = 1, _('Paiement mensuel')
PAIEMENT_TRIMESTRIEL = 2, _('Paiement trimestriel')
nom = models.CharField(max_length=255, unique=True)
description = models.TextField(blank=True)
montant_de_base = models.DecimalField(max_digits=10, decimal_places=2)
reductions = models.JSONField(blank=True, null=True)
supplements = models.JSONField(blank=True, null=True)
date_debut_validite = models.DateField()
date_fin_validite = models.DateField()
options_paiement = models.IntegerField(choices=OptionsPaiements, default=OptionsPaiements.PAIEMENT_1_FOIS)
def __str__(self):
return self.nom
class Langue(models.Model):
id = models.AutoField(primary_key=True)
libelle = models.CharField(max_length=200, default="")
def __str__(self):
return "LANGUE"
class Responsable(models.Model):
nom = models.CharField(max_length=200, default="")
prenom = models.CharField(max_length=200, default="")
dateNaissance = models.CharField(max_length=200, default="", blank=True)
adresse = models.CharField(max_length=200, default="", blank=True)
mail = models.CharField(max_length=200, default="", blank=True)
telephone = models.CharField(max_length=200, default="", blank=True)
profession = models.CharField(max_length=200, default="", blank=True)
profilAssocie = models.ForeignKey(Profil, on_delete=models.CASCADE)
def __str__(self):
return self.nom + "_" + self.prenom
class Frere(models.Model):
id = models.AutoField(primary_key=True)
nom = models.CharField(max_length=200, default="")
prenom = models.CharField(max_length=200, default="")
dateNaissance = models.CharField(max_length=200, default="", blank=True)
def __str__(self):
return "FRERE"
class Eleve(models.Model):
class GenreEleve(models.IntegerChoices):
NONE = 0, _('Sélection du genre')
MALE = 1, _('Garçon')
FEMALE = 2, _('Fille')
class NiveauEleve(models.IntegerChoices):
NONE = 0, _('Sélection du niveau')
TPS = 1, _('TPS - Très Petite Section')
PS = 2, _('PS - Petite Section')
MS = 3, _('MS - Moyenne Section')
GS = 4, _('GS - Grande Section')
class ModePaiement(models.IntegerChoices):
NONE = 0, _('Sélection du mode de paiement')
PRELEVEMENT_SEPA = 1, _('Prélèvement SEPA')
CHEQUE = 2, _('Chèque')
nom = models.CharField(max_length=200, default="")
prenom = models.CharField(max_length=200, default="")
genre = models.IntegerField(choices=GenreEleve, default=GenreEleve.NONE, blank=True)
niveau = models.IntegerField(choices=NiveauEleve, default=NiveauEleve.NONE, blank=True)
nationalite = models.CharField(max_length=200, default="", blank=True)
adresse = models.CharField(max_length=200, default="", blank=True)
dateNaissance = models.DateField(null=True, blank=True)
lieuNaissance = models.CharField(max_length=200, default="", blank=True)
codePostalNaissance = models.IntegerField(default=0, blank=True)
medecinTraitant = models.CharField(max_length=200, default="", blank=True)
modePaiement = models.IntegerField(choices=ModePaiement, default=ModePaiement.NONE, blank=True)
# Relation N-N
profils = models.ManyToManyField(Profil, blank=True)
# Relation N-N
responsables = models.ManyToManyField(Responsable, blank=True)
# Relation N-N
freres = models.ManyToManyField(Frere, blank=True)
# Relation N-N
languesParlees = models.ManyToManyField(Langue, blank=True)
# Relation 1-N
classeAssociee = models.ForeignKey(Classe, on_delete=models.SET_NULL, null=True, blank=True, related_name='eleves')
def __str__(self):
return self.nom + "_" + self.prenom
def getLanguesParlees(self):
return self.languesParlees.all()
def getResponsablePrincipal(self):
return self.responsables.all()[0]
def getResponsables(self):
return self.responsables.all()
def getProfils(self):
return self.profils.all()
def getFreres(self):
return self.freres.all()
def getNbFreres(self):
return self.freres.count()
@property
def age(self):
if self.dateNaissance:
today = datetime.today()
years = today.year - self.dateNaissance.year
months = today.month - self.dateNaissance.month
if today.day < self.dateNaissance.day:
months -= 1
if months < 0:
years -= 1
months += 12
# Déterminer le format de l'âge
if months >= 6 and months <= 12:
return f"{years} ans 1/2"
else:
return f"{years} ans"
return None
@property
def dateNaissance_formattee(self):
if self.dateNaissance:
return self.dateNaissance.strftime('%d-%m-%Y')
return None
class FicheInscription(models.Model):
class EtatDossierInscription(models.IntegerChoices):
DI_ABSENT = 0, _('Pas de dossier d\'inscription')
DI_CREE = 1, _('Dossier d\'inscription créé')
DI_ENVOYE = 2, _('Dossier d\'inscription envoyé')
DI_EN_VALIDATION = 3, _('Dossier d\'inscription en cours de validation')
DI_A_RELANCER = 4, _('Dossier d\'inscription à relancer')
DI_VALIDE = 5, _('Dossier d\'inscription validé')
DI_ARCHIVE = 6, _('Dossier d\'inscription archivé')
# Relation 1-1
eleve = models.OneToOneField(Eleve, on_delete=models.CASCADE, primary_key=True)
etat = models.IntegerField(choices=EtatDossierInscription, default=EtatDossierInscription.DI_ABSENT)
dateMAJ = models.DateTimeField(auto_now=True)
notes = models.CharField(max_length=200, blank=True)
codeLienInscription = models.CharField(max_length=200, default="", blank=True)
fichierInscription = models.FileField(upload_to=settings.DOCUMENT_DIR, default="", blank=True)
di_associe = models.CharField(max_length=200, default="", blank=True)
def __str__(self):
return "FI_" + self.eleve.nom + "_" + self.eleve.prenom
class FichierInscription(models.Model):
name = models.CharField(max_length=255)
file = models.FileField(upload_to='fichiers_inscription/')
date_ajout = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.nom

View File

@ -1,202 +0,0 @@
from rest_framework import serializers
from GestionInscriptions.models import FichierInscription, FicheInscription, Eleve, Responsable, Frere, Langue, FraisInscription
from GestionEnseignants.models import Classe
from GestionLogin.models import Profil
from GestionLogin.serializers import ProfilSerializer
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
class FichierInscriptionSerializer(serializers.ModelSerializer):
class Meta:
model = FichierInscription
fields = '__all__'
class FraisInscriptionSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = FraisInscription
fields = '__all__'
class LanguesSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Langue
fields = '__all__'
class FrereSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Frere
fields = '__all__'
class ResponsableSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
profil_associe = serializers.SerializerMethodField()
class Meta:
model = Responsable
fields = '__all__'
def get_profil_associe(self, obj):
return obj.profilAssocie.email
class EleveSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
responsables = ResponsableSerializer(many=True, required=False)
freres = FrereSerializer(many=True, required=False)
langues = LanguesSerializer(many=True, required=False)
classeAssocie_id = serializers.PrimaryKeyRelatedField(queryset=Classe.objects.all(), source='classeAssociee', required=False, write_only=False, read_only=False)
age = serializers.SerializerMethodField()
dateNaissance_formattee = serializers.SerializerMethodField()
dateNaissance = serializers.DateField(input_formats=['%d-%m-%Y', '%Y-%m-%d'], required=False, allow_null=True)
classeAssocieeName = serializers.SerializerMethodField()
class Meta:
model = Eleve
fields = '__all__'
def get_or_create_packages(self, responsables_data):
responsables_ids = []
for responsable_data in responsables_data:
responsable_instance, created = Responsable.objects.get_or_create( id=responsable_data.get('id'),
defaults=responsable_data)
responsables_ids.append(responsable_instance.id)
return responsables_ids
def create(self, validated_data):
responsables_data = validated_data.pop('responsables', [])
freres_data = validated_data.pop('freres', [])
langues_data = validated_data.pop('languesParlees', [])
eleve = Eleve.objects.create(**validated_data)
eleve.responsables.set(self.get_or_create_packages(responsables_data))
eleve.freres.set(self.get_or_create_packages(freres_data))
eleve.languesParlees.set(self.get_or_create_packages(langues_data))
return eleve
def create_or_update_packages(self, responsables_data):
responsables_ids = []
for responsable_data in responsables_data:
responsable_instance, created = Responsable.objects.update_or_create( id=responsable_data.get('id'),
defaults=responsable_data)
responsables_ids.append(responsable_instance.id)
return responsables_ids
def update(self, instance, validated_data):
responsables_data = validated_data.pop('responsables', [])
freres_data = validated_data.pop('freres', [])
langues_data = validated_data.pop('languesParlees', [])
if responsables_data:
instance.responsables.set(self.create_or_update_packages(responsables_data))
if freres_data:
instance.freres.set(self.create_or_update_packages(freres_data))
if langues_data:
instance.freres.set(self.create_or_update_packages(langues_data))
for field in self.fields:
try:
setattr(instance, field, validated_data[field])
except KeyError:
pass
instance.save()
return instance
def get_age(self, obj):
return obj.age
def get_dateNaissance_formattee(self, obj):
return obj.dateNaissance_formattee
def get_classeAssocieeName(self, obj):
return obj.classeAssociee.nom_ambiance if obj.classeAssociee else None
class FicheInscriptionSerializer(serializers.ModelSerializer):
eleve = EleveSerializer(many=False, required=True)
fichierInscription = serializers.FileField(required=False)
etat_label = serializers.SerializerMethodField()
dateMAJ_formattee = serializers.SerializerMethodField()
class Meta:
model = FicheInscription
fields = '__all__'
def create(self, validated_data):
eleve_data = validated_data.pop('eleve')
eleve = EleveSerializer.create(EleveSerializer(), eleve_data)
ficheEleve = FicheInscription.objects.create(eleve=eleve, **validated_data)
return ficheEleve
def update(self, instance, validated_data):
eleve_data = validated_data.pop('eleve')
eleve = instance.eleve
eleve_serializer = EleveSerializer.update(EleveSerializer(), eleve, eleve_data)
for field in self.fields:
try:
setattr(instance, field, validated_data[field])
except KeyError:
pass
instance.save()
return instance
def get_etat_label(self, obj):
return obj.get_etat_display()
def get_dateMAJ_formattee(self, obj):
utc_time = timezone.localtime(obj.dateMAJ) # Convertir en heure locale
local_tz = pytz.timezone(settings.TZ_APPLI)
local_time = utc_time.astimezone(local_tz)
return local_time.strftime("%d-%m-%Y %H:%M")
class EleveByParentSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Eleve
fields = ['id', 'nom', 'prenom']
def __init__(self, *args, **kwargs):
super(EleveByParentSerializer , self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
class FicheInscriptionByParentSerializer(serializers.ModelSerializer):
eleve = EleveByParentSerializer(many=False, required=True)
class Meta:
model = FicheInscription
fields = ['eleve', 'etat']
def __init__(self, *args, **kwargs):
super(FicheInscriptionByParentSerializer, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
class ResponsableByDICreationSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Responsable
fields = ['id', 'nom', 'prenom', 'mail', 'profilAssocie']
class EleveByDICreationSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
responsables = ResponsableByDICreationSerializer(many=True, required=False)
class Meta:
model = Eleve
fields = ['id', 'nom', 'prenom', 'responsables']
def __init__(self, *args, **kwargs):
super(EleveByDICreationSerializer , self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
class NotificationSerializer(serializers.ModelSerializer):
typeNotification_label = serializers.ReadOnlyField()
class Meta:
model = Notification
fields = '__all__'

View File

@ -1,23 +0,0 @@
from GestionInscriptions.models import FicheInscription, Eleve
from django import template
register = template.Library()
# @register.filter
# def recupereFichiersDossierInscription(pk):
# fichiers_list = FicheInscription.objects.filter(fiche_inscription=pk)
# return fichiers_list
@register.filter
def recupereModePaiement(pk):
ficheInscription = FicheInscription.objects.get(eleve=pk)
return Eleve.ModePaiement(int(ficheInscription.eleve.modePaiement)).label
@register.filter
def recupereNiveauEleve(pk):
ficheInscription = FicheInscription.objects.get(eleve=pk)
return Eleve.NiveauEleve(int(ficheInscription.eleve.niveau)).label
@register.filter
def recupereGenreEleve(pk):
ficheInscription = FicheInscription.objects.get(eleve=pk)
return Eleve.GenreEleve(int(ficheInscription.eleve.genre)).label

View File

@ -1,36 +0,0 @@
from django.urls import path, re_path
from . import views
from GestionInscriptions.views import FichierInscriptionView, ListFichesInscriptionView, FicheInscriptionView, EleveView, ResponsableView, ListeEnfantsView, ListeElevesView, FraisInscriptionView
urlpatterns = [
re_path(r'^fichesInscription/([a-zA-z]+)$', ListFichesInscriptionView.as_view(), name="listefichesInscriptions"),
re_path(r'^ficheInscription$', FicheInscriptionView.as_view(), name="fichesInscriptions"),
re_path(r'^ficheInscription/([0-9]+)$', FicheInscriptionView.as_view(), name="fichesInscriptions"),
# Page de formulaire d'inscription - ELEVE
re_path(r'^eleve/([0-9]+)$', EleveView.as_view(), name="eleves"),
# Page de formulaire d'inscription - RESPONSABLE
re_path(r'^recupereDernierResponsable$', ResponsableView.as_view(), name="recupereDernierResponsable"),
# Envoi d'un dossier d'inscription
re_path(r'^send/([0-9]+)$', views.send, name="send"),
# Archivage d'un dossier d'inscription
re_path(r'^archive/([0-9]+)$', views.archive, name="archive"),
# Envoi d'une relance de dossier d'inscription
re_path(r'^sendRelance/([0-9]+)$', views.relance, name="relance"),
# Page PARENT - Liste des enfants
re_path(r'^enfants/([0-9]+)$', ListeEnfantsView.as_view(), name="enfants"),
# Page INSCRIPTION - Liste des élèves
re_path(r'^eleves$', ListeElevesView.as_view(), name="enfants"),
# Frais d'inscription
re_path(r'^tarifsInscription$', FraisInscriptionView.as_view(), name="fraisInscription"),
re_path(r'^fichiersInscription$', FichierInscriptionView.as_view(), name='fichiersInscription'),
re_path(r'^fichiersInscription/([0-9]+)$', FichierInscriptionView.as_view(), name="fichiersInscription"),
]

View File

@ -1,201 +0,0 @@
from django.shortcuts import render,get_object_or_404,get_list_or_404
from .models import FicheInscription, Eleve, Responsable, Frere
import time
from datetime import date, datetime, timedelta
from zoneinfo import ZoneInfo
from django.conf import settings
from N3wtSchool import renderers
from N3wtSchool import bdd
from io import BytesIO
from django.core.files import File
from pathlib import Path
import os
from enum import Enum
import random
import string
from rest_framework.parsers import JSONParser
def recupereListeFichesInscription():
context = {
"ficheInscriptions_list": bdd.getAllObjects(FicheInscription),
}
return context
def recupereListeFichesInscriptionEnAttenteSEPA():
ficheInscriptionsSEPA_list = FicheInscription.objects.filter(modePaiement="Prélèvement SEPA").filter(etat=FicheInscription.EtatDossierInscription['SEPA_ENVOYE'])
return ficheInscriptionsSEPA_list
def updateEleve(eleve, inputs, erase=False):
eleve.nom = inputs["nomEleve"]
eleve.prenom = inputs["prenomEleve"]
eleve.ambiance = inputs["ambiance"]
eleve.genre = inputs["genre"]
eleve.adresse = inputs["adresseEleve"]
eleve.dateNaissance = inputs["dateNaissanceEleve"]
eleve.lieuNaissance = inputs["lieuNaissanceEleve"]
eleve.codePostalNaissance = inputs["codePostalNaissanceEleve"]
eleve.nationalite = inputs["nationaliteEleve"]
eleve.medecinTraitant = inputs["medecinTraitantEleve"]
responsable=eleve.getResponsablePrincipal()
responsable.adresse = inputs["adresseResponsable1"]
responsable.dateNaissance = inputs["dateNaissanceResponsable1"]
responsable.profession = inputs["professionResponsable1"]
responsable.save()
# Création du 2ème responsable
if inputs["nomResponsable2"] != "" and inputs["prenomResponsable2"] != "":
responsable2 = Responsable.objects.create(nom=inputs["nomResponsable2"],
prenom=inputs["prenomResponsable2"],
dateNaissance=inputs["dateNaissanceResponsable2"],
adresse=inputs["adresseResponsable2"],
mail=inputs["mailResponsable2"],
telephone=inputs["telephoneResponsable2"],
profession=inputs["professionResponsable2"])
responsable2.save()
eleve.responsables.add(responsable2)
# Création du 1er frère
if inputs["nomFrere1"] != "" and inputs["prenomFrere1"] != "":
frere1 = Frere.objects.create(nom=inputs["nomFrere1"],
prenom=inputs["prenomFrere1"],
dateNaissance=inputs["dateNaissanceFrere1"])
frere1.save()
eleve.freres.add(frere1)
# Création du 2ème frère
if inputs["nomFrere2"] != "" and inputs["prenomFrere2"] != "":
frere2 = Frere.objects.create(nom=inputs["nomFrere2"],
prenom=inputs["prenomFrere2"],
dateNaissance=inputs["dateNaissanceFrere2"])
frere2.save()
eleve.freres.add(frere2)
eleve.save()
def _now():
return datetime.now(ZoneInfo(settings.TZ_APPLI))
def convertToStr(dateValue, dateFormat):
return dateValue.strftime(dateFormat)
def convertToDate(date_time):
format = '%d-%m-%Y %H:%M'
datetime_str = datetime.strptime(date_time, format)
return datetime_str
def convertTelephone(telephoneValue, separator='-'):
return f"{telephoneValue[:2]}{separator}{telephoneValue[2:4]}{separator}{telephoneValue[4:6]}{separator}{telephoneValue[6:8]}{separator}{telephoneValue[8:10]}"
def generePDF(ficheEleve):
data = {
'pdf_title': "Dossier d'inscription de %s"%ficheEleve.eleve.prenom,
'dateSignature': convertToStr(_now(), '%d-%m-%Y'),
'heureSignature': convertToStr(_now(), '%H:%M'),
'eleve':ficheEleve.eleve,
}
pdf = renderers.render_to_pdf('pdfs/dossier_inscription.html', data)
nomFichierPDF = "Dossier_Inscription_%s_%s.pdf"%(ficheEleve.eleve.nom, ficheEleve.eleve.prenom)
pathFichier = Path(settings.DOCUMENT_DIR + "/" + nomFichierPDF)
if os.path.exists(str(pathFichier)):
os.remove(str(pathFichier))
receipt_file = BytesIO(pdf.content)
# fichier = Fichier.objects.create(fiche_inscription=ficheEleve)
# fichier.document = File(receipt_file, nomFichierPDF)
# fichier.save()
def genereRandomCode(length):
return ''.join(random.choice(string.ascii_letters) for i in range(length))
def calculeDatePeremption(_start, nbDays):
return convertToStr(_start + timedelta(days=nbDays), settings.DATE_FORMAT)
# Fonction permettant de retourner la valeur du QueryDict
# QueryDict [ index ] -> Dernière valeur d'une liste
# dict (QueryDict [ index ]) -> Toutes les valeurs de la liste
def _(liste):
return liste[0]
def toNewEleveJSONRequest(jsonOrigin):
etat=FicheInscription.EtatDossierInscription.DI_CREE
telephone = convertTelephone(_(jsonOrigin['telephoneResponsable']))
finalJSON = {
"eleve":
{
"nom" : _(jsonOrigin['nomEleve']),
"prenom" : _(jsonOrigin['prenomEleve']),
"responsables" : [
{
"nom" : _(jsonOrigin['nomResponsable']),
"prenom" : _(jsonOrigin['prenomResponsable']),
"mail" : _(jsonOrigin['mailResponsable']),
"telephone" : telephone
}
],
"profils" : [
],
},
"etat": str(etat),
"dateMAJ": str(convertToStr(_now(), '%d-%m-%Y %H:%M')),
}
print(finalJSON)
return finalJSON
def toEditEleveJSONRequest(jsonOrigin):
telephone = convertTelephone(_(jsonOrigin['telephoneResponsable']), '.')
finalJSON = {
"eleve":
{
"id" : _(jsonOrigin['fiche_id']),
"nom" : _(jsonOrigin['nomEleve']),
"prenom" : _(jsonOrigin['prenomEleve']),
"responsables" : [
{
"id" : _(jsonOrigin['responsable_id']),
"nom" : _(jsonOrigin['nomResponsable']),
"prenom" : _(jsonOrigin['prenomResponsable']),
"mail" : _(jsonOrigin['mailResponsable']),
"telephone" : telephone
}
],
"profils" : [
],
},
"dateMAJ": str(convertToStr(_now(), '%d-%m-%Y %H:%M')),
}
print(finalJSON)
return finalJSON
def getArgFromRequest(_argument, _request):
resultat = None
data=JSONParser().parse(_request)
resultat = data[_argument]
return resultat
def diToPDF(ficheEleve):
# Ajout du fichier d'inscriptions
data = {
'pdf_title': "Dossier d'inscription de %s"%ficheEleve.eleve.prenom,
'dateSignature': convertToStr(_now(), '%d-%m-%Y'),
'heureSignature': convertToStr(_now(), '%H:%M'),
'eleve':ficheEleve.eleve,
}
pdf = renderers.render_to_pdf('pdfs/dossier_inscription.html', data)
nomFichierPDF = "Dossier_Inscription_%s_%s.pdf"%(ficheEleve.eleve.nom, ficheEleve.eleve.prenom)
pathFichier = Path(settings.DOCUMENT_DIR + "/" + nomFichierPDF)
if os.path.exists(str(pathFichier)):
print(f'File exists : {str(pathFichier)}')
os.remove(str(pathFichier))
receipt_file = BytesIO(pdf.content)
ficheEleve.fichierInscription = File(receipt_file, nomFichierPDF)

View File

@ -1,282 +0,0 @@
from django.http.response import JsonResponse
from django.contrib.auth import login, authenticate, get_user_model
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
from django.utils.decorators import method_decorator
from django.core.cache import cache
from django.core.paginator import Paginator
from django.core.files import File
from django.db.models import Q # Ajout de cet import
from rest_framework.parsers import JSONParser,MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
import json
from pathlib import Path
import os
from io import BytesIO
import GestionInscriptions.mailManager as mailer
import GestionInscriptions.util as util
from GestionInscriptions.serializers import FichierInscriptionSerializer, FicheInscriptionSerializer, EleveSerializer, FicheInscriptionByParentSerializer, EleveByDICreationSerializer, FraisInscriptionSerializer
from GestionInscriptions.pagination import CustomPagination
from GestionInscriptions.signals import clear_cache
from .models import Eleve, Responsable, FicheInscription, FraisInscription, FichierInscription
from GestionInscriptions.automate import Automate_DI_Inscription, load_config, getStateMachineObjectState, updateStateMachine
from GestionLogin.models import Profil
from N3wtSchool import settings, renderers, bdd
class ListFichesInscriptionView(APIView):
pagination_class = CustomPagination
def get_fiche_inscriptions(self, _filter, search=None):
"""
Récupère les fiches d'inscriptions en fonction du filtre passé.
_filter: Filtre pour déterminer l'état des fiches ('pending', 'archived', 'subscribed')
search: Terme de recherche (optionnel)
"""
if _filter == 'pending':
exclude_states = [FicheInscription.EtatDossierInscription.DI_VALIDE, FicheInscription.EtatDossierInscription.DI_ARCHIVE]
return bdd.searchObjects(FicheInscription, search, _excludeStates=exclude_states)
elif _filter == 'archived':
return bdd.getObjects(FicheInscription, 'etat', FicheInscription.EtatDossierInscription.DI_ARCHIVE)
elif _filter == 'subscribed':
return bdd.getObjects(FicheInscription, 'etat', FicheInscription.EtatDossierInscription.DI_VALIDE)
return None
def get(self, request, _filter):
# Récupération des paramètres
search = request.GET.get('search', '').strip()
page_size = request.GET.get('page_size', None)
# Gestion du page_size
if page_size is not None:
try:
page_size = int(page_size)
except ValueError:
page_size = settings.NB_RESULT_PER_PAGE
# Définir le cache_key en fonction du filtre
page_number = request.GET.get('page', 1)
cache_key = f'N3WT_ficheInscriptions_{_filter}_page_{page_number}_search_{search if _filter == "pending" else ""}'
cached_page = cache.get(cache_key)
if cached_page:
return JsonResponse(cached_page, safe=False)
# Récupérer les fiches d'inscriptions en fonction du filtre
ficheInscriptions_List = self.get_fiche_inscriptions(_filter, search)
if not ficheInscriptions_List:
return JsonResponse({'error' : 'aucune donnée trouvée', 'count' :0}, safe=False)
# Pagination
paginator = self.pagination_class()
page = paginator.paginate_queryset(ficheInscriptions_List, request)
if page is not None:
ficheInscriptions_serializer = FicheInscriptionSerializer(page, many=True)
response_data = paginator.get_paginated_response(ficheInscriptions_serializer.data)
cache.set(cache_key, response_data, timeout=60*15)
return JsonResponse(response_data, safe=False)
return JsonResponse({'error' : 'aucune donnée trouvée', 'count' :0}, safe=False)
def post(self, request):
fichesEleve_data=JSONParser().parse(request)
for ficheEleve_data in fichesEleve_data:
# Ajout de la date de mise à jour
ficheEleve_data["dateMAJ"] = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
json.dumps(ficheEleve_data)
# Ajout du code d'inscription
code = util.genereRandomCode(12)
ficheEleve_data["codeLienInscription"] = code
ficheEleve_serializer = FicheInscriptionSerializer(data=ficheEleve_data)
if ficheEleve_serializer.is_valid():
ficheEleve_serializer.save()
return JsonResponse(ficheEleve_serializer.errors, safe=False)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class FicheInscriptionView(APIView):
pagination_class = CustomPagination
def get(self, request, _id):
ficheInscription=bdd.getObject(FicheInscription, "eleve__id", _id)
fiche_serializer=FicheInscriptionSerializer(ficheInscription)
return JsonResponse(fiche_serializer.data, safe=False)
def post(self, request):
ficheEleve_data=JSONParser().parse(request)
# Ajout de la date de mise à jour
ficheEleve_data["dateMAJ"] = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
json.dumps(ficheEleve_data)
# Ajout du code d'inscription
code = util.genereRandomCode(12)
ficheEleve_data["codeLienInscription"] = code
responsablesId = ficheEleve_data.pop('idResponsables', [])
ficheEleve_serializer = FicheInscriptionSerializer(data=ficheEleve_data)
if ficheEleve_serializer.is_valid():
di = ficheEleve_serializer.save()
# Mise à jour de l'automate
updateStateMachine(di, 'creationDI')
# Récupération du reponsable associé
for responsableId in responsablesId:
responsable = Responsable.objects.get(id=responsableId)
di.eleve.responsables.add(responsable)
di.save()
return JsonResponse(ficheEleve_serializer.data, safe=False)
return JsonResponse(ficheEleve_serializer.errors, safe=False)
def put(self, request, id):
ficheEleve_data=JSONParser().parse(request)
etat = ficheEleve_data.pop('etat', 0)
ficheEleve_data["dateMAJ"] = str(util.convertToStr(util._now(), '%d-%m-%Y %H:%M'))
ficheEleve = bdd.getObject(_objectName=FicheInscription, _columnName='eleve__id', _value=id)
if etat == FicheInscription.EtatDossierInscription.DI_EN_VALIDATION:
# Le parent a complété le dossier d'inscription, il est soumis à validation par l'école
print('EN VALIDATION')
json.dumps(ficheEleve_data)
util.diToPDF(ficheEleve)
# Mise à jour de l'automate
updateStateMachine(ficheEleve, 'saisiDI')
elif etat == FicheInscription.EtatDossierInscription.DI_VALIDE:
# L'école a validé le dossier d'inscription
# Mise à jour de l'automate
print('VALIDATION')
updateStateMachine(ficheEleve, 'valideDI')
ficheEleve_serializer = FicheInscriptionSerializer(ficheEleve, data=ficheEleve_data)
if ficheEleve_serializer.is_valid():
ficheEleve_serializer.save()
return JsonResponse(ficheEleve_serializer.data, safe=False)
return JsonResponse(ficheEleve_serializer.errors, safe=False)
def delete(self, request, id):
fiche_inscription = bdd.getObject(_objectName=FicheInscription, _columnName='eleve__id', _value=id)
if fiche_inscription != None:
eleve = fiche_inscription.eleve
eleve.responsables.clear()
eleve.profils.clear()
eleve.delete()
clear_cache()
return JsonResponse("La suppression du dossier a été effectuée avec succès", safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False)
class EleveView(APIView):
def get(self, request, _id):
eleve = bdd.getObject(_objectName=Eleve, _columnName='id', _value=_id)
eleve_serializer = EleveSerializer(eleve)
return JsonResponse(eleve_serializer.data, safe=False)
class ResponsableView(APIView):
def get(self, request):
lastResponsable = bdd.getLastId(Responsable)
return JsonResponse({"lastid":lastResponsable}, safe=False)
def send(request, id):
fiche_inscription = bdd.getObject(_objectName=FicheInscription, _columnName='eleve__id', _value=id)
if fiche_inscription != None:
eleve = fiche_inscription.eleve
responsable = eleve.getResponsablePrincipal()
mail = responsable.mail
errorMessage = mailer.envoieDossierInscription(mail)
if errorMessage == '':
fiche_inscription.dateMAJ=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
# Mise à jour de l'automate
updateStateMachine(fiche_inscription, 'envoiDI')
return JsonResponse({"errorMessage":errorMessage}, safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False)
def archive(request, id):
fiche_inscription = bdd.getObject(_objectName=FicheInscription, _columnName='eleve__id', _value=id)
if fiche_inscription != None:
fiche_inscription.dateMAJ=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
# Mise à jour de l'automate
updateStateMachine(fiche_inscription, 'archiveDI')
return JsonResponse({"errorMessage":''}, safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False)
def relance(request, id):
fiche_inscription = bdd.getObject(_objectName=FicheInscription, _columnName='eleve__id', _value=id)
if fiche_inscription != None:
eleve = fiche_inscription.eleve
responsable = eleve.getResponsablePrincipal()
mail = responsable.mail
errorMessage = mailer.envoieRelanceDossierInscription(mail, fiche_inscription.codeLienInscription)
if errorMessage == '':
fiche_inscription.etat=FicheInscription.EtatDossierInscription.DI_ENVOYE
fiche_inscription.dateMAJ=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
fiche_inscription.save()
return JsonResponse({"errorMessage":errorMessage}, safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False)
# API utilisée pour la vue parent
class ListeEnfantsView(APIView):
# Récupération des élèves d'un parent
# idProfile : identifiant du profil connecté rattaché aux fiches d'élèves
def get(self, request, _idProfile):
students = bdd.getObjects(_objectName=FicheInscription, _columnName='eleve__responsables__profilAssocie__id', _value=_idProfile)
students_serializer = FicheInscriptionByParentSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)
# API utilisée pour la vue de création d'un DI
class ListeElevesView(APIView):
# Récupération de la liste des élèves inscrits ou en cours d'inscriptions
def get(self, request):
students = bdd.getAllObjects(_objectName=Eleve)
students_serializer = EleveByDICreationSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)
# API utilisée pour la vue de personnalisation des frais d'inscription pour la structure
class FraisInscriptionView(APIView):
def get(self, request):
tarifs = bdd.getAllObjects(FraisInscription)
tarifs_serializer = FraisInscriptionSerializer(tarifs, many=True)
return JsonResponse(tarifs_serializer.data, safe=False)
class FichierInscriptionView(APIView):
parser_classes = (MultiPartParser, FormParser)
def get(self, request):
fichiers = FichierInscription.objects.all()
serializer = FichierInscriptionSerializer(fichiers, many=True)
return Response(serializer.data)
def post(self, request):
serializer = FichierInscriptionSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, _id):
fichierInscription = bdd.getObject(_objectName=FichierInscription, _columnName='id', _value=_id)
if fichierInscription is not None:
fichierInscription.file.delete() # Supprimer le fichier uploadé
fichierInscription.delete()
return JsonResponse({'message': 'La suppression du fichier d\'inscription a été effectuée avec succès'}, safe=False)
else:
return JsonResponse({'erreur': 'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False)

View File

@ -1,22 +0,0 @@
from django.urls import path, re_path
from . import views
import GestionLogin.views
from GestionLogin.views import ProfilView, ListProfilView, SessionView, LoginView, SubscribeView, NewPasswordView, ResetPasswordView
urlpatterns = [
re_path(r'^csrf$', GestionLogin.views.csrf, name='csrf'),
re_path(r'^login$', LoginView.as_view(), name="login"),
re_path(r'^subscribe$', SubscribeView.as_view(), name='subscribe'),
re_path(r'^newPassword$', NewPasswordView.as_view(), name='newPassword'),
re_path(r'^resetPassword/([a-zA-Z]+)$', ResetPasswordView.as_view(), name='resetPassword'),
re_path(r'^infoSession$', GestionLogin.views.infoSession, name='infoSession'),
re_path(r'^profils$', ListProfilView.as_view(), name="profil"),
re_path(r'^profil$', ProfilView.as_view(), name="profil"),
re_path(r'^profil/([0-9]+)$', ProfilView.as_view(), name="profil"),
# Test SESSION VIEW
re_path(r'^session$', SessionView.as_view(), name="session"),
]

View File

@ -2,13 +2,13 @@ from django.contrib.auth.models import AbstractUser
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.conf import settings from django.conf import settings
from GestionLogin.models import Profil from Auth.models import Profile
class Messagerie(models.Model): class Messagerie(models.Model):
id = models.AutoField(primary_key=True) id = models.AutoField(primary_key=True)
objet = models.CharField(max_length=200, default="", blank=True) objet = models.CharField(max_length=200, default="", blank=True)
emetteur = models.ForeignKey(Profil, on_delete=models.PROTECT, related_name='messages_envoyes') emetteur = models.ForeignKey(Profile, on_delete=models.PROTECT, related_name='messages_envoyes')
destinataire = models.ForeignKey(Profil, on_delete=models.PROTECT, related_name='messages_recus') destinataire = models.ForeignKey(Profile, on_delete=models.PROTECT, related_name='messages_recus')
corpus = models.CharField(max_length=200, default="", blank=True) corpus = models.CharField(max_length=200, default="", blank=True)
def __str__(self): def __str__(self):

View File

@ -1,5 +1,5 @@
from rest_framework import serializers from rest_framework import serializers
from GestionLogin.models import Profil from Auth.models import Profile
from GestionMessagerie.models import Messagerie from GestionMessagerie.models import Messagerie
class MessageSerializer(serializers.ModelSerializer): class MessageSerializer(serializers.ModelSerializer):

View File

@ -2,7 +2,7 @@ from django.contrib.auth.models import AbstractUser
from django.db import models from django.db import models
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.conf import settings from django.conf import settings
from GestionLogin.models import Profil from Auth.models import Profile
class TypeNotif(models.IntegerChoices): class TypeNotif(models.IntegerChoices):
NOTIF_NONE = 0, _('Aucune notification') NOTIF_NONE = 0, _('Aucune notification')
@ -10,7 +10,7 @@ class TypeNotif(models.IntegerChoices):
NOTIF_DI = 2, _('Le dossier d\'inscription a été mis à jour') NOTIF_DI = 2, _('Le dossier d\'inscription a été mis à jour')
class Notification(models.Model): class Notification(models.Model):
user = models.ForeignKey(Profil, on_delete=models.PROTECT) user = models.ForeignKey(Profile, on_delete=models.PROTECT)
message = models.CharField(max_length=255) message = models.CharField(max_length=255)
is_read = models.BooleanField(default=False) is_read = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True) created_at = models.DateTimeField(auto_now_add=True)

View File

@ -2,7 +2,7 @@ from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from .models import Notification, TypeNotif from .models import Notification, TypeNotif
from GestionMessagerie.models import Messagerie from GestionMessagerie.models import Messagerie
from GestionInscriptions.models import FicheInscription from Subscriptions.models import RegistrationForm
@receiver(post_save, sender=Messagerie) @receiver(post_save, sender=Messagerie)
def notification_MESSAGE(sender, instance, created, **kwargs): def notification_MESSAGE(sender, instance, created, **kwargs):
@ -13,11 +13,11 @@ def notification_MESSAGE(sender, instance, created, **kwargs):
typeNotification=TypeNotif.NOTIF_MESSAGE typeNotification=TypeNotif.NOTIF_MESSAGE
) )
@receiver(post_save, sender=FicheInscription) @receiver(post_save, sender=RegistrationForm)
def notification_DI(sender, instance, created, **kwargs): def notification_DI(sender, instance, created, **kwargs):
for responsable in instance.eleve.responsables.all(): for responsable in instance.student.guardians.all():
Notification.objects.create( Notification.objects.create(
user=responsable.profilAssocie, user=responsable.associated_profile,
message=(TypeNotif.NOTIF_DI).label, message=(TypeNotif.NOTIF_DI).label,
typeNotification=TypeNotif.NOTIF_DI typeNotification=TypeNotif.NOTIF_DI
) )

View File

@ -3,7 +3,7 @@ from rest_framework.views import APIView
from .models import * from .models import *
from GestionInscriptions.serializers import NotificationSerializer from Subscriptions.serializers import NotificationSerializer
from N3wtSchool import bdd from N3wtSchool import bdd

View File

@ -1,6 +1,6 @@
import logging import logging
from django.db.models import Q from django.db.models import Q
from GestionInscriptions.models import FicheInscription, Profil, Eleve from Subscriptions.models import RegistrationForm, Profile, Student
logger = logging.getLogger('N3wtSchool') logger = logging.getLogger('N3wtSchool')
@ -43,12 +43,12 @@ def getProfile(objectList, valueToCheck):
return result return result
def getEleveByCodeFI(_codeFI): def getEleveByCodeFI(_codeFI):
eleve = None student = None
ficheInscriptions_List=getAllObjects(FicheInscription) ficheInscriptions_List=getAllObjects(RegistrationForm)
for fi in ficheInscriptions_List: for rf in ficheInscriptions_List:
if fi.codeLienInscription == _codeFI: if rf.codeLienInscription == _codeFI:
eleve = fi.eleve student = rf.student
return eleve return student
def getLastId(_object): def getLastId(_object):
result = 1 result = 1
@ -61,7 +61,7 @@ def getLastId(_object):
def searchObjects(_objectName, _searchTerm=None, _excludeStates=None): def searchObjects(_objectName, _searchTerm=None, _excludeStates=None):
""" """
Recherche générique sur les objets avec possibilité d'exclure certains états Recherche générique sur les objets avec possibilité d'exclure certains états
_objectName: Classe du modèle _objectName: SchoolClass du modèle
_searchTerm: Terme de recherche _searchTerm: Terme de recherche
_excludeStates: Liste d'état à exclure de la recherche (optionnel) _excludeStates: Liste d'état à exclure de la recherche (optionnel)
""" """
@ -70,18 +70,18 @@ def searchObjects(_objectName, _searchTerm=None, _excludeStates=None):
# Si on a un état à exclure # Si on a un état à exclure
if _excludeStates is not None: if _excludeStates is not None:
query = query.exclude(etat__in=_excludeStates) query = query.exclude(status__in=_excludeStates)
# Si on a un terme de recherche # Si on a un terme de recherche
if _searchTerm and _searchTerm.strip(): if _searchTerm and _searchTerm.strip():
terms = _searchTerm.lower().strip().split() terms = _searchTerm.lower().strip().split()
for term in terms: for term in terms:
query = query.filter( query = query.filter(
Q(eleve__nom__icontains=term) | Q(student__last_name__icontains=term) |
Q(eleve__prenom__icontains=term) Q(student__first_name__icontains=term)
) )
return query.order_by('eleve__nom', 'eleve__prenom') return query.order_by('student__last_name', 'student__first_name')
except _objectName.DoesNotExist: except _objectName.DoesNotExist:
logging.error(f"Aucun résultat n'a été trouvé - {_objectName.__name__} (recherche: {_searchTerm})") logging.error(f"Aucun résultat n'a été trouvé - {_objectName.__name__} (recherche: {_searchTerm})")

View File

@ -19,7 +19,7 @@ BASE_DIR = Path(__file__).resolve().parent.parent
MEDIA_URL = '/data/' MEDIA_URL = '/data/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'data') MEDIA_ROOT = os.path.join(BASE_DIR, 'data')
LOGIN_REDIRECT_URL = '/GestionInscriptions/fichesInscriptions' LOGIN_REDIRECT_URL = '/Subscriptions/registerForms'
# Quick-start development settings - unsuitable for production # Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/5.0/howto/deployment/checklist/
@ -35,11 +35,11 @@ ALLOWED_HOSTS = ['*']
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
'GestionInscriptions.apps.GestioninscriptionsConfig', 'Subscriptions.apps.GestioninscriptionsConfig',
'GestionLogin.apps.GestionloginConfig', 'Auth.apps.GestionloginConfig',
'GestionMessagerie.apps.GestionMessagerieConfig', 'GestionMessagerie.apps.GestionMessagerieConfig',
'GestionNotification.apps.GestionNotificationConfig', 'GestionNotification.apps.GestionNotificationConfig',
'GestionEnseignants.apps.GestionenseignantsConfig', 'School.apps.SchoolConfig',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
@ -133,12 +133,12 @@ LOGGING = {
"level": os.getenv("GESTION_NOTIFICATION_LOG_LEVEL", "INFO"), "level": os.getenv("GESTION_NOTIFICATION_LOG_LEVEL", "INFO"),
"propagate": False, "propagate": False,
}, },
"GestionLogin": { "Auth": {
"handlers": ["console"], "handlers": ["console"],
"level": os.getenv("GESTION_LOGIN_LOG_LEVEL", "INFO"), "level": os.getenv("GESTION_LOGIN_LOG_LEVEL", "INFO"),
"propagate": False, "propagate": False,
}, },
"GestionInscriptions": { "Subscriptions": {
"handlers": ["console"], "handlers": ["console"],
"level": os.getenv("GESTION_INSCRIPTIONS_LOG_LEVEL", "DEBUG"), "level": os.getenv("GESTION_INSCRIPTIONS_LOG_LEVEL", "DEBUG"),
"propagate": False, "propagate": False,
@ -148,7 +148,7 @@ LOGGING = {
"level": os.getenv("GESTION_MESSAGERIE_LOG_LEVEL", "INFO"), "level": os.getenv("GESTION_MESSAGERIE_LOG_LEVEL", "INFO"),
"propagate": False, "propagate": False,
}, },
"GestionEnseignants": { "School": {
"handlers": ["console"], "handlers": ["console"],
"level": os.getenv("GESTION_ENSEIGNANTS_LOG_LEVEL", "INFO"), "level": os.getenv("GESTION_ENSEIGNANTS_LOG_LEVEL", "INFO"),
"propagate": False, "propagate": False,
@ -211,7 +211,7 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
#################### Application Settings ############################## #################### Application Settings ##############################
######################################################################## ########################################################################
with open('GestionInscriptions/Configuration/application.json', 'r') as f: with open('Subscriptions/Configuration/application.json', 'r') as f:
jsonObject = json.load(f) jsonObject = json.load(f)
DJANGO_SUPERUSER_PASSWORD='admin' DJANGO_SUPERUSER_PASSWORD='admin'
@ -275,8 +275,8 @@ DATABASES = {
} }
} }
AUTH_USER_MODEL = 'GestionLogin.Profil' AUTH_USER_MODEL = 'Auth.Profile'
AUTHENTICATION_BACKENDS = ('GestionLogin.backends.EmailBackend', ) AUTHENTICATION_BACKENDS = ('Auth.backends.EmailBackend', )
SILENCED_SYSTEM_CHECKS = ["auth.W004"] SILENCED_SYSTEM_CHECKS = ["auth.W004"]
EXPIRATION_URL_NB_DAYS = 7 EXPIRATION_URL_NB_DAYS = 7
@ -289,7 +289,7 @@ NB_RESULT_PER_PAGE = 8
NB_MAX_PAGE = 100 NB_MAX_PAGE = 100
REST_FRAMEWORK = { REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'GestionInscriptions.pagination.CustomPagination', 'DEFAULT_PAGINATION_CLASS': 'Subscriptions.pagination.CustomPagination',
'PAGE_SIZE': NB_RESULT_PER_PAGE 'PAGE_SIZE': NB_RESULT_PER_PAGE
} }

View File

@ -16,6 +16,6 @@ def setup_periodic_tasks(sender, **kwargs):
PeriodicTask.objects.get_or_create( PeriodicTask.objects.get_or_create(
interval=schedule, # Utiliser l'intervalle défini ci-dessus interval=schedule, # Utiliser l'intervalle défini ci-dessus
name='Tâche périodique toutes les 5 secondes', name='Tâche périodique toutes les 5 secondes',
task='GestionInscriptions.tasks.check_for_signature_deadlines', # Remplacer par le nom de ta tâche task='Subscriptions.tasks.check_for_signature_deadlines', # Remplacer par le nom de ta tâche
kwargs=json.dumps({}) # Si nécessaire, ajoute kwargs=json.dumps({}) # Si nécessaire, ajoute
) )

View File

@ -7,7 +7,7 @@ Examples:
Function views Function views
1. Add an import: from my_app import views 1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home') 2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views SchoolClass-based views
1. Add an import: from other_app.views import Home 1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf Including another URLconf
@ -39,11 +39,11 @@ schema_view = get_schema_view(
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
path("GestionInscriptions/", include(("GestionInscriptions.urls", 'GestionInscriptions'), namespace='GestionInscriptions')), path("Subscriptions/", include(("Subscriptions.urls", 'Subscriptions'), namespace='Subscriptions')),
path("GestionLogin/", include(("GestionLogin.urls", 'GestionLogin'), namespace='GestionLogin')), path("Auth/", include(("Auth.urls", 'Auth'), namespace='Auth')),
path("GestionMessagerie/", include(("GestionMessagerie.urls", 'GestionMessagerie'), namespace='GestionMessagerie')), path("GestionMessagerie/", include(("GestionMessagerie.urls", 'GestionMessagerie'), namespace='GestionMessagerie')),
path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')), path("GestionNotification/", include(("GestionNotification.urls", 'GestionNotification'), namespace='GestionNotification')),
path("GestionEnseignants/", include(("GestionEnseignants.urls", 'GestionEnseignants'), namespace='GestionEnseignants')), path("School/", include(("School.urls", 'School'), namespace='School')),
# Documentation Api # Documentation Api
re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'), re_path(r'^swagger(?P<format>\.json|\.yaml)$', schema_view.without_ui(cache_timeout=0), name='schema-json'),
path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'), path('swagger/', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),

View File

@ -0,0 +1 @@
default_app_config = 'School.apps.SchoolConfig'

14
Back-End/School/apps.py Normal file
View File

@ -0,0 +1,14 @@
from django.apps import AppConfig
from django.db.models.signals import post_migrate
def create_speciality(sender, **kwargs):
from .models import Speciality
if not Speciality.objects.filter(name='GROUPE').exists():
Speciality.objects.create(name='GROUPE', colorCode='#FF0000')
class SchoolConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'School'
def ready(self):
post_migrate.connect(create_speciality, sender=self)

66
Back-End/School/models.py Normal file
View File

@ -0,0 +1,66 @@
from django.db import models
from Auth.models import Profile
from django.db.models import JSONField
from django.dispatch import receiver
from django.contrib.postgres.fields import ArrayField
LEVEL_CHOICES = [
(1, 'Très Petite Section (TPS)'),
(2, 'Petite Section (PS)'),
(3, 'Moyenne Section (MS)'),
(4, 'Grande Section (GS)'),
(5, 'Cours Préparatoire (CP)'),
(6, 'Cours Élémentaire 1 (CE1)'),
(7, 'Cours Élémentaire 2 (CE2)'),
(8, 'Cours Moyen 1 (CM1)'),
(9, 'Cours Moyen 2 (CM2)')
]
class Speciality(models.Model):
name = models.CharField(max_length=100)
updatedDate = models.DateTimeField(auto_now=True)
colorCode = models.CharField(max_length=7, default='#FFFFFF')
def __str__(self):
return self.name
class Teacher(models.Model):
lastName = models.CharField(max_length=100)
firstName = models.CharField(max_length=100)
email = models.EmailField(unique=True)
specialities = models.ManyToManyField(Speciality, related_name='teachers')
associatedProfile = models.ForeignKey(Profile, on_delete=models.CASCADE, null=True, blank=True)
updatedDate = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.lastName} {self.firstName}"
class SchoolClass(models.Model):
PLANNING_TYPE_CHOICES = [
(1, 'Annuel'),
(2, 'Semestriel'),
(3, 'Trimestriel')
]
atmosphereName = models.CharField(max_length=255, null=True, blank=True)
ageGroup = models.JSONField()
numberOfStudents = models.PositiveIntegerField()
teachingLanguage = models.CharField(max_length=255)
schoolYear = models.CharField(max_length=9)
updatedDate = models.DateTimeField(auto_now_add=True)
teachers = models.ManyToManyField(Teacher, related_name='schoolClasses')
levels = ArrayField(models.IntegerField(choices=LEVEL_CHOICES), default=list)
type = models.IntegerField(choices=PLANNING_TYPE_CHOICES, default=1)
schedule = models.JSONField(default=list)
openingDays = ArrayField(models.IntegerField(), default=list)
def __str__(self):
return self.atmosphereName
class Planning(models.Model):
level = models.IntegerField(choices=LEVEL_CHOICES, null=True, blank=True)
classModel = models.ForeignKey(SchoolClass, null=True, blank=True, related_name='plannings', on_delete=models.CASCADE)
schedule = JSONField(default=dict)
def __str__(self):
return f'Planning for {self.level} of {self.classModel.atmosphereName}'

View File

@ -0,0 +1,194 @@
from rest_framework import serializers
from .models import Teacher, Speciality, SchoolClass, Planning, LEVEL_CHOICES
from Subscriptions.models import RegistrationForm
from Subscriptions.serializers import StudentSerializer
from Auth.serializers import ProfileSerializer
from Auth.models import Profile
from N3wtSchool import settings, bdd
from django.utils import timezone
import pytz
class SpecialitySerializer(serializers.ModelSerializer):
creationDateFormatted = serializers.SerializerMethodField()
class Meta:
model = Speciality
fields = '__all__'
def get_creationDateFormatted(self, obj):
utc_time = timezone.localtime(obj.updatedDate) # Convert to local time
local_tz = pytz.timezone(settings.TZ_APPLI)
local_time = utc_time.astimezone(local_tz)
return local_time.strftime("%d-%m-%Y %H:%M")
class TeacherDetailSerializer(serializers.ModelSerializer):
specialities = SpecialitySerializer(many=True, read_only=True)
class Meta:
model = Teacher
fields = ['id', 'lastName', 'firstName', 'email', 'specialities']
class TeacherSerializer(serializers.ModelSerializer):
specialities = SpecialitySerializer(many=True, read_only=True)
specialties_ids = serializers.PrimaryKeyRelatedField(queryset=Speciality.objects.all(), many=True, source='specialities')
associatedProfile_id = serializers.PrimaryKeyRelatedField(queryset=Profile.objects.all(), source='associatedProfile', write_only=False, read_only=False)
mainClasses = serializers.PrimaryKeyRelatedField(many=True, read_only=True, source='schoolClasses')
associatedProfile = ProfileSerializer(read_only=True)
rightLabel = serializers.SerializerMethodField()
rightValue = serializers.SerializerMethodField()
creationDateFormatted = serializers.SerializerMethodField()
class Meta:
model = Teacher
fields = ['id', 'lastName', 'firstName', 'email', 'specialities', 'specialties_ids', 'mainClasses', 'associatedProfile', 'associatedProfile_id', 'rightLabel', 'rightValue', 'updatedDate', 'creationDateFormatted']
def create(self, validated_data):
specialties_data = validated_data.pop('specialities', None)
associatedProfile = validated_data.pop('associatedProfile', None)
teacher = Teacher.objects.create(**validated_data)
teacher.specialities.set(specialties_data)
if associatedProfile:
teacher.associatedProfile = associatedProfile
teacher.save()
return teacher
def update(self, instance, validated_data):
specialties_data = validated_data.pop('specialities', [])
instance.lastName = validated_data.get('lastName', instance.lastName)
instance.firstName = validated_data.get('firstName', instance.firstName)
instance.email = validated_data.get('email', instance.email)
instance.associatedProfile = validated_data.get('associatedProfile', instance.associatedProfile)
instance.save()
instance.specialities.set(specialties_data)
return instance
def get_rightLabel(self, obj):
return obj.associatedProfile.get_right_display() if obj.associatedProfile else None
def get_rightValue(self, obj):
return obj.associatedProfile.right if obj.associatedProfile else None
def get_creationDateFormatted(self, obj):
utc_time = timezone.localtime(obj.updatedDate) # Convert to local time
local_tz = pytz.timezone(settings.TZ_APPLI)
local_time = utc_time.astimezone(local_tz)
return local_time.strftime("%d-%m-%Y %H:%M")
class PlanningSerializer(serializers.ModelSerializer):
class Meta:
model = Planning
fields = ['id', 'level', 'schedule']
def to_internal_value(self, data):
internal_value = super().to_internal_value(data)
internal_value['schedule'] = data.get('schedule', {})
return internal_value
class SchoolClassSerializer(serializers.ModelSerializer):
creationDateFormatted = serializers.SerializerMethodField()
teachers = TeacherSerializer(many=True, read_only=True)
teachers_ids = serializers.PrimaryKeyRelatedField(queryset=Teacher.objects.all(), many=True, source='teachers')
students = serializers.SerializerMethodField()
levels = serializers.ListField(child=serializers.ChoiceField(choices=LEVEL_CHOICES))
plannings_read = serializers.SerializerMethodField()
plannings = PlanningSerializer(many=True, write_only=True)
class Meta:
model = SchoolClass
fields = [
'id', 'atmosphereName', 'ageGroup', 'numberOfStudents', 'teachingLanguage',
'teachers', 'teachers_ids', 'schoolYear', 'updatedDate',
'creationDateFormatted', 'students', 'levels', 'type', 'schedule',
'openingDays', 'plannings', 'plannings_read'
]
def create(self, validated_data):
teachers_data = validated_data.pop('teachers', [])
levels_data = validated_data.pop('levels', [])
plannings_data = validated_data.pop('plannings', [])
classModel = SchoolClass.objects.create(
atmosphereName=validated_data.get('atmosphereName', ''),
ageGroup=validated_data.get('ageGroup', []),
numberOfStudents=validated_data.get('numberOfStudents', 0),
teachingLanguage=validated_data.get('teachingLanguage', ''),
schoolYear=validated_data.get('schoolYear', ''),
levels=levels_data,
type=validated_data.get('type', 1), # Added here
schedule=validated_data.get('schedule', ['08:30', '17:30']), # Added here
openingDays=validated_data.get('openingDays', [1, 2, 4, 5]) # Added here
)
classModel.teachers.set(teachers_data)
for planning_data in plannings_data:
Planning.objects.create(
classModel=classModel,
level=planning_data['level'],
schedule=planning_data.get('schedule', {})
)
return classModel
def update(self, instance, validated_data):
teachers_data = validated_data.pop('teachers', [])
levels_data = validated_data.pop('levels', [])
plannings_data = validated_data.pop('plannings', [])
instance.atmosphereName = validated_data.get('atmosphereName', instance.atmosphereName)
instance.ageGroup = validated_data.get('ageGroup', instance.ageGroup)
instance.numberOfStudents = validated_data.get('numberOfStudents', instance.numberOfStudents)
instance.teachingLanguage = validated_data.get('teachingLanguage', instance.teachingLanguage)
instance.schoolYear = validated_data.get('schoolYear', instance.schoolYear)
instance.levels = levels_data
instance.type = validated_data.get('type', instance.type) # Added here
instance.schedule = validated_data.get('schedule', instance.schedule) # Added here
instance.openingDays = validated_data.get('openingDays', instance.openingDays) # Added here
instance.save()
instance.teachers.set(teachers_data)
existing_plannings = {planning.level: planning for planning in instance.plannings.all()}
for planning_data in plannings_data:
level = planning_data['level']
if level in existing_plannings:
# Update existing planning
planning = existing_plannings[level]
planning.schedule = planning_data.get('schedule', planning.schedule)
planning.save()
else:
# Create new planning if level not existing
Planning.objects.create(
classModel=instance,
level=level,
schedule=planning_data.get('schedule', {})
)
return instance
def get_creationDateFormatted(self, obj):
utc_time = timezone.localtime(obj.updatedDate)
local_tz = pytz.timezone(settings.TZ_APPLI)
local_time = utc_time.astimezone(local_tz)
return local_time.strftime("%d-%m-%Y %H:%M")
def get_students(self, obj):
studentsList = obj.students.all()
filtered_students = []
for student in studentsList:
registrationForm = bdd.getObject(RegistrationForm, "student__id", student.id)
if registrationForm.status == registrationForm.RegistrationFormStatus.RF_VALIDATED:
filtered_students.append(student)
return StudentSerializer(filtered_students, many=True, read_only=True).data
def get_plannings_read(self, obj):
plannings = obj.plannings.all()
levels_dict = {level: {'level': level, 'planning': None} for level in obj.levels}
for planning in plannings:
if planning.level in levels_dict:
levels_dict[planning.level]['planning'] = PlanningSerializer(planning).data
return list(levels_dict.values())

21
Back-End/School/urls.py Normal file
View File

@ -0,0 +1,21 @@
from django.urls import path, re_path
from School.views import TeachersView, EnseignantView, SpecialitiesView, SpecialityView, ClassesView, ClasseView, PlanningsView, PlanningView
urlpatterns = [
re_path(r'^teachers$', TeachersView.as_view(), name="teachers"),
re_path(r'^teacher$', EnseignantView.as_view(), name="teacher"),
re_path(r'^teacher/([0-9]+)$', EnseignantView.as_view(), name="teacher"),
re_path(r'^specialities$', SpecialitiesView.as_view(), name="specialities"),
re_path(r'^speciality$', SpecialityView.as_view(), name="speciality"),
re_path(r'^speciality/([0-9]+)$', SpecialityView.as_view(), name="speciality"),
re_path(r'^schoolClasses$', ClassesView.as_view(), name="schoolClasses"),
re_path(r'^schoolClass$', ClasseView.as_view(), name="schoolClass"),
re_path(r'^schoolClass/([0-9]+)$', ClasseView.as_view(), name="schoolClass"),
re_path(r'^plannings$', PlanningsView.as_view(), name="plannings"),
re_path(r'^planning$', PlanningView.as_view(), name="planning"),
re_path(r'^planning/([0-9]+)$', PlanningView.as_view(), name="planning"),
]

View File

@ -4,121 +4,121 @@ from django.utils.decorators import method_decorator
from rest_framework.parsers import JSONParser from rest_framework.parsers import JSONParser
from rest_framework.views import APIView from rest_framework.views import APIView
from django.core.cache import cache from django.core.cache import cache
from .models import Enseignant, Specialite, Classe, Planning from .models import Teacher, Speciality, SchoolClass, Planning
from .serializers import EnseignantSerializer, SpecialiteSerializer, ClasseSerializer, PlanningSerializer from .serializers import TeacherSerializer, SpecialitySerializer, SchoolClassSerializer, PlanningSerializer
from N3wtSchool import bdd from N3wtSchool import bdd
class EnseignantsView(APIView): class TeachersView(APIView):
def get(self, request): def get(self, request):
enseignantsList=bdd.getAllObjects(Enseignant) teachersList=bdd.getAllObjects(Teacher)
enseignants_serializer=EnseignantSerializer(enseignantsList, many=True) teachers_serializer=TeacherSerializer(teachersList, many=True)
return JsonResponse(enseignants_serializer.data, safe=False) return JsonResponse(teachers_serializer.data, safe=False)
@method_decorator(csrf_protect, name='dispatch') @method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch')
class EnseignantView(APIView): class EnseignantView(APIView):
def get (self, request, _id): def get (self, request, _id):
enseignant = bdd.getObject(_objectName=Enseignant, _columnName='id', _value=_id) teacher = bdd.getObject(_objectName=Teacher, _columnName='id', _value=_id)
enseignant_serializer=EnseignantSerializer(enseignant) teacher_serializer=TeacherSerializer(teacher)
return JsonResponse(enseignant_serializer.data, safe=False) return JsonResponse(teacher_serializer.data, safe=False)
def post(self, request): def post(self, request):
enseignant_data=JSONParser().parse(request) teacher_data=JSONParser().parse(request)
enseignant_serializer = EnseignantSerializer(data=enseignant_data) teacher_serializer = TeacherSerializer(data=teacher_data)
if enseignant_serializer.is_valid(): if teacher_serializer.is_valid():
enseignant_serializer.save() teacher_serializer.save()
return JsonResponse(enseignant_serializer.data, safe=False) return JsonResponse(teacher_serializer.data, safe=False)
return JsonResponse(enseignant_serializer.errors, safe=False) return JsonResponse(teacher_serializer.errors, safe=False)
def put(self, request, _id): def put(self, request, _id):
enseignant_data=JSONParser().parse(request) teacher_data=JSONParser().parse(request)
enseignant = bdd.getObject(_objectName=Enseignant, _columnName='id', _value=_id) teacher = bdd.getObject(_objectName=Teacher, _columnName='id', _value=_id)
enseignant_serializer = EnseignantSerializer(enseignant, data=enseignant_data) teacher_serializer = TeacherSerializer(teacher, data=teacher_data)
if enseignant_serializer.is_valid(): if teacher_serializer.is_valid():
enseignant_serializer.save() teacher_serializer.save()
return JsonResponse(enseignant_serializer.data, safe=False) return JsonResponse(teacher_serializer.data, safe=False)
return JsonResponse(enseignant_serializer.errors, safe=False) return JsonResponse(teacher_serializer.errors, safe=False)
def delete(self, request, _id): def delete(self, request, _id):
enseignant = bdd.getObject(_objectName=Enseignant, _columnName='id', _value=_id) teacher = bdd.getObject(_objectName=Teacher, _columnName='id', _value=_id)
if enseignant is not None: if teacher is not None:
if enseignant.profilAssocie: if teacher.profilAssocie:
print('Suppression du profil associé') print('Suppression du profil associé')
enseignant.profilAssocie.delete() teacher.profilAssocie.delete()
enseignant.delete() teacher.delete()
return JsonResponse({'message': 'La suppression de l\'enseignant a été effectuée avec succès'}, safe=False) return JsonResponse({'message': 'La suppression de l\'teacher a été effectuée avec succès'}, safe=False)
else: else:
return JsonResponse({'erreur': 'L\'enseignant n\'a pas été trouvé'}, safe=False) return JsonResponse({'erreur': 'L\'teacher n\'a pas été trouvé'}, safe=False)
@method_decorator(csrf_protect, name='dispatch') @method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch')
class SpecialitesView(APIView): class SpecialitiesView(APIView):
def get(self, request): def get(self, request):
specialitesList=bdd.getAllObjects(Specialite) specialitiesList=bdd.getAllObjects(Speciality)
specialites_serializer=SpecialiteSerializer(specialitesList, many=True) specialities_serializer=SpecialitySerializer(specialitiesList, many=True)
return JsonResponse(specialites_serializer.data, safe=False) return JsonResponse(specialities_serializer.data, safe=False)
def post(self, request): def post(self, request):
specialites_data=JSONParser().parse(request) specialities_data=JSONParser().parse(request)
all_valid = True all_valid = True
for specialite_data in specialites_data: for speciality_data in specialities_data:
specialite_serializer = SpecialiteSerializer(data=specialite_data) speciality_serializer = SpecialitySerializer(data=speciality_data)
if specialite_serializer.is_valid(): if speciality_serializer.is_valid():
specialite_serializer.save() speciality_serializer.save()
else: else:
all_valid = False all_valid = False
break break
if all_valid: if all_valid:
specialitesList = bdd.getAllObjects(Specialite) specialitiesList = bdd.getAllObjects(Speciality)
specialites_serializer = SpecialiteSerializer(specialitesList, many=True) specialities_serializer = SpecialitySerializer(specialitiesList, many=True)
return JsonResponse(specialites_serializer.data, safe=False) return JsonResponse(specialities_serializer.data, safe=False)
return JsonResponse(specialite_serializer.errors, safe=False) return JsonResponse(speciality_serializer.errors, safe=False)
@method_decorator(csrf_protect, name='dispatch') @method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch')
class SpecialiteView(APIView): class SpecialityView(APIView):
def get (self, request, _id): def get (self, request, _id):
specialite = bdd.getObject(_objectName=Specialite, _columnName='id', _value=_id) speciality = bdd.getObject(_objectName=Speciality, _columnName='id', _value=_id)
specialite_serializer=SpecialiteSerializer(specialite) speciality_serializer=SpecialitySerializer(speciality)
return JsonResponse(specialite_serializer.data, safe=False) return JsonResponse(speciality_serializer.data, safe=False)
def post(self, request): def post(self, request):
specialite_data=JSONParser().parse(request) speciality_data=JSONParser().parse(request)
specialite_serializer = SpecialiteSerializer(data=specialite_data) speciality_serializer = SpecialitySerializer(data=speciality_data)
if specialite_serializer.is_valid(): if speciality_serializer.is_valid():
specialite_serializer.save() speciality_serializer.save()
return JsonResponse(specialite_serializer.data, safe=False) return JsonResponse(speciality_serializer.data, safe=False)
return JsonResponse(specialite_serializer.errors, safe=False) return JsonResponse(speciality_serializer.errors, safe=False)
def put(self, request, _id): def put(self, request, _id):
specialite_data=JSONParser().parse(request) speciality_data=JSONParser().parse(request)
specialite = bdd.getObject(_objectName=Specialite, _columnName='id', _value=_id) speciality = bdd.getObject(_objectName=Speciality, _columnName='id', _value=_id)
specialite_serializer = SpecialiteSerializer(specialite, data=specialite_data) speciality_serializer = SpecialitySerializer(speciality, data=speciality_data)
if specialite_serializer.is_valid(): if speciality_serializer.is_valid():
specialite_serializer.save() speciality_serializer.save()
return JsonResponse(specialite_serializer.data, safe=False) return JsonResponse(speciality_serializer.data, safe=False)
return JsonResponse(specialite_serializer.errors, safe=False) return JsonResponse(speciality_serializer.errors, safe=False)
def delete(self, request, _id): def delete(self, request, _id):
specialite = bdd.getObject(_objectName=Specialite, _columnName='id', _value=_id) speciality = bdd.getObject(_objectName=Speciality, _columnName='id', _value=_id)
if specialite != None: if speciality != None:
specialite.delete() speciality.delete()
return JsonResponse("La suppression de la spécialité a été effectuée avec succès", safe=False) return JsonResponse("La suppression de la spécialité a été effectuée avec succès", safe=False)
@ -126,15 +126,15 @@ class SpecialiteView(APIView):
@method_decorator(ensure_csrf_cookie, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch')
class ClassesView(APIView): class ClassesView(APIView):
def get(self, request): def get(self, request):
classesList=bdd.getAllObjects(Classe) classesList=bdd.getAllObjects(SchoolClass)
classes_serializer=ClasseSerializer(classesList, many=True) classes_serializer=SchoolClassSerializer(classesList, many=True)
return JsonResponse(classes_serializer.data, safe=False) return JsonResponse(classes_serializer.data, safe=False)
def post(self, request): def post(self, request):
all_valid = True all_valid = True
classes_data=JSONParser().parse(request) classes_data=JSONParser().parse(request)
for classe_data in classes_data: for classe_data in classes_data:
classe_serializer = ClasseSerializer(data=classe_data) classe_serializer = SchoolClassSerializer(data=classe_data)
if classe_serializer.is_valid(): if classe_serializer.is_valid():
classe_serializer.save() classe_serializer.save()
@ -143,8 +143,8 @@ class ClassesView(APIView):
break break
if all_valid: if all_valid:
classesList = bdd.getAllObjects(Classe) classesList = bdd.getAllObjects(SchoolClass)
classes_serializer = ClasseSerializer(classesList, many=True) classes_serializer = SchoolClassSerializer(classesList, many=True)
return JsonResponse(classes_serializer.data, safe=False) return JsonResponse(classes_serializer.data, safe=False)
@ -154,14 +154,14 @@ class ClassesView(APIView):
@method_decorator(ensure_csrf_cookie, name='dispatch') @method_decorator(ensure_csrf_cookie, name='dispatch')
class ClasseView(APIView): class ClasseView(APIView):
def get (self, request, _id): def get (self, request, _id):
classe = bdd.getObject(_objectName=Classe, _columnName='id', _value=_id) schoolClass = bdd.getObject(_objectName=SchoolClass, _columnName='id', _value=_id)
classe_serializer=ClasseSerializer(classe) classe_serializer=SchoolClassSerializer(schoolClass)
return JsonResponse(classe_serializer.data, safe=False) return JsonResponse(classe_serializer.data, safe=False)
def post(self, request): def post(self, request):
classe_data=JSONParser().parse(request) classe_data=JSONParser().parse(request)
classe_serializer = ClasseSerializer(data=classe_data) classe_serializer = SchoolClassSerializer(data=classe_data)
if classe_serializer.is_valid(): if classe_serializer.is_valid():
classe_serializer.save() classe_serializer.save()
@ -171,8 +171,8 @@ class ClasseView(APIView):
def put(self, request, _id): def put(self, request, _id):
classe_data=JSONParser().parse(request) classe_data=JSONParser().parse(request)
classe = bdd.getObject(_objectName=Classe, _columnName='id', _value=_id) schoolClass = bdd.getObject(_objectName=SchoolClass, _columnName='id', _value=_id)
classe_serializer = ClasseSerializer(classe, data=classe_data) classe_serializer = SchoolClassSerializer(schoolClass, data=classe_data)
if classe_serializer.is_valid(): if classe_serializer.is_valid():
classe_serializer.save() classe_serializer.save()
return JsonResponse(classe_serializer.data, safe=False) return JsonResponse(classe_serializer.data, safe=False)
@ -180,23 +180,23 @@ class ClasseView(APIView):
return JsonResponse(classe_serializer.errors, safe=False) return JsonResponse(classe_serializer.errors, safe=False)
def delete(self, request, _id): def delete(self, request, _id):
classe = bdd.getObject(_objectName=Classe, _columnName='id', _value=_id) schoolClass = bdd.getObject(_objectName=SchoolClass, _columnName='id', _value=_id)
if classe is not None: if schoolClass is not None:
# Supprimer les plannings associés à la classe # Supprimer les plannings associés à la schoolClass
for planning in classe.plannings.all(): for planning in schoolClass.plannings.all():
print(f'Planning à supprimer : {planning}') print(f'Planning à supprimer : {planning}')
planning.delete() planning.delete()
# Retirer la classe des élèves associés # Retirer la schoolClass des élèves associés
for eleve in classe.eleves.all(): for eleve in schoolClass.eleves.all():
print(f'Eleve à retirer de la classe : {eleve}') print(f'Student à retirer de la schoolClass : {eleve}')
eleve.classeAssociee = None eleve.classeAssociee = None
eleve.save() eleve.save()
# Supprimer la classe # Supprimer la schoolClass
classe.delete() schoolClass.delete()
return JsonResponse("La suppression de la classe a été effectuée avec succès", safe=False) return JsonResponse("La suppression de la schoolClass a été effectuée avec succès", safe=False)
@method_decorator(csrf_protect, name='dispatch') @method_decorator(csrf_protect, name='dispatch')

View File

@ -0,0 +1 @@
default_app_config = 'Subscriptions.apps.GestionInscriptionsConfig'

View File

@ -2,8 +2,8 @@ from django.contrib import admin
from .models import * from .models import *
admin.site.register(Eleve) admin.site.register(Student)
admin.site.register(Responsable) admin.site.register(Guardian)
class EleveAdmin(admin.ModelAdmin): class EleveAdmin(admin.ModelAdmin):
def save_model(self, request, obj, form, change): def save_model(self, request, obj, form, change):

View File

@ -3,8 +3,8 @@ from django.conf import settings
class GestioninscriptionsConfig(AppConfig): class GestioninscriptionsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField' default_auto_field = 'django.db.models.BigAutoField'
name = 'GestionInscriptions' name = 'Subscriptions'
def ready(self): def ready(self):
from GestionInscriptions.signals import clear_cache from Subscriptions.signals import clear_cache
clear_cache() clear_cache()

View File

@ -0,0 +1,45 @@
# state_machine.py
import json
from Subscriptions.models import RegistrationForm
from Subscriptions.signals import clear_cache
state_mapping = {
"ABSENT": RegistrationForm.RegistrationFormStatus.RF_ABSENT,
"CREE": RegistrationForm.RegistrationFormStatus.RF_CREATED,
"ENVOYE": RegistrationForm.RegistrationFormStatus.RF_SENT,
"EN_VALIDATION": RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW,
"A_RELANCER": RegistrationForm.RegistrationFormStatus.RF_TO_BE_FOLLOWED_UP,
"VALIDE": RegistrationForm.RegistrationFormStatus.RF_VALIDATED,
"ARCHIVE": RegistrationForm.RegistrationFormStatus.RF_ARCHIVED
}
def load_config(config_file):
with open(config_file, 'r') as file:
config = json.load(file)
return config
def getStateMachineObject(etat) :
return Automate_RF_Register(etat)
def getStateMachineObjectState(etat):
return Automate_RF_Register(etat).state
def updateStateMachine(rf, transition) :
automateModel = load_config('Subscriptions/Configuration/automate.json')
state_machine = getStateMachineObject(rf.status)
print(f'etat DI : {state_machine.state}')
if state_machine.trigger(transition, automateModel):
rf.status = state_machine.state
rf.save()
clear_cache()
class Automate_RF_Register:
def __init__(self, initial_state):
self.state = initial_state
def trigger(self, transition_name, config):
for transition in config["transitions"]:
if transition["name"] == transition_name and self.state == state_mapping[transition["from"]]:
self.state = state_mapping[transition["to"]]
return True
return False

View File

@ -11,7 +11,7 @@ def envoieReinitMotDePasse(recipients, code):
fail_silently=False, fail_silently=False,
) )
def envoieDossierInscription(recipients): def sendRegisterForm(recipients):
errorMessage = '' errorMessage = ''
try: try:
print(f'{settings.EMAIL_HOST_USER}') print(f'{settings.EMAIL_HOST_USER}')
@ -68,7 +68,7 @@ def isValid(message, fiche_inscription):
idMail = result.group(1).strip() idMail = result.group(1).strip()
eleve = fiche_inscription.eleve eleve = fiche_inscription.eleve
responsable = eleve.getResponsablePrincipal() responsable = eleve.getMainGuardian()
mailReponsableAVerifier = responsable.mail mailReponsableAVerifier = responsable.mail
return responsableMail == mailReponsableAVerifier and str(idMail) == str(fiche_inscription.eleve.id) return responsableMail == mailReponsableAVerifier and str(idMail) == str(fiche_inscription.eleve.id)

View File

@ -0,0 +1,179 @@
from django.db import models
from django.utils.timezone import now
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from Auth.models import Profile
from School.models import SchoolClass
from datetime import datetime
class RegistrationFee(models.Model):
class PaymentOptions(models.IntegerChoices):
SINGLE_PAYMENT = 0, _('Paiement en une seule fois')
MONTHLY_PAYMENT = 1, _('Paiement mensuel')
QUARTERLY_PAYMENT = 2, _('Paiement trimestriel')
name = models.CharField(max_length=255, unique=True)
description = models.TextField(blank=True)
base_amount = models.DecimalField(max_digits=10, decimal_places=2)
discounts = models.JSONField(blank=True, null=True)
supplements = models.JSONField(blank=True, null=True)
validity_start_date = models.DateField()
validity_end_date = models.DateField()
payment_option = models.IntegerField(choices=PaymentOptions, default=PaymentOptions.SINGLE_PAYMENT)
def __str__(self):
return self.name
class Language(models.Model):
id = models.AutoField(primary_key=True)
label = models.CharField(max_length=200, default="")
def __str__(self):
return "LANGUAGE"
class Guardian(models.Model):
last_name = models.CharField(max_length=200, default="")
first_name = models.CharField(max_length=200, default="")
birth_date = models.CharField(max_length=200, default="", blank=True)
address = models.CharField(max_length=200, default="", blank=True)
email = models.CharField(max_length=200, default="", blank=True)
phone = models.CharField(max_length=200, default="", blank=True)
profession = models.CharField(max_length=200, default="", blank=True)
associated_profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
def __str__(self):
return self.last_name + "_" + self.first_name
class Sibling(models.Model):
id = models.AutoField(primary_key=True)
last_name = models.CharField(max_length=200, default="")
first_name = models.CharField(max_length=200, default="")
birth_date = models.CharField(max_length=200, default="", blank=True)
def __str__(self):
return "SIBLING"
class Student(models.Model):
class StudentGender(models.IntegerChoices):
NONE = 0, _('Sélection du genre')
MALE = 1, _('Garçon')
FEMALE = 2, _('Fille')
class StudentLevel(models.IntegerChoices):
NONE = 0, _('Sélection du niveau')
TPS = 1, _('TPS - Très Petite Section')
PS = 2, _('PS - Petite Section')
MS = 3, _('MS - Moyenne Section')
GS = 4, _('GS - Grande Section')
class PaymentMethod(models.IntegerChoices):
NONE = 0, _('Sélection du mode de paiement')
SEPA_DIRECT_DEBIT = 1, _('Prélèvement SEPA')
CHECK = 2, _('Chèques')
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)
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)
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)
payment_method = models.IntegerField(choices=PaymentMethod, default=PaymentMethod.NONE, blank=True)
# Many-to-Many Relationship
profiles = models.ManyToManyField(Profile, blank=True)
# Many-to-Many Relationship
guardians = models.ManyToManyField(Guardian, blank=True)
# Many-to-Many Relationship
siblings = models.ManyToManyField(Sibling, blank=True)
# Many-to-Many Relationship
spoken_languages = models.ManyToManyField(Language, blank=True)
# One-to-Many Relationship
associated_class = models.ForeignKey(SchoolClass, on_delete=models.SET_NULL, null=True, blank=True, related_name='students')
def __str__(self):
return self.last_name + "_" + self.first_name
def getSpokenLanguages(self):
return self.spoken_languages.all()
def getMainGuardian(self):
return self.guardians.all()[0]
def getGuardians(self):
return self.guardians.all()
def getProfiles(self):
return self.profiles.all()
def getSiblings(self):
return self.siblings.all()
def getNumberOfSiblings(self):
return self.siblings.count()
@property
def age(self):
if self.birth_date:
today = datetime.today()
years = today.year - self.birth_date.year
months = today.month - self.birth_date.month
if today.day < self.birth_date.day:
months -= 1
if months < 0:
years -= 1
months += 12
# Determine the age format
if 6 <= months <= 12:
return f"{years} years 1/2"
else:
return f"{years} years"
return None
@property
def formatted_birth_date(self):
if self.birth_date:
return self.birth_date.strftime('%d-%m-%Y')
return None
class RegistrationForm(models.Model):
class RegistrationFormStatus(models.IntegerChoices):
RF_ABSENT = 0, _('Pas de dossier d\'inscription')
RF_CREATED = 1, _('Dossier d\'inscription créé')
RF_SENT = 2, _('Dossier d\'inscription envoyé')
RF_UNDER_REVIEW = 3, _('Dossier d\'inscription en cours de validation')
RF_TO_BE_FOLLOWED_UP = 4, _('Dossier d\'inscription à relancer')
RF_VALIDATED = 5, _('Dossier d\'inscription validé')
RF_ARCHIVED = 6, _('Dossier d\'inscription archivé')
# One-to-One Relationship
student = models.OneToOneField(Student, on_delete=models.CASCADE, primary_key=True)
status = models.IntegerField(choices=RegistrationFormStatus, default=RegistrationFormStatus.RF_ABSENT)
last_update = models.DateTimeField(auto_now=True)
notes = models.CharField(max_length=200, blank=True)
registration_link_code = models.CharField(max_length=200, default="", blank=True)
registration_file = models.FileField(upload_to=settings.DOCUMENT_DIR, default="", blank=True)
associated_rf = models.CharField(max_length=200, default="", blank=True)
def __str__(self):
return "RF_" + self.student.last_name + "_" + self.student.first_name
class RegistrationFile(models.Model):
name = models.CharField(max_length=255)
file = models.FileField(upload_to='registration_files/')
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name

View File

@ -16,5 +16,5 @@ class CustomPagination(PageNumberPagination):
'count': self.page.paginator.count, 'count': self.page.paginator.count,
'page_size': self.page_size, 'page_size': self.page_size,
'max_page_size' : self.max_page_size, 'max_page_size' : self.max_page_size,
'fichesInscriptions': data } 'registerForms': data }
) )

View File

@ -0,0 +1,214 @@
from rest_framework import serializers
from .models import RegistrationFile, RegistrationForm, Student, Guardian, Sibling, Language, RegistrationFee
from School.models import SchoolClass
from Auth.models import Profile
from Auth.serializers import ProfileSerializer
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
class RegistrationFileSerializer(serializers.ModelSerializer):
class Meta:
model = RegistrationFile
fields = '__all__'
class RegistrationFeeSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = RegistrationFee
fields = '__all__'
class LanguageSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Language
fields = '__all__'
class SiblingSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Sibling
fields = '__all__'
class GuardianSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
associated_profile = serializers.PrimaryKeyRelatedField(queryset=Profile.objects.all(), required=True)
associated_profile_email = serializers.SerializerMethodField()
class Meta:
model = Guardian
fields = '__all__'
def get_associated_profile_email(self, obj):
return obj.associated_profile.email
class StudentSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
guardians = GuardianSerializer(many=True, required=False)
siblings = SiblingSerializer(many=True, required=False)
languages = LanguageSerializer(many=True, required=False)
associated_class_id = serializers.PrimaryKeyRelatedField(queryset=SchoolClass.objects.all(), source='associated_class', required=False, write_only=False, read_only=False)
age = serializers.SerializerMethodField()
formatted_birth_date = serializers.SerializerMethodField()
birth_date = serializers.DateField(input_formats=['%d-%m-%Y', '%Y-%m-%d'], required=False, allow_null=True)
associated_class_name = serializers.SerializerMethodField()
class Meta:
model = Student
fields = '__all__'
def get_or_create_packages(self, guardians_data):
guardians_ids = []
for guardian_data in guardians_data:
guardian_instance, created = Guardian.objects.get_or_create(
id=guardian_data.get('id'),
defaults=guardian_data
)
guardians_ids.append(guardian_instance.id)
return guardians_ids
def create(self, validated_data):
guardians_data = validated_data.pop('guardians', [])
siblings_data = validated_data.pop('siblings', [])
languages_data = validated_data.pop('spoken_languages', [])
student = Student.objects.create(**validated_data)
student.guardians.set(self.get_or_create_packages(guardians_data))
student.siblings.set(self.get_or_create_packages(siblings_data))
student.spoken_languages.set(self.get_or_create_packages(languages_data))
return student
def create_or_update_packages(self, guardians_data):
guardians_ids = []
for guardian_data in guardians_data:
guardian_instance, created = Guardian.objects.update_or_create(
id=guardian_data.get('id'),
defaults=guardian_data
)
guardians_ids.append(guardian_instance.id)
return guardians_ids
def update(self, instance, validated_data):
guardians_data = validated_data.pop('guardians', [])
siblings_data = validated_data.pop('siblings', [])
languages_data = validated_data.pop('spoken_languages', [])
if guardians_data:
instance.guardians.set(self.create_or_update_packages(guardians_data))
if siblings_data:
instance.siblings.set(self.create_or_update_packages(siblings_data))
if languages_data:
instance.spoken_languages.set(self.create_or_update_packages(languages_data))
for field in self.fields:
try:
setattr(instance, field, validated_data[field])
except KeyError:
pass
instance.save()
return instance
def get_age(self, obj):
return obj.age
def get_formatted_birth_date(self, obj):
return obj.formatted_birth_date
def get_associated_class_name(self, obj):
return obj.associated_class.atmosphereName if obj.associated_class else None
class RegistrationFormSerializer(serializers.ModelSerializer):
student = StudentSerializer(many=False, required=False)
registration_file = serializers.FileField(required=False)
status_label = serializers.SerializerMethodField()
formatted_last_update = serializers.SerializerMethodField()
class Meta:
model = RegistrationForm
fields = '__all__'
def create(self, validated_data):
student_data = validated_data.pop('student')
student = StudentSerializer.create(StudentSerializer(), student_data)
registrationForm = RegistrationForm.objects.create(student=student, **validated_data)
return registrationForm
def update(self, instance, validated_data):
student_data = validated_data.pop('student', None)
if student_data:
student = instance.student
StudentSerializer.update(StudentSerializer(), student, student_data)
for field in self.fields:
try:
setattr(instance, field, validated_data[field])
except KeyError:
pass
instance.save()
return instance
def get_status_label(self, obj):
return obj.get_status_display()
def get_formatted_last_update(self, obj):
utc_time = timezone.localtime(obj.last_update) # Convert to local time
local_tz = pytz.timezone(settings.TZ_APPLI)
local_time = utc_time.astimezone(local_tz)
return local_time.strftime("%d-%m-%Y %H:%M")
class StudentByParentSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Student
fields = ['id', 'last_name', 'first_name']
def __init__(self, *args, **kwargs):
super(StudentByParentSerializer, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
class RegistrationFormByParentSerializer(serializers.ModelSerializer):
student = StudentByParentSerializer(many=False, required=True)
class Meta:
model = RegistrationForm
fields = ['student', 'status']
def __init__(self, *args, **kwargs):
super(RegistrationFormByParentSerializer, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
class GuardianByDICreationSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
class Meta:
model = Guardian
fields = ['id', 'last_name', 'first_name', 'email', 'associated_profile']
class StudentByRFCreationSerializer(serializers.ModelSerializer):
id = serializers.IntegerField(required=False)
guardians = GuardianByDICreationSerializer(many=True, required=False)
class Meta:
model = Student
fields = ['id', 'last_name', 'first_name', 'guardians']
def __init__(self, *args, **kwargs):
super(StudentByRFCreationSerializer, self).__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].required = False
class NotificationSerializer(serializers.ModelSerializer):
notification_type_label = serializers.ReadOnlyField()
class Meta:
model = Notification
fields = '__all__'

View File

@ -1,8 +1,8 @@
from django.db.models.signals import post_save, post_delete, m2m_changed from django.db.models.signals import post_save, post_delete, m2m_changed
from django.dispatch import receiver from django.dispatch import receiver
from django.core.cache import cache from django.core.cache import cache
from GestionInscriptions.models import FicheInscription, Eleve, Responsable from .models import RegistrationForm, Student, Guardian
from GestionLogin.models import Profil from Auth.models import Profile
from N3wtSchool import settings from N3wtSchool import settings
from N3wtSchool.redis_client import redis_client from N3wtSchool.redis_client import redis_client
import logging import logging
@ -20,25 +20,25 @@ def clear_cache():
redis_client.delete(key) redis_client.delete(key)
logger.debug(f'deleting : {key}') logger.debug(f'deleting : {key}')
@receiver(post_save, sender=FicheInscription) @receiver(post_save, sender=RegistrationForm)
@receiver(post_delete, sender=FicheInscription) @receiver(post_delete, sender=RegistrationForm)
def clear_cache_after_change(sender, instance, **kwargs): def clear_cache_after_change(sender, instance, **kwargs):
clear_cache() clear_cache()
@receiver(m2m_changed, sender=Eleve.responsables.through) @receiver(m2m_changed, sender=Student.guardians.through)
def check_orphan_reponsables(sender, **kwargs): def check_orphan_reponsables(sender, **kwargs):
action = kwargs.pop('action', None) action = kwargs.pop('action', None)
instance = kwargs.pop('instance', None) instance = kwargs.pop('instance', None)
# pre_clear : lors de la suppression d'une FI (on fait un "clear" sur chaque relation) # pre_clear : lors de la suppression d'une FI (on fait un "clear" sur chaque relation)
if action in ('post_remove', 'post_clear'): if action in ('post_remove', 'post_clear'):
if instance.responsables.all(): if instance.guardians.all():
Responsable.objects.filter(eleve=None).delete() Guardian.objects.filter(eleve=None).delete()
@receiver(m2m_changed, sender=Eleve.profils.through) @receiver(m2m_changed, sender=Student.profiles.through)
def check_orphan_profils(sender, **kwargs): def check_orphan_profils(sender, **kwargs):
action = kwargs.pop('action', None) action = kwargs.pop('action', None)
instance = kwargs.pop('instance', None) instance = kwargs.pop('instance', None)
# pre_clear : lors de la suppression d'une FI (on fait un "clear" sur chaque relation) # pre_clear : lors de la suppression d'une FI (on fait un "clear" sur chaque relation)
if action in ('post_remove', 'post_clear'): if action in ('post_remove', 'post_clear'):
if instance.profils.all(): if instance.profiles.all():
Profil.objects.filter(eleve=None).delete() Profile.objects.filter(eleve=None).delete()

View File

@ -1,8 +1,8 @@
# tasks.py # tasks.py
from celery import shared_task from celery import shared_task
from django.utils import timezone from django.utils import timezone
from GestionInscriptions.automate import Automate_DI_Inscription, updateStateMachine from Subscriptions.automate import Automate_RF_Register, updateStateMachine
from .models import FicheInscription from .models import RegistrationForm
from GestionMessagerie.models import Messagerie from GestionMessagerie.models import Messagerie
from N3wtSchool import settings, bdd from N3wtSchool import settings, bdd
import requests import requests
@ -15,7 +15,7 @@ def check_for_signature_deadlines():
deadline = now - timezone.timedelta(days=settings.EXPIRATION_DI_NB_DAYS) deadline = now - timezone.timedelta(days=settings.EXPIRATION_DI_NB_DAYS)
# deadline = now - timezone.timedelta(seconds=settings.EXPIRATION_DI_NB_DAYS) # deadline = now - timezone.timedelta(seconds=settings.EXPIRATION_DI_NB_DAYS)
dossiers_en_attente = FicheInscription.objects.filter(etat=FicheInscription.EtatDossierInscription.DI_ENVOYE, dateMAJ__lt=deadline) dossiers_en_attente = RegistrationForm.objects.filter(etat=RegistrationForm.RegistrationFormStatus.DI_ENVOYE, dateMAJ__lt=deadline)
for dossier in dossiers_en_attente: for dossier in dossiers_en_attente:
send_notification(dossier) send_notification(dossier)
@ -28,7 +28,7 @@ def send_notification(dossier):
url = settings.URL_DJANGO + 'GestionMessagerie/message' url = settings.URL_DJANGO + 'GestionMessagerie/message'
destinataires = dossier.eleve.profils.all() destinataires = dossier.eleve.profiles.all()
for destinataire in destinataires: for destinataire in destinataires:
message = { message = {
"objet": "[RELANCE]", "objet": "[RELANCE]",

View File

@ -3,7 +3,7 @@
{% block content %} {% block content %}
<h1>Création d'une nouvelle fiche d'inscription</h1> <h1>Création d'une nouvelle fiche d'inscription</h1>
<br> <br>
<form action='{% url 'GestionInscriptions:nouvelEleve' %}' method="post"> <form action='{% url 'Subscriptions:nouvelEleve' %}' method="post">
{% csrf_token %} {% csrf_token %}
<ul> <ul>
<li style="margin-bottom: 15px"><strong>ELEVE</strong></li> <li style="margin-bottom: 15px"><strong>ELEVE</strong></li>

View File

@ -2,7 +2,7 @@
{% block content %} {% block content %}
<h1>Configuration des dossiers d'inscriptions</h1> <h1>Configuration des dossiers d'inscriptions</h1>
<br> <br>
<form action='{% url 'GestionInscriptions:index' %}' method="post"> <form action='{% url 'Subscriptions:index' %}' method="post">
{% csrf_token %} {% csrf_token %}
<ul> <ul>
<div style="margin-bottom: 15px"> <div style="margin-bottom: 15px">

View File

@ -2,9 +2,9 @@
{% block content %} {% block content %}
<h1>Création du dossier d'inscription</h1> <h1>Création du dossier d'inscription</h1>
<br> <br>
<form action='{% url 'GestionInscriptions:validate' eleve.id %}' method="post" enctype="multipart/form-data"> <form action='{% url 'Subscriptions:validate' eleve.id %}' method="post" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{% with responsable=eleve.getResponsablePrincipal %} {% with responsable=eleve.getMainGuardian %}
<ul> <ul>
<li style="margin-bottom: 15px"><strong>ELEVE</strong></li> <li style="margin-bottom: 15px"><strong>ELEVE</strong></li>
<div style="margin-bottom: 15px"> <div style="margin-bottom: 15px">

View File

@ -2,9 +2,9 @@
{% block content %} {% block content %}
<h1>Edition d'une fiche d'inscription</h1> <h1>Edition d'une fiche d'inscription</h1>
<br> <br>
<form action='{% url 'GestionInscriptions:index' %}' method="post"> <form action='{% url 'Subscriptions:index' %}' method="post">
{% csrf_token %} {% csrf_token %}
{% with responsable=eleve.getResponsablePrincipal %} {% with responsable=eleve.getMainGuardian %}
<ul> <ul>
<div style="margin-bottom: 15px"> <div style="margin-bottom: 15px">
<input type="hidden" name="fiche_id" value="{{ eleve.id }}"> <input type="hidden" name="fiche_id" value="{{ eleve.id }}">

View File

@ -47,22 +47,22 @@
</thead> </thead>
<tbody> <tbody>
{% for ficheInscription in ficheInscriptions_list %} {% for registerForm in ficheInscriptions_list %}
{% with eleve=ficheInscription.eleve %} {% with eleve=registerForm.eleve %}
{% with responsable=eleve.getResponsablePrincipal %} {% with responsable=eleve.getMainGuardian %}
{% with fichiers=ficheInscription|recupereFichiersDossierInscription %} {% with fichiers=registerForm|recupereFichiersDossierInscription %}
<tr> <tr>
<td>{{ eleve.nom }}</td> <td>{{ eleve.nom }}</td>
<td>{{ eleve.prenom }}</td> <td>{{ eleve.prenom }}</td>
<td>{{ responsable.mail }}</td> <td>{{ responsable.mail }}</td>
<td>{{ responsable.telephone }}</td> <td>{{ responsable.telephone }}</td>
<td>{{ ficheInscription.dateMAJ }}</td> <td>{{ registerForm.dateMAJ }}</td>
<td> <td>
{% if ficheInscription.etat == 0 %} {% if registerForm.etat == 0 %}
<span class="tag blue"> Créé</span> <span class="tag blue"> Créé</span>
{% elif ficheInscription.etat == 1 %} {% elif registerForm.etat == 1 %}
<span class="tag orange"> Envoyé</span> <span class="tag orange"> Envoyé</span>
{% elif ficheInscription.etat == 2 %} {% elif registerForm.etat == 2 %}
<span class="tag purple"> En Validation</span> <span class="tag purple"> En Validation</span>
{% else %} {% else %}
<span class="tag green"> Validé</span> <span class="tag green"> Validé</span>
@ -74,7 +74,7 @@
{% endfor %} {% endfor %}
</td> </td>
<td class="actions"> <td class="actions">
<button class="icon-btn" onclick="location.href='{% url 'GestionInscriptions:send' eleve.id %}'" type="submit"> <i class="icon directbox-send"></i></button> <button class="icon-btn" onclick="location.href='{% url 'Subscriptions:send' eleve.id %}'" type="submit"> <i class="icon directbox-send"></i></button>
<button class="icon-btn"> <i class="icon edit"></i></button> <button class="icon-btn"> <i class="icon edit"></i></button>
<button class="icon-btn red"> <i class="icon user-minus"></i></button> <button class="icon-btn red"> <i class="icon user-minus"></i></button>
</td> </td>

View File

@ -45,49 +45,49 @@
</div> </div>
<div> <div>
<div class='details'> <div class='details'>
Signé le : <b>{{ dateSignature }}</b> <br/> Signé le : <b>{{ signatureDate }}</b> <br/>
A : <b>{{ heureSignature }}</b> A : <b>{{ signatureTime }}</b>
<hr class='hrItem' /> <hr class='hrItem' />
<h1>ELEVE</h1> <h1>ELEVE</h1>
{% with niveau=eleve|recupereNiveauEleve %} {% with level=student|getStudentLevel %}
{% with genre=eleve|recupereGenreEleve %} {% with gender=student|getStudentGender %}
NOM : <b>{{ eleve.nom }}</b> <br/> NOM : <b>{{ student.last_name }}</b> <br/>
PRENOM : <b>{{ eleve.prenom }}</b> <br/> PRENOM : <b>{{ student.first_name }}</b> <br/>
ADRESSE : <b>{{ eleve.adresse }}</b> <br/> ADRESSE : <b>{{ student.address }}</b> <br/>
GENRE : <b>{{ genre }}</b> <br/> GENRE : <b>{{ gender }}</b> <br/>
NE(E) LE : <b>{{ eleve.dateNaissance }}</b> <br/> NE(E) LE : <b>{{ student.birth_date }}</b> <br/>
A : <b>{{ eleve.lieuNaissance }} ({{ eleve.codePostalNaissance }})</b> <br/> A : <b>{{ student.birth_place }} ({{ student.birth_postal_code }})</b> <br/>
NATIONALITE : <b>{{ eleve.nationalite }}</b> <br/> NATIONALITE : <b>{{ student.nationality }}</b> <br/>
NIVEAU : <b>{{ niveau }}</b> <br/> NIVEAU : <b>{{ level }}</b> <br/>
MEDECIN TRAITANT : <b>{{ eleve.medecinTraitant }}</b> <br/> MEDECIN TRAITANT : <b>{{ student.attending_physician }}</b> <br/>
{% endwith %} {% endwith %}
{% endwith %} {% endwith %}
<hr class='hrItem' /> <hr class='hrItem' />
<h1>RESPONSABLES</h1> <h1>RESPONSABLES</h1>
{% with responsables_List=eleve.getResponsables %} {% with guardians=student.getGuardians %}
{% with freres_List=eleve.getFreres %} {% with siblings=student.getGuardians %}
{% for responsable in responsables_List%} {% for guardian in guardians%}
<h2>Responsable {{ forloop.counter }}</h2> <h2>Guardian {{ forloop.counter }}</h2>
NOM : <b>{{ responsable.nom }}</b> <br/> NOM : <b>{{ guardian.last_name }}</b> <br/>
PRENOM : <b>{{ responsable.prenom }}</b> <br/> PRENOM : <b>{{ guardian.first_name }}</b> <br/>
ADRESSE : <b>{{ responsable.adresse }}</b> <br/> ADRESSE : <b>{{ guardian.address }}</b> <br/>
NE(E) LE : <b>{{ responsable.dateNaissance }}</b> <br/> NE(E) LE : <b>{{ guardian.birth_date }}</b> <br/>
MAIL : <b>{{ responsable.mail }}</b> <br/> MAIL : <b>{{ guardian.email }}</b> <br/>
TEL : <b>{{ responsable.telephone }}</b> <br/> TEL : <b>{{ guardian.phone }}</b> <br/>
PROFESSION : <b>{{ responsable.profession }}</b> <br/> PROFESSION : <b>{{ guardian.profession }}</b> <br/>
{% endfor %} {% endfor %}
<hr class='hrItem' /> <hr class='hrItem' />
<h1>FRATRIE</h1> <h1>FRATRIE</h1>
{% for frere in freres_List%} {% for sibling in siblings%}
<h2>Frère - Soeur {{ forloop.counter }}</h2> <h2>Frère - Soeur {{ forloop.counter }}</h2>
NOM : <b>{{ frere.nom }}</b> <br/> NOM : <b>{{ sibling.last_name }}</b> <br/>
PRENOM : <b>{{ frere.prenom }}</b> <br/> PRENOM : <b>{{ sibling.first_name }}</b> <br/>
NE(E) LE : <b>{{ frere.dateNaissance }}</b> <br/> NE(E) LE : <b>{{ sibling.birth_date }}</b> <br/>
{% endfor %} {% endfor %}
<hr class='hrItem' /> <hr class='hrItem' />
<h1>MODALITES DE PAIEMENT</h1> <h1>MODALITES DE PAIEMENT</h1>
{% with modePaiement=eleve|recupereModePaiement %} {% with paymentMethod=student|getStudentPaymentMethod %}
<b>{{ modePaiement }}</b> <br/> <b>{{ paymentMethod }}</b> <br/>
{% endwith %} {% endwith %}
{% endwith %} {% endwith %}
{% endwith %} {% endwith %}

View File

@ -0,0 +1,18 @@
from Subscriptions.models import RegistrationForm, Student
from django import template
register = template.Library()
@register.filter
def getStudentPaymentMethod(pk):
registerForm = RegistrationForm.objects.get(student=pk)
return Student.PaymentMethod(int(registerForm.student.payment_method)).label
@register.filter
def getStudentLevel(pk):
registerForm = RegistrationForm.objects.get(student=pk)
return Student.StudentLevel(int(registerForm.student.level)).label
@register.filter
def getStudentGender(pk):
registerForm = RegistrationForm.objects.get(student=pk)
return Student.StudentGender(int(registerForm.student.gender)).label

View File

@ -0,0 +1,36 @@
from django.urls import path, re_path
from . import views
from Subscriptions.views import RegisterFileTemplateView, RegisterFormListView, RegisterFormView, StudentView, GuardianView, ChildrenListView, StudentListView, RegisterFeeView
urlpatterns = [
re_path(r'^registerForms/([a-zA-z]+)$', RegisterFormListView.as_view(), name="listefichesInscriptions"),
re_path(r'^registerForm$', RegisterFormView.as_view(), name="registerForms"),
re_path(r'^registerForm/([0-9]+)$', RegisterFormView.as_view(), name="registerForms"),
# Page de formulaire d'inscription - ELEVE
re_path(r'^student/([0-9]+)$', StudentView.as_view(), name="students"),
# Page de formulaire d'inscription - RESPONSABLE
re_path(r'^fetchLastGuardian$', GuardianView.as_view(), name="fetchLastGuardian"),
# Envoi d'un dossier d'inscription
re_path(r'^send/([0-9]+)$', views.send, name="send"),
# Archivage d'un dossier d'inscription
re_path(r'^archive/([0-9]+)$', views.archive, name="archive"),
# Envoi d'une relance de dossier d'inscription
re_path(r'^sendRelance/([0-9]+)$', views.relance, name="relance"),
# Page PARENT - Liste des children
re_path(r'^children/([0-9]+)$', ChildrenListView.as_view(), name="children"),
# Page INSCRIPTION - Liste des élèves
re_path(r'^students$', StudentListView.as_view(), name="students"),
# Frais d'inscription
re_path(r'^registerFees$', RegisterFeeView.as_view(), name="registerFees"),
re_path(r'^registerFilesTemplates$', RegisterFileTemplateView.as_view(), name='registerFilesTemplates'),
re_path(r'^registerFilesTemplates/([0-9]+)$', RegisterFileTemplateView.as_view(), name="registerFilesTemplates"),
]

View File

@ -0,0 +1,82 @@
from django.shortcuts import render,get_object_or_404,get_list_or_404
from .models import RegistrationForm, Student, Guardian, Sibling
import time
from datetime import date, datetime, timedelta
from zoneinfo import ZoneInfo
from django.conf import settings
from N3wtSchool import renderers
from N3wtSchool import bdd
from io import BytesIO
from django.core.files import File
from pathlib import Path
import os
from enum import Enum
import random
import string
from rest_framework.parsers import JSONParser
def recupereListeFichesInscription():
context = {
"ficheInscriptions_list": bdd.getAllObjects(RegistrationForm),
}
return context
def recupereListeFichesInscriptionEnAttenteSEPA():
ficheInscriptionsSEPA_list = RegistrationForm.objects.filter(modePaiement="Prélèvement SEPA").filter(etat=RegistrationForm.RegistrationFormStatus['SEPA_ENVOYE'])
return ficheInscriptionsSEPA_list
def _now():
return datetime.now(ZoneInfo(settings.TZ_APPLI))
def convertToStr(dateValue, dateFormat):
return dateValue.strftime(dateFormat)
def convertToDate(date_time):
format = '%d-%m-%Y %H:%M'
datetime_str = datetime.strptime(date_time, format)
return datetime_str
def convertTelephone(telephoneValue, separator='-'):
return f"{telephoneValue[:2]}{separator}{telephoneValue[2:4]}{separator}{telephoneValue[4:6]}{separator}{telephoneValue[6:8]}{separator}{telephoneValue[8:10]}"
def genereRandomCode(length):
return ''.join(random.choice(string.ascii_letters) for i in range(length))
def calculeDatePeremption(_start, nbDays):
return convertToStr(_start + timedelta(days=nbDays), settings.DATE_FORMAT)
# Fonction permettant de retourner la valeur du QueryDict
# QueryDict [ index ] -> Dernière valeur d'une liste
# dict (QueryDict [ index ]) -> Toutes les valeurs de la liste
def _(liste):
return liste[0]
def getArgFromRequest(_argument, _request):
resultat = None
data=JSONParser().parse(_request)
resultat = data[_argument]
return resultat
def rfToPDF(registerForm):
# Ajout du fichier d'inscriptions
data = {
'pdf_title': "Dossier d'inscription de %s"%registerForm.student.first_name,
'signatureDate': convertToStr(_now(), '%d-%m-%Y'),
'signatureTime': convertToStr(_now(), '%H:%M'),
'student':registerForm.student,
}
pdf = renderers.render_to_pdf('pdfs/dossier_inscription.html', data)
PDFFileName = "Dossier_Inscription_%s_%s.pdf"%(registerForm.student.last_name, registerForm.student.first_name)
pathFichier = Path(settings.DOCUMENT_DIR + "/" + PDFFileName)
if os.path.exists(str(pathFichier)):
print(f'File exists : {str(pathFichier)}')
os.remove(str(pathFichier))
receipt_file = BytesIO(pdf.content)
registerForm.fichierInscription = File(receipt_file, PDFFileName)

View File

@ -0,0 +1,280 @@
from django.http.response import JsonResponse
from django.contrib.auth import login, authenticate, get_user_model
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
from django.utils.decorators import method_decorator
from django.core.cache import cache
from django.core.paginator import Paginator
from django.core.files import File
from django.db.models import Q # Ajout de cet import
from rest_framework.parsers import JSONParser,MultiPartParser, FormParser
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
import json
from pathlib import Path
import os
from io import BytesIO
import Subscriptions.mailManager as mailer
import Subscriptions.util as util
from Subscriptions.serializers import RegistrationFormSerializer, RegistrationFileSerializer, StudentSerializer, RegistrationFormByParentSerializer, StudentByRFCreationSerializer, RegistrationFeeSerializer
from Subscriptions.pagination import CustomPagination
from Subscriptions.signals import clear_cache
from .models import Student, Guardian, RegistrationForm, RegistrationFee, RegistrationFile
from Subscriptions.automate import Automate_RF_Register, load_config, getStateMachineObjectState, updateStateMachine
from Auth.models import Profile
from N3wtSchool import settings, renderers, bdd
class RegisterFormListView(APIView):
pagination_class = CustomPagination
def get_register_form(self, _filter, search=None):
"""
Récupère les fiches d'inscriptions en fonction du filtre passé.
_filter: Filtre pour déterminer l'état des fiches ('pending', 'archived', 'subscribed')
search: Terme de recherche (optionnel)
"""
if _filter == 'pending':
exclude_states = [RegistrationForm.RegistrationFormStatus.RF_VALIDATED, RegistrationForm.RegistrationFormStatus.RF_ARCHIVED]
return bdd.searchObjects(RegistrationForm, search, _excludeStates=exclude_states)
elif _filter == 'archived':
return bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_ARCHIVED)
elif _filter == 'subscribed':
return bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_VALIDATED)
return None
def get(self, request, _filter):
# Récupération des paramètres
search = request.GET.get('search', '').strip()
page_size = request.GET.get('page_size', None)
# Gestion du page_size
if page_size is not None:
try:
page_size = int(page_size)
except ValueError:
page_size = settings.NB_RESULT_PER_PAGE
# Définir le cache_key en fonction du filtre
page_number = request.GET.get('page', 1)
cache_key = f'N3WT_ficheInscriptions_{_filter}_page_{page_number}_search_{search if _filter == "pending" else ""}'
cached_page = cache.get(cache_key)
if cached_page:
return JsonResponse(cached_page, safe=False)
# Récupérer les fiches d'inscriptions en fonction du filtre
registerForms_List = self.get_register_form(_filter, search)
if not registerForms_List:
return JsonResponse({'error' : 'aucune donnée trouvée', 'count' :0}, safe=False)
# Pagination
paginator = self.pagination_class()
page = paginator.paginate_queryset(registerForms_List, request)
if page is not None:
registerForms_serializer = RegistrationFormSerializer(page, many=True)
response_data = paginator.get_paginated_response(registerForms_serializer.data)
cache.set(cache_key, response_data, timeout=60*15)
return JsonResponse(response_data, safe=False)
return JsonResponse({'error' : 'aucune donnée trouvée', 'count' :0}, safe=False)
def post(self, request):
studentFormList_serializer=JSONParser().parse(request)
for studentForm_data in studentFormList_serializer:
# Ajout de la date de mise à jour
studentForm_data["last_update"] = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
json.dumps(studentForm_data)
# Ajout du code d'inscription
code = util.genereRandomCode(12)
studentForm_data["codeLienInscription"] = code
studentForm_serializer = RegistrationFormSerializer(data=studentForm_data)
if studentForm_serializer.is_valid():
studentForm_serializer.save()
return JsonResponse(studentForm_serializer.errors, safe=False)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
class RegisterFormView(APIView):
pagination_class = CustomPagination
def get(self, request, _id):
registerForm=bdd.getObject(RegistrationForm, "student__id", _id)
registerForm_serializer=RegistrationFormSerializer(registerForm)
return JsonResponse(registerForm_serializer.data, safe=False)
def post(self, request):
studentForm_data=JSONParser().parse(request)
# Ajout de la date de mise à jour
studentForm_data["last_update"] = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
json.dumps(studentForm_data)
# Ajout du code d'inscription
code = util.genereRandomCode(12)
studentForm_data["codeLienInscription"] = code
guardiansId = studentForm_data.pop('idGuardians', [])
studentForm_serializer = RegistrationFormSerializer(data=studentForm_data)
if studentForm_serializer.is_valid():
di = studentForm_serializer.save()
# Mise à jour de l'automate
updateStateMachine(di, 'creationDI')
# Récupération du reponsable associé
for guardianId in guardiansId:
guardian = Guardian.objects.get(id=guardianId)
di.student.guardians.add(guardian)
di.save()
return JsonResponse(studentForm_serializer.data, safe=False)
return JsonResponse(studentForm_serializer.errors, safe=False)
def put(self, request, id):
studentForm_data=JSONParser().parse(request)
status = studentForm_data.pop('status', 0)
studentForm_data["last_update"] = str(util.convertToStr(util._now(), '%d-%m-%Y %H:%M'))
registerForm = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
# Le parent a complété le dossier d'inscription, il est soumis à validation par l'école
json.dumps(studentForm_data)
util.rfToPDF(registerForm)
# Mise à jour de l'automate
updateStateMachine(registerForm, 'saisiDI')
elif status == RegistrationForm.RegistrationFormStatus.RF_VALIDATED:
# L'école a validé le dossier d'inscription
# Mise à jour de l'automate
updateStateMachine(registerForm, 'valideDI')
studentForm_serializer = RegistrationFormSerializer(registerForm, data=studentForm_data)
if studentForm_serializer.is_valid():
studentForm_serializer.save()
return JsonResponse(studentForm_serializer.data, safe=False)
return JsonResponse(studentForm_serializer.errors, safe=False)
def delete(self, request, id):
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
student = register_form.student
student.guardians.clear()
student.profiles.clear()
student.delete()
clear_cache()
return JsonResponse("La suppression du dossier a été effectuée avec succès", safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False)
class StudentView(APIView):
def get(self, request, _id):
student = bdd.getObject(_objectName=Student, _columnName='id', _value=_id)
student_serializer = StudentSerializer(student)
return JsonResponse(student_serializer.data, safe=False)
class GuardianView(APIView):
def get(self, request):
lastGuardian = bdd.getLastId(Guardian)
return JsonResponse({"lastid":lastGuardian}, safe=False)
def send(request, id):
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
student = register_form.student
guardian = student.getMainGuardian()
email = guardian.email
errorMessage = mailer.sendRegisterForm(email)
if errorMessage == '':
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
# Mise à jour de l'automate
updateStateMachine(register_form, 'envoiDI')
return JsonResponse({"errorMessage":errorMessage}, safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False)
def archive(request, id):
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
# Mise à jour de l'automate
updateStateMachine(register_form, 'archiveDI')
return JsonResponse({"errorMessage":''}, safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False)
def relance(request, id):
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
student = register_form.student
guardian = student.getMainGuardian()
email = guardian.email
errorMessage = mailer.envoieRelanceDossierInscription(email, register_form.codeLienInscription)
if errorMessage == '':
register_form.status=RegistrationForm.RegistrationFormStatus.RF_SENT
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
register_form.save()
return JsonResponse({"errorMessage":errorMessage}, safe=False)
return JsonResponse({"errorMessage":'Aucun dossier d\'inscription rattaché à l\'élève'}, safe=False)
# API utilisée pour la vue parent
class ChildrenListView(APIView):
# Récupération des élèves d'un parent
# idProfile : identifiant du profil connecté rattaché aux fiches d'élèves
def get(self, request, _idProfile):
students = bdd.getObjects(_objectName=RegistrationForm, _columnName='student__guardians__profilAssocie__id', _value=_idProfile)
students_serializer = RegistrationFormByParentSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)
# API utilisée pour la vue de création d'un DI
class StudentListView(APIView):
# Récupération de la liste des élèves inscrits ou en cours d'inscriptions
def get(self, request):
students = bdd.getAllObjects(_objectName=Student)
students_serializer = StudentByRFCreationSerializer(students, many=True)
return JsonResponse(students_serializer.data, safe=False)
# API utilisée pour la vue de personnalisation des frais d'inscription pour la structure
class RegisterFeeView(APIView):
def get(self, request):
tarifs = bdd.getAllObjects(RegistrationFee)
tarifs_serializer = RegistrationFeeSerializer(tarifs, many=True)
return JsonResponse(tarifs_serializer.data, safe=False)
class RegisterFileTemplateView(APIView):
parser_classes = (MultiPartParser, FormParser)
def get(self, request):
fichiers = RegistrationFile.objects.all()
serializer = RegistrationFormSerializer(fichiers, many=True)
return Response(serializer.data)
def post(self, request):
serializer = RegistrationFormSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, _id):
fichierInscription = bdd.getObject(_objectName=RegistrationFile, _columnName='id', _value=_id)
if fichierInscription is not None:
fichierInscription.file.delete() # Supprimer le fichier uploadé
fichierInscription.delete()
return JsonResponse({'message': 'La suppression du fichier d\'inscription a été effectuée avec succès'}, safe=False)
else:
return JsonResponse({'erreur': 'Le fichier d\'inscription n\'a pas été trouvé'}, safe=False)

View File

@ -13,11 +13,11 @@ def run_command(command):
commands = [ commands = [
["python", "manage.py", "collectstatic", "--noinput"], ["python", "manage.py", "collectstatic", "--noinput"],
["python", "manage.py", "flush", "--noinput"], ["python", "manage.py", "flush", "--noinput"],
["python", "manage.py", "makemigrations", "GestionInscriptions"], ["python", "manage.py", "makemigrations", "Subscriptions"],
["python", "manage.py", "makemigrations", "GestionNotification"], ["python", "manage.py", "makemigrations", "GestionNotification"],
["python", "manage.py", "makemigrations", "GestionMessagerie"], ["python", "manage.py", "makemigrations", "GestionMessagerie"],
["python", "manage.py", "makemigrations", "GestionLogin"], ["python", "manage.py", "makemigrations", "Auth"],
["python", "manage.py", "makemigrations", "GestionEnseignants"], ["python", "manage.py", "makemigrations", "School"],
["python", "manage.py", "migrate"] ["python", "manage.py", "migrate"]
] ]