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