11 Commits

Author SHA1 Message Date
b03a4214c0 Bug: Validation des conges
All checks were successful
Organisation/sirh/pipeline/head This commit looks good
2026-05-11 15:33:04 +00:00
d4f4b7d954 Bug: Validation des conges
Some checks failed
Organisation/sirh/pipeline/head There was a failure building this commit
2026-05-11 15:27:50 +00:00
489eeb439f Correction Bug : Validation 2026-05-11 14:46:59 +00:00
5277b7f355 Bug: Validation de reservation
All checks were successful
Organisation/sirh/pipeline/head This commit looks good
2026-05-11 13:20:13 +00:00
9d9e6c6549 Bug: Affichage de la lite des conges en fonction des profil
All checks were successful
Organisation/sirh/pipeline/head This commit looks good
2026-05-07 15:32:22 +00:00
784822478e feature: Affichage de la liste des bailleur 2026-05-07 15:28:52 +00:00
ab87baaa3a Bug: Affichage des details de la reservation 2026-05-07 15:28:42 +00:00
6026af5498 Bug : Affichages des conges 2026-05-07 15:23:47 +00:00
91bdd791f1 Bug : Affichage des demandes de conges 2026-05-07 15:11:25 +00:00
671072864d Bug: Details des reservations
All checks were successful
Organisation/sirh/pipeline/head This commit looks good
2026-05-07 14:44:16 +00:00
bb93a853db Gestion de l'envoie des mails
All checks were successful
Organisation/sirh/pipeline/head This commit looks good
2026-05-07 11:25:11 +00:00
47 changed files with 327 additions and 142 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ media/
staticfiles/
.env
migrations/
*.pyc

1
Jenkinsfile vendored
View File

@@ -39,6 +39,7 @@ pipeline
python manage.py makemigrations
python manage.py migrate
python manage.py collectstatic --noinput
echo $SUDO_PASSWORD | sudo -S chown -R www-data:www-data /var/www/sirh
echo "Deploiement reussi"

View File

@@ -150,6 +150,7 @@ MEDIA_ROOT = BASE_DIR / "media"
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# Configuration de l'email
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'ssl0.ovh.net'
EMAIL_PORT = 465

View File

@@ -1,5 +1,5 @@
from django.utils import timezone
from gestion_employe.models import Contrat
from gestion_employe.models import Contrat, Employe
from gestion_conge.models import Conge
@@ -7,6 +7,7 @@ QUOTA_CONGE_ANNUEL = 30
NOMBRE_PAGINATION = 8
DEBUT_RAPPEL = 60
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):
"""Fonction de calcul du solde de congé restant l'employé"""
@@ -32,3 +33,25 @@ def solde_conge(employe):
"quota_annuel": QUOTA_CONGE_ANNUEL - 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))

View File

@@ -83,7 +83,6 @@ def index(request):
Q(validation_hierarchique = True) | Q(validation_hierarchique = False)
).order_by('-date_demande')
return render(request, 'gestion_conge/index.html', {
"nombre_conges_valide": nombre_conges_valide,
"nombre_conges_refuse": nombre_conges_refuse,
@@ -123,56 +122,66 @@ def demander_conge(request):
conge_obj.save()
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")
@login_required
def liste_demande_conges(request):
"""Vue de liste des demandes de congés en attente de validation selon le statut de l'utilisateur actuel"""
try:
employe = Employe.objects.get(user__username = request.user)
employe = Employe.objects.get(user=request.user)
except Employe.DoesNotExist:
return JsonResponse({
"success": False,
"message": "Votre profil Utilisateur n'est lié à aucun profil Employé. Veuillez contacter l'administrateur."
"message": "Profil employé introuvable"
})
try:
affectation = Affectation.objects.get(
affectation = Affectation.objects.filter(
employe=employe,
date_fin_daffectation__gte=timezone.now().date()
)
except Affectation.DoesNotExist:
affectation = None
).first()
is_direction = employe.user.groups.filter(name='direction').exists()
if employe.chef:
print("chef")
conges_en_attente = Conge.objects.filter(
employe__departement = employe.departement,
validation_hierarchique = None
conges = Conge.objects.filter(
Q(employe__departement=employe.departement) |
Q(employe=employe)
).order_by('-date_demande')
elif affectation and affectation.role == "chef_projet":
employes_du_projet = Affectation.objects.filter(
projet=affectation.projet,
date_fin_daffectation__gte=timezone.now().date()
).values('employe')
).values_list('employe', flat=True)
conges_en_attente = Conge.objects.filter(
employe__in = employes_du_projet,
validation_hierarchique = None
conges = Conge.objects.filter(
Q(employe__in=employes_du_projet) |
Q(employe=employe)
).order_by('-date_demande')
elif 'direction' in employe.user.groups.values_list('name', flat=True):
conges_en_attente = Conge.objects.filter(
validation_hierarchique = True,
validation_direction = None
).order_by('-date_demande')
elif is_direction:
conges = Conge.objects.filter(
Q(validation_hierarchique=True) |
Q(employe__user__groups__name='direction')
).distinct().order_by('-date_demande')
else:
conges_en_attente = Conge.objects.filter(
employe__user__username = request.user
conges = Conge.objects.filter(
employe=employe
).order_by('-date_demande')
return JsonResponse({
@@ -186,9 +195,9 @@ def liste_demande_conges(request):
"type": dict(conge.TYPE_CHOICES).get(conge.type),
"solde_conge": fonctions_utilitaire.solde_conge(conge.employe)["quota_annuel"]
}
for conge in conges_en_attente]},
safe=False
)
for conge in conges
]
})
@login_required
def validation_de_conge(request):

