mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
refactor: Traduction en anglais des modules "GestionInscription" et
"GestionLogin"
This commit is contained in:
@ -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'
|
||||||
|
|
||||||
@ -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
|
||||||
|
|
||||||
@ -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')
|
||||||
@ -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
22
Back-End/Auth/urls.py
Normal 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"),
|
||||||
|
]
|
||||||
@ -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'):
|
||||||
@ -1 +0,0 @@
|
|||||||
default_app_config = 'GestionEnseignants.apps.GestionenseignantsConfig'
|
|
||||||
@ -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)
|
|
||||||
@ -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}'
|
|
||||||
|
|
||||||
|
|
||||||
@ -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())
|
|
||||||
@ -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"),
|
|
||||||
]
|
|
||||||
@ -1 +0,0 @@
|
|||||||
default_app_config = 'GestionInscriptions.apps.GestionInscriptionsConfig'
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
@ -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__'
|
|
||||||
@ -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
|
|
||||||
@ -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"),
|
|
||||||
]
|
|
||||||
@ -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)
|
|
||||||
@ -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)
|
|
||||||
@ -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"),
|
|
||||||
]
|
|
||||||
@ -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):
|
||||||
|
|||||||
@ -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):
|
||||||
|
|||||||
@ -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)
|
||||||
|
|||||||
@ -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
|
||||||
)
|
)
|
||||||
|
|||||||
@ -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
|
||||||
|
|
||||||
|
|||||||
@ -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})")
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
)
|
)
|
||||||
@ -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'),
|
||||||
|
|||||||
1
Back-End/School/__init__.py
Normal file
1
Back-End/School/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
default_app_config = 'School.apps.SchoolConfig'
|
||||||
14
Back-End/School/apps.py
Normal file
14
Back-End/School/apps.py
Normal 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
66
Back-End/School/models.py
Normal 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}'
|
||||||
194
Back-End/School/serializers.py
Normal file
194
Back-End/School/serializers.py
Normal 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
21
Back-End/School/urls.py
Normal 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"),
|
||||||
|
]
|
||||||
@ -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')
|
||||||
1
Back-End/Subscriptions/__init__.py
Normal file
1
Back-End/Subscriptions/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
default_app_config = 'Subscriptions.apps.GestionInscriptionsConfig'
|
||||||
@ -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):
|
||||||
@ -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()
|
||||||
45
Back-End/Subscriptions/automate.py
Normal file
45
Back-End/Subscriptions/automate.py
Normal 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
|
||||||
@ -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)
|
||||||
179
Back-End/Subscriptions/models.py
Normal file
179
Back-End/Subscriptions/models.py
Normal 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
|
||||||
@ -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 }
|
||||||
)
|
)
|
||||||
214
Back-End/Subscriptions/serializers.py
Normal file
214
Back-End/Subscriptions/serializers.py
Normal 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__'
|
||||||
@ -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()
|
||||||
@ -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]",
|
||||||
@ -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>
|
||||||
@ -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">
|
||||||
@ -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">
|
||||||
@ -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 }}">
|
||||||
@ -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>
|
||||||
@ -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 %}
|
||||||
18
Back-End/Subscriptions/templatetags/myTemplateTag.py
Normal file
18
Back-End/Subscriptions/templatetags/myTemplateTag.py
Normal 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
|
||||||
36
Back-End/Subscriptions/urls.py
Normal file
36
Back-End/Subscriptions/urls.py
Normal 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"),
|
||||||
|
]
|
||||||
82
Back-End/Subscriptions/util.py
Normal file
82
Back-End/Subscriptions/util.py
Normal 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)
|
||||||
280
Back-End/Subscriptions/views.py
Normal file
280
Back-End/Subscriptions/views.py
Normal 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)
|
||||||
@ -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"]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user