mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-28 23:43:22 +00:00
feat: Précablage du formulaire dynamique [N3WTS-17]
This commit is contained in:
@ -1,18 +0,0 @@
|
||||
{
|
||||
"activationMailRelance": "Oui",
|
||||
"delaiRelance": "30",
|
||||
"ambiances": [
|
||||
"2-3 ans",
|
||||
"3-6 ans",
|
||||
"6-12 ans"
|
||||
],
|
||||
"genres": [
|
||||
"Fille",
|
||||
"Garçon"
|
||||
],
|
||||
"modesPaiement": [
|
||||
"Chèque",
|
||||
"Virement",
|
||||
"Prélèvement SEPA"
|
||||
]
|
||||
}
|
||||
0
Back-End/Subscriptions/management/__init__.py
Normal file
0
Back-End/Subscriptions/management/__init__.py
Normal file
43
Back-End/Subscriptions/management/commands/test_email.py
Normal file
43
Back-End/Subscriptions/management/commands/test_email.py
Normal file
@ -0,0 +1,43 @@
|
||||
"""
|
||||
Management command pour tester la configuration email Django
|
||||
"""
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
from N3wtSchool.mailManager import getConnection, sendMail
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Test de la configuration email'
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--establishment-id', type=int, help='ID de l\'établissement pour test')
|
||||
parser.add_argument('--email', type=str, default='test@example.com', help='Email de destination')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.stdout.write("=== Test de configuration email ===")
|
||||
|
||||
# Affichage de la configuration
|
||||
self.stdout.write(f"EMAIL_HOST: {settings.EMAIL_HOST}")
|
||||
self.stdout.write(f"EMAIL_PORT: {settings.EMAIL_PORT}")
|
||||
self.stdout.write(f"EMAIL_HOST_USER: {settings.EMAIL_HOST_USER}")
|
||||
self.stdout.write(f"EMAIL_HOST_PASSWORD: {settings.EMAIL_HOST_PASSWORD}")
|
||||
self.stdout.write(f"EMAIL_USE_TLS: {settings.EMAIL_USE_TLS}")
|
||||
self.stdout.write(f"EMAIL_USE_SSL: {settings.EMAIL_USE_SSL}")
|
||||
self.stdout.write(f"EMAIL_BACKEND: {settings.EMAIL_BACKEND}")
|
||||
|
||||
# Test 1: Configuration par défaut Django
|
||||
self.stdout.write("\n--- Test : Configuration EMAIL par défaut ---")
|
||||
try:
|
||||
result = send_mail(
|
||||
'Test Django Email',
|
||||
'Ceci est un test de la configuration email par défaut.',
|
||||
settings.EMAIL_HOST_USER,
|
||||
[options['email']],
|
||||
fail_silently=False,
|
||||
)
|
||||
self.stdout.write(self.style.SUCCESS(f"✅ Email envoyé avec succès (résultat: {result})"))
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.ERROR(f"❌ Erreur: {e}"))
|
||||
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.3 on 2025-05-28 11:14
|
||||
# Generated by Django 5.1.3 on 2025-11-30 11:02
|
||||
|
||||
import Subscriptions.models
|
||||
import django.db.models.deletion
|
||||
@ -46,10 +46,11 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='RegistrationSchoolFileTemplate',
|
||||
fields=[
|
||||
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('slug', models.CharField(default='', max_length=255)),
|
||||
('name', models.CharField(default='', max_length=255)),
|
||||
('file', models.FileField(blank=True, null=True, upload_to=Subscriptions.models.registration_school_file_upload_to)),
|
||||
('formTemplateData', models.JSONField(blank=True, default=list, null=True)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
@ -153,7 +154,7 @@ class Migration(migrations.Migration):
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(default='', max_length=255)),
|
||||
('description', models.CharField(blank=True, null=True)),
|
||||
('description', models.CharField(blank=True, max_length=500, null=True)),
|
||||
('is_required', models.BooleanField(default=False)),
|
||||
('groups', models.ManyToManyField(blank=True, related_name='parent_file_masters', to='Subscriptions.registrationfilegroup')),
|
||||
],
|
||||
@ -161,9 +162,10 @@ class Migration(migrations.Migration):
|
||||
migrations.CreateModel(
|
||||
name='RegistrationSchoolFileMaster',
|
||||
fields=[
|
||||
('id', models.IntegerField(primary_key=True, serialize=False)),
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(default='', max_length=255)),
|
||||
('is_required', models.BooleanField(default=False)),
|
||||
('formMasterData', models.JSONField(blank=True, default=list, null=True)),
|
||||
('groups', models.ManyToManyField(blank=True, related_name='school_file_masters', to='Subscriptions.registrationfilegroup')),
|
||||
],
|
||||
),
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
# Generated by Django 5.1.3 on 2025-05-30 07:39
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('Subscriptions', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='registrationparentfilemaster',
|
||||
name='description',
|
||||
field=models.CharField(blank=True, max_length=500, null=True),
|
||||
),
|
||||
]
|
||||
@ -1,15 +1,15 @@
|
||||
from rest_framework import serializers
|
||||
from .models import (
|
||||
RegistrationFileGroup,
|
||||
RegistrationForm,
|
||||
Student,
|
||||
Guardian,
|
||||
Sibling,
|
||||
RegistrationFileGroup,
|
||||
RegistrationForm,
|
||||
Student,
|
||||
Guardian,
|
||||
Sibling,
|
||||
Language,
|
||||
RegistrationSchoolFileMaster,
|
||||
RegistrationSchoolFileTemplate,
|
||||
RegistrationParentFileMaster,
|
||||
RegistrationParentFileTemplate,
|
||||
RegistrationSchoolFileMaster,
|
||||
RegistrationSchoolFileTemplate,
|
||||
RegistrationParentFileMaster,
|
||||
RegistrationParentFileTemplate,
|
||||
AbsenceManagement,
|
||||
BilanCompetence
|
||||
)
|
||||
@ -95,7 +95,7 @@ class RegistrationFormSimpleSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = RegistrationForm
|
||||
fields = ['student_id', 'last_name', 'first_name', 'guardians']
|
||||
|
||||
|
||||
def get_last_name(self, obj):
|
||||
return obj.student.last_name
|
||||
|
||||
@ -164,12 +164,20 @@ class StudentSerializer(serializers.ModelSerializer):
|
||||
|
||||
if guardian_id:
|
||||
# Si un ID est fourni, récupérer ou mettre à jour le Guardian existant
|
||||
guardian_instance, created = Guardian.objects.update_or_create(
|
||||
id=guardian_id,
|
||||
defaults=guardian_data
|
||||
)
|
||||
guardians_ids.append(guardian_instance.id)
|
||||
continue
|
||||
try:
|
||||
guardian_instance = Guardian.objects.get(id=guardian_id)
|
||||
# Mettre à jour explicitement tous les champs y compris birth_date, profession, address
|
||||
for field, value in guardian_data.items():
|
||||
if field != 'id': # Ne pas mettre à jour l'ID
|
||||
setattr(guardian_instance, field, value)
|
||||
guardian_instance.save()
|
||||
guardians_ids.append(guardian_instance.id)
|
||||
continue
|
||||
except Guardian.DoesNotExist:
|
||||
# Si le guardian n'existe pas, créer un nouveau
|
||||
guardian_instance = Guardian.objects.create(**guardian_data)
|
||||
guardians_ids.append(guardian_instance.id)
|
||||
continue
|
||||
|
||||
if profile_role_data:
|
||||
# Vérifiez si 'profile_data' est fourni pour créer un nouveau profil
|
||||
|
||||
@ -5,6 +5,8 @@ from Subscriptions.automate import Automate_RF_Register, updateStateMachine
|
||||
from .models import RegistrationForm
|
||||
from GestionMessagerie.models import Messagerie
|
||||
from N3wtSchool import settings, bdd
|
||||
from N3wtSchool.mailManager import sendMail, getConnection
|
||||
from django.template.loader import render_to_string
|
||||
import requests
|
||||
import logging
|
||||
logger = logging.getLogger(__name__)
|
||||
@ -26,17 +28,82 @@ def send_notification(dossier):
|
||||
# Changer l'état de l'automate
|
||||
updateStateMachine(dossier, 'EVENT_FOLLOW_UP')
|
||||
|
||||
url = settings.URL_DJANGO + 'GestionMessagerie/message'
|
||||
# Envoyer un email de relance aux responsables
|
||||
try:
|
||||
# Récupérer l'établissement du dossier
|
||||
establishment_id = dossier.establishment.id
|
||||
|
||||
destinataires = dossier.eleve.profiles.all()
|
||||
for destinataire in destinataires:
|
||||
message = {
|
||||
"objet": "[RELANCE]",
|
||||
"destinataire" : destinataire.id,
|
||||
"corpus": "RELANCE pour le dossier d'inscription"
|
||||
# Obtenir la connexion SMTP pour cet établissement
|
||||
connection = getConnection(establishment_id)
|
||||
|
||||
# Préparer le contenu de l'email
|
||||
subject = f"[RELANCE] Dossier d'inscription en attente - {dossier.eleve.first_name} {dossier.eleve.last_name}"
|
||||
|
||||
context = {
|
||||
'student_name': f"{dossier.eleve.first_name} {dossier.eleve.last_name}",
|
||||
'deadline_date': (timezone.now() - timezone.timedelta(days=settings.EXPIRATION_DI_NB_DAYS)).strftime('%d/%m/%Y'),
|
||||
'establishment_name': dossier.establishment.name,
|
||||
'base_url': settings.BASE_URL
|
||||
}
|
||||
|
||||
response = requests.post(url, json=message)
|
||||
# Utiliser un template HTML pour l'email (si disponible)
|
||||
try:
|
||||
html_message = render_to_string('emails/relance_signature.html', context)
|
||||
except:
|
||||
# Si pas de template, message simple
|
||||
html_message = f"""
|
||||
<html>
|
||||
<body>
|
||||
<h2>Relance - Dossier d'inscription en attente</h2>
|
||||
<p>Bonjour,</p>
|
||||
<p>Le dossier d'inscription de <strong>{context['student_name']}</strong> est en attente de signature depuis plus de {settings.EXPIRATION_DI_NB_DAYS} jours.</p>
|
||||
<p>Merci de vous connecter à votre espace pour finaliser l'inscription.</p>
|
||||
<p>Cordialement,<br>L'équipe {context['establishment_name']}</p>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
# Récupérer les emails des responsables
|
||||
destinataires = []
|
||||
profiles = dossier.eleve.profiles.all()
|
||||
for profile in profiles:
|
||||
if profile.email:
|
||||
destinataires.append(profile.email)
|
||||
|
||||
if destinataires:
|
||||
# Envoyer l'email
|
||||
result = sendMail(
|
||||
subject=subject,
|
||||
message=html_message,
|
||||
recipients=destinataires,
|
||||
connection=connection
|
||||
)
|
||||
logger.info(f"Email de relance envoyé pour le dossier {dossier.id} à {destinataires}")
|
||||
else:
|
||||
logger.warning(f"Aucun email trouvé pour les responsables du dossier {dossier.id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lors de l'envoi de l'email de relance pour le dossier {dossier.id}: {str(e)}")
|
||||
|
||||
# En cas d'erreur email, utiliser la messagerie interne comme fallback
|
||||
try:
|
||||
url = settings.URL_DJANGO + 'GestionMessagerie/send-message/'
|
||||
|
||||
# Créer ou récupérer une conversation avec chaque responsable
|
||||
destinataires = dossier.eleve.profiles.all()
|
||||
for destinataire in destinataires:
|
||||
message_data = {
|
||||
"conversation_id": None, # Sera géré par l'API
|
||||
"sender_id": 1, # ID du système ou admin
|
||||
"content": f"RELANCE pour le dossier d'inscription de {dossier.eleve.first_name} {dossier.eleve.last_name}"
|
||||
}
|
||||
|
||||
response = requests.post(url, json=message_data)
|
||||
if response.status_code != 201:
|
||||
logger.error(f"Erreur lors de l'envoi du message interne: {response.text}")
|
||||
|
||||
except Exception as inner_e:
|
||||
logger.error(f"Erreur lors de l'envoi du message interne de fallback: {str(inner_e)}")
|
||||
|
||||
# subject = f"Dossier d'inscription non signé - {dossier.objet}"
|
||||
# message = f"Le dossier d'inscription avec l'objet '{dossier.objet}' n'a pas été signé depuis {dossier.created_at}."
|
||||
|
||||
121
Back-End/Subscriptions/templates/emails/relance_signature.html
Normal file
121
Back-End/Subscriptions/templates/emails/relance_signature.html
Normal file
@ -0,0 +1,121 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Relance - Dossier d'inscription</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 0 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header {
|
||||
text-align: center;
|
||||
border-bottom: 3px solid #007bff;
|
||||
padding-bottom: 20px;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.header h1 {
|
||||
color: #007bff;
|
||||
margin: 0;
|
||||
}
|
||||
.alert {
|
||||
background-color: #fff3cd;
|
||||
border: 1px solid #ffeaa7;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.alert-icon {
|
||||
font-size: 20px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.content {
|
||||
margin: 20px 0;
|
||||
}
|
||||
.student-info {
|
||||
background-color: #f8f9fa;
|
||||
border-left: 4px solid #007bff;
|
||||
padding: 15px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.cta-button {
|
||||
display: inline-block;
|
||||
background-color: #007bff;
|
||||
color: white;
|
||||
padding: 12px 25px;
|
||||
text-decoration: none;
|
||||
border-radius: 5px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
.footer {
|
||||
margin-top: 30px;
|
||||
padding-top: 20px;
|
||||
border-top: 1px solid #dee2e6;
|
||||
font-size: 14px;
|
||||
color: #6c757d;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>{{ establishment_name }}</h1>
|
||||
<p>Relance - Dossier d'inscription</p>
|
||||
</div>
|
||||
|
||||
<div class="alert">
|
||||
<span class="alert-icon">⚠️</span>
|
||||
<strong>Attention :</strong> Votre dossier d'inscription nécessite votre attention
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<p>Bonjour,</p>
|
||||
|
||||
<div class="student-info">
|
||||
<h3>Dossier d'inscription de : <strong>{{ student_name }}</strong></h3>
|
||||
<p>En attente depuis le : <strong>{{ deadline_date }}</strong></p>
|
||||
</div>
|
||||
|
||||
<p>Nous vous informons que le dossier d'inscription mentionné ci-dessus est en attente de finalisation depuis plus de {{ deadline_date }}.</p>
|
||||
|
||||
<p><strong>Action requise :</strong></p>
|
||||
<ul>
|
||||
<li>Connectez-vous à votre espace personnel</li>
|
||||
<li>Vérifiez les documents manquants</li>
|
||||
<li>Complétez et signez les formulaires en attente</li>
|
||||
</ul>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<a href="{{ base_url }}" class="cta-button">Accéder à mon espace</a>
|
||||
</div>
|
||||
|
||||
<p>Si vous rencontrez des difficultés ou avez des questions concernant ce dossier, n'hésitez pas à nous contacter.</p>
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<p>Cordialement,<br>
|
||||
L'équipe {{ establishment_name }}</p>
|
||||
|
||||
<hr style="margin: 20px 0;">
|
||||
|
||||
<p style="font-size: 12px;">
|
||||
Cet email a été envoyé automatiquement. Si vous pensez avoir reçu ce message par erreur,
|
||||
veuillez contacter l'établissement directement.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@ -35,6 +35,18 @@ def build_payload_from_request(request):
|
||||
- supporte application/json ou form-data simple
|
||||
Retour: (payload_dict, None) ou (None, Response erreur)
|
||||
"""
|
||||
# Si c'est du JSON pur (Content-Type: application/json)
|
||||
if hasattr(request, 'content_type') and 'application/json' in request.content_type:
|
||||
try:
|
||||
# request.data contient déjà le JSON parsé par Django REST
|
||||
payload = dict(request.data) if hasattr(request.data, 'items') else request.data
|
||||
logger.info(f"JSON payload extracted: {payload}")
|
||||
return payload, None
|
||||
except Exception as e:
|
||||
logger.error(f'Error processing JSON: {e}')
|
||||
return None, Response({'error': "Invalid JSON", 'detail': str(e)}, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
# Cas multipart/form-data avec champ 'data'
|
||||
data_field = request.data.get('data') if hasattr(request.data, 'get') else None
|
||||
if data_field:
|
||||
try:
|
||||
|
||||
@ -17,10 +17,10 @@ import Subscriptions.util as util
|
||||
from Subscriptions.serializers import RegistrationFormSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileTemplateSerializer
|
||||
from Subscriptions.pagination import CustomSubscriptionPagination
|
||||
from Subscriptions.models import (
|
||||
Guardian,
|
||||
RegistrationForm,
|
||||
RegistrationSchoolFileTemplate,
|
||||
RegistrationFileGroup,
|
||||
Guardian,
|
||||
RegistrationForm,
|
||||
RegistrationSchoolFileTemplate,
|
||||
RegistrationFileGroup,
|
||||
RegistrationParentFileTemplate,
|
||||
StudentCompetency
|
||||
)
|
||||
@ -431,6 +431,262 @@ class RegisterFormWithIdView(APIView):
|
||||
# Retourner les données mises à jour
|
||||
return JsonResponse(studentForm_serializer.data, safe=False)
|
||||
|
||||
@swagger_auto_schema(
|
||||
request_body=openapi.Schema(
|
||||
type=openapi.TYPE_OBJECT,
|
||||
properties={
|
||||
'student_data': openapi.Schema(type=openapi.TYPE_STRING, description='JSON string des données étudiant'),
|
||||
'guardians_data': openapi.Schema(type=openapi.TYPE_STRING, description='JSON string des données responsables'),
|
||||
'siblings_data': openapi.Schema(type=openapi.TYPE_STRING, description='JSON string des données fratrie'),
|
||||
'payment_data': openapi.Schema(type=openapi.TYPE_STRING, description='JSON string des données de paiement'),
|
||||
'current_page': openapi.Schema(type=openapi.TYPE_INTEGER, description='Page actuelle du formulaire'),
|
||||
'auto_save': openapi.Schema(type=openapi.TYPE_BOOLEAN, description='Indicateur auto-save'),
|
||||
}
|
||||
),
|
||||
responses={200: RegistrationFormSerializer()},
|
||||
operation_description="Auto-sauvegarde partielle d'un dossier d'inscription.",
|
||||
operation_summary="Auto-sauvegarder un dossier d'inscription"
|
||||
)
|
||||
@method_decorator(csrf_protect, name='dispatch')
|
||||
@method_decorator(ensure_csrf_cookie, name='dispatch')
|
||||
def patch(self, request, id):
|
||||
"""
|
||||
Auto-sauvegarde partielle d'un dossier d'inscription.
|
||||
Cette méthode est optimisée pour les sauvegardes automatiques périodiques.
|
||||
"""
|
||||
try:
|
||||
# Récupérer le dossier d'inscription
|
||||
registerForm = bdd.getObject(_objectName=RegistrationForm, _columnName='student__id', _value=id)
|
||||
if not registerForm:
|
||||
return JsonResponse({"error": "Dossier d'inscription introuvable"}, status=status.HTTP_404_NOT_FOUND)
|
||||
|
||||
# Préparer les données à mettre à jour
|
||||
update_data = {}
|
||||
|
||||
# Traiter les données étudiant si présentes
|
||||
if 'student_data' in request.data:
|
||||
try:
|
||||
student_data = json.loads(request.data['student_data'])
|
||||
|
||||
# Extraire les données de paiement des données étudiant
|
||||
payment_fields = ['registration_payment', 'tuition_payment', 'registration_payment_plan', 'tuition_payment_plan']
|
||||
payment_data = {}
|
||||
|
||||
for field in payment_fields:
|
||||
if field in student_data:
|
||||
payment_data[field] = student_data.pop(field)
|
||||
|
||||
# Si nous avons des données de paiement, les traiter
|
||||
if payment_data:
|
||||
logger.debug(f"Auto-save: extracted payment_data from student_data = {payment_data}")
|
||||
|
||||
# Traiter les données de paiement
|
||||
payment_updates = {}
|
||||
|
||||
# Gestion du mode de paiement d'inscription
|
||||
if 'registration_payment' in payment_data and payment_data['registration_payment']:
|
||||
try:
|
||||
from School.models import PaymentMode
|
||||
payment_mode = PaymentMode.objects.get(id=payment_data['registration_payment'])
|
||||
registerForm.registration_payment = payment_mode
|
||||
payment_updates['registration_payment'] = payment_mode.id
|
||||
except PaymentMode.DoesNotExist:
|
||||
logger.warning(f"Auto-save: PaymentMode with id {payment_data['registration_payment']} not found")
|
||||
|
||||
# Gestion du mode de paiement de scolarité
|
||||
if 'tuition_payment' in payment_data and payment_data['tuition_payment']:
|
||||
try:
|
||||
from School.models import PaymentMode
|
||||
payment_mode = PaymentMode.objects.get(id=payment_data['tuition_payment'])
|
||||
registerForm.tuition_payment = payment_mode
|
||||
payment_updates['tuition_payment'] = payment_mode.id
|
||||
except PaymentMode.DoesNotExist:
|
||||
logger.warning(f"Auto-save: PaymentMode with id {payment_data['tuition_payment']} not found")
|
||||
|
||||
# Gestion du plan de paiement d'inscription
|
||||
if 'registration_payment_plan' in payment_data and payment_data['registration_payment_plan']:
|
||||
try:
|
||||
from School.models import PaymentPlan
|
||||
payment_plan = PaymentPlan.objects.get(id=payment_data['registration_payment_plan'])
|
||||
registerForm.registration_payment_plan = payment_plan
|
||||
payment_updates['registration_payment_plan'] = payment_plan.id
|
||||
except PaymentPlan.DoesNotExist:
|
||||
logger.warning(f"Auto-save: PaymentPlan with id {payment_data['registration_payment_plan']} not found")
|
||||
|
||||
# Gestion du plan de paiement de scolarité
|
||||
if 'tuition_payment_plan' in payment_data and payment_data['tuition_payment_plan']:
|
||||
try:
|
||||
from School.models import PaymentPlan
|
||||
payment_plan = PaymentPlan.objects.get(id=payment_data['tuition_payment_plan'])
|
||||
registerForm.tuition_payment_plan = payment_plan
|
||||
payment_updates['tuition_payment_plan'] = payment_plan.id
|
||||
except PaymentPlan.DoesNotExist:
|
||||
logger.warning(f"Auto-save: PaymentPlan with id {payment_data['tuition_payment_plan']} not found")
|
||||
|
||||
# Sauvegarder les modifications de paiement
|
||||
if payment_updates:
|
||||
registerForm.save()
|
||||
logger.debug(f"Auto-save: Payment data updated - {payment_updates}")
|
||||
|
||||
update_data['student'] = student_data
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("Auto-save: Invalid JSON in student_data")
|
||||
|
||||
# Traiter les données des responsables si présentes
|
||||
if 'guardians_data' in request.data:
|
||||
try:
|
||||
guardians_data = json.loads(request.data['guardians_data'])
|
||||
logger.debug(f"Auto-save: guardians_data = {guardians_data}")
|
||||
|
||||
# Enregistrer directement chaque guardian avec le modèle
|
||||
for i, guardian_data in enumerate(guardians_data):
|
||||
guardian_id = guardian_data.get('id')
|
||||
if guardian_id:
|
||||
try:
|
||||
# Récupérer le guardian existant et mettre à jour ses champs
|
||||
guardian = Guardian.objects.get(id=guardian_id)
|
||||
|
||||
# Mettre à jour les champs si ils sont présents
|
||||
if 'birth_date' in guardian_data and guardian_data['birth_date']:
|
||||
guardian.birth_date = guardian_data['birth_date']
|
||||
if 'profession' in guardian_data:
|
||||
guardian.profession = guardian_data['profession']
|
||||
if 'address' in guardian_data:
|
||||
guardian.address = guardian_data['address']
|
||||
if 'phone' in guardian_data:
|
||||
guardian.phone = guardian_data['phone']
|
||||
if 'first_name' in guardian_data:
|
||||
guardian.first_name = guardian_data['first_name']
|
||||
if 'last_name' in guardian_data:
|
||||
guardian.last_name = guardian_data['last_name']
|
||||
|
||||
guardian.save()
|
||||
logger.debug(f"Guardian {i}: Updated birth_date={guardian.birth_date}, profession={guardian.profession}, address={guardian.address}")
|
||||
|
||||
except Guardian.DoesNotExist:
|
||||
logger.warning(f"Auto-save: Guardian with id {guardian_id} not found")
|
||||
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("Auto-save: Invalid JSON in guardians_data")
|
||||
|
||||
# Traiter les données de la fratrie si présentes
|
||||
if 'siblings_data' in request.data:
|
||||
try:
|
||||
siblings_data = json.loads(request.data['siblings_data'])
|
||||
logger.debug(f"Auto-save: siblings_data = {siblings_data}")
|
||||
|
||||
# Enregistrer directement chaque sibling avec le modèle
|
||||
for i, sibling_data in enumerate(siblings_data):
|
||||
sibling_id = sibling_data.get('id')
|
||||
if sibling_id:
|
||||
try:
|
||||
# Récupérer le sibling existant et mettre à jour ses champs
|
||||
from Subscriptions.models import Sibling
|
||||
sibling = Sibling.objects.get(id=sibling_id)
|
||||
|
||||
# Mettre à jour les champs si ils sont présents
|
||||
if 'first_name' in sibling_data:
|
||||
sibling.first_name = sibling_data['first_name']
|
||||
if 'last_name' in sibling_data:
|
||||
sibling.last_name = sibling_data['last_name']
|
||||
if 'birth_date' in sibling_data and sibling_data['birth_date']:
|
||||
sibling.birth_date = sibling_data['birth_date']
|
||||
|
||||
sibling.save()
|
||||
logger.debug(f"Sibling {i}: Updated first_name={sibling.first_name}, last_name={sibling.last_name}, birth_date={sibling.birth_date}")
|
||||
|
||||
except Sibling.DoesNotExist:
|
||||
logger.warning(f"Auto-save: Sibling with id {sibling_id} not found")
|
||||
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("Auto-save: Invalid JSON in siblings_data")
|
||||
|
||||
# Traiter les données de paiement si présentes
|
||||
if 'payment_data' in request.data:
|
||||
try:
|
||||
payment_data = json.loads(request.data['payment_data'])
|
||||
logger.debug(f"Auto-save: payment_data = {payment_data}")
|
||||
|
||||
# Mettre à jour directement les champs de paiement du formulaire
|
||||
payment_updates = {}
|
||||
|
||||
# Gestion du mode de paiement d'inscription
|
||||
if 'registration_payment' in payment_data and payment_data['registration_payment']:
|
||||
try:
|
||||
from School.models import PaymentMode
|
||||
payment_mode = PaymentMode.objects.get(id=payment_data['registration_payment'])
|
||||
registerForm.registration_payment = payment_mode
|
||||
payment_updates['registration_payment'] = payment_mode.id
|
||||
except PaymentMode.DoesNotExist:
|
||||
logger.warning(f"Auto-save: PaymentMode with id {payment_data['registration_payment']} not found")
|
||||
|
||||
# Gestion du mode de paiement de scolarité
|
||||
if 'tuition_payment' in payment_data and payment_data['tuition_payment']:
|
||||
try:
|
||||
from School.models import PaymentMode
|
||||
payment_mode = PaymentMode.objects.get(id=payment_data['tuition_payment'])
|
||||
registerForm.tuition_payment = payment_mode
|
||||
payment_updates['tuition_payment'] = payment_mode.id
|
||||
except PaymentMode.DoesNotExist:
|
||||
logger.warning(f"Auto-save: PaymentMode with id {payment_data['tuition_payment']} not found")
|
||||
|
||||
# Gestion du plan de paiement d'inscription
|
||||
if 'registration_payment_plan' in payment_data and payment_data['registration_payment_plan']:
|
||||
try:
|
||||
from School.models import PaymentPlan
|
||||
payment_plan = PaymentPlan.objects.get(id=payment_data['registration_payment_plan'])
|
||||
registerForm.registration_payment_plan = payment_plan
|
||||
payment_updates['registration_payment_plan'] = payment_plan.id
|
||||
except PaymentPlan.DoesNotExist:
|
||||
logger.warning(f"Auto-save: PaymentPlan with id {payment_data['registration_payment_plan']} not found")
|
||||
|
||||
# Gestion du plan de paiement de scolarité
|
||||
if 'tuition_payment_plan' in payment_data and payment_data['tuition_payment_plan']:
|
||||
try:
|
||||
from School.models import PaymentPlan
|
||||
payment_plan = PaymentPlan.objects.get(id=payment_data['tuition_payment_plan'])
|
||||
registerForm.tuition_payment_plan = payment_plan
|
||||
payment_updates['tuition_payment_plan'] = payment_plan.id
|
||||
except PaymentPlan.DoesNotExist:
|
||||
logger.warning(f"Auto-save: PaymentPlan with id {payment_data['tuition_payment_plan']} not found")
|
||||
|
||||
# Sauvegarder les modifications de paiement
|
||||
if payment_updates:
|
||||
registerForm.save()
|
||||
logger.debug(f"Auto-save: Payment data updated - {payment_updates}")
|
||||
|
||||
except json.JSONDecodeError:
|
||||
logger.warning("Auto-save: Invalid JSON in payment_data")
|
||||
|
||||
# Mettre à jour la page actuelle si présente
|
||||
if 'current_page' in request.data:
|
||||
try:
|
||||
current_page = int(request.data['current_page'])
|
||||
# Vous pouvez sauvegarder cette info dans un champ du modèle si nécessaire
|
||||
logger.debug(f"Auto-save: current_page = {current_page}")
|
||||
except (ValueError, TypeError):
|
||||
logger.warning("Auto-save: Invalid current_page value")
|
||||
|
||||
# Effectuer la mise à jour partielle seulement si nous avons des données
|
||||
if update_data:
|
||||
serializer = RegistrationFormSerializer(registerForm, data=update_data, partial=True)
|
||||
if serializer.is_valid():
|
||||
serializer.save()
|
||||
logger.debug(f"Auto-save successful for student {id}")
|
||||
return JsonResponse({"status": "auto_save_success", "timestamp": util._now().isoformat()}, safe=False)
|
||||
else:
|
||||
logger.warning(f"Auto-save validation errors: {serializer.errors}")
|
||||
# Pour l'auto-save, on retourne un succès même en cas d'erreur de validation
|
||||
return JsonResponse({"status": "auto_save_partial", "errors": serializer.errors}, safe=False)
|
||||
else:
|
||||
# Pas de données à sauvegarder, mais on retourne un succès
|
||||
return JsonResponse({"status": "auto_save_no_data"}, safe=False)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Auto-save error for student {id}: {str(e)}")
|
||||
# Pour l'auto-save, on ne retourne pas d'erreur HTTP pour éviter d'interrompre l'UX
|
||||
return JsonResponse({"status": "auto_save_failed", "error": str(e)}, safe=False)
|
||||
|
||||
@swagger_auto_schema(
|
||||
responses={204: 'No Content'},
|
||||
operation_description="Supprime un dossier d'inscription donné.",
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
from django.http.response import JsonResponse
|
||||
from drf_yasg.utils import swagger_auto_schema
|
||||
from drf_yasg import openapi
|
||||
from rest_framework.parsers import MultiPartParser, FormParser
|
||||
from rest_framework.parsers import MultiPartParser, FormParser, JSONParser
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
from rest_framework import status
|
||||
import json
|
||||
from django.http import QueryDict
|
||||
|
||||
from Subscriptions.serializers import RegistrationSchoolFileMasterSerializer, RegistrationSchoolFileTemplateSerializer, RegistrationParentFileMasterSerializer, RegistrationParentFileTemplateSerializer
|
||||
from Subscriptions.serializers import RegistrationSchoolFileMasterSerializer, RegistrationParentFileMasterSerializer, RegistrationParentFileTemplateSerializer
|
||||
from Subscriptions.models import (
|
||||
RegistrationForm,
|
||||
RegistrationSchoolFileMaster,
|
||||
RegistrationSchoolFileTemplate,
|
||||
RegistrationParentFileMaster,
|
||||
RegistrationSchoolFileMaster,
|
||||
RegistrationParentFileMaster,
|
||||
RegistrationParentFileTemplate
|
||||
)
|
||||
from N3wtSchool import bdd
|
||||
@ -23,7 +22,8 @@ import Subscriptions.util as util
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class RegistrationSchoolFileMasterView(APIView):
|
||||
parser_classes = [MultiPartParser, FormParser]
|
||||
parser_classes = [MultiPartParser, FormParser, JSONParser]
|
||||
|
||||
@swagger_auto_schema(
|
||||
operation_description="Récupère tous les masters de templates d'inscription pour un établissement donné",
|
||||
manual_parameters=[
|
||||
@ -64,6 +64,7 @@ class RegistrationSchoolFileMasterView(APIView):
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
|
||||
logger.info(f"payload for serializer: {payload}")
|
||||
serializer = RegistrationSchoolFileMasterSerializer(data=payload, partial=True)
|
||||
if serializer.is_valid():
|
||||
@ -90,6 +91,7 @@ class RegistrationSchoolFileMasterView(APIView):
|
||||
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
class RegistrationSchoolFileMasterSimpleView(APIView):
|
||||
parser_classes = [MultiPartParser, FormParser, JSONParser]
|
||||
@swagger_auto_schema(
|
||||
operation_description="Récupère un master de template d'inscription spécifique",
|
||||
responses={
|
||||
@ -126,6 +128,7 @@ class RegistrationSchoolFileMasterSimpleView(APIView):
|
||||
if resp:
|
||||
return resp
|
||||
|
||||
|
||||
logger.info(f"payload for update serializer: {payload}")
|
||||
serializer = RegistrationSchoolFileMasterSerializer(master, data=payload, partial=True)
|
||||
if serializer.is_valid():
|
||||
|
||||
Reference in New Issue
Block a user