From 59aee80c2e7592a7cdb119d1d30a5ad2c8bb20b0 Mon Sep 17 00:00:00 2001 From: N3WT DE COMPET Date: Thu, 17 Apr 2025 19:06:28 +0200 Subject: [PATCH] feat: Gestion des documents parent --- Back-End/Subscriptions/models.py | 3 +- Back-End/Subscriptions/serializers.py | 7 +- Back-End/Subscriptions/urls.py | 17 +- Back-End/Subscriptions/views/__init__.py | 13 +- .../views/register_form_views.py | 10 +- .../views/registration_file_views.py | 81 ++++- .../app/[locale]/admin/subscriptions/page.js | 31 +- .../app/actions/registerFileGroupAction.js | 302 ++++++++++-------- .../src/app/actions/subscriptionAction.js | 15 +- .../components/Inscription/FilesToUpload.js | 4 +- .../Inscription/InscriptionFormShared.js | 57 ++-- .../Structure/Files/FileUploadDocuSeal.js | 13 +- .../Structure/Files/FilesGroupsManagement.js | 5 +- .../Structure/Files/ParentFilesSection.js | 43 ++- Front-End/src/utils/Url.js | 7 +- 15 files changed, 402 insertions(+), 206 deletions(-) diff --git a/Back-End/Subscriptions/models.py b/Back-End/Subscriptions/models.py index a670af8..26283b6 100644 --- a/Back-End/Subscriptions/models.py +++ b/Back-End/Subscriptions/models.py @@ -283,8 +283,7 @@ class RegistrationSchoolFileTemplate(models.Model): ####### Parent files templates (par dossier d'inscription) ####### class RegistrationParentFileTemplate(models.Model): - master = models.ForeignKey(RegistrationSchoolFileMaster, on_delete=models.CASCADE, related_name='parent_file_templates', blank=True) - name = models.CharField(max_length=255, default="") + master = models.ForeignKey(RegistrationParentFileMaster, on_delete=models.CASCADE, related_name='parent_file_templates', blank=True) registration_form = models.ForeignKey(RegistrationForm, on_delete=models.CASCADE, related_name='parent_file_templates', blank=True) file = models.FileField(null=True,blank=True, upload_to=registration_file_upload_to) diff --git a/Back-End/Subscriptions/serializers.py b/Back-End/Subscriptions/serializers.py index 78bf8f4..aad1cfa 100644 --- a/Back-End/Subscriptions/serializers.py +++ b/Back-End/Subscriptions/serializers.py @@ -1,5 +1,5 @@ from rest_framework import serializers -from .models import RegistrationFileGroup, RegistrationForm, Student, Guardian, Sibling, Language, RegistrationSchoolFileMaster, RegistrationSchoolFileTemplate, RegistrationParentFileMaster +from .models import RegistrationFileGroup, RegistrationForm, Student, Guardian, Sibling, Language, RegistrationSchoolFileMaster, RegistrationSchoolFileTemplate, RegistrationParentFileMaster, RegistrationParentFileTemplate from School.models import SchoolClass, Fee, Discount, FeeType from School.serializers import FeeSerializer, DiscountSerializer from Auth.models import ProfileRole, Profile @@ -27,6 +27,7 @@ class RegistrationParentFileMasterSerializer(serializers.ModelSerializer): class RegistrationSchoolFileTemplateSerializer(serializers.ModelSerializer): id = serializers.IntegerField(required=False) file_url = serializers.SerializerMethodField() + class Meta: model = RegistrationSchoolFileTemplate fields = '__all__' @@ -38,8 +39,10 @@ class RegistrationSchoolFileTemplateSerializer(serializers.ModelSerializer): class RegistrationParentFileTemplateSerializer(serializers.ModelSerializer): id = serializers.IntegerField(required=False) file = serializers.SerializerMethodField() + master_name = serializers.CharField(source='master.name', read_only=True) + master_description = serializers.CharField(source='master.description', read_only=True) class Meta: - model = RegistrationParentFileMaster + model = RegistrationParentFileTemplate fields = '__all__' def get_file(self, obj): diff --git a/Back-End/Subscriptions/urls.py b/Back-End/Subscriptions/urls.py index eb5bb4b..00cdc91 100644 --- a/Back-End/Subscriptions/urls.py +++ b/Back-End/Subscriptions/urls.py @@ -7,7 +7,17 @@ from .views import RegisterFormView, RegisterFormWithIdView, send, resend, archi # SubClasses from .views import StudentView, GuardianView, ChildrenListView, StudentListView, DissociateGuardianView # Files -from .views import RegistrationSchoolFileMasterView, RegistrationSchoolFileMasterSimpleView, RegistrationSchoolFileTemplateView, RegistrationSchoolFileTemplateSimpleView, RegistrationParentFileMasterSimpleView, RegistrationParentFileMasterView +from .views import ( + RegistrationSchoolFileMasterView, + RegistrationSchoolFileMasterSimpleView, + RegistrationSchoolFileTemplateView, + RegistrationSchoolFileTemplateSimpleView, + RegistrationParentFileMasterSimpleView, + RegistrationParentFileMasterView, + RegistrationParentFileTemplateSimpleView, + RegistrationParentFileTemplateView +) + from .views import RegistrationFileGroupView, RegistrationFileGroupSimpleView, get_registration_files_by_group from .views import registration_file_views, get_school_file_templates_by_rf, get_parent_file_templates_by_rf @@ -17,7 +27,7 @@ urlpatterns = [ re_path(r'^registerForms/(?P[0-9]+)/send$', send, name="send"), re_path(r'^registerForms/(?P[0-9]+)$', RegisterFormWithIdView.as_view(), name="registerForm"), re_path(r'^registerForms/(?P[0-9]+)/school_file_templates$', get_school_file_templates_by_rf, name="get_school_file_templates_by_rf"), - re_path(r'^registerForms/(?P[0-9]+)/parent_file_templatess$', get_parent_file_templates_by_rf, name="get_parent_file_templates_by_rf"), + re_path(r'^registerForms/(?P[0-9]+)/parent_file_templates$', get_parent_file_templates_by_rf, name="get_parent_file_templates_by_rf"), re_path(r'^registerForms$', RegisterFormView.as_view(), name="registerForms"), # Page INSCRIPTION - Liste des élèves @@ -43,6 +53,9 @@ urlpatterns = [ re_path(r'^registrationSchoolFileTemplates/(?P[0-9]+)$', RegistrationSchoolFileTemplateSimpleView.as_view(), name='registrationSchoolFileTemplates'), re_path(r'^registrationSchoolFileTemplates$', RegistrationSchoolFileTemplateView.as_view(), name="registrationSchoolFileTemplates"), + re_path(r'^registrationParentFileTemplates/(?P[0-9]+)$', RegistrationParentFileTemplateSimpleView.as_view(), name='registrationParentFileTemplates'), + re_path(r'^registrationParentFileTemplates$', RegistrationParentFileTemplateView.as_view(), name="registrationSchoolFileTregistrationParentFileTemplatesemplates"), + re_path(r'^students/(?P[0-9]+)/guardians/(?P[0-9]+)/dissociate', DissociateGuardianView.as_view(), name='dissociate-guardian'), ] \ No newline at end of file diff --git a/Back-End/Subscriptions/views/__init__.py b/Back-End/Subscriptions/views/__init__.py index c505486..fb24394 100644 --- a/Back-End/Subscriptions/views/__init__.py +++ b/Back-End/Subscriptions/views/__init__.py @@ -1,5 +1,14 @@ from .register_form_views import RegisterFormView, RegisterFormWithIdView, send, resend, archive, get_school_file_templates_by_rf, get_parent_file_templates_by_rf -from .registration_file_views import RegistrationSchoolFileMasterView, RegistrationSchoolFileMasterSimpleView, RegistrationSchoolFileTemplateView, RegistrationSchoolFileTemplateSimpleView, RegistrationParentFileMasterView, RegistrationParentFileMasterSimpleView +from .registration_file_views import ( + RegistrationSchoolFileMasterView, + RegistrationSchoolFileMasterSimpleView, + RegistrationSchoolFileTemplateView, + RegistrationSchoolFileTemplateSimpleView, + RegistrationParentFileMasterView, + RegistrationParentFileMasterSimpleView, + RegistrationParentFileTemplateSimpleView, + RegistrationParentFileTemplateView +) from .registration_file_group_views import RegistrationFileGroupView, RegistrationFileGroupSimpleView, get_registration_files_by_group from .student_views import StudentView, StudentListView, ChildrenListView from .guardian_views import GuardianView, DissociateGuardianView @@ -16,6 +25,8 @@ __all__ = [ 'RegistrationParentFileMasterView', 'RegistrationSchoolFileMasterView', 'RegistrationSchoolFileMasterSimpleView', + 'RegistrationParentFileTemplateSimpleView', + 'RegistrationParentFileTemplateView', 'RegistrationFileGroupView', 'RegistrationFileGroupSimpleView', 'get_registration_files_by_group', diff --git a/Back-End/Subscriptions/views/register_form_views.py b/Back-End/Subscriptions/views/register_form_views.py index 1d07885..3d57610 100644 --- a/Back-End/Subscriptions/views/register_form_views.py +++ b/Back-End/Subscriptions/views/register_form_views.py @@ -14,9 +14,9 @@ from django.core.files import File import Subscriptions.mailManager as mailer import Subscriptions.util as util -from Subscriptions.serializers import RegistrationFormSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileMasterSerializer +from Subscriptions.serializers import RegistrationFormSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileTemplateSerializer from Subscriptions.pagination import CustomPagination -from Subscriptions.models import Student, Guardian, RegistrationForm, RegistrationSchoolFileTemplate, RegistrationFileGroup, RegistrationParentFileMaster +from Subscriptions.models import Student, Guardian, RegistrationForm, RegistrationSchoolFileTemplate, RegistrationFileGroup, RegistrationParentFileTemplate from Subscriptions.automate import updateStateMachine from N3wtSchool import settings, bdd @@ -441,12 +441,12 @@ def get_school_file_templates_by_rf(request, id): def get_parent_file_templates_by_rf(request, id): try: # Récupérer les pièces à fournir associés au RegistrationForm donné - parent_files = RegistrationParentFileMaster.objects.filter(registration_form=id) + parent_files = RegistrationParentFileTemplate.objects.filter(registration_form=id) # Sérialiser les données - serializer = RegistrationParentFileMasterSerializer(parent_files, many=True) + serializer = RegistrationParentFileTemplateSerializer(parent_files, many=True) # Retourner les données sérialisées return JsonResponse(serializer.data, safe=False) - except RegistrationSchoolFileTemplate.DoesNotExist: + except RegistrationParentFileTemplate.DoesNotExist: return JsonResponse({'error': 'Aucune pièce à fournir trouvée pour ce dossier d\'inscription'}, status=status.HTTP_404_NOT_FOUND) \ No newline at end of file diff --git a/Back-End/Subscriptions/views/registration_file_views.py b/Back-End/Subscriptions/views/registration_file_views.py index dd1e93c..2a02ced 100644 --- a/Back-End/Subscriptions/views/registration_file_views.py +++ b/Back-End/Subscriptions/views/registration_file_views.py @@ -6,8 +6,8 @@ from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import status -from Subscriptions.serializers import RegistrationSchoolFileMasterSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileMasterSerializer -from Subscriptions.models import RegistrationSchoolFileMaster, RegistrationSchoolFileTemplate, RegistrationParentFileMaster +from Subscriptions.serializers import RegistrationSchoolFileMasterSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileMasterSerializer, RegistrationParentFileTemplateSerializer +from Subscriptions.models import RegistrationSchoolFileMaster, RegistrationSchoolFileTemplate, RegistrationParentFileMaster, RegistrationParentFileTemplate from N3wtSchool import bdd class RegistrationSchoolFileMasterView(APIView): @@ -183,7 +183,6 @@ class RegistrationParentFileMasterView(APIView): return Response(serializer.data, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) - class RegistrationParentFileMasterSimpleView(APIView): @swagger_auto_schema( operation_description="Récupère un fichier parent spécifique", @@ -231,4 +230,78 @@ class RegistrationParentFileMasterSimpleView(APIView): template.delete() return JsonResponse({'message': 'La suppression du fichier parent a été effectuée avec succès'}, safe=False, status=status.HTTP_204_NO_CONTENT) else: - return JsonResponse({'erreur': 'Le fichier parent n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND) \ No newline at end of file + return JsonResponse({'erreur': 'Le fichier parent n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND) + +class RegistrationParentFileTemplateView(APIView): + @swagger_auto_schema( + operation_description="Récupère tous les templates d'inscription", + responses={200: RegistrationParentFileTemplateSerializer(many=True)} + ) + def get(self, request): + templates = RegistrationParentFileTemplate.objects.all() + serializer = RegistrationParentFileTemplateSerializer(templates, many=True) + return Response(serializer.data) + + @swagger_auto_schema( + operation_description="Crée un nouveau template d'inscription", + request_body=RegistrationParentFileTemplateSerializer, + responses={ + 201: RegistrationParentFileTemplateSerializer, + 400: "Données invalides" + } + ) + def post(self, request): + serializer = RegistrationParentFileTemplateSerializer(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) + +class RegistrationParentFileTemplateSimpleView(APIView): + @swagger_auto_schema( + operation_description="Récupère un template d'inscription spécifique", + responses={ + 200: RegistrationParentFileTemplateSerializer, + 404: "Template non trouvé" + } + ) + def get(self, request, id): + template = bdd.getObject(_objectName=RegistrationParentFileTemplate, _columnName='id', _value=id) + if template is None: + return JsonResponse({"errorMessage":'Le template d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND) + serializer = RegistrationParentFileTemplateSerializer(template) + return JsonResponse(serializer.data, safe=False) + + @swagger_auto_schema( + operation_description="Met à jour un template d'inscription existant", + request_body=RegistrationParentFileTemplateSerializer, + responses={ + 200: RegistrationParentFileTemplateSerializer, + 400: "Données invalides", + 404: "Template non trouvé" + } + ) + def put(self, request, id): + template = bdd.getObject(_objectName=RegistrationParentFileTemplate, _columnName='id', _value=id) + if template is None: + return JsonResponse({'erreur': 'Le template d\'inscription n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND) + serializer = RegistrationParentFileTemplateSerializer(template, data=request.data) + if serializer.is_valid(): + serializer.save() + return Response({'message': 'Template mis à jour avec succès', 'data': serializer.data}, status=status.HTTP_200_OK) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + @swagger_auto_schema( + operation_description="Supprime un template d'inscription", + responses={ + 204: "Suppression réussie", + 404: "Template non trouvé" + } + ) + def delete(self, request, id): + template = bdd.getObject(_objectName=RegistrationParentFileTemplate, _columnName='id', _value=id) + if template is not None: + template.delete() + return JsonResponse({'message': 'La suppression du template a été effectuée avec succès'}, safe=False, status=status.HTTP_204_NO_CONTENT) + else: + return JsonResponse({'erreur': 'Le template n\'a pas été trouvé'}, safe=False, status=status.HTTP_404_NOT_FOUND) diff --git a/Front-End/src/app/[locale]/admin/subscriptions/page.js b/Front-End/src/app/[locale]/admin/subscriptions/page.js index 312fac6..65659dc 100644 --- a/Front-End/src/app/[locale]/admin/subscriptions/page.js +++ b/Front-End/src/app/[locale]/admin/subscriptions/page.js @@ -29,7 +29,9 @@ import { import { fetchRegistrationSchoolFileMasters, - createRegistrationTemplates, + fetchRegistrationParentFileMasters, + createRegistrationSchoolFileTemplate, + createRegistrationParentFileTemplate, fetchRegistrationFileGroups, cloneTemplate } from "@/app/actions/registerFileGroupAction"; @@ -73,6 +75,7 @@ export default function Page({ params: { locale } }) { const [itemsPerPage, setItemsPerPage] = useState(10); // Définir le nombre d'éléments par page const [schoolFileMasters, setSchoolFileMasters] = useState([]); + const [parentFileMasters, setParentFileMasters] = useState([]); const [isOpen, setIsOpen] = useState(false); const [isOpenAffectationClasse, setIsOpenAffectationClasse] = useState(false); const [student, setStudent] = useState(''); @@ -220,6 +223,13 @@ useEffect(() => { .catch(err => { logger.debug(err.message); }), + fetchRegistrationParentFileMasters() + .then(data => { + setParentFileMasters(data); + }) + .catch(err => { + logger.debug(err.message); + }), fetchRegistrationDiscounts(selectedEstablishmentId) .then(data => { setRegistrationDiscounts(data); @@ -462,6 +472,7 @@ useEffect(()=>{ .then(data => { // Cloner les schoolFileTemplates pour chaque templateMaster du fileGroup const masters = schoolFileMasters.filter(file => file.groups.includes(selectedFileGroup)); + const parent_masters = parentFileMasters.filter(file => file.groups.includes(selectedFileGroup)); const clonePromises = masters.map((templateMaster, index) => { return cloneTemplate(templateMaster.id, updatedData.guardianEmail, templateMaster.is_required) .then(clonedDocument => { @@ -474,7 +485,7 @@ useEffect(()=>{ registration_form: data.student.id }; - return createRegistrationTemplates(cloneData, csrfToken) + return createRegistrationSchoolFileTemplate(cloneData, csrfToken) .then(response => { logger.debug('Template enregistré avec succès:', response); }) @@ -487,6 +498,22 @@ useEffect(()=>{ }); }); + // Créer les parentFileTemplates pour chaque parentMaster + const parentClonePromises = parent_masters.map((parentMaster, index) => { + const parentTemplateData = { + master: parentMaster.id, + registration_form: data.student.id + }; + + return createRegistrationParentFileTemplate(parentTemplateData, csrfToken) + .then(response => { + logger.debug('Parent template enregistré avec succès:', response); + }) + .catch(error => { + logger.error('Erreur lors de l\'enregistrement du parent template:', error); + }); + }); + // Attendre que tous les clones soient créés Promise.all(clonePromises) .then(() => { diff --git a/Front-End/src/app/actions/registerFileGroupAction.js b/Front-End/src/app/actions/registerFileGroupAction.js index 4253303..56c39d7 100644 --- a/Front-End/src/app/actions/registerFileGroupAction.js +++ b/Front-End/src/app/actions/registerFileGroupAction.js @@ -1,7 +1,8 @@ import { BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL, BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL, - BE_SUBSCRIPTION_REGISTRATIONSCHOOL_FILE_MASTERS_URL, + BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_MASTERS_URL, BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL, + BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_TEMPLATES_URL, FE_API_DOCUSEAL_CLONE_URL, FE_API_DOCUSEAL_DOWNLOAD_URL, FE_API_DOCUSEAL_GENERATE_TOKEN @@ -17,7 +18,9 @@ const requestResponseHandler = async (response) => { const error = new Error(body?.errorMessage || "Une erreur est survenue"); error.details = body; throw error; -} +}; + +// FETCH requests export async function fetchRegistrationFileGroups(establishment) { const response = await fetch(`${BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL}?establishment_id=${establishment}`, { @@ -30,7 +33,73 @@ export async function fetchRegistrationFileGroups(establishment) { throw new Error('Failed to fetch file groups'); } return response.json(); -} +}; + +export const fetchRegistrationFileFromGroup = async (groupId) => { + const response = await fetch(`${BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL}/${groupId}/school_file_templates`, { + credentials: 'include', + headers: { + 'Accept': 'application/json', + } + }); + if (!response.ok) { + throw new Error('Erreur lors de la récupération des fichiers associés au groupe'); + } + return response.json(); +}; + +export const fetchRegistrationSchoolFileMasters = (id = null) => { + let url = `${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_MASTERS_URL}`; + if(id){ + url = `${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_MASTERS_URL}/${id}`; + } + const request = new Request( + `${url}`, + { + method:'GET', + headers: { + 'Content-Type':'application/json' + }, + } + ); + return fetch(request).then(requestResponseHandler) +}; + +export const fetchRegistrationParentFileMasters = (id = null) => { + let url = `${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}` + if (id) { + url = `${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}/${id}`; + } + const request = new Request( + `${url}`, + { + method:'GET', + headers: { + 'Content-Type':'application/json' + }, + } + ); + return fetch(request).then(requestResponseHandler) +}; + +export const fetchRegistrationSchoolFileTemplates = (id = null) => { + let url = `${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL}` + if (id) { + url = `${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL}/${id}`; + } + const request = new Request( + `${url}`, + { + method:'GET', + headers: { + 'Content-Type':'application/json' + }, + } + ); + return fetch(request).then(requestResponseHandler) +}; + +// CREATE requests export async function createRegistrationFileGroup(groupData, csrfToken) { const response = await fetch(`${BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL}`, { @@ -48,19 +117,62 @@ export async function createRegistrationFileGroup(groupData, csrfToken) { } return response.json(); -} +}; -export async function deleteRegistrationFileGroup(groupId, csrfToken) { - const response = await fetch(`${BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL}/${groupId}`, { - method: 'DELETE', +export const createRegistrationSchoolFileMaster = (data,csrfToken) => { + return fetch(`${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_MASTERS_URL}`, { + method: 'POST', + body: JSON.stringify(data), headers: { 'X-CSRFToken': csrfToken, + 'Content-Type':'application/json' }, - credentials: 'include' - }); + credentials: 'include', + }) + .then(requestResponseHandler) +}; - return response; -} +export const createRegistrationParentFileMaster = (data,csrfToken) => { + return fetch(`${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}`, { + method: 'POST', + body: JSON.stringify(data), + headers: { + 'X-CSRFToken': csrfToken, + 'Content-Type': 'application/json', + }, + credentials: 'include', + }) + .then(requestResponseHandler) +}; + +export const createRegistrationSchoolFileTemplate = (data,csrfToken) => { + return fetch(`${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL}`, { + method: 'POST', + body: JSON.stringify(data), + headers: { + 'X-CSRFToken': csrfToken, + 'Content-Type': 'application/json', + }, + credentials: 'include', + }) + .then(requestResponseHandler) +}; + +export const createRegistrationParentFileTemplate = (data,csrfToken) => { + + return fetch(`${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_TEMPLATES_URL}`, { + method: 'POST', + body: JSON.stringify(data), + headers: { + 'X-CSRFToken': csrfToken, + 'Content-Type': 'application/json', + }, + credentials: 'include', + }) + .then(requestResponseHandler) +}; + +// EDIT requests export const editRegistrationFileGroup = async (groupId, groupData, csrfToken) => { const response = await fetch(`${BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL}/${groupId}`, { @@ -79,49 +191,18 @@ export const editRegistrationFileGroup = async (groupId, groupData, csrfToken) = return response.json(); }; -export const fetchRegistrationFileFromGroup = async (groupId) => { - const response = await fetch(`${BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL}/${groupId}/schoolFileTemplates`, { - credentials: 'include', - headers: { - 'Accept': 'application/json', - } - }); - if (!response.ok) { - throw new Error('Erreur lors de la récupération des fichiers associés au groupe'); - } - return response.json(); -} - -export const fetchRegistrationParentFileMasters = (id = null) => { - let url = `${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}` - if (id) { - url = `${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}/${id}`; - } - const request = new Request( - `${url}`, - { - method:'GET', - headers: { - 'Content-Type':'application/json' - }, - } - ); - return fetch(request).then(requestResponseHandler) -}; - -export const createRegistrationParentFileMaster = (data,csrfToken) => { - - return fetch(`${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}`, { - method: 'POST', +export const editRegistrationSchoolFileMaster = (fileId, data, csrfToken) => { + return fetch(`${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_MASTERS_URL}/${fileId}`, { + method: 'PUT', body: JSON.stringify(data), headers: { 'X-CSRFToken': csrfToken, - 'Content-Type': 'application/json', + 'Content-Type':'application/json' }, credentials: 'include', }) - .then(requestResponseHandler) -} + .then(requestResponseHandler) +}; export const editRegistrationParentFileMaster = (id, data, csrfToken) => { return fetch(`${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}/${id}`, { @@ -134,36 +215,9 @@ export const editRegistrationParentFileMaster = (id, data, csrfToken) => { credentials: 'include', }) .then(requestResponseHandler) -} - -export const deleteRegistrationParentFileMaster = (id, csrfToken) => { - return fetch(`${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}/${id}`, { - method: 'DELETE', - headers: { - 'X-CSRFToken': csrfToken, - }, - credentials: 'include', - }) -} - -export const fetchRegistrationSchoolFileTemplates = (id = null) => { - let url = `${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL}` - if (id) { - url = `${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL}/${id}`; - } - const request = new Request( - `${url}`, - { - method:'GET', - headers: { - 'Content-Type':'application/json' - }, - } - ); - return fetch(request).then(requestResponseHandler) }; -export const editRegistrationTemplates = (fileId, data, csrfToken) => { +export const editRegistrationSchoolFileTemplates = (fileId, data, csrfToken) => { return fetch(`${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL}/${fileId}`, { method: 'PUT', body: data, @@ -173,23 +227,43 @@ export const editRegistrationTemplates = (fileId, data, csrfToken) => { credentials: 'include', }) .then(requestResponseHandler) -} +}; -export const createRegistrationTemplates = (data,csrfToken) => { +// DELETE requests - return fetch(`${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL}`, { - method: 'POST', - body: JSON.stringify(data), +export async function deleteRegistrationFileGroup(groupId, csrfToken) { + const response = await fetch(`${BE_SUBSCRIPTION_REGISTRATIONFILE_GROUPS_URL}/${groupId}`, { + method: 'DELETE', + headers: { + 'X-CSRFToken': csrfToken, + }, + credentials: 'include' + }); + + return response; +}; + +export const deleteRegistrationSchoolFileMaster = (fileId,csrfToken) => { + return fetch(`${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_MASTERS_URL}/${fileId}`, { + method: 'DELETE', headers: { 'X-CSRFToken': csrfToken, - 'Content-Type': 'application/json', }, credentials: 'include', }) - .then(requestResponseHandler) -} +}; -export const deleteRegistrationTemplates = (fileId,csrfToken) => { +export const deleteRegistrationParentFileMaster = (id, csrfToken) => { + return fetch(`${BE_SUBSCRIPTION_REGISTRATION_PARENT_FILE_MASTERS_URL}/${id}`, { + method: 'DELETE', + headers: { + 'X-CSRFToken': csrfToken, + }, + credentials: 'include', + }) +}; + +export const deleteRegistrationSchoolFileTemplates = (fileId,csrfToken) => { return fetch(`${BE_SUBSCRIPTION_REGISTRATION_SCHOOL_FILE_TEMPLATES_URL}/${fileId}`, { method: 'DELETE', headers: { @@ -197,61 +271,9 @@ export const deleteRegistrationTemplates = (fileId,csrfToken) => { }, credentials: 'include', }) -} - -export const fetchRegistrationSchoolFileMasters = (id = null) => { - let url = `${BE_SUBSCRIPTION_REGISTRATIONSCHOOL_FILE_MASTERS_URL}`; - if(id){ - url = `${BE_SUBSCRIPTION_REGISTRATIONSCHOOL_FILE_MASTERS_URL}/${id}`; - } - const request = new Request( - `${url}`, - { - method:'GET', - headers: { - 'Content-Type':'application/json' - }, - } - ); - return fetch(request).then(requestResponseHandler) }; -export const createRegistrationSchoolFileMaster = (data,csrfToken) => { - - return fetch(`${BE_SUBSCRIPTION_REGISTRATIONSCHOOL_FILE_MASTERS_URL}`, { - method: 'POST', - body: JSON.stringify(data), - headers: { - 'X-CSRFToken': csrfToken, - 'Content-Type':'application/json' - }, - credentials: 'include', - }) - .then(requestResponseHandler) -} - -export const deleteRegistrationSchoolFileMaster = (fileId,csrfToken) => { - return fetch(`${BE_SUBSCRIPTION_REGISTRATIONSCHOOL_FILE_MASTERS_URL}/${fileId}`, { - method: 'DELETE', - headers: { - 'X-CSRFToken': csrfToken, - }, - credentials: 'include', - }) -} - -export const editRegistrationSchoolFileMaster = (fileId, data, csrfToken) => { - return fetch(`${BE_SUBSCRIPTION_REGISTRATIONSCHOOL_FILE_MASTERS_URL}/${fileId}`, { - method: 'PUT', - body: JSON.stringify(data), - headers: { - 'X-CSRFToken': csrfToken, - 'Content-Type':'application/json' - }, - credentials: 'include', - }) - .then(requestResponseHandler) -} +// API requests export const cloneTemplate = (templateId, email, is_required) => { return fetch(`${FE_API_DOCUSEAL_CLONE_URL}`, { @@ -266,7 +288,7 @@ export const cloneTemplate = (templateId, email, is_required) => { }) }) .then(requestResponseHandler) -} +}; export const downloadTemplate = (slug) => { return fetch(`${FE_API_DOCUSEAL_DOWNLOAD_URL}/${slug}`, { @@ -276,7 +298,7 @@ export const downloadTemplate = (slug) => { } }) .then(requestResponseHandler) -} +}; export const generateToken = (email, id = null) => { return fetch(`${FE_API_DOCUSEAL_GENERATE_TOKEN}`, { diff --git a/Front-End/src/app/actions/subscriptionAction.js b/Front-End/src/app/actions/subscriptionAction.js index b8fc993..c5e39a1 100644 --- a/Front-End/src/app/actions/subscriptionAction.js +++ b/Front-End/src/app/actions/subscriptionAction.js @@ -162,7 +162,20 @@ export const fetchSchoolFileTemplatesFromRegistrationFiles = async (id) => { throw new Error('Erreur lors de la récupération des fichiers associés au groupe'); } return response.json(); -} +}; + +export const fetchParentFileTemplatesFromRegistrationFiles = async (id) => { + const response = await fetch(`${BE_SUBSCRIPTION_REGISTERFORMS_URL}/${id}/parent_file_templates`, { + credentials: 'include', + headers: { + 'Accept': 'application/json', + } + }); + if (!response.ok) { + throw new Error('Erreur lors de la récupération des fichiers associés au groupe'); + } + return response.json(); +}; export const dissociateGuardian = async (studentId, guardianId) => { const response = await fetch(`${BE_SUBSCRIPTION_STUDENTS_URL}/${studentId}/guardians/${guardianId}/dissociate`, { diff --git a/Front-End/src/components/Inscription/FilesToUpload.js b/Front-End/src/components/Inscription/FilesToUpload.js index 78a713a..f52ba97 100644 --- a/Front-End/src/components/Inscription/FilesToUpload.js +++ b/Front-End/src/components/Inscription/FilesToUpload.js @@ -1,12 +1,12 @@ import React from 'react'; import Table from '@/components/Table'; -export default function FilesToUpload({ fileTemplates, columns }) { +export default function FilesToUpload({ parentFileTemplates, columns }) { return (

