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