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