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