diff --git a/SIRH/settings.py b/SIRH/settings.py index 577808e..8b6f149 100644 --- a/SIRH/settings.py +++ b/SIRH/settings.py @@ -41,12 +41,9 @@ INSTALLED_APPS = [ 'gestion_employe', 'gestion_conge', 'gestion_projet', - 'gestion_salle', - 'simple_sso.sso_server' + 'gestion_salle' ] -LOGIN_URL = 'login' - MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -151,6 +148,15 @@ MEDIA_ROOT = BASE_DIR / "media" DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +# Connexion sso +# LOGIN_URL = '/client/' +LOGIN_URL = 'simple-sso-login' + +SSO_PRIVATE_KEY = 'wV3nf1YXeZpepf8iJAdWcfJOS4BVXYlIKsKES2RheuJLu5ycgm0ZK3zgdw9ODjdo' # Designe la clé privée +SSO_PUBLIC_KEY = 'E8vV810D8HSmhUwl6abuZALhO5fmUdjjd3wAVCFZyyDX7SsSeAf9XwVyKZ5brilt' # Designe la clé publique +SSO_SERVER = 'http://localhost:8000/server/' +SSO_LOGOUT_URL = 'http://localhost:8000/deconnexion' + # Configuration de l'email EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' EMAIL_HOST = 'ssl0.ovh.net' @@ -159,4 +165,4 @@ EMAIL_USE_SSL = True EMAIL_USE_TLS = False EMAIL_HOST_USER = 'support.it@cerfig.org' EMAIL_HOST_PASSWORD = 'Cerfig2025' -DEFAULT_FROM_EMAIL = EMAIL_HOST_USER +DEFAULT_FROM_EMAIL = EMAIL_HOST_USER \ No newline at end of file diff --git a/SIRH/sso.py b/SIRH/sso.py new file mode 100644 index 0000000..52e4660 --- /dev/null +++ b/SIRH/sso.py @@ -0,0 +1,33 @@ +# SGL/sso.py +from gestion_employe.models import Employe, Departement +from simple_sso.sso_client.client import Client +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Group + +User = get_user_model() + +class SIRHClient(Client): + def build_user(self, user_data): + """Crée le User et son Profile avec les infos reçues du serveur.""" + user_data_copy = user_data.copy() + user_data.pop("departement") + user_data.pop("chef_departement") + user_data.pop("groups") + + user = super().build_user(user_data) + departement = Departement.objects.get_or_create( + nom=user_data_copy.get("departement", ""))[0] + + Employe.objects.update_or_create( + user = user, + defaults = { + "departement": departement, + "chef": user_data_copy.get("chef_departement", ""), + } + ) + + for group_name in user_data_copy.get("groups", []): + group, _ = Group.objects.get_or_create(name=group_name) + user.groups.add(group) + + return user \ No newline at end of file diff --git a/SIRH/templates/SIRH/BASE.html b/SIRH/templates/SIRH/BASE.html index 5a0f392..faa8f2f 100644 --- a/SIRH/templates/SIRH/BASE.html +++ b/SIRH/templates/SIRH/BASE.html @@ -15,8 +15,9 @@
+ {% include 'parts/menu_application.html' %} {% include 'parts/menu_principal.html' %} -
+
{% block 'contenu' %} {% endblock %}
diff --git a/SIRH/templates/SIRH/login.html b/SIRH/templates/SIRH/login.html index 801af39..d8dac08 100644 --- a/SIRH/templates/SIRH/login.html +++ b/SIRH/templates/SIRH/login.html @@ -24,15 +24,16 @@ {% endfor %} {% endif %} {% csrf_token %} +
- - + +
- - - + + +
diff --git a/SIRH/templates/SIRH/parts/menu_application.html b/SIRH/templates/SIRH/parts/menu_application.html new file mode 100644 index 0000000..e07de74 --- /dev/null +++ b/SIRH/templates/SIRH/parts/menu_application.html @@ -0,0 +1,8 @@ + \ No newline at end of file diff --git a/SIRH/templates/SIRH/parts/menu_principal.html b/SIRH/templates/SIRH/parts/menu_principal.html index 41bee0e..54e0a9d 100644 --- a/SIRH/templates/SIRH/parts/menu_principal.html +++ b/SIRH/templates/SIRH/parts/menu_principal.html @@ -13,35 +13,36 @@ {% endif %}
- {{ user.username }} + {{ user.first_name }} {{ user.last_name }}
- + Mon profil {% if user|has_group:"ressource_humaine" or user|has_group:"direction" %} - + Tableau de bord {% endif %} {% if user|has_group:"ressource_humaine" or user|has_group:"direction" %} - + Gestion des Projets {% endif %} - + Gestion des congés {% if user|is_chef_projet %} - + Suivi des Activités {% endif %} - + Réservation - + {% comment %} {% url 'deconnexion' %} {% endcomment %} + Déconnexion
\ No newline at end of file diff --git a/SIRH/urls.py b/SIRH/urls.py index ba5be4b..7123c35 100644 --- a/SIRH/urls.py +++ b/SIRH/urls.py @@ -16,17 +16,30 @@ Including another URLconf """ from django.contrib import admin from django.urls import include, path -from django.conf.urls.static import static +# from django.conf.urls.static import static from django.conf import settings -# from simple_sso.sso_server.server import Server -from . import views +from .sso import SIRHClient -# server_sso = Server() +client_sirh = SIRHClient( + settings.SSO_SERVER, + settings.SSO_PUBLIC_KEY, + settings.SSO_PRIVATE_KEY +) -urlpatterns = [ +urlpatterns = [ + # path('login/', + # views.login_view, + # name='login' + # ), + # path( + # 'deconnexion/', + # views.deconnexion_view, + # name='deconnexion' + # ), path( '', +<<<<<<< HEAD views.login_view, name='index' ), @@ -42,6 +55,8 @@ urlpatterns = [ ), path( 'gestion-employe/', +======= +>>>>>>> 4934b42 (Implementation de sso) include("gestion_employe.urls") ), path( @@ -59,9 +74,7 @@ urlpatterns = [ path( 'admin/', admin.site.urls - ), - # path( - # 'sso', - # include(server_sso.get_urls()) - # ) -] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + ), + path("client/", include(client_sirh.get_urls())), +] +# + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file diff --git a/SIRH/views.py b/SIRH/views.py index 77a057d..e69de29 100644 --- a/SIRH/views.py +++ b/SIRH/views.py @@ -1,37 +0,0 @@ -from django.contrib.auth import authenticate, login, logout -from django.shortcuts import render, redirect -from django.contrib import messages - -def login_view(request): - """ - Gère la connexion des utilisateurs avec redirection selon le rôle et - vérification de l'acceptation de la politique d'utilisation. - """ - if request.method == 'POST': - email = request.POST.get('mail') - password = request.POST.get('mot_de_passe') - - if not (email and password): - messages.error(request, "Veuillez remplir tous les champs.") - return render(request, 'login.html') - - user = authenticate(request, username=email, password=password) - - if user is None: - messages.error(request, "Nom d’utilisateur ou mot de passe incorrect.") - return render(request, 'login.html') - - if not user.is_active: - messages.error(request, "Compte inactif. Contactez l'administrateur.") - return render(request, 'login.html') - - login(request, user) - - return redirect("gestion_conges:conge") - - return render(request, 'login.html') - -def deconnexion_view(request): - """Gère la déconnexion de l'utilisateur.""" - logout(request) - return redirect('login') \ No newline at end of file diff --git a/fonction_utilitaire/fonctions_utilitaire.py b/fonction_utilitaire/fonctions_utilitaire.py index 78f9cd3..d3a3203 100644 --- a/fonction_utilitaire/fonctions_utilitaire.py +++ b/fonction_utilitaire/fonctions_utilitaire.py @@ -7,10 +7,14 @@ QUOTA_CONGE_ANNUEL = 30 NOMBRE_PAGINATION = 8 DEBUT_RAPPEL = 60 DUREE_FIN_CONTRAT = 90 +<<<<<<< HEAD try: EMAIL_ASSISTANTE_DE_DIRECTION = list(Employe.objects.filter(fonction="assistant_direction").values_list('user__email', flat=True)) except: pass +======= +# EMAIL_ASSISTANTE_DE_DIRECTION = list(Employe.objects.filter(fonction="assistant_direction").values_list('user__email', flat=True)) +>>>>>>> 4934b42 (Implementation de sso) def solde_conge(employe): """Fonction de calcul du solde de congé restant l'employé""" diff --git a/gestion_conge/migrations/0001_initial.py b/gestion_conge/migrations/0001_initial.py new file mode 100644 index 0000000..e498b12 --- /dev/null +++ b/gestion_conge/migrations/0001_initial.py @@ -0,0 +1,30 @@ +# Generated by Django 5.2.13 on 2026-06-16 11:06 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('gestion_employe', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Conge', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date_debut', models.DateField(verbose_name='Date de Début')), + ('date_fin', models.DateField(verbose_name='Date de Fin')), + ('type', models.CharField(choices=[('conge_annuel', 'Conge Annuel')], max_length=100, verbose_name='Type de Congé')), + ('date_demande', models.DateField(auto_now_add=True, verbose_name='Date de Demande')), + ('validation_hierarchique', models.BooleanField(default=None, null=True)), + ('validation_direction', models.BooleanField(default=None, null=True)), + ('motif_refus', models.TextField(blank=True, null=True)), + ('employe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='employe', to='gestion_employe.employe')), + ], + ), + ] diff --git a/gestion_conge/static/gestion_conge/js/index.js b/gestion_conge/static/gestion_conge/js/index.js index 1d156cf..5308791 100644 --- a/gestion_conge/static/gestion_conge/js/index.js +++ b/gestion_conge/static/gestion_conge/js/index.js @@ -3,7 +3,7 @@ const $ = (element) => document.getElementById(element); const url_liste_conge_attente = $("liste-demande-conges").dataset.url const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", { - layout : "fitColumns", + // layout : "fitColumns", columns: [ {"title": "Nom et Prénom", "field": "prenom_nom"}, {"title": "Date de début", "field": "date_debut", formatter:"datetime", formatterParams:{ @@ -15,7 +15,7 @@ const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", { outputFormat:"dd/MM/yy", }}, {"title": "Type de congé", "field": "type"}, - {"title": "Date de la demande", "field": "date_demande"}, + {"title": "Date de la demande", "field": "date_demande", responsive: 1}, {"title": "Validation par supérieur hiérarchique", "field": "validation_hierarchique", formatter:"tickCross", formatterParams :{ allowEmpty : true , }}, @@ -24,7 +24,7 @@ const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", { }}, ], pagination: true, - paginationSize: 5 + paginationSize: 5, }) const bouton_demande_conges = $("bouton-demande-conge"); diff --git a/gestion_conge/templates/gestion_conge/index.html b/gestion_conge/templates/gestion_conge/index.html index 17d1ff6..30a2595 100644 --- a/gestion_conge/templates/gestion_conge/index.html +++ b/gestion_conge/templates/gestion_conge/index.html @@ -7,6 +7,7 @@
{{message}}
{% endfor %} {% endif %} +
@@ -32,11 +33,17 @@
{{ nombre_conges_valide }}
-
+
+ +
+

Liste des demandes de congé

-
+
+ +
+
diff --git a/gestion_employe/migrations/0001_initial.py b/gestion_employe/migrations/0001_initial.py new file mode 100644 index 0000000..3c27a92 --- /dev/null +++ b/gestion_employe/migrations/0001_initial.py @@ -0,0 +1,88 @@ +# Generated by Django 5.2.13 on 2026-06-16 11:06 + +import django.db.models.deletion +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('gestion_projet', '0001_initial'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Departement', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nom', models.CharField(max_length=100)), + ], + ), + migrations.CreateModel( + name='Employe', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('matricule', models.CharField(blank=True, max_length=10, null=True, unique=True)), + ('fonction', models.CharField(blank=True, choices=[('directeur', 'Directeur'), ('assistant_direction', 'Assistante de direction'), ('assistant_technique_recherche', 'Assistant technique de recherche'), ('comptable', 'Comptable'), ('raf', 'RAF'), ('data_manager', 'Data Manager'), ('logisticien', 'Logisticien'), ('post_doctorant', 'Post-Doctorant'), ('qualiticien', 'Qualiticien'), ('technicien_surface', 'Technicien de surface'), ('chauffeur', 'Chauffeur')], max_length=50, null=True)), + ('date_embauche', models.DateField(blank=True, null=True)), + ('adresse', models.CharField(blank=True, max_length=100, null=True)), + ('telephone', models.CharField(blank=True, max_length=15, null=True)), + ('sexe', models.CharField(blank=True, choices=[('m', 'Masculin'), ('f', 'Féminin')], max_length=1, null=True)), + ('date_naissance', models.DateField(blank=True, null=True)), + ('CV', models.FileField(blank=True, null=True, upload_to='cv/')), + ('diplome', models.FileField(blank=True, null=True, upload_to='diplomes/')), + ('rib', models.FileField(blank=True, null=True, upload_to='rib/')), + ('photo', models.ImageField(blank=True, null=True, upload_to='photos/')), + ('casier_judiciaire', models.FileField(blank=True, null=True, upload_to='casier/')), + ('chef', models.BooleanField(default=False, verbose_name='Cet utilisateur est-il chef de ce département ?')), + ('departement', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='gestion_employe.departement')), + ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='Contrat', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('numero_contrat', models.CharField(max_length=100, unique=True)), + ('type_contrat', models.CharField(choices=[('contrat_duree_determinee', 'Contrat à Durée Déterminée'), ('contrat_duree_indeterminee', 'Contrat à Durée Indéterminée'), ('contrat_prestation', 'Contrat de Prestation de Service'), ('contrat_stage', 'Contrat de Stage'), ('convention_bourse_entretien', "Convention de bourse d'entretien")], max_length=50)), + ('date_debut', models.DateField()), + ('date_fin', models.DateField(blank=True, null=True)), + ('salaire_mensuel', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)), + ('statut', models.CharField(choices=[('actif', 'Actif'), ('termine', 'Terminé'), ('suspendu', 'Suspendu'), ('rupture_contrat', 'Rupture de Contrat')], max_length=50)), + ('fichier_contrat', models.FileField(blank=True, null=True, upload_to='contrats/')), + ('employe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_employe.employe')), + ], + ), + migrations.CreateModel( + name='Formation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('titre', models.CharField(max_length=255, verbose_name='Nom du certificat')), + ('organisme', models.CharField(max_length=255, verbose_name="Nom de l'organisme")), + ('description', models.TextField(blank=True, null=True, verbose_name='Description de la formation')), + ('date_obtention', models.DateField(blank=True, null=True, verbose_name="Date d'obtention")), + ('date_fin', models.DateField(blank=True, null=True, verbose_name='Date de fin de validité')), + ('certificat', models.FileField(blank=True, null=True, upload_to='documents/formations/', verbose_name='Certificat (PDF/Image)')), + ('employe', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='employe_formation', to='gestion_employe.employe')), + ], + ), + migrations.CreateModel( + name='Affectation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date_affectation', models.DateField()), + ('date_fin_daffectation', models.DateField(blank=True, null=True)), + ('role', models.CharField(choices=[('chef_projet', 'Chef de projet'), ('doctorant', 'Doctorant'), ('mastorant', 'Mastorant'), ('consultant', 'Consultant'), ('stagiaire', 'Stagiaire'), ('laborantin', 'Laborantin'), ('medecin', 'Médecin'), ('autre', 'Autre')], default='Membre', max_length=20)), + ('pourcentage_temps_affectation', models.DecimalField(decimal_places=2, max_digits=5)), + ('projet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.projet')), + ('employe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_employe.employe')), + ], + options={ + 'unique_together': {('projet', 'employe')}, + }, + ), + ] diff --git a/gestion_employe/static/gestion_employe/js/index.js b/gestion_employe/static/gestion_employe/js/index.js index 950142e..8ea144f 100644 --- a/gestion_employe/static/gestion_employe/js/index.js +++ b/gestion_employe/static/gestion_employe/js/index.js @@ -12,6 +12,7 @@ const tableau_liste_employe = new Tabulator("#tableau_liste_employe", { // ajaxURL: url_liste_employe, pagination: true, paginationSize: 10, + responsiveLayout : "hide" }) fetch(url_liste_employe) diff --git a/gestion_projet/migrations/0001_initial.py b/gestion_projet/migrations/0001_initial.py new file mode 100644 index 0000000..350818e --- /dev/null +++ b/gestion_projet/migrations/0001_initial.py @@ -0,0 +1,107 @@ +# Generated by Django 5.2.13 on 2026-06-16 11:06 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='ActiviteProjet', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('titre', models.CharField(max_length=200, verbose_name="Titre de l'activité")), + ('description', models.TextField(blank=True, null=True, verbose_name="Description de l'activité")), + ('date_debut', models.DateField(verbose_name='Date de début')), + ('date_fin', models.DateField(verbose_name='Date de fin')), + ('annuler', models.BooleanField(default=False, verbose_name="Annuler l'activité")), + ('motif_annulation', models.TextField(blank=True, null=True, verbose_name="Motif d'annulation")), + ('motif_changement_budget', models.TextField(blank=True, null=True, verbose_name='Motif de changement de budget')), + ('budget_prevu', models.DecimalField(decimal_places=2, default=0, max_digits=15, verbose_name='Budget prévu')), + ('budget_depense', models.DecimalField(decimal_places=2, default=0, max_digits=15, verbose_name='Budget dépensé')), + ('besoin_ressource_materielle', models.TextField(verbose_name='Besoin de ressources matérielles')), + ], + ), + migrations.CreateModel( + name='Bailleur', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nom_organisme', models.CharField(max_length=200, unique=True)), + ('contact', models.CharField(blank=True, max_length=100, null=True)), + ('email', models.EmailField(blank=True, max_length=254, null=True)), + ('pays', models.CharField(blank=True, max_length=100, null=True)), + ], + ), + migrations.CreateModel( + name='DomaineDeRecherche', + fields=[ + ('nom', models.CharField(choices=[('sciences_sociales', 'Sciences sociales'), ('naturelles', 'Naturelles'), ('humaines', 'Humaines'), ('veterinaires', 'Vétérinaires')], max_length=100, primary_key=True, serialize=False, verbose_name='Domaine de recherche')), + ], + options={ + 'verbose_name': 'Domaine de recherche', + 'verbose_name_plural': 'Domaines de recherche', + }, + ), + migrations.CreateModel( + name='LivrablesLivres', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('nom', models.CharField(max_length=255, verbose_name='Nom du livrable')), + ('fichier', models.FileField(blank=True, null=True, upload_to='fichier_livrables/')), + ('activite', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.activiteprojet')), + ], + ), + migrations.CreateModel( + name='Projet', + fields=[ + ('id_projet', models.CharField(blank=True, max_length=100, primary_key=True, serialize=False, unique=True, verbose_name='ID du projet')), + ('nom_projet', models.CharField(max_length=200, verbose_name='Nom du projet')), + ('date_debut', models.DateField(verbose_name='Date de début')), + ('date_fin', models.DateField(verbose_name='Date de fin')), + ('numero_convention', models.CharField(max_length=100, verbose_name='Numéro de convention')), + ('description', models.TextField(verbose_name='Description')), + ('type_projet', models.CharField(choices=[('laboratoire', 'Laboratoire'), ('épidémiologie', 'Épidémiologie'), ('sciences sociales', 'Sciences sociales'), ('cliniques', 'Cliniques'), ('autre', 'Autre')], default='épidémiologie', max_length=100, verbose_name='Type de projet')), + ('budget', models.DecimalField(decimal_places=2, max_digits=12, verbose_name='Budget')), + ('budget_RH', models.DecimalField(decimal_places=2, max_digits=12, verbose_name='Budget RH')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('bailleur', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='gestion_projet.bailleur', verbose_name='Bailleur de fonds')), + ('domaine_recherche', models.ManyToManyField(to='gestion_projet.domainederecherche')), + ], + ), + migrations.CreateModel( + name='DocumentProjet', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date_ajout', models.DateTimeField(auto_now_add=True, verbose_name="Date d'ajout")), + ('nom_document', models.CharField(choices=[('protocole', 'Protocole d’étude'), ('ethique', "Approbation du comité d'éthique"), ('autorisation', 'Autorisation (DNLP)'), ('rapport_technique', 'Rapport technique'), ('rapport_financier', 'Rapport financier'), ('rapport_avancement', "Rapport d'avancement"), ('convention', 'Convention'), ('rapport_final', 'Rapport final'), ('autre', 'Autre')], max_length=100, verbose_name='Type de document')), + ('description', models.TextField(blank=True, verbose_name='Description')), + ('numero', models.CharField(blank=True, max_length=100, null=True, verbose_name='Numéro du document')), + ('date_validite', models.DateField(blank=True, null=True, verbose_name='Date de validité')), + ('fichier', models.FileField(upload_to='documents_projets/', verbose_name='Fichier à télécharger')), + ('projet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='documents', to='gestion_projet.projet', verbose_name='Projet')), + ], + ), + migrations.AddField( + model_name='activiteprojet', + name='projet', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.projet', verbose_name='Projet'), + ), + migrations.CreateModel( + name='FinancementProjet', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('pourcentage', models.DecimalField(decimal_places=2, max_digits=5)), + ('bailleur', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.bailleur')), + ('projet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.projet')), + ], + options={ + 'unique_together': {('projet', 'bailleur')}, + }, + ), + ] diff --git a/gestion_salle/migrations/0001_initial.py b/gestion_salle/migrations/0001_initial.py new file mode 100644 index 0000000..ceff4f8 --- /dev/null +++ b/gestion_salle/migrations/0001_initial.py @@ -0,0 +1,34 @@ +# Generated by Django 5.2.13 on 2026-06-16 11:06 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('gestion_employe', '0001_initial'), + ] + + operations = [ + migrations.CreateModel( + name='Reservation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('salle', models.CharField(choices=[('formation', 'Salle de formation'), ('reunion', 'Salle de réunion'), ('lien_zoom', 'Lien Zoom')], max_length=100)), + ('date_demande', models.DateTimeField(auto_now_add=True)), + ('date_debut', models.DateField()), + ('date_fin', models.DateField(blank=True, null=True)), + ('heure_debut', models.TimeField()), + ('heure_fin', models.TimeField()), + ('besoin_zoom', models.BooleanField(default=False, verbose_name="Besoin d'un lien Zoom ?")), + ('besoin_ordi', models.BooleanField(default=False, verbose_name="Besoin d'un ordinateur ?")), + ('lien_zoom', models.URLField(blank=True, null=True, verbose_name='Lien Zoom')), + ('motif_reservation', models.TextField()), + ('statut', models.CharField(choices=[('en_attente', 'En attente'), ('validee', 'Validée'), ('refusee', 'Refusée'), ('annulee', 'Annulée')], default='en_attente', max_length=25)), + ('employe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_employe.employe')), + ], + ), + ] diff --git a/requirements.txt b/requirements.txt index a0fb268..b4b76bc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,6 +10,7 @@ numpy==2.2.6 pandas==2.3.3 pillow==12.2.0 python-dateutil==2.9.0.post0 +python-decouple==3.8 pytz==2026.1.post1 requests==2.33.1 six==1.17.0 @@ -17,5 +18,5 @@ sqlparse==0.5.5 typing_extensions==4.15.0 tzdata==2026.2 urllib3==2.6.3 -python-decouple -gunicorn +webservices==0.7 +webservices.naudit==0.7.2