feat: Ajout d'un nouvel état dans l'automatique lorsqu'un mandat SEPA

doit être envoyé aux parent
This commit is contained in:
N3WT DE COMPET
2025-04-27 13:40:48 +02:00
parent 3c62cc9ad2
commit 545349c7db
14 changed files with 214 additions and 153 deletions

View File

@ -30,6 +30,16 @@
"from": "SENT", "from": "SENT",
"to": "UNDER_REVIEW" "to": "UNDER_REVIEW"
}, },
{
"name": "EVENT_WAITING_FOR_SEPA",
"from": "SENT",
"to": "SEPA_TO_SEND"
},
{
"name": "EVENT_SEND_SEPA",
"from": "SEPA_TO_SEND",
"to": "SEPA_SENT"
},
{ {
"name": "EVENT_FOLLOW_UP", "name": "EVENT_FOLLOW_UP",
"from": "SENT", "from": "SENT",
@ -55,11 +65,6 @@
"from": "UNDER_REVIEW", "from": "UNDER_REVIEW",
"to": "VALIDATED" "to": "VALIDATED"
}, },
{
"name": "EVENT_SEND_SEPA",
"from": "UNDER_REVIEW",
"to": "SEPA_SENT"
},
{ {
"name": "EVENT_ARCHIVE", "name": "EVENT_ARCHIVE",
"from": "UNDER_REVIEW", "from": "UNDER_REVIEW",

View File

@ -10,7 +10,8 @@ state_mapping = {
"TO_BE_FOLLOWED_UP": RegistrationForm.RegistrationFormStatus.RF_TO_BE_FOLLOWED_UP, "TO_BE_FOLLOWED_UP": RegistrationForm.RegistrationFormStatus.RF_TO_BE_FOLLOWED_UP,
"VALIDATED": RegistrationForm.RegistrationFormStatus.RF_VALIDATED, "VALIDATED": RegistrationForm.RegistrationFormStatus.RF_VALIDATED,
"ARCHIVED": RegistrationForm.RegistrationFormStatus.RF_ARCHIVED, "ARCHIVED": RegistrationForm.RegistrationFormStatus.RF_ARCHIVED,
"SEPA_SENT": RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT "SEPA_SENT": RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT,
"SEPA_TO_SEND": RegistrationForm.RegistrationFormStatus.RF_SEPA_TO_SEND
} }
def load_config(config_file): def load_config(config_file):

View File

@ -182,6 +182,7 @@ class RegistrationForm(models.Model):
RF_VALIDATED = 5, _('Dossier d\'inscription validé') RF_VALIDATED = 5, _('Dossier d\'inscription validé')
RF_ARCHIVED = 6, _('Dossier d\'inscription archivé') RF_ARCHIVED = 6, _('Dossier d\'inscription archivé')
RF_SEPA_SENT = 7, _('Mandat SEPA envoyé') RF_SEPA_SENT = 7, _('Mandat SEPA envoyé')
RF_SEPA_TO_SEND = 8, _('Mandat SEPA à envoyer')
# One-to-One Relationship # One-to-One Relationship
student = models.OneToOneField(Student, on_delete=models.CASCADE, primary_key=True) student = models.OneToOneField(Student, on_delete=models.CASCADE, primary_key=True)

View File

@ -252,6 +252,8 @@ class RegisterFormWithIdView(APIView):
return JsonResponse(studentForm_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST) return JsonResponse(studentForm_serializer.errors, safe=False, status=status.HTTP_400_BAD_REQUEST)
if _status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW: 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: try:
# Génération de la fiche d'inscription au format PDF # 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}") base_dir = os.path.join(settings.MEDIA_ROOT, f"registration_files/dossier_rf_{registerForm.pk}")
@ -304,11 +306,14 @@ class RegisterFormWithIdView(APIView):
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 != '':
return JsonResponse({"errorMessage": errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST)
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'adresse {email}"}, safe=False) elif _status == RegistrationForm.RegistrationFormStatus.RF_SEPA_TO_SEND:
return JsonResponse({"errorMessage": errorMessage}, safe=False, status=status.HTTP_400_BAD_REQUEST) # 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')
# 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

@ -101,7 +101,8 @@ class ChildrenListView(APIView):
status__in=[ status__in=[
RegistrationForm.RegistrationFormStatus.RF_SENT, RegistrationForm.RegistrationFormStatus.RF_SENT,
RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW, RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW,
RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT RegistrationForm.RegistrationFormStatus.RF_SEPA_SENT,
RegistrationForm.RegistrationFormStatus.RF_SEPA_TO_SEND
] ]
).distinct() ).distinct()
students_serializer = RegistrationFormByParentSerializer(students, many=True) students_serializer = RegistrationFormByParentSerializer(students, many=True)

