Premiere version SIRH

This commit is contained in:
2026-04-27 10:17:10 +00:00
commit 9865860254
485 changed files with 46065 additions and 0 deletions

View File

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.

Binary file not shown.

3
gestion_salle/admin.py Normal file
View File

@@ -0,0 +1,3 @@
from django.contrib import admin
# Register your models here.

5
gestion_salle/apps.py Normal file
View File

@@ -0,0 +1,5 @@
from django.apps import AppConfig
class GestionSalleConfig(AppConfig):
name = 'gestion_salle'

32
gestion_salle/forms.py Normal file
View File

@@ -0,0 +1,32 @@
from django import forms
from .models import Reservation
class ReservationForm(forms.ModelForm):
class Meta:
model = Reservation
fields = ['salle', 'date_debut', 'date_fin', 'heure_debut', 'heure_fin', 'motif_reservation', 'besoin_zoom', 'besoin_ordi']
widgets = {
'date_debut': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
'date_fin': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
'heure_debut': forms.TimeInput(attrs={'type': 'time', 'class': 'form-control'}),
'heure_fin': forms.TimeInput(attrs={'type': 'time', 'class': 'form-control'}),
'motif_reservation': forms.Textarea(attrs={'rows': 3, 'cols': 40, 'style':'resize:none;', 'class': 'form-control'}),
'salle': forms.Select(attrs={'class': 'form-select'}),
}
besoin_zoom = forms.BooleanField(
required=False,
label="Besoin d'un lien Zoom ?",
widget=forms.CheckboxInput(attrs={'class': 'form-check-input', 'id': 'id_besoin_zoom'})
)
besoin_ordi = forms.BooleanField(
required=False,
label="Besoin d'ordinateur ?",
widget=forms.CheckboxInput(attrs={'class': 'form-check-input', 'id': 'id_besoin_ordi'})
)
class RefusReservationForm(forms.Form):
motif_refus = forms.CharField(
label= "Motif du refus",
widget=forms.Textarea(attrs={'rows': 3, 'cols': 40, 'style': 'resize:none;'}),
required=True
)

View File

@@ -0,0 +1,34 @@
# Generated by Django 5.2.13 on 2026-04-17 12:03
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')),
],
),
]

View File

33
gestion_salle/models.py Normal file
View File

@@ -0,0 +1,33 @@
from django.db import models
from gestion_employe.models import Employe
class Reservation(models.Model):
"""Modèle de création des réservations"""
TYPE_CHOICES = [
('formation', 'Salle de formation'),
('reunion', 'Salle de réunion'),
('lien_zoom', 'Lien Zoom'),
]
STATUT = [
('en_attente', 'En attente'),
('validee', 'Validée'),
('refusee', 'Refusée'),
('annulee', 'Annulée'),
]
employe = models.ForeignKey(Employe, on_delete=models.CASCADE)
salle = models.CharField(max_length=100, choices=TYPE_CHOICES)
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=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}"

View File

