2026-04-30 13:28:57 +02:00
import json
2026-04-30 13:33:39 +02:00
from datetime import date , timedelta , datetime
2026-04-30 13:28:57 +02:00
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 } . " )
2026-05-07 11:22:14 +00:00
fonctions_utilitaire . envoyer_mail (
sujet = " Affectation à un projet " ,
message = f """ Bonjour { employe . user . first_name } { employe . user . last_name } , vous avez été affecté au projet { projet . nom_projet . upper ( ) } pour la période du { form . cleaned_data [ ' date_affectation ' ] . strftime ( ' %d / % m/ % Y ' ) } au { date_fin_affectation . strftime ( ' %d / % m/ % Y ' ) } en tant que { dict ( Affectation . ROLE_CHOICES ) . get ( form . cleaned_data [ ' role ' ] ) } .
Veuillez consulter votre profil pour plus de détails . """ ,
destinataires = [ employe . user . email ]
)
2026-04-30 13:28:57 +02:00
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 :
2026-04-30 17:00:00 +02:00
messages . error (
request ,
" Impossible d ' acceder au menu ' Mon profil ' car votre profil Utilisateur n ' est lié à aucun profil Employé. Veuillez contacter l ' Administrateur. "
)
2026-04-30 13:28:57 +02:00
return redirect ( " gestion_conges:conge " )
2026-04-30 17:00:00 +02:00
2026-04-30 13:28:57 +02:00
contrats = Contrat . objects . filter ( employe = employe , statut = ' actif ' ) . first ( )
2026-04-30 17:00:00 +02:00
2026-04-30 13:28:57 +02:00
projets = Affectation . objects . filter (
2026-04-30 17:00:00 +02:00
employe = employe ,
date_fin_daffectation__gte = timezone . now ( ) . date ( )
2026-04-30 13:28:57 +02:00
) . select_related ( ' projet ' )
2026-04-30 17:00:00 +02:00
has_contrat = contrats is not None
expiration_contrat = False
contrat_nb_jours_restant = None
if contrats :
nb_jours = contrats . nombre_jours_restant
contrat_nb_jours_restant = nb_jours
expiration_contrat = nb_jours < = fonctions_utilitaire . DUREE_FIN_CONTRAT
2026-04-30 13:28:57 +02:00
return render (
2026-04-30 17:00:00 +02:00
request ,
' gestion_employe/monprofil.html ' ,
2026-04-30 13:28:57 +02:00
{
' employe ' : employe ,
2026-04-30 17:00:00 +02:00
2026-04-30 13:28:57 +02:00
' 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 " " ,
2026-04-30 17:00:00 +02:00
} ] if contrats else [ ] ,
2026-04-30 13:28:57 +02:00
' 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
] ,
2026-04-30 17:00:00 +02:00
2026-04-30 13:28:57 +02:00
" formation_form " : FormationForm ( ) ,
2026-04-30 17:00:00 +02:00
" has_contrat " : has_contrat ,
" expiration_contrat " : expiration_contrat ,
" contrat_nb_jours_restant " : contrat_nb_jours_restant
2026-04-30 13:28:57 +02:00
}
)
@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 " )
2026-05-06 11:19:30 +00:00
2026-04-30 13:28:57 +02:00
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 ) :
2026-05-06 11:19:30 +00:00
""" Vue pour permettre à un utilisateur de télécharger et enregistrer des documents liés à son profil """
2026-04-30 13:28:57 +02:00
employe = Employe . objects . get ( user = request . user )
if request . method == " POST " :
2026-05-06 11:19:30 +00:00
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 " ]
2026-04-30 13:28:57 +02:00
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 ) :
2026-04-30 13:33:39 +02:00
""" Créer un contrat pour un employé (avec contrôle d ' existence de contrat actif) """
2026-04-30 13:28:57 +02:00
try :
employe = Employe . objects . get ( id = request . POST . get ( ' employe_id ' ) )
except Employe . DoesNotExist :
messages . error ( request , " Employé non trouvé. " )
return redirect ( ' employe-index ' )
2026-04-30 13:28:57 +02:00
2026-04-30 13:33:39 +02:00
contrat_actif = Contrat . objects . filter (
employe = employe ,
date_fin__gte = date . today ( )
) . exists ( )
2026-04-30 13:28:57 +02:00
if request . method == " POST " :
2026-04-30 13:33:39 +02:00
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 ' )
2026-04-30 13:28:57 +02:00
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 " )
2026-04-30 13:33:39 +02:00
2026-04-30 13:28:57 +02:00
else :
form = ContratForm ( initial = { ' employe ' : employe } )
2026-04-30 13:33:39 +02:00
return render ( request , ' gestion_employe/index.html ' , {
' contrat_form ' : form
} )
2026-04-30 13:28:57 +02:00
@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 " )
2026-04-30 13:28:57 +02:00
return redirect ( " mes_formations " )