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