import json from datetime import datetime, timedelta from dateutil.relativedelta import relativedelta from django.contrib import messages from django.contrib.auth import authenticate from django.contrib.auth.decorators import login_required from django.contrib.auth.models import User from django.db.models import Sum from django.forms.models import model_to_dict from django.http import JsonResponse from django.shortcuts import redirect, render from django.utils import timezone from fonction_utilitaire import fonctions_utilitaire from .forms import AffectationForm, ContratForm, FormationForm from .models import Affectation, Contrat, Employe, Formation @login_required def index(request): """Vue d'index""" if not request.user.groups.filter(name="ressource_humaine").exists(): return redirect('gestion_employe:mon-profil') 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.user.first_name} {employe.user.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}.") 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] ) 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') 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 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(), "has_contrat": has_contrat, "expiration_contrat": expiration_contrat, "contrat_nb_jours_restant": contrat_nb_jours_restant } ) @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": <<<<<<< HEAD data = request.POST ======= >>>>>>> 8c6e59e (Correction enregistrement profil) user = User.objects.get(username=request.user) user.last_name = request.POST['nom'] user.first_name = request.POST['prenom'] user.email = request.POST['email'] employe.telephone = request.POST['telephone'] employe.adresse = request.POST['adresse'] employe.sexe = request.POST['sexe'] if request.FILES.get("photo"): employe.photo = request.FILES["photo"] if request.POST['date_naissance']: difference = relativedelta(timezone.now().date(), datetime.strptime(request.POST['date_naissance'], "%Y-%m-%d").date()) if difference.years >= 18: employe.date_naissance = request.POST['date_naissance'] else: messages.error(request, "Veuillez entrez une date de naissance correcte.") employe.save() user.save() messages.success(request, "Profil mis à jour avec succès.") return redirect("gestion_employe:mon-profil") def enregistrement_document(request): """Vue pour permettre à un utilisateur de télécharger et enregistrer des documents liés à son profil""" 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=datetime.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 contrats_employe(request, employe_id): try: employe = Employe.objects.get(id=employe_id) except Employe.DoesNotExist: return JsonResponse( {"error": "Employé non trouvé"}, status=404 ) contrats = Contrat.objects.filter( employe=employe ).order_by("-date_debut") data = [ { "id": contrat.id, "numero_contrat": contrat.numero_contrat, "type_contrat": dict(Contrat.TYPE_CONTRAT).get( contrat.type_contrat ), "date_debut": contrat.date_debut.strftime("%Y-%m-%d"), "date_fin": contrat.date_fin.strftime("%Y-%m-%d") if contrat.date_fin else "", "salaire_mensuel": contrat.salaire_mensuel, "statut": dict(Contrat.STATUT_CONTRAT).get( contrat.statut ), "fichier": contrat.fichier_contrat.url if contrat.fichier_contrat else "", } for contrat in contrats ] return JsonResponse({ "employe": employe.user.get_full_name(), "contrats": data }) @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")