View File

@@ -109,6 +109,13 @@ 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}.")
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')
else:
messages.error(request, "Erreur : Formulaire non valide.")

View File

@@ -1,4 +1,5 @@
const btnEnregistrerBailleur = document.getElementById('btnEnregistrerBailleur');
let table;
btnEnregistrerBailleur.addEventListener('click', function() {
const form = document.getElementById('formBailleur');
@@ -21,3 +22,30 @@ btnEnregistrerBailleur.addEventListener('click', function() {
}
});
});
document.addEventListener("DOMContentLoaded", function () {
table = new Tabulator("#table-bailleurs", {
ajaxURL: "/gestion-projet/bailleurs/",
layout: "fitColumns",
pagination: "local",
paginationSize: 5,
columns: [
{title: "#", formatter: "rownum", width: 60},
{title: "Organisme", field: "nom_organisme"},
{title: "Contact", field: "contact"},
{title: "Email", field: "email"},
{title: "Pays", field: "pays"},
],
rowDblClick: function(e, row) {
const data = row.getData();
if (confirm(`Voulez-vous vraiment supprimer ${data.nom_organisme} ?`)) {
supprimerBailleur(data.id);
}
}
});
});

View File

@@ -1,20 +1,51 @@
<div class="modal fade" id="modalBailleur" tabindex="-1" aria-labelledby="modalBailleurLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-dialog ">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="modalBailleurLabel">Ajouter un Bailleur</h5>
<h5 class="modal-title" id="modalBailleurLabel">Gestion des Bailleurs</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body p-4">
<ul class="nav nav-tabs px-3 pt-2" id="bailleurTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="ajouter-tab" data-bs-toggle="tab"
data-bs-target="#ajouter" type="button" role="tab">
Ajouter
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="liste-tab" data-bs-toggle="tab"
data-bs-target="#liste" type="button" role="tab">
Liste
</button>
</li>
</ul>
<div class="modal-body">
<div class="tab-content pt-3">
<div class="tab-pane fade show active" id="ajouter" role="tabpanel">
<form id="formBailleur" method="POST" action="{% url 'gestion_projet:creation-bailleur' %}">
{% csrf_token %}
{{ form_ajout_bailleur.as_p }}
<button type="submit" class="btn btn-success mt-3" id="btnEnregistrerBailleur">
<i class="bi bi-save me-1"></i> Enregistrer
</button>
</form>
</div>
<div class="modal-footer">
<button type="submit" id="btnEnregistrerBailleur" class="btn btn-success"><i class="bi bi-save me-1"></i> Enregistrer</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
<div class="tab-pane fade" id="liste" role="tabpanel">
<div class="d-flex justify-content-between align-items-center mb-3">
<h6 class="mb-0">Liste des bailleurs</h6>
</div>
<div class="row">
<div class="col">
<div id="table-bailleurs"
data-url="{% url 'gestion_projet:liste-bailleurs' %}">
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View File

@@ -19,6 +19,12 @@ urlpatterns = [
views.creation_projet,
name='creation-projet'
),
path(
'bailleurs/',
views.liste_bailleur,
name='liste-bailleurs'
),
path(
'projet/modifier/<int:projet_id>/',
views.modification_projet,
@@ -84,6 +90,7 @@ urlpatterns = [
views.liste_activites_projet,
name='liste-activites-projet'
),
# path(
# 'projet/ajout-de-document/',
# views.ajouter_document_projet,
@@ -119,4 +126,6 @@ urlpatterns = [
views.mises_a_jour_projet,
name='mises-a-jour-projet'
)
]

