[#3255] limiter le lieu d'affectation d'une offre d'emploi en fonction de région
[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, Implantation
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:emploi_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 def formfield_for_foreignkey(self, db_field, request, **kwargs):
209 if db_field.name == 'lieu_affectation':
210 employe = get_emp(request.user)
211 kwargs["queryset"] = Implantation.objects.filter(region=employe.implantation.region)
212 return db_field.formfield(**kwargs)
213 return super(OffreEmploiAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
214
215
216 class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
217 list_display = (
218 'nom', 'date_limite', 'region', 'statut', 'est_affiche'
219 )
220 readonly_fields = (
221 'description', 'bureau', 'duree_affectation', 'renumeration',
222 'debut_affectation', 'lieu_affectation', 'nom', 'resume',
223 'date_limite', 'region', 'poste'
224 )
225 fieldsets = (
226 ('Nom', {
227 'fields': ('nom',)
228 }),
229 ('Description générale', {
230 'fields': ('description', 'date_limite',)
231 }),
232 ('Coordonnées', {
233 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
234 }),
235 ('Autre', {
236 'fields': (
237 'debut_affectation', 'duree_affectation', 'renumeration',
238 )
239 }),
240 )
241 inlines = []
242
243 ### Lieu de redirection après le change
244 def response_change(self, request, obj):
245 return redirect('admin:recrutement_proxyoffreemploi_changelist')
246
247 ### Formulaire
248 def get_form(self, request, obj=None, **kwargs):
249 form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs)
250 return form
251
252 ### Permissions add, delete, change
253 def has_add_permission(self, request):
254 return False
255
256 def has_delete_permission(self, request, obj=None):
257 return False
258
259 def has_change_permission(self, request, obj=None):
260 if obj is not None:
261 return True
262
263 return not super(ProxyOffreEmploiAdmin, self).has_change_permission(request, obj)
264
265
266 class CandidatPieceInline(admin.TabularInline):
267 model = CandidatPiece
268 fields = ('candidat', 'nom', 'path',)
269 extra = 1
270 max_num = 3
271
272
273 class ReadOnlyCandidatPieceInline(CandidatPieceInline):
274 readonly_fields = ('candidat', 'nom', 'path', )
275 cand_delete = False
276
277
278 class CandidatEvaluationInlineFormSet(BaseInlineFormSet):
279 """
280 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
281 """
282 def __init__(self, *args, **kwargs):
283 super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs)
284 self.can_delete = False
285
286
287 class CandidatEvaluationInline(admin.TabularInline):
288 model = CandidatEvaluation
289 fields = ('evaluateur', 'note', 'commentaire')
290 max_num = 0
291 extra = 0
292 formset = CandidatEvaluationInlineFormSet
293
294 ### Fields readonly
295 def get_readonly_fields(self, request, obj=None):
296 """
297 Empêche la modification des évaluations
298 """
299 if obj:
300 return self.readonly_fields + ('evaluateur', 'note', 'commentaire')
301 return self.readonly_fields
302
303 class CandidatAdmin(BaseAdmin, VersionAdmin, ExportAdmin):
304 change_list_template = 'admin/recrutement/candidat/change_list.html'
305 search_fields = ('nom', 'prenom')
306 exclude = ('actif', )
307 list_editable = ('statut', )
308 list_display = ('_candidat', 'offre_emploi',
309 'voir_offre_emploi', 'calculer_moyenne',
310 'afficher_candidat', '_date_creation', 'statut', )
311 list_filter = ('offre_emploi__nom', 'offre_emploi__region', 'statut', )
312
313 fieldsets = (
314 ("Offre d'emploi", {
315 'fields': ('offre_emploi', )
316 }),
317 ('Informations personnelles', {
318 'fields': (
319 'prenom', 'nom', 'genre', 'nationalite',
320 'situation_famille', 'nombre_dependant'
321 )
322 }),
323 ('Coordonnées', {
324 'fields': (
325 'telephone', 'email', 'adresse', 'ville', 'etat_province',
326 'code_postal', 'pays'
327 )
328 }),
329 ('Informations professionnelles', {
330 'fields': (
331 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
332 'domaine_professionnel'
333 )
334 }),
335 ('Traitement', {
336 'fields': ('statut', )
337 }),
338 )
339 inlines = [
340 CandidatPieceInline,
341 CandidatEvaluationInline,
342 ]
343 actions = ['envoyer_courriel_candidats', 'changer_statut']
344
345 export_fields = ['statut', 'offre_emploi', 'prenom', 'nom', 'genre',
346 'nationalite', 'situation_famille', 'nombre_dependant',
347 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
348 'domaine_professionnel', 'telephone', 'email', 'adresse',
349 'ville', 'etat_province', 'code_postal', 'pays']
350
351 def _candidat(self, obj):
352 txt = u"%s %s (%s)" % (obj.nom.upper(), obj.prenom, obj.genre)
353 txt = textwrap.wrap(txt, 30)
354 return "<br/>".join(txt)
355 _candidat.short_description = "Candidat"
356 _candidat.admin_order_field = "nom"
357 _candidat.allow_tags = True
358
359 def _date_creation(self, obj):
360 return obj.date_creation
361 _date_creation.admin_order_field = "date_creation"
362 _date_creation.short_description = "Date de réception"
363
364 ### Actions à afficher
365 def get_actions(self, request):
366 actions = super(CandidatAdmin, self).get_actions(request)
367 del actions['delete_selected']
368 return actions
369
370 ### Envoyer un courriel à des candidats
371 def envoyer_courriel_candidats(modeladmin, obj, candidats):
372 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
373
374 return HttpResponseRedirect(
375 reverse('selectionner_template') + "?ids=%s" % (",".join(selected))
376 )
377 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
378
379 ### Changer le statut à des candidats
380 def changer_statut(modeladmin, request, queryset):
381 if request.POST.get('post'):
382 queryset.update(statut=request.POST.get('statut'))
383 return None
384
385 context = {
386 'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
387 'queryset': queryset,
388 'status': STATUT_CHOICES,
389 }
390
391 return render_to_response("recrutement/selectionner_statut.html",
392 context, context_instance = RequestContext(request))
393
394 changer_statut.short_description = u'Changer statut'
395
396 ### Évaluer un candidat
397 def evaluer_candidat(self, obj):
398 return "<a href='%s?candidat__id__exact=%s'>" \
399 "Évaluer le candidat</a>" % (
400 reverse('admin:recrutement_candidatevaluation_changelist'),
401 obj.id
402 )
403 evaluer_candidat.allow_tags = True
404 evaluer_candidat.short_description = 'Évaluation'
405
406 ### Afficher un candidat
407 def afficher_candidat(self, obj):
408 items = [u"<li><a href='%s%s'>%s</li>" % \
409 (settings.OE_PRIVE_MEDIA_URL, pj.path, pj.get_nom_display()) \
410 for pj in obj.pieces_jointes()]
411 html = "<a href='%s'>Candidature</a>" % (
412 reverse('admin:recrutement_proxycandidat_change', args=(obj.id,))
413 )
414 return "%s<ul>%s</ul>" % (html, "\n".join(items))
415 afficher_candidat.allow_tags = True
416 afficher_candidat.short_description = u'Détails du candidat'
417
418 ### Voir l'offre d'emploi
419 def voir_offre_emploi(self, obj):
420 return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse(
421 'admin:recrutement_proxyoffreemploi_change',
422 args=(obj.offre_emploi.id,)
423 ))
424 voir_offre_emploi.allow_tags = True
425 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
426
427 ### Calculer la moyenne des notes
428 def calculer_moyenne(self, obj):
429 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
430
431 notes = [evaluation.note for evaluation in evaluations \
432 if evaluation.note is not None]
433
434 if len(notes) > 0:
435 moyenne_votes = round(float(sum(notes)) / len(notes), 2)
436 else:
437 moyenne_votes = "Non disponible"
438
439 totales = len(evaluations)
440 faites = len(notes)
441
442 if obj.statut == 'REC':
443 if totales == faites:
444 color = "green"
445 elif faites > 0 and float(totales) / float(faites) >= 2:
446 color = "orange"
447 else:
448 color = "red"
449 else:
450 color = "black"
451
452 return """<span style="color: %s;">%s (%s/%s)</span>""" % (
453 color, moyenne_votes, faites, totales
454 )
455 calculer_moyenne.allow_tags = True
456 calculer_moyenne.short_description = "Moyenne"
457 calculer_moyenne.admin_order_field = ""
458
459 ### Permissions add, delete, change
460 def has_add_permission(self, request):
461 user_groupes = request.user.groups.all()
462 if request.user.is_superuser is True or \
463 grp_correspondants_rh in user_groupes or \
464 grp_drh in user_groupes or \
465 grp_drh2 in user_groupes or \
466 grp_directeurs_bureau in user_groupes or \
467 grp_administrateurs in user_groupes or \
468 grp_haute_direction in user_groupes:
469 return True
470 return False
471
472 def has_delete_permission(self, request, obj=None):
473 user_groupes = request.user.groups.all()
474 if request.user.is_superuser is True or \
475 grp_correspondants_rh in user_groupes or \
476 grp_drh in user_groupes or \
477 grp_drh2 in user_groupes or \
478 grp_directeurs_bureau in user_groupes or \
479 grp_administrateurs in user_groupes or \
480 grp_haute_direction in user_groupes:
481 return True
482 return False
483
484 def has_change_permission(self, request, obj=None):
485 user_groupes = request.user.groups.all()
486 if request.user.is_superuser is True or \
487 grp_correspondants_rh in user_groupes or \
488 grp_drh in user_groupes or \
489 grp_drh2 in user_groupes or \
490 grp_directeurs_bureau in user_groupes or \
491 grp_administrateurs in user_groupes or \
492 grp_haute_direction in user_groupes:
493 return True
494 return False
495
496 def formfield_for_foreignkey(self, db_field, request, **kwargs):
497 if db_field.name == 'offre_emploi':
498 employe = get_emp(request.user)
499 kwargs["queryset"] = OffreEmploi.objects.filter(region=employe.implantation.region)
500 return db_field.formfield(**kwargs)
501 return super(CandidatAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
502
503 def get_changelist(self, request, **kwargs):
504 return OrderedChangeList
505
506 def queryset(self, request):
507 """
508 Spécifie un queryset limité, autrement Django exécute un
509 select_related() sans paramètre, ce qui a pour effet de charger tous
510 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
511 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
512 génération d'une requête infinie.
513 """
514 qs = self.model._default_manager.get_query_set() \
515 .select_related('offre_emploi') \
516 .annotate(moyenne=Avg('evaluations__note'))
517
518 user_groupes = request.user.groups.all()
519 if grp_drh in user_groupes or \
520 grp_drh2 in user_groupes or \
521 grp_haute_direction in user_groupes:
522 return qs
523
524 if grp_directeurs_bureau in user_groupes or \
525 grp_correspondants_rh in user_groupes or \
526 grp_administrateurs in user_groupes:
527 employe = get_emp(request.user)
528 return qs.filter(offre_emploi__region=employe.implantation.region)
529
530 if Evaluateur.objects.filter(user=request.user).exists():
531 evaluateur = Evaluateur.objects.get(user=request.user)
532 candidat_ids = [e.candidat.id for e in
533 CandidatEvaluation.objects.filter(evaluateur=evaluateur)]
534 return qs.filter(id__in=candidat_ids)
535 return qs.none()
536
537
538 class ProxyCandidatAdmin(CandidatAdmin):
539 list_editable = ()
540 readonly_fields = (
541 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
542 'situation_famille', 'nombre_dependant', 'telephone', 'email',
543 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
544 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
545 'domaine_professionnel', 'pieces_jointes'
546 )
547 fieldsets = (
548 ("Offre d'emploi", {
549 'fields': ('offre_emploi', )
550 }),
551 ('Informations personnelles', {
552 'fields': (
553 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille',
554 'nombre_dependant'
555 )
556 }),
557 ('Coordonnées', {
558 'fields': (
559 'telephone', 'email', 'adresse', 'ville', 'etat_province',
560 'code_postal', 'pays'
561 )
562 }),
563 ('Informations professionnelles', {
564 'fields': (
565 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
566 'domaine_professionnel'
567 )
568 }),
569 )
570 inlines = (CandidatEvaluationInline, )
571
572 def has_add_permission(self, request):
573 return False
574
575 def has_delete_permission(self, request, obj=None):
576 return False
577
578 def has_change_permission(self, request, obj=None):
579 if obj is not None:
580 evaluateur = Evaluateur.objects.get(user=request.user)
581 for e in obj.evaluations.all():
582 if e.evaluateur == evaluateur:
583 return True
584
585 return not super(ProxyCandidatAdmin, self).has_change_permission(request, obj)
586
587 def get_actions(self, request):
588 return None
589
590
591 class CandidatPieceAdmin(admin.ModelAdmin):
592 list_display = ('nom', 'candidat', )
593
594 ### Queryset
595 def queryset(self, request):
596 """
597 Spécifie un queryset limité, autrement Django exécute un
598 select_related() sans paramètre, ce qui a pour effet de charger tous
599 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
600 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
601 génération d'une requête infinie. Affiche la liste de candidats que
602 si le user connecté possède un Evaluateur
603 """
604 qs = self.model._default_manager.get_query_set()
605 return qs.select_related('candidat')
606
607
608 class EvaluateurAdmin(BaseAdmin, VersionAdmin):
609 fieldsets = (
610 ("Utilisateur", {
611 'fields': ('user',)
612 }),
613 )
614
615 ### Actions à afficher
616 def get_actions(self, request):
617 actions = super(EvaluateurAdmin, self).get_actions(request)
618 del actions['delete_selected']
619 return actions
620
621 ### Permissions add, delete, change
622 def has_add_permission(self, request):
623 user_groupes = request.user.groups.all()
624 if request.user.is_superuser is True or \
625 grp_drh in user_groupes or \
626 grp_drh2 in user_groupes or \
627 grp_haute_direction in user_groupes:
628 return True
629 return False
630
631 def has_delete_permission(self, request, obj=None):
632 user_groupes = request.user.groups.all()
633 if request.user.is_superuser is True or \
634 grp_drh in user_groupes or \
635 grp_drh2 in user_groupes or \
636 grp_haute_direction in user_groupes:
637 return True
638 return False
639
640 def has_change_permission(self, request, obj=None):
641 user_groupes = request.user.groups.all()
642 if request.user.is_superuser is True or \
643 grp_drh in user_groupes or \
644 grp_drh2 in user_groupes or \
645 grp_haute_direction in user_groupes:
646 return True
647 return False
648
649
650 class CandidatEvaluationAdmin(BaseAdmin):
651 search_fields = ('candidat__nom', 'candidat__prenom')
652 list_display = (
653 '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
654 '_commentaire'
655 )
656 readonly_fields = ('candidat', 'evaluateur')
657 list_filter = ('candidat__statut', 'candidat__offre_emploi',)
658 fieldsets = (
659 ('Évaluation du candidat', {
660 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
661 }),
662 )
663
664 def get_actions(self, request):
665 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
666 try:
667 self.evaluateur = Evaluateur.objects.get(user=request.user)
668 except:
669 self.evaluateur = None
670
671 actions = super(CandidatEvaluationAdmin, self).get_actions(request)
672 del actions['delete_selected']
673 return actions
674
675 ### Afficher la note
676 def _note(self, obj):
677 """
678 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
679 un lien pour Évaluer le candidat.
680 Sinon afficher la note.
681 """
682 page = self.model.__name__.lower()
683 redirect_url = 'admin:recrutement_%s_change' % page
684
685 if obj.note is None:
686 label = "Candidat non évalué"
687 else:
688 label = obj.note
689
690 if self.evaluateur == obj.evaluateur:
691 return "<a href='%s'>%s</a>" % (
692 reverse(redirect_url, args=(obj.id,)), label
693 )
694 else:
695 return label
696 _note.allow_tags = True
697 _note.short_description = "Note"
698 _note.admin_order_field = 'note'
699
700 def _statut(self, obj):
701 return obj.candidat.get_statut_display()
702 _statut.order_field = 'candidat__statut'
703 _statut.short_description = 'Statut'
704
705 ### Lien en lecture seule vers le candidat
706 def _candidat(self, obj):
707 return "<a href='%s'>%s</a>" \
708 % (reverse('admin:recrutement_proxycandidat_change',
709 args=(obj.candidat.id,)), obj.candidat)
710 _candidat.allow_tags = True
711 _candidat.short_description = 'Candidat'
712
713 ### Afficher commentaire
714 def _commentaire(self, obj):
715 """
716 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
717 dans le champ commentaire, Aucun au lieu de (None)
718 Sinon afficher la note.
719 """
720 if obj.commentaire is None:
721 return "Aucun"
722 return obj.commentaire
723 _commentaire.allow_tags = True
724 _commentaire.short_description = "Commentaire"
725
726 ### Afficher offre d'emploi
727 def _offre_emploi(self, obj):
728 return "<a href='%s'>%s</a>" % \
729 (reverse('admin:recrutement_proxyoffreemploi_change',
730 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
731 _offre_emploi.allow_tags = True
732 _offre_emploi.short_description = "Voir offre d'emploi"
733
734 def has_add_permission(self, request):
735 return False
736
737 def has_delete_permission(self, request, obj=None):
738 return False
739
740 def has_change_permission(self, request, obj=None):
741 """
742 Permettre la visualisation dans la changelist
743 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
744 le request.user
745 """
746 user_groupes = request.user.groups.all()
747
748 if request.user.is_superuser or \
749 grp_drh in user_groupes or \
750 grp_drh2 in user_groupes or \
751 grp_correspondants_rh in user_groupes or \
752 grp_directeurs_bureau in user_groupes or \
753 grp_administrateurs in user_groupes or \
754 grp_haute_direction in user_groupes:
755 is_recrutement = True
756 else:
757 is_recrutement = False
758
759 return is_recrutement
760
761 def queryset(self, request):
762 """
763 Afficher uniquement les évaluations de l'évaluateur, sauf si
764 l'utilisateur est dans les groupes suivants.
765 """
766 qs = self.model._default_manager.get_query_set() \
767 .select_related('offre_emploi')
768 user_groupes = request.user.groups.all()
769
770 if grp_drh in user_groupes or \
771 grp_drh2 in user_groupes or \
772 grp_correspondants_rh in user_groupes or \
773 grp_directeurs_bureau in user_groupes or \
774 grp_administrateurs in user_groupes or \
775 grp_haute_direction in user_groupes:
776 return qs.filter(candidat__statut__in=('REC', 'SEL'))
777
778 evaluateur = Evaluateur.objects.get(user=request.user)
779 candidats_evaluations = \
780 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
781 candidat__statut__in=('REC', ))
782 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
783 return qs.filter(id__in=candidats_evaluations_ids)
784
785
786 class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin):
787 list_filter = []
788
789 def has_change_permission(self, request, obj=None):
790 try:
791 Evaluateur.objects.get(user=request.user)
792 is_evaluateur = True
793 except:
794 is_evaluateur = False
795
796 if obj is None and is_evaluateur:
797 return True
798
799 try:
800 return request.user == obj.evaluateur.user
801 except:
802 return False
803
804 def queryset(self, request):
805 qs = self.model._default_manager.get_query_set() \
806 .select_related('offre_emploi')
807 evaluateur = Evaluateur.objects.get(user=request.user)
808 candidats_evaluations = \
809 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
810 candidat__statut__in=('REC', ))
811 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
812 return qs.filter(id__in=candidats_evaluations_ids)
813
814
815 class CourrielTemplateAdmin(BaseAdmin, VersionAdmin):
816 ### Actions à afficher
817 def get_actions(self, request):
818 actions = super(CourrielTemplateAdmin, self).get_actions(request)
819 del actions['delete_selected']
820 return actions
821
822 admin.site.register(OffreEmploi, OffreEmploiAdmin)
823 admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
824 admin.site.register(Candidat, CandidatAdmin)
825 admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
826 admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
827 admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin)
828 admin.site.register(Evaluateur, EvaluateurAdmin)
829 admin.site.register(CourrielTemplate, CourrielTemplateAdmin)