diff --git a/Back-End/School/models.py b/Back-End/School/models.py index a992eac..25967b2 100644 --- a/Back-End/School/models.py +++ b/Back-End/School/models.py @@ -68,6 +68,11 @@ class Planning(models.Model): def __str__(self): return f'Planning for {self.level} of {self.school_class.atmosphere_name}' +class PaymentOptions(models.IntegerChoices): + SINGLE_PAYMENT = 0, _('Paiement en une seule fois') + FOUR_TIME_PAYMENT = 1, _('Paiement en 4 fois') + TEN_TIME_PAYMENT = 2, _('Paiement en 10 fois') + class Discount(models.Model): name = models.CharField(max_length=255, unique=True) amount = models.DecimalField(max_digits=10, decimal_places=2) @@ -78,25 +83,23 @@ class Discount(models.Model): class Fee(models.Model): name = models.CharField(max_length=255, unique=True) - amount = models.DecimalField(max_digits=10, decimal_places=2) description = models.TextField(blank=True) + base_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0) + currency = models.CharField(max_length=3, default='EUR') + discounts = models.ManyToManyField('Discount', blank=True) + payment_option = models.IntegerField(choices=PaymentOptions, default=PaymentOptions.SINGLE_PAYMENT) + is_active = models.BooleanField(default=True) + updated_at = models.DateTimeField(auto_now=True) def __str__(self): return self.name class TuitionFee(models.Model): - class PaymentOptions(models.IntegerChoices): - SINGLE_PAYMENT = 0, _('Paiement en une seule fois') - FOUR_TIME_PAYMENT = 1, _('Paiement en 4 fois') - TEN_TIME_PAYMENT = 2, _('Paiement en 10 fois') - name = models.CharField(max_length=255, unique=True) description = models.TextField(blank=True) - base_amount = models.DecimalField(max_digits=10, decimal_places=2) + base_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0) currency = models.CharField(max_length=3, default='EUR') discounts = models.ManyToManyField('Discount', blank=True) - validity_start_date = models.DateField() - validity_end_date = models.DateField() payment_option = models.IntegerField(choices=PaymentOptions, default=PaymentOptions.SINGLE_PAYMENT) is_active = models.BooleanField(default=True) updated_at = models.DateTimeField(auto_now=True) @@ -107,16 +110,3 @@ class TuitionFee(models.Model): def clean(self): if self.validity_end_date <= self.validity_start_date: raise ValidationError(_('La date de fin de validité doit être après la date de début de validité.')) - - def calculate_final_amount(self): - amount = self.base_amount - - # Apply fees (supplements and taxes) - # for fee in self.fees.all(): - # amount += fee.amount - - # Apply discounts - for discount in self.discounts.all(): - amount -= discount.amount - - return amount diff --git a/Back-End/School/serializers.py b/Back-End/School/serializers.py index 2248861..08b5588 100644 --- a/Back-End/School/serializers.py +++ b/Back-End/School/serializers.py @@ -180,21 +180,48 @@ class DiscountSerializer(serializers.ModelSerializer): fields = '__all__' class FeeSerializer(serializers.ModelSerializer): + discounts = serializers.PrimaryKeyRelatedField(queryset=Discount.objects.all(), many=True) + class Meta: model = Fee fields = '__all__' + def create(self, validated_data): + discounts_data = validated_data.pop('discounts', []) + + # Create the Fee instance + fee = Fee.objects.create(**validated_data) + + # Add discounts if provided + fee.discounts.set(discounts_data) + + return fee + + def update(self, instance, validated_data): + discounts_data = validated_data.pop('discounts', []) + + # Update the Fee instance + instance.name = validated_data.get('name', instance.name) + instance.description = validated_data.get('description', instance.description) + instance.base_amount = validated_data.get('base_amount', instance.base_amount) + instance.currency = validated_data.get('currency', instance.currency) + instance.payment_option = validated_data.get('payment_option', instance.payment_option) + instance.is_active = validated_data.get('is_active', instance.is_active) + instance.updated_at = validated_data.get('updated_at', instance.updated_at) + instance.save() + + # Update discounts if provided + instance.discounts.set(discounts_data) + + return instance + class TuitionFeeSerializer(serializers.ModelSerializer): discounts = serializers.PrimaryKeyRelatedField(queryset=Discount.objects.all(), many=True) - final_amount = serializers.SerializerMethodField() class Meta: model = TuitionFee fields = '__all__' - def get_final_amount(self, obj): - return obj.calculate_final_amount() - def create(self, validated_data): discounts_data = validated_data.pop('discounts', []) @@ -202,8 +229,7 @@ class TuitionFeeSerializer(serializers.ModelSerializer): tuition_fee = TuitionFee.objects.create(**validated_data) # Add discounts if provided - for discount in discounts_data: - tuition_fee.discounts.add(discount) + tuition_fee.discounts.set(discounts_data) return tuition_fee @@ -215,14 +241,12 @@ class TuitionFeeSerializer(serializers.ModelSerializer): instance.description = validated_data.get('description', instance.description) instance.base_amount = validated_data.get('base_amount', instance.base_amount) instance.currency = validated_data.get('currency', instance.currency) - instance.validity_start_date = validated_data.get('validity_start_date', instance.validity_start_date) - instance.validity_end_date = validated_data.get('validity_end_date', instance.validity_end_date) instance.payment_option = validated_data.get('payment_option', instance.payment_option) instance.is_active = validated_data.get('is_active', instance.is_active) + instance.updated_at = validated_data.get('updated_at', instance.updated_at) instance.save() # Update discounts if provided - if discounts_data: - instance.discounts.set(discounts_data) + instance.discounts.set(discounts_data) return instance \ No newline at end of file diff --git a/Front-End/src/app/[locale]/admin/structure/page.js b/Front-End/src/app/[locale]/admin/structure/page.js index 2f111a2..4300560 100644 --- a/Front-End/src/app/[locale]/admin/structure/page.js +++ b/Front-End/src/app/[locale]/admin/structure/page.js @@ -99,7 +99,7 @@ export default function Page() { .catch(error => console.error('Error fetching tuition fees', error)); }; - const handleCreate = (url, newData, setDatas, setErrors) => { + const handleCreate = (url, newData, setDatas) => { return fetch(url, { method: 'POST', headers: { @@ -119,17 +119,15 @@ export default function Page() { }) .then(data => { setDatas(prevState => [...prevState, data]); - setErrors({}); return data; }) .catch(error => { - setErrors(error); console.error('Error creating data:', error); throw error; }); }; - const handleEdit = (url, id, updatedData, setDatas, setErrors) => { + const handleEdit = (url, id, updatedData, setDatas) => { return fetch(`${url}/${id}`, { method: 'PUT', headers: { @@ -149,18 +147,16 @@ export default function Page() { }) .then(data => { setDatas(prevState => prevState.map(item => item.id === id ? data : item)); - setErrors({}); return data; }) .catch(error => { - setErrors(error); console.error('Error editing data:', error); throw error; }); }; const handleDelete = (url, id, setDatas) => { - fetch(`${url}/${id}`, { + return fetch(`${url}/${id}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', @@ -168,12 +164,24 @@ export default function Page() { }, credentials: 'include' }) - .then(response => response.json()) + .then(response => { + if (!response.ok) { + return response.json().then(errorData => { + throw errorData; + }); + } + return response.json(); + }) .then(data => { setDatas(prevState => prevState.filter(item => item.id !== id)); + return data; }) - .catch(error => console.error('Error deleting data:', error)); + .catch(error => { + console.error('Error deleting data:', error); + throw error; + }); }; + const handleUpdatePlanning = (url, planningId, updatedData) => { fetch(`${url}/${planningId}`, { method: 'PUT', diff --git a/Front-End/src/components/InputTextIcon.js b/Front-End/src/components/InputTextIcon.js index 8b60ba2..25aeb94 100644 --- a/Front-End/src/components/InputTextIcon.js +++ b/Front-End/src/components/InputTextIcon.js @@ -1,7 +1,7 @@ export default function InputTextIcon({name, type, IconItem, label, value, onChange, errorMsg, placeholder, className}) { return ( <> -