1699: Première partie-Voir les évaluateurs qui n'ont pas encore donné de note. 1700...
[auf_rh_dae.git] / project / recrutement / admin.py
CommitLineData
df59fcab 1# -*- encoding: utf-8 -*-
2
6067184b 3from django.core.urlresolvers import reverse
4from django.http import HttpResponseRedirect
df59fcab 5from django.contrib import admin
38df74bb 6from django.shortcuts import get_object_or_404
7
6067184b 8from reversion.admin import VersionAdmin
38df74bb 9from datamaster_modeles.models import Employe, Implantation, Region
6067184b 10
df59fcab 11from recrutement.models import *
f6724c20
NBV
12from recrutement.workflow import grp_administrateurs_recrutement,\
13 grp_evaluateurs_recrutement, grp_drh_recrutement
df59fcab 14
d2b30f5f 15class OffreEmploiAdmin(VersionAdmin):
7f9e891e 16 date_hierarchy = 'date_creation'
ec517164 17 list_display = ('nom', 'resume', 'date_limite', 'region', '_candidatsList')
f6724c20 18
8941aee7 19 # Afficher la liste des candidats pour l'offre d'emploi
596fe324 20 def _candidatsList(self, obj):
8ea41642 21 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
22 </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id)
2f78949d 23 _candidatsList.allow_tags = True
f6724c20 24 _candidatsList.short_description = "Afficher la liste des candidats"
362a3534 25
2f78949d 26 def queryset(self, request):
382501c1 27 qs = self.model._default_manager.get_query_set()
f6724c20
NBV
28 # Si user est superuser afficher toutes les offres d'emploi
29 user_groupes = request.user.groups.all()
30 if not grp_drh_recrutement in user_groupes:
beef7690 31 """
beef7690
NBV
32 Si le user n'est ni un évaluateur ni un administrateur régional,
33 retourner none
34 Vérifier groupes
35 """
f6724c20 36 if grp_evaluateurs_recrutement in user_groupes:
ca73c3c6
NBV
37 try:
38 user = Evaluateur.objects.get(user=request.user)
39 except Evaluateur.DoesNotExist:
40 return qs.none()
f6724c20 41 elif grp_administrateurs_recrutement in user_groupes:
ca73c3c6
NBV
42 try:
43 user = AdministrateurRegional.objects.get(user=request.user)
44 except AdministrateurRegional.DoesNotExist:
45 return qs.none()
f6724c20
NBV
46 else:
47 return qs.none()
48
49 if type(user) is AdministrateurRegional:
50 region_ids = [g.id for g in user.regions.all()]
51 return qs.select_related('offre_emploi').\
52 filter(region__in=region_ids)
beef7690 53 if type(user) is Evaluateur:
f6724c20 54 candidats = [g for g in user.candidats.all()]
beef7690 55 offre_emploi_ids = [c.offre_emploi.id for c in candidats]
f6724c20 56 return qs.select_related('offre_emploi').\
beef7690 57 filter(id__in=offre_emploi_ids)
3bcef02d 58 return qs.none()
382501c1 59 return qs.select_related('offre_emploi')
f6724c20
NBV
60
61 def has_change_permission(self, request, obj=None):
62 user_groupes = request.user.groups.all()
63 if grp_drh_recrutement in user_groupes or \
64 grp_administrateurs_recrutement in user_groupes:
65 return True
66 return False
67
68class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
beef7690 69 list_display = ('nom', 'resume', 'date_limite', 'region', )
65c4cbd9 70 readonly_fields = ('description', 'poste', 'bureau',
f6724c20
NBV
71 'duree_affectation', 'renumeration',
72 'debut_affectation', 'lieu_affectation', 'nom',
73 'resume', 'date_limite', 'region')
74 fieldsets = (
720c3ad5 75 ('Nom', {
f6724c20
NBV
76 'fields': ('nom', )
77 }),
720c3ad5 78 ('Description générale', {
f6724c20
NBV
79 'fields': ('poste', 'resume','description', 'date_limite', )
80 }),
720c3ad5 81 ('Coordonnées', {
f6724c20
NBV
82 'fields': ('lieu_affectation', 'bureau', 'region', )
83 }),
720c3ad5 84 ('Autre', {
f6724c20
NBV
85 'fields': ('debut_affectation', 'duree_affectation',
86 'renumeration', )
87 }),
88 )
89 def has_add_permission(self, request):
90 return False
91
92 def has_delete_permission(self, request, obj=None):
93 return False
94
2d083449
NBV
95 def has_change_permission(self, request, obj=None):
96 user_groupes = request.user.groups.all()
beef7690
NBV
97 if grp_evaluateurs_recrutement in user_groupes or \
98 grp_drh_recrutement in user_groupes:
2d083449
NBV
99 return True
100 return False
101
cced6a23 102class ProxyCandidatPiece(CandidatPiece):
103 """
104 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
105 plus ergonomique.
106 """
107 class Meta:
108 proxy = True
109 verbose_name = "pièce jointe"
74cbc7a7 110 verbose_name_plural = "pièces jointes"
cced6a23 111
170c9aa2 112class CandidatPieceInline(admin.TabularInline):
cced6a23 113 model = ProxyCandidatPiece
114 fields = ('candidat', 'nom', 'path', )
170c9aa2 115 extra = 1
116
27c81d11 117class ProxyEvaluateur(Evaluateur.candidats.through):
cced6a23 118 """
119 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
120 plus ergonomique.
121 """
122 class Meta:
123 proxy = True
124 verbose_name = "évaluateur"
125
eb579d40 126class EvaluateurInline(admin.TabularInline):
cced6a23 127 model = ProxyEvaluateur
720c3ad5 128 fields = ('evaluateur',)
eb579d40 129 extra = 1
130
d2b30f5f 131class CandidatAdmin(VersionAdmin):
7f9e891e 132 date_hierarchy = 'date_creation'
0fd8a26d 133 list_display = ('nom', 'prenom', 'offre_emploi','statut',
720c3ad5 134 'voir_offre_emploi', #'note_evaluateur',
8941aee7 135 'calculer_moyenne', 'afficher_candidat',)
8ea41642 136 list_filter = ('offre_emploi', )
7f9e891e 137 fieldsets = (
4896b661 138 ("Offre d'emploi", {
139 'fields': ('offre_emploi', )
140 }),
7f9e891e 141 ('Informations personnelles', {
142 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance',
143 'situation_famille', 'nombre_dependant',)
144 }),
ec517164 145 ('Coordonnées', {
146 'fields': ('telephone', 'email', 'adresse', 'ville',
147 'etat_province', 'code_postal', 'pays', )
7f9e891e 148 }),
149 ('Informations professionnelles', {
4896b661 150 'fields': ('niveau_diplome','employeur_actuel',
8ea41642 151 'poste_actuel', 'domaine_professionnel',)
7f9e891e 152 }),
65c4cbd9
NBV
153 ('Traitement', {
154 'fields': ('statut', )
7f9e891e 155 }),
156 )
170c9aa2 157 inlines = [
158 CandidatPieceInline,
eb579d40 159 EvaluateurInline,
170c9aa2 160 ]
f9983b5a 161
4e8340cf 162 actions = ['affecter_candidats_evaluateur', 'envoyer_courriel_candidats']
362a3534 163 # Affecter un évaluateurs à des candidats
7061f835 164 def affecter_candidats_evaluateur(modeladmin, obj, candidats):
596fe324 165 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
2adf9e0c 166
8ea41642 167 return HttpResponseRedirect(reverse('affecter_evaluateurs_candidats')+
168 "?ids=%s" % (",".join(selected)))
d835c9f3 169 affecter_candidats_evaluateur.short_description = u'Affecter évaluateur'
362a3534 170
4e8340cf 171 # Envoyer un courriel à des candidats
52765380 172 def envoyer_courriel_candidats(modeladmin, obj, candidats):
173 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
174
175 return HttpResponseRedirect(reverse('envoyer_courriel_candidats')+
176 "?ids=%s" % (",".join(selected)))
177 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
178
05503d56 179 # Évaluer un candidat
596fe324 180 def evaluer_candidat(self, obj):
beef7690
NBV
181 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat </a>" % \
182 (reverse('admin:recrutement_candidatevaluation_changelist'),
183 obj.id)
596fe324 184 evaluer_candidat.allow_tags = True
beef7690 185 evaluer_candidat.short_description = 'Évaluation'
596fe324 186
7d82fd33 187 # Afficher un candidat
188 def afficher_candidat(self, obj):
382501c1
NBV
189 return "<a href='%s'>Voir le candidat</a>" % \
190 (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
7d82fd33 191 afficher_candidat.allow_tags = True
f6724c20 192 afficher_candidat.short_description = u'Afficher les détails du candidat'
7d82fd33 193
8941aee7 194 # Voir l'offre d'emploi
195 def voir_offre_emploi(self, obj):
720c3ad5
NBV
196 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
197 (reverse('admin:recrutement_proxyoffreemploi_change',
198 args=(obj.offre_emploi.id,)))
8941aee7 199 voir_offre_emploi.allow_tags = True
200 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
201
8941aee7 202 # Calculer la moyenne des notes
203 def calculer_moyenne(self, obj):
204 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
205 offre_emploi = obj.offre_emploi
206
f6724c20
NBV
207 notes = [evaluation.note for evaluation in evaluations.all() \
208 if evaluation.note is not None]
8941aee7 209
210 if len(notes) > 0 and offre_emploi.date_limite <= datetime.date.today():
211 moyenne_votes = float(sum(notes)) / len(notes)
212 else:
213 moyenne_votes = "Non disponible"
214 return moyenne_votes
215 calculer_moyenne.allow_tags = True
216 calculer_moyenne.short_description = "Moyenne des notes"
217
f6724c20
NBV
218 def add_delete_permission(self, request, obj=None) :
219 user_groupes = request.user.groups.all()
220 if grp_drh_recrutement in user_groupes or \
221 grp_administrateurs_recrutement in user_groupes:
222 return True
223 return False
4896b661 224
f6724c20
NBV
225 def has_add_permission(self, request):
226 return self.add_delete_permission(request, request)
4896b661 227
f6724c20
NBV
228 def has_delete_permission(self, request, obj=None):
229 return self.add_delete_permission(request, request)
230
231 def has_change_permission(self, request, obj=None):
232 user_groupes = request.user.groups.all()
233 if grp_drh_recrutement in user_groupes or \
2d083449 234 grp_administrateurs_recrutement in user_groupes:
f6724c20
NBV
235 return True
236 return False
4896b661 237
596fe324 238 def queryset(self, obj):
f9983b5a 239 """
8ea41642 240 Spécifie un queryset limité, autrement Django exécute un
241 select_related() sans paramètre, ce qui a pour effet de charger tous
242 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
243 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
244 génération d'une requête infinie.
d835c9f3 245
f9983b5a 246 """
f6724c20
NBV
247 qs = self.model._default_manager.get_query_set()
248 # Si user est superuser afficher tous les candidats
249 user_groupes = obj.user.groups.all()
250 if not grp_drh_recrutement in user_groupes:
251 # Si le user n'est ni un évaluateur ni un administrateur régional,
252 # retourner none
253
254 # Vérifier groupes
255 if grp_evaluateurs_recrutement in user_groupes:
ca73c3c6
NBV
256 try:
257 user = Evaluateur.objects.get(user=obj.user)
258 except Evaluateur.DoesNotExist:
259 return qs.none()
efedc086
NBV
260 """
261 elif grp_administrateurs_recrutement in user_groupes:
262 try:
263 user = AdministrateurRegional.objects.get(user=obj.user)
264 except AdministrateurRegional.DoesNotExist:
265 return qs.none()
266 """
f6724c20
NBV
267 else:
268 return qs.none()
f6724c20
NBV
269 ids = [c.id for c in user.candidats.all()]
270 return qs.select_related('candidats').filter(id__in=ids)
271 return qs.select_related('candidats')
272
273class ProxyCandidatAdmin(CandidatAdmin):
f6724c20
NBV
274 readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom',
275 'genre', 'nationalite', 'date_naissance',
276 'situation_famille', 'nombre_dependant', 'telephone',
277 'email', 'adresse', 'ville', 'etat_province',
278 'code_postal', 'pays', 'niveau_diplome',
279 'employeur_actuel', 'poste_actuel',
280 'domaine_professionnel',)
2d083449
NBV
281 fieldsets = (
282 ("Offre d'emploi", {
283 'fields': ('offre_emploi', )
284 }),
285 ('Informations personnelles', {
286 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance',
287 'situation_famille', 'nombre_dependant',)
288 }),
289 ('Coordonnées', {
290 'fields': ('telephone', 'email', 'adresse', 'ville',
291 'etat_province', 'code_postal', 'pays', )
292 }),
293 ('Informations professionnelles', {
294 'fields': ('niveau_diplome','employeur_actuel',
295 'poste_actuel', 'domaine_professionnel',)
296 }),
297 )
f6724c20 298 inlines = []
2d083449 299
f6724c20
NBV
300 def has_add_permission(self, request):
301 return False
302
303 def has_delete_permission(self, request, obj=None):
304 return False
2adf9e0c 305
2d083449
NBV
306 def has_change_permission(self, request, obj=None):
307 user_groupes = request.user.groups.all()
beef7690
NBV
308 if grp_drh_recrutement in user_groupes or \
309 grp_administrateurs_recrutement in user_groupes or \
310 grp_evaluateurs_recrutement in user_groupes:
2d083449
NBV
311 return True
312 return False
313
2e9ee615 314class CandidatPieceAdmin(admin.ModelAdmin):
170c9aa2 315 list_display = ('nom', 'candidat', )
316
317 def queryset(self, request):
318 """
319 Spécifie un queryset limité, autrement Django exécute un
320 select_related() sans paramètre, ce qui a pour effet de charger tous
321 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
322 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
323 génération d'une requête infinie.
d835c9f3 324 Affiche la liste de candidats que si le user connecté
27c81d11 325 possède un Evaluateur
170c9aa2 326 """
327 qs = self.model._default_manager.get_query_set()
328 return qs.select_related('candidat')
2e9ee615 329
d2b30f5f 330class EvaluateurAdmin(VersionAdmin):
eb579d40 331 fieldsets = (
f6724c20 332 (None, {'fields': ('user', )}),
720c3ad5 333 #(None, {'fields': ('candidats',)}),
eb579d40 334 )
4418c732 335
b89fef74 336class AdministrateurRegionalAdmin(VersionAdmin):
27c81d11 337 pass
338
d2b30f5f 339class CandidatEvaluationAdmin(VersionAdmin):
b903198b
NBV
340 list_display = ('_offre_emploi', '_candidat', 'evaluateur', '_note',
341 '_commentaire', )
beef7690
NBV
342 readonly_fields = ('candidat', 'evaluateur')
343 fieldsets = (
344 ('Évaluation du candidat', {
345 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
346 }),
347 )
348
349 def _note(self, obj):
350 """
351 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
352 un lien pour Évaluer le candidat.
353 Sinon afficher la note.
354 """
b903198b
NBV
355 evaluateur = obj.evaluateur
356 candidat = obj.candidat
357 candidat_evaluation = CandidatEvaluation.objects.\
358 get(candidat=candidat, evaluateur=evaluateur)
beef7690 359 if obj.note is None:
b903198b 360 return "<a href='%s'>Candidat non évalué</a>" % \
beef7690 361 (reverse('admin:recrutement_candidatevaluation_change',
b903198b
NBV
362 args=(candidat_evaluation.id,)))
363 return "<a href='%s'>%s</a>" % \
364 (reverse('admin:recrutement_candidatevaluation_change',
365 args=(candidat_evaluation.id,)), obj.note)
366 return
beef7690
NBV
367 _note.allow_tags = True
368 _note.short_description = "Votre note"
369 _note.admin_order_field = 'note'
370
371 def _candidat(self, obj):
372 return "<a href='%s'>%s</a>" \
373 % (reverse('admin:recrutement_proxycandidat_change',
374 args=(obj.candidat.id,)), obj.candidat)
375 _candidat.allow_tags = True
376 _candidat.short_description = 'Candidat'
377
378 def _commentaire(self, obj):
379 """
380 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
381 dans le champ commentaire, Aucun au lieu de (None)
382 Sinon afficher la note.
383 """
384 if obj.commentaire is None:
385 return "Aucun"
386 return obj.commentaire
387 _commentaire.allow_tags = True
388 _commentaire.short_description = "Commentaire"
720c3ad5 389
720c3ad5 390
beef7690
NBV
391 def _offre_emploi(self, obj):
392 return "<a href='%s'>%s</a>" % \
393 (reverse('admin:recrutement_proxyoffreemploi_change',
394 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
395 _offre_emploi.allow_tags = True
396 _offre_emploi.short_description = "Voir offre d'emploi"
397 _offre_emploi.admin_order_field = 'offre_emploi'
398
720c3ad5 399 def queryset(self, request):
beef7690
NBV
400 """
401 Afficher uniquement les évaluations de l'évaluateur, sauf si
402 l'utilisateur est super admin.
403 """
720c3ad5 404 qs = self.model._default_manager.get_query_set()
beef7690
NBV
405 user_groupes = request.user.groups.all()
406 if grp_drh_recrutement in user_groupes:
407 return qs.select_related('offre_emploi')
408
ca73c3c6 409 try:
d069cdf1 410 evaluateur = Evaluateur.objects.get(user=request.user)
ca73c3c6
NBV
411 except Evaluateur.DoesNotExist:
412 return qs.none()
413
414 candidats_evaluations = CandidatEvaluation.objects.\
415 filter(evaluateur=evaluateur)
416 candidats_evaluations_ids = [ce.id for ce in \
417 candidats_evaluations.all()]
418 return qs.select_related('offre_emploi').\
419 filter(id__in=candidats_evaluations_ids)
596fe324 420
4e8340cf 421class CourrielTemplateAdmin(VersionAdmin):
422 pass
423
df59fcab 424admin.site.register(OffreEmploi, OffreEmploiAdmin)
382501c1 425admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
df59fcab 426admin.site.register(Candidat, CandidatAdmin)
382501c1 427admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
720c3ad5 428admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
27c81d11 429admin.site.register(Evaluateur, EvaluateurAdmin)
beef7690 430#admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
382501c1 431#admin.site.register(CourrielTemplate, CourrielTemplateAdmin)