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