mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
refactor: Traduction en anglais des modules "GestionInscription" et
"GestionLogin"
This commit is contained in:
@ -0,0 +1,4 @@
|
||||
{
|
||||
"mailFrom":"",
|
||||
"password":""
|
||||
}
|
||||
63
Back-End/Subscriptions/Configuration/automate.json
Normal file
63
Back-End/Subscriptions/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/Subscriptions/Configuration/inscriptions.json
Normal file
18
Back-End/Subscriptions/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/Subscriptions/__init__.py
Normal file
1
Back-End/Subscriptions/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
default_app_config = 'Subscriptions.apps.GestionInscriptionsConfig'
|
||||
11
Back-End/Subscriptions/admin.py
Normal file
11
Back-End/Subscriptions/admin.py
Normal file
@ -0,0 +1,11 @@
|
||||
from django.contrib import admin
|
||||
|
||||
from .models import *
|
||||
|
||||
admin.site.register(Student)
|
||||
admin.site.register(Guardian)
|
||||
|
||||
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/Subscriptions/apps.py
Normal file
10
Back-End/Subscriptions/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 = 'Subscriptions'
|
||||
|
||||
def ready(self):
|
||||
from Subscriptions.signals import 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
|
||||
74
Back-End/Subscriptions/mailManager.py
Normal file
74
Back-End/Subscriptions/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 sendRegisterForm(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.getMainGuardian()
|
||||
mailReponsableAVerifier = responsable.mail
|
||||
|
||||
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
|
||||
20
Back-End/Subscriptions/pagination.py
Normal file
20
Back-End/Subscriptions/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,
|
||||
'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__'
|
||||
44
Back-End/Subscriptions/signals.py
Normal file
44
Back-End/Subscriptions/signals.py
Normal file
@ -0,0 +1,44 @@
|
||||
from django.db.models.signals import post_save, post_delete, m2m_changed
|
||||
from django.dispatch import receiver
|
||||
from django.core.cache import cache
|
||||
from .models import RegistrationForm, Student, Guardian
|
||||
from Auth.models import Profile
|
||||
from N3wtSchool import settings
|
||||
from N3wtSchool.redis_client import redis_client
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
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}*'
|
||||
logger.debug(f'pattern : {pattern}')
|
||||
for key in redis_client.scan_iter(pattern):
|
||||
redis_client.delete(key)
|
||||
logger.debug(f'deleting : {key}')
|
||||
|
||||
@receiver(post_save, sender=RegistrationForm)
|
||||
@receiver(post_delete, sender=RegistrationForm)
|
||||
def clear_cache_after_change(sender, instance, **kwargs):
|
||||
clear_cache()
|
||||
|
||||
@receiver(m2m_changed, sender=Student.guardians.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.guardians.all():
|
||||
Guardian.objects.filter(eleve=None).delete()
|
||||
|
||||
@receiver(m2m_changed, sender=Student.profiles.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.profiles.all():
|
||||
Profile.objects.filter(eleve=None).delete()
|
||||
43
Back-End/Subscriptions/tasks.py
Normal file
43
Back-End/Subscriptions/tasks.py
Normal file
@ -0,0 +1,43 @@
|
||||
# tasks.py
|
||||
from celery import shared_task
|
||||
from django.utils import timezone
|
||||
from Subscriptions.automate import Automate_RF_Register, updateStateMachine
|
||||
from .models import RegistrationForm
|
||||
from GestionMessagerie.models import Messagerie
|
||||
from N3wtSchool import settings, bdd
|
||||
import requests
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@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 = RegistrationForm.objects.filter(etat=RegistrationForm.RegistrationFormStatus.DI_ENVOYE, dateMAJ__lt=deadline)
|
||||
|
||||
for dossier in dossiers_en_attente:
|
||||
send_notification(dossier)
|
||||
|
||||
def send_notification(dossier):
|
||||
logger.debug(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.profiles.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 'Subscriptions: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 'Subscriptions: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 'Subscriptions:validate' eleve.id %}' method="post" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% with responsable=eleve.getMainGuardian %}
|
||||
<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 'Subscriptions:index' %}' method="post">
|
||||
{% csrf_token %}
|
||||
{% with responsable=eleve.getMainGuardian %}
|
||||
<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 %}
|
||||
126
Back-End/Subscriptions/templates/GestionInscriptions/index.html
Normal file
126
Back-End/Subscriptions/templates/GestionInscriptions/index.html
Normal file
@ -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 registerForm in ficheInscriptions_list %}
|
||||
{% with eleve=registerForm.eleve %}
|
||||
{% with responsable=eleve.getMainGuardian %}
|
||||
{% with fichiers=registerForm|recupereFichiersDossierInscription %}
|
||||
<tr>
|
||||
<td>{{ eleve.nom }}</td>
|
||||
<td>{{ eleve.prenom }}</td>
|
||||
<td>{{ responsable.mail }}</td>
|
||||
<td>{{ responsable.telephone }}</td>
|
||||
<td>{{ registerForm.dateMAJ }}</td>
|
||||
<td>
|
||||
{% if registerForm.etat == 0 %}
|
||||
<span class="tag blue"> Créé</span>
|
||||
{% elif registerForm.etat == 1 %}
|
||||
<span class="tag orange"> Envoyé</span>
|
||||
{% elif registerForm.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 '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 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/Subscriptions/templates/base.html
Normal file
31
Back-End/Subscriptions/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>{{ signatureDate }}</b> <br/>
|
||||
A : <b>{{ signatureTime }}</b>
|
||||
<hr class='hrItem' />
|
||||
<h1>ELEVE</h1>
|
||||
{% with level=student|getStudentLevel %}
|
||||
{% with gender=student|getStudentGender %}
|
||||
NOM : <b>{{ student.last_name }}</b> <br/>
|
||||
PRENOM : <b>{{ student.first_name }}</b> <br/>
|
||||
ADRESSE : <b>{{ student.address }}</b> <br/>
|
||||
GENRE : <b>{{ gender }}</b> <br/>
|
||||
NE(E) LE : <b>{{ student.birth_date }}</b> <br/>
|
||||
A : <b>{{ student.birth_place }} ({{ student.birth_postal_code }})</b> <br/>
|
||||
NATIONALITE : <b>{{ student.nationality }}</b> <br/>
|
||||
NIVEAU : <b>{{ level }}</b> <br/>
|
||||
MEDECIN TRAITANT : <b>{{ student.attending_physician }}</b> <br/>
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
<hr class='hrItem' />
|
||||
<h1>RESPONSABLES</h1>
|
||||
{% with guardians=student.getGuardians %}
|
||||
{% with siblings=student.getGuardians %}
|
||||
{% for guardian in guardians%}
|
||||
<h2>Guardian {{ forloop.counter }}</h2>
|
||||
NOM : <b>{{ guardian.last_name }}</b> <br/>
|
||||
PRENOM : <b>{{ guardian.first_name }}</b> <br/>
|
||||
ADRESSE : <b>{{ guardian.address }}</b> <br/>
|
||||
NE(E) LE : <b>{{ guardian.birth_date }}</b> <br/>
|
||||
MAIL : <b>{{ guardian.email }}</b> <br/>
|
||||
TEL : <b>{{ guardian.phone }}</b> <br/>
|
||||
PROFESSION : <b>{{ guardian.profession }}</b> <br/>
|
||||
{% endfor %}
|
||||
<hr class='hrItem' />
|
||||
<h1>FRATRIE</h1>
|
||||
{% for sibling in siblings%}
|
||||
<h2>Frère - Soeur {{ forloop.counter }}</h2>
|
||||
NOM : <b>{{ sibling.last_name }}</b> <br/>
|
||||
PRENOM : <b>{{ sibling.first_name }}</b> <br/>
|
||||
NE(E) LE : <b>{{ sibling.birth_date }}</b> <br/>
|
||||
{% endfor %}
|
||||
<hr class='hrItem' />
|
||||
<h1>MODALITES DE PAIEMENT</h1>
|
||||
{% with paymentMethod=student|getStudentPaymentMethod %}
|
||||
<b>{{ paymentMethod }}</b> <br/>
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
{% endwith %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
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)
|
||||
Reference in New Issue
Block a user