View File

@@ -2,6 +2,7 @@ from datetime import date
from decimal import Decimal, InvalidOperation
from django.http import JsonResponse
from django.shortcuts import redirect, render
from django.urls import reverse
from django.utils import timezone
from django.contrib import messages
from django.contrib.auth.decorators import login_required
@@ -143,6 +144,22 @@ def creation_bailleur(request):
return JsonResponse({'success': True})
return JsonResponse({'success': False})
@login_required
def liste_bailleur(request):
""" Vue pour retourner la liste de tous les bailleurs """
bailleurs = Bailleur.objects.all().order_by('-id')
data = []
for b in bailleurs:
data.append({
"id": b.id,
"nom_organisme": b.nom_organisme,
"contact": b.contact,
"email": b.email,
"pays": b.pays,
})
return JsonResponse(data, safe=False)
@login_required
def ajouter_financement_projet(request):
"""Ajoute un financement à un projet en vérifiant que le total ne dépasse pas 100%"""
@@ -318,6 +335,7 @@ def activites_projet(request):
}
return render(request, 'gestion_projet/suivi_activite.html', context)
@login_required
def ajouter_activite_projet(request):
"""Vue pour ajouter une activité à un projet spécifique via un formulaire"""

View File

@@ -30,4 +30,4 @@ class Reservation(models.Model):
statut = models.CharField(choices=STATUT, default='en_attente', max_length=25)
def __str__(self):
return f"{self.salle} - {self.employe.user.first_name} {self.employe.user.last_name} le {self.date_reservation}"
return f"{self.salle} - {self.employe.user.first_name} {self.employe.user.last_name}"

View File

