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