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