clean: remove pycache from tracking
This commit is contained in:
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.
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,36 +0,0 @@
|
||||
import pandas as pd
|
||||
from django.db import models
|
||||
from gestion_employe.models import Employe
|
||||
|
||||
class Conge(models.Model):
|
||||
"""Modèle de création des congés"""
|
||||
TYPE_CHOICES = [
|
||||
# ('maladie', 'Maladie'),
|
||||
('conge_annuel', 'Conge Annuel'),
|
||||
# ('conge_maternite', 'Conge Maternité'),
|
||||
# ('conge_mariage', 'Conge Mariage'),
|
||||
# ('conge_naissance', 'Conge de Naissance'),
|
||||
# ('conge_deces_proche', 'Conge de décès d\'un proche'),
|
||||
# ('conge_mariage_proche', 'Conge de mariage d\'un proche'),
|
||||
# ('autre', 'Autre'),
|
||||
]
|
||||
|
||||
employe = models.ForeignKey(
|
||||
Employe,
|
||||
on_delete=models.CASCADE,
|
||||
related_name="employe"
|
||||
)
|
||||
date_debut = models.DateField(verbose_name='Date de Début')
|
||||
date_fin = models.DateField(verbose_name='Date de Fin')
|
||||
type = models.CharField(max_length=100, choices=TYPE_CHOICES, 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)
|
||||
|
||||
@property
|
||||
def nombre_jours(self):
|
||||
if self.date_debut and self.date_fin:
|
||||
jours = pd.bdate_range(start=self.date_debut, end=self.date_fin)
|
||||
return len(jours)
|
||||
@@ -1,75 +0,0 @@
|
||||
const bouton_enregistrer_detail = document.getElementById("bouton-enregistrer-detail-conge");
|
||||
|
||||
if(bouton_enregistrer_detail){
|
||||
bouton_enregistrer_detail.addEventListener("click", () => {
|
||||
const form = document.getElementById("form-detail-conge");
|
||||
const csrftoken = new FormData(form).get("csrfmiddlewaretoken");
|
||||
const actionUrl = form.action;
|
||||
const id_conge = document.getElementById("id_conge").value;
|
||||
const validation_hierarchique_input = document.querySelector('input[name="validation_hierarchique"]:checked');
|
||||
const validation_hierarchique = validation_hierarchique_input ? validation_hierarchique_input.value : null;
|
||||
const validation_direction_input = document.querySelector('input[name="validation_direction"]:checked');
|
||||
const validation_direction = validation_direction_input ? validation_direction_input.value : null;
|
||||
const motif_refus = document.getElementById("motif_refus").value;
|
||||
|
||||
fetch(actionUrl, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRFToken": csrftoken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
id_conge,
|
||||
validation_hierarchique,
|
||||
validation_direction,
|
||||
motif_refus
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
alert(data.message);
|
||||
navigation.reload();
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
if(document.getElementById("validation_hierarchique_refuse")){
|
||||
document.getElementById("validation_hierarchique_refuse").addEventListener('click', function(){
|
||||
if(this.checked){
|
||||
alert("coucou");
|
||||
document.getElementById("motif_refus_container").className="d-block form-group mt-3";
|
||||
}else{
|
||||
document.getElementById("motif_refus_container").className="d-none";
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(document.getElementById("validation_hierarchique_refuse")){
|
||||
document.getElementById("validation_hierarchique_refuse").addEventListener('click', function(){
|
||||
if(this.checked){
|
||||
document.getElementById("motif_refus_container").className="d-block form-group mt-3";
|
||||
}else{
|
||||
document.getElementById("motif_refus_container").className="d-none";
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(document.getElementById("validation_hierarchique_valide")){
|
||||
document.getElementById("validation_hierarchique_valide").addEventListener('click', function(){
|
||||
if(this.checked){
|
||||
document.getElementById("motif_refus_container").className="d-none";
|
||||
}else{
|
||||
document.getElementById("motif_refus_container").className="d-block form-group mt-3";
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(document.getElementById("validation_direction_valide")){
|
||||
document.getElementById("validation_direction_valide").addEventListener('click', function(){
|
||||
if(this.checked){
|
||||
document.getElementById("motif_refus_container").className="d-block form-group mt-3";
|
||||
}else{
|
||||
document.getElementById("motif_refus_container").className="d-none";
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
const $ = (element) => document.getElementById(element);
|
||||
|
||||
const url_liste_conge_attente = $("liste-demande-conges").dataset.url
|
||||
|
||||
const tableau_liste_demande_conge = new Tabulator("#liste-demande-conges", {
|
||||
layout : "fitColumns",
|
||||
columns: [
|
||||
{"title": "Nom et Prénom", "field": "prenom_nom"},
|
||||
{"title": "Date de début", "field": "date_debut", formatter:"datetime", formatterParams:{
|
||||
inputFormat:"yyyy-MM-dd",
|
||||
outputFormat:"dd/MM/yy",
|
||||
}},
|
||||
{"title": "Date de fin", "field": "date_fin", formatter:"datetime", formatterParams:{
|
||||
inputFormat:"yyyy-MM-dd",
|
||||
outputFormat:"dd/MM/yy",
|
||||
}},
|
||||
{"title": "Type de congé", "field": "type"},
|
||||
{"title": "Date de la demande", "field": "date_demande"},
|
||||
{"title": "Validation par supérieur hiérarchique", "field": "validation_hierarchique", formatter:"tickCross", formatterParams :{
|
||||
allowEmpty : true ,
|
||||
}},
|
||||
{"title": "Validation par supérieur hiérarchique", "field": "validation_direction", formatter:"tickCross", formatterParams :{
|
||||
allowEmpty : true ,
|
||||
}},
|
||||
],
|
||||
pagination: true,
|
||||
paginationSize: 5
|
||||
})
|
||||
|
||||
const bouton_demande_conges = $("bouton-demande-conge");
|
||||
|
||||
bouton_demande_conges.addEventListener("click", (e) => {
|
||||
var modalDemandeConge = new bootstrap.Modal(document.getElementById('modalDemandeConge'));
|
||||
modalDemandeConge.show();
|
||||
})
|
||||
|
||||
tableau_liste_demande_conge.on("rowClick", function(row, rowData) {
|
||||
const data = rowData.getData();
|
||||
$("id_conge").value = data.id;
|
||||
$("employe").value = data.prenom_nom;
|
||||
$("type_conge").value = data.type;
|
||||
$("date_debut").value = data.date_debut;
|
||||
$("date_fin").value = data.date_fin;
|
||||
$("date_demande").value = data.date_demande;
|
||||
$("nombre_jours").value = data.nombre_jours;
|
||||
$("solde_restant").value = data.solde_conge;
|
||||
$("motif_refus").value = data.motif_refus;
|
||||
|
||||
if($("validation_hierarchique_valide") & $("validation_hierarchique_refuse")){
|
||||
$("validation_hierarchique_valide").checked = data.validation_hierarchique === true;
|
||||
$("validation_hierarchique_refuse").checked = data.validation_hierarchique === false;
|
||||
}
|
||||
|
||||
if($("validation_direction_valide") & $("validation_direction_refuse")){
|
||||
$("validation_direction_valide").checked = data.validation_direction === true;
|
||||
$("validation_direction_refuse").checked = data.validation_direction === false;
|
||||
}
|
||||
|
||||
const modal = new bootstrap.Modal(document.getElementById('detailsCongeModal'));
|
||||
modal.show();
|
||||
});
|
||||
|
||||
fetch(url_liste_conge_attente)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if(data.success === true){
|
||||
tableau_liste_demande_conge.setData(data.data)
|
||||
}else{
|
||||
alert(data.message)
|
||||
}
|
||||
})
|
||||
@@ -1,51 +0,0 @@
|
||||
{% extends "BASE.html" %}
|
||||
{% load static %}
|
||||
{% block 'titre_page' %} Gestion des congés {% endblock %}
|
||||
{% block 'contenu' %}
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}success{% endif %}">{{message}}</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="row d-flex justify-content-center mb-4">
|
||||
<div class="col text-white bg-danger d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
||||
<div class="card-header fw-bold">
|
||||
<i class="bi bi-x-circle me-2"></i> Congés refusés
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<h5 class="fw-bold">{{ nombre_conges_refuse }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-white bg-warning d-flex flex-column justify-content-center align-items-center border rounded p-4 mx-2">
|
||||
<div class="card-header fw-bold">
|
||||
<i class="bi bi-hourglass-split me-2"></i> Congés en attente
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<h5 class="fw-bold">{{ nombre_conges_en_attente }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
||||
<div class="card-header fw-bold">
|
||||
<i class="bi bi-check-circle me-2"></i> Congés Validé
|
||||
</div>
|
||||
<div class="card-body text-center">
|
||||
<h5 class="fw-bold">{{ nombre_conges_valide }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-between my-4">
|
||||
<h3><i class="bi bi-list-ul"></i> Liste des demandes de congé</h3>
|
||||
<button class='btn btn-primary' id="bouton-demande-conge">Demande de congé</button>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<div id="liste-demande-conges" data-url="{% url 'gestion_conges:liste-des-conges' %}"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block 'modal' %}
|
||||
{% include 'gestion_conge/parts/modalDemandeConge.html' %}
|
||||
{% include 'gestion_conge/parts/modalDetailConge.html' %}
|
||||
{% endblock %}
|
||||
{% block 'js' %}
|
||||
<script type="text/javascript" src="{% static 'gestion_conge/js/index.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'gestion_conge/js/detail_conges.js' %}"></script>
|
||||
{% endblock %}
|
||||
@@ -1,26 +0,0 @@
|
||||
<div class="modal fade" id="modalDemandeConge" tabindex="-1" aria-labelledby="modalDemandeCongeLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<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">
|
||||
<form method="post" action="{% url 'gestion_conges:demande-conge' %}" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ formulaire_demande_conge.as_p }}
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-send"></i> Soumettre
|
||||
</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>
|
||||
</div>
|
||||
@@ -1,92 +0,0 @@
|
||||
<div class="modal fade" id="detailsCongeModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-orange-dark">
|
||||
<h5 class="modal-title">Détails de la demande de congés</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" id="form-detail-conge" action="{% url 'gestion_conges:validation-des-conges' %}">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" id="id_conge" value="">
|
||||
<div class="form-group mb-2">
|
||||
<label for="motif_refus">Employé :</label>
|
||||
<input type="text" class="form-control" id="employe" value="" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label for="type_conge">Type de congé :</label>
|
||||
<select class="form-select" id="type_conge" readonly>
|
||||
{% comment %} <option value="maladie">Maladie</option> {% endcomment %}
|
||||
<option value="Conge Annuel">Conge Annuel</option>
|
||||
{% comment %} <option value="conge_maternite">Conge Maternité</option> {% endcomment %}
|
||||
{% comment %} <option value="conge_mariage">Conge Mariage</option>
|
||||
<option value="conge_naissance">Conge Naissance</option>
|
||||
<option value="conge_deces_proche">Conge de décès d'un proche</option>
|
||||
<option value="conge_mariage_proche">Conge de mariage d'un proche</option>
|
||||
<option value="autre">Autre</option> {% endcomment %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label for="date_debut">Date début :</label>
|
||||
<input type="date" class="form-control" id="date_debut" value="" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label for="date_fin">Date fin :</label>
|
||||
<input type="date" class="form-control" id="date_fin" value="" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label for="nombre_jours">Nombre de jours :</label>
|
||||
<input type="number" class="form-control" id="nombre_jours" value="" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label for="solde_restant">Solde restant :</label>
|
||||
<input type="number" class="form-control" id="solde_restant" value="" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label for="date_demande">Date de la demande :</label>
|
||||
<input type="text" class="form-control" id="date_demande" value="" readonly>
|
||||
</div>
|
||||
{% if employe_est_il_chef or est_chef_projet %}
|
||||
<hr>
|
||||
<h5 class="text-center">Validation par le supérieur hiérarchique</h5>
|
||||
<div class="d-flex align-items-center justify-content-center mb-2">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="validation_hierarchique" id="validation_hierarchique_valide" value="valide">
|
||||
<label class="form-check-label" for="validation_hierarchique_valide">Valide</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="validation_hierarchique" id="validation_hierarchique_refuse" value="refuse" {% if conge.validation_hierarchique == False %}checked{% endif %}>
|
||||
<label class="form-check-label" for="validation_hierarchique_refuse">Refusé</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if membre_de_la_direction %}
|
||||
<hr>
|
||||
<h5 class="text-center">Validation par le directeur</h5>
|
||||
<div class="d-flex align-items-center justify-content-center mb-2">
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="validation_direction" id="validation_direction_valide" value="valide" {% if conge.validation_direction == True %}checked{% endif %}>
|
||||
<label class="form-check-label" for="validation_direction_valide">Valide</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="validation_direction" id="validation_direction_refuse" value="refuse" {% if conge.validation_direction == False %}checked{% endif %}>
|
||||
<label class="form-check-label" for="validation_direction_refuse">Refusé</label>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<hr>
|
||||
<div class="d-none form-group mt-3" id="motif_refus_container">
|
||||
<label for="motif_refus">Motif de refus (si applicable) :</label>
|
||||
<textarea class="form-control" id="motif_refus" rows="3"></textarea>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
||||
{% if employe_est_il_chef or membre_de_la_direction or est_chef_projet %}
|
||||
<button type="button" class="btn btn-success" id="bouton-enregistrer-detail-conge">Enregistrer</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,48 +0,0 @@
|
||||
{% 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="Conge maternité" {% if conge.type == "Conge maternité" %}selected{% endif %}>Conge Maternité</option>
|
||||
<option value="Conge de Mariage" {% if conge.type == "Conge de Mariage" %}selected{% endif %}>Conge Mariage</option>
|
||||
<option value="conge de naissance" {% if conge.type == "conge de naissance" %}selected{% endif %}>Conge de Naissance</option>
|
||||
<option value="conge de deces dun proche" {% if conge.type == "conge de deces dun proche" %}selected{% endif %}>Conge de décès d'un proche</option>
|
||||
<option value="conge de mariage dun proche" {% if conge.type == "conge de mariage dun proche" %}selected{% endif %}>Conge de mariage d'un proche</option>
|
||||
<option value="conge pour evenements familiaux" {% if conge.type == "conge pour evenements familiaux" %}selected{% endif %}>Conge pour événements familiaux</option>
|
||||
<option value="Autre" {% if conge.type == "Autre" %}selected{% endif %}>Autre</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 bg-orange-dark">Enregistrer</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
@@ -1,24 +0,0 @@
|
||||
<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>
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
@@ -1,27 +0,0 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = "gestion_conges"
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
'',
|
||||
views.index,
|
||||
name='conge'
|
||||
),
|
||||
path(
|
||||
'demande_conge/',
|
||||
views.demander_conge,
|
||||
name='demande-conge'
|
||||
),
|
||||
path(
|
||||
'liste-des-conges/',
|
||||
views.liste_demande_conges,
|
||||
name='liste-des-conges'
|
||||
),
|
||||
path(
|
||||
'validation-des-conges/',
|
||||
views.validation_de_conge,
|
||||
name='validation-des-conges'
|
||||
),
|
||||
]
|
||||
@@ -1,225 +0,0 @@
|
||||
import json
|
||||
from django.http import JsonResponse
|
||||
from django.shortcuts import redirect, render
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from gestion_conge.forms import CongeForm
|
||||
from gestion_employe.models import Affectation, Employe
|
||||
from django.forms.models import model_to_dict
|
||||
from django.utils import timezone
|
||||
from django.db.models import Q
|
||||
from fonction_utilitaire import fonctions_utilitaire
|
||||
from .models import Conge
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
"""Vue de gestion de l'index"""
|
||||
|
||||
employe = Employe.objects.get(user__username = request.user)
|
||||
membre_direction = 'direction' in employe.user.groups.values_list('name', flat=True)
|
||||
|
||||
try:
|
||||
affectation = Affectation.objects.get(employe = employe, date_fin_daffectation__gte = timezone.now().date())
|
||||
except Affectation.DoesNotExist:
|
||||
affectation = None
|
||||
|
||||
try:
|
||||
projet = Affectation.objects.get(employe=employe, date_fin_daffectation__gte = timezone.now().date())
|
||||
except Affectation.DoesNotExist:
|
||||
pass
|
||||
|
||||
if employe.chef:
|
||||
nombre_conges_valide = Conge.objects.filter(validation_hierarchique = True, employe__departement = employe.departement).count()
|
||||
nombre_conges_refuse = Conge.objects.filter(validation_hierarchique = False, employe__departement = employe.departement).count()
|
||||
conges_en_attente = Conge.objects.filter(validation_hierarchique = None, employe__departement = employe.departement).order_by('-date_demande')
|
||||
|
||||
elif membre_direction:
|
||||
nombre_conges_valide = Conge.objects.filter(validation_direction = True).count()
|
||||
nombre_conges_refuse = Conge.objects.filter(validation_direction = False).count()
|
||||
conges_en_attente = Conge.objects.filter(validation_hierarchique = True, validation_direction = None).order_by('-date_demande')
|
||||
|
||||
elif affectation and affectation.role == "chef_projet":
|
||||
employes_du_projet = Affectation.objects.filter(
|
||||
projet = projet.projet,
|
||||
date_fin_daffectation__gte = timezone.now().date()
|
||||
).values('employe')
|
||||
|
||||
nombre_conges_valide = Conge.objects.filter(
|
||||
employe__in = employes_du_projet,
|
||||
validation_hierarchique = True
|
||||
).count()
|
||||
|
||||
nombre_conges_refuse = Conge.objects.filter(
|
||||
Q(employe__in = employes_du_projet) &
|
||||
(Q(validation_hierarchique = False) | Q(validation_direction = False))
|
||||
).count()
|
||||
|
||||
conges_en_attente = Conge.objects.filter(
|
||||
Q(employe__in = employes_du_projet) &
|
||||
(
|
||||
Q(validation_hierarchique__isnull = True) | Q(validation_direction__isnull = True)
|
||||
)
|
||||
).exclude(
|
||||
Q(validation_hierarchique = True) | Q(validation_hierarchique = False) |
|
||||
Q(validation_direction = True) | Q(validation_direction = False)
|
||||
).order_by('-date_demande')
|
||||
|
||||
else:
|
||||
nombre_conges_valide = Conge.objects.filter(
|
||||
employe=employe,
|
||||
validation_direction = True
|
||||
).count()
|
||||
|
||||
nombre_conges_refuse = Conge.objects.filter(Q(employe=employe) & (
|
||||
Q(validation_direction = False) | Q(validation_hierarchique = False)
|
||||
)).count()
|
||||
|
||||
conges_en_attente = Conge.objects.filter(
|
||||
Q(employe = employe) &
|
||||
(
|
||||
Q(validation_direction__isnull = True) | Q(validation_hierarchique__isnull = True)
|
||||
)
|
||||
).exclude(
|
||||
Q(validation_hierarchique = True) | Q(validation_hierarchique = False)
|
||||
).order_by('-date_demande')
|
||||
|
||||
|
||||
return render(request, 'gestion_conge/index.html', {
|
||||
"nombre_conges_valide": nombre_conges_valide,
|
||||
"nombre_conges_refuse": nombre_conges_refuse,
|
||||
"nombre_conges_en_attente": conges_en_attente.count(),
|
||||
"formulaire_demande_conge": CongeForm,
|
||||
"employe_est_il_chef": employe.chef,
|
||||
"membre_de_la_direction": membre_direction,
|
||||
"est_chef_projet": affectation.role == "chef_projet" if affectation else False,
|
||||
})
|
||||
|
||||
@login_required
|
||||
def demander_conge(request):
|
||||
"""Vue de gestion des demandes de congés"""
|
||||
try:
|
||||
employe = Employe.objects.get(user__username = request.user)
|
||||
except Employe.DoesNotExist:
|
||||
messages.error(request, "Votre demande de congé a échoué car votre profil Utilisateur n'est lié à aucun profil Employé. Veuillez contacter l'administrateur.")
|
||||
return redirect("gestion_conges:conge")
|
||||
|
||||
retour_quota = fonctions_utilitaire.solde_conge(employe)
|
||||
if retour_quota["success"]:
|
||||
quota_annuel = retour_quota['quota_annuel']
|
||||
else:
|
||||
messages.error(request, retour_quota['message'])
|
||||
return redirect("gestion_conges:conge")
|
||||
|
||||
if request.method == "POST":
|
||||
form = CongeForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
conge_obj = form.save(commit=False)
|
||||
conge_obj.employe = employe
|
||||
|
||||
if conge_obj.type == "conge_annuel":
|
||||
if retour_quota["nombre_jours_valide"] + conge_obj.nombre_jours > quota_annuel:
|
||||
messages.error(request, "Quota annuel dépassé (30 jours max).")
|
||||
return redirect("gestion_conges:conge")
|
||||
|
||||
conge_obj.save()
|
||||
messages.success(request, "Votre demande de congé a été enregistrée.")
|
||||
return redirect("gestion_conges:conge")
|
||||
|
||||
return redirect("gestion_conges:conge")
|
||||
|
||||
@login_required
|
||||
def liste_demande_conges(request):
|
||||
"""Vue de liste des demandes de congés en attente de validation selon le statut de l'utilisateur actuel"""
|
||||
try:
|
||||
employe = Employe.objects.get(user__username = request.user)
|
||||
except Employe.DoesNotExist:
|
||||
return JsonResponse({
|
||||
"success": False,
|
||||
"message": "Votre profil Utilisateur n'est lié à aucun profil Employé. Veuillez contacter l'administrateur."
|
||||
})
|
||||
|
||||
try:
|
||||
affectation = Affectation.objects.get(
|
||||
employe=employe,
|
||||
date_fin_daffectation__gte=timezone.now().date()
|
||||
)
|
||||
except Affectation.DoesNotExist:
|
||||
affectation = None
|
||||
|
||||
if employe.chef:
|
||||
print("chef")
|
||||
conges_en_attente = Conge.objects.filter(
|
||||
employe__departement = employe.departement,
|
||||
validation_hierarchique = None
|
||||
).order_by('-date_demande')
|
||||
|
||||
elif affectation and affectation.role == "chef_projet":
|
||||
employes_du_projet = Affectation.objects.filter(
|
||||
projet = affectation.projet,
|
||||
date_fin_daffectation__gte = timezone.now().date()
|
||||
).values('employe')
|
||||
|
||||
conges_en_attente = Conge.objects.filter(
|
||||
employe__in = employes_du_projet,
|
||||
validation_hierarchique = None
|
||||
).order_by('-date_demande')
|
||||
|
||||
elif 'direction' in employe.user.groups.values_list('name', flat=True):
|
||||
conges_en_attente = Conge.objects.filter(
|
||||
validation_hierarchique = True,
|
||||
validation_direction = None
|
||||
).order_by('-date_demande')
|
||||
|
||||
else:
|
||||
conges_en_attente = Conge.objects.filter(
|
||||
employe__user__username = request.user
|
||||
).order_by('-date_demande')
|
||||
|
||||
return JsonResponse({
|
||||
"success": True,
|
||||
"data":[
|
||||
{
|
||||
**model_to_dict(conge),
|
||||
"prenom_nom": f"{conge.employe.user.first_name} {conge.employe.user.last_name}",
|
||||
"date_demande": conge.date_demande,
|
||||
"nombre_jours": conge.nombre_jours,
|
||||
"type": dict(conge.TYPE_CHOICES).get(conge.type),
|
||||
"solde_conge": fonctions_utilitaire.solde_conge(conge.employe)["quota_annuel"]
|
||||
}
|
||||
for conge in conges_en_attente]},
|
||||
safe=False
|
||||
)
|
||||
|
||||
@login_required
|
||||
def validation_de_conge(request):
|
||||
"""
|
||||
Vue de validation de conges par le superieur hierarchique.
|
||||
1- Si l'employe appartient à un département, le congé est validé par le chef de département.
|
||||
2- Si l'employé n'appartient pas à un département, le congé est validé par le chef de projet.
|
||||
"""
|
||||
request_data = json.loads(request.body)
|
||||
conge_id = request_data.get("id_conge", None)
|
||||
try:
|
||||
conge = Conge.objects.get(id=conge_id)
|
||||
except conge.DoesNotExist:
|
||||
return JsonResponse({"message": "Le congé selectionné n'existe pas."})
|
||||
|
||||
if request.method == "POST":
|
||||
validation_hierarchique = request_data.get("validation_hierarchique", None)
|
||||
validation_direction = request_data.get("validation_direction", None)
|
||||
motif_refus = request_data.get("motif_refus", "")
|
||||
|
||||
if validation_hierarchique is not None:
|
||||
conge.validation_hierarchique = True if validation_hierarchique == "valide" else False
|
||||
if validation_hierarchique == "refuse" and not motif_refus:
|
||||
return JsonResponse({"message": "Veuillez fournir un motif de refus."})
|
||||
conge.motif_refus = motif_refus if validation_hierarchique == "refuse" else ""
|
||||
|
||||
if validation_direction is not None:
|
||||
conge.validation_direction = True if validation_direction == "valide" else False
|
||||
if validation_direction == "refuse" and not motif_refus:
|
||||
return JsonResponse({"message": "Veuillez fournir un motif de refus."})
|
||||
conge.motif_refus = motif_refus if validation_direction == "refuse" else ""
|
||||
|
||||
conge.save()
|
||||
return JsonResponse({"message": "La décision a été enregistrée avec succès."})
|
||||
Reference in New Issue
Block a user