Première groose modification

This commit is contained in:
2026-04-27 14:27:07 +02:00
parent 4f9df2214c
commit f470cebfac
62 changed files with 437 additions and 160 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,6 +1,7 @@
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"},
@@ -12,6 +13,8 @@ const tableau_liste_employe = new Tabulator("#tableau_liste_employe", {
// ajaxURL: url_liste_employe,
pagination: true,
paginationSize: 10,
})
fetch(url_liste_employe)
@@ -44,6 +47,8 @@ tableau_liste_employe.on("rowClick", function (row, rowData) {
document.getElementById('document-diplome').href = data.diplome;
document.getElementById('document-diplome').textContent = data.diplome || "Aucun diplôme";
document.getElementById('document-photo').href = data.photo;
document.getElementById('document-photo').textContent = data.photo || "Aucune photo";
document.getElementById('document-cv').href = data.CV;
document.getElementById('document-cv').textContent = data.CV || "Aucun CV";
document.getElementById('document-rib').href = data.rib;
@@ -123,6 +128,7 @@ tableau_liste_employe.on("rowClick", function (row, rowData) {
</div>
`
};
const supprimerButtons = document.getElementsByClassName("btn-supprimer-contrat");
Array.from(supprimerButtons).forEach(button => {
@@ -144,8 +150,46 @@ tableau_liste_employe.on("rowClick", function (row, rowData) {
location.reload();
})
});
})
}),
document.addEventListener("click", function (e) {
if (e.target.closest(".btn-modifier-contrat")) {
const button = e.target.closest(".btn-modifier-contrat");
const parent = button.closest(".col-6");
const contratId = button.dataset.contratid;
const data = {
type_contrat: parent.querySelector("select").value,
date_debut: parent.querySelectorAll("input")[1].value,
date_fin: parent.querySelectorAll("input")[2].value,
salaire_mensuel: parent.querySelectorAll("input")[3].value,
statut: parent.querySelectorAll("input")[4].value,
};
fetch(`/contrat/modifier/${contratId}/`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-CSRFToken": document.querySelector('[name=csrfmiddlewaretoken]').value
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
if (data.message) {
alert(data.message);
} else {
alert(data.error || "Erreur");
}
})
.catch(error => {
console.error("Erreur:", error);
});
}
});
document.getElementById("affectation-nom-employe").textContent = data.employe || "Employé inconnu";
document.getElementById("affecter_employe_id").value = data.id;
@@ -204,7 +248,7 @@ tableau_liste_employe.on("rowClick", function (row, rowData) {
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;

View File

@@ -16,27 +16,36 @@ const tableau_certificat = new Tabulator("#tableau-certificat", {
],
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);
const photoInput = $("photo");
if (photoInput.files.length > 0) {
formData.append("photo", photoInput.files[0]);
}
fetch(url, {
method: 'POST',
method: "POST",
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': csrftoken
"X-CSRFToken": csrftoken
},
body: JSON.stringify({
"nom": $("nom").value,
"prenom": $("prenom").value,
"email": $("email").value,
"telephone": $("telephone").value,
"adresse": $("adresse").value,
"sexe": $("sexe").value,
"date_naissance": $("date_naissance").value,
})
body: formData
})
.then(response => response.json())
.then(data => alert(data.message))
})
.catch(error => console.error("Erreur:", error));
});

View File

@@ -19,17 +19,14 @@
{% endfor %}
{% endif %}
{% if expiration_contrat %}
{% if contrat_nb_jours_restant %}
{% 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 %}
{% else %}
<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>
{% endif %}
<div class="accordion mt-2" id="accordionInformationEmploye">
@@ -44,6 +41,13 @@
<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>
@@ -63,12 +67,13 @@
<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>
<div class="col">
<div class="form-group mb-2">
<label>Département :</label>
<input type="text" class="form-control" id="departement" value="{{ employe.departement.nom|default:'' }}" readonly>
@@ -167,6 +172,13 @@
{% 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 %}

View File

@@ -88,22 +88,23 @@
<div class="row">
<div class="col">
<div class="d-flex justify-content-between">
<h5>
<h5>G
<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>
<!-- <button class="btn btn-primary btn-modifier-contrat" data-contratid="${contrat.id}">
<i class="bi bi-pencil"></i> Modifier
</button> -->
</div>
{% endif %}
</div>
{% csrf_token %}
<div class="row" id="contrats-list"></div>
<div class="row" id="contrats-list">
</div>
</div>
</div>
<hr class="my-4">

View File

@@ -11,6 +11,10 @@
<div class="row g-3">
<div class="col">
<ul class="list-group">
<li class="list-group-item">
<strong>Photo :</strong>
<a id="document-photo" target="_blank"></a>
</li>
<li class="list-group-item">
<strong>Diplôme :</strong>
<a id="document-diplome" target="_blank"></a>

View File

@@ -34,6 +34,12 @@ urlpatterns = [
views.suppression_contrat,
name='supprimer-contrat'
),
path(
"contrat/modifier/",
views.modifier_contrat,
name="modifier-contrat"
),
path(
'Affectation/affectation/',
views.affecter_employe_projet,

View File

@@ -1,12 +1,12 @@
import json
from datetime import timedelta, datetime
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.shortcuts import get_object_or_404, render, redirect
from django.contrib.auth.decorators import login_required
from django.http import JsonResponse
@@ -124,8 +124,8 @@ def mon_profil(request):
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()
@@ -140,6 +140,7 @@ def mon_profil(request):
**model_to_dict(contrats),
"type_contrat": dict(Contrat.TYPE_CONTRAT).get(contrats.type_contrat),
"statut": dict(Contrat.STATUT_CONTRAT).get(contrats.statut),
# "salaire_mensuel": dict(Contrat.SALAIRR_MENSSUEL).get(contrats.salaire_mensuel),
"fichier_contrat": contrats.fichier_contrat.url if contrats.fichier_contrat else "",
} if contrats else []],
'projets': [
@@ -192,7 +193,8 @@ def modifier_employer(request):
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:
@@ -201,18 +203,18 @@ def modifier_employer(request):
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__username=request.user)
employe = Employe.objects.get(user=request.user)
if request.method == "POST":
employe.CV = request.FILES["cv"] if 'cv' in request.FILES else employe.CV
employe.diplome = request.FILES["diplome"] if 'diplome' in request.FILES else employe.diplome
employe.rib = request.FILES["rib"] if 'rib' in request.FILES else employe.rib
employe.casier_judiciaire = request.FILES["casier_judiciaire"] if 'casier_judiciaire' in request.FILES else employe.casier_judiciaire
messages.success(request, "Documents enregistrés avec succès.")
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")
@@ -240,14 +242,25 @@ def suppression_affectation(request):
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é"""
"""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)
@@ -256,9 +269,13 @@ def creation_contrat(request):
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})
return render(request, 'gestion_employe/index.html', {
'contrat_form': form
})
@login_required
def enregistrer_detail_employe(request):
@@ -281,76 +298,106 @@ def enregistrer_detail_employe(request):
@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(
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)
]
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,
}
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 modifier_contrat(request):
"""vue pour la modification du 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)
try:
data = json.loads(request.body)
id_contrat = data.get("id")
contrat = get_object_or_404(Contrat, id=id_contrat)
contrat.type_contrat = data.get("type_contrat")
contrat.date_debut = data.get("date_debut")
contrat.date_fin = data.get("date_fin")
contrat.salaire_mensuel = data.get("salaire_mensuel")
contrat.statut = data.get("statut")
contrat.save()
return JsonResponse({"message": "Contrat modifié avec succès"})
except Exception as e:
return JsonResponse({"message": str(e)}, status=400)
@login_required
def ajouter_formation(request):
"""Vue pour permettre à un employé d'ajouter une formation à son profil"""