mirror of
https://git.v0id.ovh/n3wt-innov/n3wt-school.git
synced 2026-01-29 07:53:23 +00:00
fix: Calcul du montant total des tarif par RF + affichage des tarifs
actifs lors de la création d'un RF [#26]
This commit is contained in:
@ -8,27 +8,6 @@ from School.models import SchoolClass, Fee, Discount
|
|||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
class RegistrationFee(models.Model):
|
|
||||||
"""
|
|
||||||
Représente un tarif ou frais d’inscription avec différentes options de paiement.
|
|
||||||
"""
|
|
||||||
class PaymentOptions(models.IntegerChoices):
|
|
||||||
SINGLE_PAYMENT = 0, _('Paiement en une seule fois')
|
|
||||||
MONTHLY_PAYMENT = 1, _('Paiement mensuel')
|
|
||||||
QUARTERLY_PAYMENT = 2, _('Paiement trimestriel')
|
|
||||||
|
|
||||||
name = models.CharField(max_length=255, unique=True)
|
|
||||||
description = models.TextField(blank=True)
|
|
||||||
base_amount = models.DecimalField(max_digits=10, decimal_places=2)
|
|
||||||
discounts = models.JSONField(blank=True, null=True)
|
|
||||||
supplements = models.JSONField(blank=True, null=True)
|
|
||||||
validity_start_date = models.DateField()
|
|
||||||
validity_end_date = models.DateField()
|
|
||||||
payment_option = models.IntegerField(choices=PaymentOptions, default=PaymentOptions.SINGLE_PAYMENT)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.name
|
|
||||||
|
|
||||||
class Language(models.Model):
|
class Language(models.Model):
|
||||||
"""
|
"""
|
||||||
Représente une langue parlée par l’élève.
|
Représente une langue parlée par l’élève.
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from .models import RegistrationFileTemplate, RegistrationFile, RegistrationForm, Student, Guardian, Sibling, Language, RegistrationFee
|
from .models import RegistrationFileTemplate, RegistrationFile, RegistrationForm, Student, Guardian, Sibling, Language
|
||||||
from School.models import SchoolClass, Fee, Discount
|
from School.models import SchoolClass, Fee, Discount, FeeType
|
||||||
from School.serializers import FeeSerializer, DiscountSerializer
|
from School.serializers import FeeSerializer, DiscountSerializer
|
||||||
from Auth.models import Profile
|
from Auth.models import Profile
|
||||||
from Auth.serializers import ProfileSerializer
|
from Auth.serializers import ProfileSerializer
|
||||||
@ -11,12 +11,6 @@ from django.utils import timezone
|
|||||||
import pytz
|
import pytz
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
class RegistrationFeeSerializer(serializers.ModelSerializer):
|
|
||||||
id = serializers.IntegerField(required=False)
|
|
||||||
class Meta:
|
|
||||||
model = RegistrationFee
|
|
||||||
fields = '__all__'
|
|
||||||
|
|
||||||
class RegistrationFileSerializer(serializers.ModelSerializer):
|
class RegistrationFileSerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RegistrationFile
|
model = RegistrationFile
|
||||||
@ -136,6 +130,8 @@ class RegistrationFormSerializer(serializers.ModelSerializer):
|
|||||||
registration_files = RegistrationFileSerializer(many=True, required=False)
|
registration_files = RegistrationFileSerializer(many=True, required=False)
|
||||||
fees = serializers.PrimaryKeyRelatedField(queryset=Fee.objects.all(), many=True, required=False)
|
fees = serializers.PrimaryKeyRelatedField(queryset=Fee.objects.all(), many=True, required=False)
|
||||||
discounts = serializers.PrimaryKeyRelatedField(queryset=Discount.objects.all(), many=True, required=False)
|
discounts = serializers.PrimaryKeyRelatedField(queryset=Discount.objects.all(), many=True, required=False)
|
||||||
|
totalRegistrationFees = serializers.SerializerMethodField()
|
||||||
|
totalTuitionFees = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RegistrationForm
|
model = RegistrationForm
|
||||||
@ -184,6 +180,14 @@ class RegistrationFormSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
return local_time.strftime("%d-%m-%Y %H:%M")
|
return local_time.strftime("%d-%m-%Y %H:%M")
|
||||||
|
|
||||||
|
def get_totalRegistrationFees(self, obj):
|
||||||
|
for fee in obj.fees.filter(type=FeeType.REGISTRATION_FEE):
|
||||||
|
print(fee.base_amount)
|
||||||
|
return sum(fee.base_amount for fee in obj.fees.filter(type=FeeType.REGISTRATION_FEE))
|
||||||
|
|
||||||
|
def get_totalTuitionFees(self, obj):
|
||||||
|
return sum(fee.base_amount for fee in obj.fees.filter(type=FeeType.TUITION_FEE))
|
||||||
|
|
||||||
class StudentByParentSerializer(serializers.ModelSerializer):
|
class StudentByParentSerializer(serializers.ModelSerializer):
|
||||||
id = serializers.IntegerField(required=False)
|
id = serializers.IntegerField(required=False)
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
from django.urls import path, re_path
|
from django.urls import path, re_path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
from .views import RegistrationFileTemplateView, RegisterFormListView, RegisterFormView, StudentView, GuardianView, ChildrenListView, StudentListView, RegistrationFeeView, RegistrationFileView
|
from .views import RegistrationFileTemplateView, RegisterFormListView, RegisterFormView, StudentView, GuardianView, ChildrenListView, StudentListView, RegistrationFileView
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
re_path(r'^registerForms/(?P<_filter>[a-zA-z]+)$', RegisterFormListView.as_view(), name="registerForms"),
|
re_path(r'^registerForms/(?P<_filter>[a-zA-z]+)$', RegisterFormListView.as_view(), name="registerForms"),
|
||||||
@ -30,9 +30,6 @@ urlpatterns = [
|
|||||||
# Page INSCRIPTION - Liste des élèves
|
# Page INSCRIPTION - Liste des élèves
|
||||||
re_path(r'^students$', StudentListView.as_view(), name="students"),
|
re_path(r'^students$', StudentListView.as_view(), name="students"),
|
||||||
|
|
||||||
# Frais d'inscription
|
|
||||||
re_path(r'^registrationFees$', RegistrationFeeView.as_view(), name="registrationFees"),
|
|
||||||
|
|
||||||
# modèles de fichiers d'inscription
|
# modèles de fichiers d'inscription
|
||||||
re_path(r'^registrationFileTemplates$', RegistrationFileTemplateView.as_view(), name='registrationFileTemplates'),
|
re_path(r'^registrationFileTemplates$', RegistrationFileTemplateView.as_view(), name='registrationFileTemplates'),
|
||||||
re_path(r'^registrationFileTemplates/(?P<_id>[0-9]+)$', RegistrationFileTemplateView.as_view(), name="registrationFileTemplate"),
|
re_path(r'^registrationFileTemplates/(?P<_id>[0-9]+)$', RegistrationFileTemplateView.as_view(), name="registrationFileTemplate"),
|
||||||
|
|||||||
@ -22,10 +22,10 @@ import Subscriptions.mailManager as mailer
|
|||||||
import Subscriptions.util as util
|
import Subscriptions.util as util
|
||||||
|
|
||||||
from Subscriptions.automate import Automate_RF_Register, load_config, getStateMachineObjectState, updateStateMachine
|
from Subscriptions.automate import Automate_RF_Register, load_config, getStateMachineObjectState, updateStateMachine
|
||||||
from .serializers import RegistrationFormSerializer, StudentSerializer, RegistrationFormByParentSerializer, StudentByRFCreationSerializer, RegistrationFileSerializer, RegistrationFileTemplateSerializer, RegistrationFormByParentSerializer, StudentByRFCreationSerializer, RegistrationFeeSerializer
|
from .serializers import RegistrationFormSerializer, StudentSerializer, RegistrationFormByParentSerializer, StudentByRFCreationSerializer, RegistrationFileSerializer, RegistrationFileTemplateSerializer, RegistrationFormByParentSerializer, StudentByRFCreationSerializer
|
||||||
from .pagination import CustomPagination
|
from .pagination import CustomPagination
|
||||||
from .signals import clear_cache
|
from .signals import clear_cache
|
||||||
from .models import Student, Guardian, RegistrationForm, RegistrationFee, RegistrationFileTemplate, RegistrationFile
|
from .models import Student, Guardian, RegistrationForm, RegistrationFileTemplate, RegistrationFile
|
||||||
from .automate import Automate_RF_Register, load_config, getStateMachineObjectState, updateStateMachine
|
from .automate import Automate_RF_Register, load_config, getStateMachineObjectState, updateStateMachine
|
||||||
|
|
||||||
from Auth.models import Profile
|
from Auth.models import Profile
|
||||||
@ -335,16 +335,6 @@ class StudentListView(APIView):
|
|||||||
students_serializer = StudentByRFCreationSerializer(students, many=True)
|
students_serializer = StudentByRFCreationSerializer(students, many=True)
|
||||||
return JsonResponse(students_serializer.data, safe=False)
|
return JsonResponse(students_serializer.data, safe=False)
|
||||||
|
|
||||||
# API utilisée pour la vue de personnalisation des frais d'inscription pour la structure
|
|
||||||
class RegistrationFeeView(APIView):
|
|
||||||
"""
|
|
||||||
Liste les frais d’inscription.
|
|
||||||
"""
|
|
||||||
def get(self, request):
|
|
||||||
tarifs = bdd.getAllObjects(RegistrationFee)
|
|
||||||
tarifs_serializer = RegistrationFeeSerializer(tarifs, many=True)
|
|
||||||
return JsonResponse(tarifs_serializer.data, safe=False)
|
|
||||||
|
|
||||||
class RegistrationFileTemplateView(APIView):
|
class RegistrationFileTemplateView(APIView):
|
||||||
"""
|
"""
|
||||||
Gère les fichiers templates pour les dossiers d’inscription.
|
Gère les fichiers templates pour les dossiers d’inscription.
|
||||||
|
|||||||
@ -410,7 +410,9 @@ useEffect(()=>{
|
|||||||
associated_profile: response.id
|
associated_profile: response.id
|
||||||
}],
|
}],
|
||||||
sibling: []
|
sibling: []
|
||||||
}
|
},
|
||||||
|
fees: allFeesIds,
|
||||||
|
discounts: allDiscountsds
|
||||||
};
|
};
|
||||||
|
|
||||||
createRegisterForm(data, csrfToken)
|
createRegisterForm(data, csrfToken)
|
||||||
@ -422,6 +424,7 @@ useEffect(()=>{
|
|||||||
sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
|
sendConfirmRegisterForm(data.student.id, updatedData.studentLastName, updatedData.studentFirstName);
|
||||||
}
|
}
|
||||||
closeModal();
|
closeModal();
|
||||||
|
console.log('Success:', data);
|
||||||
// Forcer le rechargement complet des données
|
// Forcer le rechargement complet des données
|
||||||
setReloadFetch(true);
|
setReloadFetch(true);
|
||||||
})
|
})
|
||||||
@ -810,8 +813,8 @@ const handleFileUpload = ({file, name, is_required, order}) => {
|
|||||||
<InscriptionForm students={students}
|
<InscriptionForm students={students}
|
||||||
registrationDiscounts={registrationDiscounts}
|
registrationDiscounts={registrationDiscounts}
|
||||||
tuitionDiscounts={tuitionDiscounts}
|
tuitionDiscounts={tuitionDiscounts}
|
||||||
registrationFees={registrationFees}
|
registrationFees={registrationFees.filter(fee => fee.is_active)}
|
||||||
tuitionFees={tuitionFees}
|
tuitionFees={tuitionFees.filter(fee => fee.is_active)}
|
||||||
onSubmit={createRF}
|
onSubmit={createRF}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -123,6 +123,7 @@ const InscriptionForm = ( { students, registrationDiscounts, tuitionDiscounts, r
|
|||||||
};
|
};
|
||||||
|
|
||||||
const submit = () => {
|
const submit = () => {
|
||||||
|
console.log('Submitting form data:', formData);
|
||||||
onSubmit(formData);
|
onSubmit(formData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,10 +4,15 @@ import ReactDOM from 'react-dom';
|
|||||||
const Popup = ({ visible, message, onConfirm, onCancel, uniqueConfirmButton = false }) => {
|
const Popup = ({ visible, message, onConfirm, onCancel, uniqueConfirmButton = false }) => {
|
||||||
if (!visible) return null;
|
if (!visible) return null;
|
||||||
|
|
||||||
|
// Diviser le message en lignes
|
||||||
|
const messageLines = message.split('\n');
|
||||||
|
|
||||||
return ReactDOM.createPortal(
|
return ReactDOM.createPortal(
|
||||||
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
|
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50">
|
||||||
<div className="bg-white p-6 rounded-md shadow-md">
|
<div className="bg-white p-6 rounded-md shadow-md">
|
||||||
<p className="mb-4">{message}</p>
|
{messageLines.map((line, index) => (
|
||||||
|
<p key={index} className="mb-4">{line}</p>
|
||||||
|
))}
|
||||||
<div className={`flex ${uniqueConfirmButton ? 'justify-center' : 'justify-end'} gap-4`}>
|
<div className={`flex ${uniqueConfirmButton ? 'justify-center' : 'justify-end'} gap-4`}>
|
||||||
{!uniqueConfirmButton && (
|
{!uniqueConfirmButton && (
|
||||||
<button className="px-4 py-2 bg-gray-200 rounded-md" onClick={onCancel}>Annuler</button>
|
<button className="px-4 py-2 bg-gray-200 rounded-md" onClick={onCancel}>Annuler</button>
|
||||||
|
|||||||
@ -94,6 +94,9 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
|
|||||||
const [localErrors, setLocalErrors] = useState({});
|
const [localErrors, setLocalErrors] = useState({});
|
||||||
const [popupVisible, setPopupVisible] = useState(false);
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
const [popupMessage, setPopupMessage] = useState("");
|
const [popupMessage, setPopupMessage] = useState("");
|
||||||
|
const [removePopupVisible, setRemovePopupVisible] = useState(false);
|
||||||
|
const [removePopupMessage, setRemovePopupMessage] = useState("");
|
||||||
|
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||||||
|
|
||||||
const niveauxPremierCycle = [
|
const niveauxPremierCycle = [
|
||||||
{ id: 1, name: 'TPS', age: 2 },
|
{ id: 1, name: 'TPS', age: 2 },
|
||||||
@ -377,7 +380,25 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleDelete(classe.id)}
|
onClick={() => {
|
||||||
|
setRemovePopupVisible(true);
|
||||||
|
setRemovePopupMessage("Attentions ! \nVous êtes sur le point de supprimer la classe " + classe.atmosphere_name + ".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
|
||||||
|
setRemovePopupOnConfirm(() => () => {
|
||||||
|
handleDelete(classe.id)
|
||||||
|
.then(data => {
|
||||||
|
console.log('Success:', data);
|
||||||
|
setPopupMessage("La classe " + classe.atmosphere_name + " a été correctement supprimée");
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error archiving data:', error);
|
||||||
|
setPopupMessage("Erreur lors de la suppression de la classe " + classe.atmosphere_name);
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
className="text-red-500 hover:text-red-700"
|
className="text-red-500 hover:text-red-700"
|
||||||
>
|
>
|
||||||
<Trash2 className="w-5 h-5" />
|
<Trash2 className="w-5 h-5" />
|
||||||
@ -432,6 +453,12 @@ const ClassesSection = ({ classes, setClasses, teachers, handleCreate, handleEdi
|
|||||||
onCancel={() => setPopupVisible(false)}
|
onCancel={() => setPopupVisible(false)}
|
||||||
uniqueConfirmButton={true}
|
uniqueConfirmButton={true}
|
||||||
/>
|
/>
|
||||||
|
<Popup
|
||||||
|
visible={removePopupVisible}
|
||||||
|
message={removePopupMessage}
|
||||||
|
onConfirm={removePopupOnConfirm}
|
||||||
|
onCancel={() => setRemovePopupVisible(false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -16,6 +16,10 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
|
|||||||
const [popupVisible, setPopupVisible] = useState(false);
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
const [popupMessage, setPopupMessage] = useState("");
|
const [popupMessage, setPopupMessage] = useState("");
|
||||||
|
|
||||||
|
const [removePopupVisible, setRemovePopupVisible] = useState(false);
|
||||||
|
const [removePopupMessage, setRemovePopupMessage] = useState("");
|
||||||
|
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||||||
|
|
||||||
// Récupération des messages d'erreur
|
// Récupération des messages d'erreur
|
||||||
const getError = (field) => {
|
const getError = (field) => {
|
||||||
return localErrors?.[field]?.[0];
|
return localErrors?.[field]?.[0];
|
||||||
@ -26,7 +30,7 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveSpeciality = (id) => {
|
const handleRemoveSpeciality = (id) => {
|
||||||
handleDelete(id)
|
return handleDelete(id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setSpecialities(prevSpecialities => prevSpecialities.filter(speciality => speciality.id !== id));
|
setSpecialities(prevSpecialities => prevSpecialities.filter(speciality => speciality.id !== id));
|
||||||
})
|
})
|
||||||
@ -161,7 +165,25 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleRemoveSpeciality(speciality.id)}
|
onClick={() => {
|
||||||
|
setRemovePopupVisible(true);
|
||||||
|
setRemovePopupMessage("Attentions ! \nVous êtes sur le point de supprimer la spécialité " + speciality.name + ".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
|
||||||
|
setRemovePopupOnConfirm(() => () => {
|
||||||
|
handleRemoveSpeciality(speciality.id)
|
||||||
|
.then(data => {
|
||||||
|
console.log('Success:', data);
|
||||||
|
setPopupMessage("La spécialité " + speciality.name + " a été correctement supprimée");
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error archiving data:', error);
|
||||||
|
setPopupMessage("Erreur lors de la suppression de la spécialité " + speciality.name);
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
className="text-red-500 hover:text-red-700"
|
className="text-red-500 hover:text-red-700"
|
||||||
>
|
>
|
||||||
<Trash2 className="w-5 h-5" />
|
<Trash2 className="w-5 h-5" />
|
||||||
@ -204,6 +226,12 @@ const SpecialitiesSection = ({ specialities, setSpecialities, handleCreate, hand
|
|||||||
onCancel={() => setPopupVisible(false)}
|
onCancel={() => setPopupVisible(false)}
|
||||||
uniqueConfirmButton={true}
|
uniqueConfirmButton={true}
|
||||||
/>
|
/>
|
||||||
|
<Popup
|
||||||
|
visible={removePopupVisible}
|
||||||
|
message={removePopupMessage}
|
||||||
|
onConfirm={removePopupOnConfirm}
|
||||||
|
onCancel={() => setRemovePopupVisible(false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -98,6 +98,10 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
const [popupVisible, setPopupVisible] = useState(false);
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
const [popupMessage, setPopupMessage] = useState("");
|
const [popupMessage, setPopupMessage] = useState("");
|
||||||
|
|
||||||
|
const [removePopupVisible, setRemovePopupVisible] = useState(false);
|
||||||
|
const [removePopupMessage, setRemovePopupMessage] = useState("");
|
||||||
|
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||||||
|
|
||||||
// Récupération des messages d'erreur
|
// Récupération des messages d'erreur
|
||||||
const getError = (field) => {
|
const getError = (field) => {
|
||||||
return localErrors?.[field]?.[0];
|
return localErrors?.[field]?.[0];
|
||||||
@ -109,7 +113,7 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveTeacher = (id) => {
|
const handleRemoveTeacher = (id) => {
|
||||||
handleDelete(id)
|
return handleDelete(id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setTeachers(prevTeachers => prevTeachers.filter(teacher => teacher.id !== id));
|
setTeachers(prevTeachers => prevTeachers.filter(teacher => teacher.id !== id));
|
||||||
})
|
})
|
||||||
@ -361,7 +365,25 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleRemoveTeacher(teacher.id)}
|
onClick={() => {
|
||||||
|
setRemovePopupVisible(true);
|
||||||
|
setRemovePopupMessage("Attentions ! \nVous êtes sur le point de supprimer l'enseignant " + teacher.last_name + " " + teacher.first_name + ".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
|
||||||
|
setRemovePopupOnConfirm(() => () => {
|
||||||
|
handleRemoveTeacher(teacher.id)
|
||||||
|
.then(data => {
|
||||||
|
console.log('Success:', data);
|
||||||
|
setPopupMessage("L'enseignant " + teacher.last_name + " " + teacher.first_name + " a été correctement supprimé");
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error archiving data:', error);
|
||||||
|
setPopupMessage("Erreur lors de la suppression de l'enseignant " + teacher.last_name + " " + teacher.first_name);
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
className="text-red-500 hover:text-red-700"
|
className="text-red-500 hover:text-red-700"
|
||||||
>
|
>
|
||||||
<Trash2 className="w-5 h-5" />
|
<Trash2 className="w-5 h-5" />
|
||||||
@ -407,6 +429,12 @@ const TeachersSection = ({ teachers, setTeachers, specialities, handleCreate, ha
|
|||||||
onCancel={() => setPopupVisible(false)}
|
onCancel={() => setPopupVisible(false)}
|
||||||
uniqueConfirmButton={true}
|
uniqueConfirmButton={true}
|
||||||
/>
|
/>
|
||||||
|
<Popup
|
||||||
|
visible={removePopupVisible}
|
||||||
|
message={removePopupMessage}
|
||||||
|
onConfirm={removePopupOnConfirm}
|
||||||
|
onCancel={() => setRemovePopupVisible(false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -12,13 +12,16 @@ const DiscountsSection = ({ discounts, setDiscounts, handleCreate, handleEdit, h
|
|||||||
const [localErrors, setLocalErrors] = useState({});
|
const [localErrors, setLocalErrors] = useState({});
|
||||||
const [popupVisible, setPopupVisible] = useState(false);
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
const [popupMessage, setPopupMessage] = useState("");
|
const [popupMessage, setPopupMessage] = useState("");
|
||||||
|
const [removePopupVisible, setRemovePopupVisible] = useState(false);
|
||||||
|
const [removePopupMessage, setRemovePopupMessage] = useState("");
|
||||||
|
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||||||
|
|
||||||
const handleAddDiscount = () => {
|
const handleAddDiscount = () => {
|
||||||
setNewDiscount({ id: Date.now(), name: '', amount: '', description: '', discount_type: 0, type: type });
|
setNewDiscount({ id: Date.now(), name: '', amount: '', description: '', discount_type: 0, type: type });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveDiscount = (id) => {
|
const handleRemoveDiscount = (id) => {
|
||||||
handleDelete(id)
|
return handleDelete(id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setDiscounts(prevDiscounts => prevDiscounts.filter(discount => discount.id !== id));
|
setDiscounts(prevDiscounts => prevDiscounts.filter(discount => discount.id !== id));
|
||||||
})
|
})
|
||||||
@ -204,7 +207,25 @@ const DiscountsSection = ({ discounts, setDiscounts, handleCreate, handleEdit, h
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleRemoveDiscount(discount.id)}
|
onClick={() => {
|
||||||
|
setRemovePopupVisible(true);
|
||||||
|
setRemovePopupMessage("Attentions ! \nVous êtes sur le point de supprimer un tarif personnalisé.\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
|
||||||
|
setRemovePopupOnConfirm(() => () => {
|
||||||
|
handleRemoveDiscount(discount.id)
|
||||||
|
.then(data => {
|
||||||
|
console.log('Success:', data);
|
||||||
|
setPopupMessage("Réduction correctement supprimé");
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error archiving data:', error);
|
||||||
|
setPopupMessage("Erreur lors de la suppression de la réduction");
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
className="text-red-500 hover:text-red-700"
|
className="text-red-500 hover:text-red-700"
|
||||||
>
|
>
|
||||||
<Trash2 className="w-5 h-5" />
|
<Trash2 className="w-5 h-5" />
|
||||||
@ -269,6 +290,12 @@ const DiscountsSection = ({ discounts, setDiscounts, handleCreate, handleEdit, h
|
|||||||
onCancel={() => setPopupVisible(false)}
|
onCancel={() => setPopupVisible(false)}
|
||||||
uniqueConfirmButton={true}
|
uniqueConfirmButton={true}
|
||||||
/>
|
/>
|
||||||
|
<Popup
|
||||||
|
visible={removePopupVisible}
|
||||||
|
message={removePopupMessage}
|
||||||
|
onConfirm={removePopupOnConfirm}
|
||||||
|
onCancel={() => setRemovePopupVisible(false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -12,13 +12,22 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
|
|||||||
const [localErrors, setLocalErrors] = useState({});
|
const [localErrors, setLocalErrors] = useState({});
|
||||||
const [popupVisible, setPopupVisible] = useState(false);
|
const [popupVisible, setPopupVisible] = useState(false);
|
||||||
const [popupMessage, setPopupMessage] = useState("");
|
const [popupMessage, setPopupMessage] = useState("");
|
||||||
|
const [removePopupVisible, setRemovePopupVisible] = useState(false);
|
||||||
|
const [removePopupMessage, setRemovePopupMessage] = useState("");
|
||||||
|
const [removePopupOnConfirm, setRemovePopupOnConfirm] = useState(() => {});
|
||||||
|
const labelTypeFrais = (type === 0 ? 'Frais d\'inscription' : 'Frais de scolarité');
|
||||||
|
|
||||||
|
// Récupération des messages d'erreur
|
||||||
|
const getError = (field) => {
|
||||||
|
return localErrors?.[field]?.[0];
|
||||||
|
};
|
||||||
|
|
||||||
const handleAddFee = () => {
|
const handleAddFee = () => {
|
||||||
setNewFee({ id: Date.now(), name: '', base_amount: '', description: '', validity_start_date: '', validity_end_date: '', discounts: [], type: type });
|
setNewFee({ id: Date.now(), name: '', base_amount: '', description: '', validity_start_date: '', validity_end_date: '', discounts: [], type: type });
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveFee = (id) => {
|
const handleRemoveFee = (id) => {
|
||||||
handleDelete(id)
|
return handleDelete(id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setFees(prevFees => prevFees.filter(fee => fee.id !== id));
|
setFees(prevFees => prevFees.filter(fee => fee.id !== id));
|
||||||
})
|
})
|
||||||
@ -37,11 +46,11 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
|
|||||||
setNewFee(null);
|
setNewFee(null);
|
||||||
setLocalErrors({});
|
setLocalErrors({});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
if (error && typeof error === 'object') {
|
console.error('Error:', error.message);
|
||||||
setLocalErrors(error);
|
if (error.details) {
|
||||||
} else {
|
console.error('Form errors:', error.details);
|
||||||
console.error(error);
|
setLocalErrors(error.details);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -60,11 +69,11 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
|
|||||||
setEditingFee(null);
|
setEditingFee(null);
|
||||||
setLocalErrors({});
|
setLocalErrors({});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
if (error && typeof error === 'object') {
|
console.error('Error:', error.message);
|
||||||
setLocalErrors(error);
|
if (error.details) {
|
||||||
} else {
|
console.error('Form errors:', error.details);
|
||||||
console.error(error);
|
setLocalErrors(error.details);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -118,7 +127,7 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
|
|||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
placeholder={placeholder}
|
placeholder={placeholder}
|
||||||
errorMsg={localErrors && localErrors[field] && Array.isArray(localErrors[field]) ? localErrors[field][0] : ''}
|
errorMsg={getError(field)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -187,7 +196,25 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => handleRemoveFee(fee.id)}
|
onClick={() => {
|
||||||
|
setRemovePopupVisible(true);
|
||||||
|
setRemovePopupMessage("Attentions ! \nVous êtes sur le point de supprimer un " + labelTypeFrais + ".\nÊtes-vous sûr(e) de vouloir poursuivre l'opération ?");
|
||||||
|
setRemovePopupOnConfirm(() => () => {
|
||||||
|
handleRemoveFee(fee.id)
|
||||||
|
.then(data => {
|
||||||
|
console.log('Success:', data);
|
||||||
|
setPopupMessage(labelTypeFrais + " correctement supprimé");
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error archiving data:', error);
|
||||||
|
setPopupMessage("Erreur lors de la suppression du " + labelTypeFrais);
|
||||||
|
setPopupVisible(true);
|
||||||
|
setRemovePopupVisible(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
className="text-red-500 hover:text-red-700"
|
className="text-red-500 hover:text-red-700"
|
||||||
>
|
>
|
||||||
<Trash2 className="w-5 h-5" />
|
<Trash2 className="w-5 h-5" />
|
||||||
@ -232,7 +259,7 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
|
|||||||
<div className="flex justify-between items-center">
|
<div className="flex justify-between items-center">
|
||||||
<div className="flex items-center mb-4">
|
<div className="flex items-center mb-4">
|
||||||
<CreditCard className="w-6 h-6 text-emerald-500 mr-2" />
|
<CreditCard className="w-6 h-6 text-emerald-500 mr-2" />
|
||||||
<h2 className="text-xl font-semibold">{type === 0 ? 'Frais d\'inscription' : 'Frais de scolarité'}</h2>
|
<h2 className="text-xl font-semibold">{labelTypeFrais}</h2>
|
||||||
</div>
|
</div>
|
||||||
<button type="button" onClick={handleAddFee} className="text-emerald-500 hover:text-emerald-700">
|
<button type="button" onClick={handleAddFee} className="text-emerald-500 hover:text-emerald-700">
|
||||||
<Plus className="w-5 h-5" />
|
<Plus className="w-5 h-5" />
|
||||||
@ -251,6 +278,12 @@ const FeesSection = ({ fees, setFees, discounts, handleCreate, handleEdit, handl
|
|||||||
onCancel={() => setPopupVisible(false)}
|
onCancel={() => setPopupVisible(false)}
|
||||||
uniqueConfirmButton={true}
|
uniqueConfirmButton={true}
|
||||||
/>
|
/>
|
||||||
|
<Popup
|
||||||
|
visible={removePopupVisible}
|
||||||
|
message={removePopupMessage}
|
||||||
|
onConfirm={removePopupOnConfirm}
|
||||||
|
onCancel={() => setRemovePopupVisible(false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user