View File

@ -7,6 +7,7 @@ import { useCsrfToken } from '@/context/CsrfContext';
import { useEstablishment } from '@/context/EstablishmentContext'; import { useEstablishment } from '@/context/EstablishmentContext';
import { editRegisterForm } from '@/app/actions/subscriptionAction'; import { editRegisterForm } from '@/app/actions/subscriptionAction';
import logger from '@/utils/logger'; import logger from '@/utils/logger';
import Loader from '@/components/Loader';
export default function Page() { export default function Page() {
const router = useRouter(); const router = useRouter();
@ -16,14 +17,18 @@ export default function Page() {
const [formErrors, setFormErrors] = useState({}); const [formErrors, setFormErrors] = useState({});
const csrfToken = useCsrfToken(); const csrfToken = useCsrfToken();
const { selectedEstablishmentId } = useEstablishment(); const { selectedEstablishmentId } = useEstablishment();
const [isLoading, setIsLoading] = useState(false);
const handleSubmit = (data) => { const handleSubmit = (data) => {
setIsLoading(true);
editRegisterForm(studentId, data, csrfToken) editRegisterForm(studentId, data, csrfToken)
.then((result) => { .then((result) => {
setIsLoading(false);
logger.debug('Success:', result); logger.debug('Success:', result);
router.push(FE_ADMIN_SUBSCRIPTIONS_URL); router.push(FE_ADMIN_SUBSCRIPTIONS_URL);
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false);
logger.error('Error:', error.message); logger.error('Error:', error.message);
if (error.details) { if (error.details) {
logger.error('Form errors:', error.details); logger.error('Form errors:', error.details);
@ -32,6 +37,10 @@ export default function Page() {
}); });
}; };
if (isLoading) {
return <Loader />;
}
return ( return (
<InscriptionFormShared <InscriptionFormShared
studentId={studentId} studentId={studentId}

View File

@ -18,7 +18,7 @@ import {
FileText, FileText,
CheckCircle, CheckCircle,
Plus, Plus,
XCircle, Upload,
} from 'lucide-react'; } from 'lucide-react';
import Modal from '@/components/Modal'; import Modal from '@/components/Modal';
import InscriptionForm from '@/components/Inscription/InscriptionForm'; import InscriptionForm from '@/components/Inscription/InscriptionForm';
@ -35,6 +35,7 @@ import {
archiveRegisterForm, archiveRegisterForm,
fetchStudents, fetchStudents,
editRegisterForm, editRegisterForm,
sendSEPARegisterForm,
} from '@/app/actions/subscriptionAction'; } from '@/app/actions/subscriptionAction';
import { import {
@ -66,6 +67,7 @@ import DjangoCSRFToken from '@/components/DjangoCSRFToken';
import { useCsrfToken } from '@/context/CsrfContext'; import { useCsrfToken } from '@/context/CsrfContext';
import logger from '@/utils/logger'; import logger from '@/utils/logger';
import { PhoneLabel } from '@/components/PhoneLabel'; import { PhoneLabel } from '@/components/PhoneLabel';
import FileUpload from '@/components/FileUpload';
export default function Page({ params: { locale } }) { export default function Page({ params: { locale } }) {
const t = useTranslations('subscriptions'); const t = useTranslations('subscriptions');
@ -80,11 +82,6 @@ export default function Page({ params: { locale } }) {
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [alertPage, setAlertPage] = useState(false); const [alertPage, setAlertPage] = useState(false);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [popup, setPopup] = useState({
visible: false,
message: '',
onConfirm: null,
});
const [activeTab, setActiveTab] = useState('pending'); const [activeTab, setActiveTab] = useState('pending');
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [totalPages, setTotalPages] = useState(1); const [totalPages, setTotalPages] = useState(1);
@ -113,10 +110,29 @@ export default function Page({ params: { locale } }) {
const [isFilesModalOpen, setIsFilesModalOpen] = useState(false); const [isFilesModalOpen, setIsFilesModalOpen] = useState(false);
const [selectedRowFiles, setSelectedRowFiles] = useState([]); const [selectedRowFiles, setSelectedRowFiles] = useState([]);
const [popupVisible, setPopupVisible] = useState(false);
const [popupMessage, setPopupMessage] = useState('');
const [confirmPopupVisible, setConfirmPopupVisible] = useState(false);
const [confirmPopupMessage, setConfirmPopupMessage] = useState('');
const [confirmPopupOnConfirm, setConfirmPopupOnConfirm] = useState(() => {});
const [isSepaUploadModalOpen, setIsSepaUploadModalOpen] = useState(false);
const [selectedRowForUpload, setSelectedRowForUpload] = useState(null);
const csrfToken = useCsrfToken(); const csrfToken = useCsrfToken();
const router = useRouter(); const router = useRouter();
const { selectedEstablishmentId } = useEstablishment(); const { selectedEstablishmentId } = useEstablishment();
const openSepaUploadModal = (row) => {
setSelectedRowForUpload(row);
setIsSepaUploadModalOpen(true);
};
const closeSepaUploadModal = () => {
setSelectedRowForUpload(null);
setIsSepaUploadModalOpen(false);
};
const openModal = () => { const openModal = () => {
setIsOpen(true); setIsOpen(true);
}; };
@ -221,28 +237,6 @@ export default function Page({ params: { locale } }) {
} }
}; };
useEffect(() => {
if (selectedEstablishmentId) {
const fetchInitialData = () => {
Promise.all([
fetchClasses(selectedEstablishmentId),
fetchStudents(selectedEstablishmentId),
])
.then(([classesData, studentsData]) => {
setClasses(classesData);
setEleves(studentsData);
logger.debug('Success - Classes:', classesData);
logger.debug('Success - Students:', studentsData);
})
.catch((error) => {
logger.error('Error fetching initial data:', error);
});
};
fetchInitialData();
}
}, [selectedEstablishmentId]);
useEffect(() => { useEffect(() => {
if (selectedEstablishmentId) { if (selectedEstablishmentId) {
const fetchDataAndSetState = () => { const fetchDataAndSetState = () => {
@ -257,6 +251,19 @@ export default function Page({ params: { locale } }) {
) )
.then(registerFormPendingDataHandler) .then(registerFormPendingDataHandler)
.catch(requestErrorHandler), .catch(requestErrorHandler),
fetchClasses(selectedEstablishmentId)
.then((classesData) => {
setClasses(classesData);
})
.catch(requestErrorHandler),
fetchStudents(selectedEstablishmentId)
.then((studentsData) => {
setEleves(studentsData);
})
.catch(requestErrorHandler),
fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED) fetchRegisterForms(selectedEstablishmentId, SUBSCRIBED)
.then(registerFormSubscribedDataHandler) .then(registerFormSubscribedDataHandler)
.catch(requestErrorHandler), .catch(requestErrorHandler),
@ -378,6 +385,33 @@ export default function Page({ params: { locale } }) {
setTotalPages(Math.ceil(totalArchives / itemsPerPage)); setTotalPages(Math.ceil(totalArchives / itemsPerPage));
} }
}, [currentPage]); }, [currentPage]);
const handleSepaFileUpload = (file, row) => {
if (!file || !row) {
logger.error("Aucun fichier ou ligne sélectionnée pour l'upload.");
return;
}
const formData = new FormData();
formData.append('status', 7);
formData.append('sepa_file', file);
// Appeler l'API pour uploader le fichier SEPA
sendSEPARegisterForm(row.student.id, formData, csrfToken)
.then((response) => {
logger.debug('Mandat SEPA uploadé avec succès :', response);
setPopupMessage('Le mandat SEPA a été uploadé avec succès.');
setPopupVisible(true);
setReloadFetch(true);
closeSepaUploadModal();
})
.catch((error) => {
logger.error("Erreur lors de l'upload du mandat SEPA :", error);
setPopupMessage("Erreur lors de l'upload du mandat SEPA.");
setPopupVisible(true);
});
};
/** /**
* Archives a registration form after user confirmation. * Archives a registration form after user confirmation.
* *
@ -386,44 +420,56 @@ export default function Page({ params: { locale } }) {
* @param {string} prenom - The first name of the person whose registration form is being archived. * @param {string} prenom - The first name of the person whose registration form is being archived.
*/ */
const archiveFicheInscription = (id, nom, prenom) => { const archiveFicheInscription = (id, nom, prenom) => {
setPopup({ setConfirmPopupMessage(
visible: true, `Attentions ! \nVous êtes sur le point d'archiver le dossier d'inscription de ${nom} ${prenom}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`
message: `Attentions ! \nVous êtes sur le point d'archiver le dossier d'inscription de ${nom} ${prenom}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`, );
onConfirm: () => { setConfirmPopupOnConfirm(() => () => {
archiveRegisterForm(id) archiveRegisterForm(id)
.then((data) => { .then((data) => {
logger.debug('Success:', data); logger.debug('Success:', data);
setPopupMessage(
`Le dossier d'inscription a été correctement archivé`
);
setPopupVisible(true);
setRegistrationForms( setRegistrationForms(
registrationForms.filter((fiche) => fiche.id !== id) registrationForms.filter((fiche) => fiche.id !== id)
); );
setReloadFetch(true); setReloadFetch(true);
alert("Le dossier d'inscription a été correctement archivé");
}) })
.catch((error) => { .catch((error) => {
logger.error('Error archiving data:', error); logger.error('Error archiving data:', error);
alert( setPopupMessage(
"Erreur lors de l'archivage du dossier d'inscription.\nContactez l'administrateur." `Erreur lors de l'archivage du dossier d'inscription.\nContactez l'administrateur.`
); );
setPopupVisible(true);
}); });
}, setConfirmPopupVisible(false);
}); });
setConfirmPopupVisible(true);
}; };
const sendConfirmRegisterForm = (id, nom, prenom) => { const sendConfirmRegisterForm = (id, nom, prenom) => {
setPopup({ setConfirmPopupMessage(
visible: true, `Avertissement ! \nVous êtes sur le point d'envoyer un dossier d'inscription à ${nom} ${prenom}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`
message: `Avertissement ! \nVous êtes sur le point d'envoyer un dossier d'inscription à ${nom} ${prenom}\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?`, );
onConfirm: () => { setConfirmPopupOnConfirm(() => () => {
sendRegisterForm(id) sendRegisterForm(id)
.then((data) => { .then((data) => {
logger.debug('Success:', data); logger.debug('Success:', data);
setPopupMessage(`Le dossier d'inscription a été envoyé avec succès`);
setPopupVisible(true);
setReloadFetch(true); setReloadFetch(true);
}) })
.catch((error) => { .catch((error) => {
logger.error('Error fetching data:', error); logger.error('Error archiving data:', error);
setPopupMessage(
`Erreur lors de l'envoi du dossier d'inscription.\nContactez l'administrateur.`
);
setPopupVisible(true);
}); });
}, setConfirmPopupVisible(false);
}); });
setConfirmPopupVisible(true);
}; };
const affectationClassFormSubmitHandler = (formdata) => { const affectationClassFormSubmitHandler = (formdata) => {
@ -437,25 +483,6 @@ export default function Page({ params: { locale } }) {
}); });
}; };
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) => { const updateStatusAction = (id, newStatus) => {
logger.debug( logger.debug(
`Mise à jour du statut du dossier d'inscription avec l'ID : ${id} vers le statut : ${newStatus}` `Mise à jour du statut du dossier d'inscription avec l'ID : ${id} vers le statut : ${newStatus}`
@ -551,6 +578,7 @@ export default function Page({ params: { locale } }) {
establishment: selectedEstablishmentId, establishment: selectedEstablishmentId,
}; };
setIsLoading(true);
createRegisterForm(data, csrfToken) createRegisterForm(data, csrfToken)
.then((data) => { .then((data) => {
// Cloner les schoolFileTemplates pour chaque templateMaster du fileGroup // Cloner les schoolFileTemplates pour chaque templateMaster du fileGroup
@ -582,6 +610,7 @@ export default function Page({ params: { locale } }) {
logger.debug('Template enregistré avec succès:', response); logger.debug('Template enregistré avec succès:', response);
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false);
logger.error( logger.error(
"Erreur lors de l'enregistrement du template:", "Erreur lors de l'enregistrement du template:",
error error
@ -589,6 +618,7 @@ export default function Page({ params: { locale } }) {
}); });
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false);
logger.error('Error during cloning or sending:', error); logger.error('Error during cloning or sending:', error);
}); });
}); });
@ -608,6 +638,7 @@ export default function Page({ params: { locale } }) {
logger.debug('Parent template enregistré avec succès:', response); logger.debug('Parent template enregistré avec succès:', response);
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false);
logger.error( logger.error(
"Erreur lors de l'enregistrement du parent template:", "Erreur lors de l'enregistrement du parent template:",
error error
@ -634,12 +665,15 @@ export default function Page({ params: { locale } }) {
closeModal(); // Appeler closeModal ici après que tout soit terminé 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);
setIsLoading(false);
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false);
logger.error('Error during cloning or sending:', error); logger.error('Error during cloning or sending:', error);
}); });
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false);
logger.error('Error:', error); logger.error('Error:', error);
}); });
}; };
@ -810,6 +844,24 @@ export default function Page({ params: { locale } }) {
onClick: () => openFilesModal(row), onClick: () => openFilesModal(row),
}, },
], ],
8: [
{
icon: (
<span title="Voir les fichiers">
<FileText className="w-5 h-5 text-cyan-500 hover:text-cyan-700" />
</span>
),
onClick: () => openFilesModal(row),
},
{
icon: (
<span title="Uploader un mandat SEPA">
<Upload className="w-5 h-5 text-emerald-500 hover:text-emerald-700" />
</span>
),
onClick: () => openSepaUploadModal(row),
},
],
default: [ default: [
{ {
icon: ( icon: (
@ -879,37 +931,6 @@ export default function Page({ params: { locale } }) {
</div> </div>
), ),
}, },
{
name: t('files'),
transform: (row) => (
<ul>
{row.registration_file && (
<li className="flex justify-center items-center gap-2">
<FileText size={16} />
<a
href={`${BASE_URL}${row.registration_file}`}
target="_blank"
rel="noopener noreferrer"
>
{row.registration_file?.split('/').pop()}
</a>
</li>
)}
{row.sepa_file && (
<li className="flex justify-center items-center gap-2">
<FileText size={16} />
<a
href={`${BASE_URL}${row.sepa_file}`}
target="_blank"
rel="noopener noreferrer"
>
{row.sepa_file?.split('/').pop()}
</a>
</li>
)}
</ul>
),
},
{ {
name: 'Actions', name: 'Actions',
transform: (row) => ( transform: (row) => (
@ -1116,13 +1137,16 @@ export default function Page({ params: { locale } }) {
) : null} ) : null}
</div> </div>
<Popup <Popup
visible={popup.visible} visible={popupVisible}
message={popup.message} message={popupMessage}
onConfirm={() => { onConfirm={() => setPopupVisible(false)}
popup.onConfirm(); uniqueConfirmButton={true}
setPopup({ ...popup, visible: false }); />
}} <Popup
onCancel={() => setPopup({ ...popup, visible: false })} visible={confirmPopupVisible}
message={confirmPopupMessage}
onConfirm={confirmPopupOnConfirm}
onCancel={() => setConfirmPopupVisible(false)}
/> />
{isOpen && ( {isOpen && (
@ -1176,6 +1200,21 @@ export default function Page({ params: { locale } }) {
)} )}
/> />
)} )}
{isSepaUploadModalOpen && (
<Modal
isOpen={isSepaUploadModalOpen}
setIsOpen={setIsSepaUploadModalOpen}
title="Uploader un mandat SEPA"
ContentComponent={() => (
<FileUpload
selectionMessage="Sélectionnez un mandat SEPA à uploader"
onFileSelect={(file) =>
handleSepaFileUpload(file, selectedRowForUpload)
}
/>
)}
/>
)}
{isFilesModalOpen && ( {isFilesModalOpen && (
<Modal <Modal
isOpen={isFilesModalOpen} isOpen={isFilesModalOpen}

View File

@ -24,15 +24,16 @@ export default function ParentHomePage() {
const [uploadState, setUploadState] = useState('off'); // État "on" ou "off" pour l'affichage du composant const [uploadState, setUploadState] = useState('off'); // État "on" ou "off" pour l'affichage du composant
const router = useRouter(); const router = useRouter();
const csrfToken = useCsrfToken(); const csrfToken = useCsrfToken();
const [reloadFetch, setReloadFetch] = useState(false);
useEffect(() => { useEffect(() => {
const userIdFromSession = user.user_id; const userIdFromSession = user.user_id;
setUserId(userIdFromSession); setUserId(userIdFromSession);
console.log(selectedEstablishmentId);
fetchChildren(userIdFromSession, selectedEstablishmentId).then((data) => { fetchChildren(userIdFromSession, selectedEstablishmentId).then((data) => {
setChildren(data); setChildren(data);
}); });
}, [selectedEstablishmentId]); setReloadFetch(false);
}, [selectedEstablishmentId, reloadFetch]);
function handleView(eleveId) { function handleView(eleveId) {
logger.debug(`View dossier for student id: ${eleveId}`); logger.debug(`View dossier for student id: ${eleveId}`);
@ -70,7 +71,8 @@ export default function ParentHomePage() {
sendSEPARegisterForm(uploadingStudentId, formData, csrfToken) sendSEPARegisterForm(uploadingStudentId, formData, csrfToken)
.then((response) => { .then((response) => {
logger.debug('RF mis à jour avec succès:', response); logger.debug('RF mis à jour avec succès:', response);
// Logique supplémentaire après la mise à jour (par exemple, redirection ou notification) setReloadFetch(true);
setUploadState('off');
}) })
.catch((error) => { .catch((error) => {
logger.error('Erreur lors de la mise à jour du RF:', error); logger.error('Erreur lors de la mise à jour du RF:', error);
@ -118,7 +120,7 @@ export default function ParentHomePage() {
</button> </button>
)} )}
{row.status === 3 && ( {(row.status === 3 || row.status === 8) && (
<button <button
className="text-purple-500 hover:text-purple-700" className="text-purple-500 hover:text-purple-700"
onClick={(e) => { onClick={(e) => {

View File

@ -23,7 +23,7 @@ import StudentInfoForm from '@/components/Inscription/StudentInfoForm';
import ResponsableInputFields from '@/components/Inscription/ResponsableInputFields'; import ResponsableInputFields from '@/components/Inscription/ResponsableInputFields';
import PaymentMethodSelector from '@/components/Inscription/PaymentMethodSelector'; import PaymentMethodSelector from '@/components/Inscription/PaymentMethodSelector';
import ProgressStep from '@/components/ProgressStep'; import ProgressStep from '@/components/ProgressStep';
import { CheckCircle, Loader2 } from 'lucide-react'; import { CheckCircle, Hourglass } from 'lucide-react';
/** /**
* Composant de formulaire d'inscription partagé * Composant de formulaire d'inscription partagé
@ -315,16 +315,21 @@ export default function InscriptionFormShared({
// Soumission du formulaire // Soumission du formulaire
const handleSubmit = (e) => { const handleSubmit = (e) => {
e.preventDefault(); e.preventDefault();
// Vérifier si le mode de paiement sélectionné est un prélèvement SEPA
const isSepaPayment =
formData.registration_payment === '1' || formData.tuition_payment === '1';
const data = { const data = {
student: { student: {
...formData, ...formData,
guardians, guardians,
}, },
establishment: selectedEstablishmentId, establishment: selectedEstablishmentId,
status: 3, status: isSepaPayment ? 8 : 3,
tuition_payment: formData.tuition_payment, tuition_payment: formData.tuition_payment,
registration_payment: formData.registration_payment, registration_payment: formData.registration_payment,
}; };
onSubmit(data); onSubmit(data);
}; };
@ -448,7 +453,7 @@ export default function InscriptionFormShared({
{template.file !== null ? ( {template.file !== null ? (
<CheckCircle className="w-5 h-5 text-green-600" /> <CheckCircle className="w-5 h-5 text-green-600" />
) : ( ) : (
<Loader2 className="w-5 h-5 text-gray-600" /> <Hourglass className="w-5 h-5 text-gray-600" />
)} )}
</span> </span>
{template.name || 'Document sans nom'} {template.name || 'Document sans nom'}

View File

@ -13,7 +13,6 @@ export default function PaymentMethodSelector({
const isValid = !Object.keys(formData).some( const isValid = !Object.keys(formData).some(
(field) => getLocalError(field) !== '' (field) => getLocalError(field) !== ''
); );
console.log(isValid);
setIsPageValid(isValid); setIsPageValid(isValid);
}, [formData, setIsPageValid]); }, [formData, setIsPageValid]);

View File

@ -1,18 +1,9 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { import { Trash2, ToggleLeft, ToggleRight, Info, XCircle } from 'lucide-react';
Trash2,
Eye,
EyeOff,
ToggleLeft,
ToggleRight,
Info,
XCircle,
} from 'lucide-react';
import Table from '@/components/Table'; import Table from '@/components/Table';
import Popup from '@/components/Popup'; import Popup from '@/components/Popup';
import StatusLabel from '@/components/StatusLabel'; import StatusLabel from '@/components/StatusLabel';
import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem'; import SpecialityItem from '@/components/Structure/Configuration/SpecialityItem';
import Tooltip from '@/components/Tooltip';
const roleTypeToLabel = (roleType) => { const roleTypeToLabel = (roleType) => {
switch (roleType) { switch (roleType) {

View File

@ -11,6 +11,7 @@ const StatusLabel = ({ status, onChange, showDropdown = true, parent }) => {
{ value: 2, label: 'Nouveau' }, { value: 2, label: 'Nouveau' },
{ value: 3, label: 'En validation' }, { value: 3, label: 'En validation' },
{ value: 7, label: 'SEPA reçu' }, { value: 7, label: 'SEPA reçu' },
{ value: 8, label: 'En validation' },
] ]
: [ : [
{ value: 1, label: 'A envoyer' }, { value: 1, label: 'A envoyer' },
@ -20,6 +21,7 @@ const StatusLabel = ({ status, onChange, showDropdown = true, parent }) => {
{ value: 5, label: 'Validé' }, { value: 5, label: 'Validé' },
{ value: 6, label: 'Archivé' }, { value: 6, label: 'Archivé' },
{ value: 7, label: 'En attente SEPA' }, { value: 7, label: 'En attente SEPA' },
{ value: 8, label: 'SEPA à envoyer' },
]; ];
const currentStatus = statusOptions.find((option) => option.value === status); const currentStatus = statusOptions.find((option) => option.value === status);
@ -29,7 +31,7 @@ const StatusLabel = ({ status, onChange, showDropdown = true, parent }) => {
if (parent) { if (parent) {
return ( return (
(status === 2 && 'bg-orange-50 text-orange-600') || (status === 2 && 'bg-orange-50 text-orange-600') ||
(status === 3 && 'bg-purple-50 text-purple-600') || ((status === 3 || status === 8) && 'bg-purple-50 text-purple-600') ||
(status === 7 && 'bg-yellow-50 text-yellow-600') (status === 7 && 'bg-yellow-50 text-yellow-600')
); );
} }
@ -40,7 +42,8 @@ const StatusLabel = ({ status, onChange, showDropdown = true, parent }) => {
(status === 4 && 'bg-red-50 text-red-600') || (status === 4 && 'bg-red-50 text-red-600') ||
(status === 5 && 'bg-green-50 text-green-600') || (status === 5 && 'bg-green-50 text-green-600') ||
(status === 6 && 'bg-red-50 text-red-600') || (status === 6 && 'bg-red-50 text-red-600') ||
(status === 7 && 'bg-yellow-50 text-yellow-600') (status === 7 && 'bg-yellow-50 text-yellow-600') ||
(status === 8 && 'bg-cyan-50 text-cyan-600')
); );
}; };

View File

@ -163,7 +163,7 @@ export default function ParentFilesSection({
return ( return (
<MultiSelect <MultiSelect
name="groups" name="groups"
label="Sélection de groupes de fichiers" label="Sélection du(des) dossier(s) d'inscription"
options={groups} options={groups}
selectedOptions={selectedGroups} selectedOptions={selectedGroups}
onChange={handleGroupChange} onChange={handleGroupChange}