Files
n3wt-school/Back-End/Subscriptions/views/register_form_views.py
2025-04-27 16:34:41 +02:00

482 lines
22 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from django.http.response import JsonResponse
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
from django.utils.decorators import method_decorator
from rest_framework.views import APIView
from rest_framework.decorators import action, api_view
from rest_framework import status
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
import json
import os
from django.core.files import File
import Subscriptions.mailManager as mailer
import Subscriptions.util as util
from Subscriptions.serializers import RegistrationFormSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileTemplateSerializer
from Subscriptions.pagination import CustomPagination
from Subscriptions.models import Student, Guardian, RegistrationForm, RegistrationSchoolFileTemplate, RegistrationFileGroup, RegistrationParentFileTemplate
from Subscriptions.automate import updateStateMachine
from N3wtSchool import settings, bdd
import logging
logger = logging.getLogger(__name__)
# /Subscriptions/registerForms
class RegisterFormView(APIView):
"""
Gère la liste des dossiers dinscription, lecture et création.
"""
pagination_class = CustomPagination
@swagger_auto_schema(
manual_parameters=[
openapi.Parameter('filter', openapi.IN_QUERY, description="filtre", type=openapi.TYPE_STRING, enum=['pending', 'archived', 'subscribed'], required=True),
openapi.Parameter('search', openapi.IN_QUERY, description="search", type=openapi.TYPE_STRING, required=False),
openapi.Parameter('page_size', openapi.IN_QUERY, description="limite de page lors de la pagination", type=openapi.TYPE_INTEGER, required=False),
openapi.Parameter('establishment_id', openapi.IN_QUERY, description="ID de l'établissement", type=openapi.TYPE_INTEGER, required=True),
],
responses={200: RegistrationFormSerializer(many=True)},
operation_description="Récupère les dossier d'inscriptions en fonction du filtre passé.",
operation_summary="Récupérer les dossier d'inscriptions",
examples={
"application/json": [
{
"id": 1,
"student": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2010-01-01"
},
"status": "pending",
"last_update": "10-02-2025 10:00"
},
{
"id": 2,
"student": {
"id": 2,
"first_name": "Jane",
"last_name": "Doe",
"date_of_birth": "2011-02-02"
},
"status": "archived",
"last_update": "09-02-2025 09:00"
}
]
}
)
def get(self, request):
"""
Récupère les fiches d'inscriptions en fonction du filtre passé.
"""
# Récupération des paramètres
filter = request.GET.get('filter', '').strip()
search = request.GET.get('search', '').strip()
page_size = request.GET.get('page_size', None)
establishment_id = request.GET.get('establishment_id', 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
# Récupérer les dossier d'inscriptions en fonction du filtre
registerForms_List = None
if filter == 'pending':
exclude_states = [RegistrationForm.RegistrationFormStatus.RF_VALIDATED, RegistrationForm.RegistrationFormStatus.RF_ARCHIVED]
registerForms_List = bdd.searchObjects(RegistrationForm, search, _excludeStates=exclude_states)
elif filter == 'archived':
registerForms_List = bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_ARCHIVED)
elif filter == 'subscribed':
registerForms_List = bdd.getObjects(RegistrationForm, 'status', RegistrationForm.RegistrationFormStatus.RF_VALIDATED)
else:
registerForms_List = None
if registerForms_List:
registerForms_List = registerForms_List.filter(establishment=establishment_id).order_by('-last_update')
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)
return JsonResponse(response_data, safe=False)
return JsonResponse({'error': 'aucune donnée trouvée', 'count': 0}, safe=False)
@swagger_auto_schema(
request_body=RegistrationFormSerializer,
responses={200: RegistrationFormSerializer()},
operation_description="Crée un dossier d'inscription.",
operation_summary="Créer un dossier d'inscription",
examples={
"application/json": {
"student": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2010-01-01"
},
"status": "pending",
"last_update": "10-02-2025 10:00",
"codeLienInscription": "ABC123XYZ456"
}
}
)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
def post(self, request):
"""
Crée un dossier d'inscription.
"""
regiterFormData = request.data.copy()
logger.info(f"Création d'un dossier d'inscription {request}")
# Ajout de la date de mise à jour
regiterFormData["last_update"] = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
# Ajout du code d'inscription
code = util.genereRandomCode(12)
regiterFormData["codeLienInscription"] = code
guardiansId = regiterFormData.pop('idGuardians', [])
registerForm_serializer = RegistrationFormSerializer(data=regiterFormData)
fileGroupId = regiterFormData.pop('fileGroup', None)
if registerForm_serializer.is_valid():
di = registerForm_serializer.save()
# Mise à jour de l'automate
updateStateMachine(di, 'EVENT_INIT')
# Récupération du reponsable associé
for guardianId in guardiansId:
guardian = Guardian.objects.get(id=guardianId)
di.student.guardians.add(guardian)
di.save()
if fileGroupId:
di.fileGroup = RegistrationFileGroup.objects.get(id=fileGroupId)
di.save()
return JsonResponse(registerForm_serializer.data, safe=False)
else:
logger.error(f"Erreur lors de la validation des données {regiterFormData}")
return JsonResponse(registerForm_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
# /Subscriptions/registerForms/{id}
class RegisterFormWithIdView(APIView):
"""
Gère la lecture, création, modification et suppression dun dossier dinscription.
"""
pagination_class = CustomPagination
@swagger_auto_schema(
responses={200: RegistrationFormSerializer()},
operation_description="Récupère un dossier d'inscription donné.",
operation_summary="Récupérer un dossier d'inscription",
examples={
"application/json": {
"id": 1,
"student": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2010-01-01"
},
}
}
)
def get(self, request, id):
"""
Récupère un dossier d'inscription donné.
"""
registerForm = bdd.getObject(RegistrationForm, "student__id", id)
if registerForm is None:
return JsonResponse({"errorMessage":'Le dossier d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
registerForm_serializer = RegistrationFormSerializer(registerForm)
return JsonResponse(registerForm_serializer.data, safe=False)
@swagger_auto_schema(
request_body=RegistrationFormSerializer,
responses={200: RegistrationFormSerializer()},
operation_description="Modifie un dossier d'inscription donné.",
operation_summary="Modifier un dossier d'inscription",
examples={
"application/json": {
"id": 1,
"student": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "2010-01-01"
},
"status": "under_review",
"last_update": "10-02-2025 10:00"
}
}
)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
def put(self, request, id):
"""
Modifie un dossier d'inscription donné.
"""
# Récupérer les données de la requête
studentForm_data = request.data.copy()
logger.info(f"Mise à jour du dossier d'inscription {studentForm_data}")
_status = studentForm_data.pop('status', 0)
if isinstance(_status, list): # Cas Multipart/data, les données sont envoyées sous forme de liste, c'est nul
_status = int(_status[0])
else:
_status = int(_status)
# Récupérer le dossier d'inscription
registerForm = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if not registerForm:
return JsonResponse({"error": "Dossier d'inscription introuvable"}, status=status.HTTP_404_NOT_FOUND)
studentForm_serializer = RegistrationFormSerializer(registerForm, data=studentForm_data, partial=True)
if studentForm_serializer.is_valid():
studentForm_serializer.save()
else:
return JsonResponse(studentForm_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
if _status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
# Le parent a rempli le dossier d'inscription sans sélectionner "Prélèvement par Mandat SEPA"
# L'école doit désormais valider le dossier d'inscription
try:
# Génération de la fiche d'inscription au format PDF
base_dir = os.path.join(settings.MEDIA_ROOT, f"registration_files/dossier_rf_{registerForm.pk}")
os.makedirs(base_dir, exist_ok=True)
# Fichier PDF initial
initial_pdf = f"{base_dir}/Inscription_{registerForm.student.last_name}_{registerForm.student.first_name}.pdf"
registerForm.registration_file = util.rfToPDF(registerForm, initial_pdf)
registerForm.save()
# Mise à jour de l'automate
# Vérification de la présence du fichier SEPA
if registerForm.sepa_file:
# Mise à jour de l'automate pour SEPA
updateStateMachine(registerForm, 'EVENT_SIGNATURE_SEPA')
else:
# Mise à jour de l'automate pour une signature classique
updateStateMachine(registerForm, 'EVENT_SIGNATURE')
except Exception as e:
return JsonResponse({'error': str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
elif _status == RegistrationForm.RegistrationFormStatus.RF_SENT:
if registerForm.status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
updateStateMachine(registerForm, 'EVENT_REFUSE')
util.delete_registration_files(registerForm)
elif _status == RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT:
# Sauvegarde du mandat SEPA
student = registerForm.student
guardian = student.getMainGuardian()
email = guardian.profile_role.profile.email
errorMessage = mailer.sendMandatSEPA(email, registerForm.establishment.pk)
if errorMessage != '':
return JsonResponse({"errorMessage": errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
registerForm.last_update = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
updateStateMachine(registerForm, 'EVENT_SEND_SEPA')
elif _status == RegistrationForm.RegistrationFormStatus.RF_SEPA_TO_SEND:
# Le parent a rempli le dossier d'inscription en sélectionnant "Prélèvement par Mandat SEPA"
# L'école doit désormais envoyer le mandat SEPA pour poursuivre l'inscription
updateStateMachine(registerForm, 'EVENT_WAITING_FOR_SEPA')
elif _status == RegistrationForm.RegistrationFormStatus.RF_VALIDATED:
# Vérifier si le paramètre fusion est activé via l'URL
fusion = studentForm_data.get('fusion', False)
if fusion:
# Fusion des documents
# Récupération des fichiers schoolFileTemplates
school_file_paths = RegistrationSchoolFileTemplate.get_files_from_rf(registerForm.pk)
# Récupération des fichiers parentFileTemplates
parent_file_templates = RegistrationParentFileTemplate.get_files_from_rf(registerForm.pk)
# Initialisation de la liste des fichiers à fusionner
fileNames = []
# Ajout du fichier registration_file en première position
if registerForm.registration_file:
fileNames.append(registerForm.registration_file.path)
# Ajout des fichiers schoolFileTemplates
fileNames.extend(school_file_paths)
# Ajout des fichiers parentFileTemplates
fileNames.extend(parent_file_templates)
# Création du fichier PDF fusionné
merged_pdf_content = util.merge_files_pdf(fileNames)
# Mise à jour du champ registration_file avec le fichier fusionné
registerForm.fusion_file.save(
f"dossier_complet.pdf",
File(merged_pdf_content),
save=True
)
updateStateMachine(registerForm, 'EVENT_VALIDATE')
# Retourner les données mises à jour
return JsonResponse(studentForm_serializer.data, safe=False)
@swagger_auto_schema(
responses={204: 'No Content'},
operation_description="Supprime un dossier d'inscription donné.",
operation_summary="Supprimer un dossier d'inscription"
)
@method_decorator(csrf_protect, name='dispatch')
@method_decorator(ensure_csrf_cookie, name='dispatch')
def delete(self, request, id):
"""
Supprime un dossier d'inscription donné.
"""
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.registration_files.clear()
student.delete()
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, status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Envoie le dossier d'inscription par e-mail",
operation_summary="Envoyer un dossier d'inscription"
)
@api_view(['GET'])
def send(request,id):
"""Envoie le dossier d'inscription par e-mail."""
register_form = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
if register_form != None:
student = register_form.student
guardian = student.getMainGuardian()
email = guardian.profile_role.profile.email
errorMessage = mailer.sendRegisterForm(email, register_form.establishment.pk)
if errorMessage == '':
register_form.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
updateStateMachine(register_form, 'EVENT_SEND')
return JsonResponse({"message": f"Le dossier d'inscription a bien été envoyé à l'addresse {email}"}, safe=False)
return JsonResponse({"errorMessage":errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
return JsonResponse({"errorMessage":'Dossier d\'inscription non trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Archive le dossier d'inscription",
operation_summary="Archiver un dossier d'inscription"
)
@api_view(['GET'])
def archive(request,id):
"""Archive le dossier d'inscription."""
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')
updateStateMachine(register_form, 'EVENT_ARCHIVE')
return JsonResponse({"message": "Le dossier a été archivé avec succès"}, safe=False)
return JsonResponse({"errorMessage":'Dossier d\'inscription non trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Relance un dossier d'inscription par e-mail",
operation_summary="Relancer un dossier d'inscription"
)
@api_view(['GET'])
def resend(request,id):
"""Relance un dossier d'inscription par e-mail."""
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({"message": f"Le dossier a été renvoyé à l'adresse {email}"}, safe=False)
return JsonResponse({"errorMessage":errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
return JsonResponse({"errorMessage":'Dossier d\'inscription non trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Récupère les fichiers à signer d'un dossier d'inscription donné",
operation_summary="Récupérer les fichiers à signer d'un dossier d'inscription donné"
)
@api_view(['GET'])
def get_school_file_templates_by_rf(request, id):
try:
# Récupérer les templates associés au RegistrationForm donné
templates = RegistrationSchoolFileTemplate.objects.filter(registration_form=id)
# Sérialiser les données
serializer = RegistrationSchoolFileTemplateSerializer(templates, many=True)
# Retourner les données sérialisées
return JsonResponse(serializer.data, safe=False)
except RegistrationSchoolFileTemplate.DoesNotExist:
return JsonResponse({'error': 'Aucun template trouvé pour ce dossier d\'inscription'}, status=status.HTTP_404_NOT_FOUND)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('Success', schema=openapi.Schema(
type=openapi.TYPE_OBJECT,
properties={
'message': openapi.Schema(type=openapi.TYPE_STRING)
}
))},
operation_description="Récupère les pièces à fournir d'un dossier d'inscription donné",
operation_summary="Récupérer les pièces à fournir d'un dossier d'inscription donné"
)
@api_view(['GET'])
def get_parent_file_templates_by_rf(request, id):
try:
# Récupérer les pièces à fournir associés au RegistrationForm donné
parent_files = RegistrationParentFileTemplate.objects.filter(registration_form=id)
# Sérialiser les données
serializer = RegistrationParentFileTemplateSerializer(parent_files, many=True)
# Retourner les données sérialisées
return JsonResponse(serializer.data, safe=False)
except RegistrationParentFileTemplate.DoesNotExist:
return JsonResponse({'error': 'Aucune pièce à fournir trouvée pour ce dossier d\'inscription'}, status=status.HTTP_404_NOT_FOUND)