Compare commits
5 Commits
5277b7f355
...
detail_res
| Author | SHA1 | Date | |
|---|---|---|---|
| 267994044c | |||
| a4b4a68dd2 | |||
| 07dc097d27 | |||
| 4146563f41 | |||
| c0cdca48fa |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -4,4 +4,4 @@ media/
|
||||
staticfiles/
|
||||
.env
|
||||
migrations/
|
||||
*.pyc
|
||||
*.pyc
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -19,12 +19,13 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if not expiration_contrat %}
|
||||
<div class="alert alert-danger fade show alert-dismissible mt-2">
|
||||
{% if not has_contrat %}
|
||||
<div class="alert alert-danger 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">
|
||||
|
||||
{% elif expiration_contrat %}
|
||||
<div class="alert alert-warning mt-2">
|
||||
<strong>Important :</strong> Votre contrat de travail expire dans {{ contrat_nb_jours_restant }} jours, veuillez contacter les ressources humaines.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<div class="modal fade" id="modalContratsEmploye" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">📄 Contrats de l'employé</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
||||
</div>
|
||||
|
||||
<div class="modal-body">
|
||||
<div id="contrats-employe-body">
|
||||
<!-- contenu dynamique JS -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button class="btn btn-secondary" data-bs-dismiss="modal">
|
||||
Fermer
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
Binary file not shown.
@@ -129,26 +129,41 @@ def mon_profil(request):
|
||||
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.")
|
||||
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()
|
||||
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',
|
||||
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 []],
|
||||
}] if contrats else [],
|
||||
|
||||
'projets': [
|
||||
{
|
||||
**model_to_dict(a.projet),
|
||||
@@ -158,12 +173,13 @@ def mon_profil(request):
|
||||
"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
|
||||
"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"""
|
||||
@@ -261,6 +277,7 @@ def creation_contrat(request):
|
||||
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()
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -23,29 +23,25 @@ btnEnregistrerBailleur.addEventListener('click', function() {
|
||||
});
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
table = new Tabulator("#table-bailleurs", {
|
||||
ajaxURL: "/gestion-projet/bailleurs/",
|
||||
layout: "fitColumns",
|
||||
pagination: "local",
|
||||
paginationSize: 5,
|
||||
table = new Tabulator("#table-bailleurs", {
|
||||
ajaxURL: "/gestion-projet/bailleurs/",
|
||||
layout: "fitColumns",
|
||||
pagination: "local",
|
||||
paginationSize: 5,
|
||||
|
||||
columns: [
|
||||
{title: "#", formatter: "rownum", width: 60},
|
||||
{title: "Organisme", field: "nom_organisme"},
|
||||
{title: "Contact", field: "contact"},
|
||||
{title: "Email", field: "email"},
|
||||
{title: "Pays", field: "pays"},
|
||||
],
|
||||
rowDblClick: function(e, row) {
|
||||
const data = row.getData();
|
||||
columns: [
|
||||
{title: "#", formatter: "rownum", width: 60},
|
||||
{title: "Organisme", field: "nom_organisme"},
|
||||
{title: "Contact", field: "contact"},
|
||||
{title: "Email", field: "email"},
|
||||
{title: "Pays", field: "pays"},
|
||||
],
|
||||
rowDblClick: function(e, row) {
|
||||
const data = row.getData();
|
||||
|
||||
if (confirm(`Voulez-vous vraiment supprimer ${data.nom_organisme} ?`)) {
|
||||
supprimerBailleur(data.id);
|
||||
}
|
||||
if (confirm(`Voulez-vous vraiment supprimer ${data.nom_organisme} ?`)) {
|
||||
supprimerBailleur(data.id);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
@@ -48,4 +48,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -335,7 +335,6 @@ def activites_projet(request):
|
||||
}
|
||||
return render(request, 'gestion_projet/suivi_activite.html', context)
|
||||
|
||||
|
||||
@login_required
|
||||
def ajouter_activite_projet(request):
|
||||
"""Vue pour ajouter une activité à un projet spécifique via un formulaire"""
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -27,8 +27,14 @@ const calendrier = Schedule(document.getElementById('planning-reservation'), {
|
||||
$("motif_reservation").value=data.motif_reservation;
|
||||
$("besoin_zoom").checked=data.besoin_zoom;
|
||||
$("besoin_ordinateur").checked=data.besoin_ordinateur;
|
||||
$("lien_zoom").value=data.lien_zoom;
|
||||
|
||||
$("lien_zoom").value=data.lien_zoom;
|
||||
|
||||
const zoomContainer = $("lien_zoom_container");
|
||||
if (!data.besoin_zoom) {
|
||||
zoomContainer.classList.add("d-none");
|
||||
} else {
|
||||
zoomContainer.classList.remove("d-none");
|
||||
}
|
||||
if (data.besoin_zoom === false){
|
||||
$("lien_zoom_container").className = "d-none";
|
||||
}
|
||||
@@ -164,6 +170,8 @@ const tableau_reservation_attente = new Tabulator("#tableau-reservation-attente"
|
||||
tableau_reservation_attente.on("rowClick", (row, rowData) => {
|
||||
const data = rowData.getData();
|
||||
|
||||
console.log(data);
|
||||
|
||||
if(data.besoin_zoom === false){
|
||||
$("lien_zoom_container").className = 'd-none';
|
||||
}
|
||||
@@ -177,6 +185,7 @@ tableau_reservation_attente.on("rowClick", (row, rowData) => {
|
||||
$("statut-reservation").innerHTML=data.statut;
|
||||
$("date_debut").value = data.date_debut;
|
||||
$("date_fin").value = data.date_fin;
|
||||
|
||||
$("heure_debut").value=data.heure_debut;
|
||||
$("heure_fin").value=data.heure_fin;
|
||||
$("motif_reservation").value=data.motif_reservation;
|
||||
@@ -187,4 +196,4 @@ tableau_reservation_attente.on("rowClick", (row, rowData) => {
|
||||
const modal = new bootstrap.Modal($("modalDetailReservation"));
|
||||
bootstrap.Modal.getOrCreateInstance($("modalReservationAttente")).hide();
|
||||
modal.show();
|
||||
})
|
||||
})
|
||||
|
||||
@@ -22,11 +22,7 @@
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date de debut :</label>
|
||||
<input type='date' class="form-control" id="date_debut" readonly >
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Date de fin :</label>
|
||||
<input type='date' class="form-control" id="date_fin" readonly >
|
||||
<input type='date' class="form-control" id="date_evenement" readonly >
|
||||
</div>
|
||||
<div class="form-group mb-2">
|
||||
<label>Heure de début :</label>
|
||||
@@ -67,4 +63,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,9 @@ from fonction_utilitaire import fonctions_utilitaire
|
||||
from gestion_employe.models import Employe
|
||||
from gestion_salle.forms import ReservationForm
|
||||
from .models import Reservation
|
||||
from datetime import timedelta
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
|
||||
|
||||
@login_required
|
||||
@@ -130,8 +133,7 @@ def liste_reservation_attente(request):
|
||||
{
|
||||
**model_to_dict(reservation),
|
||||
"employe": f"{reservation.employe.user.first_name} {reservation.employe.user.last_name}",
|
||||
"salle": dict(Reservation.TYPE_CHOICES).get(reservation.salle),
|
||||
'statut': dict(Reservation.STATUT).get(reservation.statut),
|
||||
"salle": dict(Reservation.TYPE_CHOICES).get(reservation.salle)
|
||||
} for reservation in reservations
|
||||
]
|
||||
|
||||
@@ -156,7 +158,6 @@ def detail_reservation(request:HttpRequest, reservation_id:int):
|
||||
'besoin_ordinateur': reservation.besoin_ordi,
|
||||
'lien_zoom': reservation.lien_zoom or '',
|
||||
}
|
||||
|
||||
return JsonResponse(reservation_json, safe=True)
|
||||
|
||||
@login_required
|
||||
|
||||
301
notification/services.py
Normal file
301
notification/services.py
Normal file
@@ -0,0 +1,301 @@
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
|
||||
def send_notification_email(user, sujet, message):
|
||||
"""
|
||||
Fonction générique pour envoyer un email simple
|
||||
"""
|
||||
if not user.email:
|
||||
return
|
||||
send_mail(
|
||||
sujet,
|
||||
message,
|
||||
settings.DEFAULT_FROM_EMAIL,
|
||||
[user.email],
|
||||
fail_silently=False,
|
||||
)
|
||||
|
||||
def email_reservation_creee(reservation):
|
||||
user = reservation.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Votre réservation a été enregistrée avec succès.
|
||||
|
||||
Salle : {reservation.salle}
|
||||
Date : {reservation.date_debut}
|
||||
Heure : {reservation.heure_debut} - {reservation.heure_fin}
|
||||
Motif : {reservation.motif_reservation}
|
||||
|
||||
Merci.
|
||||
"""
|
||||
send_notification_email(user, "Confirmation de votre réservation", message)
|
||||
|
||||
def email_reservation_directeur(reservation, directeur):
|
||||
message = f"""
|
||||
Bonjour {directeur.get_full_name()},
|
||||
|
||||
Une nouvelle réservation attend votre validation.
|
||||
|
||||
Employé : {reservation.employe.user.get_full_name()}
|
||||
Salle : {reservation.salle}
|
||||
Date : Du {reservation.date_debut} au {reservation.date_fin}
|
||||
Heure : {reservation.heure_debut} - {reservation.heure_fin}
|
||||
Motif : {reservation.motif_reservation}
|
||||
|
||||
Connectez-vous à la plateforme pour valider.
|
||||
|
||||
https://support.cerfig.org/login/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(directeur, "Nouvelle réservation à valider", message)
|
||||
|
||||
def email_reservation_zoom(reservation, admin):
|
||||
message = f"""
|
||||
Bonjour {admin.get_full_name()},
|
||||
|
||||
Une demande de lien Zoom a été faite.
|
||||
|
||||
Employé : {reservation.employe.user.get_full_name()}
|
||||
Date : {reservation.date_debut} au {reservation.date_fin}
|
||||
Heure : {reservation.heure_debut} - {reservation.heure_fin}
|
||||
Motif : {reservation.motif_reservation}
|
||||
|
||||
Veuillez créer le lien Zoom.
|
||||
|
||||
https://support.cerfig.org/login/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(admin, "Création lien Zoom requise", message)
|
||||
|
||||
def email_statut_reservation(reservation):
|
||||
user = reservation.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Le statut de votre réservation a été mis à jour.
|
||||
|
||||
Salle : {reservation.salle}
|
||||
Date : {reservation.date_debut}
|
||||
Statut : {reservation.statut}
|
||||
|
||||
Merci de vous connecter
|
||||
|
||||
https://support.cerfig.org
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
|
||||
"""
|
||||
send_notification_email(user, "Mise à jour de votre réservation", message)
|
||||
|
||||
def email_reservation_validee(reservation):
|
||||
user = reservation.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Votre réservation a été VALIDÉE.
|
||||
|
||||
Salle : {reservation.salle}
|
||||
Date : {reservation.date_debut}
|
||||
|
||||
https://support.cerfig.org/login/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(user, "Réservation validée", message)
|
||||
|
||||
def email_reservation_refusee(reservation):
|
||||
user = reservation.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Votre réservation a été REFUSÉE.
|
||||
|
||||
Salle : {reservation.salle}
|
||||
Date : {reservation.date_debut}
|
||||
|
||||
https://support.cerfig.org/login/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(user, "Réservation refusée", message)
|
||||
|
||||
def email_contrat_cree(contrat):
|
||||
user = contrat.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Un nouveau contrat a été créé pour vous.
|
||||
|
||||
Date début : {contrat.date_debut}
|
||||
Date fin : {contrat.date_fin}
|
||||
|
||||
Bienvenue !
|
||||
Merci de vous connecter pour plus informations sur votre contrat
|
||||
|
||||
https://support.cerfig.org
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
|
||||
send_notification_email(user, "Nouveau contrat", message)
|
||||
|
||||
def email_statut_contrat(contrat):
|
||||
user = contrat.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Votre contrat a été modifier par les ressource humaine .
|
||||
veuillez vous connecter pour voir les nouvelles informations sur votre contrat
|
||||
|
||||
https://support.cerfig.org/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(user, "Mise à jour du contrat", message)
|
||||
|
||||
def email_affectation_projet(affectation):
|
||||
user = affectation.employe.user
|
||||
projet = affectation.projet
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Votre affectation au projet a été mise à jour.
|
||||
|
||||
Projet : {projet.nom}
|
||||
Description : {projet.description}
|
||||
Date début : {projet.date_debut}
|
||||
Date fin : {projet.date_fin}
|
||||
Rôle : {affectation.role}
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
|
||||
"""
|
||||
send_notification_email(user, "Affectation projet", message)
|
||||
|
||||
def email_expiration_fichier(projet, fichier, chef_projet):
|
||||
message = f"""
|
||||
Bonjour {chef_projet.get_full_name()},
|
||||
|
||||
Un fichier est proche de son expiration.
|
||||
|
||||
Projet : {projet.nom}
|
||||
Fichier : {fichier.nom}
|
||||
Date début : {fichier.date_debut}
|
||||
Date fin : {fichier.date_fin}
|
||||
|
||||
https://support.cerfig.org/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
|
||||
"""
|
||||
send_notification_email(chef_projet, "Fichier proche expiration", message)
|
||||
|
||||
def email_conge_cree(conge):
|
||||
user = conge.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Votre demande de congé a été enregistrée avec succès.
|
||||
|
||||
Type de congé : {conge.type_conge}
|
||||
Date début : {conge.date_debut}
|
||||
Date fin : {conge.date_fin}
|
||||
Motif : {conge.motif}
|
||||
|
||||
Votre demande est en attente de validation.
|
||||
|
||||
https://support.cerfig.org/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(user, "Demande de congé enregistrée", message)
|
||||
|
||||
def email_conge_responsable(conge, responsable):
|
||||
message = f"""
|
||||
Bonjour {responsable.get_full_name()},
|
||||
|
||||
Une demande de congé nécessite votre validation.
|
||||
|
||||
Employé : {conge.employe.user.get_full_name()}
|
||||
Type : {conge.type_conge}
|
||||
Date : {conge.date_debut} au {conge.date_fin}
|
||||
Motif : {conge.motif}
|
||||
|
||||
Merci de valider ou refuser.
|
||||
|
||||
https://support.cerfig.org/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(responsable, "Validation congé (Niveau 1)", message)
|
||||
|
||||
def email_conge_directeur(conge, directeur):
|
||||
message = f"""
|
||||
Bonjour {directeur.get_full_name()},
|
||||
|
||||
Une demande de congé a été validée par le responsable et attend votre validation finale.
|
||||
|
||||
Employé : {conge.employe.user.get_full_name()}
|
||||
Type : {conge.type_conge}
|
||||
Date : {conge.date_debut} au {conge.date_fin}
|
||||
|
||||
Merci de valider définitivement.
|
||||
|
||||
https://support.cerfig.org/login/
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(directeur, "Validation congé (Niveau 2)", message)
|
||||
|
||||
def email_conge_valide(conge):
|
||||
user = conge.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Votre demande de congé a été VALIDÉE.
|
||||
|
||||
Type : {conge.type_conge}
|
||||
Date : {conge.date_debut} au {conge.date_fin}
|
||||
|
||||
Bon repos a vous
|
||||
|
||||
https://support.cerfig.org
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(user, "Congé validé", message)
|
||||
|
||||
def email_conge_refuse(conge):
|
||||
user = conge.employe.user
|
||||
message = f"""
|
||||
Bonjour {user.get_full_name()},
|
||||
|
||||
Votre demande de congé a été REFUSÉE.
|
||||
|
||||
Type : {conge.type_conge}
|
||||
Date : {conge.date_debut} au {conge.date_fin}
|
||||
|
||||
Motif : {conge.motif_refus or "Non précisé"}
|
||||
|
||||
https://support.cerfig.org
|
||||
|
||||
Cordialement,
|
||||
SIRH
|
||||
"""
|
||||
send_notification_email(user, "Congé refusé", message)
|
||||
Reference in New Issue
Block a user