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