Compare commits
7 Commits
feature/ni
...
d09154ef9a
| Author | SHA1 | Date | |
|---|---|---|---|
| d09154ef9a | |||
|
|
0abbb26149 | ||
| 65497cd669 | |||
| f061f482d9 | |||
| 622b412a21 | |||
| 54dc65f0d8 | |||
|
|
29a42ee6be |
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.
@@ -15,6 +15,21 @@ try:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
EMAIL_EQUIPE_INFORMATIQUE = list(
|
||||||
|
Employe.objects.filter(departement__nom="Systeme informatique").values_list('user__email', flat=True)
|
||||||
|
) or ["support@cerfig.org"]
|
||||||
|
except:
|
||||||
|
EMAIL_EQUIPE_INFORMATIQUE = ["support@cerfig.org"]
|
||||||
|
|
||||||
|
def est_equipe_informatique(employe):
|
||||||
|
"""Vérifie si un employé appartient au département informatique"""
|
||||||
|
return employe.departement and employe.departement.nom == "Systeme informatique"
|
||||||
|
|
||||||
|
def est_assistante_direction(employe):
|
||||||
|
"""Vérifie si un employé est l'assistante de direction"""
|
||||||
|
return employe.fonction == "assistant_direction"
|
||||||
|
|
||||||
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é"""
|
||||||
contrat = Contrat.objects.filter(employe=employe, statut='actif').order_by('-date_debut').first()
|
contrat = Contrat.objects.filter(employe=employe, statut='actif').order_by('-date_debut').first()
|
||||||
|
|||||||
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.
@@ -2,6 +2,34 @@ const $ = (element) => document.getElementById(element);
|
|||||||
|
|
||||||
const url_liste_conge_attente = $("liste-demande-conges").dataset.url
|
const url_liste_conge_attente = $("liste-demande-conges").dataset.url
|
||||||
|
|
||||||
|
function supprimerDemandeConge(congeId) {
|
||||||
|
if (!window.confirm("Voulez-vous vraiment supprimer cette demande de congé en attente ?")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = $("form-detail-conge");
|
||||||
|
const csrftoken = new FormData(form).get("csrfmiddlewaretoken");
|
||||||
|
const url = $("bouton-supprimer-demande-conge").dataset.url.replace(
|
||||||
|
"/0/",
|
||||||
|
`/${congeId}/`
|
||||||
|
);
|
||||||
|
|
||||||
|
fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {"X-CSRFToken": csrftoken},
|
||||||
|
})
|
||||||
|
.then(response => response.json().then(data => ({response, data})))
|
||||||
|
.then(({response, data}) => {
|
||||||
|
window.alert(data.message);
|
||||||
|
if (response.ok && data.success) {
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
window.alert("La suppression a échoué. Veuillez réessayer.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
||||||
columns: [
|
columns: [
|
||||||
{"title": "Nom et Prénom", "field": "prenom_nom"},
|
{"title": "Nom et Prénom", "field": "prenom_nom"},
|
||||||
@@ -21,12 +49,31 @@ const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
|||||||
{"title": "Validation par supérieur hiérarchique", "field": "validation_direction", formatter:"tickCross", formatterParams :{
|
{"title": "Validation par supérieur hiérarchique", "field": "validation_direction", formatter:"tickCross", formatterParams :{
|
||||||
allowEmpty : true ,
|
allowEmpty : true ,
|
||||||
}},
|
}},
|
||||||
|
{
|
||||||
|
title: "Action",
|
||||||
|
hozAlign: "center",
|
||||||
|
formatter: (cell) => {
|
||||||
|
const data = cell.getRow().getData();
|
||||||
|
if (!data.est_proprietaire || !data.en_attente) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return '<button type="button" class="btn btn-danger btn-sm">Supprimer</button>';
|
||||||
|
},
|
||||||
|
cellClick: (event, cell) => {
|
||||||
|
const data = cell.getRow().getData();
|
||||||
|
if (data.est_proprietaire && data.en_attente) {
|
||||||
|
event.stopPropagation();
|
||||||
|
supprimerDemandeConge(data.id);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
pagination: true,
|
pagination: true,
|
||||||
paginationSize: 5,
|
paginationSize: 5,
|
||||||
})
|
})
|
||||||
|
|
||||||
const bouton_demande_conges = $("bouton-demande-conge");
|
const bouton_demande_conges = $("bouton-demande-conge");
|
||||||
|
const bouton_supprimer_conge = $("bouton-supprimer-demande-conge");
|
||||||
|
|
||||||
bouton_demande_conges.addEventListener("click", (e) => {
|
bouton_demande_conges.addEventListener("click", (e) => {
|
||||||
var modalDemandeConge = new bootstrap.Modal(document.getElementById('modalDemandeConge'));
|
var modalDemandeConge = new bootstrap.Modal(document.getElementById('modalDemandeConge'));
|
||||||
@@ -44,6 +91,11 @@ tableau_liste_demande_conge.on("rowClick", function(row, rowData) {
|
|||||||
$("nombre_jours").value = data.nombre_jours;
|
$("nombre_jours").value = data.nombre_jours;
|
||||||
$("solde_restant").value = data.solde_conge;
|
$("solde_restant").value = data.solde_conge;
|
||||||
$("motif_refus").value = data.motif_refus;
|
$("motif_refus").value = data.motif_refus;
|
||||||
|
bouton_supprimer_conge.classList.toggle(
|
||||||
|
"d-none",
|
||||||
|
!(data.est_proprietaire && data.en_attente)
|
||||||
|
);
|
||||||
|
bouton_supprimer_conge.dataset.congeId = data.id;
|
||||||
|
|
||||||
if($("validation_hierarchique_valide") & $("validation_hierarchique_refuse")){
|
if($("validation_hierarchique_valide") & $("validation_hierarchique_refuse")){
|
||||||
$("validation_hierarchique_valide").checked = data.validation_hierarchique === true;
|
$("validation_hierarchique_valide").checked = data.validation_hierarchique === true;
|
||||||
@@ -59,6 +111,10 @@ tableau_liste_demande_conge.on("rowClick", function(row, rowData) {
|
|||||||
modal.show();
|
modal.show();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
bouton_supprimer_conge.addEventListener("click", () => {
|
||||||
|
supprimerDemandeConge(bouton_supprimer_conge.dataset.congeId);
|
||||||
|
});
|
||||||
|
|
||||||
fetch(url_liste_conge_attente)
|
fetch(url_liste_conge_attente)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
|||||||
@@ -83,6 +83,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
||||||
|
{% if conge.validation_hierarchique == None and conge.validation_direction == None%}
|
||||||
|
<button type="button" class="btn btn-danger " id="bouton-supprimer-demande-conge"
|
||||||
|
data-url="{% url 'gestion_conges:supprimer-demande-conge' 0 %}"
|
||||||
|
>
|
||||||
|
Supprimer ma demande
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
{% if employe_est_il_chef or membre_de_la_direction or est_chef_projet %}
|
{% if employe_est_il_chef or membre_de_la_direction or est_chef_projet %}
|
||||||
<button type="button" class="btn btn-success" id="bouton-enregistrer-detail-conge">Enregistrer</button>
|
<button type="button" class="btn btn-success" id="bouton-enregistrer-detail-conge">Enregistrer</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -24,4 +24,9 @@ urlpatterns = [
|
|||||||
views.validation_de_conge,
|
views.validation_de_conge,
|
||||||
name='validation-des-conges'
|
name='validation-des-conges'
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
'demande/<int:conge_id>/supprimer/',
|
||||||
|
views.supprimer_demande_conge,
|
||||||
|
name='supprimer-demande-conge',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
@@ -235,3 +235,55 @@ def validation_de_conge(request):
|
|||||||
|
|
||||||
conge.save()
|
conge.save()
|
||||||
return JsonResponse({"message": "La décision a été enregistrée avec succès."})
|
return JsonResponse({"message": "La décision a été enregistrée avec succès."})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _conge_est_en_attente(conge):
|
||||||
|
return (
|
||||||
|
conge.validation_hierarchique is not False
|
||||||
|
and conge.validation_direction is not False
|
||||||
|
and not (
|
||||||
|
conge.validation_hierarchique is True
|
||||||
|
and conge.validation_direction is True
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
def supprimer_demande_conge(request, conge_id):
|
||||||
|
if request.method != "POST":
|
||||||
|
return JsonResponse(
|
||||||
|
{"success": False, "message": "Méthode non autorisée."},
|
||||||
|
status=405,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
employe = Employe.objects.get(user=request.user)
|
||||||
|
except Employe.DoesNotExist:
|
||||||
|
return JsonResponse(
|
||||||
|
{"success": False, "message": "Profil employé introuvable."},
|
||||||
|
status=403,
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
conge = Conge.objects.get(pk=conge_id, employe=employe)
|
||||||
|
except Conge.DoesNotExist:
|
||||||
|
return JsonResponse(
|
||||||
|
{"success": False, "message": "Demande introuvable ou accès non autorisé."},
|
||||||
|
status=404,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not _conge_est_en_attente(conge):
|
||||||
|
return JsonResponse(
|
||||||
|
{
|
||||||
|
"success": False,
|
||||||
|
"message": "Seules les demandes en attente peuvent être supprimées.",
|
||||||
|
},
|
||||||
|
status=400,
|
||||||
|
)
|
||||||
|
|
||||||
|
conge.delete()
|
||||||
|
return JsonResponse(
|
||||||
|
{"success": True, "message": "Votre demande de congé en attente a été supprimée."}
|
||||||
|
)
|
||||||
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -9,7 +9,6 @@ const tableau_liste_employe = new Tabulator("#tableau_liste_employe", {
|
|||||||
{"title": "Projet", "field": "projet"},
|
{"title": "Projet", "field": "projet"},
|
||||||
{"title": "Téléphone", "field": "telephone"},
|
{"title": "Téléphone", "field": "telephone"},
|
||||||
],
|
],
|
||||||
// ajaxURL: url_liste_employe,
|
|
||||||
pagination: true,
|
pagination: true,
|
||||||
paginationSize: 10,
|
paginationSize: 10,
|
||||||
responsiveLayout : "hide"
|
responsiveLayout : "hide"
|
||||||
@@ -19,7 +18,6 @@ fetch(url_liste_employe)
|
|||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success){
|
if (data.success){
|
||||||
console.log(data.data)
|
|
||||||
tableau_liste_employe.setData(data.data);
|
tableau_liste_employe.setData(data.data);
|
||||||
}else{
|
}else{
|
||||||
alert(data.message);
|
alert(data.message);
|
||||||
@@ -29,7 +27,6 @@ fetch(url_liste_employe)
|
|||||||
|
|
||||||
tableau_liste_employe.on("rowClick", function (row, rowData) {
|
tableau_liste_employe.on("rowClick", function (row, rowData) {
|
||||||
const data = rowData.getData();
|
const data = rowData.getData();
|
||||||
console.log('Employé cliqué:', data);
|
|
||||||
|
|
||||||
document.getElementById('detail-id').value = data.id;
|
document.getElementById('detail-id').value = data.id;
|
||||||
document.getElementById('detail-matricule').value = data.matricule;
|
document.getElementById('detail-matricule').value = data.matricule;
|
||||||
@@ -215,16 +212,9 @@ $("enregistrerDetail").addEventListener("click", function() {
|
|||||||
const matricule = document.getElementById('detail-matricule').value;
|
const matricule = document.getElementById('detail-matricule').value;
|
||||||
const departement = document.getElementById('detail-departement').value;
|
const departement = document.getElementById('detail-departement').value;
|
||||||
|
|
||||||
console.log('=== ENREGISTREMENT DÉTAILS ===');
|
const url_enregistrer_detail = document.getElementById("modalDetailEmployeBody").dataset.url;
|
||||||
console.log('ID:', id_);
|
|
||||||
console.log('Fonction:', fonction);
|
|
||||||
console.log('Date embauche:', dateEmbauche);
|
|
||||||
console.log('Matricule:', matricule);
|
|
||||||
console.log('Département (valeur brute):', departement);
|
|
||||||
console.log('Département (type):', typeof departement);
|
|
||||||
console.log('Département est vide:', !departement);
|
|
||||||
|
|
||||||
const url_enregistrer_detail = $("modalDetailEmployeBody").dataset.url;
|
console.log("Le lien de l'enregistrement :", document.getElementById("modalDetailEmployeBody").dataset)
|
||||||
|
|
||||||
const payload = {
|
const payload = {
|
||||||
"id": id_,
|
"id": id_,
|
||||||
@@ -234,9 +224,6 @@ $("enregistrerDetail").addEventListener("click", function() {
|
|||||||
"departement": departement
|
"departement": departement
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Payload JSON:', payload);
|
|
||||||
console.log('Payload stringifié:', JSON.stringify(payload));
|
|
||||||
|
|
||||||
fetch(url_enregistrer_detail, {
|
fetch(url_enregistrer_detail, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -283,15 +270,12 @@ const listeContratExpirant = new Tabulator("#listeContratExpirant", {
|
|||||||
ajaxURL: $("boutonContratExpirants").dataset.urlexpirants,
|
ajaxURL: $("boutonContratExpirants").dataset.urlexpirants,
|
||||||
})
|
})
|
||||||
|
|
||||||
let tabContrats = null;
|
/* let tabContrats = null;
|
||||||
|
|
||||||
document.getElementById("modalContratsEmploye")
|
document.getElementById("modalContratsEmploye").addEventListener("show.bs.modal", function () {
|
||||||
.addEventListener("show.bs.modal", function () {
|
|
||||||
|
|
||||||
const employeId = document.getElementById("detail-id").value;
|
const employeId = document.getElementById("detail-id").value;
|
||||||
|
|
||||||
console.log("Employe ID :", employeId);
|
|
||||||
|
|
||||||
if (!employeId) {
|
if (!employeId) {
|
||||||
alert("Aucun employé sélectionné");
|
alert("Aucun employé sélectionné");
|
||||||
return;
|
return;
|
||||||
@@ -350,4 +334,4 @@ document.getElementById("modalContratsEmploye")
|
|||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error("Erreur :", error);
|
console.error("Erreur :", error);
|
||||||
});
|
});
|
||||||
});
|
}); */
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
</h5>
|
</h5>
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body" id="modalDetailEmployeBody">
|
<div class="modal-body" id="modalDetailEmployeBody" data-url="{% url 'gestion_employe:enregistrer-detail-employe' %}">
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<input type="hidden" id="detail-id">
|
<input type="hidden" id="detail-id">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|||||||
Binary file not shown.
@@ -3,8 +3,8 @@ from datetime import datetime, timedelta
|
|||||||
|
|
||||||
import requests
|
import requests
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
|
from decouple import config
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.contrib.auth import logout
|
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.password_validation import validate_password
|
from django.contrib.auth.password_validation import validate_password
|
||||||
@@ -27,6 +27,18 @@ def index(request):
|
|||||||
if not request.user.groups.filter(name="ressource_humaine").exists():
|
if not request.user.groups.filter(name="ressource_humaine").exists():
|
||||||
return redirect('gestion_employe:mon-profil')
|
return redirect('gestion_employe:mon-profil')
|
||||||
|
|
||||||
|
response = requests.get(f"{config('SERVEUR_AUTHENTIFICATION')}recuperer-list-departement/")
|
||||||
|
|
||||||
|
if response.status_code == 200:
|
||||||
|
try:
|
||||||
|
departements_data = response.json()
|
||||||
|
for dept in departements_data:
|
||||||
|
Departement.objects.update_or_create(
|
||||||
|
nom = dept['nom']
|
||||||
|
)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"[ERROR] Erreur lors du décodage JSON : {e}")
|
||||||
|
|
||||||
employes = Employe.objects.all().order_by('-user__date_joined')
|
employes = Employe.objects.all().order_by('-user__date_joined')
|
||||||
nombre_employes = Employe.objects.count()
|
nombre_employes = Employe.objects.count()
|
||||||
nombre_cps = Contrat.objects.filter(type_contrat='contrat_prestation').count()
|
nombre_cps = Contrat.objects.filter(type_contrat='contrat_prestation').count()
|
||||||
@@ -341,9 +353,6 @@ def enregistrer_detail_employe(request):
|
|||||||
|
|
||||||
# Traiter le département
|
# Traiter le département
|
||||||
dept_value = data.get('departement')
|
dept_value = data.get('departement')
|
||||||
print(f"[DEBUG] Département brut: {dept_value!r}")
|
|
||||||
print(f"[DEBUG] Type département: {type(dept_value).__name__}")
|
|
||||||
print(f"[DEBUG] Est vide: {not dept_value}")
|
|
||||||
|
|
||||||
if dept_value and str(dept_value).strip():
|
if dept_value and str(dept_value).strip():
|
||||||
try:
|
try:
|
||||||
@@ -521,7 +530,7 @@ def modifier_mot_passe(request):
|
|||||||
}
|
}
|
||||||
|
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
"http://localhost:8000/modifier-mot-de-passe/",
|
f"{config('SERVEUR_AUTHENTIFICATION')}modifier-mot-de-passe/",
|
||||||
json=donnees,
|
json=donnees,
|
||||||
headers=headers
|
headers=headers
|
||||||
)
|
)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -22,7 +22,6 @@ class ProjetForm(forms.ModelForm):
|
|||||||
'date_fin',
|
'date_fin',
|
||||||
'numero_convention',
|
'numero_convention',
|
||||||
'domaine_recherche',
|
'domaine_recherche',
|
||||||
'type_projet',
|
|
||||||
'budget',
|
'budget',
|
||||||
'budget_RH',
|
'budget_RH',
|
||||||
'description'
|
'description'
|
||||||
@@ -37,7 +36,6 @@ class ProjetForm(forms.ModelForm):
|
|||||||
'nom_projet': forms.TextInput(attrs={'class': "form-control"}),
|
'nom_projet': forms.TextInput(attrs={'class': "form-control"}),
|
||||||
'numero_convention': forms.TextInput(attrs={'class': "form-control"}),
|
'numero_convention': forms.TextInput(attrs={'class': "form-control"}),
|
||||||
'domaine_recherche': forms.SelectMultiple(attrs={'class': "form-control"}),
|
'domaine_recherche': forms.SelectMultiple(attrs={'class': "form-control"}),
|
||||||
'type_projet': forms.Select(attrs={'class': "form-select"}),
|
|
||||||
'budget': forms.NumberInput(attrs={'class': "form-control"}),
|
'budget': forms.NumberInput(attrs={'class': "form-control"}),
|
||||||
'budget_RH': forms.NumberInput(attrs={'class': "form-control"}),
|
'budget_RH': forms.NumberInput(attrs={'class': "form-control"}),
|
||||||
'description': forms.Textarea(attrs={'class': "form-control"}),
|
'description': forms.Textarea(attrs={'class': "form-control"}),
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
from datetime import datetime
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
@@ -33,9 +31,11 @@ class DomaineDeRecherche(models.Model):
|
|||||||
|
|
||||||
DOMAINE_RECHERCHE = (
|
DOMAINE_RECHERCHE = (
|
||||||
('sciences_sociales', 'Sciences sociales'),
|
('sciences_sociales', 'Sciences sociales'),
|
||||||
('naturelles', 'Naturelles'),
|
|
||||||
('humaines', 'Humaines'),
|
('humaines', 'Humaines'),
|
||||||
('veterinaires', 'Vétérinaires')
|
('epidemiologie', 'Epidémiologie'),
|
||||||
|
('sciences_biomedicales', 'Sciences biomédicales'),
|
||||||
|
('service_pedagogique', 'Service Pédagogique'),
|
||||||
|
('recherche_clinique', 'Recherche clinique')
|
||||||
)
|
)
|
||||||
|
|
||||||
nom = models.CharField(
|
nom = models.CharField(
|
||||||
@@ -54,13 +54,6 @@ class DomaineDeRecherche(models.Model):
|
|||||||
|
|
||||||
class Projet(models.Model):
|
class Projet(models.Model):
|
||||||
"""Modèle représentant un projet de recherche avec ses caractéristiques et son bailleur associé."""
|
"""Modèle représentant un projet de recherche avec ses caractéristiques et son bailleur associé."""
|
||||||
TYPE_PROJET = (
|
|
||||||
('laboratoire', 'Laboratoire'),
|
|
||||||
('épidémiologie', 'Épidémiologie'),
|
|
||||||
('sciences sociales', 'Sciences sociales'),
|
|
||||||
('cliniques', 'Cliniques'),
|
|
||||||
('autre', 'Autre'),
|
|
||||||
)
|
|
||||||
|
|
||||||
id_projet = models.CharField(
|
id_projet = models.CharField(
|
||||||
max_length=100,
|
max_length=100,
|
||||||
@@ -86,12 +79,6 @@ class Projet(models.Model):
|
|||||||
description = models.TextField(
|
description = models.TextField(
|
||||||
verbose_name="Description"
|
verbose_name="Description"
|
||||||
)
|
)
|
||||||
type_projet = models.CharField(
|
|
||||||
max_length=100,
|
|
||||||
choices=TYPE_PROJET,
|
|
||||||
default='épidémiologie',
|
|
||||||
verbose_name="Type de projet"
|
|
||||||
)
|
|
||||||
domaine_recherche = models.ManyToManyField(DomaineDeRecherche)
|
domaine_recherche = models.ManyToManyField(DomaineDeRecherche)
|
||||||
budget=models.DecimalField(
|
budget=models.DecimalField(
|
||||||
max_digits=12,
|
max_digits=12,
|
||||||
@@ -114,13 +101,13 @@ class Projet(models.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def statut(self):
|
def statut(self):
|
||||||
if self.date_fin < datetime.date.today():
|
if self.date_fin < timezone.now().date():
|
||||||
return "Terminé"
|
return "Terminé"
|
||||||
return "En cours"
|
return "En cours"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def avancement(self):
|
def avancement(self):
|
||||||
aujourd_hui = datetime.date.today()
|
aujourd_hui = timezone.now().date()
|
||||||
if (self.date_debut and self.date_fin) and (self.date_debut < self.date_fin):
|
if (self.date_debut and self.date_fin) and (self.date_debut < self.date_fin):
|
||||||
duree_projet = (self.date_fin - self.date_debut).days
|
duree_projet = (self.date_fin - self.date_debut).days
|
||||||
temps_ecoule = (aujourd_hui - self.date_debut).days
|
temps_ecoule = (aujourd_hui - self.date_debut).days
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const $ = (element) => document.getElementById(element)
|
const $ = (element) => document.getElementById(element)
|
||||||
const url_liste_projet = $("tableau-liste-projet").dataset.url;
|
const url_liste_projet = $("tableau-liste-projet").dataset.url;
|
||||||
|
|
||||||
const tableau_liste_projet = new Tabulator("#tableau-liste-projet", {
|
const tableau_liste_projet = new Tabulator("#tableau-liste-projet", {
|
||||||
fitColumns: true,
|
fitColumns: true,
|
||||||
responsiveLayout : true,
|
responsiveLayout : true,
|
||||||
@@ -39,7 +40,6 @@ tableau_liste_projet.on("rowClick", function (row, rowData) {
|
|||||||
$("detail_date_debut").value = data.date_debut;
|
$("detail_date_debut").value = data.date_debut;
|
||||||
$("detail_date_fin").value = data.date_fin;
|
$("detail_date_fin").value = data.date_fin;
|
||||||
$("detail_numero_convention").value = data.numero_convention;
|
$("detail_numero_convention").value = data.numero_convention;
|
||||||
$("detail_type_projet").value = data.type_projet;
|
|
||||||
Array.from($("detail_domaine_recherche").options).forEach(option => {
|
Array.from($("detail_domaine_recherche").options).forEach(option => {
|
||||||
if (data.domaine_recherche.includes(option.value)) {
|
if (data.domaine_recherche.includes(option.value)) {
|
||||||
option.selected = true;
|
option.selected = true;
|
||||||
|
|||||||
@@ -31,23 +31,15 @@
|
|||||||
<label>Date de fin :</label>
|
<label>Date de fin :</label>
|
||||||
<input type="date" class="form-control" id="detail_date_fin" name='date_fin'>
|
<input type="date" class="form-control" id="detail_date_fin" name='date_fin'>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group mb-2">
|
|
||||||
<label> Type de projet </label>
|
|
||||||
<select class="form-select" id="detail_type_projet" name='type_projet'>
|
|
||||||
<option value="laboratoire">Laboratoire</option>
|
|
||||||
<option value="épidémiologie">Épidémiologie</option>
|
|
||||||
<option value="sciences sociales">Sciences sociales</option>
|
|
||||||
<option value="cliniques">Cliniques</option>
|
|
||||||
<option value="autre">Autre</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="form-group mb-2">
|
<div class="form-group mb-2">
|
||||||
<label> Domaine de recherche </label>
|
<label> Domaine de recherche </label>
|
||||||
<select class="form-select" multiple id="detail_domaine_recherche" name="domaine_recherche">
|
<select class="form-select" multiple id="detail_domaine_recherche" name="domaine_recherche">
|
||||||
<option value="sciences_sociales">Sciences sociales</option>
|
<option value="sciences_sociales">Sciences sociales</option>
|
||||||
<option value="naturelles">Naturelles</option>
|
|
||||||
<option value="humaines">Humaines</option>
|
<option value="humaines">Humaines</option>
|
||||||
<option value="veterinaires">Vétérinaires</option>
|
<option value="epidemiologie">Epidémiologie</option>
|
||||||
|
<option value="sciences_biomedicales">Sciences biomédicales</option>
|
||||||
|
<option value="service_pedagogique">Service Pédagogique</option>
|
||||||
|
<option value="recherche_clinique">Recherche clinique</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group mb-2">
|
<div class="form-group mb-2">
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ def liste_projet(request):
|
|||||||
"date_fin": p.date_fin,
|
"date_fin": p.date_fin,
|
||||||
"numero_convention": p.numero_convention,
|
"numero_convention": p.numero_convention,
|
||||||
"description": p.description,
|
"description": p.description,
|
||||||
"type_projet": p.type_projet,
|
|
||||||
"budget": p.budget,
|
"budget": p.budget,
|
||||||
"budget_RH": p.budget_RH,
|
"budget_RH": p.budget_RH,
|
||||||
"created_at": p.created_at,
|
"created_at": p.created_at,
|
||||||
|
|||||||
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.
@@ -1,3 +1 @@
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
|
|||||||
@@ -92,9 +92,6 @@ $("bouton-annuler").addEventListener("click", (e) => {
|
|||||||
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
|
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
|
||||||
const url_annuler = $("formulaire-details").dataset.urlannuler;
|
const url_annuler = $("formulaire-details").dataset.urlannuler;
|
||||||
|
|
||||||
console.log("URL d'annulation :");
|
|
||||||
console.log($("formulaire-details"))
|
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
fetch(
|
fetch(
|
||||||
@@ -189,7 +186,7 @@ tableau_reservation_attente.on("rowClick", (row, rowData) => {
|
|||||||
$("lien_zoom_container").className = 'd-none';
|
$("lien_zoom_container").className = 'd-none';
|
||||||
}
|
}
|
||||||
|
|
||||||
const id_user = $("current-user-id").dataset.userid;
|
const id_user = $("current-user-id").dataset.userId;
|
||||||
|
|
||||||
$("id_reservation_detail").value = data.id;
|
$("id_reservation_detail").value = data.id;
|
||||||
$("id_reservation_refus").value = data.id;
|
$("id_reservation_refus").value = data.id;
|
||||||
@@ -206,8 +203,6 @@ tableau_reservation_attente.on("rowClick", (row, rowData) => {
|
|||||||
$("besoin_ordinateur").checked=data.besoin_ordi;
|
$("besoin_ordinateur").checked=data.besoin_ordi;
|
||||||
$("lien_zoom").value=data.lien_zoom;
|
$("lien_zoom").value=data.lien_zoom;
|
||||||
|
|
||||||
console.log("Verification de data :", data);
|
|
||||||
|
|
||||||
const refuserReservation = document.querySelector("#refuserReservation");
|
const refuserReservation = document.querySelector("#refuserReservation");
|
||||||
const bouton_valider = document.querySelector("#bouton-valider");
|
const bouton_valider = document.querySelector("#bouton-valider");
|
||||||
|
|
||||||
|
|||||||
@@ -50,15 +50,19 @@
|
|||||||
<input type="checkbox" class="form-check-input" id="besoin_ordinateur" readonly >
|
<input type="checkbox" class="form-check-input" id="besoin_ordinateur" readonly >
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
<div class='d-flex justify-content-around mt-2'>
|
<div class='d-flex justify-content-center mt-2'>
|
||||||
{% if appartient_au_departement_informatique %}
|
{% if est_equipe_informatique %}
|
||||||
<button class="btn btn-primary" id="ajoutZoom">Ajout du lien zoom</button>
|
<button class="btn btn-primary me-1" id="ajoutZoom">Ajout du lien zoom</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if appartient_direction %}
|
{% if est_assistante_direction %}
|
||||||
<button class="btn btn-danger" id="refuserReservation" data-lienrefus="{% url 'gestion_salle:refuser-reservation' %}">Refuser</button>
|
<button class="btn btn-danger me-1" id="refuserReservation" data-lienrefus="{% url 'gestion_salle:refuser-reservation' %}">Refuser</button>
|
||||||
<button class="btn btn-success" id="bouton-valider">Valider</button>
|
<button class="btn btn-success me-1" id="bouton-valider">Valider</button>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span id="current-user-id" data-user-id="{{ request.user.id }}"></span>
|
{% if est_equipe_informatique %}
|
||||||
|
<button class="btn btn-danger me-1" id="refuserReservationInfo" data-lienrefus="{% url 'gestion_salle:refuser-reservation' %}">Refuser</button>
|
||||||
|
<button class="btn btn-success me-1" id="bouton-valider-info">Valider</button>
|
||||||
|
{% endif %}
|
||||||
|
<span id="current-user-id" data-user-id="{{ user.id }}"></span>
|
||||||
<button class="btn btn-danger" id="bouton-annuler">Annuler</button>
|
<button class="btn btn-danger" id="bouton-annuler">Annuler</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ 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.db.models import Q
|
||||||
from django.forms import model_to_dict
|
from django.forms import model_to_dict
|
||||||
from django.http import HttpRequest, JsonResponse
|
from django.http import HttpRequest, JsonResponse
|
||||||
from django.shortcuts import redirect, render
|
from django.shortcuts import redirect, render
|
||||||
@@ -16,13 +17,16 @@ from .models import Reservation
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def index(request: HttpRequest):
|
def index(request: HttpRequest):
|
||||||
|
"""Vue d'affichage de la page d'accueil de la gestion des salles"""
|
||||||
try:
|
try:
|
||||||
employe = Employe.objects.get(user=request.user)
|
employe = Employe.objects.get(user=request.user)
|
||||||
except Employe.DoesNotExist:
|
except Employe.DoesNotExist:
|
||||||
messages.error(request, "Profil employé introuvable.")
|
messages.error(request, "Profil employé introuvable.")
|
||||||
return redirect('gestion_conges:conge')
|
return redirect('gestion_conges:conge')
|
||||||
|
|
||||||
|
est_equipe_info = fonctions_utilitaire.est_equipe_informatique(employe)
|
||||||
|
est_assistante = fonctions_utilitaire.est_assistante_direction(employe)
|
||||||
|
|
||||||
if request.method == "POST":
|
if request.method == "POST":
|
||||||
form = ReservationForm(request.POST)
|
form = ReservationForm(request.POST)
|
||||||
|
|
||||||
@@ -37,11 +41,11 @@ def index(request: HttpRequest):
|
|||||||
besoin_ordi = form.cleaned_data['besoin_ordi']
|
besoin_ordi = form.cleaned_data['besoin_ordi']
|
||||||
|
|
||||||
if date_fin < date_debut:
|
if date_fin < date_debut:
|
||||||
messages.error(request, "Date fin invalide.")
|
messages.error(request, "La date de fin est antérieure à la date de début.")
|
||||||
return redirect('gestion_salle:reservation-salle')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
if heure_fin <= heure_debut:
|
if heure_fin <= heure_debut:
|
||||||
messages.error(request, "Heure invalide.")
|
messages.error(request, "L'heure de fin est antérieure à l'heure de début.")
|
||||||
return redirect('gestion_salle:reservation-salle')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
if not request.user.first_name.strip() or not request.user.last_name.strip():
|
if not request.user.first_name.strip() or not request.user.last_name.strip():
|
||||||
@@ -54,8 +58,9 @@ def index(request: HttpRequest):
|
|||||||
created = []
|
created = []
|
||||||
current_date = date_debut
|
current_date = date_debut
|
||||||
|
|
||||||
while current_date <= date_fin:
|
print(f"Création de réservations pour {employe}")
|
||||||
|
|
||||||
|
while current_date <= date_fin:
|
||||||
reservation = Reservation.objects.create(
|
reservation = Reservation.objects.create(
|
||||||
employe=employe,
|
employe=employe,
|
||||||
date_debut=current_date,
|
date_debut=current_date,
|
||||||
@@ -74,18 +79,35 @@ def index(request: HttpRequest):
|
|||||||
|
|
||||||
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:
|
# Nouvelle logique d'envoi de mails à la création :
|
||||||
|
# 1. Une demande de salle (formation/réunion) est envoyée à l'assistante de direction pour validation.
|
||||||
|
# - Si elle nécessite un lien Zoom ou un ordinateur, l'équipe informatique sera notifiée
|
||||||
|
# seulement après la validation par l'assistante.
|
||||||
|
# 2. Une demande de lien Zoom directement est envoyée à l'équipe informatique.
|
||||||
|
if salle != "lien_zoom" and fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION:
|
||||||
fonctions_utilitaire.envoyer_mail(
|
fonctions_utilitaire.envoyer_mail(
|
||||||
sujet = "Reservation de salle",
|
sujet="Demande de réservation de salle",
|
||||||
message = f"""
|
message=f"""Bonjour,
|
||||||
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}".
|
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}".
|
||||||
|
{"Cette demande nécessite un lien Zoom et/ou un ordinateur et sera traitée par l'équipe informatique après votre validation." if besoin_zoom or besoin_ordi else ""}
|
||||||
Veuillez vous connecter à la plateforme pour plus de détails.""",
|
Veuillez vous connecter à la plateforme pour plus de détails.""",
|
||||||
destinataires=fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION
|
destinataires=fonctions_utilitaire.EMAIL_ASSISTANTE_DE_DIRECTION
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if salle == "lien_zoom" and fonctions_utilitaire.EMAIL_EQUIPE_INFORMATIQUE:
|
||||||
|
fonctions_utilitaire.envoyer_mail(
|
||||||
|
sujet="Demande de lien Zoom",
|
||||||
|
message=f"""Bonjour,
|
||||||
|
Une nouvelle demande de lien Zoom a été effectuée par {employe.user.first_name} {employe.user.last_name} du {date_debut.strftime('%d/%m/%Y')} au {date_fin.strftime('%d/%m/%Y')} de {heure_debut.strftime('%H:%M')} à {heure_fin.strftime('%H:%M')} pour le motif {motif}.
|
||||||
|
|
||||||
|
Veuillez vous connecter à la plateforme pour traiter cette demande.""",
|
||||||
|
destinataires=fonctions_utilitaire.EMAIL_EQUIPE_INFORMATIQUE
|
||||||
|
)
|
||||||
return redirect('gestion_salle:reservation-salle')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
|
|
||||||
formulaire_reservation = ReservationForm()
|
formulaire_reservation = ReservationForm()
|
||||||
departement = employe.departement
|
# departement = employe.departement
|
||||||
|
|
||||||
liste_demande_reservation = Reservation.objects.filter(
|
liste_demande_reservation = Reservation.objects.filter(
|
||||||
employe=employe,
|
employe=employe,
|
||||||
@@ -95,8 +117,9 @@ Veuillez vous connecter à la plateforme pour plus de détails.""",
|
|||||||
context = {
|
context = {
|
||||||
'formulaire_reservation': formulaire_reservation,
|
'formulaire_reservation': formulaire_reservation,
|
||||||
'nb_reservation_attente': Reservation.objects.filter(statut='en_attente').count(),
|
'nb_reservation_attente': Reservation.objects.filter(statut='en_attente').count(),
|
||||||
'appartient_au_departement_informatique': departement and departement.nom == "Systeme informatique",
|
'appartient_au_departement_informatique': est_equipe_info,
|
||||||
'appartient_direction': request.user.groups.filter(name='direction').exists(),
|
'est_assistante_direction': est_assistante,
|
||||||
|
'est_equipe_informatique': est_equipe_info,
|
||||||
'liste_demande_reservation': list(liste_demande_reservation),
|
'liste_demande_reservation': list(liste_demande_reservation),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +131,6 @@ def liste_reservation(request:HttpRequest):
|
|||||||
liste_reservation = []
|
liste_reservation = []
|
||||||
|
|
||||||
for reservation in reservations:
|
for reservation in reservations:
|
||||||
print(reservation.statut)
|
|
||||||
color = None
|
color = None
|
||||||
if reservation.statut == "en_attente":
|
if reservation.statut == "en_attente":
|
||||||
color = "#ffc107"
|
color = "#ffc107"
|
||||||
@@ -117,8 +139,6 @@ def liste_reservation(request:HttpRequest):
|
|||||||
else:
|
else:
|
||||||
color = "#dc3545"
|
color = "#dc3545"
|
||||||
|
|
||||||
print(dict(Reservation.TYPE_CHOICES).get(reservation.salle))
|
|
||||||
|
|
||||||
liste_reservation.append({
|
liste_reservation.append({
|
||||||
"guid": reservation.pk,
|
"guid": reservation.pk,
|
||||||
"title": dict(Reservation.TYPE_CHOICES).get(reservation.salle),
|
"title": dict(Reservation.TYPE_CHOICES).get(reservation.salle),
|
||||||
@@ -131,7 +151,35 @@ def liste_reservation(request:HttpRequest):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def liste_reservation_attente(request):
|
def liste_reservation_attente(request):
|
||||||
|
"""Liste des réservations en attente, filtrée selon le profil :
|
||||||
|
- Assistante de direction : voit les salles à valider (pas les liens choisis).
|
||||||
|
- Équipe informatique : voit les liens choisis et les salles demandant zoom/ordi non traités.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
employe = Employe.objects.get(user=request.user)
|
||||||
|
except Employe.DoesNotExist:
|
||||||
|
return JsonResponse({"success": False, "message": "Profil employé introuvable"})
|
||||||
|
|
||||||
|
est_informatique = fonctions_utilitaire.est_equipe_informatique(employe)
|
||||||
|
est_assistante = fonctions_utilitaire.est_assistante_direction(employe)
|
||||||
|
|
||||||
reservations = Reservation.objects.filter(statut="en_attente")
|
reservations = Reservation.objects.filter(statut="en_attente")
|
||||||
|
|
||||||
|
if est_assistante:
|
||||||
|
# L'assistante voit les demandes de salle (formation / réunion)
|
||||||
|
# Elle ne reçoit pas les demandes de simple lien (lien_zoom) qui vont à l'équipe info.
|
||||||
|
reservations = reservations.exclude(salle="lien_zoom")
|
||||||
|
elif est_informatique:
|
||||||
|
# L'équipe informatique voit :
|
||||||
|
# - les demandes de lien zoom directs
|
||||||
|
# - les demandes de salle avec besoin_zoom ou besoin_ordi (déjà validés par l'assistance)
|
||||||
|
# pour lesquelles le lien_zoom n'a pas encore était fourni (lien_zoom vide)
|
||||||
|
reservations = reservations.filter(
|
||||||
|
Q(salle="lien_zoom") | Q(besoin_zoom=True) | Q(besoin_ordi=True)
|
||||||
|
)
|
||||||
|
|
||||||
|
print("Test :", [reservation.employe for reservation in reservations])
|
||||||
|
|
||||||
liste_reservation = [
|
liste_reservation = [
|
||||||
{
|
{
|
||||||
**model_to_dict(reservation),
|
**model_to_dict(reservation),
|
||||||
@@ -167,49 +215,99 @@ def detail_reservation(request:HttpRequest, reservation_id:int):
|
|||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def ajouter_lien_zoom(request:HttpRequest):
|
def ajouter_lien_zoom(request:HttpRequest):
|
||||||
"""Vue de gestion de l'ajout du lien zoom"""
|
"""Traitement de la réservation par l'équipe informatique :
|
||||||
|
- Ajoute lien zoom si demandé.
|
||||||
|
- Valide une réservation qui exigeait un traitement par l'équipe informatique.
|
||||||
|
- Envoie un mail à toutes les équipes et au demandeur après validation.
|
||||||
|
"""
|
||||||
|
reservation = None
|
||||||
|
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
reservation_id= request.POST['id_reservation']
|
reservation_id = request.POST.get('id_reservation')
|
||||||
try:
|
try:
|
||||||
reservation = Reservation.objects.get(id=reservation_id)
|
reservation = Reservation.objects.get(id=reservation_id)
|
||||||
except reservation.DoesNotExist:
|
except (Reservation.DoesNotExist, ValueError):
|
||||||
messages.error(request, "La resevertion selectionné n'existe pas.")
|
messages.error(request, "La réservation sélectionnée 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')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
if request.method == "POST":
|
try:
|
||||||
|
employe = Employe.objects.get(user=request.user)
|
||||||
|
except Employe.DoesNotExist:
|
||||||
|
messages.error(request, "Profil employé introuvable.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
|
# Vérification : seule l'équipe informatique peut traiter ces demandes
|
||||||
|
if not fonctions_utilitaire.est_equipe_informatique(employe):
|
||||||
|
messages.error(request, "Vous n'êtes pas autorisé à traiter cette demande.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
|
if reservation.salle == "lien_zoom" or reservation.besoin_zoom:
|
||||||
lien = request.POST.get("lien_zoom")
|
lien = request.POST.get("lien_zoom")
|
||||||
|
if not lien:
|
||||||
|
messages.error(request, "Veuillez fournir un lien Zoom.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
reservation.lien_zoom = lien
|
reservation.lien_zoom = lien
|
||||||
|
|
||||||
reservation.statut = "validee"
|
reservation.statut = "validee"
|
||||||
reservation.save()
|
reservation.save()
|
||||||
messages.success(request, "Le lien Zoom a été ajouté et la réservation a été validée. ")
|
messages.success(request, "La demande a été traitée et validée. ")
|
||||||
|
|
||||||
|
# Mail au demandeur
|
||||||
|
fonctions_utilitaire.envoyer_mail(
|
||||||
|
sujet="Réservation traitée",
|
||||||
|
message=f"""Bonjour {reservation.employe.user.first_name} {reservation.employe.user.last_name}, votre demande de {dict(Reservation.TYPE_CHOICES).get(reservation.salle)}{' avec lien Zoom' if reservation.lien_zoom else ''} a été traitée. Veuillez vous connecter à la plateforme pour plus de détails.""",
|
||||||
|
destinataires=[reservation.employe.user.email]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Mail aux emails de l'équipe informatique (hors utilisateur courant)
|
||||||
|
autres_membres = Employe.objects.filter(departement__nom="Systeme informatique").exclude(id=employe.id).values_list('user__email', flat=True)
|
||||||
|
if autres_membres:
|
||||||
|
fonctions_utilitaire.envoyer_mail(
|
||||||
|
sujet="Réservation validée par l'équipe informatique",
|
||||||
|
message=f"""Bonjour,
|
||||||
|
La réservation {dict(Reservation.TYPE_CHOICES).get(reservation.salle)} du {reservation.date_debut.strftime('%d/%m/%Y')} pour {reservation.employe.user.first_name} {reservation.employe.user.last_name} a été traitée et validée par {employe.user.first_name} {employe.user.last_name}.\n\nVeuillez vous connecter à la plateforme pour plus de détails.""",
|
||||||
|
destinataires=list(autres_membres)
|
||||||
|
)
|
||||||
|
|
||||||
return redirect('gestion_salle:reservation-salle')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def annuler_reservation(request:HttpRequest):
|
def annuler_reservation(request:HttpRequest):
|
||||||
"""Vue de gestion de l'annulation de la reservation"""
|
"""Vue de gestion de l'annulation de la reservation, réservée à l'employé demandeur ou aux validateurs."""
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
reservation_id= request.POST['id_reservation']
|
reservation_id= request.POST['id_reservation']
|
||||||
try:
|
try:
|
||||||
reservation = Reservation.objects.get(id=reservation_id)
|
reservation = Reservation.objects.get(id=reservation_id)
|
||||||
except Reservation.DoesNotExist:
|
except Reservation.DoesNotExist:
|
||||||
messages.error(request, "La resevertion selectionné n'existe pas.")
|
messages.error(request, "La reservation selectionné n'existe pas.")
|
||||||
return redirect("salle")
|
return redirect("gestion_salle:reservation-salle")
|
||||||
|
|
||||||
|
try:
|
||||||
|
employe = Employe.objects.get(user=request.user)
|
||||||
|
except Employe.DoesNotExist:
|
||||||
|
messages.error(request, "Profil employé introuvable.")
|
||||||
|
return redirect("gestion_salle:reservation-salle")
|
||||||
|
|
||||||
|
# Seul l'employé demandeur ou un validateur (assistante / équipe info) peut annuler
|
||||||
|
est_demandeur = reservation.employe == employe
|
||||||
|
est_validateur = fonctions_utilitaire.est_assistante_direction(employe) or fonctions_utilitaire.est_equipe_informatique(employe)
|
||||||
|
|
||||||
|
if not est_demandeur and not est_validateur:
|
||||||
|
messages.error(request, "Vous n'êtes pas autorisé à annuler cette réservation.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
reservation.statut = 'annulee'
|
reservation.statut = 'annulee'
|
||||||
reservation.save()
|
reservation.save()
|
||||||
messages.success(request, "Votre réservation a été annulée.")
|
messages.success(request, "La réservation a été annulée.")
|
||||||
return redirect('gestion_salle:reservation-salle')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def valider_reservation(request: HttpRequest):
|
def valider_reservation(request: HttpRequest):
|
||||||
"""Validation d'une réservation"""
|
"""Validation d'une réservation selon le profil :
|
||||||
|
- Assistante de direction : valide les demandes de salles (sauf lien_zoom) ;
|
||||||
|
- Équipe informatique : valide les demandes de lien_zoom et les
|
||||||
|
demandes de salle avec besoin zoom/ordi restées en attente après la première correction.
|
||||||
|
"""
|
||||||
if request.method == 'POST':
|
if request.method == 'POST':
|
||||||
reservation_id = request.POST.get('id_reservation')
|
reservation_id = request.POST.get('id_reservation')
|
||||||
|
|
||||||
@@ -217,36 +315,121 @@ def valider_reservation(request: HttpRequest):
|
|||||||
reservation = Reservation.objects.get(id=reservation_id)
|
reservation = Reservation.objects.get(id=reservation_id)
|
||||||
except Reservation.DoesNotExist:
|
except Reservation.DoesNotExist:
|
||||||
messages.error(request, "La réservation sélectionnée n'existe pas.")
|
messages.error(request, "La réservation sélectionnée n'existe pas.")
|
||||||
return redirect("salle")
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
reservation.statut = 'validee'
|
try:
|
||||||
reservation.save()
|
employe = Employe.objects.get(user=request.user)
|
||||||
|
except Employe.DoesNotExist:
|
||||||
|
messages.error(request, "Profil employé introuvable.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
|
est_assistante = fonctions_utilitaire.est_assistante_direction(employe)
|
||||||
|
est_equipe_info = fonctions_utilitaire.est_equipe_informatique(employe)
|
||||||
|
|
||||||
|
if est_assistante:
|
||||||
|
# L'assistante ne doit pas traiter les simple lien_zoom
|
||||||
|
if reservation.salle == "lien_zoom":
|
||||||
|
messages.error(request, "Les demandes de lien Zoom sont traitées par l'équipe informatique.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
|
if reservation.besoin_zoom or reservation.besoin_ordi:
|
||||||
|
# La demande reste en attente, l'équipe informatique doit être notifiée
|
||||||
|
# L'assistante a donné sa validation "salle", on garde le statut "en_attente"
|
||||||
|
# pour que l'équipe informatique puisse traiter, et on envoie le mail à l'équipe.
|
||||||
|
if fonctions_utilitaire.EMAIL_EQUIPE_INFORMATIQUE:
|
||||||
fonctions_utilitaire.envoyer_mail(
|
fonctions_utilitaire.envoyer_mail(
|
||||||
sujet = "Reservation de salle",
|
sujet="Réservation de salle à traiter par l'équipe informatique",
|
||||||
message = f"""Bonjour {reservation.employe.user.first_name} {reservation.employe.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.""",
|
message=f"""Bonjour,
|
||||||
|
L'assistante de direction a validé la réservation de la salle {dict(Reservation.TYPE_CHOICES).get(reservation.salle)} pour {reservation.employe.user.first_name} {reservation.employe.user.last_name} le {reservation.date_debut.strftime('%d/%m/%Y')} (de {reservation.heure_debut.strftime('%H:%M')} à {reservation.heure_fin.strftime('%H:%M')}).
|
||||||
|
Cette demande nécessite {"un lien zoom" if reservation.besoin_zoom else ""}{" - un ordinateur" if reservation.besoin_ordi else ""}.
|
||||||
|
|
||||||
|
Veuillez vous connecter à la plateforme pour traiter cette demande.""",
|
||||||
|
destinataires=fonctions_utilitaire.EMAIL_EQUIPE_INFORMATIQUE
|
||||||
|
)
|
||||||
|
|
||||||
|
messages.success(request, "Réservation validée, une demande a été envoyée à l'équipe informatique.")
|
||||||
|
reservation.statut = "en_attente" # reste en attente pour l'équipe info
|
||||||
|
reservation.save()
|
||||||
|
else:
|
||||||
|
# Validation directe sans traitement informatique
|
||||||
|
reservation.statut = "validee"
|
||||||
|
reservation.save()
|
||||||
|
fonctions_utilitaire.envoyer_mail(
|
||||||
|
sujet="Réservation de salle validée",
|
||||||
|
message=f"""Bonjour {reservation.employe.user.first_name} {reservation.employe.user.last_name}, votre réservation de la {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]
|
destinataires=[reservation.employe.user.email]
|
||||||
)
|
)
|
||||||
|
|
||||||
messages.success(request, f"La réservation de {request.user.first_name} {request.user.last_name} validée avec succès.")
|
elif est_equipe_info:
|
||||||
|
# L'équipe informatique traite le reste : lien_zoom et besoins info
|
||||||
|
if reservation.salle == "lien_zoom" or reservation.besoin_zoom or reservation.besoin_ordi:
|
||||||
|
if reservation.besoin_zoom and not reservation.lien_zoom:
|
||||||
|
# La demande exige un lien zoom qui n'a pas été encore rempli,
|
||||||
|
# il est préférable de passer par ajouter_lien_zoom. On laisse traiter.
|
||||||
|
messages.success(request, "Veuillez ajouter le lien Zoom via le champs dédié.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
|
reservation.statut = "validee"
|
||||||
|
reservation.save()
|
||||||
|
|
||||||
|
# Mail au demandeur + autres membres de l'équipe
|
||||||
|
fonctions_utilitaire.envoyer_mail(
|
||||||
|
sujet="Réservation validée",
|
||||||
|
message=f"""Bonjour {reservation.employe.user.first_name} {reservation.employe.user.last_name}, votre demande de {dict(Reservation.TYPE_CHOICES).get(reservation.salle)} a été traitée et validée. Veuillez vous connecter pour plus de détails.""",
|
||||||
|
destinataires=[reservation.employe.user.email]
|
||||||
|
)
|
||||||
|
|
||||||
|
autres = Employe.objects.filter(departement__nom="Systeme informatique").exclude(id=employe.id).values_list('user__email', flat=True)
|
||||||
|
if autres:
|
||||||
|
fonctions_utilitaire.envoyer_mail(
|
||||||
|
sujet="Réservation traitée par un collègue",
|
||||||
|
message=f"""Bonjour {request.user.first_name} {request.user.last_name}, la demande de {dict(Reservation.TYPE_CHOICES).get(reservation.salle)} du {reservation.date_debut.strftime('%d/%m/%Y')} pour {reservation.employe.user.first_name} {reservation.employe.user.last_name} a été traitée et validée par {employe.user.first_name} {employe.user.last_name}. Veuillez vous connecter pour plus de détails.""",
|
||||||
|
destinataires=list(autres)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
messages.error(request, "Cette réservation ne relève pas de l'équipe informatique.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
else:
|
||||||
|
messages.error(request, "Vous n'êtes pas autorisé à effectuer cette validation.")
|
||||||
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
|
messages.success(request, f"La réservation de {request.user.first_name} {request.user.last_name} a été validée avec succès.")
|
||||||
return redirect('gestion_salle:reservation-salle')
|
return redirect('gestion_salle:reservation-salle')
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
def refuser_reservation(request:HttpRequest):
|
def refuser_reservation(request:HttpRequest):
|
||||||
"""Vue de gestion de refus de la reservation"""
|
"""Vue de gestion de refus de la reservation, autorisée à l'assistant de direction
|
||||||
|
et l'équipe informatique selon le type de demande."""
|
||||||
data = json.loads(request.body)
|
data = json.loads(request.body)
|
||||||
reservation_id = data.get("id_reservation")
|
reservation_id = data.get("id_reservation")
|
||||||
try:
|
try:
|
||||||
reservation = Reservation.objects.get(id=reservation_id)
|
reservation = Reservation.objects.get(id=reservation_id)
|
||||||
except Reservation.DoesNotExist:
|
except Reservation.DoesNotExist:
|
||||||
return JsonResponse({"message": "La resevertion selectionné n'existe pas."})
|
return JsonResponse({"message": "La reservation selectionné n'existe pas."})
|
||||||
else:
|
|
||||||
|
try:
|
||||||
|
employe = Employe.objects.get(user=request.user)
|
||||||
|
except Employe.DoesNotExist:
|
||||||
|
return JsonResponse({"message": "Profil employé introuvable."})
|
||||||
|
|
||||||
|
est_assistante = fonctions_utilitaire.est_assistante_direction(employe)
|
||||||
|
est_equipe_info = fonctions_utilitaire.est_equipe_informatique(employe)
|
||||||
|
|
||||||
|
peut_refuser = False
|
||||||
|
if est_assistante and reservation.salle != "lien_zoom":
|
||||||
|
peut_refuser = True
|
||||||
|
elif est_equipe_info and (reservation.salle == "lien_zoom" or reservation.besoin_zoom or reservation.besoin_ordi):
|
||||||
|
peut_refuser = True and (not reservation.besoin_zoom or reservation.lien_zoom)
|
||||||
|
|
||||||
|
if not peut_refuser:
|
||||||
|
return JsonResponse({"message": "Vous n'êtes pas autorisé à refuser cette réservation."})
|
||||||
|
|
||||||
reservation.statut = "refusee"
|
reservation.statut = "refusee"
|
||||||
reservation.save()
|
reservation.save()
|
||||||
|
|
||||||
fonctions_utilitaire.envoyer_mail(
|
fonctions_utilitaire.envoyer_mail(
|
||||||
sujet = "Reservation de salle",
|
sujet = "Réservation refusée",
|
||||||
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.""",
|
message = f"""Bonjour {reservation.employe.user.first_name} {reservation.employe.user.last_name}, votre demande de réservation du {reservation.date_debut.strftime('%d/%m/%Y')} de {reservation.date_debut.strftime('%d/%m/%Y')} de {reservation.heure_debut.strftime('%H:%M')} à {reservation.heure_fin.strftime('%H:%M')} a été refusée.""",
|
||||||
destinataires = [reservation.employe.user.email]
|
destinataires = [reservation.employe.user.email]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
6
staticfiles/bootstrap.min.css
vendored
6
staticfiles/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1,3 +0,0 @@
|
|||||||
from django.contrib import admin
|
|
||||||
|
|
||||||
# Register your models here.
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
from django.apps import AppConfig
|
|
||||||
|
|
||||||
|
|
||||||
class GestionCongeConfig(AppConfig):
|
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
|
||||||
name = 'gestion_conge'
|
|
||||||
@@ -3,23 +3,6 @@ const $ = (element) => document.getElementById(element);
|
|||||||
const url_liste_conge_attente = $("liste-demande-conges").dataset.url
|
const url_liste_conge_attente = $("liste-demande-conges").dataset.url
|
||||||
|
|
||||||
const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
// layout : "fitColumns",
|
|
||||||
=======
|
|
||||||
layout : "fitColumns",
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
layout : "fitColumns",
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
layout : "fitColumns",
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
// layout : "fitColumns",
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
columns: [
|
columns: [
|
||||||
{"title": "Nom et Prénom", "field": "prenom_nom"},
|
{"title": "Nom et Prénom", "field": "prenom_nom"},
|
||||||
{"title": "Date de début", "field": "date_debut", formatter:"datetime", formatterParams:{
|
{"title": "Date de début", "field": "date_debut", formatter:"datetime", formatterParams:{
|
||||||
@@ -31,23 +14,7 @@ const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
|||||||
outputFormat:"dd/MM/yy",
|
outputFormat:"dd/MM/yy",
|
||||||
}},
|
}},
|
||||||
{"title": "Type de congé", "field": "type"},
|
{"title": "Type de congé", "field": "type"},
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
{"title": "Date de la demande", "field": "date_demande", responsive: 1},
|
{"title": "Date de la demande", "field": "date_demande", responsive: 1},
|
||||||
=======
|
|
||||||
{"title": "Date de la demande", "field": "date_demande"},
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
{"title": "Date de la demande", "field": "date_demande"},
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
{"title": "Date de la demande", "field": "date_demande"},
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
{"title": "Date de la demande", "field": "date_demande", responsive: 1},
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
{"title": "Validation par supérieur hiérarchique", "field": "validation_hierarchique", formatter:"tickCross", formatterParams :{
|
{"title": "Validation par supérieur hiérarchique", "field": "validation_hierarchique", formatter:"tickCross", formatterParams :{
|
||||||
allowEmpty : true ,
|
allowEmpty : true ,
|
||||||
}},
|
}},
|
||||||
@@ -56,23 +23,7 @@ const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
|||||||
}},
|
}},
|
||||||
],
|
],
|
||||||
pagination: true,
|
pagination: true,
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
paginationSize: 5,
|
paginationSize: 5,
|
||||||
=======
|
|
||||||
paginationSize: 5
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
paginationSize: 5
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
paginationSize: 5
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
paginationSize: 5,
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const bouton_demande_conges = $("bouton-demande-conge");
|
const bouton_demande_conges = $("bouton-demande-conge");
|
||||||
|
|||||||
@@ -9,30 +9,15 @@ const tableau_liste_employe = new Tabulator("#tableau_liste_employe", {
|
|||||||
{"title": "Projet", "field": "projet"},
|
{"title": "Projet", "field": "projet"},
|
||||||
{"title": "Téléphone", "field": "telephone"},
|
{"title": "Téléphone", "field": "telephone"},
|
||||||
],
|
],
|
||||||
// ajaxURL: url_liste_employe,
|
|
||||||
pagination: true,
|
pagination: true,
|
||||||
paginationSize: 10,
|
paginationSize: 10,
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
responsiveLayout : "hide"
|
responsiveLayout : "hide"
|
||||||
=======
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
responsiveLayout : "hide"
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
})
|
})
|
||||||
|
|
||||||
fetch(url_liste_employe)
|
fetch(url_liste_employe)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data.success){
|
if (data.success){
|
||||||
console.log(data.data)
|
|
||||||
tableau_liste_employe.setData(data.data);
|
tableau_liste_employe.setData(data.data);
|
||||||
}else{
|
}else{
|
||||||
alert(data.message);
|
alert(data.message);
|
||||||
@@ -42,6 +27,7 @@ fetch(url_liste_employe)
|
|||||||
|
|
||||||
tableau_liste_employe.on("rowClick", function (row, rowData) {
|
tableau_liste_employe.on("rowClick", function (row, rowData) {
|
||||||
const data = rowData.getData();
|
const data = rowData.getData();
|
||||||
|
|
||||||
document.getElementById('detail-id').value = data.id;
|
document.getElementById('detail-id').value = data.id;
|
||||||
document.getElementById('detail-matricule').value = data.matricule;
|
document.getElementById('detail-matricule').value = data.matricule;
|
||||||
document.getElementById('detail-employe').value = data.employe;
|
document.getElementById('detail-employe').value = data.employe;
|
||||||
@@ -224,23 +210,31 @@ $("enregistrerDetail").addEventListener("click", function() {
|
|||||||
const fonction = document.getElementById('detail-fonction').value;
|
const fonction = document.getElementById('detail-fonction').value;
|
||||||
const dateEmbauche = document.getElementById('detail-dateEmbauche').value;
|
const dateEmbauche = document.getElementById('detail-dateEmbauche').value;
|
||||||
const matricule = document.getElementById('detail-matricule').value;
|
const matricule = document.getElementById('detail-matricule').value;
|
||||||
|
const departement = document.getElementById('detail-departement').value;
|
||||||
|
|
||||||
|
const url_enregistrer_detail = document.getElementById("modalDetailEmployeBody").dataset.url;
|
||||||
|
|
||||||
|
console.log("Le lien de l'enregistrement :", document.getElementById("modalDetailEmployeBody").dataset)
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
"id": id_,
|
||||||
|
"fonction": fonction,
|
||||||
|
"date_embauche": dateEmbauche,
|
||||||
|
"matricule": matricule,
|
||||||
|
"departement": departement
|
||||||
|
};
|
||||||
|
|
||||||
const url_enregistrer_detail = $("modalDetailEmployeBody").dataset.url;
|
|
||||||
fetch(url_enregistrer_detail, {
|
fetch(url_enregistrer_detail, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value
|
"X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify(payload)
|
||||||
"id": id_,
|
|
||||||
"fonction": fonction,
|
|
||||||
"date_embauche": dateEmbauche,
|
|
||||||
"matricule": matricule
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
|
console.log('Réponse du serveur:', data);
|
||||||
alert(data.message);
|
alert(data.message);
|
||||||
location.reload();
|
location.reload();
|
||||||
})
|
})
|
||||||
@@ -275,3 +269,69 @@ const listeContratExpirant = new Tabulator("#listeContratExpirant", {
|
|||||||
],
|
],
|
||||||
ajaxURL: $("boutonContratExpirants").dataset.urlexpirants,
|
ajaxURL: $("boutonContratExpirants").dataset.urlexpirants,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/* let tabContrats = null;
|
||||||
|
|
||||||
|
document.getElementById("modalContratsEmploye").addEventListener("show.bs.modal", function () {
|
||||||
|
|
||||||
|
const employeId = document.getElementById("detail-id").value;
|
||||||
|
|
||||||
|
if (!employeId) {
|
||||||
|
alert("Aucun employé sélectionné");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(`/employé/employe/${employeId}/contrats/`)
|
||||||
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Erreur HTTP " + response.status);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
|
.then(data => {
|
||||||
|
|
||||||
|
document.getElementById("nom-employe-contrat").innerText =
|
||||||
|
data.employe;
|
||||||
|
|
||||||
|
if (tabContrats) {
|
||||||
|
tabContrats.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
tabContrats = new Tabulator(
|
||||||
|
"#table-contrats-tabulator",
|
||||||
|
{
|
||||||
|
data: data.contrats,
|
||||||
|
layout: "fitColumns",
|
||||||
|
placeholder: "Aucun contrat",
|
||||||
|
|
||||||
|
columns: [
|
||||||
|
{ title: "Numéro", field: "numero_contrat" },
|
||||||
|
{ title: "Type", field: "type_contrat" },
|
||||||
|
{ title: "Date début", field: "date_debut" },
|
||||||
|
{ title: "Date fin", field: "date_fin" },
|
||||||
|
{ title: "Salaire", field: "salaire_mensuel" },
|
||||||
|
{ title: "Statut", field: "statut" },
|
||||||
|
|
||||||
|
{
|
||||||
|
title: "Contrat",
|
||||||
|
field: "fichier",
|
||||||
|
formatter: function(cell) {
|
||||||
|
const url = cell.getValue();
|
||||||
|
|
||||||
|
if (!url) {
|
||||||
|
return "<span class='text-danger'>Aucun fichier</span>";
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<a href="${url}" target="_blank" class="btn btn-sm btn-primary">
|
||||||
|
<i class="bi bi-file-earmark-pdf"></i> Ouvrir
|
||||||
|
</a>`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("Erreur :", error);
|
||||||
|
});
|
||||||
|
}); */
|
||||||
|
|||||||
@@ -13,22 +13,20 @@ const tableau_certificat = new Tabulator("#tableau-certificat", {
|
|||||||
inputFormat:"yyyy-MM-dd",
|
inputFormat:"yyyy-MM-dd",
|
||||||
outputFormat:"dd/MM/yy",
|
outputFormat:"dd/MM/yy",
|
||||||
}},
|
}},
|
||||||
|
{"title": "Fichier", "field": "certificat", formatter:"link", formatterParams:{
|
||||||
|
label:"Voir le fichier",
|
||||||
|
target:"_blank",
|
||||||
|
}},
|
||||||
],
|
],
|
||||||
ajaxURL: url_certificat,
|
ajaxURL: url_certificat,
|
||||||
})
|
})
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
const enregistrerProfil = $("enregistrerProfil");
|
const enregistrerProfil = $("enregistrerProfil");
|
||||||
|
|
||||||
enregistrerProfil.addEventListener("click", (e) => {
|
enregistrerProfil.addEventListener("click", (e) => {
|
||||||
|
|
||||||
const url = $("information-personnelles").dataset.url;
|
const url = $("information-personnelles").dataset.url;
|
||||||
const csrftoken = document.querySelector("[name='csrfmiddlewaretoken']").value;
|
const csrftoken = document.querySelector("[name='csrfmiddlewaretoken']").value;
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
|
||||||
formData.append("nom", $("nom").value);
|
formData.append("nom", $("nom").value);
|
||||||
formData.append("prenom", $("prenom").value);
|
formData.append("prenom", $("prenom").value);
|
||||||
formData.append("email", $("email").value);
|
formData.append("email", $("email").value);
|
||||||
@@ -36,6 +34,10 @@ enregistrerProfil.addEventListener("click", (e) => {
|
|||||||
formData.append("adresse", $("adresse").value);
|
formData.append("adresse", $("adresse").value);
|
||||||
formData.append("sexe", $("sexe").value);
|
formData.append("sexe", $("sexe").value);
|
||||||
formData.append("date_naissance", $("date_naissance").value);
|
formData.append("date_naissance", $("date_naissance").value);
|
||||||
|
const photoInput = $("photo");
|
||||||
|
if (photoInput.files.length > 0) {
|
||||||
|
formData.append("photo", photoInput.files[0]);
|
||||||
|
}
|
||||||
|
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -48,52 +50,3 @@ enregistrerProfil.addEventListener("click", (e) => {
|
|||||||
.then(data => alert(data.message))
|
.then(data => alert(data.message))
|
||||||
.catch(error => console.error("Erreur:", error));
|
.catch(error => console.error("Erreur:", error));
|
||||||
});
|
});
|
||||||
=======
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
|
|
||||||
=======
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
const enregistrerProfil = $("enregistrerProfil");
|
|
||||||
|
|
||||||
enregistrerProfil.addEventListener("click", (e) => {
|
|
||||||
|
|
||||||
const url = $("information-personnelles").dataset.url;
|
|
||||||
const csrftoken = document.querySelector("[name='csrfmiddlewaretoken']").value;
|
|
||||||
|
|
||||||
const formData = new FormData();
|
|
||||||
|
|
||||||
formData.append("nom", $("nom").value);
|
|
||||||
formData.append("prenom", $("prenom").value);
|
|
||||||
formData.append("email", $("email").value);
|
|
||||||
formData.append("telephone", $("telephone").value);
|
|
||||||
formData.append("adresse", $("adresse").value);
|
|
||||||
formData.append("sexe", $("sexe").value);
|
|
||||||
formData.append("date_naissance", $("date_naissance").value);
|
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
"X-CSRFToken": csrftoken
|
|
||||||
},
|
|
||||||
body: formData
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => alert(data.message))
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
})
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
})
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
})
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
.catch(error => console.error("Erreur:", error));
|
|
||||||
});
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
|
|||||||
@@ -1,18 +1,5 @@
|
|||||||
const btnEnregistrerBailleur = document.getElementById('btnEnregistrerBailleur');
|
const btnEnregistrerBailleur = document.getElementById('btnEnregistrerBailleur');
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
let table;
|
let table;
|
||||||
=======
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
let table;
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
|
|
||||||
btnEnregistrerBailleur.addEventListener('click', function() {
|
btnEnregistrerBailleur.addEventListener('click', function() {
|
||||||
const form = document.getElementById('formBailleur');
|
const form = document.getElementById('formBailleur');
|
||||||
@@ -34,15 +21,8 @@ btnEnregistrerBailleur.addEventListener('click', function() {
|
|||||||
alert('Ce bailleur existe déjà dans la base de données.');
|
alert('Ce bailleur existe déjà dans la base de données.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
|
|
||||||
table = new Tabulator("#table-bailleurs", {
|
table = new Tabulator("#table-bailleurs", {
|
||||||
ajaxURL: "/gestion-projet/bailleurs/",
|
ajaxURL: "/gestion-projet/bailleurs/",
|
||||||
@@ -65,18 +45,3 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
});
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
});
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
});
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const $ = (element) => document.getElementById(element)
|
const $ = (element) => document.getElementById(element)
|
||||||
const url_liste_projet = $("tableau-liste-projet").dataset.url;
|
const url_liste_projet = $("tableau-liste-projet").dataset.url;
|
||||||
|
|
||||||
const tableau_liste_projet = new Tabulator("#tableau-liste-projet", {
|
const tableau_liste_projet = new Tabulator("#tableau-liste-projet", {
|
||||||
fitColumns: true,
|
fitColumns: true,
|
||||||
responsiveLayout : true,
|
responsiveLayout : true,
|
||||||
@@ -39,7 +40,6 @@ tableau_liste_projet.on("rowClick", function (row, rowData) {
|
|||||||
$("detail_date_debut").value = data.date_debut;
|
$("detail_date_debut").value = data.date_debut;
|
||||||
$("detail_date_fin").value = data.date_fin;
|
$("detail_date_fin").value = data.date_fin;
|
||||||
$("detail_numero_convention").value = data.numero_convention;
|
$("detail_numero_convention").value = data.numero_convention;
|
||||||
$("detail_type_projet").value = data.type_projet;
|
|
||||||
Array.from($("detail_domaine_recherche").options).forEach(option => {
|
Array.from($("detail_domaine_recherche").options).forEach(option => {
|
||||||
if (data.domaine_recherche.includes(option.value)) {
|
if (data.domaine_recherche.includes(option.value)) {
|
||||||
option.selected = true;
|
option.selected = true;
|
||||||
|
|||||||
@@ -12,24 +12,14 @@ const calendrier = Schedule(document.getElementById('planning-reservation'), {
|
|||||||
const modal = new bootstrap.Modal($("modalDetailReservation"));
|
const modal = new bootstrap.Modal($("modalDetailReservation"));
|
||||||
modal.show();
|
modal.show();
|
||||||
fetch (`/gestion-salle/revervation/details/${event.guid}`)
|
fetch (`/gestion-salle/revervation/details/${event.guid}`)
|
||||||
.then(response => response.json())
|
.then(response => {
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Erreur HTTP ${response.status}`);
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
})
|
||||||
.then(data => {
|
.then(data => {
|
||||||
currentReservationId = data.id_reservation;
|
currentReservationId = data.id_reservation;
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
console.log(data);
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
console.log(data);
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
console.log(data);
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
$("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;
|
||||||
@@ -44,38 +34,18 @@ 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;
|
||||||
|
|
||||||
<<<<<<< HEAD
|
const zoomContainer = $("lien_zoom_container");
|
||||||
<<<<<<< HEAD
|
if (!data.besoin_zoom) {
|
||||||
<<<<<<< HEAD
|
zoomContainer.classList.add("d-none");
|
||||||
<<<<<<< HEAD
|
|
||||||
if (data.besoin_zoom === false){
|
|
||||||
$("lien_zoom_container").className = "d-none";
|
|
||||||
}
|
|
||||||
|
|
||||||
=======
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
if(data.statut !== "annulee"){
|
|
||||||
$("motif_refus_container").className = "d-none";
|
|
||||||
} else {
|
} else {
|
||||||
$("motif_refus").value=data.motif_refus;
|
zoomContainer.classList.remove("d-none");
|
||||||
}
|
}
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
if (data.besoin_zoom === false){
|
if (data.besoin_zoom === false){
|
||||||
$("lien_zoom_container").className = "d-none";
|
$("lien_zoom_container").className = "d-none";
|
||||||
}
|
}
|
||||||
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
})
|
})
|
||||||
|
.catch(error => console.error("Impossible de charger les détails de la réservation :", error));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -117,29 +87,13 @@ document.addEventListener("DOMContentLoaded", function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
$("bouton-annuler").addEventListener("click", (e) => {
|
$("bouton-annuler").addEventListener("click", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
|
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
|
||||||
const url_annuler = $("formulaire-details").dataset.urlannuler;
|
const url_annuler = $("formulaire-details").dataset.urlannuler;
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
console.log("URL d'annulation :");
|
|
||||||
console.log($("formulaire-details"))
|
|
||||||
|
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
fetch(
|
fetch(
|
||||||
url_annuler,
|
url_annuler,
|
||||||
{
|
{
|
||||||
@@ -186,28 +140,15 @@ if($("ajoutZoom")){
|
|||||||
|
|
||||||
if($("refuserReservation")){
|
if($("refuserReservation")){
|
||||||
$("refuserReservation").addEventListener("click", (e) => {
|
$("refuserReservation").addEventListener("click", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
|
const csrf = document.querySelector("[name=csrfmiddlewaretoken]").value;
|
||||||
const url = e.currentTarget.dataset.lienrefus;
|
const url = e.currentTarget.dataset.lienrefus;
|
||||||
const idRes = $("id_reservation_detail").value;
|
const idRes = $("id_reservation_detail").value;
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
console.log(idRes);
|
console.log(idRes);
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
=======
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
console.log(idRes);
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -227,7 +168,7 @@ const tableau_reservation_attente = new Tabulator("#tableau-reservation-attente"
|
|||||||
columns: [
|
columns: [
|
||||||
{title: "Employé", field: "employe"},
|
{title: "Employé", field: "employe"},
|
||||||
{title: "Salle", field: "salle"},
|
{title: "Salle", field: "salle"},
|
||||||
{title: "Date de l'evenement", field: "date_debut"},
|
{title: "Date de l'evenement", field: "date_evenement"},
|
||||||
{title: "Heure de début", field: "heure_debut"},
|
{title: "Heure de début", field: "heure_debut"},
|
||||||
{title: "Heure de fin", field: "heure_fin"},
|
{title: "Heure de fin", field: "heure_fin"},
|
||||||
{title: "Motif de reservation", field: "motif_reservation"},
|
{title: "Motif de reservation", field: "motif_reservation"},
|
||||||
@@ -239,52 +180,14 @@ const tableau_reservation_attente = new Tabulator("#tableau-reservation-attente"
|
|||||||
tableau_reservation_attente.on("rowClick", (row, rowData) => {
|
tableau_reservation_attente.on("rowClick", (row, rowData) => {
|
||||||
const data = rowData.getData();
|
const data = rowData.getData();
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
console.log(data);
|
console.log(data);
|
||||||
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
console.log(data);
|
|
||||||
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
if(data.besoin_zoom === false){
|
if(data.besoin_zoom === false){
|
||||||
$("lien_zoom_container").className = 'd-none';
|
$("lien_zoom_container").className = 'd-none';
|
||||||
}
|
}
|
||||||
|
|
||||||
<<<<<<< HEAD
|
const id_user = $("current-user-id").dataset.userId;
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
const id_user = $("current-user-id").dataset.userid;
|
|
||||||
=======
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
if(data.statut !== "refusee"){
|
|
||||||
$("motif_refus_container").className = 'd-none';
|
|
||||||
}
|
|
||||||
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
const id_user = $("current-user-id").dataset.userid;
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
$("id_reservation_detail").value = data.id;
|
$("id_reservation_detail").value = data.id;
|
||||||
$("id_reservation_refus").value = data.id;
|
$("id_reservation_refus").value = data.id;
|
||||||
$("id_reservation_zoom").value = data.id;
|
$("id_reservation_zoom").value = data.id;
|
||||||
@@ -292,53 +195,25 @@ tableau_reservation_attente.on("rowClick", (row, rowData) => {
|
|||||||
$("employe").value=data.employe;
|
$("employe").value=data.employe;
|
||||||
$("salle").value=data.salle;
|
$("salle").value=data.salle;
|
||||||
$("statut-reservation").innerHTML=data.statut;
|
$("statut-reservation").innerHTML=data.statut;
|
||||||
<<<<<<< HEAD
|
$("date_evenement").value = data.date_evenement;
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
|
||||||
$("date_debut").value = data.date_debut;
|
|
||||||
$("date_fin").value = data.date_fin;
|
|
||||||
=======
|
|
||||||
$("date_evenement").value=data.date_debut;
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
$("date_evenement").value=data.date_debut;
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
$("date_evenement").value=data.date_debut;
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
$("date_debut").value = data.date_debut;
|
|
||||||
$("date_fin").value = data.date_fin;
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
$("heure_debut").value=data.heure_debut;
|
$("heure_debut").value=data.heure_debut;
|
||||||
$("heure_fin").value=data.heure_fin;
|
$("heure_fin").value=data.heure_fin;
|
||||||
$("motif_reservation").value=data.motif_reservation;
|
$("motif_reservation").value=data.motif_reservation;
|
||||||
$("besoin_zoom").checked=data.besoin_zoom;
|
$("besoin_zoom").checked=data.besoin_zoom;
|
||||||
$("besoin_ordinateur").checked=data.besoin_ordi;
|
$("besoin_ordinateur").checked=data.besoin_ordi;
|
||||||
$("lien_zoom").value=data.lien_zoom;
|
$("lien_zoom").value=data.lien_zoom;
|
||||||
<<<<<<< HEAD
|
|
||||||
<<<<<<< HEAD
|
const refuserReservation = document.querySelector("#refuserReservation");
|
||||||
<<<<<<< HEAD
|
const bouton_valider = document.querySelector("#bouton-valider");
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
if((refuserReservation | bouton_valider) && data.statut === "En attente"){
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
refuserReservation.style.display = "inline-block";
|
||||||
|
bouton_valider.style.display = "inline-block";
|
||||||
|
}
|
||||||
|
|
||||||
if (id_user != data.employe_id){
|
if (id_user != data.employe_id){
|
||||||
$("bouton-annuler").className = "d-none";
|
$("bouton-annuler").className = "d-none";
|
||||||
}
|
}
|
||||||
<<<<<<< HEAD
|
|
||||||
=======
|
|
||||||
$("motif_refus").value=data.motif_refus;
|
|
||||||
>>>>>>> 0047b1f (Ajout de la prise en charge des photos de profil)
|
|
||||||
=======
|
|
||||||
$("motif_refus").value=data.motif_refus;
|
|
||||||
>>>>>>> f6b90e7 (Verification du statut avant la creation d'un contrat)
|
|
||||||
=======
|
|
||||||
$("motif_refus").value=data.motif_refus;
|
|
||||||
>>>>>>> 6026af5 (Bug : Affichages des conges)
|
|
||||||
=======
|
|
||||||
>>>>>>> 3b587d2a1a4376551b4b694a38e0e24a1c4cf4c5
|
|
||||||
|
|
||||||
const modal = new bootstrap.Modal($("modalDetailReservation"));
|
const modal = new bootstrap.Modal($("modalDetailReservation"));
|
||||||
bootstrap.Modal.getOrCreateInstance($("modalReservationAttente")).hide();
|
bootstrap.Modal.getOrCreateInstance($("modalReservationAttente")).hide();
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,278 +0,0 @@
|
|||||||
/* === Print === */
|
|
||||||
@media print {
|
|
||||||
nav, .btn, .sidebar, .form-select, .form-control {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
body {
|
|
||||||
font-size: 12pt;
|
|
||||||
color: black;
|
|
||||||
}
|
|
||||||
table {
|
|
||||||
border-collapse: collapse;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
main {
|
|
||||||
margin-left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Body & Container === */
|
|
||||||
body {
|
|
||||||
background-color: #e4dccc;
|
|
||||||
background-attachment: fixed;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dashboard-container {
|
|
||||||
background-color: #ffffff;
|
|
||||||
box-shadow: 0 0 10px rgba(0,0,0,0.05);
|
|
||||||
border-radius: 8px;
|
|
||||||
padding: 20px;
|
|
||||||
margin: 30px auto;
|
|
||||||
max-width: 1200px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
position: fixed;
|
|
||||||
width: 220px;
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
margin-left: 220px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* === Sidebar === */
|
|
||||||
.sidebar {
|
|
||||||
background: linear-gradient(180deg, #b35400, #993d00); /* dégradé orange foncé */
|
|
||||||
color: white;
|
|
||||||
min-height: 100vh; /* prend toute la hauteur */
|
|
||||||
top: 0;
|
|
||||||
z-index: 1000;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link {
|
|
||||||
color: white;
|
|
||||||
font-weight: 700;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link:hover {
|
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
|
||||||
border-radius: 5px;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .dropdown-menu {
|
|
||||||
display: none;
|
|
||||||
position: relative;
|
|
||||||
left: 10px;
|
|
||||||
top: -5px;
|
|
||||||
border: none;
|
|
||||||
padding-left: 1rem;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .dropdown:hover .dropdown-menu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar a {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar a:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Navbar / Logo / Profil === */
|
|
||||||
.logo {
|
|
||||||
max-width: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-profil {
|
|
||||||
width: 80px !important;
|
|
||||||
height: 80px !important;
|
|
||||||
object-fit: cover;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Cards === */
|
|
||||||
.card {
|
|
||||||
border: 1px solid #dee2e6;
|
|
||||||
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
|
|
||||||
border-radius: 8px;
|
|
||||||
transition: transform 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card:hover {
|
|
||||||
transform: scale(1.02);
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-header {
|
|
||||||
background-color: #f8f9fa;
|
|
||||||
font-weight: bold !important;
|
|
||||||
color: black !important;
|
|
||||||
font-size: 1rem;
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.card-body h5 {
|
|
||||||
color: black !important;
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 2.2rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Stat cards === */
|
|
||||||
.stat-card {
|
|
||||||
background: #fff;
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 5px rgba(113, 11, 11, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Employé / Projet details === */
|
|
||||||
.employe-detail {
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.employe-detail .card-title {
|
|
||||||
font-size: 1.8rem;
|
|
||||||
margin-bottom: 0.5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.employe-detail p {
|
|
||||||
margin-bottom: 0.4rem;
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.employe-detail a.btn {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.employe-card, .projet-card {
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
|
||||||
padding: 2.5rem;
|
|
||||||
max-width: 1400px;
|
|
||||||
margin: 0 auto;
|
|
||||||
font-size: 1.1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Forms === */
|
|
||||||
.form-wrapper {
|
|
||||||
max-width: 1000px;
|
|
||||||
margin: auto;
|
|
||||||
background-color: rgba(255, 255, 255, 0.95);
|
|
||||||
}
|
|
||||||
|
|
||||||
form label {
|
|
||||||
font-weight: 600;
|
|
||||||
margin-top: 1rem;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
form input, form select, form textarea {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.5rem;
|
|
||||||
margin-top: 0.3rem;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Formation badges === */
|
|
||||||
.formation-badge {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formation-actions {
|
|
||||||
position: absolute;
|
|
||||||
top: -5px;
|
|
||||||
right: -5px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formation-badge:hover .formation-actions {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.formation-actions button {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
color: #fff;
|
|
||||||
margin-left: 5px;
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Context menu === */
|
|
||||||
#contextMenu {
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Transitions / Animations === */
|
|
||||||
.fade-out {
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.5s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main-content {
|
|
||||||
transition: opacity 0.3s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.login-box {
|
|
||||||
background: linear-gradient(to right, #f5f7fa, #c3cfe2);
|
|
||||||
border-radius: 10px;
|
|
||||||
box-shadow: 0 0 10px rgba(0,0,0,0.3);
|
|
||||||
width: 100%;
|
|
||||||
max-width: 400px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* === Responsive === */
|
|
||||||
@media (max-width: 576px) {
|
|
||||||
.modal-dialog {
|
|
||||||
max-width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
height: 100%;
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-body {
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-footer button {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-profil {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebar .nav-link {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
padding: 0.5rem 1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user