feature: Affichage de la liste des bailleur #14
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
db.sqlite3
|
|
||||||
venv/*
|
|
||||||
media/*
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
16
SIRH/asgi.py
16
SIRH/asgi.py
@@ -1,16 +0,0 @@
|
|||||||
"""
|
|
||||||
ASGI config for SIRH project.
|
|
||||||
|
|
||||||
It exposes the ASGI callable as a module-level variable named ``application``.
|
|
||||||
|
|
||||||
For more information on this file, see
|
|
||||||
https://docs.djangoproject.com/en/5.2/howto/deployment/asgi/
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.core.asgi import get_asgi_application
|
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'SIRH.settings')
|
|
||||||
|
|
||||||
application = get_asgi_application()
|
|
||||||
159
SIRH/settings.py
159
SIRH/settings.py
@@ -1,159 +0,0 @@
|
|||||||
"""
|
|
||||||
Django settings for SI_RH project.
|
|
||||||
|
|
||||||
Generated by 'django-admin startproject' using Django 5.2.4.
|
|
||||||
|
|
||||||
For more information on this file, see
|
|
||||||
https://docs.djangoproject.com/en/5.2/topics/settings/
|
|
||||||
|
|
||||||
For the full list of settings and their values, see
|
|
||||||
https://docs.djangoproject.com/en/5.2/ref/settings/
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
|
||||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
|
||||||
|
|
||||||
|
|
||||||
# Quick-start development settings - unsuitable for production
|
|
||||||
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
|
|
||||||
|
|
||||||
# SECURITY WARNING: keep the secret key used in production secret!
|
|
||||||
SECRET_KEY = 'django-insecure--wdb9t(77rvyac$_q!n5gw86&0r(0&&j171v9h!-_$jahsza*5'
|
|
||||||
|
|
||||||
# SECURITY WARNING: don't run with debug turned on in production!
|
|
||||||
DEBUG = False
|
|
||||||
|
|
||||||
ALLOWED_HOSTS = ["https://support.cerfig.org", "support.cerfig.org"]
|
|
||||||
|
|
||||||
# Application definition
|
|
||||||
|
|
||||||
INSTALLED_APPS = [
|
|
||||||
'django.contrib.admin',
|
|
||||||
'django.contrib.auth',
|
|
||||||
'django.contrib.contenttypes',
|
|
||||||
'django.contrib.sessions',
|
|
||||||
'django.contrib.messages',
|
|
||||||
'django.contrib.staticfiles',
|
|
||||||
'gestion_employe',
|
|
||||||
'gestion_conge',
|
|
||||||
'gestion_projet',
|
|
||||||
'gestion_salle',
|
|
||||||
'simple_sso.sso_server'
|
|
||||||
]
|
|
||||||
|
|
||||||
LOGIN_URL = 'login'
|
|
||||||
|
|
||||||
MIDDLEWARE = [
|
|
||||||
'django.middleware.security.SecurityMiddleware',
|
|
||||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
|
||||||
'django.middleware.common.CommonMiddleware',
|
|
||||||
'django.middleware.csrf.CsrfViewMiddleware',
|
|
||||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
|
||||||
'django.contrib.messages.middleware.MessageMiddleware',
|
|
||||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
|
||||||
]
|
|
||||||
|
|
||||||
ROOT_URLCONF = 'SIRH.urls'
|
|
||||||
|
|
||||||
TEMPLATES = [
|
|
||||||
{
|
|
||||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
|
||||||
'DIRS': [os.path.join(BASE_DIR, "SIRH", "templates", "SIRH")],
|
|
||||||
'APP_DIRS': True,
|
|
||||||
'OPTIONS': {
|
|
||||||
'context_processors': [
|
|
||||||
'django.template.context_processors.request',
|
|
||||||
'django.contrib.auth.context_processors.auth',
|
|
||||||
'django.contrib.messages.context_processors.messages',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
WSGI_APPLICATION = 'SIRH.wsgi.application'
|
|
||||||
|
|
||||||
|
|
||||||
# Database
|
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#databases
|
|
||||||
|
|
||||||
# DATABASES = {
|
|
||||||
# 'default': {
|
|
||||||
# 'ENGINE': 'django.db.backends.mysql',
|
|
||||||
# 'NAME': 'sirh',
|
|
||||||
# 'USER': 'sirh',
|
|
||||||
# 'PASSWORD': 'sirh-cerfig',
|
|
||||||
# 'HOST': 'localhost',
|
|
||||||
# 'PORT': '3306',
|
|
||||||
# }
|
|
||||||
# }
|
|
||||||
|
|
||||||
DATABASES = {
|
|
||||||
'default': {
|
|
||||||
'ENGINE': 'django.db.backends.sqlite3',
|
|
||||||
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# Password validation
|
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
|
||||||
|
|
||||||
AUTH_PASSWORD_VALIDATORS = [
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# Internationalization
|
|
||||||
# https://docs.djangoproject.com/en/5.2/topics/i18n/
|
|
||||||
|
|
||||||
LANGUAGE_CODE = 'fr-fr'
|
|
||||||
|
|
||||||
TIME_ZONE = 'UTC'
|
|
||||||
|
|
||||||
USE_I18N = True
|
|
||||||
|
|
||||||
USE_TZ = True
|
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
|
||||||
# https://docs.djangoproject.com/en/5.2/howto/static-files/
|
|
||||||
|
|
||||||
STATIC_URL = 'static/'
|
|
||||||
|
|
||||||
STATIC_ROOT = BASE_DIR / 'staticfiles'
|
|
||||||
|
|
||||||
STATICFILES_DIRS = [
|
|
||||||
BASE_DIR / 'static',
|
|
||||||
]
|
|
||||||
|
|
||||||
MEDIA_URL = "/media/"
|
|
||||||
MEDIA_ROOT = BASE_DIR / "media"
|
|
||||||
|
|
||||||
|
|
||||||
# Default primary key field type
|
|
||||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#default-auto-field
|
|
||||||
|
|
||||||
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
|
||||||
|
|
||||||
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
|
||||||
EMAIL_HOST = 'ssl0.ovh.net'
|
|
||||||
EMAIL_PORT = 465
|
|
||||||
EMAIL_USE_SSL = True
|
|
||||||
EMAIL_USE_TLS = False
|
|
||||||
EMAIL_HOST_USER = 'support.it@cerfig.org'
|
|
||||||
EMAIL_HOST_PASSWORD = 'Cerfig2025'
|
|
||||||
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 58 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 180 KiB |
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
Before Width: | Height: | Size: 131 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 85 KiB |
@@ -1,157 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>PRINCICALA</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'icons.css' %}">
|
|
||||||
|
|
||||||
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #993d00, #b34700); /* oranges plus sombres */
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.sidebar .nav-link {
|
|
||||||
color: white;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
.sidebar .nav-link:hover {
|
|
||||||
background-color: rgba(255,255,255,0.2);
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
.logo {
|
|
||||||
max-width: 90px;
|
|
||||||
|
|
||||||
}
|
|
||||||
main {
|
|
||||||
margin-left: 220px;
|
|
||||||
}
|
|
||||||
.stat-card {
|
|
||||||
background: rgb(255, 255, 255);
|
|
||||||
padding: 20px;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0px 2px 5px rgba(113, 11, 11, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
|
|
||||||
<nav class="col-12 col-md-3 col-lg-2 sidebar p-3">
|
|
||||||
<div class="text-center mb-4">
|
|
||||||
<img src="{% static 'CERFIF.jpg' %}" alt="Logo" class="logo mb-5">
|
|
||||||
<h4 class="text-white">CERFIG</h4>
|
|
||||||
</div>
|
|
||||||
<ul class="nav flex-column">
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="/" class="nav-link"><i class="bi bi-speedometer2"></i> Tableau de bord</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class=" bi bi-airplane"></i> Demande de congé </a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-people"></i> Gestion des Employés</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-folder"></i> Gestion des Projets</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-airplane"></i> Gestion des Congés</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-graph-up"></i>Rapports et Statistiques</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-gear"></i> Paramètres</a>
|
|
||||||
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="#" class="nav-link"><i class="bi bi-box-arrow-right"></i> Déconnexion</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- Contenu principal -->
|
|
||||||
<main class="col px-4 py-4">
|
|
||||||
<h1 class="mb-4">Bienvenue sur le tableau de bord</h1>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="row g-3 mb-4">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="stat-card">
|
|
||||||
<h5><i class="bi bi-airplane"></i> Congés en attente</h5>
|
|
||||||
|
|
||||||
<p class="display-6 fw-bold"> {{ nombre_conges_attente }}</p>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="stat-card">
|
|
||||||
<h5><i class="bi bi-people"></i> Nombre Employés </h5>
|
|
||||||
<p class="display-6 fw-bold">{{ nombre_employes }}</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="stat-card">
|
|
||||||
<h5><i class="bi bi-kanban"></i> Projets en cours</h5>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="card p-3">
|
|
||||||
<h3>
|
|
||||||
<i class="bi bi-people"></i> La liste des employés en congé</h3>
|
|
||||||
|
|
||||||
<table class="table table-striped">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Employé</th>
|
|
||||||
<th>Type de congé</th>
|
|
||||||
<th>Date de début</th>
|
|
||||||
<th>Date de fin</th>
|
|
||||||
<th>Statut</th>
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
|
|
||||||
{% for employe in personnes_en_conge %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ employe.nom }} {{ employe.prenom }}</td>
|
|
||||||
<td>{{ employe.type }}</td>
|
|
||||||
<td>{{ employe.date_debut }}</td>
|
|
||||||
<td>{{ employe.date_fin }}</td>
|
|
||||||
<td>
|
|
||||||
<span class="badge bg-success">{{ employe.statut }} </span>
|
|
||||||
<td>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="5" class="text-center">Personne en conge </td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,197 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Connexion SI-RH</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
</head>
|
|
||||||
|
|
||||||
|
|
||||||
<body class="d-flex justify-content-center align-items-center min-vh-100 ">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #b35400, #cc6600);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
<!-- Formulaire de connexion -->
|
|
||||||
<div class="p-4 shadow-sm rounded bg-white" style="max-width: 400px; margin: auto;">
|
|
||||||
<img src="{% static 'CERFIF.jpg' %}" alt="Logo" class="logo mb-3"
|
|
||||||
style="display: block; margin-left: auto; margin-right: auto; width: 60%; max-width: 500px; height: auto;">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
<!-- Modal message -->
|
|
||||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark
|
|
||||||
{% if messages.0.tags == 'error' %}bg-orange-dark text-white
|
|
||||||
{% elif messages.0.tags == 'success' %}bg-orange-dark text-white
|
|
||||||
{% else %}bg-orange-dark text-white{% endif %}">
|
|
||||||
<h5 class="modal-title" id="messageModalLabel">
|
|
||||||
{% if messages.0.tags == 'error' %}Erreur
|
|
||||||
{% elif messages.0.tags == 'success' %}Succès
|
|
||||||
{% else %}Information{% endif %}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% for message in messages %}
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var messageModal = new bootstrap.Modal(document.getElementById('messageModal'));
|
|
||||||
messageModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
<form method="POST" action="{% url 'login' %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="username">Nom d’utilisateur</label>
|
|
||||||
<input type="text" name="username" class="form-control" placeholder="Entrez votre nom d’utilisateur" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3 position-relative">
|
|
||||||
<label for="password">Mot de passe</label>
|
|
||||||
<input type="password" name="password" class="form-control" placeholder="Entrez votre mot de passe" required>
|
|
||||||
<i class="bi bi-eye toggle-password" onclick="togglePassword()"
|
|
||||||
style="position:absolute; right:10px; top:38px; cursor:pointer;"></i>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary w-100">Se connecter</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<p class="mt-3 text-center">
|
|
||||||
<a href="#" data-bs-toggle="modal" data-bs-target="#resetPasswordModal">Mot de passe oublié ?</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modale de réinitialisation -->
|
|
||||||
<div class="modal fade" id="resetPasswordModal" tabindex="-1" aria-labelledby="resetPasswordModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content p-4">
|
|
||||||
<h5 class="modal-title mb-3" id="resetPasswordModalLabel">Réinitialisation du mot de passe</h5>
|
|
||||||
<form id="resetPasswordForm">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="email">Entrez votre email</label>
|
|
||||||
<input type="email" name="email" class="form-control" placeholder="Email" required>
|
|
||||||
</div>
|
|
||||||
<div id="resetMessage" class="mb-3"></div>
|
|
||||||
<button type="submit" class="btn btn-warning w-100">Envoyer le lien</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if show_politique_modal %}
|
|
||||||
<!-- Modal Politique d'utilisation -->
|
|
||||||
<div class="modal fade" id="politiqueModal" tabindex="-1" aria-hidden="true" data-bs-backdrop="static" data-bs-keyboard="false">
|
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">Politique d'utilisation de SI-RH</h5>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>Veuillez lire et accepter notre politique d'utilisation avant d'accéder à votre compte.</p>
|
|
||||||
<h6>Confidentialité des données</h6>
|
|
||||||
<p>Vos informations personnelles et professionnelles sont protégées. Toute divulgation non autorisée est strictement interdite.</p>
|
|
||||||
<h6>Utilisation autorisée</h6>
|
|
||||||
<p>L’application est réservée à un usage professionnel. Toute utilisation à des fins personnelles ou non autorisées est prohibée.</p>
|
|
||||||
<h6>Sécurité des comptes</h6>
|
|
||||||
<p>Ne partagez jamais vos identifiants. Changez votre mot de passe régulièrement et en cas de suspicion d’intrusion.</p>
|
|
||||||
<h6>Responsabilités de l’utilisateur</h6>
|
|
||||||
<p>Vous êtes responsable des actions effectuées via votre compte. Signalez toute anomalie ou problème à l’équipe RH ou à l’administrateur.</p>
|
|
||||||
<h6>Acceptation et conformité</h6>
|
|
||||||
<p>En cliquant sur <strong>“J’accepte”</strong>, vous confirmez avoir lu et accepté cette politique. Le non-respect peut entraîner une suspension ou une révocation de l’accès.</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<form method="POST" action="{% url 'accepter-politique' %}" style="display:inline;">
|
|
||||||
{% csrf_token %}
|
|
||||||
<button type="submit" class="btn btn-success">J'accepte</button>
|
|
||||||
</form>
|
|
||||||
<form method="POST" action="{% url 'refuser-politique' %}" style="display:inline;">
|
|
||||||
{% csrf_token %}
|
|
||||||
<button type="submit" class="btn btn-danger">Refuser</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var politiqueModal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
politiqueModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var politiqueModal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
politiqueModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var modal = new bootstrap.Modal(document.getElementById('politiqueModal'));
|
|
||||||
modal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Scripts -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
|
|
||||||
<script>
|
|
||||||
// Afficher / masquer le mot de passe
|
|
||||||
function togglePassword() {
|
|
||||||
const input = document.querySelector('input[name="password"]');
|
|
||||||
input.type = input.type === 'password' ? 'text' : 'password';
|
|
||||||
}
|
|
||||||
|
|
||||||
// AJAX pour réinitialisation
|
|
||||||
$('#resetPasswordForm').on('submit', function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
const email = $('input[name="email"]').val();
|
|
||||||
const csrfToken = $('[name=csrfmiddlewaretoken]').val();
|
|
||||||
|
|
||||||
$.ajax({
|
|
||||||
url: "{% url 'password_reset' %}",
|
|
||||||
type: 'POST',
|
|
||||||
data: {
|
|
||||||
'email': email,
|
|
||||||
'csrfmiddlewaretoken': csrfToken
|
|
||||||
},
|
|
||||||
success: function(response) {
|
|
||||||
$('#resetMessage').html('<div class="alert alert-success">Email envoyé ! Vérifiez votre boîte de réception.</div>');
|
|
||||||
},
|
|
||||||
error: function() {
|
|
||||||
$('#resetMessage').html('<div class="alert alert-danger">Erreur lors de l’envoi. Vérifiez l’email.</div>');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
@@ -1,150 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load roles %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>PRINCICALA</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<!-- ===================== -->
|
|
||||||
<!-- SIDEBAR RESPONSIVE -->
|
|
||||||
<!-- ===================== -->
|
|
||||||
<nav class="sidebar bg-orange-dark text-white d-none d-md-block col-md-3 col-lg-2 p-3"
|
|
||||||
style="background: linear-gradient(90deg, #993d00, #b34700); position: fixed; height: 100vh; overflow-y: auto;">
|
|
||||||
|
|
||||||
<!-- Profil utilisateur -->
|
|
||||||
<div class="text-center mb-4 d-flex flex-column align-items-center" style="margin-top:20px;">
|
|
||||||
<h6 class="fw-bold text-white mb-2">{{ user.first_name }} {{ user.last_name }}</h6>
|
|
||||||
<a href="{% url 'mon_profil' %}">
|
|
||||||
{% if user.photo %}
|
|
||||||
<img src="{{ user.photo.url }}" alt="Profil"
|
|
||||||
class="rounded-circle img-profil mx-auto"
|
|
||||||
style="width: 80px; height: 80px; object-fit: cover;">
|
|
||||||
{% else %}
|
|
||||||
<div class="rounded-circle bg-secondary d-flex justify-content-center align-items-center"
|
|
||||||
style="width: 80px; height: 80px;">
|
|
||||||
<i class="bi bi-person-circle text-white" style="font-size: 2rem;"></i>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Liens du menu -->
|
|
||||||
<ul class="nav flex-column">
|
|
||||||
{% if user|has_role:"Employe" or user|has_role:"Administrateur" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mon_profil' %}" class="nav-link text-white"><i class="bi bi-person-circle"></i> Mon profil</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'activites-projet' %}" class="nav-link text-white"><i class="bi bi-list-task"></i> Suivi des Activités</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'employe-conge' %}" class="nav-link text-white"><i class="bi bi-airplane"></i> Mes Congés</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mes_formations' %}" class="nav-link text-white"><i class="bi bi-journal-text"></i> Mes certificats</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'salle' %}" class="nav-link text-white"><i class="bi bi-calendar-check"></i> Réserver une salle</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if user|has_role:"RH" or user|has_role:"Directeur" or user|has_role:"Assistante" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'employe-index' %}" class="nav-link text-white"><i class="bi bi-speedometer2"></i> Tableau de bord</a>
|
|
||||||
</li>
|
|
||||||
{% if user|has_role:"Assistante" or user|has_role:"RH" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'activites-projet' %}" class="nav-link text-white"><i class="bi bi-list-task"></i> Suivi des Activités</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% if user|has_role:"Directeur" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'directeur' %}" class="nav-link text-white"><i class="bi bi-graph-up"></i> Suivi des Projets</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'projet-index' %}" class="nav-link text-white"><i class="bi bi-folder"></i> Gestion des Projets</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'conge' %}" class="nav-link text-white"><i class="bi bi-airplane"></i> Congés</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mes_formations' %}" class="nav-link text-white"><i class="bi bi-journal-text"></i> Mes certificats</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'salle' %}" class="nav-link text-white"><i class="bi bi-calendar-check"></i> Réserver une salle</a>
|
|
||||||
</li>
|
|
||||||
{% if user|has_role:"RH" or user|has_role:"Directeur" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'rapport-rh' %}" class="nav-link text-white"><i class="bi bi-graph-up"></i> Rapports et Statistiques</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mon_profil' %}" class="nav-link text-white"><i class="bi bi-person-circle"></i> Mon profil</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if user|has_role:"Administrateur" %}
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'gestion-utilisateurs' %}" class="nav-link text-white"><i class="bi bi-person-gear"></i> Gestion des Utilisateurs</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'parametres-rh' %}" class="nav-link text-white"><i class="bi bi-gear"></i> Paramètres</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'deconnexion' %}" class="nav-link text-white"><i class="bi bi-box-arrow-right"></i> Déconnexion</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- ===================== -->
|
|
||||||
<!-- MENU MOBILE (offcanvas) -->
|
|
||||||
<!-- ===================== -->
|
|
||||||
<!-- Bouton burger (visible uniquement sur téléphone) -->
|
|
||||||
<nav class="navbar navbar-dark bg-orange-dark d-md-none p-2" style="background: linear-gradient(90deg, #993d00, #b34700);">
|
|
||||||
<button class="btn btn-light" type="button" data-bs-toggle="offcanvas" data-bs-target="#menuMobile">
|
|
||||||
<i class="bi bi-list"></i> Menu
|
|
||||||
</button>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<!-- Menu Offcanvas mobile -->
|
|
||||||
<div class="offcanvas offcanvas-start" tabindex="-1" id="menuMobile" style="background: linear-gradient(90deg, #993d00, #b34700); color: white;">
|
|
||||||
<div class="offcanvas-header">
|
|
||||||
<h5 class="offcanvas-title">{{ user.first_name }} {{ user.last_name }}</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="offcanvas"></button>
|
|
||||||
</div>
|
|
||||||
<div class="offcanvas-body">
|
|
||||||
<!-- Tu peux copier ici le même <ul> du menu principal -->
|
|
||||||
<ul class="nav flex-column">
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'mon_profil' %}" class="nav-link text-white"><i class="bi bi-person-circle"></i> Mon profil</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'activites-projet' %}" class="nav-link text-white"><i class="bi bi-list-task"></i> Activités</a>
|
|
||||||
</li>
|
|
||||||
<li class="nav-item mb-2">
|
|
||||||
<a href="{% url 'deconnexion' %}" class="nav-link text-white"><i class="bi bi-box-arrow-right"></i> Déconnexion</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<div class="alert alert-{{ message.tags }} d-flex align-items-center" role="alert">
|
|
||||||
{% if message.tags == 'success' %}
|
|
||||||
<i class="bi bi-check-circle-fill me-2"></i>
|
|
||||||
{% elif message.tags == 'warning' %}
|
|
||||||
<i class="bi bi-exclamation-triangle-fill me-2"></i>
|
|
||||||
{% elif message.tags == 'error' %}
|
|
||||||
<i class="bi bi-x-circle-fill me-2"></i>
|
|
||||||
{% endif %}
|
|
||||||
{{ message }}
|
|
||||||
</div>
|
|
||||||
@@ -1,384 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Profil utilisateur</title>
|
|
||||||
|
|
||||||
<!-- CSS -->
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #993d00, #b34700); /* oranges plus sombres */
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
.card-body p { margin-bottom: 0.5rem; }
|
|
||||||
|
|
||||||
.main {
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
<!-- Sidebar -->
|
|
||||||
{% include 'menu_principal.html' %}
|
|
||||||
|
|
||||||
<!-- Main -->
|
|
||||||
<main class="col px-2 py-4" style="margin-left: 280px;">
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
<!-- Modal Message Django -->
|
|
||||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">
|
|
||||||
{% if messages.0.tags == 'error' %}
|
|
||||||
Erreur
|
|
||||||
{% elif messages.0.tags == 'success' %}
|
|
||||||
Succès
|
|
||||||
{% else %}
|
|
||||||
Information
|
|
||||||
{% endif %}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% for message in messages %}
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Icône Notification -->
|
|
||||||
<div class="notification-bell position-fixed top-0 end-0 m-3" data-bs-toggle="modal" data-bs-target="#modalNotifications" style="z-index:1050; cursor:pointer;">
|
|
||||||
<i class="bi bi-bell-fill fs-4"></i>
|
|
||||||
<span class="badge bg-danger">{{ notifications_contrats|length }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Notifications Contrats -->
|
|
||||||
<div class="modal fade" id="modalNotifications" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title"><i class="bi bi-bell me-2"></i>Contrats proches de la fin</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% if notifications_contrats %}
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for notif in notifications_contrats %}
|
|
||||||
<h5>Votre Contrat <strong>{{ notif.numero }}</strong> signé le <strong>{{ notif.date }}</strong>
|
|
||||||
se termine dans
|
|
||||||
<span class="badge bg-danger rounded-pill">{{ notif.jours_restants }} jours</span>
|
|
||||||
</h5>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
|
||||||
<p class="text-muted">Aucun contrat proche de la fin.</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Profil -->
|
|
||||||
|
|
||||||
<div class="container py-4">
|
|
||||||
<div class="row justify-content-center">
|
|
||||||
<div class="col-12 col-md-10 col-lg-8">
|
|
||||||
<div class="card border-0 shadow-sm">
|
|
||||||
|
|
||||||
<div class="card-header bg-light d-flex justify-content-between align-items-center">
|
|
||||||
<h4 class="mb-0 fw-bold">
|
|
||||||
<i class="bi bi-person-circle me-2"></i> Mon Profil
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-body p-3">
|
|
||||||
<!-- Infos personnelles -->
|
|
||||||
<div class="row mb-3">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong>Nom :</strong> {{ employe.last_name|default:"Non renseigné" }}</p>
|
|
||||||
<p><strong>Prénom :</strong> {{ employe.first_name|default:"Non renseigné" }}</p>
|
|
||||||
<p><strong>Matricule :</strong> {{ employe.matricule|default:"Non renseigné" }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong>Département :</strong> {{ employe.departement|default:"Non renseigné" }}</p>
|
|
||||||
<p><strong>Email :</strong> {{ employe.email|default:"Non renseigné" }}</p>
|
|
||||||
<p><strong>Téléphone :</strong> {{ employe.telephone|default:"Non renseigné" }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Contrats -->
|
|
||||||
<h5 class="mt-3">Contrats</h5>
|
|
||||||
{% for contrat in contrats %}
|
|
||||||
<div class="mb-3 p-3 border rounded">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong>Numéro :</strong> {{ contrat.numero_contrat }}</p>
|
|
||||||
<p><strong>Type :</strong> {{ contrat.type_contrat }}</p>
|
|
||||||
<p><strong>Date début :</strong> {{ contrat.date_debut|date:"d/m/Y" }}</p>
|
|
||||||
<p><strong>Date fin :</strong> {{ contrat.date_fin|date:"d/m/Y"|default:"Non précisée" }}</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<p><strong>Salaire mensuel :</strong>
|
|
||||||
{% if contrat.salaire_mensuel %}
|
|
||||||
{{ contrat.salaire_mensuel }} GNF
|
|
||||||
{% else %}
|
|
||||||
Non précisé
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
<p><strong>Statut :</strong>
|
|
||||||
<span class="badge
|
|
||||||
{% if contrat.statut_auto == 'Actif' %}bg-success
|
|
||||||
{% elif contrat.statut_auto == 'Terminé' %}bg-danger
|
|
||||||
{% elif contrat.statut_auto == 'Suspendu' %}bg-warning text-dark
|
|
||||||
{% else %}bg-secondary{% endif %}">
|
|
||||||
{{ contrat.statut_auto }}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p><strong>Solde congé :</strong> {{ contrat.solde_conge|default:"Non précisé" }} jours</p>
|
|
||||||
<p><strong>Fichier :</strong>
|
|
||||||
{% if contrat.fichier_contrat %}
|
|
||||||
<a href="{{ contrat.fichier_contrat.url }}" target="_blank">
|
|
||||||
<i class="bi bi-file-earmark-pdf me-1"></i> Télécharger
|
|
||||||
</a>
|
|
||||||
{% else %}
|
|
||||||
<span class="text-muted">Aucun fichier</span>
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% empty %}
|
|
||||||
<p class="text-danger">Aucun contrat trouvé.</p>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
<!-- Projets -->
|
|
||||||
<h5 class="mt-3">Projets</h5>
|
|
||||||
<ul class="list-group mb-3">
|
|
||||||
{% for a in affectations %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
<div>
|
|
||||||
{{ a.projet.nom_projet }} - {{ a.temps_affectation }}%
|
|
||||||
{% if a.projet.statut %}
|
|
||||||
- <span class="badge bg-info text-dark">{{ a.projet.statut }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
|
|
||||||
<button type="button" class="btn bg-orange-dark btn-sm text-white"
|
|
||||||
data-bs-toggle="modal" data-bs-target="#modalFicheProjet{{ a.projet.id }}">
|
|
||||||
<i class="bi bi-info-circle"></i> Détails
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li class="list-group-item text-muted text-center">Aucun projet assigné.</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card-footer bg-white d-flex justify-content-end">
|
|
||||||
<button type="button" class="btn btn-outline-secondary me-2" onclick="window.history.back()">Fermer</button>
|
|
||||||
<a href="{% url 'profil' %}" class="btn bg-orange-dark text-white">
|
|
||||||
<i class="bi bi-pencil-square me-1"></i> Renseigner les autres informations
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% for a in affectations %}
|
|
||||||
<!-- Modal Détails Projet -->
|
|
||||||
<div class="modal fade" id="modalFicheProjet{{ a.projet.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">
|
|
||||||
<i class="bi bi-info-circle me-2"></i>Détails du projet {{ a.projet.nom_projet }}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<p><strong>Nom :</strong> {{ a.projet.nom_projet }}</p>
|
|
||||||
<p><strong>Numéro convention :</strong> {{ a.projet.numero_convention }}</p>
|
|
||||||
<p><strong>Dates :</strong> {{ a.projet.date_debut|date:"d/m/Y" }} → {{ a.projet.date_fin|date:"d/m/Y" }}</p>
|
|
||||||
<p><strong>Type :</strong> {{ a.projet.get_type_projet_display }}</p>
|
|
||||||
<p><strong>Domaine :</strong> {{ a.projet.get_domaine_recherche_display }}</p>
|
|
||||||
<p><strong>Budget :</strong> {{ a.projet.budget }} GNF</p>
|
|
||||||
<p><strong>Budget RH :</strong> {{ a.projet.budget_RH }} GNF</p>
|
|
||||||
<p><strong>Statut :</strong> <span class="badge bg-info">{{ a.projet.statut }}</span></p>
|
|
||||||
<p><strong>Description :</strong> {{ a.projet.description }}</p>
|
|
||||||
|
|
||||||
<h6 class="mt-4">Employés affectés :</h6>
|
|
||||||
<ul class="list-group mb-3">
|
|
||||||
{% for aff in a.projet.affectations.all %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ aff.employe }} <span class="badge bg-orange-dark">{{ aff.temps_affectation }}%</span>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li class="list-group-item text-muted">Aucun employé affecté</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h6>Bailleurs :</h6>
|
|
||||||
<ul class="list-group mb-3">
|
|
||||||
{% for f in a.projet.financements.all %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ f.bailleur.nom }} <span class="badge bg-success">{{ f.pourcentage }}%</span>
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li class="list-group-item text-muted">Aucun bailleur enregistré</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<h6 class="mt-4">Documents du projet :</h6>
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for doc in a.projet.documents.all %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-start">
|
|
||||||
<div>
|
|
||||||
<strong>{{ doc.get_nom_document_display }}</strong><br>
|
|
||||||
pour le projet {{ a.projet.nom_projet }}<br>
|
|
||||||
{% if doc.description %}
|
|
||||||
<small class="text-muted">{{ doc.description }}</small><br>
|
|
||||||
{% endif %}
|
|
||||||
<small class="text-muted">
|
|
||||||
{% if doc.numero %}
|
|
||||||
{{ doc.numero }}
|
|
||||||
{% endif %}
|
|
||||||
</small>
|
|
||||||
<br> <small></small>
|
|
||||||
document ajouter le {{ doc.date_ajout|date:"d/m/Y" }}</small>
|
|
||||||
{% if doc.date_validite %}
|
|
||||||
<br><small class="text-muted"> et Valide jusqu'au {{ doc.date_validite|date:"d/m/Y" }}</small>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
</li>
|
|
||||||
{% empty %}
|
|
||||||
<li class="list-group-item text-muted">Aucun document disponible</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer bg-light">
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle me-1"></i> Fermer
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- JS -->
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
// Ferme les modales ouvertes avant d'en ouvrir une autre
|
|
||||||
const modals = document.querySelectorAll('.modal');
|
|
||||||
modals.forEach(modal => {
|
|
||||||
modal.addEventListener('show.bs.modal', function () {
|
|
||||||
document.querySelectorAll('.modal.show').forEach(openModal => {
|
|
||||||
if (openModal !== modal) {
|
|
||||||
const instance = bootstrap.Modal.getInstance(openModal);
|
|
||||||
if (instance) instance.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Répare le bug d'écran figé après fermeture
|
|
||||||
document.addEventListener('hidden.bs.modal', function () {
|
|
||||||
if (!document.querySelector('.modal.show')) {
|
|
||||||
document.body.classList.remove('modal-open');
|
|
||||||
document.body.style.removeProperty('padding-right');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
const forms = document.querySelectorAll('form[action*="ajouter-document"]');
|
|
||||||
forms.forEach(form => {
|
|
||||||
form.addEventListener('submit', function (e) {
|
|
||||||
const btn = form.querySelector('button[type="submit"]');
|
|
||||||
const modalEl = form.closest('.modal');
|
|
||||||
if (btn) {
|
|
||||||
btn.disabled = true;
|
|
||||||
btn.innerHTML = '<i class="bi bi-hourglass-split"></i> Enregistrement...';
|
|
||||||
}
|
|
||||||
if (modalEl) {
|
|
||||||
const modalInstance = bootstrap.Modal.getInstance(modalEl);
|
|
||||||
if (modalInstance) modalInstance.hide();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const messageModalEl = document.getElementById('messageModal');
|
|
||||||
if (messageModalEl) {
|
|
||||||
const messageModal = new bootstrap.Modal(messageModalEl);
|
|
||||||
messageModal.show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,223 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Paramètres RH</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #993d00, #b34700);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
<!-- Sidebar -->
|
|
||||||
{% include 'menu_principal.html' %}
|
|
||||||
|
|
||||||
<!-- Main -->
|
|
||||||
<main class="col px-2 py-4" style="margin-left: 280px;">
|
|
||||||
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
<!-- Modal message -->
|
|
||||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark
|
|
||||||
{% if messages.0.tags == 'error' %}bg-orange-dark text-white
|
|
||||||
{% elif messages.0.tags == 'success' %}bg-orange-dark text-white
|
|
||||||
{% else %}bg-orange-dark text-white{% endif %}">
|
|
||||||
<h5 class="modal-title" id="messageModalLabel">
|
|
||||||
{% if messages.0.tags == 'error' %}Erreur
|
|
||||||
{% elif messages.0.tags == 'success' %}Succès
|
|
||||||
{% else %}Information{% endif %}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% for message in messages %}
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var messageModal = new bootstrap.Modal(document.getElementById('messageModal'));
|
|
||||||
messageModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<h2 class="mb-4"><i class="bi bi-gear-fill"></i> Paramètres Administration</h2>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<!-- Colonne Départements -->
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
||||||
<h5><i class="bi bi-building"></i> Départements</h5>
|
|
||||||
<button class="btn bg-orange-dark btn-sm" data-bs-toggle="modal" data-bs-target="#modalAjouterDepartement">
|
|
||||||
<i class="bi bi-plus-circle"></i> Ajouter
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Ajout -->
|
|
||||||
<div class="modal fade" id="modalAjouterDepartement" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<form method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="ajouter_departement" value="1">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">Ajouter un département</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{{ form_departement.as_p }}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn bg-orange-dark">Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Liste des départements -->
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for d in departements %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ d.nom }}
|
|
||||||
<div>
|
|
||||||
<!-- Bouton détails -->
|
|
||||||
<button class="btn btn-sm btn-outline-info" data-bs-toggle="modal" data-bs-target="#modalDetailDepartement{{ d.id }}">
|
|
||||||
<i class="bi bi-eye"></i> Détails
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Bouton modification -->
|
|
||||||
<button class="btn btn-sm btn-outline-primary" data-bs-toggle="modal" data-bs-target="#modalModifierDepartement{{ d.id }}">
|
|
||||||
<i class="bi bi-pencil-square"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
|
|
||||||
<form method="POST" style="display:inline;">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="supprimer_departement" value="1">
|
|
||||||
<input type="hidden" name="departement_id" value="{{ d.id }}">
|
|
||||||
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('Voulez-vous vraiment supprimer ce département ?');">
|
|
||||||
<i class="bi bi-trash"></i>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</li><!-- Modal détails -->
|
|
||||||
<div class="modal fade" id="modalDetailDepartement{{ d.id }}" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">Détails du département</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p><strong>Nom :</strong> {{ d.nom }}</p>
|
|
||||||
<p><strong>Chef :</strong> {% if d.chef %}{{ d.chef.first_name }} {{ d.chef.last_name }}{% else %}Non défini{% endif %}</p>
|
|
||||||
|
|
||||||
<!-- Liste des employés du département -->
|
|
||||||
{% for emp in d.employe_set.all %}
|
|
||||||
<p>- {{ emp.username }}</p>
|
|
||||||
{% empty %}
|
|
||||||
<p>Aucun employé associé</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<div class="modal fade" id="modalModifierDepartement{{ d.id }}" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<form method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="modifier_departement" value="1">
|
|
||||||
<input type="hidden" name="departement_id" value="{{ d.id }}">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark text-white">
|
|
||||||
<h5 class="modal-title">Modifier le département</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<!-- Nom du département -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="nom_{{ d.id }}" class="form-label">Nom du département</label>
|
|
||||||
<input type="text" class="form-control" id="nom_{{ d.id }}" name="nom" value="{{ d.nom }}" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Sélection du chef -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="chef_{{ d.id }}" class="form-label">Chef du département</label>
|
|
||||||
<select class="form-select" id="chef_{{ d.id }}" name="chef">
|
|
||||||
<option value="">-- Aucun chef --</option>
|
|
||||||
{% for emp in employes %}
|
|
||||||
<option value="{{ emp.id }}" {% if d.chef and emp.id == d.chef.id %}selected{% endif %}>
|
|
||||||
{{ emp.first_name }} {{ emp.last_name }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn bg-orange-dark">Modifier</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Colonne Groupes -->
|
|
||||||
<div class="col-md-6">
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2">
|
|
||||||
<h5><i class="bi bi-person-badge-fill"></i> Groupes et rôles</h5>
|
|
||||||
<button class="btn bg-orange-dark btn-sm">Ajouter</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for g in groupes %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ g.name }}
|
|
||||||
<a href="{% url 'admin:auth_group_change' g.id %}" class="btn btn-sm btn-outline-secondary">
|
|
||||||
<i class="bi bi-pencil"></i>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,205 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Tableau de Bord RH</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
h1 { font-weight: 700; }
|
|
||||||
.card { border-radius: 15px; }
|
|
||||||
.chart-container { position: relative; height: 350px; }
|
|
||||||
table { min-width: 100%; }
|
|
||||||
|
|
||||||
/* Couleurs oranges */
|
|
||||||
.bg-orange-dark { background: linear-gradient(90deg, #b35400, #cc6600); color: white; }
|
|
||||||
.bg-orange { background: #ff9f1c; color: white; }
|
|
||||||
.bg-orange-light { background: #ffc107; color: #212529; }
|
|
||||||
|
|
||||||
/* Badges */
|
|
||||||
.badge-warning { background-color: #ffc107; color: #212529; }
|
|
||||||
.badge-success { background-color: #28a745; color: #fff; }
|
|
||||||
.badge-primary { background-color: #007bff; color: #fff; }
|
|
||||||
|
|
||||||
@media print {
|
|
||||||
body * { visibility: hidden; }
|
|
||||||
.printable-table, .printable-table * { visibility: visible; }
|
|
||||||
.printable-table { position: absolute; top: 0; left: 0; width: 100%; }
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container-fluid py-4">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
{% include 'menu_principal.html' %}
|
|
||||||
|
|
||||||
<main class="col px-2 py-4" style="margin-left: 280px;">
|
|
||||||
<h1 class="mb-5 text-center"><i class="bi bi-bar-chart-line-fill me-2"></i>Tableau de Bord RH</h1>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Filtres -->
|
|
||||||
<form method="GET" class="row g-3 mb-5">
|
|
||||||
<div class="col-md-4">
|
|
||||||
<select name="mois" class="form-select">
|
|
||||||
<option value="">Tous les mois</option>
|
|
||||||
{% for num, nom in mois_liste %}
|
|
||||||
<option value="{{ num }}" {% if mois_selectionne == num %}selected{% endif %}>{{ nom }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<select name="departement" class="form-select">
|
|
||||||
<option value="">Tous les départements</option>
|
|
||||||
{% for d in departements %}
|
|
||||||
<option value="{{ d.id }}" {% if departement_selectionne == d.id %}selected{% endif %}>{{ d.nom }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<button type="submit" class="btn btn-outline-primary w-100"><i class="bi bi-search"></i> Filtrer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Cartes statistiques -->
|
|
||||||
<div class="row g-4 mb-5">
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-people me-2"></i>Total Employés</h6><h3 class="fw-bold">{{ total_employes }}</h3></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-gender-male me-2"></i>Hommes</h6><h3 class="fw-bold">{{ hommes }}</h3></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-gender-female me-2"></i>Femmes</h6><h3 class="fw-bold">{{ femmes }}</h3></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-clock-history me-2"></i>Contrats expirants(2mois)</h6><h3 class="fw-bold">{{ expirants }}</h3></div></div></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-4 mb-5">
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-header fw-bold"><i class="bi bi-airplane me-2"></i>Congés en attente</div><div class="card-body"><h5 class="display-6 fw-bold">{{ conges_attente }}</h5></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-body"><h6 class="fw-bold"><i class="bi bi-kanban me-2"></i>Projets</h6><h6>(actifs / total)</h6><h3 class="fw-bold">{{ nb_projets_actifs }} / {{ nb_projets }}</h3></div></div></div>
|
|
||||||
<div class="col-md-3"><div class="card text-center"><div class="card-header fw-bold"><i class="bi bi-clock-history me-2"></i>Âge moyen</div><div class="card-body"><h5 class="display-6 fw-bold">{{ age_moyen }} ans</h5></div></div></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Graphiques -->
|
|
||||||
<div class="row g-4 mb-5">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card shadow"><div class="card-header bg-orange-dark text-white"><i class="bi bi-pie-chart-fill me-2"></i> Répartition par Département</div>
|
|
||||||
<div class="card-body chart-container"><canvas id="chartDepartement"></canvas></div></div>
|
|
||||||
</div>
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card shadow"><div class="card-header bg-orange-dark text-white"><i class="bi bi-pie-chart-fill me-2"></i> Répartition par genre</div>
|
|
||||||
<div class="card-body chart-container"><canvas id="chartSexe"></canvas></div></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row g-4 mb-6">
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card shadow"><div class="card-header bg-orange-dark text-white"><i class="bi bi-bar-chart-fill me-2"></i> Projets (En cours / Terminés)</div>
|
|
||||||
<div class="card-body chart-container"><canvas id="chartProjets"></canvas></div></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="col-lg-6">
|
|
||||||
<div class="card shadow"><div class="card-header bg-orange-dark text-white"><i class="bi bi-bar-chart-fill me-2"></i> Projets par domaine de recherche</div>
|
|
||||||
<div class="card-body chart-container"><canvas id="chartDomaine"></canvas></div></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
const couleursOrange = ['#b35400', '#ff9f1c', '#ffc107', '#ffb84d', '#ffcc80'];
|
|
||||||
const departementLabels = {{ departement_labels|safe }};
|
|
||||||
const departementCounts = {{ departement_counts|safe }};
|
|
||||||
const sexeLabels = {{ sexe_labels|safe }};
|
|
||||||
const sexeCounts = {{ sexe_counts|safe }};
|
|
||||||
const projetLabels = {{ projet_labels|safe }};
|
|
||||||
const projetCounts = {{ projet_counts|safe }};
|
|
||||||
const ticketsLabels = ["Traités", "Non traités"];
|
|
||||||
const ticketsCounts = [{{ tickets_traite }}, {{ tickets_non_traite }}];
|
|
||||||
const domaineLabels = {{ domaine_labels|safe }};
|
|
||||||
const domaineCounts = {{ domaine_counts|safe }};
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartDepartement"), {
|
|
||||||
type: 'pie',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: departementLabels,
|
|
||||||
datasets: [{ data: departementCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
plugins: {
|
|
||||||
legend: { position: 'bottom' },
|
|
||||||
datalabels: { color: '#fff', font: { weight: 'bold', size: 14 }, formatter: v => v }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartSexe"), {
|
|
||||||
type: 'doughnut',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: sexeLabels,
|
|
||||||
datasets: [{ data: sexeCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
plugins: {
|
|
||||||
legend: { position: 'bottom' },
|
|
||||||
datalabels: { color: '#fff', font: { weight: 'bold', size: 14 }, formatter: v => v }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartProjets"), {
|
|
||||||
type: 'bar',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: projetLabels,
|
|
||||||
datasets: [{ label:'Nombre de projets', data: projetCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: { display: false },
|
|
||||||
datalabels: { anchor:'end', align:'top', color:'#000', font:{ weight:'bold', size:16 }, formatter:v => v }
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: { beginAtZero:true, ticks:{ stepSize:1, precision:0 }, title:{ display:true, text:'Nombre de projets' } },
|
|
||||||
x: { title:{ display:true, text:'' } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
new Chart(document.getElementById("chartDomaine"), {
|
|
||||||
type: 'bar',
|
|
||||||
plugins: [ChartDataLabels],
|
|
||||||
data: {
|
|
||||||
labels: domaineLabels,
|
|
||||||
datasets: [{ label:'Nombre de projets', data: domaineCounts, backgroundColor: couleursOrange }]
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
responsive: true,
|
|
||||||
plugins: {
|
|
||||||
legend: { display: false },
|
|
||||||
datalabels: { anchor:'end', align:'top', color:'#000', font:{ weight:'bold', size:14 }, formatter:v => v }
|
|
||||||
},
|
|
||||||
scales: {
|
|
||||||
y: { beginAtZero:true, title:{ display:true, text:'Nombre de projets' }, ticks:{ precision:0, stepSize:1 } },
|
|
||||||
x: {
|
|
||||||
ticks:{ autoSkip:false, maxRotation:100, minRotation:30, callback: function(value){ return this.getLabelForValue(value); } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
document.getElementById('btnVoirRapport').addEventListener('click', function() {
|
|
||||||
const projetId = document.getElementById('projetId').value;
|
|
||||||
if(!projetId) return alert("Veuillez sélectionner un projet.");
|
|
||||||
fetch(`/rapports/projet/${projetId}/`)
|
|
||||||
.then(resp => { if(!resp.ok) throw new Error("Projet non trouvé"); return resp.text(); })
|
|
||||||
.then(html => { document.getElementById('contenuRapportProjet').innerHTML = html; })
|
|
||||||
.catch(err => { document.getElementById('contenuRapportProjet').innerHTML = "<p class='text-danger'>Erreur lors du chargement.</p>"; console.error(err); });
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<title>Mot de passe oublié</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
</head>
|
|
||||||
<body class="container mt-5">
|
|
||||||
<div class="p-4 shadow-sm rounded bg-white" style="max-width: 400px; margin:auto;">
|
|
||||||
<h2 class="mb-4 text-center" style="color:rgba(255, 157, 0, 0.895);">🔑 Réinitialiser le mot de passe</h2>
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-info">{{ message }}</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<form method="POST">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="email">Adresse e-mail</label>
|
|
||||||
<input type="email" name="email" class="form-control" placeholder="Entrez votre email" required>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary w-100">Envoyer le lien</button>
|
|
||||||
</form>
|
|
||||||
<p class="mt-3 text-center">
|
|
||||||
<a href="{% url 'login' %}">Retour à la connexion</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,620 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load roles %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Mes demandes</title>
|
|
||||||
<link rel="stylesheet" href="{% static 'bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link rel="stylesheet" href="{% static 'styles.css' %}">
|
|
||||||
<style>
|
|
||||||
@keyframes pulse {
|
|
||||||
0% { transform: scale(1); }
|
|
||||||
50% { transform: scale(1.2); }
|
|
||||||
100% { transform: scale(1); }
|
|
||||||
}
|
|
||||||
|
|
||||||
.bg-orange-dark {
|
|
||||||
background: linear-gradient(90deg, #b35400, #cc6600);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
<nav class="col-12 col-md-3 col-lg-2 sidebar p-3">
|
|
||||||
{% include 'menu_principal.html' %}
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<main class="col px-4 py-4">
|
|
||||||
|
|
||||||
<!-- Boutons Notifications -->
|
|
||||||
{% if notifications %}
|
|
||||||
<div class="d-flex justify-content-end mb-3">
|
|
||||||
<button type="button" class="btn position-relative" data-bs-toggle="modal" data-bs-target="#modalNotifications">
|
|
||||||
<i class="bi bi-bell-fill"></i> Notifications
|
|
||||||
<span class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
|
|
||||||
{{ notifications|length }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Bouton Notifications -->
|
|
||||||
{% if notifications_employe %}
|
|
||||||
<div class="d-flex justify-content-end mb-3">
|
|
||||||
<button type="button" class="btn position-relative" data-bs-toggle="modal" data-bs-target="#modalNotifications">
|
|
||||||
<i class="bi bi-bell-fill"></i> Notifications
|
|
||||||
<span id="badgeNotifications" class="position-absolute top-0 start-100 translate-middle badge rounded-pill bg-danger">
|
|
||||||
{{ notifications_employe|length }}
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Modal Notifications -->
|
|
||||||
<div class="modal fade" id="modalNotifications" tabindex="-1" aria-labelledby="modalNotificationsLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="modalNotificationsLabel">Mes Notifications</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% if notifications_employe %}
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for notif in notifications_employe %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
{{ notif.message|default:"Nouvelle notification" }}
|
|
||||||
<small class="text-muted">{{ notif.date_created|date:"d/m/Y H:i" }}</small>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% else %}
|
|
||||||
<p class="text-muted">Aucune notification pour le moment.</p>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
var modal = document.getElementById('modalNotifications');
|
|
||||||
|
|
||||||
modal.addEventListener('show.bs.modal', function () {
|
|
||||||
fetch("{% url 'notifications-lues' %}", {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'X-CSRFToken': '{{ csrf_token }}',
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify({})
|
|
||||||
})
|
|
||||||
.then(res => res.json())
|
|
||||||
.then(data => {
|
|
||||||
if(data.status === "ok"){
|
|
||||||
document.getElementById('badgeNotifications').style.display = 'none';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
<h1 class="mb-4">La liste des demandes de congés</h1>
|
|
||||||
<!-- Cartes Statistiques -->
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="card text-white ">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title"><i class="bi bi-list-check me-2"></i> Total Demandes</h6>
|
|
||||||
<p class="card-text fs-4">{{ total }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="card text-white ">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title"><i class="bi bi-check-circle me-2"></i> Validés</h6>
|
|
||||||
<p class="card-text fs-4">{{ valides }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="card text-white ">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title"><i class="bi bi-x-circle me-2"></i> Refusés</h6>
|
|
||||||
<p class="card-text fs-4">{{ refuses }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-3">
|
|
||||||
<div class="card text-dark ">
|
|
||||||
<div class="card-body">
|
|
||||||
<h6 class="card-title"><i class="bi bi-hourglass-split me-2"></i> En attente</h6>
|
|
||||||
<p class="card-text fs-4">{{ attentes }}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% if messages %}
|
|
||||||
<!-- Modal message -->
|
|
||||||
<div class="modal fade" id="messageModal" tabindex="-1" aria-labelledby="messageModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark
|
|
||||||
{% if messages.0.tags == 'error' %}bg-danger text-white
|
|
||||||
{% elif messages.0.tags == 'success' %}bg-success text-white
|
|
||||||
{% else %}bg-info text-white{% endif %}">
|
|
||||||
<h5 class="modal-title" id="messageModalLabel">
|
|
||||||
{% if messages.0.tags == 'error' %}Erreur
|
|
||||||
{% elif messages.0.tags == 'success' %}Succès
|
|
||||||
{% else %}Information{% endif %}
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% for message in messages %}
|
|
||||||
<p>{{ message }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
var messageModal = new bootstrap.Modal(document.getElementById('messageModal'));
|
|
||||||
messageModal.show();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Bouton Nouvelle Demande -->
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3">
|
|
||||||
<h2><i class="bi bi-people"></i> Liste</h2>
|
|
||||||
<button type="button" class="btn btn-primary mb-3" data-bs-toggle="modal" data-bs-target="#modalDemandeConge">
|
|
||||||
<i class="bi bi-calendar-plus"></i> Nouvelle demande de congé
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal Nouvelle Demande -->
|
|
||||||
<div class="modal fade" id="modalDemandeConge" tabindex="-1" aria-labelledby="modalDemandeCongeLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post" enctype="multipart/form-data">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title" id="modalDemandeCongeLabel">
|
|
||||||
<i class="bi bi-calendar-plus me-2"></i> Nouvelle demande de congé
|
|
||||||
</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Fermer"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<fieldset class="border p-3 rounded">
|
|
||||||
<legend class="fw-bold">Informations du congé
|
|
||||||
Il vous reste {{ employe.solde_conge }} jours de congé Annuel
|
|
||||||
</legend>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
{{ form.type.label_tag }} {{ form.type }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
{{ form.date_debut.label_tag }} {{ form.date_debut }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
{{ form.date_fin.label_tag }} {{ form.date_fin }}
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6 mb-3">
|
|
||||||
{{ form.nombre_jours.label_tag }} {{ form.nombre_jours }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-success">
|
|
||||||
<i class="bi bi-send"></i> Envoyer
|
|
||||||
</button>
|
|
||||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
|
||||||
<i class="bi bi-x-circle"></i> Annuler
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Tableau des demandes -->
|
|
||||||
<table class="table table-striped mt-2">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Employe</th>
|
|
||||||
<th>Date demande</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Date début</th>
|
|
||||||
<th>Date fin</th>
|
|
||||||
<th>Nombre jours</th>
|
|
||||||
<th>Jours restant</th>
|
|
||||||
<th>Statut</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for conge in conges %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ conge.employe.first_name }} {{ conge.employe.last_name }}</td>
|
|
||||||
|
|
||||||
<td>{{ conge.date_demande|date:"d/m/Y" }}</td>
|
|
||||||
<td>{{ conge.type }}</td>
|
|
||||||
<td>{{ conge.date_debut|date:"d/m/Y"}}</td>
|
|
||||||
<td>{{ conge.date_fin|date:"d/m/Y" }}</td>
|
|
||||||
<td>{{ conge.nombre_jours }}</td>
|
|
||||||
|
|
||||||
<td>{{ conge.employe.solde_conge }} </td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
{% if conge.statut == "Refusé" %}
|
|
||||||
<span class="badge bg-danger">Refusé</span>
|
|
||||||
{% elif conge.statut == "Validé directeur" %}
|
|
||||||
<span class="badge bg-success">Valide </span>
|
|
||||||
{% elif conge.statut == "Validé chef" %}
|
|
||||||
<span class="badge bg-warning">Approuvé </span>
|
|
||||||
{% elif conge.statut == "Refusé par chef" %}
|
|
||||||
<span class="badge bg-danger">Refusé </span>
|
|
||||||
{% elif conge.statut == "En attente" %}
|
|
||||||
<span class="badge bg-warning">En attente </span>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-sm btn-info"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#detailsCongeModal{{ conge.id }}">
|
|
||||||
<i class="bi bi-eye"></i> Voir
|
|
||||||
</button>
|
|
||||||
{% if conge.statut == "En attente" and conge.employe == request.user %}
|
|
||||||
<!-- Bouton modifier -->
|
|
||||||
<button class="btn btn-sm btn-primary"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#modifierCongeModal{{ conge.id }}">
|
|
||||||
Modifier
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Bouton supprimer -->
|
|
||||||
<button class="btn btn-sm btn-danger"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#supprimerCongeModal{{ conge.id }}">
|
|
||||||
Supprimer
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
</td>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{% for conge in conges %}
|
|
||||||
<div class="modal fade" id="modifierCongeModal{{ conge.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="conge_id" value="{{ conge.id }}">
|
|
||||||
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Modifier la demande de congé</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Type de congé</label>
|
|
||||||
<select name="type" class="form-select">
|
|
||||||
<option value="Conge Annuel" {% if conge.type == "Conge Annuel" %}selected{% endif %}>Conge Annuel</option>
|
|
||||||
<option value="Maladie" {% if conge.type == "Maladie" %}selected{% endif %}>Maladie</option>
|
|
||||||
<option value="Vacances" {% if conge.type == "Vacances" %}selected{% endif %}>Vacances</option>
|
|
||||||
<option value="Maternité" {% if conge.type == "Maternité" %}selected{% endif %}>Maternité</option>
|
|
||||||
|
|
||||||
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Nombre de jours</label>
|
|
||||||
<input type="number" name="nombre_jours" class="form-control" value="{{ conge.nombre_jours }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Date début</label>
|
|
||||||
<input type="date" name="date_debut" class="form-control" value="{{ conge.date_debut|date:'Y-m-d' }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mb-2">
|
|
||||||
<label>Date fin</label>
|
|
||||||
<input type="date" name="date_fin" class="form-control" value="{{ conge.date_fin|date:'Y-m-d' }}">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-primary">Enregistrer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% for conge in conges %}
|
|
||||||
<div class="modal fade" id="detailsCongeModal{{ conge.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-lg">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Détails de la demande</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<ul class="list-group list-group-flush">
|
|
||||||
<li class="list-group-item"><strong>Employé :</strong> {{ conge.employe.first_name }} {{ conge.employe.last_name }}</li>
|
|
||||||
<li class="list-group-item"><strong>Type de congé :</strong> {{ conge.type }}</li>
|
|
||||||
<li class="list-group-item"><strong>Date début :</strong> {{ conge.date_debut|date:"d/m/Y" }}</li>
|
|
||||||
<li class="list-group-item"><strong>Date fin :</strong> {{ conge.date_fin|date:"d/m/Y" }}</li>
|
|
||||||
<li class="list-group-item"><strong>Nombre de jours :</strong> {{ conge.nombre_jours }}</li>
|
|
||||||
<li class="list-group-item"><strong>Solde restant :</strong> {{ conge.employe.solde_conge }}</li>
|
|
||||||
<li class="list-group-item">
|
|
||||||
<strong>Statut :</strong>
|
|
||||||
{% if conge.statut == "En attente" %}
|
|
||||||
<span class="badge bg-warning text-dark">{{ conge.statut }}</span>
|
|
||||||
{% elif conge.statut == "Validé directeur" %}
|
|
||||||
<span class="badge bg-success">Validé</span>
|
|
||||||
{% elif conge.statut == "Refusé" %}
|
|
||||||
<span class="badge bg-danger">Refusé</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-secondary">{{ conge.statut }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</li>
|
|
||||||
<li class="list-group-item"><strong>Motif :</strong> {{ conge.motif_refus|default:"—" }}</li>
|
|
||||||
<li class="list-group-item"><strong>Date de la demande :</strong> {{ conge.date_demande|date:"d/m/Y H:i" }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
|
|
||||||
{% for conge in conges %}
|
|
||||||
<!-- Modal supprimer -->
|
|
||||||
<div class="modal fade" id="supprimerCongeModal{{ conge.id }}" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="post">
|
|
||||||
{% csrf_token %}
|
|
||||||
<input type="hidden" name="delete_id" value="{{ conge.id }}">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Supprimer la demande</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p>Voulez-vous vraiment supprimer la demande de congé du
|
|
||||||
<strong>{{ conge.date_debut|date:"d/m/Y" }}</strong> au
|
|
||||||
<strong>{{ conge.date_fin|date:"d/m/Y" }}</strong> ?</p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
<button type="submit" class="btn btn-danger">Supprimer</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
</tr>
|
|
||||||
{% empty %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="10" class="text-center text-muted">Aucune demande trouvée.</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Pagination -->
|
|
||||||
<nav>
|
|
||||||
<ul class="pagination">
|
|
||||||
{% for page_num in conges.paginator.page_range %}
|
|
||||||
<li class="page-item {% if conges.number == page_num %}active{% endif %}">
|
|
||||||
<a class="page-link" href="?page={{ page_num }}&search={{ search }}">{{ page_num }}</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
<!-- Modal Notifications Chef -->
|
|
||||||
<div class="modal fade" id="modalNotifications" tabindex="-1" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title"><i class="bi bi-bell-fill me-2"></i> Demandes de congé en attente</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
{% if notifications %}
|
|
||||||
<table class="table table-bordered table-hover">
|
|
||||||
<thead class="table-light">
|
|
||||||
<tr>
|
|
||||||
<th>Employé</th>
|
|
||||||
<th>Période</th>
|
|
||||||
<th>Jours</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for conge in notifications %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ conge.employe.first_name }} {{ conge.employe.last_name }}</td>
|
|
||||||
<td>{{ conge.date_debut|date:"d/m/Y" }} - {{ conge.date_fin|date:"d/m/Y" }}</td>
|
|
||||||
<td>{{ conge.nombre_jours }}</td>
|
|
||||||
<td>{{ conge.type }}</td>
|
|
||||||
<td class="d-flex gap-1">
|
|
||||||
|
|
||||||
<!-- Valider -->
|
|
||||||
<form method="POST" action="{% url 'valider-par-chef' conge.id %}">
|
|
||||||
{% csrf_token %}
|
|
||||||
<button type="submit" class="btn btn-success btn-sm" title="Valider">
|
|
||||||
<i class="bi bi-check-circle"></i>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
|
|
||||||
<!-- Refuser -->
|
|
||||||
<button class="btn btn-danger btn-sm btn-refuser"
|
|
||||||
data-id="{{ conge.id }}"
|
|
||||||
data-nom="{{ conge.employe.first_name }} {{ conge.employe.last_name }}"
|
|
||||||
data-bs-toggle="modal"
|
|
||||||
data-bs-target="#modalRefuserGlobal">
|
|
||||||
<i class="bi bi-x-circle"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
{% else %}
|
|
||||||
<div class="alert alert-info">Aucune demande en attente.</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Modal Refuser -->
|
|
||||||
<div class="modal fade" id="modalRefuserGlobal" tabindex="-1">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<form method="POST" id="formRefuser">
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="modal-header bg-orange-dark">
|
|
||||||
<h5 class="modal-title">Refuser la demande</h5>
|
|
||||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<p id="texteConge"></p>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label class="form-label">Motif du refus</label>
|
|
||||||
{{ form.motif_refus }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="submit" class="btn btn-danger">Refuser</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
|
||||||
const modal = new bootstrap.Modal(document.getElementById('modalRefuserGlobal'));
|
|
||||||
const texteConge = document.getElementById('texteConge');
|
|
||||||
const formRefuser = document.getElementById('formRefuser');
|
|
||||||
|
|
||||||
document.querySelectorAll('.btn-refuser').forEach(button => {
|
|
||||||
button.addEventListener('click', function() {
|
|
||||||
const congeId = this.getAttribute('data-id');
|
|
||||||
const nomEmploye = this.getAttribute('data-nom');
|
|
||||||
|
|
||||||
texteConge.innerHTML = `Refuser le congé de <strong>${nomEmploye}</strong> ?`;
|
|
||||||
formRefuser.action = `/refuser-par-chef/${congeId}/`; // URL dynamique vers Django
|
|
||||||
formRefuser.reset();
|
|
||||||
modal.show();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
|
||||||
<script>
|
|
||||||
if ('serviceWorker' in navigator) {
|
|
||||||
window.addEventListener('load', function() {
|
|
||||||
navigator.serviceWorker.register('{% static "sw.js" %}').then(function(reg) {
|
|
||||||
console.log('Service worker registered.', reg);
|
|
||||||
}).catch(function(err) {
|
|
||||||
console.warn('Service worker registration failed:', err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load tags_personnaliser %}
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
|
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css">
|
|
||||||
<link href="https://unpkg.com/tabulator-tables@6.4.0/dist/css/tabulator_bootstrap5.min.css" rel="stylesheet">
|
|
||||||
|
|
||||||
{% block 'css' %}{% endblock %}
|
|
||||||
<title> {% block 'titre_page'%}{% endblock%}</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container-fluid">
|
|
||||||
<div class="row flex-nowrap">
|
|
||||||
{% include 'parts/menu_principal.html' %}
|
|
||||||
<div class="col-9 p-4">
|
|
||||||
{% block 'contenu' %} {% endblock %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% block 'modal' %} {% endblock %}
|
|
||||||
</div>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/3.7.2/luxon.min.js"></script>
|
|
||||||
<script type="text/javascript" src="https://unpkg.com/tabulator-tables/dist/js/tabulator.min.js"></script>
|
|
||||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.8/js/bootstrap.min.js"></script>
|
|
||||||
{% block 'js' %} {% endblock%}
|
|
||||||
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="fr">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<link rel="stylesheet" href="{% static 'css/bootstrap.min.css' %}">
|
|
||||||
<title>Login - SIRH</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container-fluid vh-100">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-6 vh-100 d-flex flex-column justify-content-center align-items-center">
|
|
||||||
<img src="{% static 'img/cerfig.jpg' %}" class="w-50">
|
|
||||||
<h5 class="text-center">Bienvenue sur les systèmes de gestion du CERFIG</h5>
|
|
||||||
</div>
|
|
||||||
<div class="col-6 vh-100 d-flex justify-content-center align-items-center">
|
|
||||||
<form method="POST" action="{% url 'login' %}" class="w-100 shadow rounded px-3 py-5">
|
|
||||||
<h2 class="text-center">Connexion</h2>
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}success{% endif %}">{{message}}</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="mail">Votre adresse email :</label>
|
|
||||||
<input type="text" name="mail" class="form-control" placeholder="Entrez votre e-mail" required>
|
|
||||||
</div>
|
|
||||||
<div class="mb-3">
|
|
||||||
<label for="mot_de_passe">Mot de passe</label>
|
|
||||||
<input type="password" name="mot_de_passe" class="form-control" placeholder="Entrez votre mot de passe" required>
|
|
||||||
<i class="bi bi-eye toggle-password" onclick="togglePassword()"
|
|
||||||
style="position:absolute; right:10px; top:38px; cursor:pointer;"></i>
|
|
||||||
</div>
|
|
||||||
<button type="submit" class="btn btn-primary w-100">Se connecter</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{% load static %}
|
|
||||||
{% load tags_personnaliser %}
|
|
||||||
|
|
||||||
<div class="col-3 bg-danger d-flex flex-column vh-100 pt-5 sticky-top">
|
|
||||||
<div class="text-center mb-4">
|
|
||||||
{% if user.employe.photo %}
|
|
||||||
<img src="{{ user.employe.photo.url }}"
|
|
||||||
class="rounded-circle"
|
|
||||||
width="80"
|
|
||||||
height="80"
|
|
||||||
style="object-fit:cover;">
|
|
||||||
{% else %}
|
|
||||||
<i class="bi bi-person-circle text-white" style="font-size:60px;"></i>
|
|
||||||
{% endif %}
|
|
||||||
<div class="text-white mt-2">
|
|
||||||
{{ user.username }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a href="{% url 'gestion_employe:mon-profil' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
|
||||||
<i class="bi bi-person-circle"></i> Mon profil
|
|
||||||
</a>
|
|
||||||
{% if user|has_group:"ressource_humaine" or user|has_group:"direction" %}
|
|
||||||
<a href="{% url 'gestion_employe:index' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
|
||||||
<i class="bi bi-speedometer2"></i> Tableau de bord
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if user|has_group:"ressource_humaine" or user|has_group:"direction" %}
|
|
||||||
<a href="{% url 'gestion_projet:index' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
|
||||||
<i class="bi bi-folder"></i> Gestion des Projets
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
<a href="{% url 'gestion_conges:conge' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
|
||||||
<i class="bi bi-airplane"></i> Gestion des congés
|
|
||||||
</a>
|
|
||||||
{% if user|is_chef_projet %}
|
|
||||||
<a href="{% url 'gestion_projet:activites-projet' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
|
||||||
<i class="bi bi-list-task"></i> Suivi des Activités
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
<a href="{% url 'gestion_salle:reservation-salle' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
|
||||||
<i class="bi bi-calendar-check"></i> Réservation
|
|
||||||
</a>
|
|
||||||
{% comment %} <a href="{% url 'rapport-rh' %}" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
|
||||||
<i class="bi bi-graph-up"></i> Rapports et Statistiques
|
|
||||||
</a> {% endcomment %}
|
|
||||||
{% comment %} <a href="" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
|
||||||
<i class="bi bi-person-gear"></i> Gestion des Utilisateurs
|
|
||||||
</a> {% endcomment %}
|
|
||||||
{% comment %} <a href="{% url 'gestion_employe:departement' %}" class="text-white fw-bold text-decoration-none mb-2" style="font-size:1.2em">
|
|
||||||
<i class="bi bi-gear"></i> Paramètres
|
|
||||||
</a> {% endcomment %}
|
|
||||||
<a href="{% url 'deconnexion' %}" class="text-white fw-bold text-decoration-none mb-4" style="font-size:1.4em">
|
|
||||||
<i class="bi bi-box-arrow-right"></i> Déconnexion
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
67
SIRH/urls.py
67
SIRH/urls.py
@@ -1,67 +0,0 @@
|
|||||||
"""
|
|
||||||
URL configuration for SIRH project.
|
|
||||||
|
|
||||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
|
||||||
https://docs.djangoproject.com/en/5.2/topics/http/urls/
|
|
||||||
Examples:
|
|
||||||
Function views
|
|
||||||
1. Add an import: from my_app import views
|
|
||||||
2. Add a URL to urlpatterns: path('', views.home, name='home')
|
|
||||||
Class-based views
|
|
||||||
1. Add an import: from other_app.views import Home
|
|
||||||
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
|
|
||||||
Including another URLconf
|
|
||||||
1. Import the include() function: from django.urls import include, path
|
|
||||||
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
|
|
||||||
"""
|
|
||||||
from django.contrib import admin
|
|
||||||
from django.urls import include, path
|
|
||||||
from django.conf.urls.static import static
|
|
||||||
from django.conf import settings
|
|
||||||
# from simple_sso.sso_server.server import Server
|
|
||||||
|
|
||||||
from . import views
|
|
||||||
|
|
||||||
# server_sso = Server()
|
|
||||||
|
|
||||||
urlpatterns = [
|
|
||||||
path(
|
|
||||||
'',
|
|
||||||
views.login_view,
|
|
||||||
name='index'
|
|
||||||
),
|
|
||||||
|
|
||||||
path('login/',
|
|
||||||
views.login_view,
|
|
||||||
name='login'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'deconnexion/',
|
|
||||||
views.deconnexion_view,
|
|
||||||
name='deconnexion'
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'employé/',
|
|
||||||
include("gestion_employe.urls")
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'gestion-conge/',
|
|
||||||
include("gestion_conge.urls")
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'gestion-projet/',
|
|
||||||
include("gestion_projet.urls")
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'gestion-salle/',
|
|
||||||
include("gestion_salle.urls")
|
|
||||||
),
|
|
||||||
path(
|
|
||||||
'admin/',
|
|
||||||
admin.site.urls
|
|
||||||
),
|
|
||||||
# path(
|
|
||||||
# 'sso',
|
|
||||||
# include(server_sso.get_urls())
|
|
||||||
# )
|
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
from django.contrib.auth import authenticate, login, logout
|
|
||||||
from django.shortcuts import render, redirect
|
|
||||||
from django.contrib import messages
|
|
||||||
|
|
||||||
def login_view(request):
|
|
||||||
"""
|
|
||||||
Gère la connexion des utilisateurs avec redirection selon le rôle et
|
|
||||||
vérification de l'acceptation de la politique d'utilisation.
|
|
||||||
"""
|
|
||||||
if request.method == 'POST':
|
|
||||||
email = request.POST.get('mail')
|
|
||||||
password = request.POST.get('mot_de_passe')
|
|
||||||
|
|
||||||
if not (email and password):
|
|
||||||
messages.error(request, "Veuillez remplir tous les champs.")
|
|
||||||
return render(request, 'login.html')
|
|
||||||
|
|
||||||
user = authenticate(request, username=email, password=password)
|
|
||||||
|
|
||||||
if user is None:
|
|
||||||
messages.error(request, "Nom d’utilisateur ou mot de passe incorrect.")
|
|
||||||
return render(request, 'login.html')
|
|
||||||
|
|
||||||
if not user.is_active:
|
|
||||||
messages.error(request, "Compte inactif. Contactez l'administrateur.")
|
|
||||||
return render(request, 'login.html')
|
|
||||||
|
|
||||||
login(request, user)
|
|
||||||
|
|
||||||
return redirect("gestion_conges:conge")
|
|
||||||
|
|
||||||
return render(request, 'login.html')
|
|
||||||
|
|
||||||
def deconnexion_view(request):
|
|
||||||
"""Gère la déconnexion de l'utilisateur."""
|
|
||||||
logout(request)
|
|
||||||
return redirect('login')
|
|
||||||
16
SIRH/wsgi.py
16
SIRH/wsgi.py
@@ -1,16 +0,0 @@
|
|||||||
"""
|
|
||||||
WSGI config for SIRH project.
|
|
||||||
|
|
||||||
It exposes the WSGI callable as a module-level variable named ``application``.
|
|
||||||
|
|
||||||
For more information on this file, see
|
|
||||||
https://docs.djangoproject.com/en/5.2/howto/deployment/wsgi/
|
|
||||||
"""
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from django.core.wsgi import get_wsgi_application
|
|
||||||
|
|
||||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'SIRH.settings')
|
|
||||||
|
|
||||||
application = get_wsgi_application()
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,34 +0,0 @@
|
|||||||
from django.utils import timezone
|
|
||||||
from gestion_employe.models import Contrat
|
|
||||||
from gestion_conge.models import Conge
|
|
||||||
|
|
||||||
|
|
||||||
QUOTA_CONGE_ANNUEL = 30
|
|
||||||
NOMBRE_PAGINATION = 8
|
|
||||||
DEBUT_RAPPEL = 60
|
|
||||||
DUREE_FIN_CONTRAT = 90
|
|
||||||
|
|
||||||
def solde_conge(employe):
|
|
||||||
"""Fonction de calcul du solde de congé restant l'employé"""
|
|
||||||
contrat = Contrat.objects.filter(employe=employe, statut='actif').order_by('-date_debut').first()
|
|
||||||
|
|
||||||
if contrat is None or not contrat.date_debut:
|
|
||||||
return {
|
|
||||||
"success": False,
|
|
||||||
"message": "Votre contrat de travail n'a pas été correctement renseigner. Veuillez contacter les ressources humaines."
|
|
||||||
}
|
|
||||||
|
|
||||||
conges = Conge.objects.filter(employe=employe, validation_direction=True, date_fin__year = timezone.now().date().year)
|
|
||||||
jours_conges_valider = sum([conge.nombre_jours for conge in conges])
|
|
||||||
|
|
||||||
if jours_conges_valider >= QUOTA_CONGE_ANNUEL:
|
|
||||||
return {
|
|
||||||
"success": False,
|
|
||||||
"message": "Vous avez atteint le nombre maximal de jours de congés. Veuillez contacter l'administration."
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
"success": True,
|
|
||||||
"quota_annuel": QUOTA_CONGE_ANNUEL - jours_conges_valider,
|
|
||||||
"nombre_jours_valide": jours_conges_valider
|
|
||||||
}
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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'
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
from django import forms
|
|
||||||
from .models import Conge
|
|
||||||
|
|
||||||
class CongeForm(forms.ModelForm):
|
|
||||||
"""Formulaire de demande de congé."""
|
|
||||||
class Meta:
|
|
||||||
model = Conge
|
|
||||||
fields =['type', 'date_debut', 'date_fin']
|
|
||||||
widgets = {
|
|
||||||
'date_debut': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
|
||||||
'date_fin': forms.DateInput(attrs={'type': 'date', 'class': 'form-control'}),
|
|
||||||
'type': forms.Select(attrs={'class': 'form-select'}),
|
|
||||||
}
|
|
||||||
|
|
||||||
labels = {
|
|
||||||
'nombre_jours':'Nombre de jours',
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# Generated by Django 5.2.13 on 2026-04-17 12:03
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('gestion_employe', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Conge',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('date_debut', models.DateField(verbose_name='Date de Début')),
|
|
||||||
('date_fin', models.DateField(verbose_name='Date de Fin')),
|
|
||||||
('type', models.CharField(choices=[('conge_annuel', 'Conge Annuel')], max_length=100, verbose_name='Type de Congé')),
|
|
||||||
('date_demande', models.DateField(auto_now_add=True, verbose_name='Date de Demande')),
|
|
||||||
('validation_hierarchique', models.BooleanField(default=None, null=True)),
|
|
||||||
('validation_direction', models.BooleanField(default=None, null=True)),
|
|
||||||
('motif_refus', models.TextField(blank=True, null=True)),
|
|
||||||
('employe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='employe', to='gestion_employe.employe')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user