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