fix: conflits + closeModal lors de la création d'un RF

This commit is contained in:
N3WT DE COMPET
2025-04-26 10:37:28 +02:00
parent 10f66c69dd
commit 1617b132c4
4 changed files with 178 additions and 144 deletions

View File

@ -262,21 +262,6 @@ class RegisterFormWithIdView(APIView):
registerForm.registration_file = util.rfToPDF(registerForm, initial_pdf) registerForm.registration_file = util.rfToPDF(registerForm, initial_pdf)
registerForm.save() registerForm.save()
# Récupération des fichiers d'inscription
# fileNames = RegistrationSchoolFileTemplate.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_content = util.merge_files_pdf(fileNames)
# # Mise à jour du champ registration_file avec le fichier fusionné
# registerForm.registration_file.save(
# f"dossier_complet.pdf",
# File(merged_pdf_content),
# save=True
# )
# Mise à jour de l'automate # Mise à jour de l'automate
# Vérification de la présence du fichier SEPA # Vérification de la présence du fichier SEPA
if registerForm.sepa_file: if registerForm.sepa_file:
@ -295,16 +280,35 @@ class RegisterFormWithIdView(APIView):
updateStateMachine(registerForm, 'EVENT_REFUSE') updateStateMachine(registerForm, 'EVENT_REFUSE')
util.delete_registration_files(registerForm) util.delete_registration_files(registerForm)
elif _status == RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT: elif _status == RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT:
# 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 d'inscription
fileNames = RegistrationSchoolFileTemplate.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_content = util.merge_files_pdf(fileNames)
# Mise à jour du champ registration_file avec le fichier fusionné
registerForm.registration_file.save(
f"dossier_complet.pdf",
File(merged_pdf_content),
save=True
)
# Sauvegarde du mandat SEPA # Sauvegarde du mandat SEPA
student = registerForm.student student = registerForm.student
guardian = student.getMainGuardian() guardian = student.getMainGuardian()
email = guardian.profile_role.profile.email email = guardian.profile_role.profile.email
errorMessage = mailer.sendMandatSEPA(email, registerForm.establishment.pk) errorMessage = mailer.sendMandatSEPA(email, registerForm.establishment.pk)
if errorMessage == '': if errorMessage == '':
registerForm.last_update=util.convertToStr(util._now(), '%d-%m-%Y %H:%M') registerForm.last_update = util.convertToStr(util._now(), '%d-%m-%Y %H:%M')
updateStateMachine(registerForm, 'EVENT_SEND_SEPA') updateStateMachine(registerForm, 'EVENT_SEND_SEPA')
return JsonResponse({"message": f"Le mandat SEPA a bien été envoyé à l'addresse {email}"}, safe=False) return JsonResponse({"message": f"Le mandat SEPA a bien été envoyé à l'adresse {email}"}, safe=False)
return JsonResponse({"errorMessage":errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST) return JsonResponse({"errorMessage": errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
# Retourner les données mises à jour # Retourner les données mises à jour
return JsonResponse(studentForm_serializer.data, safe=False) return JsonResponse(studentForm_serializer.data, safe=False)

View File

@ -24,7 +24,6 @@ import Modal from '@/components/Modal';
import InscriptionForm from '@/components/Inscription/InscriptionForm'; import InscriptionForm from '@/components/Inscription/InscriptionForm';
import AffectationClasseForm from '@/components/AffectationClasseForm'; import AffectationClasseForm from '@/components/AffectationClasseForm';
import { useEstablishment } from '@/context/EstablishmentContext'; import { useEstablishment } from '@/context/EstablishmentContext';
import ValidateSubscription from '@/components/Inscription/ValidateSubscription';
import { import {
PENDING, PENDING,
@ -56,8 +55,6 @@ import {
} from '@/app/actions/schoolAction'; } from '@/app/actions/schoolAction';
import { import {
createProfile,
deleteProfile,
fetchProfiles, fetchProfiles,
} from '@/app/actions/authAction'; } from '@/app/actions/authAction';
@ -115,6 +112,9 @@ export default function Page({ params: { locale } }) {
const [profiles, setProfiles] = useState([]); const [profiles, setProfiles] = useState([]);
const [isOpenAddGuardian, setIsOpenAddGuardian] = useState(false); const [isOpenAddGuardian, setIsOpenAddGuardian] = useState(false);
const [isFilesModalOpen, setIsFilesModalOpen] = useState(false);
const [selectedRowFiles, setSelectedRowFiles] = useState([]);
const csrfToken = useCsrfToken(); const csrfToken = useCsrfToken();
const router = useRouter(); const router = useRouter();
const { selectedEstablishmentId } = useEstablishment(); const { selectedEstablishmentId } = useEstablishment();
@ -141,7 +141,30 @@ export default function Page({ params: { locale } }) {
setStudent(eleveSelected); setStudent(eleveSelected);
}; };
const requestErrorHandler = (err) => { const openFilesModal = (row) => {
const files = [];
if (row.registration_file) {
files.push({
name: 'Fichier d\'inscription',
url: `${BASE_URL}${row.registration_file}`,
});
}
if (row.sepa_file) {
files.push({
name: 'Mandat SEPA',
url: `${BASE_URL}${row.sepa_file}`,
});
}
setSelectedRowFiles(files);
setIsFilesModalOpen(true);
};
const closeFilesModal = () => {
setIsFilesModalOpen(false);
setSelectedRowFiles([]);
};
const requestErrorHandler = (err)=>{
logger.error('Error fetching data:', err); logger.error('Error fetching data:', err);
}; };
@ -451,6 +474,7 @@ export default function Page({ params: { locale } }) {
const createRF = (updatedData) => { const createRF = (updatedData) => {
logger.debug('createRF updatedData:', updatedData); logger.debug('createRF updatedData:', updatedData);
const selectedRegistrationFeesIds = const selectedRegistrationFeesIds =
updatedData.selectedRegistrationFees.map((feeId) => feeId); updatedData.selectedRegistrationFees.map((feeId) => feeId);
const selectedRegistrationDiscountsIds = const selectedRegistrationDiscountsIds =
@ -538,8 +562,8 @@ export default function Page({ params: { locale } }) {
const parent_masters = parentFileMasters.filter((file) => const parent_masters = parentFileMasters.filter((file) =>
file.groups.includes(selectedFileGroup) file.groups.includes(selectedFileGroup)
); );
const clonePromises = masters
.map((templateMaster, index) => { const clonePromises = masters.map((templateMaster) => {
return cloneTemplate( return cloneTemplate(
templateMaster.id, templateMaster.id,
updatedData.guardianEmail, updatedData.guardianEmail,
@ -555,16 +579,13 @@ export default function Page({ params: { locale } }) {
registration_form: data.student.id, registration_form: data.student.id,
}; };
return createRegistrationSchoolFileTemplate( return createRegistrationSchoolFileTemplate(cloneData, csrfToken)
cloneData,
csrfToken
)
.then((response) => { .then((response) => {
logger.debug('Template enregistré avec succès:', response); logger.debug('Template enregistré avec succès:', response);
}) })
.catch((error) => { .catch((error) => {
logger.error( logger.error(
"Erreur lors de l'enregistrement du template:", 'Erreur lors de l\'enregistrement du template:',
error error
); );
}); });
@ -572,14 +593,10 @@ export default function Page({ params: { locale } }) {
.catch((error) => { .catch((error) => {
logger.error('Error during cloning or sending:', error); logger.error('Error during cloning or sending:', error);
}); });
})
.catch((error) => {
logger.error('Error:', error);
}); });
// Créer les parentFileTemplates pour chaque parentMaster // Créer les parentFileTemplates pour chaque parentMaster
const parentClonePromises = parent_masters.map( const parentClonePromises = parent_masters.map((parentMaster) => {
(parentMaster, index) => {
const parentTemplateData = { const parentTemplateData = {
master: parentMaster.id, master: parentMaster.id,
registration_form: data.student.id, registration_form: data.student.id,
@ -597,15 +614,14 @@ export default function Page({ params: { locale } }) {
}) })
.catch((error) => { .catch((error) => {
logger.error( logger.error(
"Erreur lors de l'enregistrement du parent template:", 'Erreur lors de l\'enregistrement du parent template:',
error error
); );
}); });
} });
);
// Attendre que tous les clones soient créés // Attendre que tous les clones (school et parent) soient créés
Promise.all(clonePromises) Promise.all([...clonePromises, ...parentClonePromises])
.then(() => { .then(() => {
// Mise à jour immédiate des données // Mise à jour immédiate des données
setRegistrationFormsDataPending((prevState) => [ setRegistrationFormsDataPending((prevState) => [
@ -620,7 +636,7 @@ export default function Page({ params: { locale } }) {
updatedData.studentFirstName updatedData.studentFirstName
); );
} }
closeModal(); closeModal(); // Appeler closeModal ici après que tout soit terminé
// Forcer le rechargement complet des données // Forcer le rechargement complet des données
setReloadFetch(true); setReloadFetch(true);
}) })
@ -755,6 +771,14 @@ export default function Page({ params: { locale } }) {
}, },
], ],
3: [ 3: [
{
icon: (
<span title="Voir les fichiers">
<FileText className="w-5 h-5 text-cyan-500 hover:text-cyan-700" />
</span>
),
onClick: () => openFilesModal(row),
},
{ {
icon: ( icon: (
<span title="Valider le dossier"> <span title="Valider le dossier">
@ -781,6 +805,16 @@ export default function Page({ params: { locale } }) {
onClick: () => openModalAssociationEleve(row.student), onClick: () => openModalAssociationEleve(row.student),
}, },
], ],
7: [
{
icon: (
<span title="Voir les fichiers">
<FileText className="w-5 h-5 text-cyan-500 hover:text-cyan-700" />
</span>
),
onClick: () => openFilesModal(row),
},
],
default: [ default: [
{ {
icon: ( icon: (
@ -1147,6 +1181,30 @@ export default function Page({ params: { locale } }) {
)} )}
/> />
)} )}
{isFilesModalOpen && (
<Modal
isOpen={isFilesModalOpen}
setIsOpen={setIsFilesModalOpen}
title="Fichiers disponibles"
ContentComponent={() => (
<ul className="space-y-4">
{selectedRowFiles.map((file, index) => (
<li key={index} className="flex items-center gap-2">
<FileText className="w-5 h-5 text-gray-500" />
<a
href={file.url}
target="_blank"
rel="noopener noreferrer"
className="text-blue-500 hover:text-blue-700 underline"
>
{file.name}
</a>
</li>
))}
</ul>
)}
/>
)}
</div> </div>
); );
} }

View File

@ -23,10 +23,11 @@ export default function Page() {
const handleAcceptRF = (data) => { const handleAcceptRF = (data) => {
logger.debug('Mise à jour du RF avec les données:', data); logger.debug('Mise à jour du RF avec les données:', data);
const { status, sepa_file } = data; const {status, sepa_file, fusionParam} = data
const formData = new FormData(); const formData = new FormData();
formData.append('status', status); // Ajoute le statut formData.append('status', status); // Ajoute le statut
formData.append('sepa_file', sepa_file); // Ajoute le fichier SEPA formData.append('sepa_file', sepa_file); // Ajoute le fichier SEPA
formData.append('fusion', fusionParam);
// Appeler l'API pour mettre à jour le RF // Appeler l'API pour mettre à jour le RF
sendSEPARegisterForm(studentId, formData, csrfToken) sendSEPARegisterForm(studentId, formData, csrfToken)

View File

@ -4,10 +4,7 @@ import Button from '@/components/Button';
import ToggleSwitch from '@/components/ToggleSwitch'; // Import du composant ToggleSwitch import ToggleSwitch from '@/components/ToggleSwitch'; // Import du composant ToggleSwitch
import { BASE_URL } from '@/utils/Url'; import { BASE_URL } from '@/utils/Url';
import { generateToken } from '@/app/actions/registerFileGroupAction'; import { generateToken } from '@/app/actions/registerFileGroupAction';
import { import { fetchSchoolFileTemplatesFromRegistrationFiles, fetchParentFileTemplatesFromRegistrationFiles } from '@/app/actions/subscriptionAction';
fetchSchoolFileTemplatesFromRegistrationFiles,
fetchParentFileTemplatesFromRegistrationFiles,
} from '@/app/actions/subscriptionAction';
import logger from '@/utils/logger'; import logger from '@/utils/logger';
import { GraduationCap } from 'lucide-react'; import { GraduationCap } from 'lucide-react';
import FileUpload from '@/components/FileUpload'; import FileUpload from '@/components/FileUpload';
@ -50,12 +47,7 @@ export default function ValidateSubscription({
setSchoolFileTemplates(data); setSchoolFileTemplates(data);
logger.debug('Fichiers schoolFileTemplates récupérés:', data); logger.debug('Fichiers schoolFileTemplates récupérés:', data);
}) })
.catch((error) => .catch((error) => logger.error('Erreur lors de la récupération des schoolFileTemplates:', error));
logger.error(
'Erreur lors de la récupération des schoolFileTemplates:',
error
)
);
// Récupérer les fichiers parentFileTemplates pour l'étudiant // Récupérer les fichiers parentFileTemplates pour l'étudiant
fetchParentFileTemplatesFromRegistrationFiles(studentId) fetchParentFileTemplatesFromRegistrationFiles(studentId)
@ -63,12 +55,7 @@ export default function ValidateSubscription({
setParentFileTemplates(data); setParentFileTemplates(data);
logger.debug('Fichiers parentFileTemplates récupérés:', data); logger.debug('Fichiers parentFileTemplates récupérés:', data);
}) })
.catch((error) => .catch((error) => logger.error('Erreur lors de la récupération des parentFileTemplates:', error));
logger.error(
'Erreur lors de la récupération des parentFileTemplates:',
error
)
);
}, [studentId]); }, [studentId]);
const handleAccept = () => { const handleAccept = () => {
@ -83,7 +70,7 @@ export default function ValidateSubscription({
const data = { const data = {
status: 7, status: 7,
sepa_file: selectedFile, // Utilise le fichier sélectionné depuis l'état sepa_file: selectedFile, // Utilise le fichier sélectionné depuis l'état
fusionParam: fusionParam, fusionParam: fusionParam
}; };
// Appeler la fonction passée par le parent pour mettre à jour le RF // Appeler la fonction passée par le parent pour mettre à jour le RF
@ -98,11 +85,7 @@ export default function ValidateSubscription({
const isValidateButtonDisabled = isSepa && !uploadedFileName; const isValidateButtonDisabled = isSepa && !uploadedFileName;
const goToNextPage = () => { const goToNextPage = () => {
const totalPages = const totalPages = 1 + schoolFileTemplates.length + parentFileTemplates.length + (isSepa ? 1 : 0);
1 +
schoolFileTemplates.length +
parentFileTemplates.length +
(isSepa ? 1 : 0);
if (currentPage < totalPages) { if (currentPage < totalPages) {
setCurrentPage(currentPage + 1); setCurrentPage(currentPage + 1);
} }
@ -114,11 +97,7 @@ export default function ValidateSubscription({
} }
}; };
const totalPages = const totalPages = 1 + schoolFileTemplates.length + parentFileTemplates.length + (isSepa ? 1 : 0);
1 +
schoolFileTemplates.length +
parentFileTemplates.length +
(isSepa ? 1 : 0);
const renderContent = () => { const renderContent = () => {
if (currentPage === 1) { if (currentPage === 1) {
@ -135,10 +114,7 @@ export default function ValidateSubscription({
}} }}
/> />
); );
} else if ( } else if (currentPage > 1 && currentPage <= 1 + schoolFileTemplates.length) {
currentPage > 1 &&
currentPage <= 1 + schoolFileTemplates.length
) {
// Pages des schoolFileTemplates // Pages des schoolFileTemplates
const index = currentPage - 2; // Décalage pour correspondre à l'index du tableau const index = currentPage - 2; // Décalage pour correspondre à l'index du tableau
return ( return (
@ -153,10 +129,7 @@ export default function ValidateSubscription({
}} }}
/> />
); );
} else if ( } else if (currentPage > 1 + schoolFileTemplates.length && currentPage <= 1 + schoolFileTemplates.length + parentFileTemplates.length) {
currentPage > 1 + schoolFileTemplates.length &&
currentPage <= 1 + schoolFileTemplates.length + parentFileTemplates.length
) {
// Pages des parentFileTemplates // Pages des parentFileTemplates
const index = currentPage - 2 - schoolFileTemplates.length; // Décalage pour correspondre à l'index du tableau const index = currentPage - 2 - schoolFileTemplates.length; // Décalage pour correspondre à l'index du tableau
return ( return (
@ -202,9 +175,7 @@ export default function ValidateSubscription({
{/* Option de fusion des documents (affichée uniquement sur la dernière page) */} {/* Option de fusion des documents (affichée uniquement sur la dernière page) */}
{currentPage === totalPages && ( {currentPage === totalPages && (
<div className="flex items-center justify-between mt-6"> <div className="flex items-center justify-between mt-6">
<span className="text-gray-700"> <span className="text-gray-700">Fusionner les documents en un seul fichier PDF</span>
Fusionner les documents en un seul fichier PDF
</span>
<ToggleSwitch <ToggleSwitch
label="Fusionner" label="Fusionner"
checked={mergeDocuments} checked={mergeDocuments}