feat(backend,frontend): régénération et visualisation inline de la fiche élève PDF

This commit is contained in:
Luc SORIGNET
2026-04-04 17:40:46 +02:00
parent 2d678b732f
commit e37aee2abc
8 changed files with 487 additions and 268 deletions

View File

@ -1,4 +1,5 @@
from django.http.response import JsonResponse
from django.http import HttpResponse
from django.views.decorators.csrf import ensure_csrf_cookie, csrf_protect
from django.utils.decorators import method_decorator
from rest_framework.views import APIView
@ -365,7 +366,7 @@ class RegisterFormWithIdView(APIView):
student = registerForm.student
student_name = f"{student.first_name} {student.last_name}"
notes = registerForm.notes or "Aucun motif spécifié"
guardians = student.guardians.all()
for guardian in guardians:
email = None
@ -373,13 +374,13 @@ class RegisterFormWithIdView(APIView):
email = guardian.profile_role.profile.email
if not email:
email = getattr(guardian, "email", None)
if email:
logger.info(f"[RF_SENT] Envoi email de refus à {email} pour l'élève {student_name}")
mailer.sendRefusDossier(email, registerForm.establishment.pk, student_name, notes)
except Exception as e:
logger.error(f"[RF_SENT] Erreur lors de l'envoi de l'email de refus: {e}")
updateStateMachine(registerForm, 'EVENT_REFUSE')
util.delete_registration_files(registerForm)
elif _status == RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT:
@ -411,6 +412,17 @@ class RegisterFormWithIdView(APIView):
# Initialisation de la liste des fichiers à fusionner
fileNames = []
# Régénérer la fiche élève avec le nouveau template avant fusion
try:
base_dir = os.path.join(settings.MEDIA_ROOT, f"registration_files/dossier_rf_{registerForm.pk}")
os.makedirs(base_dir, exist_ok=True)
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()
logger.debug(f"[RF_VALIDATED] Fiche élève régénérée avant fusion")
except Exception as e:
logger.error(f"[RF_VALIDATED] Erreur lors de la régénération de la fiche élève: {e}")
# Ajout du fichier registration_file en première position
if registerForm.registration_file:
fileNames.append(registerForm.registration_file.path)
@ -488,7 +500,7 @@ class RegisterFormWithIdView(APIView):
class_name = None
if student.associated_class:
class_name = student.associated_class.atmosphere_name
guardians = student.guardians.all()
for guardian in guardians:
email = None
@ -496,13 +508,13 @@ class RegisterFormWithIdView(APIView):
email = guardian.profile_role.profile.email
if not email:
email = getattr(guardian, "email", None)
if email:
logger.info(f"[RF_VALIDATED] Envoi email de validation à {email} pour l'élève {student_name}")
mailer.sendValidationDossier(email, registerForm.establishment.pk, student_name, class_name)
except Exception as e:
logger.error(f"[RF_VALIDATED] Erreur lors de l'envoi de l'email de validation: {e}")
# Lancer l'envoi d'email dans un thread séparé pour ne pas bloquer la réponse
email_thread = threading.Thread(target=send_validation_emails)
email_thread.start()
@ -518,7 +530,7 @@ class RegisterFormWithIdView(APIView):
student = registerForm.student
student_name = f"{student.first_name} {student.last_name}"
notes = data.get('notes', '') or "Aucun motif spécifié"
guardians = student.guardians.all()
for guardian in guardians:
email = None
@ -526,17 +538,17 @@ class RegisterFormWithIdView(APIView):
email = guardian.profile_role.profile.email
if not email:
email = getattr(guardian, "email", None)
if email:
logger.info(f"[RF_ARCHIVED] Envoi email de refus définitif à {email} pour l'élève {student_name}")
mailer.sendRefusDefinitif(email, registerForm.establishment.pk, student_name, notes)
except Exception as e:
logger.error(f"[RF_ARCHIVED] Erreur lors de l'envoi de l'email de refus définitif: {e}")
# Lancer l'envoi d'email dans un thread séparé pour ne pas bloquer la réponse
email_thread = threading.Thread(target=send_refus_definitif_emails)
email_thread.start()
updateStateMachine(registerForm, 'EVENT_ARCHIVE')
# Retourner les données mises à jour
@ -946,3 +958,26 @@ def get_parent_file_templates_by_rf(request, id):
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)
@swagger_auto_schema(
method='get',
responses={200: openapi.Response('PDF file', schema=openapi.Schema(type=openapi.TYPE_FILE))},
operation_description="Génère et retourne le PDF de la fiche élève à la volée",
operation_summary="Télécharger la fiche élève (régénérée)"
)
@api_view(['GET'])
def generate_registration_pdf(request, id):
try:
registerForm = RegistrationForm.objects.select_related('student', 'establishment').get(student__id=id)
except RegistrationForm.DoesNotExist:
return JsonResponse({"error": "Dossier d'inscription introuvable"}, status=status.HTTP_404_NOT_FOUND)
try:
pdf_content = util.generateRegistrationPDF(registerForm)
except ValueError as e:
return JsonResponse({"error": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
filename = f"Inscription_{registerForm.student.last_name}_{registerForm.student.first_name}.pdf"
response = HttpResponse(pdf_content, content_type='application/pdf')
response['Content-Disposition'] = f'inline; filename="{filename}"'
return response