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