@@ -15,7 +15,6 @@ const calendrier = Schedule(document.getElementById('planning-reservation'), {
.then(response => response.json())
.then(data => {
currentReservationId = data.id_reservation;
console.log(data);
$("id_reservation_detail").value = data.id_reservation;
$("id_reservation_refus").value = data.id_reservation;
$("id_reservation_zoom").value = data.id_reservation;
@@ -30,11 +29,10 @@ const calendrier = Schedule(document.getElementById('planning-reservation'), {
$("besoin_ordinateur").checked=data.besoin_ordinateur;
$("lien_zoom").value=data.lien_zoom;
if(data.statut !== "annulee"){
$("motif_refus_container").className = "d-none";
}else{
$("motif_refus").value=data.motif_refus;
if (data.besoin_zoom === false){
$("lien_zoom_container").className = "d-none";
}
})
}
});
@@ -161,16 +159,11 @@ const tableau_reservation_attente = new Tabulator("#tableau-reservation-attente"
tableau_reservation_attente.on("rowClick", (row, rowData) => {
const data = rowData.getData();
console.log(data);
if(data.besoin_zoom === false){
$("lien_zoom_container").className = 'd-none';
}
if(data.statut !== "refusee"){
$("motif_refus_container").className = 'd-none';
}
const id_user = $("current-user-id").dataset.userid;
$("id_reservation_detail").value = data.id;
$("id_reservation_refus").value = data.id;
$("id_reservation_zoom").value = data.id;
@@ -178,14 +171,18 @@ tableau_reservation_attente.on("rowClick", (row, rowData) => {
$("employe").value=data.employe;
$("salle").value=data.salle;
$("statut-reservation").innerHTML=data.statut;
$("date_evenement").value=data.date_debut;
$("date_debut").value = data.date_debut;
$("date_fin").value = data.date_fin;
$("heure_debut").value=data.heure_debut;
$("heure_fin").value=data.heure_fin;
$("motif_reservation").value=data.motif_reservation;
$("besoin_zoom").checked=data.besoin_zoom;
$("besoin_ordinateur").checked=data.besoin_ordi;
$("lien_zoom").value=data.lien_zoom;
$("motif_refus").value=data.motif_refus;
if (id_user != data.employe_id){
$("bouton-annuler").className = "d-none";
}
const modal = new bootstrap.Modal($("modalDetailReservation"));
bootstrap.Modal.getOrCreateInstance($("modalReservationAttente")).hide();

View File

@@ -1,4 +1,5 @@
<!-- Modal d'affichage des détails d'une reservation -->
{% load tags_personnaliser %}
<div class="modal fade" id="modalDetailReservation" tabindex="-1" aria-labelledby="modalDetailReservationLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
@@ -21,8 +22,12 @@
<input class="form-control" id="salle" readonly>
</div>
<div class="form-group mb-2">
<label>Date de l'évènement :</label>
<input type='date' class="form-control" id="date_evenement" readonly >
<label>Date de debut :</label>
<input type='date' class="form-control" id="date_debut" readonly >
</div>
<div class="form-group mb-2">
<label>Date de fin :</label>
<input type='date' class="form-control" id="date_fin" readonly >
</div>
<div class="form-group mb-2">
<label>Heure de début :</label>
@@ -48,21 +53,16 @@
<label label="form-check-label">Besoin d'un ordinateur</label>
<input type="checkbox" class="form-check-input" id="besoin_ordinateur" readonly >
</div>
<div class="form-group mb-2" id='motif_refus_container'>
<label>Motif de refus de la reservation :</label>
<textarea class="form-control" id="motif_refus" readonly></textarea>
</div>
<div class='d-flex justify-content-around mt-2'>
{% if appartient_au_departement_informatique %}
<button class="btn btn-primary" id="ajoutZoom">Ajout du lien zoom</button>
{% endif %}
{% if appartient_direction and reservation.statut == "en_attente" %}
{% if user|has_group:'direction' %}
<button class="btn btn-danger" id="refuserReservation" data-lienrefus="{% url 'gestion_salle:refuser-reservation' %}">Refuser</button>
{% endif %}
<button class="btn btn-danger" id="bouton-annuler">Annuler</button>
{% if appartient_direction %}
<button class="btn btn-success" id="bouton-valider">Valider</button>
{% endif %}
<span id="current-user-id" data-userid="{{ request.user.id }}"></span>
<button class="btn btn-danger" id="bouton-annuler">Annuler</button>
</div>
</form>
</div>

View File

@@ -1,68 +1,106 @@
import json
from datetime import timedelta
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.shortcuts import redirect, render
from django.http import JsonResponse, HttpRequest
from django.forms import model_to_dict
from fonction_utilitaire import fonctions_utilitaire
from gestion_employe.models import Employe
from gestion_salle.forms import ReservationForm
from .models import Reservation
@login_required
def index(request: HttpRequest):
"""Vue de gestion de la reservation de la salle"""
try:
employe = Employe.objects.get(user=request.user)
except Employe.DoesNotExist:
messages.error(request, "Impossible d'accéder au menu 'Reservation de salle' car votre profil Utilisateur n'est lié à aucun profil Employe. Veuillez contacter l'administrateur.")
messages.error(request, "Profil employé introuvable.")
return redirect('gestion_conges:conge')
if request.method == "POST":
form = ReservationForm(request.POST)
if form.is_valid():
date_debut = form.cleaned_data.get('date_debut')
date_fin = form.cleaned_data.get('date_fin')
salle = form.cleaned_data.get('salle')
heure_debut = form.cleaned_data.get('heure_debut')
heure_fin = form.cleaned_data.get('heure_fin')
motif_reservation = form.cleaned_data.get('motif_reservation')
besoin_zoom = form.cleaned_data.get('besoin_zoom')
besoin_ordi = form.cleaned_data.get('besoin_ordi')
while date_debut <= date_fin :
reservation = Reservation(
if form.is_valid():
date_debut = form.cleaned_data['date_debut']
date_fin = form.cleaned_data['date_fin']
salle = form.cleaned_data['salle']
heure_debut = form.cleaned_data['heure_debut']
heure_fin = form.cleaned_data['heure_fin']
motif = form.cleaned_data['motif_reservation']
besoin_zoom = form.cleaned_data['besoin_zoom']
besoin_ordi = form.cleaned_data['besoin_ordi']
if date_fin < date_debut:
messages.error(request, "Date fin invalide.")
return redirect('gestion_salle:reservation-salle')
if heure_fin <= heure_debut:
messages.error(request, "Heure invalide.")
return redirect('gestion_salle:reservation-salle')
if not request.user.first_name.strip() or not request.user.last_name.strip():
messages.error(
request,
"Veuillez renseigner votre nom et prénom pour pouvoir faire une réservation."
)
return redirect('gestion_salle:reservation-salle')
created = []
current_date = date_debut
while current_date <= date_fin:
reservation = Reservation.objects.create(
employe=employe,
date_debut = date_debut,
date_fin = date_debut,
date_debut=current_date,
date_fin=current_date,
salle=salle,
heure_debut=heure_debut,
heure_fin=heure_fin,
besoin_zoom=besoin_zoom,
besoin_ordi=besoin_ordi,
motif_reservation=motif_reservation,
motif_reservation=motif,
statut="en_attente"
)
reservation.save()
date_debut = date_debut + timedelta(days=1)
messages.success(request, "Réservation(s) créées avec succès.")
created.append(reservation)
current_date += timedelta(days=1)
messages.success(request, "Réservation(s) créée(s) avec succès.")
print(fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION)
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 = fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION
)
return redirect('gestion_salle:reservation-salle')
formulaire_reservation = ReservationForm()
departement = Employe.objects.get(user__username=request.user).departement
appartient_direction = 'direction' in request.user.groups.values_list('name', flat=True)
liste_demande_reservation = [
reservation.id for reservation in
Reservation.objects.filter(employe=employe, statut='en_attente')
]
departement = employe.departement
appartient_direction = request.user.groups.filter(name='direction').exists()
liste_demande_reservation = Reservation.objects.filter(
employe=employe,
statut='en_attente'
).values_list('id', flat=True)
context = {
'formulaire_reservation': formulaire_reservation,
'nb_reservation_attente': Reservation.objects.filter(statut='en_attente').count(),
'appartient_au_departement_informatique': 'Informatique' == departement.nom if departement else False,
'appartient_au_departement_informatique': departement and departement.nom == "Systeme informatique",
'appartient_direction': appartient_direction,
'liste_demande_reservation': liste_demande_reservation
'liste_demande_reservation': list(liste_demande_reservation),
}
return render(request, "gestion_salle/index.html", context)
def liste_reservation(request:HttpRequest):
@@ -86,7 +124,6 @@ def liste_reservation(request:HttpRequest):
"end": reservation.heure_fin,
"color": color,
})
return JsonResponse(liste_reservation, safe=False)
@login_required
@@ -96,20 +133,25 @@ def liste_reservation_attente(request):
{
**model_to_dict(reservation),
"employe": f"{reservation.employe.user.first_name} {reservation.employe.user.last_name}",
"salle": dict(Reservation.TYPE_CHOICES).get(reservation.salle)
"employe_id": reservation.employe.user.id,
"salle": dict(Reservation.TYPE_CHOICES).get(reservation.salle),
'statut': dict(Reservation.STATUT).get(reservation.statut),
} for reservation in reservations
]
return JsonResponse(liste_reservation, safe=False)
def detail_reservation(request:HttpRequest, reservation_id:int):
reservation = Reservation.objects.get(id=reservation_id)
employe = reservation.employe.user
reservation_json = {
'id_reservation': reservation_id,
'employe': f"{employe.first_name} {employe.last_name}",
'salle': reservation.salle,
'statut': reservation.statut,
'statut': dict(Reservation.STATUT).get(reservation.statut),
'date_evenement': reservation.date_debut.strftime('%Y-%m-%d'),
'heure_debut': reservation.heure_debut.strftime('%H:%M'),
'heure_fin': reservation.heure_fin.strftime('%H:%M'),
@@ -117,7 +159,6 @@ def detail_reservation(request:HttpRequest, reservation_id:int):
'besoin_zoom': reservation.besoin_zoom,
'besoin_ordinateur': reservation.besoin_ordi,
'lien_zoom': reservation.lien_zoom or '',
'motif_refus': reservation.motif_refus or '',
}
return JsonResponse(reservation_json, safe=True)
@@ -166,30 +207,49 @@ def annuler_reservation(request:HttpRequest):
@login_required
def valider_reservation(request: HttpRequest):
"""Vue de gestion de l'annulation de la reservation"""
"""Validation d'une réservation"""
if request.method == 'POST':
reservation_id= request.POST['id_reservation']
reservation_id = request.POST.get('id_reservation')
try:
reservation = Reservation.objects.get(id=reservation_id)
except reservation.DoesNotExist:
messages.error(request, "La resevertion selectionné n'existe pas.")
except Reservation.DoesNotExist:
messages.error(request, "La réservation sélectionnée n'existe pas.")
return redirect("salle")
reservation.statut = 'validee'
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')
@login_required
def refuser_reservation(request: HttpRequest):
"""Vue de gestion de refus de la reservation"""
data = json.loads(request.body)
reservation_id = data.get("id_reservation")
"""Refuser une réservation"""
if request.method == 'POST':
reservation_id = request.POST.get('id_reservation')
try:
reservation = Reservation.objects.get(id=reservation_id)
except Reservation.DoesNotExist and ValueError:
return JsonResponse({"message": "La resevertion selectionné n'existe pas."})
else:
reservation.statut = "refusee"
except Reservation.DoesNotExist:
messages.error(request, "La réservation n'existe pas.")
return redirect("salle")
reservation.statut = 'refusee'
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é 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."})