463 lines
20 KiB
Python
463 lines
20 KiB
Python
import json
|
|
from datetime import date, 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):
|
|
"""Créer un contrat pour un employé (avec contrôle d'existence de contrat actif)"""
|
|
|
|
try:
|
|
employe = Employe.objects.get(id=request.POST.get('employe_id'))
|
|
except Employe.DoesNotExist:
|
|
messages.error(request, "Employé non trouvé.")
|
|
return redirect('employe-index')
|
|
contrat_actif = Contrat.objects.filter(
|
|
employe=employe,
|
|
date_fin__gte=date.today()
|
|
).exists()
|
|
|
|
if request.method == "POST":
|
|
if contrat_actif:
|
|
messages.error(
|
|
request,
|
|
"Impossible de créer un contrat : cet employé a déjà un contrat actif."
|
|
)
|
|
return redirect('gestion_employe:index')
|
|
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')
|