mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-04-03 16:51:26 +00:00
feat: Gestion du refus définitif d'un dossier [N3WTS-2]
This commit is contained in:
@ -293,4 +293,38 @@ def sendValidationDossier(recipients, establishment_id, student_name, class_name
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
errorMessage = str(e)
|
errorMessage = str(e)
|
||||||
logger.error(f"Erreur lors de l'envoi de l'email de validation: {errorMessage}")
|
logger.error(f"Erreur lors de l'envoi de l'email de validation: {errorMessage}")
|
||||||
|
return errorMessage
|
||||||
|
|
||||||
|
|
||||||
|
def sendRefusDefinitif(recipients, establishment_id, student_name, notes):
|
||||||
|
"""
|
||||||
|
Envoie un email au parent pour l'informer que le dossier d'inscription
|
||||||
|
a été définitivement refusé.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
recipients: Email du destinataire (parent)
|
||||||
|
establishment_id: ID de l'établissement
|
||||||
|
student_name: Nom complet de l'élève
|
||||||
|
notes: Motifs du refus
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Message d'erreur si échec, chaîne vide sinon
|
||||||
|
"""
|
||||||
|
errorMessage = ''
|
||||||
|
try:
|
||||||
|
EMAIL_REFUS_DEFINITIF_SUBJECT = '[N3WT-SCHOOL] Dossier d\'inscription refusé'
|
||||||
|
context = {
|
||||||
|
'BASE_URL': settings.BASE_URL,
|
||||||
|
'URL_DJANGO': settings.URL_DJANGO,
|
||||||
|
'student_name': student_name,
|
||||||
|
'notes': notes
|
||||||
|
}
|
||||||
|
connection = getConnection(establishment_id)
|
||||||
|
subject = EMAIL_REFUS_DEFINITIF_SUBJECT
|
||||||
|
html_message = render_to_string('emails/refus_definitif.html', context)
|
||||||
|
sendMail(subject=subject, message=html_message, recipients=recipients, connection=connection)
|
||||||
|
logger.info(f"Email de refus définitif envoyé à {recipients} pour l'élève {student_name}")
|
||||||
|
except Exception as e:
|
||||||
|
errorMessage = str(e)
|
||||||
|
logger.error(f"Erreur lors de l'envoi de l'email de refus définitif: {errorMessage}")
|
||||||
return errorMessage
|
return errorMessage
|
||||||
66
Back-End/Subscriptions/templates/emails/refus_definitif.html
Normal file
66
Back-End/Subscriptions/templates/emails/refus_definitif.html
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Dossier d'inscription refusé</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.header {
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.notes {
|
||||||
|
background-color: #f8d7da;
|
||||||
|
border: 1px solid #f5c6cb;
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<div class="header">
|
||||||
|
<img src="{{URL_DJANGO}}static/img/logo_min.svg" alt="Logo N3wt School" class="logo" />
|
||||||
|
<h1>Dossier d'inscription refusé</h1>
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<p>Bonjour,</p>
|
||||||
|
<p>Nous avons le regret de vous informer que le dossier d'inscription de <strong>{{ student_name }}</strong> n'a pas été retenu.</p>
|
||||||
|
|
||||||
|
<div class="notes">
|
||||||
|
<strong>Motif(s) :</strong><br>
|
||||||
|
{{ notes }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>Nous vous remercions de l'intérêt que vous avez porté à notre établissement et restons à votre disposition pour tout renseignement complémentaire.</p>
|
||||||
|
|
||||||
|
<p>Cordialement,</p>
|
||||||
|
<p>L'équipe N3wt School</p>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
<p>Ce message est généré automatiquement, merci de ne pas y répondre.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@ -509,6 +509,36 @@ class RegisterFormWithIdView(APIView):
|
|||||||
|
|
||||||
updateStateMachine(registerForm, 'EVENT_VALIDATE')
|
updateStateMachine(registerForm, 'EVENT_VALIDATE')
|
||||||
|
|
||||||
|
elif _status == RegistrationForm.RegistrationFormStatus.RF_ARCHIVED:
|
||||||
|
# Vérifier si on vient de l'état "À valider" (RF_UNDER_REVIEW) pour un refus définitif
|
||||||
|
if registerForm.status == RegistrationForm.RegistrationFormStatus.RF_UNDER_REVIEW:
|
||||||
|
# Envoi de l'email de refus définitif aux responsables légaux (en arrière-plan)
|
||||||
|
def send_refus_definitif_emails():
|
||||||
|
try:
|
||||||
|
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
|
||||||
|
if hasattr(guardian, "profile_role") and guardian.profile_role and hasattr(guardian.profile_role, "profile") and guardian.profile_role.profile:
|
||||||
|
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
|
# Retourner les données mises à jour
|
||||||
return JsonResponse(studentForm_serializer.data, safe=False)
|
return JsonResponse(studentForm_serializer.data, safe=False)
|
||||||
|
|
||||||
|
|||||||
@ -18,6 +18,7 @@ import {
|
|||||||
Plus,
|
Plus,
|
||||||
Upload,
|
Upload,
|
||||||
Eye,
|
Eye,
|
||||||
|
XCircle,
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import Modal from '@/components/Modal';
|
import Modal from '@/components/Modal';
|
||||||
import { useEstablishment } from '@/context/EstablishmentContext';
|
import { useEstablishment } from '@/context/EstablishmentContext';
|
||||||
@ -114,11 +115,10 @@ export default function Page({ params: { locale } }) {
|
|||||||
showNotification('Merci de préciser la raison du refus.', 'error', 'Erreur');
|
showNotification('Merci de préciser la raison du refus.', 'error', 'Erreur');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
editRegisterForm(
|
const formData = new FormData();
|
||||||
rowToRefuse.student.id,
|
formData.append('data', JSON.stringify({ status: RegistrationFormStatus.STATUS_ARCHIVED, notes: refuseReason }));
|
||||||
{ status: RegistrationFormStatus.STATUS_ARCHIVED, notes: refuseReason },
|
|
||||||
csrfToken
|
editRegisterForm(rowToRefuse.student.id, formData, csrfToken)
|
||||||
)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
showNotification('Le dossier a été refusé et archivé.', 'success', 'Succès');
|
showNotification('Le dossier a été refusé et archivé.', 'success', 'Succès');
|
||||||
setReloadFetch(true);
|
setReloadFetch(true);
|
||||||
@ -527,7 +527,7 @@ export default function Page({ params: { locale } }) {
|
|||||||
{
|
{
|
||||||
icon: (
|
icon: (
|
||||||
<span title="Refuser le dossier">
|
<span title="Refuser le dossier">
|
||||||
<Archive className="w-5 h-5 text-red-500 hover:text-red-700" />
|
<XCircle className="w-5 h-5 text-red-500 hover:text-red-700" />
|
||||||
</span>
|
</span>
|
||||||
),
|
),
|
||||||
onClick: () => openRefusePopup(row),
|
onClick: () => openRefusePopup(row),
|
||||||
|
|||||||
Reference in New Issue
Block a user