mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
chore: Initial Commit
feat: Gestion des inscriptions [#1] feat(frontend): Création des vues pour le paramétrage de l'école [#2] feat: Gestion du login [#6] fix: Correction lors de la migration des modèle [#8] feat: Révision du menu principal [#9] feat: Ajout d'un footer [#10] feat: Création des dockers compose pour les environnements de développement et de production [#12] doc(ci): Mise en place de Husky et d'un suivi de version automatique [#14]
This commit is contained in:
@ -0,0 +1,4 @@
|
||||
{
|
||||
"mailFrom":"",
|
||||
"password":""
|
||||
}
|
||||
63
Back-End/GestionInscriptions/Configuration/automate.json
Normal file
63
Back-End/GestionInscriptions/Configuration/automate.json
Normal file
@ -0,0 +1,63 @@
|
||||
{
|
||||
"states": [
|
||||
"ABSENT",
|
||||
"CREE",
|
||||
"ENVOYE",
|
||||
"EN_VALIDATION",
|
||||
"A_RELANCER",
|
||||
"VALIDE",
|
||||
"ARCHIVE"
|
||||
],
|
||||
"transitions": [
|
||||
{
|
||||
"name": "creationDI",
|
||||
"from": "ABSENT",
|
||||
"to": "CREE"
|
||||
},
|
||||
{
|
||||
"name": "envoiDI",
|
||||
"from": "CREE",
|
||||
"to": "ENVOYE"
|
||||
},
|
||||
{
|
||||
"name": "archiveDI",
|
||||
"from": "CREE",
|
||||
"to": "ARCHIVE"
|
||||
},
|
||||
{
|
||||
"name": "saisiDI",
|
||||
"from": "ENVOYE",
|
||||
"to": "EN_VALIDATION"
|
||||
},
|
||||
{
|
||||
"name": "relanceDI",
|
||||
"from": "ENVOYE",
|
||||
"to": "A_RELANCER"
|
||||
},
|
||||
{
|
||||
"name": "archiveDI",
|
||||
"from": "A_RELANCER",
|
||||
"to": "ARCHIVE"
|
||||
},
|
||||
{
|
||||
"name": "archiveDI",
|
||||
"from": "ENVOYE",
|
||||
"to": "ARCHIVE"
|
||||
},
|
||||
{
|
||||
"name": "valideDI",
|
||||
"from": "EN_VALIDATION",
|
||||
"to": "VALIDE"
|
||||
},
|
||||
{
|
||||
"name": "archiveDI",
|
||||
"from": "EN_VALIDATION",
|
||||
"to": "ARCHIVE"
|
||||
},
|
||||
{
|
||||
"name": "archiveDI",
|
||||
"from": "VALIDE",
|
||||
"to": "ARCHIVE"
|
||||
}
|
||||
]
|
||||
}
|
||||
18
Back-End/GestionInscriptions/Configuration/inscriptions.json
Normal file
18
Back-End/GestionInscriptions/Configuration/inscriptions.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"activationMailRelance": "Oui",
|
||||
"delaiRelance": "30",
|
||||
"ambiances": [
|
||||
"2-3 ans",
|
||||
"3-6 ans",
|
||||
"6-12 ans"
|
||||
],
|
||||
"genres": [
|
||||
"Fille",
|
||||
"Garçon"
|
||||
],
|
||||
"modesPaiement": [
|
||||
"Chèque",
|
||||
"Virement",
|
||||
"Prélèvement SEPA"
|
||||
]
|
||||
}
|
||||
1
Back-End/GestionInscriptions/__init__.py
Normal file
1
Back-End/GestionInscriptions/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
default_app_config = 'GestionInscriptions.apps.GestionInscriptionsConfig'
|
||||
11
Back-End/GestionInscriptions/admin.py
Normal file
11
Back-End/GestionInscriptions/admin.py
Normal file
@ -0,0 +1,11 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import *
|
||||
|
||||
admin.site.register(Eleve)
|
||||
admin.site.register(Responsable)
|
||||
|
||||
class EleveAdmin(admin.ModelAdmin):
|
||||
def save_model(self, request, obj, form, change):
|
||||
obj.user = request.user
|
||||
super().save_model(request, obj, form, change)
|
||||
10
Back-End/GestionInscriptions/apps.py
Normal file
10
Back-End/GestionInscriptions/apps.py
Normal file
@ -0,0 +1,10 @@
|
||||
from django.apps import AppConfig
|
||||
from django.conf import settings
|
||||
|
||||
class GestioninscriptionsConfig(AppConfig):
|
||||
default_auto_field = 'django.db.models.BigAutoField'
|
||||
name = 'GestionInscriptions'
|
||||
|
||||
def ready(self):
|
||||
from GestionInscriptions.signals import clear_cache
|
||||
clear_cache()
|
||||
45
Back-End/GestionInscriptions/automate.py
Normal file
45
Back-End/GestionInscriptions/automate.py
Normal file
@ -0,0 +1,45 @@
|
||||
# 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
|
||||
74
Back-End/GestionInscriptions/mailManager.py
Normal file
74
Back-End/GestionInscriptions/mailManager.py
Normal file
@ -0,0 +1,74 @@
|
||||
from django.core.mail import send_mail
|
||||
import re
|
||||
from N3wtSchool import settings
|
||||
|
||||
def envoieReinitMotDePasse(recipients, code):
|
||||
send_mail(
|
||||
settings.EMAIL_REINIT_SUBJECT,
|
||||
settings.EMAIL_REINIT_CORPUS%(str(code)),
|
||||
settings.EMAIL_HOST_USER,
|
||||
[recipients],
|
||||
fail_silently=False,
|
||||
)
|
||||
|
||||
def envoieDossierInscription(recipients):
|
||||
errorMessage = ''
|
||||
try:
|
||||
print(f'{settings.EMAIL_HOST_USER}')
|
||||
send_mail(
|
||||
settings.EMAIL_INSCRIPTION_SUBJECT,
|
||||
settings.EMAIL_INSCRIPTION_CORPUS%[recipients],
|
||||
settings.EMAIL_HOST_USER,
|
||||
[recipients],
|
||||
fail_silently=False,
|
||||
)
|
||||
except Exception as e:
|
||||
errorMessage = str(e)
|
||||
|
||||
return errorMessage
|
||||
|
||||
def envoieRelanceDossierInscription(recipients, code):
|
||||
errorMessage = ''
|
||||
try:
|
||||
send_mail(
|
||||
settings.EMAIL_RELANCE_SUBJECT,
|
||||
settings.EMAIL_RELANCE_CORPUS%str(code),
|
||||
settings.EMAIL_HOST_USER,
|
||||
[recipients],
|
||||
fail_silently=False,
|
||||
)
|
||||
except Exception as e:
|
||||
errorMessage = str(e)
|
||||
|
||||
return errorMessage
|
||||
|
||||
|
||||
def envoieSEPA(recipients, ref):
|
||||
send_mail(
|
||||
settings.EMAIL_SEPA_SUBJECT%str(ref),
|
||||
settings.EMAIL_SEPA_CORPUS,
|
||||
settings.EMAIL_HOST_USER,
|
||||
[recipients],
|
||||
fail_silently=False,
|
||||
)
|
||||
|
||||
def isValid(message, fiche_inscription):
|
||||
# Est-ce que la référence du dossier est VALIDE
|
||||
subject = message.subject
|
||||
print ("++++ " + subject)
|
||||
responsableMail = message.from_header
|
||||
result = re.search('<(.*)>', responsableMail)
|
||||
|
||||
if result:
|
||||
responsableMail = result.group(1)
|
||||
|
||||
result = re.search(r'.*\[Ref(.*)\].*', subject)
|
||||
idMail = -1
|
||||
if result:
|
||||
idMail = result.group(1).strip()
|
||||
|
||||
eleve = fiche_inscription.eleve
|
||||
responsable = eleve.getResponsablePrincipal()
|
||||
mailReponsableAVerifier = responsable.mail
|
||||
|
||||
return responsableMail == mailReponsableAVerifier and str(idMail) == str(fiche_inscription.eleve.id)
|
||||
123
Back-End/GestionInscriptions/models.py
Normal file
123
Back-End/GestionInscriptions/models.py
Normal file
@ -0,0 +1,123 @@
|
||||
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
|
||||
|
||||
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.CharField(max_length=200, default="", 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)
|
||||
|
||||
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()
|
||||
|
||||
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
|
||||
|
||||
20
Back-End/GestionInscriptions/pagination.py
Normal file
20
Back-End/GestionInscriptions/pagination.py
Normal file
@ -0,0 +1,20 @@
|
||||
from rest_framework.pagination import PageNumberPagination
|
||||
|
||||
from N3wtSchool import settings
|
||||
|
||||
class CustomPagination(PageNumberPagination):
|
||||
page_size_query_param = 'page_size'
|
||||
max_page_size = settings.NB_MAX_PAGE
|
||||
page_size = settings.NB_RESULT_PER_PAGE
|
||||
|
||||
def get_paginated_response(self, data):
|
||||
return ({
|
||||
'links': {
|
||||
'next': self.get_next_link(),
|
||||
'previous': self.get_previous_link()
|
||||
},
|
||||
'count': self.page.paginator.count,
|
||||
'page_size': self.page_size,
|
||||
'max_page_size' : self.max_page_size,
|
||||
'fichesInscriptions': data }
|
||||
)
|
||||
176
Back-End/GestionInscriptions/serializers.py
Normal file
176
Back-End/GestionInscriptions/serializers.py
Normal file
@ -0,0 +1,176 @@
|
||||
from rest_framework import serializers
|
||||
from GestionInscriptions.models import FicheInscription, Eleve, Responsable, Frere, Langue
|
||||
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
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
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__'
|
||||
|
||||
43
Back-End/GestionInscriptions/signals.py
Normal file
43
Back-End/GestionInscriptions/signals.py
Normal file
@ -0,0 +1,43 @@
|
||||
from django.db.models.signals import post_save, post_delete, m2m_changed
|
||||
from django.dispatch import receiver
|
||||
from django.core.cache import cache
|
||||
|
||||
from GestionInscriptions.models import FicheInscription, Eleve, Responsable
|
||||
from GestionLogin.models import Profil
|
||||
from N3wtSchool import settings
|
||||
from N3wtSchool.redis_client import redis_client
|
||||
|
||||
def clear_cache():
|
||||
# Préfixes des clés à supprimer
|
||||
prefixes = ['N3WT_']
|
||||
|
||||
for prefix in prefixes:
|
||||
# Utiliser le motif pour obtenir les clés correspondant au préfixe
|
||||
pattern = f'*{prefix}*'
|
||||
print(f'pattern : {pattern}')
|
||||
for key in redis_client.scan_iter(pattern):
|
||||
redis_client.delete(key)
|
||||
print(f'deleting : {key}')
|
||||
|
||||
@receiver(post_save, sender=FicheInscription)
|
||||
@receiver(post_delete, sender=FicheInscription)
|
||||
def clear_cache_after_change(sender, instance, **kwargs):
|
||||
clear_cache()
|
||||
|
||||
@receiver(m2m_changed, sender=Eleve.responsables.through)
|
||||
def check_orphan_reponsables(sender, **kwargs):
|
||||
action = kwargs.pop('action', None)
|
||||
instance = kwargs.pop('instance', None)
|
||||
# pre_clear : lors de la suppression d'une FI (on fait un "clear" sur chaque relation)
|
||||
if action in ('post_remove', 'post_clear'):
|
||||
if instance.responsables.all():
|
||||
Responsable.objects.filter(eleve=None).delete()
|
||||
|
||||
@receiver(m2m_changed, sender=Eleve.profils.through)
|
||||
def check_orphan_profils(sender, **kwargs):
|
||||
action = kwargs.pop('action', None)
|
||||
instance = kwargs.pop('instance', None)
|
||||
# pre_clear : lors de la suppression d'une FI (on fait un "clear" sur chaque relation)
|
||||
if action in ('post_remove', 'post_clear'):
|
||||
if instance.profils.all():
|
||||
Profil.objects.filter(eleve=None).delete()
|
||||
44
Back-End/GestionInscriptions/tasks.py
Normal file
44
Back-End/GestionInscriptions/tasks.py
Normal file
@ -0,0 +1,44 @@
|
||||
# tasks.py
|
||||
from celery import shared_task
|
||||
from django.utils import timezone
|
||||
from GestionInscriptions.automate import Automate_DI_Inscription, updateStateMachine
|
||||
from .models import FicheInscription
|
||||
from GestionMessagerie.models import Messagerie
|
||||
from N3wtSchool import settings, bdd
|
||||
import requests
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
logger.setLevel(logging.WARNING)
|
||||
|
||||
@shared_task
|
||||
def check_for_signature_deadlines():
|
||||
now = timezone.now()
|
||||
deadline = now - timezone.timedelta(days=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)
|
||||
|
||||
for dossier in dossiers_en_attente:
|
||||
send_notification(dossier)
|
||||
|
||||
def send_notification(dossier):
|
||||
print(f'Dossier en attente.... {dossier} - Positionnement à l\'état A_RELANCER')
|
||||
|
||||
# Changer l'état de l'automate
|
||||
updateStateMachine(dossier, 'relanceDI')
|
||||
|
||||
url = settings.URL_DJANGO + 'GestionMessagerie/message'
|
||||
|
||||
destinataires = dossier.eleve.profils.all()
|
||||
for destinataire in destinataires:
|
||||
message = {
|
||||
"objet": "[RELANCE]",
|
||||
"destinataire" : destinataire.id,
|
||||
"corpus": "RELANCE pour le dossier d'inscription"
|
||||
}
|
||||
|
||||
response = requests.post(url, json=message)
|
||||
|
||||
# subject = f"Dossier d'inscription non signé - {dossier.objet}"
|
||||
# message = f"Le dossier d'inscription avec l'objet '{dossier.objet}' n'a pas été signé depuis {dossier.created_at}."
|
||||
# send_mail(subject, message, settings.EMAIL_HOST_USER, [dossier.destinataire.email])
|
||||
@ -0,0 +1,52 @@
|
||||
{% extends "base.html" %}
|
||||
{% load rest_framework %}
|
||||
{% block content %}
|
||||
<h1>Création d'une nouvelle fiche d'inscription</h1>
|
||||
<br>
|
||||
<form action='{% url 'GestionInscriptions:nouvelEleve' %}' method="post">
|
||||
{% csrf_token %}
|
||||
<ul>
|
||||
<li style="margin-bottom: 15px"><strong>ELEVE</strong></li>
|
||||
<div class="input-group">
|
||||
<label for="nomEleve">Nom</label>
|
||||
<div class="input-wrapper">
|
||||
<input type="text" id="nomEleve" name="nomEleve">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="prenomEleve">Prénom</label>
|
||||
<div class="input-wrapper">
|
||||
<input type="text" id="prenomEleve" name="prenomEleve">
|
||||
</div>
|
||||
</div>
|
||||
<li style="margin-bottom: 15px"><strong>LISTE DES CONTACTS</strong></li>
|
||||
<div class="input-group">
|
||||
<label for="mail">Adresse e-mail </label>
|
||||
<div class="input-wrapper">
|
||||
<input type="text" id="mail" name="mailResponsable">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="telephone">Numéro de téléphone</label>
|
||||
<div class="input-wrapper">
|
||||
<input type="text" id="telephone" name="telephoneResponsable">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="nomContact">Nom</label>
|
||||
<div class="input-wrapper">
|
||||
<input type="text" id="nomContact" name="nomResponsable">
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<label for="prenomContact">Prénom</label>
|
||||
<div class="input-wrapper">
|
||||
<input type="text" id="prenomContact" name="prenomResponsable">
|
||||
</div>
|
||||
</div>
|
||||
</ul>
|
||||
<input class="btn primary" type="submit" value="Créer" name="valider">
|
||||
<br>
|
||||
<input class="btn" type="button" value="Annuler" name="cancel">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@ -0,0 +1,16 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Configuration des dossiers d'inscriptions</h1>
|
||||
<br>
|
||||
<form action='{% url 'GestionInscriptions:index' %}' method="post">
|
||||
{% csrf_token %}
|
||||
<ul>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Relance automatique :</label>
|
||||
<input type="text" name="delaiRelance" value="{{ delaiRelance }}">
|
||||
<label>secondes</label>
|
||||
</div>
|
||||
</ul>
|
||||
<input class="btn" type="submit" value="Configurer" name="valider">
|
||||
</form>
|
||||
{% endblock %}
|
||||
@ -0,0 +1,162 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Création du dossier d'inscription</h1>
|
||||
<br>
|
||||
<form action='{% url 'GestionInscriptions:validate' eleve.id %}' method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% with responsable=eleve.getResponsablePrincipal %}
|
||||
<ul>
|
||||
<li style="margin-bottom: 15px"><strong>ELEVE</strong></li>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Nom :</label>
|
||||
<input type="text" name="nomEleve" value="{{ eleve.nom }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" name="prenomEleve" value="{{ eleve.prenom }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Genre :<br></label>
|
||||
{% for genre in genres %}
|
||||
<label>{{ genre }}</label>
|
||||
<input type="radio" id="{{ genre }}" name="genre" value="{{ genre }}">
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Adresse :</label>
|
||||
<input type="text" name="adresseEleve">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Date de naissance :</label>
|
||||
<input type="text" name="dateNaissanceEleve">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Lieu de naissance :</label>
|
||||
<input type="text" name="lieuNaissanceEleve">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Code postal de naissance :</label>
|
||||
<input type="text" name="codePostalNaissanceEleve">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Nationalité :</label>
|
||||
<input type="text" name="nationaliteEleve">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Langue parlée :</label>
|
||||
<input type="text" name="langueEleve">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Ambiance :<br></label>
|
||||
{% for ambiance in ambiances %}
|
||||
<label>{{ ambiance }}</label>
|
||||
<input type="radio" id="{{ ambiance }}" name="ambiance" value="{{ ambiance }}">
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Médecin traitant :</label>
|
||||
<input type="text" name="medecinTraitantEleve">
|
||||
</div>
|
||||
<li style="margin-bottom: 15px"><strong>RESPONSABLES</strong></li>
|
||||
<ul>
|
||||
<li style="margin-bottom: 15px"><strong>RESPONSABLE 1</strong></li>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Nom :</label>
|
||||
<input type="text" name="nomResponsable1" value="{{ responsable.nom }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" name="prenomResponsable1" value="{{ responsable.prenom }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Adresse :</label>
|
||||
<input type="text" name="adresseResponsable1" value="{{ responsable.adresse }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Date de naissance :</label>
|
||||
<input type="text" name="dateNaissanceResponsable1" value="{{ responsable.dateNaissance }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Mail :</label>
|
||||
<input type="text" name="mailResponsable1" value="{{ responsable.mail }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Téléphone :</label>
|
||||
<input type="text" name="telephoneResponsable1" value="{{ responsable.telephone }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Profession :</label>
|
||||
<input type="text" name="professionResponsable1" value="{{ responsable.profession }}">
|
||||
</div>
|
||||
<li style="margin-bottom: 15px"><strong>RESPONSABLE 2</strong></li>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Nom :</label>
|
||||
<input type="text" name="nomResponsable2">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" name="prenomResponsable2">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Adresse :</label>
|
||||
<input type="text" name="adresseResponsable2">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Date de naissance :</label>
|
||||
<input type="text" name="dateNaissanceResponsable2">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Mail :</label>
|
||||
<input type="text" name="mailResponsable2">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Téléphone :</label>
|
||||
<input type="text" name="telephoneResponsable2">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Profession :</label>
|
||||
<input type="text" name="professionResponsable2">
|
||||
</div>
|
||||
</ul>
|
||||
<li style="margin-bottom: 15px"><strong>FRATRIE</strong></li>
|
||||
<ul>
|
||||
<li style="margin-bottom: 15px"><strong>FRERE - SOEUR 1 :</strong></li>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Nom :</label>
|
||||
<input type="text" name="nomFrere1">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" name="prenomFrere1">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Date de naissance :</label>
|
||||
<input type="text" name="dateNaissanceFrere1">
|
||||
</div>
|
||||
<li style="margin-bottom: 15px"><strong>FRERE - SOEUR 2 :</strong></li>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Nom :</label>
|
||||
<input type="text" name="nomFrere2">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" name="prenomFrere2">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Date de naissance :</label>
|
||||
<input type="text" name="dateNaissanceFrere2">
|
||||
</div>
|
||||
</ul>
|
||||
<li style="margin-bottom: 15px"><strong>PAIEMENT</strong></li>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Mode Paiement :<br></label>
|
||||
{% for modePaiement in modesPaiement %}
|
||||
<label>{{ modePaiement }}</label>
|
||||
<input type="radio" id="{{ modePaiement }}" name="modePaiement" value="{{ modePaiement }}">
|
||||
{% endfor %}
|
||||
</div>
|
||||
</ul>
|
||||
<input class="btn" type="submit" value="Valider" name="valider">
|
||||
{% endwith %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
@ -0,0 +1,42 @@
|
||||
{% extends "base.html" %}
|
||||
{% block content %}
|
||||
<h1>Edition d'une fiche d'inscription</h1>
|
||||
<br>
|
||||
<form action='{% url 'GestionInscriptions:index' %}' method="post">
|
||||
{% csrf_token %}
|
||||
{% with responsable=eleve.getResponsablePrincipal %}
|
||||
<ul>
|
||||
<div style="margin-bottom: 15px">
|
||||
<input type="hidden" name="fiche_id" value="{{ eleve.id }}">
|
||||
</div>
|
||||
<li style="margin-bottom: 15px"><strong>ELEVE</strong></li>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Nom :</label>
|
||||
<input type="text" name="nomEleve" value="{{ eleve.nom }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" name="prenomEleve" value="{{ eleve.prenom }}">
|
||||
</div>
|
||||
<li style="margin-bottom: 15px"><strong>LISTE DES CONTACTS</strong></li>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Adresse e-mail :</label>
|
||||
<input type="text" name="mail" value="{{ responsable.mail }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Numéro de téléphone :</label>
|
||||
<input type="text" name="telephone" value="{{ responsable.telephone }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Nom :</label>
|
||||
<input type="text" name="nomContact" value="{{ responsable.nom }}">
|
||||
</div>
|
||||
<div style="margin-bottom: 15px">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" name="prenomContact" value="{{ responsable.prenom }}">
|
||||
</div>
|
||||
</ul>
|
||||
<input class="btn" type="submit" value="Modifier" name="valider">
|
||||
{% endwith %}
|
||||
</form>
|
||||
{% endblock %}
|
||||
@ -0,0 +1,126 @@
|
||||
{% extends "base.html" %}
|
||||
{% load myTemplateTag %}
|
||||
|
||||
{% block content %}
|
||||
<h1>Inscriptions 2024/2025</h1>
|
||||
<br>
|
||||
<div>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
|
||||
<section class="heading-section">
|
||||
<!-- Search bar -->
|
||||
<div class="input-group max-80">
|
||||
<div class="input-wrapper max">
|
||||
<span class="icon-ctn">
|
||||
<i class="icon user-search"></i>
|
||||
</span>
|
||||
<input type="text" id="username" placeholder="Rechercher">
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn primary" href="nouvelEleve">
|
||||
Ajouter <i class="icon profile-add"></i>
|
||||
</a>
|
||||
</section>
|
||||
<section class="heading-section">
|
||||
<div class="alphabet-filter">
|
||||
{% for letter in "*ABCDEFGHIJKLMNOPQRSTUVWXYZ" %}
|
||||
<a class="item" href="?letter={{ letter }}">{{ letter }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Nom</th>
|
||||
<th>Prenom</th>
|
||||
<th>Mail</th>
|
||||
<th>Téléphone</th>
|
||||
<th>MàJ Le</th>
|
||||
<th>Statut</th>
|
||||
<th>Fichiers</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
{% for ficheInscription in ficheInscriptions_list %}
|
||||
{% with eleve=ficheInscription.eleve %}
|
||||
{% with responsable=eleve.getResponsablePrincipal %}
|
||||
{% with fichiers=ficheInscription|recupereFichiersDossierInscription %}
|
||||
<tr>
|
||||
<td>{{ eleve.nom }}</td>
|
||||
<td>{{ eleve.prenom }}</td>
|
||||
<td>{{ responsable.mail }}</td>
|
||||
<td>{{ responsable.telephone }}</td>
|
||||
<td>{{ ficheInscription.dateMAJ }}</td>
|
||||
<td>
|
||||
{% if ficheInscription.etat == 0 %}
|
||||
<span class="tag blue"> Créé</span>
|
||||
{% elif ficheInscription.etat == 1 %}
|
||||
<span class="tag orange"> Envoyé</span>
|
||||
{% elif ficheInscription.etat == 2 %}
|
||||
<span class="tag purple"> En Validation</span>
|
||||
{% else %}
|
||||
<span class="tag green"> Validé</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% for fichier in fichiers %}
|
||||
<a href="{{ fichier.url }}">{{ fichier.nom }}</a>
|
||||
{% endfor %}
|
||||
</td>
|
||||
<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"> <i class="icon edit"></i></button>
|
||||
<button class="icon-btn red"> <i class="icon user-minus"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td colspan="6">
|
||||
<div class="pagination">
|
||||
{% if ficheInscriptions_list.has_previous %}
|
||||
{% if ficheInscriptions_list.previous_page_number == 1 %}
|
||||
<a class="item" href="?page={{ ficheInscriptions_list.previous_page_number }}"><</a>
|
||||
<a class="item" href="?page=1">1</a>
|
||||
{% else %}
|
||||
<a class="item" href="?page={{ ficheInscriptions_list.previous_page_number }}"><</a>
|
||||
<a class="item" href="?page=1">1</a>
|
||||
<a class="item" >...</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% if ficheInscriptions_list %}
|
||||
<a class="item active">{{ ficheInscriptions_list.number }}</a>
|
||||
{% else %}
|
||||
<a class="item">{{ ficheInscriptions_list.number }}</a>
|
||||
{% endif %}
|
||||
|
||||
{% if ficheInscriptions_list.has_next %}
|
||||
{% if ficheInscriptions_list.next_page_number == ficheInscriptions_list.paginator.num_pages %}
|
||||
<a class="item" href="?page={{ ficheInscriptions_list.next_page_number }}">{{ ficheInscriptions_list.next_page_number }}</a>
|
||||
<a class="item" href="?page={{ ficheInscriptions_list.next_page_number }}">></a>
|
||||
{% else %}
|
||||
<a class="item" >...</a>
|
||||
<a class="item" href="?page={{ ficheInscriptions_list.paginator.num_pages }}">{{ ficheInscriptions_list.paginator.num_pages }}</a>
|
||||
<a class="item" href="?page={{ ficheInscriptions_list.next_page_number }}">></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
31
Back-End/GestionInscriptions/templates/base.html
Normal file
31
Back-End/GestionInscriptions/templates/base.html
Normal file
@ -0,0 +1,31 @@
|
||||
{% load static %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="{% static '/css/main.css' %}">
|
||||
<title>Monteschool</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="sidebar">
|
||||
<div class="itemlogo">
|
||||
<div class="circle"></div>
|
||||
</div>
|
||||
<a class="item active">
|
||||
<i class="icon receipt-edit"></i> Administration
|
||||
</a>
|
||||
<a class="item">
|
||||
<i class="icon user-line"></i> Statistiques
|
||||
</a>
|
||||
<a class="item">
|
||||
<i class="icon book"></i> Paramétrage
|
||||
</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -0,0 +1,97 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ pdf_title }}</title>
|
||||
<style type="text/css">
|
||||
body {
|
||||
font-weight: 200;
|
||||
font-size: 14px;
|
||||
}
|
||||
.header {
|
||||
font-size: 20px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
color: #007cae;
|
||||
}
|
||||
.title {
|
||||
font-size: 22px;
|
||||
font-weight: 100;
|
||||
/* text-align: right;*/
|
||||
padding: 10px 20px 0px 20px;
|
||||
}
|
||||
.title span {
|
||||
color: #007cae;
|
||||
}
|
||||
.details {
|
||||
padding: 10px 20px 0px 20px;
|
||||
text-align: left !important;
|
||||
/*margin-left: 40%;*/
|
||||
}
|
||||
.hrItem {
|
||||
border: none;
|
||||
height: 1px;
|
||||
/* Set the hr color */
|
||||
color: #333; /* old IE */
|
||||
background-color: #fff; /* Modern Browsers */
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
{% load myTemplateTag %}
|
||||
<div class='wrapper'>
|
||||
<div class='header'>
|
||||
<p class='title'>{{ pdf_title }}</p>
|
||||
</div>
|
||||
<div>
|
||||
<div class='details'>
|
||||
Signé le : <b>{{ dateSignature }}</b> <br/>
|
||||
A : <b>{{ heureSignature }}</b>
|
||||
<hr class='hrItem' />
|
||||
<h1>ELEVE</h1>
|
||||
{% with niveau=eleve|recupereNiveauEleve %}
|
||||
{% with genre=eleve|recupereGenreEleve %}
|
||||
NOM : <b>{{ eleve.nom }}</b> <br/>
|
||||
PRENOM : <b>{{ eleve.prenom }}</b> <br/>
|
||||
ADRESSE : <b>{{ eleve.adresse }}</b> <br/>
|
||||
GENRE : <b>{{ genre }}</b> <br/>
|
||||
NE(E) LE : <b>{{ eleve.dateNaissance }}</b> <br/>
|
||||
A : <b>{{ eleve.lieuNaissance }} ({{ eleve.codePostalNaissance }})</b> <br/>
|
||||
NATIONALITE : <b>{{ eleve.nationalite }}</b> <br/>
|
||||
NIVEAU : <b>{{ niveau }}</b> <br/>
|
||||
MEDECIN TRAITANT : <b>{{ eleve.medecinTraitant }}</b> <br/>
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
<hr class='hrItem' />
|
||||
<h1>RESPONSABLES</h1>
|
||||
{% with responsables_List=eleve.getResponsables %}
|
||||
{% with freres_List=eleve.getFreres %}
|
||||
{% for responsable in responsables_List%}
|
||||
<h2>Responsable {{ forloop.counter }}</h2>
|
||||
NOM : <b>{{ responsable.nom }}</b> <br/>
|
||||
PRENOM : <b>{{ responsable.prenom }}</b> <br/>
|
||||
ADRESSE : <b>{{ responsable.adresse }}</b> <br/>
|
||||
NE(E) LE : <b>{{ responsable.dateNaissance }}</b> <br/>
|
||||
MAIL : <b>{{ responsable.mail }}</b> <br/>
|
||||
TEL : <b>{{ responsable.telephone }}</b> <br/>
|
||||
PROFESSION : <b>{{ responsable.profession }}</b> <br/>
|
||||
{% endfor %}
|
||||
<hr class='hrItem' />
|
||||
<h1>FRATRIE</h1>
|
||||
{% for frere in freres_List%}
|
||||
<h2>Frère - Soeur {{ forloop.counter }}</h2>
|
||||
NOM : <b>{{ frere.nom }}</b> <br/>
|
||||
PRENOM : <b>{{ frere.prenom }}</b> <br/>
|
||||
NE(E) LE : <b>{{ frere.dateNaissance }}</b> <br/>
|
||||
{% endfor %}
|
||||
<hr class='hrItem' />
|
||||
<h1>MODALITES DE PAIEMENT</h1>
|
||||
{% with modePaiement=eleve|recupereModePaiement %}
|
||||
<b>{{ modePaiement }}</b> <br/>
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
23
Back-End/GestionInscriptions/templatetags/myTemplateTag.py
Normal file
23
Back-End/GestionInscriptions/templatetags/myTemplateTag.py
Normal file
@ -0,0 +1,23 @@
|
||||
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
|
||||
31
Back-End/GestionInscriptions/urls.py
Normal file
31
Back-End/GestionInscriptions/urls.py
Normal file
@ -0,0 +1,31 @@
|
||||
from django.urls import path, re_path
|
||||
|
||||
from . import views
|
||||
from GestionInscriptions.views import ListFichesInscriptionView, FicheInscriptionView, EleveView, ResponsableView, ListeEnfantsView, ListeElevesView
|
||||
|
||||
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"),
|
||||
]
|
||||
181
Back-End/GestionInscriptions/util.py
Normal file
181
Back-End/GestionInscriptions/util.py
Normal file
@ -0,0 +1,181 @@
|
||||
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
|
||||
289
Back-End/GestionInscriptions/views.py
Normal file
289
Back-End/GestionInscriptions/views.py
Normal file
@ -0,0 +1,289 @@
|
||||
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
|
||||
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 FicheInscriptionSerializer, EleveSerializer, FicheInscriptionByParentSerializer, EleveByDICreationSerializer
|
||||
from GestionInscriptions.pagination import CustomPagination
|
||||
from GestionInscriptions.signals import clear_cache
|
||||
from .models import Eleve, Responsable, FicheInscription
|
||||
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(self, request, _filter):
|
||||
if _filter == 'all':
|
||||
# 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
|
||||
|
||||
cached_page_size = cache.get('N3WT_page_size')
|
||||
if cached_page_size != page_size:
|
||||
clear_cache()
|
||||
cache.set('N3WT_page_size', page_size)
|
||||
|
||||
# Gestion du cache
|
||||
page_number = request.GET.get('page', 1)
|
||||
cache_key = f'N3WT_ficheInscriptions_page_{page_number}_search_{search}'
|
||||
cached_page = cache.get(cache_key)
|
||||
if cached_page:
|
||||
return JsonResponse(cached_page, safe=False)
|
||||
|
||||
# Filtrage des résultats
|
||||
if search:
|
||||
# Utiliser la nouvelle fonction de recherche
|
||||
ficheInscriptions_List = bdd.searchObjects(
|
||||
FicheInscription,
|
||||
search,
|
||||
_excludeState=6 # Exclure les fiches archivées
|
||||
)
|
||||
else:
|
||||
# Récupère toutes les fiches non archivées
|
||||
ficheInscriptions_List = bdd.getObjects(FicheInscription, 'etat', 6, _reverseCondition=True)
|
||||
|
||||
# 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)
|
||||
|
||||
elif _filter == 'archived' :
|
||||
page_size = request.GET.get('page_size', None)
|
||||
if page_size is not None:
|
||||
try:
|
||||
page_size = int(page_size)
|
||||
except ValueError:
|
||||
page_size = settings.NB_RESULT_PER_PAGE
|
||||
|
||||
cached_page_size = cache.get('N3WT_archived_page_size')
|
||||
|
||||
# Comparer avec le nouveau page_size
|
||||
if cached_page_size != page_size:
|
||||
# Appeler cached_page() et mettre à jour le cache
|
||||
clear_cache()
|
||||
cache.set('N3WT_archived_page_size',page_size)
|
||||
|
||||
page_number = request.GET.get('page', 1)
|
||||
cache_key_page = f'N3WT_ficheInscriptions_archives_page_{page_number}'
|
||||
cached_page = cache.get(cache_key_page)
|
||||
if cached_page:
|
||||
return JsonResponse(cached_page, safe=False)
|
||||
|
||||
ficheInscriptions_List=bdd.getObjects(FicheInscription, 'etat', 6)
|
||||
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_page, response_data, timeout=60*15)
|
||||
|
||||
return JsonResponse(response_data, safe=False)
|
||||
|
||||
return JsonResponse(status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
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()
|
||||
|
||||
ficheInscriptions_List=bdd.getAllObjects(FicheInscription)
|
||||
return JsonResponse({'totalInscrits':len(ficheInscriptions_List)}, safe=False)
|
||||
|
||||
return JsonResponse(ficheEleve_serializer.errors, safe=False)
|
||||
|
||||
def put(self, request, id):
|
||||
ficheEleve_data=JSONParser().parse(request)
|
||||
admin = ficheEleve_data.pop('admin', 1)
|
||||
ficheEleve_data["dateMAJ"] = str(util.convertToStr(util._now(), '%d-%m-%Y %H:%M'))
|
||||
ficheEleve = bdd.getObject(_objectName=FicheInscription, _columnName='eleve__id', _value=id)
|
||||
currentState = getStateMachineObjectState(ficheEleve.etat)
|
||||
if admin == 0 and currentState == FicheInscription.EtatDossierInscription.DI_ENVOYE:
|
||||
json.dumps(ficheEleve_data)
|
||||
|
||||
# Ajout du fichier d'inscriptions
|
||||
data = {
|
||||
'pdf_title': "Dossier d'inscription de %s"%ficheEleve.eleve.prenom,
|
||||
'dateSignature': util.convertToStr(util._now(), '%d-%m-%Y'),
|
||||
'heureSignature': util.convertToStr(util._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)
|
||||
|
||||
# Mise à jour de l'automate
|
||||
updateStateMachine(di, 'saisiDI')
|
||||
|
||||
ficheEleve_serializer = FicheInscriptionSerializer(ficheEleve, data=ficheEleve_data)
|
||||
if ficheEleve_serializer.is_valid():
|
||||
di = ficheEleve_serializer.save()
|
||||
return JsonResponse("Updated Successfully", 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)
|
||||
Reference in New Issue
Block a user