Fichiers à uploader

{ fetchSchoolFileTemplatesFromRegistrationFiles(studentId).then((data) => { - setFileTemplates(data); + setSchoolFileTemplates(data); + }) + + fetchParentFileTemplatesFromRegistrationFiles(studentId).then((data) => { + setParentFileTemplates(data); }) - }, []); - useEffect(() => { if (selectedEstablishmentId) { // Fetch data for registration payment modes handleRegistrationPaymentModes(); @@ -164,7 +167,7 @@ export default function InscriptionFormShared({ data.append('register_form', formData.id); try { - const response = await createRegistrationTemplates(data, csrfToken); + const response = await createRegistrationSchoolFileTemplate(data, csrfToken); if (response) { setUploadedFiles(prev => { const newFiles = prev.filter(f => parseInt(f.template) !== currentTemplateId); @@ -205,7 +208,7 @@ export default function InscriptionFormShared({ if (!fileToDelete) return; try { - await deleteRegistrationTemplates(fileToDelete.id, csrfToken); + await deleteRegistrationSchoolFileTemplates(fileToDelete.id, csrfToken); setUploadedFiles(prev => prev.filter(f => parseInt(f.template) !== templateId)); } catch (error) { logger.error('Error deleting file:', error); @@ -249,12 +252,10 @@ export default function InscriptionFormShared({ setCurrentPage(currentPage - 1); }; - const requiredFileTemplates = fileTemplates; - // Configuration des colonnes pour le tableau des fichiers const columns = [ - { name: 'Nom du fichier', transform: (row) => row.name }, - { name: 'Fichier à Remplir', transform: (row) => row.is_required ? 'Oui' : 'Non' }, + { name: 'Nom du fichier', transform: (row) => row.master_name }, + { name: 'Description du fichier', transform: (row) => row.master_description }, { name: 'Fichier de référence', transform: (row) => row.file && }, @@ -328,34 +329,34 @@ export default function InscriptionFormShared({ )} {/* Pages suivantes : Section Fichiers d'inscription */} - {currentPage > 1 && currentPage <= requiredFileTemplates.length + 1 && ( + {currentPage > 1 && currentPage <= schoolFileTemplates.length + 1 && (
{/* Titre du document */}

- {requiredFileTemplates[currentPage - 2].name || "Document sans nom"} + {schoolFileTemplates[currentPage - 2].name || "Document sans nom"}

- {requiredFileTemplates[currentPage - 2].description || "Aucune description disponible pour ce document."} + {schoolFileTemplates[currentPage - 2].description || "Aucune description disponible pour ce document."}

{/* Affichage du formulaire ou du document */} - {requiredFileTemplates[currentPage - 2].file === null ? ( + {schoolFileTemplates[currentPage - 2].file === null ? ( { - downloadTemplate(requiredFileTemplates[currentPage - 2].slug) + downloadTemplate(schoolFileTemplates[currentPage - 2].slug) .then((data) => fetch(data)) .then((response) => response.blob()) .then((blob) => { - const file = new File([blob], `${requiredFileTemplates[currentPage - 2].name}.pdf`, { type: blob.type }); + const file = new File([blob], `${schoolFileTemplates[currentPage - 2].name}.pdf`, { type: blob.type }); const updateData = new FormData(); updateData.append('file', file); - return editRegistrationTemplates(requiredFileTemplates[currentPage - 2].id, updateData, csrfToken); + return editRegistrationSchoolFileTemplates(schoolFileTemplates[currentPage - 2].id, updateData, csrfToken); }) .then((data) => { logger.debug("EDIT TEMPLATE : ", data); @@ -367,7 +368,7 @@ export default function InscriptionFormShared({ /> ) : (