clean: remove pycache from tracking
This commit is contained in:
0
gestion_employe/__init__.py
Normal file
0
gestion_employe/__init__.py
Normal file
14
gestion_employe/admin.py
Normal file
14
gestion_employe/admin.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from django.contrib import admin
|
||||
from .models import Departement, Employe
|
||||
|
||||
@admin.register(Departement)
|
||||
class DepartementAdmin(admin.ModelAdmin):
|
||||
list_display = ("nom", )
|
||||
|
||||
@admin.register(Employe)
|
||||
class EmployeAdmin(admin.ModelAdmin):
|
||||
list_display = (
|
||||
"user",
|
||||
"matricule",
|
||||
"fonction",
|
||||
)
|
||||
84
gestion_employe/forms.py
Normal file
84
gestion_employe/forms.py
Normal file
@@ -0,0 +1,84 @@
|
||||
from django import forms
|
||||
from .models import Contrat, Departement, Employe,Affectation,Formation
|
||||
|
||||
class EmployeForm(forms.ModelForm):
|
||||
"""Formulaire pour modifier les informations de profil d'un employé"""
|
||||
class Meta:
|
||||
model = Employe
|
||||
fields = (
|
||||
'adresse',
|
||||
'telephone',
|
||||
'CV',
|
||||
'diplome',
|
||||
'rib',
|
||||
'photo',
|
||||
'casier_judiciaire'
|
||||
)
|
||||
|
||||
class AffectationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Affectation
|
||||
fields = (
|
||||
'projet',
|
||||
'date_affectation',
|
||||
'date_fin_daffectation',
|
||||
'role',
|
||||
'pourcentage_temps_affectation'
|
||||
)
|
||||
|
||||
widgets = {
|
||||
'projet': forms.Select(attrs={'class': 'form-select'}),
|
||||
'date_affectation': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
||||
'date_fin_daffectation': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
||||
'role': forms.Select(attrs={'class': 'form-select'}),
|
||||
'pourcentage_temps_affectation': forms.NumberInput(attrs={'class': 'form-control'}),
|
||||
}
|
||||
|
||||
class ContratForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Contrat
|
||||
fields = [
|
||||
"numero_contrat",
|
||||
"type_contrat",
|
||||
"date_debut",
|
||||
"date_fin",
|
||||
"salaire_mensuel",
|
||||
"statut",
|
||||
"fichier_contrat"
|
||||
]
|
||||
|
||||
widgets = {
|
||||
'numero_contrat': forms.TextInput(attrs={'class': 'form-control'}),
|
||||
'type_contrat': forms.Select(attrs={'class': 'form-select'}),
|
||||
'date_debut': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
||||
'date_fin': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
||||
'salaire_mensuel': forms.TextInput(attrs={'class': 'form-control'}),
|
||||
'statut': forms.Select(attrs={'class': 'form-select'}),
|
||||
'fichier_contrat': forms.FileInput(attrs={'class': 'form-control'}),
|
||||
}
|
||||
|
||||
class DepartementForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Departement
|
||||
fields = ['nom']
|
||||
|
||||
class FormationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Formation
|
||||
fields = [
|
||||
'titre',
|
||||
'organisme',
|
||||
'date_obtention',
|
||||
'date_fin',
|
||||
'description',
|
||||
'certificat'
|
||||
]
|
||||
|
||||
widgets = {
|
||||
'titre': forms.TextInput(attrs={"class": "form-control"}),
|
||||
'organisme': forms.TextInput(attrs={"class": "form-control"}),
|
||||
'date_obtention': forms.DateInput(attrs={"class": "form-control", "type": "date"}),
|
||||
'date_fin': forms.DateInput(attrs={"class": "form-control", "type": "date"}),
|
||||
'description': forms.Textarea(attrs={"class": "form-control"}),
|
||||
'certificat': forms.FileInput(attrs={"class": "form-control"}),
|
||||
}
|
||||
88
gestion_employe/migrations/0001_initial.py
Normal file
88
gestion_employe/migrations/0001_initial.py
Normal file
@@ -0,0 +1,88 @@
|
||||
# Generated by Django 5.2.13 on 2026-04-17 12:03
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
('gestion_projet', '0001_initial'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Departement',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('nom', models.CharField(max_length=100)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Employe',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('matricule', models.CharField(blank=True, max_length=10, null=True, unique=True)),
|
||||
('fonction', models.CharField(blank=True, choices=[('directeur', 'Directeur'), ('assistant_direction', 'Assistante de direction'), ('comptable', 'Comptable'), ('raf', 'RAF'), ('data_manager', 'Data Manager'), ('logisticien', 'Logisticien'), ('post_doctorant', 'Post-Doctorant'), ('qualiticien', 'Qualiticien'), ('technicien_surface', 'Technicien de surface'), ('chauffeur', 'Chauffeur')], max_length=50, null=True)),
|
||||
('date_embauche', models.DateField(blank=True, null=True)),
|
||||
('adresse', models.CharField(blank=True, max_length=100, null=True)),
|
||||
('telephone', models.CharField(blank=True, max_length=15, null=True)),
|
||||
('sexe', models.CharField(blank=True, choices=[('m', 'Masculin'), ('f', 'Féminin')], max_length=1, null=True)),
|
||||
('date_naissance', models.DateField(blank=True, null=True)),
|
||||
('CV', models.FileField(blank=True, null=True, upload_to='cv/')),
|
||||
('diplome', models.FileField(blank=True, null=True, upload_to='diplomes/')),
|
||||
('rib', models.FileField(blank=True, null=True, upload_to='rib/')),
|
||||
('photo', models.ImageField(blank=True, null=True, upload_to='photos/')),
|
||||
('casier_judiciaire', models.FileField(blank=True, null=True, upload_to='casier/')),
|
||||
('chef', models.BooleanField(default=False, verbose_name='Cet utilisateur est-il chef de ce département ?')),
|
||||
('departement', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='gestion_employe.departement')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Contrat',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('numero_contrat', models.CharField(max_length=100, unique=True)),
|
||||
('type_contrat', models.CharField(choices=[('contrat_duree_determinee', 'Contrat à Durée Déterminée'), ('contrat_duree_indeterminee', 'Contrat à Durée Indéterminée'), ('contrat_prestation', 'Contrat de Prestation de Service'), ('contrat_stage', 'Contrat de Stage')], max_length=50)),
|
||||
('date_debut', models.DateField()),
|
||||
('date_fin', models.DateField(blank=True, null=True)),
|
||||
('salaire_mensuel', models.DecimalField(blank=True, decimal_places=2, max_digits=10, null=True)),
|
||||
('statut', models.CharField(choices=[('actif', 'Actif'), ('termine', 'Terminé'), ('suspendu', 'Suspendu'), ('rupture_contrat', 'Rupture de Contrat')], max_length=50)),
|
||||
('fichier_contrat', models.FileField(blank=True, null=True, upload_to='contrats/')),
|
||||
('employe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_employe.employe')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Formation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('titre', models.CharField(max_length=255, verbose_name='Nom du certificat')),
|
||||
('organisme', models.CharField(max_length=255, verbose_name="Nom de l'organisme")),
|
||||
('description', models.TextField(blank=True, null=True, verbose_name='Description de la formation')),
|
||||
('date_obtention', models.DateField(blank=True, null=True, verbose_name="Date d'obtention")),
|
||||
('date_fin', models.DateField(blank=True, null=True, verbose_name='Date de fin de validité')),
|
||||
('certificat', models.FileField(blank=True, null=True, upload_to='documents/formations/', verbose_name='Certificat (PDF/Image)')),
|
||||
('employe', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='employe_formation', to='gestion_employe.employe')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Affectation',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('date_affectation', models.DateField()),
|
||||
('date_fin_daffectation', models.DateField(blank=True, null=True)),
|
||||
('role', models.CharField(choices=[('chef_projet', 'Chef de projet'), ('doctorant', 'Doctorant'), ('mastorant', 'Mastorant'), ('consultant', 'Consultant'), ('stagiaire', 'Stagiaire'), ('laborantin', 'Laborantin'), ('medecin', 'Médecin'), ('autre', 'Autre')], default='Membre', max_length=20)),
|
||||
('pourcentage_temps_affectation', models.DecimalField(decimal_places=2, max_digits=5)),
|
||||
('projet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_projet.projet')),
|
||||
('employe', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='gestion_employe.employe')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('projet', 'employe')},
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 6.0.4 on 2026-04-29 10:42
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gestion_employe', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='contrat',
|
||||
name='type_contrat',
|
||||
field=models.CharField(choices=[('contrat_duree_determinee', 'Contrat à Durée Déterminée'), ('contrat_duree_indeterminee', 'Contrat à Durée Indéterminée'), ('contrat_prestation', 'Contrat de Prestation de Service'), ('contrat_stage', 'Contrat de Stage'), ('convention_bourse_entretien', "Convention de bourse d'entretien")], max_length=50),
|
||||
),
|
||||
]
|
||||
0
gestion_employe/migrations/__init__.py
Normal file
0
gestion_employe/migrations/__init__.py
Normal file
122
gestion_employe/models.py
Normal file
122
gestion_employe/models.py
Normal file
@@ -0,0 +1,122 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils import timezone
|
||||
from gestion_projet.models import Projet
|
||||
|
||||
class Departement(models.Model):
|
||||
"""Modèle représentant un département de l'entreprise."""
|
||||
nom = models.CharField(max_length=100)
|
||||
|
||||
def __str__(self):
|
||||
return self.nom
|
||||
|
||||
class Employe(models.Model):
|
||||
"""Modèle représentant un employé de l'entreprise."""
|
||||
FONCTION_LISTE = [
|
||||
('directeur', 'Directeur'),
|
||||
('assistant_direction', 'Assistante de direction'),
|
||||
('comptable', 'Comptable'),
|
||||
('raf', 'RAF'),
|
||||
('data_manager', 'Data Manager'),
|
||||
('logisticien', 'Logisticien'),
|
||||
('post_doctorant', 'Post-Doctorant'),
|
||||
('qualiticien', 'Qualiticien'),
|
||||
('technicien_surface', 'Technicien de surface'),
|
||||
('chauffeur', 'Chauffeur'),
|
||||
]
|
||||
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
matricule = models.CharField(max_length=10, unique=True, null=True, blank=True)
|
||||
departement = models.ForeignKey(Departement, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
fonction = models.CharField(max_length=50, blank=True, null=True, choices=FONCTION_LISTE)
|
||||
date_embauche = models.DateField(blank=True, null=True)
|
||||
adresse = models.CharField(max_length=100, null=True, blank=True)
|
||||
telephone = models.CharField(max_length=15, null=True, blank=True)
|
||||
sexe = models.CharField(max_length=1, null=True, blank=True, choices=[('m', 'Masculin'), ('f', 'Féminin')])
|
||||
date_naissance = models.DateField(blank=True, null=True)
|
||||
|
||||
CV = models.FileField(upload_to='cv/', blank=True, null=True)
|
||||
diplome = models.FileField(upload_to='diplomes/', blank=True, null=True)
|
||||
rib = models.FileField(upload_to='rib/', blank=True, null=True)
|
||||
photo = models.ImageField(upload_to='photos/', blank=True, null=True)
|
||||
casier_judiciaire = models.FileField(upload_to='casier/', blank=True, null=True)
|
||||
|
||||
chef = models.BooleanField(
|
||||
default=False,
|
||||
verbose_name="Cet utilisateur est-il chef de ce département ?"
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.user.first_name or 'N/A'} {self.user.last_name or ' '} ({self.matricule or ' '})"
|
||||
|
||||
class Contrat(models.Model):
|
||||
"""Modèle représentant un contrat de travail d'un employé."""
|
||||
TYPE_CONTRAT = [
|
||||
('contrat_duree_determinee', 'Contrat à Durée Déterminée'),
|
||||
('contrat_duree_indeterminee', 'Contrat à Durée Indéterminée'),
|
||||
('contrat_prestation', 'Contrat de Prestation de Service'),
|
||||
('contrat_stage', 'Contrat de Stage'),
|
||||
('convention_bourse_entretien', 'Convention de bourse d\'entretien'),
|
||||
]
|
||||
|
||||
STATUT_CONTRAT = [
|
||||
('actif', 'Actif'),
|
||||
('termine', 'Terminé'),
|
||||
('suspendu', 'Suspendu'),
|
||||
('rupture_contrat', 'Rupture de Contrat'),
|
||||
]
|
||||
employe = models.ForeignKey(Employe, on_delete=models.CASCADE)
|
||||
numero_contrat = models.CharField(max_length=100, unique=True)
|
||||
type_contrat = models.CharField(
|
||||
max_length=50,
|
||||
choices=TYPE_CONTRAT,
|
||||
)
|
||||
date_debut = models.DateField()
|
||||
date_fin = models.DateField(null=True, blank=True)
|
||||
salaire_mensuel = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
|
||||
statut = models.CharField(max_length=50, choices=STATUT_CONTRAT)
|
||||
fichier_contrat = models.FileField(upload_to='contrats/', null=True, blank=True)
|
||||
|
||||
@property
|
||||
def nombre_jours_restant(self):
|
||||
if self.date_fin:
|
||||
return (self.date_fin - timezone.now().date()).days
|
||||
return 100
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.numero_contrat} - {self.type_contrat}"
|
||||
|
||||
class Affectation(models.Model):
|
||||
"""Modèle représentant l'affectation d'un employé à un projet avec un rôle spécifique."""
|
||||
ROLE_CHOICES = [
|
||||
('chef_projet', 'Chef de projet'),
|
||||
('doctorant','Doctorant'),
|
||||
('mastorant','Mastorant'),
|
||||
('consultant','Consultant'),
|
||||
('stagiaire','Stagiaire'),
|
||||
('laborantin','Laborantin'),
|
||||
('medecin','Médecin'),
|
||||
('autre','Autre'),
|
||||
]
|
||||
|
||||
employe = models.ForeignKey(Employe, on_delete=models.CASCADE)
|
||||
projet = models.ForeignKey(Projet, on_delete=models.CASCADE)
|
||||
date_affectation = models.DateField()
|
||||
date_fin_daffectation = models.DateField(null=True, blank=True)
|
||||
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='Membre')
|
||||
pourcentage_temps_affectation = models.DecimalField(max_digits=5, decimal_places=2)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('projet', 'employe')
|
||||
|
||||
class Formation(models.Model):
|
||||
"""Modèle représentant une formation suivie par un employé."""
|
||||
employe = models.ForeignKey(Employe, on_delete=models.CASCADE, null=True, related_name='employe_formation')
|
||||
titre = models.CharField(max_length=255, verbose_name="Nom du certificat")
|
||||
organisme = models.CharField(max_length=255, verbose_name="Nom de l'organisme")
|
||||
description = models.TextField(blank=True, null=True, verbose_name="Description de la formation")
|
||||
date_obtention = models.DateField(blank=True, null=True, verbose_name="Date d'obtention")
|
||||
date_fin = models.DateField(blank=True, null=True, verbose_name="Date de fin de validité")
|
||||
certificat = models.FileField(upload_to='documents/formations/', blank=True, null=True, verbose_name="Certificat (PDF/Image)")
|
||||
def __str__(self):
|
||||
return self.titre
|
||||
263
gestion_employe/static/gestion_employe/js/index.js
Normal file
263
gestion_employe/static/gestion_employe/js/index.js
Normal file
@@ -0,0 +1,263 @@
|
||||
const $ = (element) => document.getElementById(element);
|
||||
|
||||
const url_liste_employe = $("tableau_liste_employe").dataset.url;
|
||||
const tableau_liste_employe = new Tabulator("#tableau_liste_employe", {
|
||||
columns: [
|
||||
{"title": "Matricule", "field": "matricule"},
|
||||
{"title": "Nom & Prénom", "field": "employe"},
|
||||
{"title": "Fonction", "field": "fonction"},
|
||||
{"title": "Projet", "field": "projet"},
|
||||
{"title": "Téléphone", "field": "telephone"},
|
||||
],
|
||||
// ajaxURL: url_liste_employe,
|
||||
pagination: true,
|
||||
paginationSize: 10,
|
||||
})
|
||||
|
||||
fetch(url_liste_employe)
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.success){
|
||||
console.log(data.data)
|
||||
tableau_liste_employe.setData(data.data);
|
||||
}else{
|
||||
alert(data.message);
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
tableau_liste_employe.on("rowClick", function (row, rowData) {
|
||||
const data = rowData.getData();
|
||||
document.getElementById('detail-id').value = data.id;
|
||||
document.getElementById('detail-matricule').value = data.matricule;
|
||||
document.getElementById('detail-employe').value = data.employe;
|
||||
document.getElementById('detail-fonction').value = data.fonction;
|
||||
document.getElementById('detail-departement').value = data.departement;
|
||||
document.getElementById('detail-sexe').value = "";
|
||||
document.getElementById('detail-dateNaissance').value = "";
|
||||
document.getElementById('detail-email').value = data.email;
|
||||
document.getElementById('detail-telephone').value = data.telephone;
|
||||
document.getElementById('detail-adresse').value = data.adresse;
|
||||
document.getElementById('detail-dateEmbauche').value = data.date_embauche;
|
||||
document.getElementById('detail-dateNaissance').value = data.date_naissance;
|
||||
document.getElementById('detail-sexe').value = data.sexe;
|
||||
|
||||
document.getElementById('document-diplome').href = data.diplome;
|
||||
document.getElementById('document-diplome').textContent = data.diplome || "Aucun diplôme";
|
||||
document.getElementById('document-cv').href = data.CV;
|
||||
document.getElementById('document-cv').textContent = data.CV || "Aucun CV";
|
||||
document.getElementById('document-rib').href = data.rib;
|
||||
document.getElementById('document-rib').textContent = data.rib || "Aucun RIB";
|
||||
document.getElementById('document-casier-judiciaire').href = data.casier_judiciaire;
|
||||
document.getElementById('document-casier-judiciaire').textContent = data.casier_judiciaire || "Aucun casier judiciaire";
|
||||
|
||||
document.getElementById("document-employe").innerHTML = data.employe || "Employé inconnu";
|
||||
|
||||
document.getElementById("formations-list").innerHTML = "";
|
||||
for (const formation of data.formations) {
|
||||
document.getElementById("formations-list").innerHTML += `
|
||||
<div class="col-6">
|
||||
<div class="form-group mb-2">
|
||||
<label>Titre :</label>
|
||||
<input type="text" class="form-control" value="${formation.titre}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Organisme :</label>
|
||||
<input type="text" class="form-control" value="${formation.organisme}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date d'Optention :</label>
|
||||
<input type="text" class="form-control" value="${formation.date_obtention}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date de validitée :</label>
|
||||
<input type="text" class="form-control" value="${formation.date_fin}">
|
||||
</div>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
document.getElementById("contrat-employe").innerHTML = data.employe || "Employé inconnu";
|
||||
document.getElementById("employeIdInput").value = data.id;
|
||||
|
||||
document.getElementById("contrats-list").innerHTML = "";
|
||||
for (const contrat of data.contrats) {
|
||||
document.getElementById("contrats-list").innerHTML += `
|
||||
<div class="col-6">
|
||||
<div class="form-group mb-2">
|
||||
<label>Numéro de contrat :</label>
|
||||
<input type="text" class="form-control" value="${contrat.numero_contrat}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Type de contrat :</label>
|
||||
<select class="form-select">
|
||||
<option value="">Sélectionnez un projet</option>
|
||||
<option value="contrat_duree_determinee" ${contrat.type_contrat == 'contrat_duree_determinee' ? 'selected' : ''}>Contrat à Durée Déterminée</option>
|
||||
<option value="contrat_duree_indeterminee" ${contrat.type_contrat == 'contrat_duree_indeterminee' ? 'selected' : ''}>Contrat à Durée Indéterminée</option>
|
||||
<option value="contrat_prestation" ${contrat.type_contrat == 'contrat_prestation' ? 'selected' : ''}>Contrat de Prestation de Service</option>
|
||||
<option value="contrat_stage" ${contrat.type_contrat == 'contrat_stage' ? 'selected' : ''}>Contrat de Stage</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date de début :</label>
|
||||
<input type="text" class="form-control" value="${contrat.date_debut}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date de fin :</label>
|
||||
<input type="text" class="form-control" value="${contrat.date_fin}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Salaire mensuel :</label>
|
||||
<input type="text" class="form-control" value="${contrat.salaire_mensuel}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Statut :</label>
|
||||
<input type="text" class="form-control" value="${contrat.statut}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Fichier de contrat :</label>
|
||||
<a href="${contrat.fichier_contrat}" target="_blank">Voir le document</a>
|
||||
</div>
|
||||
<button class='d-block m-auto btn btn-danger btn-supprimer-contrat' data-contratid="${contrat.numero_contrat}">
|
||||
<i class='bi bi-trash'></i> Supprimer le contrat
|
||||
</button>
|
||||
</div>
|
||||
`
|
||||
};
|
||||
|
||||
const supprimerButtons = document.getElementsByClassName("btn-supprimer-contrat");
|
||||
Array.from(supprimerButtons).forEach(button => {
|
||||
button.addEventListener("click", function() {
|
||||
const contratId = this.dataset.contratid;
|
||||
fetch(`contrat/supprimer/`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"id": contratId
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
alert(data.message);
|
||||
location.reload();
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
document.getElementById("affectation-nom-employe").textContent = data.employe || "Employé inconnu";
|
||||
document.getElementById("affecter_employe_id").value = data.id;
|
||||
|
||||
document.getElementById("affectations-list").innerHTML = "";
|
||||
for (const affectation of data.affectations) {
|
||||
document.getElementById("affectations-list").innerHTML += `
|
||||
<div class="col-6">
|
||||
<div class="form-group mb-2">
|
||||
<label>Nom du projet :</label>
|
||||
<input type="text" class="form-control" value="${affectation.projet}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Rôle :</label>
|
||||
<input type="text" class="form-control" value="${affectation.role}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Pourcentation d'affectation :</label>
|
||||
<input type="text" class="form-control" value="${affectation.pourcentage_temps_affectation}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date d'affectation :</label>
|
||||
<input type="date" class="form-control" value="${affectation.date_affectation}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date de fin d'affectation :</label>
|
||||
<input type="date" class="form-control" value="${affectation.date_fin_daffectation}">
|
||||
</div>
|
||||
<button class='d-block m-auto btn btn-danger btn-supprimer-affectation' data-contratid="${affectation.id}">
|
||||
<i class='bi bi-trash'></i> Supprimer l'affectation
|
||||
</button>
|
||||
</div>
|
||||
`
|
||||
}
|
||||
|
||||
Array.from(document.getElementsByClassName("btn-supprimer-affectation")).forEach(button => {
|
||||
button.addEventListener("click", function() {
|
||||
const affectationId = this.dataset.contratid;
|
||||
fetch(`affectation/supprimer/`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"id": affectationId
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
alert(data.message);
|
||||
location.reload();
|
||||
})
|
||||
});
|
||||
})
|
||||
|
||||
const modal = new bootstrap.Modal($("modalDetailEmploye"));
|
||||
modal.show();
|
||||
})
|
||||
|
||||
$("enregistrerDetail").addEventListener("click", function() {
|
||||
const id_ = document.getElementById('detail-id').value;
|
||||
const fonction = document.getElementById('detail-fonction').value;
|
||||
const dateEmbauche = document.getElementById('detail-dateEmbauche').value;
|
||||
const matricule = document.getElementById('detail-matricule').value;
|
||||
|
||||
const url_enregistrer_detail = $("modalDetailEmployeBody").dataset.url;
|
||||
fetch(url_enregistrer_detail, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"id": id_,
|
||||
"fonction": fonction,
|
||||
"date_embauche": dateEmbauche,
|
||||
"matricule": matricule
|
||||
})
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
alert(data.message);
|
||||
location.reload();
|
||||
})
|
||||
});
|
||||
|
||||
$("input-recherche").addEventListener("input", function() {
|
||||
const recherche = this.value;
|
||||
if (recherche){
|
||||
tableau_liste_employe.setFilter("employe", "like", recherche);
|
||||
}else{
|
||||
tableau_liste_employe.clearFilter();
|
||||
}
|
||||
})
|
||||
|
||||
const listeContratExpirant = new Tabulator("#listeContratExpirant", {
|
||||
columns: [
|
||||
{"title": "Employé", "field": "employe"},
|
||||
{"title": "Type de contrat", "field": "type_contrat"},
|
||||
{"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": "Statut", "field": "statut"},
|
||||
{"title": "Lien du fichier", "field": "fichier_contrat", formatter:"link", formatterParams:{
|
||||
target:"_blank",
|
||||
}
|
||||
},
|
||||
],
|
||||
ajaxURL: $("boutonContratExpirants").dataset.urlexpirants,
|
||||
})
|
||||
46
gestion_employe/static/gestion_employe/js/mon_profil.js
Normal file
46
gestion_employe/static/gestion_employe/js/mon_profil.js
Normal file
@@ -0,0 +1,46 @@
|
||||
const $ = (element) => document.getElementById(element);
|
||||
|
||||
url_certificat = $("tableau-certificat").dataset.url;
|
||||
const tableau_certificat = new Tabulator("#tableau-certificat", {
|
||||
columns: [
|
||||
{"title": "Nom du certificat", "field": "titre"},
|
||||
{"title": "Nom de l'organisme", "field": "organisme"},
|
||||
{"title": "Date d'obtention", "field": "date_obtention", formatter:"datetime", formatterParams:{
|
||||
inputFormat:"yyyy-MM-dd",
|
||||
outputFormat:"dd/MM/yy",
|
||||
}},
|
||||
{"title": "Date de fin de validité", "field": "date_fin", formatter:"datetime", formatterParams:{
|
||||
inputFormat:"yyyy-MM-dd",
|
||||
outputFormat:"dd/MM/yy",
|
||||
}},
|
||||
],
|
||||
ajaxURL: url_certificat,
|
||||
})
|
||||
const enregistrerProfil = $("enregistrerProfil");
|
||||
|
||||
enregistrerProfil.addEventListener("click", (e) => {
|
||||
|
||||
const url = $("information-personnelles").dataset.url;
|
||||
const csrftoken = document.querySelector("[name='csrfmiddlewaretoken']").value;
|
||||
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("nom", $("nom").value);
|
||||
formData.append("prenom", $("prenom").value);
|
||||
formData.append("email", $("email").value);
|
||||
formData.append("telephone", $("telephone").value);
|
||||
formData.append("adresse", $("adresse").value);
|
||||
formData.append("sexe", $("sexe").value);
|
||||
formData.append("date_naissance", $("date_naissance").value);
|
||||
|
||||
fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"X-CSRFToken": csrftoken
|
||||
},
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => alert(data.message))
|
||||
.catch(error => console.error("Erreur:", error));
|
||||
});
|
||||
67
gestion_employe/templates/gestion_employe/index.html
Normal file
67
gestion_employe/templates/gestion_employe/index.html
Normal file
@@ -0,0 +1,67 @@
|
||||
{% extends "BASE.html" %}
|
||||
{% load static %}
|
||||
{% block 'titre_page' %} Gestion des projets {% endblock %}
|
||||
{% block 'css' %}
|
||||
{% endblock %}
|
||||
{% block 'contenu' %}
|
||||
<div class="col px-2">
|
||||
<h3>Gestion des employés</h3>
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col text-white bg-success d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
||||
<span class="fs-5">Nombre d'employés</span>
|
||||
<h3>{{ nombre_employes }}</h3>
|
||||
</div>
|
||||
<div class="col text-white bg-info d-flex flex-column justify-content-center align-items-center border rounded p-4 mx-3">
|
||||
<span class="fs-5">Nombre de prestataires</span>
|
||||
<h3>{{ nombre_cps }}</h3>
|
||||
</div>
|
||||
<div class="col text-white bg-warning d-flex flex-column justify-content-center align-items-center border rounded p-4">
|
||||
<span class="fs-5">Nombre de stagiaires</span>
|
||||
<h3>{{ nombre_stage }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-4">
|
||||
<div class="col d-flex justify-content-between mb-3">
|
||||
<h3>
|
||||
<i class="bi bi-people"></i>
|
||||
La liste des employés
|
||||
</h3>
|
||||
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#modalListeDesContratExpirants" id="boutonContratExpirants" data-urlexpirants="{% url 'gestion_employe:liste-contrat-expirants' %}">
|
||||
Contrats proches de la fin <span class="badge badge-light">{{ nombre_expirants }}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="row mb-2 d-flex justify-content-end">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col d-flex justify-content-center">
|
||||
<input class="form-control d-block" type="search" placeholder="Recherche par nom et prénom..." id="input-recherche">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table-responsive">
|
||||
<div id="tableau_liste_employe" data-url={% url 'gestion_employe:liste-employes' %}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block 'modal' %}
|
||||
{% include "gestion_employe/parts/modalDetailEmploye.html" %}
|
||||
{% include "gestion_employe/parts/modalCreationContrat.html" %}
|
||||
{% include "gestion_employe/parts/modalAffectationProjet.html" %}
|
||||
{% include "gestion_employe/parts/modalDocument.html" %}
|
||||
{% include "gestion_employe/parts/modalListeContratExpirants.html" %}
|
||||
{% endblock %}
|
||||
{% block 'js' %}
|
||||
<script type="text/javascript" src="{% static 'gestion_employe/js/index.js' %}"></script>
|
||||
{% endblock %}
|
||||
105
gestion_employe/templates/gestion_employe/modifier-profil.html
Normal file
105
gestion_employe/templates/gestion_employe/modifier-profil.html
Normal file
@@ -0,0 +1,105 @@
|
||||
{% extends "BASE.html" %}
|
||||
{% load static %}
|
||||
{% block 'titre_page' %} Gestion des employés - Mon profil {% endblock %}
|
||||
{% block 'contenu' %}
|
||||
<div class="card shadow-sm border-0 w-100" style="max-width: 850px;">
|
||||
<div class="card-header bg-orange-dark">
|
||||
<h5 class="mb-0 fw-bold">
|
||||
<i class="bi bi-pencil-square me-2"></i> Modifier mon profil
|
||||
</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<div class="accordion" id="accordionProfil">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingInfo">
|
||||
<button class="accordion-button" type="button" data-bs-toggle="collapse" data-bs-target="#collapseInfo" aria-expanded="false" aria-controls="collapseInfo">
|
||||
<i class="bi bi-person-lines-fill me-2"></i> Informations personnelles
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseInfo" class="accordion-collapse collapse" aria-labelledby="headingInfo" data-bs-parent="#accordionProfil">
|
||||
<div class="accordion-body">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="form-group mb-2">
|
||||
<label>Photo de profil :</label>
|
||||
<input type="file" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Nom :</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="form-group mb-2">
|
||||
<label>Email :</label>
|
||||
<input type="email" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Téléphone :</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Adresse :</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingDocs">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseDocs" aria-expanded="false" aria-controls="collapseDocs">
|
||||
<i class="bi bi-file-earmark-text me-2"></i> Documents
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseDocs" class="accordion-collapse collapse" aria-labelledby="headingDocs" data-bs-parent="#accordionProfil">
|
||||
<div class="accordion-body">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="form-group mb-2">
|
||||
<label>CV :</label>
|
||||
<input type="file" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Diplome :</label>
|
||||
<input type="file" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="form-group mb-2">
|
||||
<label>RIB :</label>
|
||||
<input type="file" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Casier judiciaire :</label>
|
||||
<input type="file" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-end mt-4 gap-2 flex-wrap">
|
||||
<a href="{% url 'gestion_employe:mon-profil' %}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-x-circle me-1"></i> Annuler
|
||||
</a>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="bi bi-check-circle me-1"></i> Enregistrer
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block 'modal' %}
|
||||
{% endblock %}
|
||||
{% block 'js' %}
|
||||
{% endblock %}
|
||||
241
gestion_employe/templates/gestion_employe/monprofil.html
Normal file
241
gestion_employe/templates/gestion_employe/monprofil.html
Normal file
@@ -0,0 +1,241 @@
|
||||
{% extends "BASE.html" %}
|
||||
{% load static %}
|
||||
{% block 'titre_page' %} Gestion des employés - Mon profil {% endblock %}
|
||||
{% block 'contenu' %}
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5 class="fw-bold">
|
||||
<i class="bi bi-pencil-square me-2"></i> Les informations de mon profil
|
||||
</h5>
|
||||
<button type="button" class="btn btn-warning" data-bs-toggle="modal" data-bs-target="#modalModifierProfil">
|
||||
<i class="bi bi-pencil-square me-1"></i> Modifier le mot de passe
|
||||
</button>
|
||||
</div>
|
||||
{% if messages %}
|
||||
{% for message in messages %}
|
||||
<div class="alert alert-{% if message.tags == 'error' %}danger{% else %}success{% endif %} alert-dismissible fade show" role="alert">
|
||||
{{ message }}
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if not expiration_contrat %}
|
||||
<div class="alert alert-danger fade show alert-dismissible mt-2">
|
||||
<strong>Important :</strong> Les informations sur votre contrat n'ont pas été renseignées, veuillez contacter les ressources humaines.
|
||||
</div>
|
||||
{% elif contrat_nb_jours_restant %}
|
||||
<div class="alert alert-danger fade show alert-dismissible mt-2">
|
||||
<strong>Important :</strong> Votre contrat de travail expire dans {{ contrat_nb_jours_restant }} jours, veuillez contacter les ressources humaines.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="accordion mt-2" id="accordionInformationEmploye">
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingContrats">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseProfil" aria-expanded="false" aria-controls="collapseProfil">
|
||||
<i class="bi bi-file-earmark-text me-2"></i> Mon identité
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseProfil" class="accordion-collapse" aria-labelledby="headingContrats" data-bs-parent="#accordionInformationEmploye">
|
||||
<div class="accordion-body">
|
||||
<div class="row" id="information-personnelles" data-url="{% url 'gestion_employe:modifier-employe' %}">
|
||||
{% csrf_token %}
|
||||
<div class="col">
|
||||
<div class="form-group mb-2">
|
||||
<label>photo</label>
|
||||
{% if employe.photo %}
|
||||
<span>Fichier actuel : <a href="{{ employe.photo.url }}">{{employe.photo}}</a></span>
|
||||
{% endif %}
|
||||
<input type="file" id="photo" name="photo" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Matricule :</label>
|
||||
<input type="text" class="form-control" id="matricule" value="{{ employe.matricule|default:'' }}" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Nom :</label>
|
||||
<input type="text" class="form-control" id="nom" value="{{ employe.user.last_name }}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Prénom :</label>
|
||||
<input type="text" class="form-control" id="prenom" value="{{ employe.user.first_name }}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Sexe :</label>
|
||||
<select id='sexe' class="form-select">
|
||||
<option value='h' {% if employe.sexe == 'h' %}selected{% endif %}>Homme</option>
|
||||
<option value='f' {% if employe.sexe == 'f' %}selected{% endif %}>Femme</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="form-group mb-2">
|
||||
<label>Date de naissance :</label>
|
||||
<input type="date" class="form-control" id="date_naissance" value="{{ employe.date_naissance|date:'Y-m-d' }}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Département :</label>
|
||||
<input type="text" class="form-control" id="departement" value="{{ employe.departement.nom|default:'' }}" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Email :</label>
|
||||
<input type="email" class="form-control" id="email" value="{{ employe.user.email|default:'' }}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Téléphone :</label>
|
||||
<input type="text" class="form-control" id="telephone" value="{{ employe.telephone|default:'' }}">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Adresse :</label>
|
||||
<input type="text" class="form-control" id="adresse" value="{{ employe.adresse|default:'' }}">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success d-block m-auto" id="enregistrerProfil">Enregistrer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingContrats">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseContrats" aria-expanded="false" aria-controls="collapseContrats">
|
||||
<i class="bi bi-file-earmark-text me-2"></i> Contrats
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseContrats" class="accordion-collapse collapse" aria-labelledby="headingContrats" data-bs-parent="#accordionInformationEmploye">
|
||||
<div class="accordion-body">
|
||||
{% for contrat in contrats %}
|
||||
<div class="mb-3 p-3 border rounded">
|
||||
<div class="form-group mb-2">
|
||||
<label>Numéro :</label>
|
||||
<input type="text" class="form-control" value="{{ contrat.numero_contrat }}" id="numero_contrat" readonly>
|
||||
</div><div class="form-group mb-2">
|
||||
<label>Type de Contrat :</label>
|
||||
<input type="text" class="form-control" value="{{ contrat.type_contrat }}" id="type_contrat" readonly>
|
||||
</div><div class="form-group mb-2">
|
||||
<label>Date début :</label>
|
||||
<input type="date" class="form-control" value="{{ contrat.date_debut|date:'Y-m-d' }}" id="date_debut" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date fin :</label>
|
||||
<input type="date" class="form-control" value="{{ contrat.date_fin|date:'Y-m-d' }}" id="date_fin" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Salaire :</label>
|
||||
<input type="number" class="form-control" value="{{ contrat.salaire_mensuel }}" id="salaire" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Statut :</label>
|
||||
<input type="text" class="form-control" value="{{ contrat.statut }}" id="satut" readonly>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>fichier :</label>
|
||||
<a href="{{ contrat.fichier_contrat }}" target="_blank" class="btn btn-outline-primary">Voir le contrat</a>
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<p class="text-danger">Aucun contrat trouvé.</p>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingProjets">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseProjets" aria-expanded="false" aria-controls="collapseProjets">
|
||||
<i class="bi bi-briefcase me-2"></i> Projets
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseProjets" class="accordion-collapse collapse" aria-labelledby="headingProjets" data-bs-parent="#accordionInformationEmploye">
|
||||
<div class="accordion-body">
|
||||
<ul class="list-group">
|
||||
{% for projet in projets %}
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
{{ projet.nom_projet }} ({{ projet.pourcentage_temps_affectation }}%) du <strong>{{ projet.date_debut|date:"d/m/Y" }}</strong> au
|
||||
<strong>{{ projet.date_fin|date:"d/m/Y" }}</strong> en tant que {{ projet.role }}.
|
||||
</li>
|
||||
{% empty %}
|
||||
<li class="list-group-item text-muted text-center">Vous n'êtes affecté à aucun projet.</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingDocs">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseDocs" aria-expanded="false" aria-controls="collapseDocs">
|
||||
<i class="bi bi-file-earmark-text me-2"></i> Documents
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseDocs" class="accordion-collapse collapse" aria-labelledby="headingDocs" data-bs-parent="#accordionInformationEmploye">
|
||||
<div class="accordion-body">
|
||||
<form method="POST" action="{% url 'gestion_employe:enregistrement-document-rh' %}" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="form-group mb-2">
|
||||
<label>photo</label>
|
||||
{% if employe.photo %}
|
||||
<span>Fichier actuel : <a href="{{ employe.photo.url }}">{{employe.photo}}</a></span>
|
||||
{% endif %}
|
||||
<input type="file" class="form-control" name="photo">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>CV</label>
|
||||
{% if employe.CV %}
|
||||
<span>Fichier actuel : <a href="{{ employe.CV.url }}">{{employe.CV}}</a></span>
|
||||
{% endif %}
|
||||
<input type="file" class="form-control" name="cv">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Diplôme</label>
|
||||
{% if employe.diplome %}
|
||||
<span>Fichier actuel : <a href="{{ employe.diplome.url }}">{{employe.diplome}}</a></span>
|
||||
{% endif %}
|
||||
<input type="file" class="form-control" name="diplome">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="form-group mb-2">
|
||||
<label>Casier judiciaire</label>
|
||||
{% if employe.casier_judiciaire %}
|
||||
<span>Fichier actuel : <a href="{{ employe.casier_judiciaire.url }}">{{employe.casier_judiciaire}}</a></span>
|
||||
{% endif %}
|
||||
<input type="file" class="form-control" name="casier_judiciaire">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>RIB</label>
|
||||
{% if employe.rib %}
|
||||
<span>Fichier actuel : <a href="{{ employe.rib.url }}">{{employe.rib}}</a></span>
|
||||
{% endif %}
|
||||
<input type="file" class="form-control" name="rib">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-success d-block m-auto">Enregistrer</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="headingCertificat">
|
||||
<button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#collapseCertificat" aria-expanded="false" aria-controls="collapseCertificat">
|
||||
<i class="bi bi-file-earmark-text me-2"></i> Certificats
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapseCertificat" class="accordion-collapse collapse" aria-labelledby="headingCertificat" data-bs-parent="#accordionInformationEmploye">
|
||||
<div class="accordion-body">
|
||||
<div id="tableau-certificat" data-url="{% url 'gestion_employe:liste-formation' %}"></div>
|
||||
<button class="btn btn-success d-block m-auto" data-bs-toggle="modal" data-bs-target="#modalAjouterFormation">Ajouter un certificat</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block 'modal' %}
|
||||
{% include "gestion_employe/parts/modificationMotPasse.html" %}
|
||||
{% include "gestion_employe/parts/modalAjoutFormation.html" %}
|
||||
{% endblock %}
|
||||
{% block 'js' %}
|
||||
|
||||
<script src="{% static 'gestion_employe/js/mon_profil.js' %}"></script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,28 @@
|
||||
<div class="modal fade" id="modalAffectation" tabindex="-1" aria-labelledby="modalAffectationLabel" aria-hidden="true">
|
||||
<div class="modal-dialog ">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-orange-dark">
|
||||
<h5 class="modal-title" id="modalAffectationLabel" >
|
||||
Affectation de projet (<span id="affectation-nom-employe"></span>)
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal">
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{% url 'gestion_employe:affecter_employe_projet' %}" method="POST">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="affecter_employe_id" id="affecter_employe_id">
|
||||
{{ affectation_form.as_p }}
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-check-circle"></i> affecter
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x-circle me-1"></i> Annuler
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
<div class="modal fade" id="modalAjouterFormation" tabindex="-1">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header bg-orange-dark">
|
||||
<h5 class="modal-title">Ajouter un certificat</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="post" action="{% url 'gestion_employe:ajouter_formation' %}" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{{ formation_form.as_p }}
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-success">Enregistrer</button>
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Annuler</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,57 @@
|
||||
<div class="modal fade" id="modalContrat" tabindex="-1" aria-labelledby="modalContratLabel" aria-hidden="true">
|
||||
<div class="modal-dialog ">
|
||||
<div class="modal-content bg-white">
|
||||
<div class="modal-header ">
|
||||
<h5 class="modal-title" id="modalContratLabel">
|
||||
<i class="bi bi-file-earmark-text me-2"></i>
|
||||
Contrat de <span id="contrat-employe"></span>
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{% url 'gestion_employe:creation-contrat' %}" method="POST" id="contrat_form" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="employe_id" value="" id="employeIdInput">
|
||||
{{ contrat_form.as_p }}
|
||||
<div class="modal-footer bg-light">
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-check-circle me-1"></i> Enregistrer
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">
|
||||
<i class="bi bi-x-circle me-1"></i> Annuler
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
{% comment %} <fieldset class="border p-3 mb-4">
|
||||
<legend class="fw-bold mb-3 text-muted">Informations du contrat</legend>
|
||||
|
||||
<div class="form-group mb-2">
|
||||
<label>Numero de contrat :</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Type contrat :</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>date de début :</label>
|
||||
<input type="date" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>date de fin :</label>
|
||||
<input type="date" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Salaire mensuel :</label>
|
||||
<input type="text" class="form-control">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Fichier du contrat :</label>
|
||||
<input type="file" class="form-control">
|
||||
</div>
|
||||
</div>
|
||||
</fieldset> {% endcomment %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,136 @@
|
||||
{% load tags_personnaliser %}
|
||||
<div class="modal fade" id="modalDetailEmploye" tabindex="-1" aria-labelledby="modalDetailEmployeLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-xl modal-dialog-scrollable">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header ">
|
||||
<h5 class="modal-title bi-pencil-square" id="modalDetailEmployeLabel">
|
||||
Détails de l'employé <span id="detail-employe"></span>
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body" id="modalDetailEmployeBody" data-url="{% url 'gestion_employe:enregistrer-detail-employe' %}">
|
||||
<div class="row g-3">
|
||||
<input type="hidden" id="detail-id">
|
||||
<div class="col-md-6">
|
||||
{% csrf_token %}
|
||||
<div class="form-group mb-2">
|
||||
<label>Matricule :</label>
|
||||
<input type="text" class="form-control" id="detail-matricule">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date d'embauche :</label>
|
||||
<input type="date" class="form-control" id="detail-dateEmbauche">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Département :</label>
|
||||
<input type="text" class="form-control" id="detail-departement">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Sexe :</label>
|
||||
<select id="detail-sexe" class="form-select">
|
||||
<option value="">-- Sélectionner --</option>
|
||||
<option value="h">Masculin</option>
|
||||
<option value="f">Féminin</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date de naissance :</label>
|
||||
<input type="date" class="form-control" id="detail-dateNaissance">
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group mb-2">
|
||||
<label>Fonction :</label>
|
||||
<select class="form-select" id='detail-fonction'>
|
||||
<option value='chauffeur'>Chauffeur</option>
|
||||
<option value='technicien_surface'>Technicien de surface</option>
|
||||
<option value='qualiticien'>Qualiticien</option>
|
||||
<option value='post_doctorant'>Post-Doctorant</option>
|
||||
<option value='logisticien'>Logisticien</option>
|
||||
<option value='data_manager'>Data Manager</option>
|
||||
<option value='raf'>RAF</option>
|
||||
<option value='comptable'>Comptable</option>
|
||||
<option value='assistant_direction'>Assistante de direction</option>
|
||||
<option value='directeur'>Directeur</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Email :</label>
|
||||
<input type="email" class="form-control" id="detail-email">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Téléphone :</label>
|
||||
<input type="text" class="form-control" id="detail-telephone">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Adresse :</label>
|
||||
<input type="text" class="form-control" id="detail-adresse">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
{% if user|has_group:"ressource_humaine" %}
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-success d-block m-auto" id="enregistrerDetail">
|
||||
<i class="bi bi-save"></i> Enregistrer
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col text-end">
|
||||
<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modalDocuments">
|
||||
<i class="bi bi-folder2-open"></i> Voir les documents RH
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="my-4">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5>
|
||||
<i class="bi bi-file-earmark-text me-2"></i> Liste des Contrats
|
||||
</h5>
|
||||
{% if user|has_group:"ressource_humaine" %}
|
||||
<div>
|
||||
<button class="btn btn-secondary" disabled>
|
||||
<i class="bi bi-file-earmark-lock"></i> Contrat actif
|
||||
</button>
|
||||
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#modalContrat{{ item.employe.id }}">
|
||||
<i class="bi bi-file-earmark-text"></i> Créer contrat
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% csrf_token %}
|
||||
<div class="row" id="contrats-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="my-4">
|
||||
<div class="row d-flex g-3">
|
||||
<div class="d-flex justify-content-between">
|
||||
<h5><i class="bi bi-pin-angle me-2"></i> Affectations</h5>
|
||||
{% if user|has_group:"ressource_humaine" %}
|
||||
<button type="button" class="btn btn-success" data-bs-toggle="modal" data-bs-target="#modalAffectation" onclick="setEmployeId()">
|
||||
<i class="bi bi-file-earmark-text"></i>Affecter
|
||||
</button>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div id="affectations-list"></div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="my-4">
|
||||
<div class="row g-3">
|
||||
<h5 class="mb-3"><i class="bi bi-award-fill me-2"></i> Formations</h5>
|
||||
<div class="row" id="formations-list"></div>
|
||||
</div>
|
||||
</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"></i> Fermer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,41 @@
|
||||
<div class="modal fade" id="modalDocuments" tabindex="-1" aria-labelledby="modalDocumentsLabel" aria-hidden="true">
|
||||
<div class="modal-dialog ">
|
||||
<div class="modal-content border-0 shadow-lg">
|
||||
<div class="modal-header ">
|
||||
<h5 class="modal-title" id="modalDocumentsLabel">
|
||||
<i class="bi bi-folder2-open me-2"></i> Documents RH de <span id="document-employe"></span>
|
||||
</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="row g-3">
|
||||
<div class="col">
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item">
|
||||
<strong>Diplôme :</strong>
|
||||
<a id="document-diplome" target="_blank"></a>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>CV :</strong>
|
||||
<a id="document-cv" target="_blank"></a>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>RIB :</strong>
|
||||
<a id="document-rib" target="_blank"></a>
|
||||
</li>
|
||||
<li class="list-group-item">
|
||||
<strong>Casier judiciaire :</strong>
|
||||
<a id="document-casier-judiciaire" target="_blank"></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</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"></i> Fermer
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,17 @@
|
||||
<div class="modal fade" id="modalListeDesContratExpirants" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Contrats expirants dans un maximum de 60 jours</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id='listeContratExpirant'></div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Fermer</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="modal fade" id="modalModifierProfil" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title"><i class="bi bi-person-lines-fill me-2"></i> Modifier le mot de passe</h5>
|
||||
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form method="POST" action="{% url 'gestion_employe:modifier-mot-passe' %}">
|
||||
{% csrf_token %}
|
||||
<div class="form-group mb-2">
|
||||
<label>Votre mot de passe actuel :</label>
|
||||
<input class="form-control" type="password" name="ancien-mdp">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Votre nouveau mot de passe :</label>
|
||||
<input class="form-control" type="password" name="nouveau-mdp">
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Confirmez votre nouveau mot de passe :</label>
|
||||
<input class="form-control" type="password" name="confirmation-mdp">
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
Fermer
|
||||
</button>
|
||||
<button type="submit" class="btn btn-success">
|
||||
<i class="bi bi-check-circle me-1"></i> Enregistrer
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
24
gestion_employe/templatetags/tags_personnaliser.py
Normal file
24
gestion_employe/templatetags/tags_personnaliser.py
Normal file
@@ -0,0 +1,24 @@
|
||||
"""Tags personnalisés pour les templates d'authentification.
|
||||
|
||||
Ce fichier contient des tags personnalisés pour les templates du projet lié à
|
||||
la gestion de l'accès des utilisateurs aux différentes pages.
|
||||
"""
|
||||
|
||||
from django import template
|
||||
from django.utils import timezone
|
||||
from gestion_employe.models import Affectation
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@register.filter
|
||||
def has_group(user, group_name):
|
||||
"""Vérifiez si un utilisateur appartient à un groupe spécifique."""
|
||||
return user.groups.filter(name=group_name).exists()
|
||||
|
||||
@register.filter
|
||||
def is_chef_projet(user):
|
||||
try:
|
||||
affectation = Affectation.objects.get(employe__user__username = user, date_fin_daffectation__gte = timezone.now().date())
|
||||
except Affectation.DoesNotExist:
|
||||
return False
|
||||
return affectation.role == "chef_projet"
|
||||
3
gestion_employe/tests.py
Normal file
3
gestion_employe/tests.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
102
gestion_employe/urls.py
Normal file
102
gestion_employe/urls.py
Normal file
@@ -0,0 +1,102 @@
|
||||
from . import views
|
||||
from django.urls import path
|
||||
|
||||
app_name = 'gestion_employe'
|
||||
|
||||
urlpatterns = [
|
||||
path(
|
||||
'',
|
||||
views.index,
|
||||
name='index'
|
||||
),
|
||||
path(
|
||||
'liste-employes/',
|
||||
views.liste_employe,
|
||||
name='liste-employes'
|
||||
),
|
||||
path(
|
||||
'enregistrer-detail-employe/',
|
||||
views.enregistrer_detail_employe,
|
||||
name='enregistrer-detail-employe'
|
||||
),
|
||||
path(
|
||||
'affectation/supprimer/',
|
||||
views.suppression_affectation,
|
||||
name='supprimer-affectation'
|
||||
),
|
||||
path(
|
||||
'contrat/creation/',
|
||||
views.creation_contrat,
|
||||
name='creation-contrat'
|
||||
),
|
||||
path(
|
||||
'contrat/supprimer/',
|
||||
views.suppression_contrat,
|
||||
name='supprimer-contrat'
|
||||
),
|
||||
path(
|
||||
'Affectation/affectation/',
|
||||
views.affecter_employe_projet,
|
||||
name='affecter_employe_projet'
|
||||
),
|
||||
path(
|
||||
'mon-profil/',
|
||||
views.mon_profil,
|
||||
name='mon-profil'
|
||||
),
|
||||
path(
|
||||
'enregistrement-document-rh',
|
||||
views.enregistrement_document,
|
||||
name='enregistrement-document-rh'
|
||||
),
|
||||
path(
|
||||
'modifier-employe',
|
||||
views.modifier_employer,
|
||||
name='modifier-employe'
|
||||
),
|
||||
path(
|
||||
"mes-formations/ajouter/",
|
||||
views.ajouter_formation,
|
||||
name="ajouter_formation"
|
||||
),
|
||||
path(
|
||||
"mes-formations/liste/",
|
||||
views.liste_formation,
|
||||
name="liste-formation"
|
||||
),
|
||||
path(
|
||||
"mes-formations/modifier/<int:pk>/",
|
||||
views.modifier_formation,
|
||||
name="modifier_formation"
|
||||
),
|
||||
path(
|
||||
"mes-formations/supprimer/<int:pk>/",
|
||||
views.supprimer_formation,
|
||||
name="supprimer_formation"
|
||||
),
|
||||
path(
|
||||
'modifier-mot-passe/',
|
||||
views.modifier_mot_passe,
|
||||
name='modifier-mot-passe'
|
||||
),
|
||||
# path(
|
||||
# 'creation-departement/',
|
||||
# views.creation_departement,
|
||||
# name='creation-departement'
|
||||
# ),
|
||||
# path(
|
||||
# 'modifier-departement/',
|
||||
# views.modifier_departement,
|
||||
# name='modifier-departement'
|
||||
# ),
|
||||
# path(
|
||||
# 'suppression-departement/',
|
||||
# views.supprimer_departement,
|
||||
# name='suppression-departement/'
|
||||
# ),
|
||||
path(
|
||||
"liste-contrat-expirants",
|
||||
views.liste_contrat_expirants,
|
||||
name='liste-contrat-expirants'
|
||||
)
|
||||
]
|
||||
447
gestion_employe/views.py
Normal file
447
gestion_employe/views.py
Normal file
@@ -0,0 +1,447 @@
|
||||
import json
|
||||
from datetime import timedelta, datetime
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
from django.utils import timezone
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.auth import authenticate
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
from django.http import JsonResponse
|
||||
from django.forms.models import model_to_dict
|
||||
from django.db.models import Sum
|
||||
|
||||
from .models import Employe, Contrat, Affectation, Formation
|
||||
from .forms import AffectationForm, ContratForm, FormationForm
|
||||
from fonction_utilitaire import fonctions_utilitaire
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
"""Vue d'index"""
|
||||
employes = Employe.objects.all().order_by('-user__date_joined')
|
||||
nombre_employes = Employe.objects.count()
|
||||
nombre_cps = Contrat.objects.filter(type_contrat='contrat_prestation').count()
|
||||
nombre_stage = Contrat.objects.filter(type_contrat='contrat_stage').count()
|
||||
date_limite = timezone.now().date() + timedelta(days=60)
|
||||
nombre_expirants = Contrat.objects.filter(
|
||||
date_fin__lte=date_limite,
|
||||
date_fin__gte=timezone.now().date(),
|
||||
statut='actif'
|
||||
).count()
|
||||
|
||||
return render(request, 'gestion_employe/index.html', {
|
||||
'employes': employes,
|
||||
'nombre_employes': nombre_employes,
|
||||
'nombre_cps': nombre_cps,
|
||||
'nombre_stage': nombre_stage,
|
||||
'nombre_expirants': nombre_expirants,
|
||||
'affectation_form': AffectationForm(),
|
||||
'contrat_form': ContratForm()
|
||||
})
|
||||
|
||||
@login_required
|
||||
def liste_contrat_expirants(request):
|
||||
""" Liste des contrats proches """
|
||||
|
||||
date_limite = timezone.now().date() + timedelta(days = fonctions_utilitaire.DUREE_FIN_CONTRAT)
|
||||
contats_expirants = [
|
||||
{
|
||||
'employe': f"{contrat.employe.user.first_name} {contrat.employe.user.last_name}",
|
||||
'type_contrat': dict(Contrat.TYPE_CONTRAT).get(contrat.type_contrat),
|
||||
'date_debut': contrat.date_debut,
|
||||
'date_fin': contrat.date_fin,
|
||||
'statut': contrat.statut,
|
||||
'fichier_contrat': contrat.fichier_contrat.url if contrat.fichier_contrat else ""
|
||||
}
|
||||
for contrat in
|
||||
Contrat.objects.filter(date_fin__lte=date_limite, date_fin__gte=timezone.now().date(), statut='actif')
|
||||
]
|
||||
|
||||
return JsonResponse(contats_expirants, safe=False)
|
||||
|
||||
@login_required
|
||||
def affecter_employe_projet(request):
|
||||
"""Vue pour affecter un employé à un projet avec vérification des contraintes d'affectation"""
|
||||
if request.method == 'POST':
|
||||
employe_id = request.POST.get('affecter_employe_id')
|
||||
try:
|
||||
employe = Employe.objects.get(id=employe_id)
|
||||
except Employe.DoesNotExist:
|
||||
messages.error(request, "L'employé spécifié n'existe pas.")
|
||||
return redirect('gestion_employe:index')
|
||||
|
||||
form = AffectationForm(request.POST)
|
||||
if form.is_valid():
|
||||
projet = form.cleaned_data['projet']
|
||||
date_fin_affectation = form.cleaned_data['date_fin_daffectation']
|
||||
temps_nouveau = form.cleaned_data['pourcentage_temps_affectation']
|
||||
date_affectation = form.cleaned_data['date_affectation']
|
||||
|
||||
if (date_fin_affectation and date_affectation):
|
||||
total_affectation = (
|
||||
Affectation.objects.filter(employe=employe)
|
||||
.aggregate(total_pourcentage_affectation = Sum('pourcentage_temps_affectation'))
|
||||
['total_pourcentage_affectation'] or 0
|
||||
)
|
||||
if (date_fin_affectation < date_affectation):
|
||||
messages.warning(request, "La date de fin d'affectation ne peut pas être antérieure à la date de début.")
|
||||
return redirect('gestion_employe:index')
|
||||
elif date_fin_affectation > projet.date_fin:
|
||||
messages.warning(request, f"La date de fin de l'affectation ({date_fin_affectation}) ne peut pas dépasser la date de fin du projet ({projet.date_fin}).")
|
||||
return redirect('gestion_employe:index')
|
||||
elif total_affectation + temps_nouveau > 100:
|
||||
messages.warning(
|
||||
request,
|
||||
f"Les pourcentages d'affectation de l'employé {employe.first_name} {employe.last_name} dépasse 100% sur les différents projets ({total_affectation + temps_nouveau}%)."
|
||||
)
|
||||
return redirect('gestion_employe:index')
|
||||
|
||||
Affectation.objects.update_or_create(
|
||||
employe=employe,
|
||||
projet=projet,
|
||||
defaults={
|
||||
'date_affectation': form.cleaned_data['date_affectation'],
|
||||
'date_fin_daffectation': date_fin_affectation,
|
||||
'role': form.cleaned_data['role'],
|
||||
'pourcentage_temps_affectation': temps_nouveau,
|
||||
}
|
||||
)
|
||||
messages.success(request, f"L'employé {employe.user.first_name} {employe.user.last_name} a été affecté au projet {projet.nom_projet}.")
|
||||
return redirect('gestion_employe:index')
|
||||
else:
|
||||
messages.error(request, "Erreur : Formulaire non valide.")
|
||||
return redirect('gestion_employe:index')
|
||||
else:
|
||||
return redirect('gestion_employe:index')
|
||||
|
||||
@login_required
|
||||
def mon_profil(request):
|
||||
"""Vue pour afficher et modifier le profil de l'utilisateur connecté"""
|
||||
try:
|
||||
employe = Employe.objects.get(user__username=request.user)
|
||||
except Employe.DoesNotExist:
|
||||
messages.error(request, "Impossible d'acceder au menu 'Mon profil' car votre profil Utilisateur n'est lié à aucun profil Employé. Veuillez contacter l'Administrateur.")
|
||||
return redirect("gestion_conges:conge")
|
||||
|
||||
contrats = Contrat.objects.filter(employe=employe, statut='actif').first()
|
||||
projets = Affectation.objects.filter(
|
||||
employe = employe,
|
||||
date_fin_daffectation__gte = timezone.now().date()
|
||||
).select_related('projet')
|
||||
|
||||
return render(
|
||||
request,
|
||||
'gestion_employe/monprofil.html',
|
||||
{
|
||||
'employe': employe,
|
||||
'contrats': [{
|
||||
**model_to_dict(contrats),
|
||||
"type_contrat": dict(Contrat.TYPE_CONTRAT).get(contrats.type_contrat),
|
||||
"statut": dict(Contrat.STATUT_CONTRAT).get(contrats.statut),
|
||||
"fichier_contrat": contrats.fichier_contrat.url if contrats.fichier_contrat else "",
|
||||
} if contrats else []],
|
||||
'projets': [
|
||||
{
|
||||
**model_to_dict(a.projet),
|
||||
"date_affectation": a.date_affectation,
|
||||
"date_fin_daffectation": a.date_fin_daffectation,
|
||||
"role": dict(Affectation.ROLE_CHOICES).get(a.role),
|
||||
"pourcentage_temps_affectation": a.pourcentage_temps_affectation
|
||||
} for a in projets
|
||||
],
|
||||
"formation_form": FormationForm(),
|
||||
"expiration_contrat": contrats.nombre_jours_restant <= fonctions_utilitaire.DUREE_FIN_CONTRAT if contrats else False,
|
||||
"contrat_nb_jours_restant": contrats.nombre_jours_restant if contrats else None
|
||||
}
|
||||
)
|
||||
|
||||
@login_required
|
||||
def modifier_mot_passe(request):
|
||||
"""Vue pour permettre à un utilisateur de modifier son mot de passe et ses informations de profil"""
|
||||
user = User.objects.get(username=request.user)
|
||||
if request.method == "POST":
|
||||
ancien_mdp = request.POST["ancien-mdp"]
|
||||
nouveau_mdp = request.POST["nouveau-mdp"]
|
||||
confirmation_mdp = request.POST["confirmation-mdp"]
|
||||
|
||||
if authenticate(request, username=request.user, password=ancien_mdp) is None:
|
||||
messages.error(request, "Ancien mot de passe incorrect.")
|
||||
elif nouveau_mdp != confirmation_mdp:
|
||||
messages.error(request, "Les deux nouveaux ne correspondent pas.")
|
||||
else:
|
||||
user.set_password(nouveau_mdp)
|
||||
user.save()
|
||||
messages.success(request, "Mot de passe modifié avec succès.")
|
||||
|
||||
return redirect("gestion_employe:mon-profil")
|
||||
def modifier_employer(request):
|
||||
"""Vue pour permettre à un utilisateur de modifier les informations d'un employé"""
|
||||
try:
|
||||
employe = Employe.objects.get(user__username=request.user)
|
||||
except Employe.DoesNotExist:
|
||||
return JsonResponse({"message": "Employé non trouvé."})
|
||||
if request.method == "POST":
|
||||
data = json.loads(request.body)
|
||||
user = User.objects.get(username=request.user)
|
||||
user.last_name = data['nom']
|
||||
user.first_name = data['prenom']
|
||||
user.email = data['email']
|
||||
employe.telephone = data['telephone']
|
||||
employe.adresse = data['adresse']
|
||||
employe.sexe = data['sexe']
|
||||
if request.FILES.get("photo"):
|
||||
employe.photo = request.FILES["photo"]
|
||||
if data['date_naissance']:
|
||||
difference = relativedelta(timezone.now().date(), datetime.strptime(data['date_naissance'], "%Y-%m-%d").date())
|
||||
if difference.years >= 18:
|
||||
employe.date_naissance = data['date_naissance']
|
||||
else:
|
||||
return JsonResponse({"message": "Veuillez entrez une date de naissance correcte."})
|
||||
employe.save()
|
||||
user.save()
|
||||
return JsonResponse({"message": "Profil mis à jour avec succès."})
|
||||
|
||||
def enregistrement_document(request):
|
||||
employe = Employe.objects.get(user=request.user)
|
||||
if request.method == "POST":
|
||||
if request.FILES.get("photo"):employe.photo = request.FILES["photo"]
|
||||
if "cv" in request.FILES:employe.CV = request.FILES["cv"]
|
||||
if "diplome" in request.FILES: employe.diplome = request.FILES["diplome"]
|
||||
if "rib" in request.FILES: employe.rib = request.FILES["rib"]
|
||||
if "casier_judiciaire" in request.FILES:employe.casier_judiciaire = request.FILES["casier_judiciaire"]
|
||||
employe.save()
|
||||
messages.success(request, "Documents enregistrés avec succès.")
|
||||
|
||||
return redirect("gestion_employe:mon-profil")
|
||||
|
||||
def suppression_contrat(request):
|
||||
"""Vue pour permettre à un utilisateur de supprimer un contrat"""
|
||||
id_contrat = json.loads(request.body)['id']
|
||||
try:
|
||||
contrat = Contrat.objects.get(numero_contrat = id_contrat)
|
||||
except Contrat.DoesNotExist:
|
||||
messages.error(request, "Contrat non trouvé.")
|
||||
return JsonResponse({"message": "Contrat non trouvé."}, status=404)
|
||||
|
||||
contrat.delete()
|
||||
return JsonResponse({"message": "Contrat supprimé avec succès."})
|
||||
|
||||
def suppression_affectation(request):
|
||||
"""Vue pour permettre à un utilisateur de supprimer une affectation"""
|
||||
id_affectation = json.loads(request.body)['id']
|
||||
try:
|
||||
affectation = Affectation.objects.get(id=id_affectation)
|
||||
except Affectation.DoesNotExist:
|
||||
return JsonResponse({"message": "Affectation non trouvée."}, status=404)
|
||||
|
||||
affectation.delete()
|
||||
return JsonResponse({"message": "Affectation supprimée avec succès."})
|
||||
|
||||
def creation_contrat(request):
|
||||
"""Vue pour permettre à un utilisateur de créer un contrat pour un employé"""
|
||||
try:
|
||||
employe = Employe.objects.get(id=request.POST.get('employe_id'))
|
||||
except Employe.DoesNotExist:
|
||||
messages.error(request, "Employé non trouvé.")
|
||||
return redirect('employe-index')
|
||||
|
||||
if request.method == "POST":
|
||||
form = ContratForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
contrat = form.save(commit=False)
|
||||
contrat.employe = employe
|
||||
contrat.save()
|
||||
messages.success(request, "Contrat créé avec succès.")
|
||||
return redirect('gestion_employe:index')
|
||||
messages.error(request, "Formulaire non valide")
|
||||
else:
|
||||
form = ContratForm(initial={'employe': employe})
|
||||
return render(request, 'gestion_employe/index.html', {'contrat_form': form})
|
||||
|
||||
@login_required
|
||||
def enregistrer_detail_employe(request):
|
||||
"""Vue pour permettre à un utilisateur de modifier les détails d'un employé via une requête AJAX"""
|
||||
if request.method == "POST":
|
||||
data = json.loads(request.body)
|
||||
try:
|
||||
employe = Employe.objects.get(id=data['id'])
|
||||
except Employe.DoesNotExist:
|
||||
return JsonResponse({"error": "Employé non trouvé."}, status=404)
|
||||
|
||||
employe.fonction = data['fonction']
|
||||
employe.date_embauche = data['date_embauche']
|
||||
employe.matricule = data['matricule']
|
||||
employe.save()
|
||||
return JsonResponse({"message": "Détails de l'employé mis à jour avec succès."})
|
||||
else:
|
||||
return JsonResponse({"message": "Méthode non autorisée."}, status=405)
|
||||
|
||||
@login_required
|
||||
def liste_employe(request):
|
||||
""" Vue pour retourner la liste de tous les employés """
|
||||
employes = Employe.objects.exclude(user__first_name = '', user__last_name = '')
|
||||
|
||||
data = []
|
||||
for employe in employes:
|
||||
if employe.user.first_name != ' ' and employe.user.last_name != ' ':
|
||||
projets = [
|
||||
", ".join([
|
||||
a.projet.nom_projet for a in Affectation.objects.filter(
|
||||
employe=employe,
|
||||
date_fin_daffectation__gte=timezone.now().date()
|
||||
)
|
||||
])
|
||||
]
|
||||
formations = [
|
||||
{
|
||||
"titre": formation.titre,
|
||||
"organisme": formation.organisme,
|
||||
"description": formation.description,
|
||||
"date_obtention": formation.date_obtention,
|
||||
"date_fin": formation.date_fin,
|
||||
"certificat": formation.certificat.url if formation.certificat else "",
|
||||
} for formation in Formation.objects.filter(employe=employe)
|
||||
]
|
||||
|
||||
contrats = [
|
||||
{
|
||||
"numero_contrat": contrat.numero_contrat,
|
||||
"type_contrat": contrat.type_contrat,
|
||||
"date_debut": contrat.date_debut,
|
||||
"date_fin": contrat.date_fin,
|
||||
"salaire_mensuel": contrat.salaire_mensuel,
|
||||
"statut": contrat.statut,
|
||||
"fichier_contrat": contrat.fichier_contrat.url if contrat.fichier_contrat else "",
|
||||
} for contrat in Contrat.objects.filter(employe=employe, statut='actif')
|
||||
]
|
||||
|
||||
affectations = [
|
||||
{**model_to_dict(affectation), "projet": affectation.projet.nom_projet}
|
||||
for affectation in Affectation.objects.filter(
|
||||
employe=employe,
|
||||
date_fin_daffectation__gte=timezone.now().date()
|
||||
)
|
||||
]
|
||||
|
||||
data.append(
|
||||
{
|
||||
"id": employe.id,
|
||||
"employe": f"{employe.user.first_name} {employe.user.last_name}",
|
||||
"matricule": employe.matricule,
|
||||
"email": employe.user.email,
|
||||
"formations": formations,
|
||||
"affectations": affectations,
|
||||
"projet": projets,
|
||||
"contrats": contrats,
|
||||
"departement": employe.departement.nom if employe.departement else "",
|
||||
"fonction": employe.fonction,
|
||||
"date_embauche": employe.date_embauche,
|
||||
"adresse": employe.adresse,
|
||||
"telephone": employe.telephone,
|
||||
"sexe": employe.sexe,
|
||||
"CV": employe.CV.url if employe.CV else "",
|
||||
"diplome": employe.diplome.url if employe.diplome else "",
|
||||
"rib": employe.rib.url if employe.rib else "",
|
||||
"photo": employe.photo.url if employe.photo else "",
|
||||
"casier_judiciaire": employe.casier_judiciaire.url if employe.casier_judiciaire else "",
|
||||
"date_naissance": employe.date_naissance,
|
||||
}
|
||||
)
|
||||
return JsonResponse({'success': True, 'data': data}, safe=False)
|
||||
|
||||
@login_required
|
||||
def ajouter_formation(request):
|
||||
"""Vue pour permettre à un employé d'ajouter une formation à son profil"""
|
||||
employe = Employe.objects.get(user__username=request.user)
|
||||
if request.method == "POST":
|
||||
formation = FormationForm(request.POST, request.FILES)
|
||||
if formation.is_valid():
|
||||
ma_formation = formation.save(commit=False)
|
||||
ma_formation.employe = employe
|
||||
ma_formation.save()
|
||||
messages.success(request, "Formation ajoutée avec succès ")
|
||||
return redirect("gestion_employe:mon-profil")
|
||||
messages.error(request, "Formulaire non valide. Veuillez vérifier les informations saisies.")
|
||||
return redirect("gestion_employe:mon-profil")
|
||||
|
||||
def liste_formation(request):
|
||||
formations = Formation.objects.filter(employe__user__username=request.user).order_by("-date_obtention")
|
||||
return JsonResponse([
|
||||
{
|
||||
**model_to_dict(formation),
|
||||
"certificat": formation.certificat.url if formation.certificat else ""
|
||||
}
|
||||
for formation in formations
|
||||
], safe=False)
|
||||
|
||||
@login_required
|
||||
def modifier_formation(request, id_formation):
|
||||
"""Vue pour permettre à un employé de modifier une formation de son profil"""
|
||||
try:
|
||||
formation = Formation.objects.get(id=id_formation, employes=request.user)
|
||||
except Formation.DoesNotExist:
|
||||
messages.error(request, "Formation non trouvée.")
|
||||
return redirect("mes_formations")
|
||||
|
||||
if request.method == "POST":
|
||||
formation = FormationForm(request.POST, request.FILES, instance=formation)
|
||||
if formation.is_valid():
|
||||
messages.success(request, "Formation mise à jour ")
|
||||
|
||||
formation.save()
|
||||
messages.error(request, "Formulaire non valide. Veuillez vérifier les informations saisies.")
|
||||
return redirect("mes_formations")
|
||||
|
||||
@login_required
|
||||
def supprimer_formation(request, id_formation):
|
||||
"""Vue pour permettre à un employé de supprimer une formation de son profil"""
|
||||
try:
|
||||
formation = Formation.objects.get(id=id_formation, employes=request.user)
|
||||
except Formation.DoesNotExist:
|
||||
messages.error(request, "Formation non trouvée.")
|
||||
return redirect("mes_formations")
|
||||
|
||||
if request.method == "POST":
|
||||
formation.delete()
|
||||
messages.success(request, "Formation supprimée ")
|
||||
return redirect("mes_formations")
|
||||
|
||||
# @login_required
|
||||
# def creation_departement(request):
|
||||
# """Gère la création d'un nouveau département via un formulaire."""
|
||||
# if request.method == 'POST':
|
||||
# form_departement = DepartementForm(request.POST)
|
||||
# if form_departement.is_valid():
|
||||
# form_departement.save()
|
||||
# messages.success(request, "Département ajouté avec succès.")
|
||||
# else:
|
||||
# messages.error(request, "Erreur lors de l'ajout du département.")
|
||||
# return redirect('parametres-rh')
|
||||
|
||||
# @login_required
|
||||
# def modifier_departement(request, id):
|
||||
# """Gère la modification d'un département existant via un formulaire pré-rempli."""
|
||||
# departement = Departement.objects.get(id=id)
|
||||
# form = DepartementForm(instance=departement)
|
||||
# if request.method == 'POST':
|
||||
# nouveau_nom_departement = request.POST.get('nom')
|
||||
# if nouveau_nom_departement:
|
||||
# departement.nom = nouveau_nom_departement
|
||||
# departement.save()
|
||||
# messages.success(request, "Département modifié avec succès.")
|
||||
# return redirect('parametres-rh')
|
||||
# return render(request, 'gestion_employe/edit_departement.html', {
|
||||
# 'form': form,
|
||||
# 'departement': departement
|
||||
# })
|
||||
|
||||
# @login_required
|
||||
# def supprimer_departement(request, id):
|
||||
# """Gère la suppression d'un département existant."""
|
||||
# if request.method == "POST":
|
||||
# departement = Departement.objects.get(id=id)
|
||||
# departement.delete()
|
||||
# messages.success(request, "Département supprimé avec succès !")
|
||||
# return redirect('parametres-rh')
|
||||
Reference in New Issue
Block a user