@@ -0,0 +1,193 @@
const $ = (element) => document.getElementById(element);
const { Schedule } = calendarjs;
let dateAUtiliser = new Date().toISOString().split('T')[0];
let currentReservationId = null;
const calendrier = Schedule(document.getElementById('planning-reservation'), {
type: 'weekdays',
value: dateAUtiliser,
validRange: ['08:00', '18:00'],
ondblclick: function(self, event) {
const modal = new bootstrap.Modal($("modalDetailReservation"));
modal.show();
fetch (`/gestion-salle/revervation/details/${event.guid}`)
.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;
$("employe").value=data.employe;
$("salle").value=data.salle;
$("statut-reservation").innerHTML=data.statut;
$("date_evenement").value=data.date_evenement;
$("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_ordinateur;
$("lien_zoom").value=data.lien_zoom;
if(data.statut !== "annulee"){
$("motif_refus_container").className = "d-none";
}else{
$("motif_refus").value=data.motif_refus;
}
})
}
});
$("modalReservation").addEventListener('shown.bs.modal', (e) => {
$("id_salle").value = $("liste-salle").value;
})
$('semaineDate').addEventListener('change', () => {
calendrier.value = $('semaineDate').value;
calendrier.render();
})
evenement_defini = null
$("liste-salle").addEventListener("change", (e) => {
if(evenement_defini === null){
evenement_defini = calendrier.getData();
}
evenements = evenement_defini;
evenement_filtrer = evenements.filter((evenement) => {
if(evenement.title == $("liste-salle").value){
return evenement
}
})
calendrier.setData(evenement_filtrer);
})
function chargement_evenement(){
const url = $("planning-reservation").dataset.url;
fetch (url)
.then(response => response.json())
.then(data => {
calendrier.setData(data);
})
}
document.addEventListener("DOMContentLoaded", function () {
chargement_evenement()
})
$("bouton-annuler").addEventListener("click", (e) => {
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
const url_annuler = $("formulaire-details").dataset.urlannuler;
fetch(
url_annuler,
{
method: "POST",
headers: {
"X-Requested-With": "XMTHttpRequest",
"X-CSRFToken": csrf
},
body: new FormData($("formulaire-details"))
}
)
.then(response => response.json())
.then(data => console.log(data))
})
if($("bouton-valider")){
$("bouton-valider").addEventListener("click", (e) => {
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
const urlvalider = $("formulaire-details").dataset.urlvalider;
fetch(
urlvalider,
{
method: "POST",
headers: {
"X-Requested-With": "XMTHttpRequest",
"X-CSRFToken": csrf
},
body: new FormData($("formulaire-details"))
}
)
.then(response => response.json())
.then(data => console.log(data))
})
}
if($("ajoutZoom")){
$("ajoutZoom").addEventListener("click", (e) => {
e.preventDefault();
bootstrap.Modal.getOrCreateInstance($("modalDetailReservation")).hide();
new bootstrap.Modal($("modalZoom")).show();
})
}
if($("refuserReservation")){
$("refuserReservation").addEventListener("click", (e) => {
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
const url = e.currentTarget.dataset.lienrefus;
const idRes = $("id_reservation_detail").value;
fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Requested-With": "XMLHttpRequest",
"X-CSRFToken": csrf
},
body: JSON.stringify({ "id_reservation": idRes })
})
.then(response => response.json())
.then(data => alert(data.message))
.catch(error => console.error("Erreur:", error));
});
}
const tableau_reservation_attente = new Tabulator("#tableau-reservation-attente", {
columns: [
{title: "Employé", field: "employe"},
{title: "Salle", field: "salle"},
{title: "Date de l'evenement", field: "date_debut"},
{title: "Heure de début", field: "heure_debut"},
{title: "Heure de fin", field: "heure_fin"},
{title: "Motif de reservation", field: "motif_reservation"},
],
placeholder: "Aucune reservation en attente.",
ajaxURL : $("tableau-reservation-attente").dataset.reservationattentes
})
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';
}
$("id_reservation_detail").value = data.id;
$("id_reservation_refus").value = data.id;
$("id_reservation_zoom").value = data.id;
$("employe").value=data.employe;
$("salle").value=data.salle;
$("statut-reservation").innerHTML=data.statut;
$("date_evenement").value=data.date_debut;
$("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;
const modal = new bootstrap.Modal($("modalDetailReservation"));
bootstrap.Modal.getOrCreateInstance($("modalReservationAttente")).hide();
modal.show();
})

View File

