[#3139] candidatures : action en lot pour modifier statut
[auf_rh_dae.git] / project / recrutement / admin.py
1 # -*- encoding: utf-8 -*-
2
3 import textwrap
4 from django.core.urlresolvers import reverse
5 from django.http import HttpResponseRedirect
6 from django.contrib import admin
7 from django.forms.models import BaseInlineFormSet
8 from django.db.models import Avg
9 from django.conf import settings
10 from django.shortcuts import render_to_response
11 from django.template import RequestContext
12
13 from reversion.admin import VersionAdmin
14 from datamaster_modeles.models import Region, Bureau
15 from project.rh import models as rh
16 from auf.django.emploi.models import STATUT_CHOICES
17
18 from project.dae.utils import get_employe_from_user as get_emp
19 from recrutement.models import *
20 from recrutement.workflow import grp_drh_recrutement, grp_drh2_recrutement, \
21 grp_directeurs_bureau_recrutement, \
22 grp_administrateurs_recrutement, \
23 grp_correspondants_rh_recrutement, \
24 grp_haute_direction_recrutement
25
26 from recrutement.forms import *
27
28 ### CONSTANTES
29 IMPLANTATIONS_CENTRALES = [15, 19]
30
31 class OrderedChangeList(admin.views.main.ChangeList):
32 """
33 Surcharge pour appliquer le order_by d'un annotate
34 """
35 def get_query_set(self):
36 qs = super(OrderedChangeList, self).get_query_set()
37 qs = qs.order_by('-moyenne')
38 return qs
39
40 class OffreEmploiAdmin(VersionAdmin):
41 date_hierarchy = 'date_creation'
42 list_display = ('nom', 'date_limite', 'region', 'statut',
43 'est_affiche', '_candidatsList', )
44 exclude = ('actif', 'poste_nom', 'resume',)
45 list_filter = ('statut',)
46 actions = ['affecter_evaluateurs_offre_emploi', ]
47 form = OffreEmploiForm
48
49 ### Actions à afficher
50 def get_actions(self, request):
51 actions = super(OffreEmploiAdmin, self).get_actions(request)
52 del actions['delete_selected']
53 return actions
54
55 ### Affecter un évaluateurs à des offres d'emploi
56 def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):
57 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
58
59 return HttpResponseRedirect(reverse('affecter_evaluateurs_offre_emploi')+
60 "?ids=%s" % (",".join(selected)))
61 affecter_evaluateurs_offre_emploi.short_description = u'Affecter évaluateur(s)'
62
63 ### Afficher la liste des candidats pour l'offre d'emploi
64 def _candidatsList(self, obj):
65 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
66 </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id)
67 _candidatsList.allow_tags = True
68 _candidatsList.short_description = "Afficher la liste des candidats"
69
70 ### Formulaire
71 def get_form(self, request, obj=None, **kwargs):
72 form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs)
73 employe = get_emp(request.user)
74 user_groupes = request.user.groups.all()
75
76
77 # Region
78 if form.declared_fields.has_key('region'):
79 region_field = form.declared_fields['region']
80 else:
81 region_field = form.base_fields['region']
82
83 if grp_drh_recrutement in user_groupes or \
84 grp_drh2_recrutement in user_groupes or \
85 grp_haute_direction_recrutement in user_groupes:
86 region_field.queryset = Region.objects.all()
87 else:
88 region_field.queryset = Region.objects.\
89 filter(id=employe.implantation.region.id)
90
91 # Poste
92 if form.declared_fields.has_key('poste'):
93 poste_field = form.declared_fields['poste']
94 else:
95 poste_field = form.base_fields['poste']
96
97 if grp_drh_recrutement in user_groupes or \
98 grp_drh2_recrutement in user_groupes or \
99 grp_haute_direction_recrutement in user_groupes:
100 poste_field.queryset = rh.Poste.objects.all()
101 else:
102 poste_field.queryset = rh.Poste.objects.\
103 filter(implantation__region=employe.implantation.region).\
104 exclude(implantation__in=IMPLANTATIONS_CENTRALES)
105
106 # Bureau
107 if form.declared_fields.has_key('bureau'):
108 bureau_field = form.declared_fields['bureau']
109 else:
110 bureau_field = form.base_fields['bureau']
111
112 if grp_drh_recrutement in user_groupes or \
113 grp_drh2_recrutement in user_groupes or \
114 grp_haute_direction_recrutement in user_groupes:
115 bureau_field.queryset = Bureau.objects.all()
116 else:
117 bureau_field.queryset = Bureau.objects.\
118 filter(region=employe.implantation.region)
119
120 return form
121
122 ### Queryset
123 def queryset(self, request):
124 qs = self.model._default_manager.get_query_set().select_related('offre_emploi')
125 user_groupes = request.user.groups.all()
126 if grp_drh_recrutement in user_groupes or \
127 grp_drh2_recrutement in user_groupes or \
128 grp_haute_direction_recrutement in user_groupes:
129 return qs
130
131 if grp_directeurs_bureau_recrutement in user_groupes or \
132 grp_correspondants_rh_recrutement in user_groupes or \
133 grp_administrateurs_recrutement in user_groupes:
134 employe = get_emp(request.user)
135 return qs.filter(region=employe.implantation.region)
136
137 if Evaluateur.objects.filter(user=request.user).exists():
138 evaluateur = Evaluateur.objects.get(user=request.user)
139 offre_ids = [e.candidat.offre_emploi_id for e in
140 CandidatEvaluation.objects.select_related('candidat').filter(evaluateur=evaluateur)]
141 return qs.filter(id__in=offre_ids)
142
143 return qs.none()
144
145 ### Permission add, delete, change
146 def has_add_permission(self, request):
147 user_groupes = request.user.groups.all()
148 if request.user.is_superuser is True or \
149 grp_drh_recrutement in user_groupes or \
150 grp_drh2_recrutement in user_groupes or \
151 grp_directeurs_bureau_recrutement in user_groupes or \
152 grp_administrateurs_recrutement in user_groupes or \
153 grp_haute_direction_recrutement in user_groupes:
154 return True
155 return False
156
157 def has_delete_permission(self, request, obj=None):
158 user_groupes = request.user.groups.all()
159 if request.user.is_superuser is True or \
160 grp_drh_recrutement in user_groupes or \
161 grp_drh2_recrutement in user_groupes or \
162 grp_directeurs_bureau_recrutement in user_groupes or \
163 grp_administrateurs_recrutement in user_groupes or \
164 grp_haute_direction_recrutement in user_groupes:
165 return True
166 return False
167
168 def has_change_permission(self, request, obj=None):
169 user_groupes = request.user.groups.all()
170 if request.user.is_superuser is True or \
171 grp_drh_recrutement in user_groupes or \
172 grp_drh2_recrutement in user_groupes or \
173 grp_directeurs_bureau_recrutement in user_groupes or \
174 grp_administrateurs_recrutement in user_groupes or \
175 grp_haute_direction_recrutement in user_groupes:
176 return True
177 return False
178
179 class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
180 list_display = ('nom', 'date_limite', 'region', 'statut',
181 'est_affiche')
182 readonly_fields = ('description', 'bureau', 'duree_affectation',
183 'renumeration', 'debut_affectation', 'lieu_affectation',
184 'nom', 'resume', 'date_limite', 'region', 'poste')
185 fieldsets = (
186 ('Nom', {
187 'fields': ('nom', )
188 }),
189 ('Description générale', {
190 'fields': ('description', 'date_limite', )
191 }),
192 ('Coordonnées', {
193 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
194 }),
195 ('Autre', {
196 'fields': ('debut_affectation', 'duree_affectation',
197 'renumeration', )
198 }),
199 )
200 inlines = []
201
202
203 ### Lieu de redirection après le change
204 def response_change(self, request, obj):
205 return HttpResponseRedirect(reverse\
206 ('admin:recrutement_proxyoffreemploi_changelist'))
207
208 ### Formulaire
209 def get_form(self, request, obj=None, **kwargs):
210 form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs)
211 return form
212
213 ### Permissions add, delete, change
214 def has_add_permission(self, request):
215 return False
216
217 def has_delete_permission(self, request, obj=None):
218 return False
219
220 def has_change_permission(self, request, obj=None):
221 user_groupes = request.user.groups.all()
222 if request.user.is_superuser is True or \
223 grp_correspondants_rh_recrutement in user_groupes or \
224 grp_drh_recrutement in user_groupes or \
225 grp_drh2_recrutement in user_groupes or \
226 grp_directeurs_bureau_recrutement in user_groupes or \
227 grp_administrateurs_recrutement in user_groupes or \
228 grp_haute_direction_recrutement in user_groupes:
229 return True
230
231 if obj is not None:
232 return True
233
234 return False
235
236 class CandidatPieceInline(admin.TabularInline):
237 model = CandidatPiece
238 fields = ('candidat', 'nom', 'path',)
239 extra = 1
240 max_num = 3
241
242 class ReadOnlyCandidatPieceInline(CandidatPieceInline):
243 readonly_fields = ('candidat', 'nom', 'path', )
244 cand_delete = False
245
246
247 class CandidatEvaluationInlineFormSet(BaseInlineFormSet):
248 """
249 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
250 """
251 def __init__(self, *args, **kwargs):
252 super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs)
253 self.can_delete = False
254
255 class CandidatEvaluationInline(admin.TabularInline):
256 model = CandidatEvaluation
257 fields = ('evaluateur', 'note', 'commentaire')
258 max_num = 0
259 extra = 0
260 formset = CandidatEvaluationInlineFormSet
261
262 ### Fields readonly
263 def get_readonly_fields(self, request, obj=None):
264 """
265 Empêche la modification des évaluations
266 """
267 if obj:
268 return self.readonly_fields+('evaluateur', 'note', 'commentaire')
269 return self.readonly_fields
270
271 class CandidatAdmin(VersionAdmin):
272 search_fields = ('nom', 'prenom' )
273 exclude = ('actif', )
274 list_editable = ('statut', )
275 list_display = ('_candidat', 'offre_emploi',
276 'voir_offre_emploi', 'calculer_moyenne',
277 'afficher_candidat', '_date_creation', 'statut', )
278 list_filter = ('offre_emploi', 'offre_emploi__region', 'statut', )
279
280 fieldsets = (
281 ("Offre d'emploi", {
282 'fields': ('offre_emploi', )
283 }),
284 ('Informations personnelles', {
285 'fields': ('prenom','nom','genre', 'nationalite',
286 'situation_famille', 'nombre_dependant',)
287 }),
288 ('Coordonnées', {
289 'fields': ('telephone', 'email', 'adresse', 'ville',
290 'etat_province', 'code_postal', 'pays', )
291 }),
292 ('Informations professionnelles', {
293 'fields': ('niveau_diplome','employeur_actuel',
294 'poste_actuel', 'domaine_professionnel',)
295 }),
296 ('Traitement', {
297 'fields': ('statut', )
298 }),
299 )
300 inlines = [
301 CandidatPieceInline,
302 CandidatEvaluationInline,
303 ]
304 actions = ['envoyer_courriel_candidats', 'changer_statut']
305
306 def _candidat(self, obj):
307 txt = u"%s %s (%s)" % ( obj.nom.upper(), obj.prenom,
308 obj.genre)
309 txt = textwrap.wrap(txt, 30)
310 return "<br/>".join(txt)
311 _candidat.short_description = "Candidat"
312 _candidat.admin_order_field = "nom"
313 _candidat.allow_tags = True
314
315 def _date_creation(self, obj):
316 return obj.date_creation
317 _date_creation.admin_order_field = "date_creation"
318 _date_creation.short_description = "Date de réception"
319
320 ### Actions à afficher
321 def get_actions(self, request):
322 actions = super(CandidatAdmin, self).get_actions(request)
323 del actions['delete_selected']
324 return actions
325
326 ### Envoyer un courriel à des candidats
327 def envoyer_courriel_candidats(modeladmin, obj, candidats):
328 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
329
330 return HttpResponseRedirect(reverse('selectionner_template')+
331 "?ids=%s" % (",".join(selected)))
332 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
333
334 ### Changer le statut à des candidats
335 def changer_statut(modeladmin, request, queryset):
336 if request.POST.get('post'):
337 queryset.update(statut=request.POST.get('statut'))
338 return None
339
340 context = {
341 'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
342 'queryset': queryset,
343 'status': STATUT_CHOICES,
344 }
345
346 return render_to_response("recrutement/selectionner_statut.html",
347 context, context_instance = RequestContext(request))
348
349 changer_statut.short_description = u'Changer statut'
350
351 ### Évaluer un candidat
352 def evaluer_candidat(self, obj):
353 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat</a>" % \
354 (reverse('admin:recrutement_candidatevaluation_changelist'),
355 obj.id)
356 evaluer_candidat.allow_tags = True
357 evaluer_candidat.short_description = 'Évaluation'
358
359 ### Afficher un candidat
360 def afficher_candidat(self, obj):
361 items = [u"<li><a href='%s%s'>%s</li>" % \
362 (settings.OE_PRIVE_MEDIA_URL, pj.path, pj.get_nom_display()) \
363 for pj in obj.pieces_jointes()]
364 html = "<a href='%s'>Voir le candidat</a>" % \
365 (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
366 return "%s<ul>%s</ul>" % (html, "\n".join(items))
367 afficher_candidat.allow_tags = True
368 afficher_candidat.short_description = u'Détails du candidat'
369
370 ### Voir l'offre d'emploi
371 def voir_offre_emploi(self, obj):
372 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
373 (reverse('admin:recrutement_proxyoffreemploi_change',
374 args=(obj.offre_emploi.id,)))
375 voir_offre_emploi.allow_tags = True
376 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
377
378 ### Calculer la moyenne des notes
379 def calculer_moyenne(self, obj):
380 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
381
382 notes = [evaluation.note for evaluation in evaluations \
383 if evaluation.note is not None]
384
385 if len(notes) > 0:
386 moyenne_votes = round(float(sum(notes)) / len(notes), 2)
387 else:
388 moyenne_votes = "Non disponible"
389
390 totales = len(evaluations)
391 faites = len(notes)
392
393 if obj.statut == 'REC':
394 if totales == faites:
395 color = "green"
396 elif faites > 0 and float(totales) / float(faites) >= 2:
397 color = "orange"
398 else:
399 color = "red"
400 else:
401 color = "black"
402
403 return """<span style="color: %s;">%s (%s/%s)</span>""" % (color, moyenne_votes, faites, totales)
404 calculer_moyenne.allow_tags = True
405 calculer_moyenne.short_description = "Moyenne"
406 calculer_moyenne.admin_order_field = ""
407
408 ### Permissions add, delete, change
409 def has_add_permission(self, request):
410 user_groupes = request.user.groups.all()
411 if request.user.is_superuser is True or \
412 grp_correspondants_rh_recrutement in user_groupes or \
413 grp_drh_recrutement in user_groupes or \
414 grp_drh2_recrutement in user_groupes or \
415 grp_directeurs_bureau_recrutement in user_groupes or \
416 grp_administrateurs_recrutement in user_groupes or \
417 grp_haute_direction_recrutement in user_groupes:
418 return True
419 return False
420
421 def has_delete_permission(self, request, obj=None):
422 user_groupes = request.user.groups.all()
423 if request.user.is_superuser is True or \
424 grp_correspondants_rh_recrutement in user_groupes or \
425 grp_drh_recrutement in user_groupes or \
426 grp_drh2_recrutement in user_groupes or \
427 grp_directeurs_bureau_recrutement in user_groupes or \
428 grp_administrateurs_recrutement in user_groupes or \
429 grp_haute_direction_recrutement in user_groupes:
430 return True
431 return False
432
433 def has_change_permission(self, request, obj=None):
434 user_groupes = request.user.groups.all()
435 if request.user.is_superuser is True or \
436 grp_correspondants_rh_recrutement in user_groupes or \
437 grp_drh_recrutement in user_groupes or \
438 grp_drh2_recrutement in user_groupes or \
439 grp_directeurs_bureau_recrutement in user_groupes or \
440 grp_administrateurs_recrutement in user_groupes or \
441 grp_haute_direction_recrutement in user_groupes:
442 return True
443 return False
444
445 def get_changelist(self, request, **kwargs):
446 return OrderedChangeList
447
448 def queryset(self, request):
449 """
450 Spécifie un queryset limité, autrement Django exécute un
451 select_related() sans paramètre, ce qui a pour effet de charger tous
452 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
453 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
454 génération d'une requête infinie.
455
456 """
457
458 qs = self.model._default_manager.get_query_set().select_related('offre_emploi').annotate(moyenne=Avg('evaluations__note'))
459
460 user_groupes = request.user.groups.all()
461 if grp_drh_recrutement in user_groupes or \
462 grp_drh2_recrutement in user_groupes or \
463 grp_haute_direction_recrutement in user_groupes:
464 return qs
465
466 if grp_directeurs_bureau_recrutement in user_groupes or \
467 grp_correspondants_rh_recrutement in user_groupes or \
468 grp_administrateurs_recrutement in user_groupes:
469 employe = get_emp(request.user)
470 return qs.filter(offre_emploi__region=employe.implantation.region)
471
472 if Evaluateur.objects.filter(user=request.user).exists():
473 evaluateur = Evaluateur.objects.get(user=request.user)
474 candidat_ids = [e.candidat.id for e in
475 CandidatEvaluation.objects.filter(evaluateur=evaluateur)]
476 return qs.filter(id__in=candidat_ids)
477 return qs.none()
478
479
480 class ProxyCandidatAdmin(CandidatAdmin):
481 list_editable = ()
482 readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom',
483 'genre', 'nationalite', 'situation_famille',
484 'nombre_dependant', 'telephone', 'email', 'adresse',
485 'ville', 'etat_province', 'code_postal', 'pays',
486 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
487 'domaine_professionnel', 'pieces_jointes',)
488 fieldsets = (
489 ("Offre d'emploi", {
490 'fields': ('offre_emploi', )
491 }),
492 ('Informations personnelles', {
493 'fields': ('prenom','nom','genre', 'nationalite',
494 'situation_famille', 'nombre_dependant',)
495 }),
496 ('Coordonnées', {
497 'fields': ('telephone', 'email', 'adresse', 'ville',
498 'etat_province', 'code_postal', 'pays', )
499 }),
500 ('Informations professionnelles', {
501 'fields': ('niveau_diplome','employeur_actuel',
502 'poste_actuel', 'domaine_professionnel',)
503 }),
504 )
505 inlines = (CandidatEvaluationInline, )
506
507 def has_add_permission(self, request):
508 return False
509
510 def has_delete_permission(self, request, obj=None):
511 return False
512
513 def has_change_permission(self, request, obj=None):
514 user_groupes = request.user.groups.all()
515 if request.user.is_superuser is True or \
516 grp_correspondants_rh_recrutement in user_groupes or \
517 grp_drh_recrutement in user_groupes or \
518 grp_drh2_recrutement in user_groupes or \
519 grp_directeurs_bureau_recrutement in user_groupes or \
520 grp_administrateurs_recrutement in user_groupes or \
521 grp_haute_direction_recrutement in user_groupes:
522 return True
523
524 if obj is not None:
525 evaluateur = Evaluateur.objects.get(user=request.user)
526 for e in obj.evaluations.all():
527 if e.evaluateur == evaluateur:
528 return True
529
530 return False
531
532 def get_actions(self, request):
533 return None
534
535 class CandidatPieceAdmin(admin.ModelAdmin):
536 list_display = ('nom', 'candidat', )
537
538 ### Queryset
539 def queryset(self, request):
540 """
541 Spécifie un queryset limité, autrement Django exécute un
542 select_related() sans paramètre, ce qui a pour effet de charger tous
543 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
544 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
545 génération d'une requête infinie.
546 Affiche la liste de candidats que si le user connecté
547 possède un Evaluateur
548 """
549 qs = self.model._default_manager.get_query_set()
550 return qs.select_related('candidat')
551
552 class EvaluateurAdmin(VersionAdmin):
553 fieldsets = (
554 ("Utilisateur", {
555 'fields': ('user',)
556 }),
557 )
558
559 ### Actions à afficher
560 def get_actions(self, request):
561 actions = super(EvaluateurAdmin, self).get_actions(request)
562 del actions['delete_selected']
563 return actions
564
565 ### Permissions add, delete, change
566 def has_add_permission(self, request):
567 user_groupes = request.user.groups.all()
568 if request.user.is_superuser is True or \
569 grp_drh_recrutement in user_groupes or \
570 grp_drh2_recrutement in user_groupes or \
571 grp_haute_direction_recrutement in user_groupes:
572 return True
573 return False
574
575 def has_delete_permission(self, request, obj=None):
576 user_groupes = request.user.groups.all()
577 if request.user.is_superuser is True or \
578 grp_drh_recrutement in user_groupes or \
579 grp_drh2_recrutement in user_groupes or \
580 grp_haute_direction_recrutement in user_groupes:
581 return True
582 return False
583
584 def has_change_permission(self, request, obj=None):
585 user_groupes = request.user.groups.all()
586 if request.user.is_superuser is True or \
587 grp_drh_recrutement in user_groupes or \
588 grp_drh2_recrutement in user_groupes or \
589 grp_haute_direction_recrutement in user_groupes:
590 return True
591 return False
592
593 class CandidatEvaluationAdmin(admin.ModelAdmin):
594 search_fields = ('candidat__nom', 'candidat__prenom' )
595 list_display = ('_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
596 '_commentaire', )
597 readonly_fields = ('candidat', 'evaluateur')
598 list_filter = ('candidat__statut', 'candidat__offre_emploi',)
599 fieldsets = (
600 ('Évaluation du candidat', {
601 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
602 }),
603 )
604
605 def get_actions(self, request):
606 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
607 try:
608 self.evaluateur = Evaluateur.objects.get(user=request.user)
609 except:
610 self.evaluateur = None
611
612 actions = super(CandidatEvaluationAdmin, self).get_actions(request)
613 del actions['delete_selected']
614 return actions
615
616 ### Afficher la note
617 def _note(self, obj):
618 """
619 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
620 un lien pour Évaluer le candidat.
621 Sinon afficher la note.
622 """
623 page = self.model.__name__.lower()
624 redirect_url = 'admin:recrutement_%s_change' % page
625
626 if obj.note is None:
627 label = "Candidat non évalué"
628 else:
629 label = obj.note
630
631 if self.evaluateur == obj.evaluateur:
632 return "<a href='%s'>%s</a>" % (reverse(redirect_url, args=(obj.id,)), label)
633 else:
634 return label
635 _note.allow_tags = True
636 _note.short_description = "Note"
637 _note.admin_order_field = 'note'
638
639 def _statut(self, obj):
640 return obj.candidat.get_statut_display()
641 _statut.order_field = 'candidat__statut'
642 _statut.short_description = 'Statut'
643
644
645 ### Lien en lecture seule vers le candidat
646 def _candidat(self, obj):
647 return "<a href='%s'>%s</a>" \
648 % (reverse('admin:recrutement_proxycandidat_change',
649 args=(obj.candidat.id,)), obj.candidat)
650 _candidat.allow_tags = True
651 _candidat.short_description = 'Candidat'
652
653 ### Afficher commentaire
654 def _commentaire(self, obj):
655 """
656 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
657 dans le champ commentaire, Aucun au lieu de (None)
658 Sinon afficher la note.
659 """
660 if obj.commentaire is None:
661 return "Aucun"
662 return obj.commentaire
663 _commentaire.allow_tags = True
664 _commentaire.short_description = "Commentaire"
665
666 ### Afficher offre d'emploi
667 def _offre_emploi(self, obj):
668 return "<a href='%s'>%s</a>" % \
669 (reverse('admin:recrutement_proxyoffreemploi_change',
670 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
671 _offre_emploi.allow_tags = True
672 _offre_emploi.short_description = "Voir offre d'emploi"
673
674 def has_add_permission(self, request):
675 return False
676
677 def has_delete_permission(self, request, obj=None):
678 return False
679
680 def has_change_permission(self, request, obj=None):
681 """
682 Permettre la visualisation dans la changelist
683 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
684 le request.user
685 """
686 user_groupes = request.user.groups.all()
687
688 if request.user.is_superuser or \
689 grp_drh_recrutement in user_groupes or \
690 grp_drh2_recrutement in user_groupes or \
691 grp_correspondants_rh_recrutement in user_groupes or \
692 grp_directeurs_bureau_recrutement in user_groupes or \
693 grp_administrateurs_recrutement in user_groupes or \
694 grp_haute_direction_recrutement in user_groupes:
695 is_recrutement = True
696 else:
697 is_recrutement = False
698
699 return is_recrutement
700
701 def queryset(self, request):
702 """
703 Afficher uniquement les évaluations de l'évaluateur, sauf si
704 l'utilisateur est dans les groupes suivants.
705 """
706 qs = self.model._default_manager.get_query_set().select_related('offre_emploi')
707 user_groupes = request.user.groups.all()
708
709 if grp_drh_recrutement in user_groupes or \
710 grp_drh2_recrutement in user_groupes or \
711 grp_correspondants_rh_recrutement in user_groupes or \
712 grp_directeurs_bureau_recrutement in user_groupes or \
713 grp_administrateurs_recrutement in user_groupes or \
714 grp_haute_direction_recrutement in user_groupes:
715 return qs
716
717 evaluateur = Evaluateur.objects.get(user=request.user)
718 candidats_evaluations = \
719 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
720 candidat__statut__in=('REC', ))
721 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
722 return qs.filter(id__in=candidats_evaluations_ids)
723
724
725 class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin):
726
727 def has_change_permission(self, request, obj=None):
728 try:
729 Evaluateur.objects.get(user=request.user)
730 is_evaluateur = True
731 except:
732 is_evaluateur = False
733
734 if obj is None and is_evaluateur:
735 return True
736
737 try:
738 return request.user == obj.evaluateur.user
739 except:
740 return False
741
742 def queryset(self, request):
743 qs = self.model._default_manager.get_query_set().select_related('offre_emploi')
744 evaluateur = Evaluateur.objects.get(user=request.user)
745 candidats_evaluations = \
746 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
747 candidat__statut__in=('REC', ))
748 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
749 return qs.filter(id__in=candidats_evaluations_ids)
750
751
752 class CourrielTemplateAdmin(VersionAdmin):
753 ### Actions à afficher
754 def get_actions(self, request):
755 actions = super(CourrielTemplateAdmin, self).get_actions(request)
756 del actions['delete_selected']
757 return actions
758
759 admin.site.register(OffreEmploi, OffreEmploiAdmin)
760 admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
761 admin.site.register(Candidat, CandidatAdmin)
762 admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
763 admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
764 admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin)
765 admin.site.register(Evaluateur, EvaluateurAdmin)
766 admin.site.register(CourrielTemplate, CourrielTemplateAdmin)