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