@@ -0,0 +1,59 @@
{% extends "BASE.html" %}
{% load static %}
{% block 'titre_page' %} Gestion des projets {% endblock %}
{% block 'css' %}
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Material+Icons" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@calendarjs/ce/dist/style.min.css" />
{% endblock %}
{% block 'contenu' %}
{% if messages %}
{% for message in messages %}
<div class="alert alert-{% if message.tags == "error" %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
{{ message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
{% endfor %}
{% endif %}
<div class="row">
<div class="col py-2 px-4">
<h1 class="text-center">Reservation de salle</h1>
<hr>
<div class="row d-flex justify-content-around">
<div class="form-group col-5 me-2">
<label>Selectionner le jour concerné :</label>
<input type="date" class="form-control" id="semaineDate" />
</div>
<div class="form-group col-5 me-2">
<label>Selectionner une salle :</label>
<select class = "form-select" id="liste-salle">
<option value='formation'>Salle de formation</option>
<option value='reunion'>Salle de réunion</option>
<option value='lien_zoom'>Lien Zoom</option>
</select>
</div>
</div>
<div class="row mt-2">
<div class="col d-flex justify-content-center">
<button class="btn btn-lg btn-primary me-2" data-bs-toggle="modal" data-bs-target="#modalReservation">Nouvelle reservation</button>
<button type="button" class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#modalReservationAttente">
Validation en attente <span class="badge badge-light">{{ nb_reservation_attente }}</span>
</button>
</div>
</div>
<hr>
<div data-url="{% url 'gestion_salle:liste-reservation' %}" id="planning-reservation"></div>
</div>
</div>
{% endblock %}
{% block 'modal' %}
{% include 'gestion_salle/parts/modalCreationReservation.html' %}
{% include 'gestion_salle/parts/ModaleAjoutLienZoom.html' %}
{% include 'gestion_salle/parts/ModalRefusReservation.html' %}
{% include 'gestion_salle/parts/modalDetailResevation.html' %}
{% include 'gestion_salle/parts/modalListeValidation.html' %}
{% endblock %}
{% block 'js' %}
<script src="https://cdn.jsdelivr.net/npm/lemonadejs/dist/lemonade.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@calendarjs/ce/dist/index.min.js"></script>
<script src="{% static 'gestion_salle/js/index.js' %}"></script>
{% endblock %}

View File

@@ -0,0 +1,22 @@
<div class="modal fade" id="refusModal" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header ">
<h5 class="modal-title">Motif du refus</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form method="POST" id="refusForm" action="{% url 'gestion_salle:refuser-reservation' %}">
{% csrf_token %}
<input type='' class="form-control" id="id_reservation_refus" name='id_reservation' value="">
<textarea class="form-control" name="motif_refus" rows="3" required></textarea>
<div class="modal-footer">
<button type="submit" class="btn btn-danger">Refuser</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
</div>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,26 @@
<!-- Modal Ajouter/Modifier lien Zoom -->
<div class="modal fade" id="modalZoom" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header ">
<h5 class="modal-title">Ajouter/Modifier le lien Zoom</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<form method="post" id="formZoom" action="{% url 'gestion_salle:ajouter-lien_zoom' %}">
{% csrf_token %}
<input type='hidden' class="form-control" id="id_reservation_zoom" name='id_reservation'>
<div class="mb-3">
<label for="lienZoom" class="form-label">Lien Zoom</label>
<input type="url" class="form-control" name="lien_zoom" id="lienZoom"
value="" required>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-success">Enregistrer</button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
</div>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,23 @@
<!-- Modal de création d'une nouvelle reservation -->
<div class="modal fade" id="modalReservation" tabindex="-1" aria-labelledby="modalReservationLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modalReservationLabel">
Nouvelle reservation
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="POST" action="{% url 'gestion_salle:reservation-salle' %}">
{% csrf_token %}
{{ formulaire_reservation.as_p }}
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
<button type="submit" class="btn btn-primary">Enregistrer</button>
</div>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,71 @@
<!-- Modal d'affichage des détails d'une reservation -->
<div class="modal fade" id="modalDetailReservation" tabindex="-1" aria-labelledby="modalDetailReservationLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modalDetailReservationLabel">
Détails de la reservation (<span id='statut-reservation'></span>)
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form method="POST" data-urlannuler="{% url 'gestion_salle:annuler-reservation' %}" data-urlvalider="{% url 'gestion_salle:valider-reservation' %}" id="formulaire-details">
{% csrf_token %}
<input type='hidden' class="form-control" id="id_reservation_detail" name='id_reservation'>
<div class="form-group mb-2">
<label>Employé :</label>
<input class="form-control" id="employe" readonly>
</div>
<div class="form-group mb-2">
<label>Salle :</label>
<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 >
</div>
<div class="form-group mb-2">
<label>Heure de début :</label>
<input type='time' class="form-control" id="heure_debut" readonly>
</div>
<div class="form-group mb-2">
<label>Heure de fin :</label>
<input type='time' class="form-control" id="heure_fin" readonly >
</div>
<div class="form-group mb-2">
<label>Motif de la reservation :</label>
<textarea class="form-control" id="motif_reservation" readonly ></textarea>
</div>
<div class="form-check mb-2">
<label class="form-check-label">Besoin d'un lien Zoom</label>
<input type="checkbox" class="form-check-input" id="besoin_zoom" readonly >
</div>
<div class="form-group mb-2" id="lien_zoom_container">
<label>lien Zoom :</label>
<input type="url" class="form-control" id="lien_zoom" readonly >
</div>
<div class="form-check mb-2">
<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" %}
<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 %}
</div>
</form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,16 @@
<!-- Modal d'affichage des détails d'une reservation -->
<div class="modal fade" id="modalReservationAttente" tabindex="-1" aria-labelledby="modalReservationAttenteLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="modalReservationAttenteLabel">
Liste des reservation en attente de validation
</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<div id="tableau-reservation-attente" data-reservationattentes = "{% url 'gestion_salle:liste-reservation-attente' %}"></div>
</div>
</div>
</div>
</div>

3
gestion_salle/tests.py Normal file
View File

@@ -0,0 +1,3 @@
from django.test import TestCase
# Create your tests here.

48
gestion_salle/urls.py Normal file
View File

@@ -0,0 +1,48 @@
from django.urls import path
from . import views
app_name = "gestion_salle"
urlpatterns = [
path(
'revervation/',
views.index,
name='reservation-salle'
),
path(
'revervation/details/<int:reservation_id>',
views.detail_reservation,
name='detail-reservation'
),
path(
'reservation/annuler',
views.annuler_reservation,
name='annuler-reservation'
),
path(
'reservation/valider',
views.valider_reservation,
name='valider-reservation'
),
path(
'reservation/refuser',
views.refuser_reservation,
name='refuser-reservation'
),
path(
'reservation/ajout-de-lien-zoom',
views.ajouter_lien_zoom,
name='ajouter-lien_zoom'
),
path(
'liste-reservation',
views.liste_reservation,
name='liste-reservation'
),
path(
'liste-reservation-attente',
views.liste_reservation_attente,
name="liste-reservation-attente"
)
]

195
gestion_salle/views.py Normal file
View File

@@ -0,0 +1,195 @@
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 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.")
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(
employe = employe,
date_debut = date_debut,
date_fin = date_debut,
salle = salle,
heure_debut = heure_debut,
heure_fin = heure_fin,
besoin_zoom = besoin_zoom,
besoin_ordi = besoin_ordi,
motif_reservation=motif_reservation,
)
reservation.save()
date_debut = date_debut + timedelta(days=1)
messages.success(request, "Réservation(s) créées avec succès.")
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')
]
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_direction': appartient_direction,
'liste_demande_reservation': liste_demande_reservation
}
return render(request, "gestion_salle/index.html", context)
def liste_reservation(request:HttpRequest):
"""Vue d'affichage des creneaux disponibles"""
reservations = Reservation.objects.filter(statut = "validee")
liste_reservation = []
for reservation in reservations:
color = None
if reservation.statut == "en_attente":
color = "#ffc107"
elif reservation.statut == "validee":
color = "#198754"
else:
color = "#dc3545"
liste_reservation.append({
"guid": reservation.pk,
"title": dict(Reservation.TYPE_CHOICES).get(reservation.salle),
"date": reservation.date_debut,
"start": reservation.heure_debut,
"end": reservation.heure_fin,
"color": color,
})
return JsonResponse(liste_reservation, safe=False)
@login_required
def liste_reservation_attente(request):
reservations = Reservation.objects.filter(statut="en_attente")
liste_reservation = [
{
**model_to_dict(reservation),
"employe": f"{reservation.employe.user.first_name} {reservation.employe.user.last_name}",
"salle": dict(Reservation.TYPE_CHOICES).get(reservation.salle)
} 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,
'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'),
'motif_reservation': reservation.motif_reservation,
'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)
@login_required
def ajouter_lien_zoom(request:HttpRequest):
"""Vue de gestion de l'ajout du lien zoom"""
if request.method == 'POST':
reservation_id= request.POST['id_reservation']
try:
reservation = Reservation.objects.get(id=reservation_id)
except reservation.DoesNotExist:
messages.error(request, "La resevertion selectionné n'existe pas.")
return redirect("salle")
if not (reservation.besoin_zoom or reservation.salle == "lien_zoom"):
messages.error(request, "Cette réservation ne nécessite pas de lien Zoom.")
return redirect('gestion_salle:reservation-salle')
elif reservation.statut in ["annulee", "refusee"]:
messages.error(request, "Le lien Zoom ne peut être ajouté pour les réservations annulée ou refusée.")
return redirect('gestion_salle:reservation-salle')
if request.method == "POST":
lien = request.POST.get("lien_zoom")
reservation.lien_zoom = lien
reservation.statut = "validee"
reservation.save()
messages.success(request, "Le lien Zoom a été ajouté et la réservation a été validée. ")
return redirect('gestion_salle:reservation-salle')
@login_required
def annuler_reservation(request:HttpRequest):
"""Vue de gestion de l'annulation de la reservation"""
if request.method == 'POST':
reservation_id= request.POST['id_reservation']
try:
reservation = Reservation.objects.get(id=reservation_id)
except Reservation.DoesNotExist:
messages.error(request, "La resevertion selectionné n'existe pas.")
return redirect("salle")
reservation.statut = 'annulee'
reservation.save()
messages.success(request, "Votre réservation a été annulée.")
return redirect('gestion_salle:reservation-salle')
@login_required
def valider_reservation(request:HttpRequest):
"""Vue de gestion de l'annulation de la reservation"""
if request.method == 'POST':
reservation_id= request.POST['id_reservation']
try:
reservation = Reservation.objects.get(id=reservation_id)
except reservation.DoesNotExist:
messages.error(request, "La resevertion selectionné n'existe pas.")
return redirect("salle")
reservation.statut = 'validee'
reservation.save()
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")
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"
reservation.save()
return JsonResponse({"message": "Réservation refusée avec succès."})