diff --git a/Back-End/Subscriptions/Configuration/automate.json b/Back-End/Subscriptions/Configuration/automate.json
index 0249aa3..a142479 100644
--- a/Back-End/Subscriptions/Configuration/automate.json
+++ b/Back-End/Subscriptions/Configuration/automate.json
@@ -44,6 +44,11 @@
"from": "ENVOYE",
"to": "ARCHIVE"
},
+ {
+ "name": "refuseDI",
+ "from": "EN_VALIDATION",
+ "to": "ENVOYE"
+ },
{
"name": "valideDI",
"from": "EN_VALIDATION",
diff --git a/Back-End/Subscriptions/util.py b/Back-End/Subscriptions/util.py
index 622bac5..21e0a0a 100644
--- a/Back-End/Subscriptions/util.py
+++ b/Back-End/Subscriptions/util.py
@@ -16,7 +16,9 @@ from enum import Enum
import random
import string
from rest_framework.parsers import JSONParser
-import pymupdf
+from PyPDF2 import PdfMerger
+
+import shutil
def recupereListeFichesInscription():
"""
@@ -96,23 +98,29 @@ def merge_files_pdf(filenames, output_filename):
Fusionne plusieurs fichiers PDF en un seul document.
Vérifie l'existence des fichiers sources avant la fusion.
"""
- merger = pymupdf.open()
+ merger = PdfMerger()
valid_files = []
# Vérifier l'existence des fichiers et ne garder que ceux qui existent
+ print(f'filenames : {filenames}')
for filename in filenames:
+ print(f'check exists filename : {filename}')
if os.path.exists(filename):
+ print(f'append filename : {filename}')
valid_files.append(filename)
- # Fusionner les fichiers valides
+ if not valid_files:
+ raise FileNotFoundError("Aucun fichier valide à fusionner.")
+
+ # Ajouter les fichiers valides au merger
for filename in valid_files:
- merger.insert_file(filename)
+ merger.append(filename)
# S'assurer que le dossier de destination existe
os.makedirs(os.path.dirname(output_filename), exist_ok=True)
# Sauvegarder le fichier fusionné
- merger.save(output_filename)
+ merger.write(output_filename)
merger.close()
return output_filename
@@ -134,6 +142,11 @@ def rfToPDF(registerForm, filename):
# Générer le PDF
pdf = renderers.render_to_pdf('pdfs/dossier_inscription.html', data)
+ # Vérifier si un fichier avec le même nom existe déjà et le supprimer
+ if registerForm.registration_file and os.path.exists(registerForm.registration_file.path):
+ os.remove(registerForm.registration_file.path)
+ registerForm.registration_file.delete(save=False)
+
# Écrire le fichier directement
with open(filename, 'wb') as f:
f.write(pdf.content)
@@ -146,4 +159,16 @@ def rfToPDF(registerForm, filename):
save=True
)
- return registerForm.registration_file
\ No newline at end of file
+ return filename
+
+def delete_registration_files(registerForm):
+ """
+ Supprime le fichier et le dossier associés à un RegistrationForm.
+ """
+ base_dir = f"registration_files/dossier_rf_{registerForm.pk}"
+ if registerForm.registration_file and os.path.exists(registerForm.registration_file.path):
+ os.remove(registerForm.registration_file.path)
+ registerForm.registration_file.delete(save=False)
+
+ if os.path.exists(base_dir):
+ shutil.rmtree(base_dir)
\ No newline at end of file
diff --git a/Back-End/Subscriptions/views/guardian_views.py b/Back-End/Subscriptions/views/guardian_views.py
index 221c2fd..d04fe84 100644
--- a/Back-End/Subscriptions/views/guardian_views.py
+++ b/Back-End/Subscriptions/views/guardian_views.py
@@ -4,10 +4,12 @@ from rest_framework.views import APIView
from drf_yasg.utils import swagger_auto_schema
from drf_yasg import openapi
-from Subscriptions.models import Guardian, Student
+from Subscriptions.models import Guardian, Student, RegistrationForm
from Auth.models import ProfileRole
from N3wtSchool import bdd
+import Subscriptions.util as util
+
class GuardianView(APIView):
"""
Gestion des responsables légaux.
@@ -74,6 +76,16 @@ class DissociateGuardianView(APIView):
# Supprimer le guardian
guardian.delete()
+ # Récupérer le RegistrationForm associé au Student
+ registerForm = bdd.getObject(RegistrationForm, "student__id", student_id)
+ if registerForm:
+ # Réinitialiser le statut en "Créé"
+ registerForm.status = RegistrationForm.RegistrationFormStatus.RF_CREATED
+ registerForm.save()
+
+ # Supprimer le fichier et le dossier associés
+ util.delete_registration_files(registerForm)
+
return JsonResponse(
{
"message": f"Le guardian {guardian.last_name} {guardian.first_name} a été dissocié de l'étudiant {student.last_name} {student.first_name}.",
diff --git a/Back-End/Subscriptions/views/register_form_views.py b/Back-End/Subscriptions/views/register_form_views.py
index 347aa33..b9c304e 100644
--- a/Back-End/Subscriptions/views/register_form_views.py
+++ b/Back-End/Subscriptions/views/register_form_views.py
@@ -238,7 +238,7 @@ class RegisterFormWithIdView(APIView):
if _status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
try:
# Génération de la fiche d'inscription au format PDF
- base_dir = f"data/registration_files/dossier_rf_{registerForm.pk}"
+ base_dir = f"registration_files/dossier_rf_{registerForm.pk}"
os.makedirs(base_dir, exist_ok=True)
# Fichier PDF initial
@@ -248,11 +248,13 @@ class RegisterFormWithIdView(APIView):
# Récupération des fichiers d'inscription
fileNames = RegistrationTemplate.get_files_from_rf(registerForm.pk)
+
if registerForm.registration_file:
fileNames.insert(0, registerForm.registration_file.path)
# Création du fichier PDF Fusionné
merged_pdf = f"{base_dir}/dossier_complet_{registerForm.pk}.pdf"
+
util.merge_files_pdf(fileNames, merged_pdf)
# Mise à jour du champ registration_file avec le fichier fusionné
@@ -271,6 +273,14 @@ class RegisterFormWithIdView(APIView):
# L'école a validé le dossier d'inscription
# Mise à jour de l'automate
updateStateMachine(registerForm, 'valideDI')
+ elif _status == RegistrationForm.RegistrationFormStatus.RF_SENT:
+ # Vérifier si l'étape précédente était RF_UNDER_REVIEW
+ if registerForm.status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
+ # Mise à jour de l'automate
+ updateStateMachine(registerForm, 'refuseDI')
+
+ # Supprimer le fichier et le dossier associés
+ util.delete_registration_files(registerForm)
studentForm_serializer = RegistrationFormSerializer(registerForm, data=studentForm_data)
if studentForm_serializer.is_valid():
diff --git a/Back-End/requirements.txt b/Back-End/requirements.txt
index 85047c7..dd546a6 100644
Binary files a/Back-End/requirements.txt and b/Back-End/requirements.txt differ
diff --git a/Front-End/src/app/[locale]/admin/subscriptions/page.js b/Front-End/src/app/[locale]/admin/subscriptions/page.js
index 45218ff..628fc89 100644
--- a/Front-End/src/app/[locale]/admin/subscriptions/page.js
+++ b/Front-End/src/app/[locale]/admin/subscriptions/page.js
@@ -1,7 +1,6 @@
'use client'
import React, { useState, useEffect } from 'react';
import Table from '@/components/Table';
-import {mockFicheInscription} from '@/data/mockFicheInscription';
import Tab from '@/components/Tab';
import { useTranslations } from 'next-intl';
import StatusLabel from '@/components/StatusLabel';
@@ -11,7 +10,7 @@ import Loader from '@/components/Loader';
import AlertWithModal from '@/components/AlertWithModal';
import DropdownMenu from "@/components/DropdownMenu";
import { formatPhoneNumber } from '@/utils/Telephone';
-import { MoreVertical, Send, Edit, Trash2, FileText, CheckCircle, Plus } from 'lucide-react';
+import { MoreVertical, Send, Edit, Trash2, FileText, CheckCircle, Plus, TicketX } from 'lucide-react';
import Modal from '@/components/Modal';
import InscriptionForm from '@/components/Inscription/InscriptionForm'
import AffectationClasseForm from '@/components/AffectationClasseForm'
@@ -364,8 +363,27 @@ useEffect(()=>{
});
}
+ const refuseRegistrationForm = (id, lastname, firstname, guardianEmail) => {
+ const data = { status: 2, establishment: selectedEstablishmentId };
+
+ setPopup({
+ visible: true,
+ message: `Avertissement ! \nVous êtes sur le point de refuser le dossier d'inscription de ${lastname} ${firstname}\nUne notification va être envoyée à l'adresse ${guardianEmail}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`,
+ onConfirm: () => {
+ editRegisterForm(id, data, csrfToken)
+ .then(data => {
+ logger.debug('Success:', data);
+ setReloadFetch(true);
+ })
+ .catch(error => {
+ logger.error('Error refusing RF:', error);
+ });
+ }
+ });
+ };
+
const updateStatusAction = (id, newStatus) => {
- logger.debug('Edit fiche inscription with id:', id);
+ logger.debug(`Mise à jour du statut du dossier d'inscription avec l'ID : ${id} vers le statut : ${newStatus}`);
};
const handleSearchChange = (event) => {
@@ -447,7 +465,7 @@ useEffect(()=>{
.then(clonedDocument => {
// Sauvegarde des templates clonés dans la base de données
const cloneData = {
- name: `clone_${clonedDocument.id}`,
+ name: `${templateMaster.name}_${updatedData.guardianFirstName}_${updatedData.guardianLastName}`,
slug: clonedDocument.slug,
id: clonedDocument.id,
master: templateMaster.id,
@@ -555,6 +573,80 @@ useEffect(()=>{
});
}
+ const getActionsByStatus = (row) => {
+ const actions = {
+ 1: [
+ {
+ label: (
+ <>
+
+ {requiredFileTemplates[currentPage - 2].description || "Aucune description disponible pour ce document."} +
+