diff --git a/Back-End/School/management/commands/init_payment_plans.py b/Back-End/School/management/commands/init_payment_plans.py
new file mode 100644
index 0000000..d2557d9
--- /dev/null
+++ b/Back-End/School/management/commands/init_payment_plans.py
@@ -0,0 +1,58 @@
+from django.core.management.base import BaseCommand
+from django.utils import timezone
+from dateutil.relativedelta import relativedelta
+from School.models import PaymentPlan, PaymentPlanType, FeeType
+
+class Command(BaseCommand):
+ help = 'Initialize or update Payment Plans'
+
+ def handle(self, *args, **kwargs):
+ self.create_or_update_payment_plans()
+
+ def create_or_update_payment_plans(self):
+ current_date = timezone.now().date()
+
+ for fee_type in FeeType.choices:
+ fee_type_value = fee_type[0]
+
+ # 1 fois - échéance à 1 mois à partir de la date actuelle
+ PaymentPlan.objects.update_or_create(
+ frequency=PaymentPlanType.ONE_TIME,
+ type=fee_type_value,
+ defaults={
+ 'due_dates': [current_date + relativedelta(months=1)],
+ 'is_active': True
+ }
+ )
+
+ # 3 fois - échéances espacées de 4 mois
+ PaymentPlan.objects.update_or_create(
+ frequency=PaymentPlanType.THREE_TIMES,
+ type=fee_type_value,
+ defaults={
+ 'due_dates': [current_date + relativedelta(months=1+4*i) for i in range(3)],
+ 'is_active': False
+ }
+ )
+
+ # 10 fois - échéances espacées d'un mois
+ PaymentPlan.objects.update_or_create(
+ frequency=PaymentPlanType.TEN_TIMES,
+ type=fee_type_value,
+ defaults={
+ 'due_dates': [current_date + relativedelta(months=1+i) for i in range(10)],
+ 'is_active': False
+ }
+ )
+
+ # 12 fois - échéances espacées d'un mois
+ PaymentPlan.objects.update_or_create(
+ frequency=PaymentPlanType.TWELVE_TIMES,
+ type=fee_type_value,
+ defaults={
+ 'due_dates': [current_date + relativedelta(months=1+i) for i in range(12)],
+ 'is_active': False
+ }
+ )
+
+ self.stdout.write(self.style.SUCCESS('Payment Plans initialized or updated successfully'))
\ No newline at end of file
diff --git a/Back-End/School/models.py b/Back-End/School/models.py
index 3bc84cf..4c8b5d9 100644
--- a/Back-End/School/models.py
+++ b/Back-End/School/models.py
@@ -108,4 +108,8 @@ class PaymentPlan(models.Model):
frequency = models.IntegerField(choices=PaymentPlanType.choices, default=PaymentPlanType.ONE_TIME)
due_dates = ArrayField(models.DateField(), blank=True)
type = models.IntegerField(choices=FeeType.choices, default=FeeType.REGISTRATION_FEE)
+ is_active = models.BooleanField(default=False)
+
+ def __str__(self):
+ return f"{self.get_frequency_display()} - {self.get_type_display()}"
diff --git a/Back-End/Subscriptions/models.py b/Back-End/Subscriptions/models.py
index e7b2f9d..a2892c9 100644
--- a/Back-End/Subscriptions/models.py
+++ b/Back-End/Subscriptions/models.py
@@ -221,7 +221,7 @@ class RegistrationFileTemplate(models.Model):
order = models.PositiveIntegerField(default=0) # Ajout du champ order
date_added = models.DateTimeField(auto_now_add=True)
is_required = models.BooleanField(default=False)
- group = models.ForeignKey(RegistrationFileGroup, on_delete=models.CASCADE, related_name='file_templates')
+ group = models.ForeignKey(RegistrationFileGroup, on_delete=models.CASCADE, related_name='file_templates', null=True, blank=True)
@property
def formatted_date_added(self):
diff --git a/Back-End/start.py b/Back-End/start.py
index be242c4..99da02b 100644
--- a/Back-End/start.py
+++ b/Back-End/start.py
@@ -18,7 +18,8 @@ commands = [
["python", "manage.py", "makemigrations", "GestionMessagerie", "--noinput"],
["python", "manage.py", "makemigrations", "Auth", "--noinput"],
["python", "manage.py", "makemigrations", "School", "--noinput"],
- ["python", "manage.py", "migrate", "--noinput"]
+ ["python", "manage.py", "migrate", "--noinput"],
+ ["python", "manage.py", "init_payment_plans"]
]
for command in commands:
diff --git a/Front-End/src/app/[locale]/admin/structure/page.js b/Front-End/src/app/[locale]/admin/structure/page.js
index 51a7722..2d4afde 100644
--- a/Front-End/src/app/[locale]/admin/structure/page.js
+++ b/Front-End/src/app/[locale]/admin/structure/page.js
@@ -9,15 +9,16 @@ import { ClassesProvider } from '@/context/ClassesContext';
import { createDatas,
updateDatas,
removeDatas,
- fetchSpecialities,
- fetchTeachers,
- fetchClasses,
- fetchSchedules,
- fetchRegistrationDiscounts,
- fetchTuitionDiscounts,
- fetchRegistrationFees,
+ fetchSpecialities,
+ fetchTeachers,
+ fetchClasses,
+ fetchSchedules,
+ fetchRegistrationDiscounts,
+ fetchTuitionDiscounts,
+ fetchRegistrationFees,
fetchTuitionFees,
- } from '@/app/lib/schoolAction';
+ fetchRregistrationPaymentPlans,
+ fetchTuitionPaymentPlans } from '@/app/lib/schoolAction';
import SidebarTabs from '@/components/SidebarTabs';
import FilesManagement from '@/components/Structure/Files/FilesManagement';
@@ -35,6 +36,8 @@ export default function Page() {
const [registrationFees, setRegistrationFees] = useState([]);
const [tuitionFees, setTuitionFees] = useState([]);
const [fichiers, setFichiers] = useState([]);
+ const [registrationPaymentPlans, setRegistrationPaymentPlans] = useState([]);
+ const [tuitionPaymentPlans, setTuitionPaymentPlans] = useState([]);
const csrfToken = useCsrfToken();
@@ -70,7 +73,11 @@ export default function Page() {
})
.catch(error => console.error('Error fetching files:', error));
+ // Fetch data for registration payment plans
+ handleRegistrationPaymentPlans();
+ // Fetch data for tuition payment plans
+ handleTuitionPaymentPlans();
}, []);
const handleSpecialities = () => {
@@ -137,6 +144,22 @@ export default function Page() {
.catch(error => console.error('Error fetching tuition fees', error));
};
+ const handleRegistrationPaymentPlans = () => {
+ fetchRregistrationPaymentPlans()
+ .then(data => {
+ setRegistrationPaymentPlans(data);
+ })
+ .catch(error => console.error('Error fetching registration payment plans:', error));
+ };
+
+ const handleTuitionPaymentPlans = () => {
+ fetchTuitionPaymentPlans()
+ .then(data => {
+ setTuitionPaymentPlans(data);
+ })
+ .catch(error => console.error('Error fetching tuition payment plans:', error));
+ };
+
const handleCreate = (url, newData, setDatas) => {
return createDatas(url, newData, csrfToken)
.then(data => {
@@ -236,6 +259,11 @@ export default function Page() {
setRegistrationFees={setRegistrationFees}
tuitionFees={tuitionFees}
setTuitionFees={setTuitionFees}
+ registrationPaymentPlans={registrationPaymentPlans}
+ setRegistrationPaymentPlans={setRegistrationPaymentPlans}
+ tuitionPaymentPlans={tuitionPaymentPlans}
+ setTuitionPaymentPlans={setTuitionPaymentPlans}
+ setRegist
handleCreate={handleCreate}
handleEdit={handleEdit}
handleDelete={handleDelete}
diff --git a/Front-End/src/app/lib/schoolAction.js b/Front-End/src/app/lib/schoolAction.js
index 2c91893..9d84f91 100644
--- a/Front-End/src/app/lib/schoolAction.js
+++ b/Front-End/src/app/lib/schoolAction.js
@@ -4,7 +4,8 @@ import {
BE_SCHOOL_SCHOOLCLASSES_URL,
BE_SCHOOL_PLANNINGS_URL,
BE_SCHOOL_FEES_URL,
- BE_SCHOOL_DISCOUNTS_URL
+ BE_SCHOOL_DISCOUNTS_URL,
+ BE_SCHOOL_PAYMENT_PLANS_URL,
} from '@/utils/Url';
const requestResponseHandler = async (response) => {
@@ -60,6 +61,16 @@ export const fetchTuitionFees = () => {
.then(requestResponseHandler)
};
+export const fetchRregistrationPaymentPlans = () => {
+ return fetch(`${BE_SCHOOL_PAYMENT_PLANS_URL}/registration`)
+ .then(requestResponseHandler)
+}
+
+export const fetchTuitionPaymentPlans = () => {
+ return fetch(`${BE_SCHOOL_PAYMENT_PLANS_URL}/tuition`)
+ .then(requestResponseHandler)
+}
+
export const createDatas = (url, newData, csrfToken) => {
return fetch(url, {
method: 'POST',
diff --git a/Front-End/src/components/CheckBox.js b/Front-End/src/components/CheckBox.js
index 3818736..02f8fd5 100644
--- a/Front-End/src/components/CheckBox.js
+++ b/Front-End/src/components/CheckBox.js
@@ -3,7 +3,6 @@ import React from 'react';
const CheckBox = ({ item, formData, handleChange, fieldName, itemLabelFunc = () => null, labelAttenuated = () => false, horizontal }) => {
const isChecked = formData[fieldName].includes(parseInt(item.id));
const isAttenuated = labelAttenuated(item) && !isChecked;
-
return (
{horizontal && (
diff --git a/Front-End/src/components/CheckBoxList.js b/Front-End/src/components/CheckBoxList.js
index 8ff7a8c..0207e52 100644
--- a/Front-End/src/components/CheckBoxList.js
+++ b/Front-End/src/components/CheckBoxList.js
@@ -14,7 +14,7 @@ const CheckBoxList = ({
horizontal = false // Ajouter l'option horizontal
}) => {
return (
-
+