Compare commits
8 Commits
9d9e6c6549
...
messege_et
| Author | SHA1 | Date | |
|---|---|---|---|
| c1dc44d223 | |||
| cea67c7057 | |||
| 741519c341 | |||
| 48f069506a | |||
| 3693ef29f9 | |||
| c28b14fb98 | |||
| 29a93e9bfe | |||
| a97c233ddb |
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,7 +1,10 @@
|
|||||||
|
# db.sqlite3
|
||||||
|
# venv/*
|
||||||
|
# media/*
|
||||||
|
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
db.sqlite3
|
db.sqlite3
|
||||||
venv/
|
venv/
|
||||||
media/
|
|
||||||
staticfiles/
|
|
||||||
.env
|
.env
|
||||||
migrations/
|
|
||||||
*.pyc
|
|
||||||
50
Jenkinsfile
vendored
50
Jenkinsfile
vendored
@@ -1,50 +0,0 @@
|
|||||||
pipeline
|
|
||||||
{
|
|
||||||
agent any
|
|
||||||
options {
|
|
||||||
// This is required if you want to clean before build
|
|
||||||
skipDefaultCheckout(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
environment
|
|
||||||
{
|
|
||||||
SUDO_PASSWORD = credentials('sudo-password')
|
|
||||||
}
|
|
||||||
|
|
||||||
stages
|
|
||||||
{
|
|
||||||
stage ( 'checkout' )
|
|
||||||
{
|
|
||||||
steps
|
|
||||||
{
|
|
||||||
sh 'echo "Debut du pipeline"'
|
|
||||||
cleanWs()
|
|
||||||
checkout scm
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stage ( 'Deploiement' )
|
|
||||||
{
|
|
||||||
when { branch 'main' }
|
|
||||||
steps {
|
|
||||||
sh '''
|
|
||||||
cd /var/www/sirh
|
|
||||||
echo $SUDO_PASSWORD | sudo -S chown -R jenkins:jenkins /var/www/sirh
|
|
||||||
|
|
||||||
git fetch origin main
|
|
||||||
git reset --hard origin/main
|
|
||||||
|
|
||||||
python3 -m venv venv
|
|
||||||
. venv/bin/activate
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
python manage.py makemigrations
|
|
||||||
python manage.py migrate
|
|
||||||
|
|
||||||
echo $SUDO_PASSWORD | sudo -S chown -R www-data:www-data /var/www/sirh
|
|
||||||
echo "Deploiement reussi"
|
|
||||||
echo $SUDO_PASSWORD | sudo -S supervisorctl restart sirh
|
|
||||||
'''
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -12,21 +12,21 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from decouple import config
|
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
# Quick-start development settings - unsuitable for production
|
||||||
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
# SECURITY WARNING: keep the secret key used in production secret!
|
||||||
SECRET_KEY = config('SECRET_KEY')
|
SECRET_KEY = 'django-insecure--wdb9t(77rvyac$_q!n5gw86&0r(0&&j171v9h!-_$jahsza*5'
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
# SECURITY WARNING: don't run with debug turned on in production!
|
||||||
DEBUG = config('DEBUG', default=False, cast=bool)
|
DEBUG = False
|
||||||
|
|
||||||
ALLOWED_HOSTS = config('ALLOWED_HOSTS', default=[]).split(',')
|
ALLOWED_HOSTS = ["https://support.cerfig.org", "support.cerfig.org"]
|
||||||
|
|
||||||
# Application definition
|
# Application definition
|
||||||
|
|
||||||
@@ -79,25 +79,24 @@ WSGI_APPLICATION = 'SIRH.wsgi.application'
|
|||||||
# Database
|
# Database
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
||||||
|
|
||||||
|
# DATABASES = {
|
||||||
|
# 'default': {
|
||||||
|
# 'ENGINE': 'django.db.backends.mysql',
|
||||||
|
# 'NAME': 'sirh',
|
||||||
|
# 'USER': 'sirh',
|
||||||
|
# 'PASSWORD': 'sirh-cerfig',
|
||||||
|
# 'HOST': 'localhost',
|
||||||
|
# 'PORT': '3306',
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
if config('ENVIRONMENT') == 'local':
|
DATABASES = {
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
'default': {
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else:
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.mysql',
|
|
||||||
'NAME': config('DATABASE_NAME'),
|
|
||||||
'USER': config('DATABASE_USER'),
|
|
||||||
'PASSWORD': config('DATABASE_PASSWORD'),
|
|
||||||
'HOST': config('DATABASE_HOST'),
|
|
||||||
'PORT': config('DATABASE_PORT'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Password validation
|
# Password validation
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
||||||
@@ -150,7 +149,6 @@ MEDIA_ROOT = BASE_DIR / "media"
|
|||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
||||||
|
|
||||||
# Configuration de l'email
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
EMAIL_HOST = 'ssl0.ovh.net'
|
EMAIL_HOST = 'ssl0.ovh.net'
|
||||||
EMAIL_PORT = 465
|
EMAIL_PORT = 465
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
{% if user.employe.photo %}
|
{% if user.employe.photo %}
|
||||||
<img src="{{ user.employe.photo.url }}"
|
<img src="{{ user.employe.photo.url }}"
|
||||||
class="rounded-circle"
|
class="rounded-circle"
|
||||||
width="100"
|
width="80"
|
||||||
height="100"
|
height="80"
|
||||||
style="object-fit:cover;">
|
style="object-fit:cover;">
|
||||||
{% else %}
|
{% else %}
|
||||||
<i class="bi bi-person-circle text-white" style="font-size:60px;"></i>
|
<i class="bi bi-person-circle text-white" style="font-size:60px;"></i>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="text-white mt-2 fw-bold fs-5">
|
<div class="text-white mt-2">
|
||||||
{{ user.username }}
|
{{ user.username }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -41,6 +41,15 @@
|
|||||||
<a href="{% url 'gestion_salle:reservation-salle' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
<a href="{% url 'gestion_salle:reservation-salle' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
||||||
<i class="bi bi-calendar-check"></i> Réservation
|
<i class="bi bi-calendar-check"></i> Réservation
|
||||||
</a>
|
</a>
|
||||||
|
{% comment %} <a href="{% url 'rapport-rh' %}" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
||||||
|
<i class="bi bi-graph-up"></i> Rapports et Statistiques
|
||||||
|
</a> {% endcomment %}
|
||||||
|
{% comment %} <a href="" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
||||||
|
<i class="bi bi-person-gear"></i> Gestion des Utilisateurs
|
||||||
|
</a> {% endcomment %}
|
||||||
|
{% comment %} <a href="{% url 'gestion_employe:departement' %}" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
||||||
|
<i class="bi bi-gear"></i> Paramètres
|
||||||
|
</a> {% endcomment %}
|
||||||
<a href="{% url 'deconnexion' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
<a href="{% url 'deconnexion' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
||||||
<i class="bi bi-box-arrow-right"></i> Déconnexion
|
<i class="bi bi-box-arrow-right"></i> Déconnexion
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from gestion_employe.models import Contrat, Employe
|
from gestion_employe.models import Contrat
|
||||||
from gestion_conge.models import Conge
|
from gestion_conge.models import Conge
|
||||||
|
|
||||||
|
|
||||||
@@ -7,7 +7,6 @@ QUOTA_CONGE_ANNUEL = 30
|
|||||||
NOMBRE_PAGINATION = 8
|
NOMBRE_PAGINATION = 8
|
||||||
DEBUT_RAPPEL = 60
|
DEBUT_RAPPEL = 60
|
||||||
DUREE_FIN_CONTRAT = 90
|
DUREE_FIN_CONTRAT = 90
|
||||||
EMAIL_ASSISTANTE_DE_DIRECTION = list(Employe.objects.filter(fonction="assistant_direction").values_list('user__email', flat=True))
|
|
||||||
|
|
||||||
def solde_conge(employe):
|
def solde_conge(employe):
|
||||||
"""Fonction de calcul du solde de congé restant l'employé"""
|
"""Fonction de calcul du solde de congé restant l'employé"""
|
||||||
@@ -33,25 +32,3 @@ def solde_conge(employe):
|
|||||||
"quota_annuel": QUOTA_CONGE_ANNUEL - jours_conges_valider,
|
"quota_annuel": QUOTA_CONGE_ANNUEL - jours_conges_valider,
|
||||||
"nombre_jours_valide": jours_conges_valider
|
"nombre_jours_valide": jours_conges_valider
|
||||||
}
|
}
|
||||||
|
|
||||||
def envoyer_mail(sujet, message, destinataires):
|
|
||||||
"""Fonction d'envoi de mail"""
|
|
||||||
from django.core.mail import send_mail
|
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
send_mail(
|
|
||||||
sujet,
|
|
||||||
message,
|
|
||||||
settings.EMAIL_HOST_USER,
|
|
||||||
destinataires,
|
|
||||||
fail_silently=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
def destinataire_mail_demande_conges(employe):
|
|
||||||
"""Fonction de récupération des destinataires pour les mails de demande de congés"""
|
|
||||||
if employe.chef:
|
|
||||||
return EMAIL_ASSISTANTE_DE_DIRECTION
|
|
||||||
else:
|
|
||||||
if employe.departement:
|
|
||||||
chefs_departement = Employe.objects.filter(departement=employe.departement, chef=True)
|
|
||||||
return list(chefs_departement.values_list('user__email', flat=True))
|
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -83,6 +83,7 @@ def index(request):
|
|||||||
Q(validation_hierarchique = True) | Q(validation_hierarchique = False)
|
Q(validation_hierarchique = True) | Q(validation_hierarchique = False)
|
||||||
).order_by('-date_demande')
|
).order_by('-date_demande')
|
||||||
|
|
||||||
|
|
||||||
return render(request, 'gestion_conge/index.html', {
|
return render(request, 'gestion_conge/index.html', {
|
||||||
"nombre_conges_valide": nombre_conges_valide,
|
"nombre_conges_valide": nombre_conges_valide,
|
||||||
"nombre_conges_refuse": nombre_conges_refuse,
|
"nombre_conges_refuse": nombre_conges_refuse,
|
||||||
@@ -122,13 +123,6 @@ def demander_conge(request):
|
|||||||
|
|
||||||
conge_obj.save()
|
conge_obj.save()
|
||||||
messages.success(request, "Votre demande de congé a été enregistrée.")
|
messages.success(request, "Votre demande de congé a été enregistrée.")
|
||||||
|
|
||||||
fonctions_utilitaire.envoyer_mail(
|
|
||||||
sujet = "Demande de congé",
|
|
||||||
message = f"""Bonjour {employe.user.first_name} {employe.user.last_name}, votre demande de congé a été enregistrée. Veuillez consulter votre profil pour plus de détails.""",
|
|
||||||
destinataires = fonctions_utilitaire.destinataire_mail_demande_conges() + [employe.user.email]
|
|
||||||
)
|
|
||||||
|
|
||||||
return redirect("gestion_conges:conge")
|
return redirect("gestion_conges:conge")
|
||||||
|
|
||||||
return redirect("gestion_conges:conge")
|
return redirect("gestion_conges:conge")
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -15,7 +15,6 @@ class Employe(models.Model):
|
|||||||
FONCTION_LISTE = [
|
FONCTION_LISTE = [
|
||||||
('directeur', 'Directeur'),
|
('directeur', 'Directeur'),
|
||||||
('assistant_direction', 'Assistante de direction'),
|
('assistant_direction', 'Assistante de direction'),
|
||||||
('assistant_technique_recherche', 'Assistant technique de recherche'),
|
|
||||||
('comptable', 'Comptable'),
|
('comptable', 'Comptable'),
|
||||||
('raf', 'RAF'),
|
('raf', 'RAF'),
|
||||||
('data_manager', 'Data Manager'),
|
('data_manager', 'Data Manager'),
|
||||||
|
|||||||
@@ -19,12 +19,13 @@
|
|||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if not expiration_contrat %}
|
{% if not has_contrat %}
|
||||||
<div class="alert alert-danger fade show alert-dismissible mt-2">
|
<div class="alert alert-danger mt-2">
|
||||||
<strong>Important :</strong> Les informations sur votre contrat n'ont pas été renseignées, veuillez contacter les ressources humaines.
|
<strong>Important :</strong> Les informations sur votre contrat n'ont pas été renseignées, veuillez contacter les ressources humaines.
|
||||||
</div>
|
</div>
|
||||||
{% elif contrat_nb_jours_restant %}
|
|
||||||
<div class="alert alert-danger fade show alert-dismissible mt-2">
|
{% elif expiration_contrat %}
|
||||||
|
<div class="alert alert-warning mt-2">
|
||||||
<strong>Important :</strong> Votre contrat de travail expire dans {{ contrat_nb_jours_restant }} jours, veuillez contacter les ressources humaines.
|
<strong>Important :</strong> Votre contrat de travail expire dans {{ contrat_nb_jours_restant }} jours, veuillez contacter les ressources humaines.
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -42,7 +43,7 @@
|
|||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="form-group mb-2">
|
<div class="form-group mb-2">
|
||||||
<label>Photo</label>
|
<label>photo</label>
|
||||||
{% if employe.photo %}
|
{% if employe.photo %}
|
||||||
<span>Fichier actuel : <a href="{{ employe.photo.url }}">{{employe.photo}}</a></span>
|
<span>Fichier actuel : <a href="{{ employe.photo.url }}">{{employe.photo}}</a></span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Binary file not shown.
@@ -79,6 +79,21 @@ urlpatterns = [
|
|||||||
views.modifier_mot_passe,
|
views.modifier_mot_passe,
|
||||||
name='modifier-mot-passe'
|
name='modifier-mot-passe'
|
||||||
),
|
),
|
||||||
|
# path(
|
||||||
|
# 'creation-departement/',
|
||||||
|
# views.creation_departement,
|
||||||
|
# name='creation-departement'
|
||||||
|
# ),
|
||||||
|
# path(
|
||||||
|
# 'modifier-departement/',
|
||||||
|
# views.modifier_departement,
|
||||||
|
# name='modifier-departement'
|
||||||
|
# ),
|
||||||
|
# path(
|
||||||
|
# 'suppression-departement/',
|
||||||
|
# views.supprimer_departement,
|
||||||
|
# name='suppression-departement/'
|
||||||
|
# ),
|
||||||
path(
|
path(
|
||||||
"liste-contrat-expirants",
|
"liste-contrat-expirants",
|
||||||
views.liste_contrat_expirants,
|
views.liste_contrat_expirants,
|
||||||
|
|||||||
@@ -109,13 +109,6 @@ def affecter_employe_projet(request):
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
messages.success(request, f"L'employé {employe.user.first_name} {employe.user.last_name} a été affecté au projet {projet.nom_projet}.")
|
messages.success(request, f"L'employé {employe.user.first_name} {employe.user.last_name} a été affecté au projet {projet.nom_projet}.")
|
||||||
|
|
||||||
fonctions_utilitaire.envoyer_mail(
|
|
||||||
sujet = "Affectation à un projet",
|
|
||||||
message = f"""Bonjour {employe.user.first_name} {employe.user.last_name}, vous avez été affecté au projet {projet.nom_projet.upper()} pour la période du {form.cleaned_data['date_affectation'].strftime('%d/%m/%Y')} au {date_fin_affectation.strftime('%d/%m/%Y')} en tant que {dict(Affectation.ROLE_CHOICES).get(form.cleaned_data['role'])}.
|
|
||||||
Veuillez consulter votre profil pour plus de détails.""",
|
|
||||||
destinataires = [employe.user.email]
|
|
||||||
)
|
|
||||||
return redirect('gestion_employe:index')
|
return redirect('gestion_employe:index')
|
||||||
else:
|
else:
|
||||||
messages.error(request, "Erreur : Formulaire non valide.")
|
messages.error(request, "Erreur : Formulaire non valide.")
|
||||||
@@ -129,26 +122,41 @@ def mon_profil(request):
|
|||||||
try:
|
try:
|
||||||
employe = Employe.objects.get(user__username=request.user)
|
employe = Employe.objects.get(user__username=request.user)
|
||||||
except Employe.DoesNotExist:
|
except Employe.DoesNotExist:
|
||||||
messages.error(request, "Impossible d'acceder au menu 'Mon profil' car votre profil Utilisateur n'est lié à aucun profil Employé. Veuillez contacter l'Administrateur.")
|
messages.error(
|
||||||
|
request,
|
||||||
|
"Impossible d'acceder au menu 'Mon profil' car votre profil Utilisateur n'est lié à aucun profil Employé. Veuillez contacter l'Administrateur."
|
||||||
|
)
|
||||||
return redirect("gestion_conges:conge")
|
return redirect("gestion_conges:conge")
|
||||||
|
|
||||||
contrats = Contrat.objects.filter(employe=employe, statut='actif').first()
|
contrats = Contrat.objects.filter(employe=employe, statut='actif').first()
|
||||||
|
|
||||||
projets = Affectation.objects.filter(
|
projets = Affectation.objects.filter(
|
||||||
employe = employe,
|
employe=employe,
|
||||||
date_fin_daffectation__gte = timezone.now().date()
|
date_fin_daffectation__gte=timezone.now().date()
|
||||||
).select_related('projet')
|
).select_related('projet')
|
||||||
|
|
||||||
|
has_contrat = contrats is not None
|
||||||
|
expiration_contrat = False
|
||||||
|
contrat_nb_jours_restant = None
|
||||||
|
|
||||||
|
if contrats:
|
||||||
|
nb_jours = contrats.nombre_jours_restant
|
||||||
|
contrat_nb_jours_restant = nb_jours
|
||||||
|
expiration_contrat = nb_jours <= fonctions_utilitaire.DUREE_FIN_CONTRAT
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
'gestion_employe/monprofil.html',
|
'gestion_employe/monprofil.html',
|
||||||
{
|
{
|
||||||
'employe': employe,
|
'employe': employe,
|
||||||
|
|
||||||
'contrats': [{
|
'contrats': [{
|
||||||
**model_to_dict(contrats),
|
**model_to_dict(contrats),
|
||||||
"type_contrat": dict(Contrat.TYPE_CONTRAT).get(contrats.type_contrat),
|
"type_contrat": dict(Contrat.TYPE_CONTRAT).get(contrats.type_contrat),
|
||||||
"statut": dict(Contrat.STATUT_CONTRAT).get(contrats.statut),
|
"statut": dict(Contrat.STATUT_CONTRAT).get(contrats.statut),
|
||||||
"fichier_contrat": contrats.fichier_contrat.url if contrats.fichier_contrat else "",
|
"fichier_contrat": contrats.fichier_contrat.url if contrats.fichier_contrat else "",
|
||||||
} if contrats else []],
|
}] if contrats else [],
|
||||||
|
|
||||||
'projets': [
|
'projets': [
|
||||||
{
|
{
|
||||||
**model_to_dict(a.projet),
|
**model_to_dict(a.projet),
|
||||||
@@ -158,12 +166,13 @@ def mon_profil(request):
|
|||||||
"pourcentage_temps_affectation": a.pourcentage_temps_affectation
|
"pourcentage_temps_affectation": a.pourcentage_temps_affectation
|
||||||
} for a in projets
|
} for a in projets
|
||||||
],
|
],
|
||||||
|
|
||||||
"formation_form": FormationForm(),
|
"formation_form": FormationForm(),
|
||||||
"expiration_contrat": contrats.nombre_jours_restant <= fonctions_utilitaire.DUREE_FIN_CONTRAT if contrats else False,
|
"has_contrat": has_contrat,
|
||||||
"contrat_nb_jours_restant": contrats.nombre_jours_restant if contrats else None
|
"expiration_contrat": expiration_contrat,
|
||||||
|
"contrat_nb_jours_restant": contrat_nb_jours_restant
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def modifier_mot_passe(request):
|
def modifier_mot_passe(request):
|
||||||
"""Vue pour permettre à un utilisateur de modifier son mot de passe et ses informations de profil"""
|
"""Vue pour permettre à un utilisateur de modifier son mot de passe et ses informations de profil"""
|
||||||
@@ -183,7 +192,6 @@ def modifier_mot_passe(request):
|
|||||||
messages.success(request, "Mot de passe modifié avec succès.")
|
messages.success(request, "Mot de passe modifié avec succès.")
|
||||||
|
|
||||||
return redirect("gestion_employe:mon-profil")
|
return redirect("gestion_employe:mon-profil")
|
||||||
|
|
||||||
def modifier_employer(request):
|
def modifier_employer(request):
|
||||||
"""Vue pour permettre à un utilisateur de modifier les informations d'un employé"""
|
"""Vue pour permettre à un utilisateur de modifier les informations d'un employé"""
|
||||||
try:
|
try:
|
||||||
@@ -212,19 +220,13 @@ def modifier_employer(request):
|
|||||||
return JsonResponse({"message": "Profil mis à jour avec succès."})
|
return JsonResponse({"message": "Profil mis à jour avec succès."})
|
||||||
|
|
||||||
def enregistrement_document(request):
|
def enregistrement_document(request):
|
||||||
"""Vue pour permettre à un utilisateur de télécharger et enregistrer des documents liés à son profil"""
|
|
||||||
employe = Employe.objects.get(user=request.user)
|
employe = Employe.objects.get(user=request.user)
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
if request.FILES.get("photo"):
|
if request.FILES.get("photo"):employe.photo = request.FILES["photo"]
|
||||||
employe.photo = request.FILES["photo"]
|
if "cv" in request.FILES:employe.CV = request.FILES["cv"]
|
||||||
if "cv" in request.FILES:
|
if "diplome" in request.FILES: employe.diplome = request.FILES["diplome"]
|
||||||
employe.CV = request.FILES["cv"]
|
if "rib" in request.FILES: employe.rib = request.FILES["rib"]
|
||||||
if "diplome" in request.FILES:
|
if "casier_judiciaire" in request.FILES:employe.casier_judiciaire = request.FILES["casier_judiciaire"]
|
||||||
employe.diplome = request.FILES["diplome"]
|
|
||||||
if "rib" in request.FILES:
|
|
||||||
employe.rib = request.FILES["rib"]
|
|
||||||
if "casier_judiciaire" in request.FILES:
|
|
||||||
employe.casier_judiciaire = request.FILES["casier_judiciaire"]
|
|
||||||
employe.save()
|
employe.save()
|
||||||
messages.success(request, "Documents enregistrés avec succès.")
|
messages.success(request, "Documents enregistrés avec succès.")
|
||||||
|
|
||||||
@@ -436,3 +438,41 @@ def supprimer_formation(request, id_formation):
|
|||||||
formation.delete()
|
formation.delete()
|
||||||
messages.success(request, "Formation supprimée ")
|
messages.success(request, "Formation supprimée ")
|
||||||
return redirect("mes_formations")
|
return redirect("mes_formations")
|
||||||
|
|
||||||
|
# @login_required
|
||||||
|
# def creation_departement(request):
|
||||||
|
# """Gère la création d'un nouveau département via un formulaire."""
|
||||||
|
# if request.method == 'POST':
|
||||||
|
# form_departement = DepartementForm(request.POST)
|
||||||
|
# if form_departement.is_valid():
|
||||||
|
# form_departement.save()
|
||||||
|
# messages.success(request, "Département ajouté avec succès.")
|
||||||
|
# else:
|
||||||
|
# messages.error(request, "Erreur lors de l'ajout du département.")
|
||||||
|
# return redirect('parametres-rh')
|
||||||
|
|
||||||
|
# @login_required
|
||||||
|
# def modifier_departement(request, id):
|
||||||
|
# """Gère la modification d'un département existant via un formulaire pré-rempli."""
|
||||||
|
# departement = Departement.objects.get(id=id)
|
||||||
|
# form = DepartementForm(instance=departement)
|
||||||
|
# if request.method == 'POST':
|
||||||
|
# nouveau_nom_departement = request.POST.get('nom')
|
||||||
|
# if nouveau_nom_departement:
|
||||||
|
# departement.nom = nouveau_nom_departement
|
||||||
|
# departement.save()
|
||||||
|
# messages.success(request, "Département modifié avec succès.")
|
||||||
|
# return redirect('parametres-rh')
|
||||||
|
# return render(request, 'gestion_employe/edit_departement.html', {
|
||||||
|
# 'form': form,
|
||||||
|
# 'departement': departement
|
||||||
|
# })
|
||||||
|
|
||||||
|
# @login_required
|
||||||
|
# def supprimer_departement(request, id):
|
||||||
|
# """Gère la suppression d'un département existant."""
|
||||||
|
# if request.method == "POST":
|
||||||
|
# departement = Departement.objects.get(id=id)
|
||||||
|
# departement.delete()
|
||||||
|
# messages.success(request, "Département supprimé avec succès !")
|
||||||
|
# return redirect('parametres-rh')
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -30,4 +30,4 @@ class Reservation(models.Model):
|
|||||||
statut = models.CharField(choices=STATUT, default='en_attente', max_length=25)
|
statut = models.CharField(choices=STATUT, default='en_attente', max_length=25)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.salle} - {self.employe.user.first_name} {self.employe.user.last_name}"
|
return f"{self.salle} - {self.employe.user.first_name} {self.employe.user.last_name} le {self.date_reservation}"
|
||||||
@@ -15,6 +15,7 @@ const calendrier = Schedule(document.getElementById('planning-reservation'), {
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
currentReservationId = data.id_reservation;
|
currentReservationId = data.id_reservation;
|
||||||
|
console.log(data);
|
||||||
$("id_reservation_detail").value = data.id_reservation;
|
$("id_reservation_detail").value = data.id_reservation;
|
||||||
$("id_reservation_refus").value = data.id_reservation;
|
$("id_reservation_refus").value = data.id_reservation;
|
||||||
$("id_reservation_zoom").value = data.id_reservation;
|
$("id_reservation_zoom").value = data.id_reservation;
|
||||||
@@ -29,10 +30,6 @@ const calendrier = Schedule(document.getElementById('planning-reservation'), {
|
|||||||
$("besoin_ordinateur").checked=data.besoin_ordinateur;
|
$("besoin_ordinateur").checked=data.besoin_ordinateur;
|
||||||
$("lien_zoom").value=data.lien_zoom;
|
$("lien_zoom").value=data.lien_zoom;
|
||||||
|
|
||||||
if (data.besoin_zoom === false){
|
|
||||||
$("lien_zoom_container").className = "d-none";
|
|
||||||
}
|
|
||||||
|
|
||||||
if(data.statut !== "annulee"){
|
if(data.statut !== "annulee"){
|
||||||
$("motif_refus_container").className = "d-none";
|
$("motif_refus_container").className = "d-none";
|
||||||
}else{
|
}else{
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
|
import json
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
from django.http import JsonResponse, HttpRequest
|
from django.http import JsonResponse, HttpRequest
|
||||||
from django.forms import model_to_dict
|
from django.forms import model_to_dict
|
||||||
from fonction_utilitaire import fonctions_utilitaire
|
|
||||||
from gestion_employe.models import Employe
|
from gestion_employe.models import Employe
|
||||||
from gestion_salle.forms import ReservationForm
|
from gestion_salle.forms import ReservationForm
|
||||||
from .models import Reservation
|
from .models import Reservation
|
||||||
|
from datetime import timedelta
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -25,6 +27,7 @@ def index(request: HttpRequest):
|
|||||||
form = ReservationForm(request.POST)
|
form = ReservationForm(request.POST)
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
|
|
||||||
date_debut = form.cleaned_data['date_debut']
|
date_debut = form.cleaned_data['date_debut']
|
||||||
date_fin = form.cleaned_data['date_fin']
|
date_fin = form.cleaned_data['date_fin']
|
||||||
salle = form.cleaned_data['salle']
|
salle = form.cleaned_data['salle']
|
||||||
@@ -71,14 +74,6 @@ def index(request: HttpRequest):
|
|||||||
current_date += timedelta(days=1)
|
current_date += timedelta(days=1)
|
||||||
|
|
||||||
messages.success(request, "Réservation(s) créée(s) avec succès.")
|
messages.success(request, "Réservation(s) créée(s) avec succès.")
|
||||||
if fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION:
|
|
||||||
fonctions_utilitaire.envoyer_mail(
|
|
||||||
sujet = "Reservation de salle",
|
|
||||||
message = f"""
|
|
||||||
Une nouvelle demande de réservation de la {dict(Reservation.TYPE_CHOICES).get(salle)} a été effectuée par {employe.user.first_name} {employe.user.last_name} du {form.cleaned_data.get('date_debut').strftime('%d/%m/%Y')} au {form.cleaned_data.get('date_fin').strftime('%d/%m/%Y')} pour motif "{motif}".
|
|
||||||
Veuillez vous connecter à la plateforme pour plus de détails.""",
|
|
||||||
destinataires = list(fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION)
|
|
||||||
)
|
|
||||||
return redirect('gestion_salle:reservation-salle')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
formulaire_reservation = ReservationForm()
|
formulaire_reservation = ReservationForm()
|
||||||
@@ -146,8 +141,9 @@ def detail_reservation(request:HttpRequest, reservation_id:int):
|
|||||||
'id_reservation': reservation_id,
|
'id_reservation': reservation_id,
|
||||||
'employe': f"{employe.first_name} {employe.last_name}",
|
'employe': f"{employe.first_name} {employe.last_name}",
|
||||||
'salle': reservation.salle,
|
'salle': reservation.salle,
|
||||||
'statut': dict(Reservation.STATUT).get(reservation.statut),
|
'statut': reservation.statut,
|
||||||
'date_evenement': reservation.date_debut.strftime('%Y-%m-%d'),
|
'date_debut': reservation.date_debut.strftime('%Y-%m-%d'),
|
||||||
|
'date_fin': reservation.date_fin.strftime('%Y-%m-%d'),
|
||||||
'heure_debut': reservation.heure_debut.strftime('%H:%M'),
|
'heure_debut': reservation.heure_debut.strftime('%H:%M'),
|
||||||
'heure_fin': reservation.heure_fin.strftime('%H:%M'),
|
'heure_fin': reservation.heure_fin.strftime('%H:%M'),
|
||||||
'motif_reservation': reservation.motif_reservation,
|
'motif_reservation': reservation.motif_reservation,
|
||||||
@@ -213,14 +209,7 @@ def valider_reservation(request: HttpRequest):
|
|||||||
|
|
||||||
reservation.statut = 'validee'
|
reservation.statut = 'validee'
|
||||||
reservation.save()
|
reservation.save()
|
||||||
if fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION:
|
|
||||||
fonctions_utilitaire.envoyer_mail(
|
|
||||||
sujet = "Reservation de salle",
|
|
||||||
message = f"""Bonjour {request.user.first_name} {request.user.last_name}, votre reservation de la salle {dict(Reservation.TYPE_CHOICES).get(reservation.salle)} du {reservation.date_debut.strftime('%d/%m/%Y')} au {reservation.date_fin.strftime('%d/%m/%Y')} pour motif "{reservation.motif_reservation}" a été validée. Veuillez vous connecter à la plateforme pour plus de détails.""",
|
|
||||||
destinataires = [reservation.employe.user.email]
|
|
||||||
)
|
|
||||||
|
|
||||||
messages.success(request, f"Réservation de {reservation.employe.get_full_name()} validée avec succès.")
|
|
||||||
return redirect('gestion_salle:reservation-salle')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -238,11 +227,4 @@ def refuser_reservation(request: HttpRequest):
|
|||||||
reservation.statut = 'refusee'
|
reservation.statut = 'refusee'
|
||||||
reservation.save()
|
reservation.save()
|
||||||
|
|
||||||
if fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION:
|
return redirect('gestion_salle:reservation-salle')
|
||||||
fonctions_utilitaire.envoyer_mail(
|
|
||||||
sujet = "Reservation de salle",
|
|
||||||
message = f"""Bonjour {request.user.first_name} {request.user.last_name}, votre reservation de la salle {dict(Reservation.TYPE_CHOICES).get(reservation.salle)} du {reservation.date_debut.strftime('%d/%m/%Y')} au {reservation.date_fin.strftime('%d/%m/%Y')} pour motif "{reservation.motif_reservation}" a été refusée. Veuillez vous connecter à l'Assistante de Direction pour plus de détails.""",
|
|
||||||
destinataires = [reservation.employe.user.email]
|
|
||||||
)
|
|
||||||
|
|
||||||
return JsonResponse({"message": "Réservation refusée avec succès."})
|
|
||||||
159
requirements.txt
159
requirements.txt
@@ -1,21 +1,152 @@
|
|||||||
asgiref==3.11.1
|
anyio==4.13.0
|
||||||
certifi==2026.4.22
|
argon2-cffi==25.1.0
|
||||||
|
argon2-cffi-bindings==25.1.0
|
||||||
|
arrow==1.4.0
|
||||||
|
asgiref==3.11.0
|
||||||
|
asttokens==3.0.1
|
||||||
|
async-lru==2.3.0
|
||||||
|
attrs==26.1.0
|
||||||
|
Automat==20.2.0
|
||||||
|
babel==2.18.0
|
||||||
|
bcrypt==3.2.0
|
||||||
|
beautifulsoup4==4.14.3
|
||||||
|
bleach==6.3.0
|
||||||
|
blinker==1.4
|
||||||
|
certifi==2026.2.25
|
||||||
|
cffi==2.0.0
|
||||||
|
chardet==4.0.0
|
||||||
charset-normalizer==3.4.7
|
charset-normalizer==3.4.7
|
||||||
Django==5.2.13
|
click==8.0.3
|
||||||
django-simple-sso==1.3.0
|
cloud-init==25.3
|
||||||
idna==3.13
|
colorama==0.4.4
|
||||||
itsdangerous==0.24
|
comm==0.2.3
|
||||||
mysqlclient==2.2.8
|
command-not-found==0.3
|
||||||
|
configobj==5.0.6
|
||||||
|
constantly==15.1.0
|
||||||
|
cryptography==3.4.8
|
||||||
|
dbus-python==1.2.18
|
||||||
|
debugpy==1.8.20
|
||||||
|
decorator==5.2.1
|
||||||
|
defusedxml==0.7.1
|
||||||
|
distlib==0.4.0
|
||||||
|
distro==1.7.0
|
||||||
|
distro-info==1.1+ubuntu0.2
|
||||||
|
Django==5.2.10
|
||||||
|
et_xmlfile==2.0.0
|
||||||
|
exceptiongroup==1.3.1
|
||||||
|
executing==2.2.1
|
||||||
|
fastjsonschema==2.21.2
|
||||||
|
filelock==3.20.3
|
||||||
|
fqdn==1.5.1
|
||||||
|
h11==0.16.0
|
||||||
|
httpcore==1.0.9
|
||||||
|
httplib2==0.20.2
|
||||||
|
httpx==0.28.1
|
||||||
|
hyperlink==21.0.0
|
||||||
|
idna==3.3
|
||||||
|
importlib-metadata==4.6.4
|
||||||
|
incremental==21.3.0
|
||||||
|
ipykernel==7.2.0
|
||||||
|
ipython==8.39.0
|
||||||
|
isoduration==20.11.0
|
||||||
|
jedi==0.19.2
|
||||||
|
jeepney==0.7.1
|
||||||
|
Jinja2==3.0.3
|
||||||
|
json5==0.14.0
|
||||||
|
jsonpatch==1.32
|
||||||
|
jsonpointer==2.0
|
||||||
|
jsonschema==4.26.0
|
||||||
|
jsonschema-specifications==2025.9.1
|
||||||
|
jupyter-events==0.12.0
|
||||||
|
jupyter-lsp==2.3.1
|
||||||
|
jupyter_client==8.8.0
|
||||||
|
jupyter_core==5.9.1
|
||||||
|
jupyter_server==2.17.0
|
||||||
|
jupyter_server_terminals==0.5.4
|
||||||
|
jupyterlab==4.5.6
|
||||||
|
jupyterlab_pygments==0.3.0
|
||||||
|
jupyterlab_server==2.28.0
|
||||||
|
keyring==23.5.0
|
||||||
|
lark==1.3.1
|
||||||
|
launchpadlib==1.10.16
|
||||||
|
lazr.restfulclient==0.14.4
|
||||||
|
lazr.uri==1.0.6
|
||||||
|
MarkupSafe==2.0.1
|
||||||
|
matplotlib-inline==0.2.1
|
||||||
|
mistune==3.2.0
|
||||||
|
more-itertools==8.10.0
|
||||||
|
nbclient==0.10.4
|
||||||
|
nbconvert==7.17.0
|
||||||
|
nbformat==5.10.4
|
||||||
|
nest-asyncio==1.6.0
|
||||||
|
netifaces==0.11.0
|
||||||
|
notebook_shim==0.2.4
|
||||||
numpy==2.2.6
|
numpy==2.2.6
|
||||||
|
oauthlib==3.2.0
|
||||||
|
openpyxl==3.1.5
|
||||||
|
overrides==7.7.0
|
||||||
|
packaging==26.0
|
||||||
pandas==2.3.3
|
pandas==2.3.3
|
||||||
pillow==12.2.0
|
pandocfilters==1.5.1
|
||||||
|
parso==0.8.6
|
||||||
|
pexpect==4.9.0
|
||||||
|
platformdirs==4.5.1
|
||||||
|
prometheus_client==0.24.1
|
||||||
|
prompt_toolkit==3.0.52
|
||||||
|
psutil==7.2.2
|
||||||
|
ptyprocess==0.7.0
|
||||||
|
pure_eval==0.2.3
|
||||||
|
pyasn1==0.4.8
|
||||||
|
pyasn1-modules==0.2.1
|
||||||
|
pycparser==3.0
|
||||||
|
pycurl==7.44.1
|
||||||
|
Pygments==2.20.0
|
||||||
|
PyGObject==3.42.1
|
||||||
|
PyHamcrest==2.0.2
|
||||||
|
PyJWT==2.3.0
|
||||||
|
pyOpenSSL==21.0.0
|
||||||
|
pyparsing==2.4.7
|
||||||
|
pyrsistent==0.18.1
|
||||||
|
pyserial==3.5
|
||||||
|
python-apt==2.4.0+ubuntu4.1
|
||||||
python-dateutil==2.9.0.post0
|
python-dateutil==2.9.0.post0
|
||||||
pytz==2026.1.post1
|
python-json-logger==4.1.0
|
||||||
|
pytz==2022.1
|
||||||
|
PyYAML==5.4.1
|
||||||
|
pyzmq==27.1.0
|
||||||
|
referencing==0.37.0
|
||||||
requests==2.33.1
|
requests==2.33.1
|
||||||
six==1.17.0
|
rfc3339-validator==0.1.4
|
||||||
|
rfc3986-validator==0.1.1
|
||||||
|
rfc3987-syntax==1.1.0
|
||||||
|
rpds-py==0.30.0
|
||||||
|
SecretStorage==3.3.1
|
||||||
|
Send2Trash==2.1.0
|
||||||
|
service-identity==18.1.0
|
||||||
|
six==1.16.0
|
||||||
|
soupsieve==2.8.3
|
||||||
sqlparse==0.5.5
|
sqlparse==0.5.5
|
||||||
|
ssh-import-id==5.11
|
||||||
|
stack-data==0.6.3
|
||||||
|
systemd-python==234
|
||||||
|
terminado==0.18.1
|
||||||
|
tinycss2==1.4.0
|
||||||
|
tomli==2.4.1
|
||||||
|
tornado==6.5.5
|
||||||
|
traitlets==5.14.3
|
||||||
|
Twisted==22.1.0
|
||||||
typing_extensions==4.15.0
|
typing_extensions==4.15.0
|
||||||
tzdata==2026.2
|
tzdata==2025.3
|
||||||
urllib3==2.6.3
|
ubuntu-pro-client==8001
|
||||||
python-decouple
|
ufw==0.36.1
|
||||||
gunicorn
|
unattended-upgrades==0.1
|
||||||
|
uri-template==1.3.0
|
||||||
|
urllib3==1.26.5
|
||||||
|
virtualenv==20.13.0+ds
|
||||||
|
wadllib==1.3.6
|
||||||
|
wcwidth==0.6.0
|
||||||
|
webcolors==25.10.0
|
||||||
|
webencodings==0.5.1
|
||||||
|
websocket-client==1.9.0
|
||||||
|
zipp==1.0.0
|
||||||
|
zope.interface==5.4.0
|
||||||
|
|||||||
Reference in New Issue
Block a user