1 # -*- encoding: utf-8 -*-
5 from auf
.django
.emploi
.models
import OffreEmploi
, Candidat
, CandidatPiece
6 from auf
.django
.references
.models
import Region
, Bureau
, Implantation
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
.shortcuts
import render_to_response
12 from django
.template
import RequestContext
14 from auf
.django
.export
.admin
import ExportAdmin
15 from auf
.django
.emploi
.models
import STATUT_CHOICES
16 from django
.forms
.models
import BaseInlineFormSet
17 from django
.http
import HttpResponseRedirect
18 from django
.shortcuts
import redirect
19 from reversion
.admin
import VersionAdmin
21 from project
import groups
23 from project
.rh
import models
as rh
24 from project
.recrutement
.forms
import OffreEmploiForm
25 from project
.recrutement
.models
import \
26 Evaluateur
, CandidatEvaluation
, \
27 ProxyOffreEmploi
, ProxyCandidat
, MesCandidatEvaluation
, \
31 IMPLANTATIONS_CENTRALES
= [15, 19]
34 class BaseAdmin(admin
.ModelAdmin
):
38 'css/admin_custom.css',
39 'jquery-autocomplete/jquery.autocomplete.css',
42 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
43 'jquery-autocomplete/jquery.autocomplete.min.js',
47 class OrderedChangeList(admin
.views
.main
.ChangeList
):
49 Surcharge pour appliquer le order_by d'un annotate
51 def get_query_set(self
):
52 qs
= super(OrderedChangeList
, self
).get_query_set()
53 qs
= qs
.order_by('-moyenne')
57 class OffreEmploiAdminMixin(BaseAdmin
):
58 date_hierarchy
= 'date_creation'
60 'nom', 'date_limite', 'region', 'statut', 'est_affiche',
63 exclude
= ('actif', 'poste_nom', 'resume',)
64 list_filter
= ('statut',)
65 actions
= ['affecter_evaluateurs_offre_emploi', ]
66 form
= OffreEmploiForm
86 ### Actions à afficher
87 def get_actions(self
, request
):
88 actions
= super(OffreEmploiAdminMixin
, self
).get_actions(request
)
89 del actions
['delete_selected']
92 ### Affecter un évaluateurs à des offres d'emploi
93 def affecter_evaluateurs_offre_emploi(modeladmin
, obj
, candidats
):
94 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
96 return HttpResponseRedirect(
97 reverse('affecter_evaluateurs_offre_emploi') +
98 "?ids=%s" % (",".join(selected
))
101 affecter_evaluateurs_offre_emploi
.short_description
= \
102 u
'Affecter évaluateur(s)'
104 ### Afficher la liste des candidats pour l'offre d'emploi
105 def _candidatsList(self
, obj
):
106 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
107 </a>" % (reverse('admin:emploi_candidat_changelist'), obj
.id)
108 _candidatsList
.allow_tags
= True
109 _candidatsList
.short_description
= "Afficher la liste des candidats"
112 def get_form(self
, request
, obj
=None, **kwargs
):
113 form
= super(OffreEmploiAdminMixin
, self
).get_form(request
, obj
, **kwargs
)
114 employe
= groups
.get_employe_from_user(request
.user
)
115 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
118 if 'region' in form
.declared_fields
:
119 region_field
= form
.declared_fields
['region']
121 region_field
= form
.base_fields
['region']
123 if groups
.DRH_NIVEAU_1
in user_groupes
or \
124 groups
.DRH_NIVEAU_2
in user_groupes
or \
125 groups
.HAUTE_DIRECTION
in user_groupes
:
126 region_field
.queryset
= Region
.objects
.all()
128 region_field
.queryset
= Region
.objects
.\
129 filter(id=employe
.implantation
.region
.id)
132 if 'poste' in form
.declared_fields
:
133 poste_field
= form
.declared_fields
['poste']
135 poste_field
= form
.base_fields
['poste']
137 if groups
.DRH_NIVEAU_1
in user_groupes
or \
138 groups
.DRH_NIVEAU_2
in user_groupes
or \
139 groups
.HAUTE_DIRECTION
in user_groupes
:
140 poste_field
.queryset
= rh
.Poste
.objects
.all()
142 poste_field
.queryset
= rh
.Poste
.objects
.\
143 filter(implantation__region
=employe
.implantation
.region
).\
144 exclude(implantation__in
=IMPLANTATIONS_CENTRALES
)
147 if 'bureau' in form
.declared_fields
:
148 bureau_field
= form
.declared_fields
['bureau']
150 bureau_field
= form
.base_fields
['bureau']
152 if groups
.DRH_NIVEAU_1
in user_groupes
or \
153 groups
.DRH_NIVEAU_2
in user_groupes
or \
154 groups
.HAUTE_DIRECTION
in user_groupes
:
155 bureau_field
.queryset
= Bureau
.objects
.all()
157 bureau_field
.queryset
= \
158 Bureau
.objects
.filter(region
=employe
.implantation
.region
)
164 def queryset(self
, request
):
165 qs
= self
.model
._default_manager
.get_query_set() \
166 .select_related('offre_emploi')
167 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
168 if groups
.DRH_NIVEAU_1
in user_groupes
or \
169 groups
.DRH_NIVEAU_2
in user_groupes
or \
170 groups
.HAUTE_DIRECTION
in user_groupes
:
173 if groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
174 groups
.CORRESPONDANT_RH
in user_groupes
or \
175 groups
.ADMINISTRATEURS
in user_groupes
:
176 employe
= groups
.get_employe_from_user(request
.user
)
177 return qs
.filter(region
=employe
.implantation
.region
)
179 if Evaluateur
.objects
.filter(user
=request
.user
).exists():
180 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
182 e
.candidat
.offre_emploi_id
183 for e
in CandidatEvaluation
.objects
184 .select_related('candidat')
185 .filter(evaluateur
=evaluateur
)
187 return qs
.filter(id__in
=offre_ids
)
191 ### Permission add, delete, change
192 def has_add_permission(self
, request
):
193 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
194 if request
.user
.is_superuser
is True or \
195 groups
.DRH_NIVEAU_1
in user_groupes
or \
196 groups
.DRH_NIVEAU_2
in user_groupes
or \
197 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
198 groups
.ADMINISTRATEURS
in user_groupes
or \
199 groups
.HAUTE_DIRECTION
in user_groupes
:
203 def has_delete_permission(self
, request
, obj
=None):
204 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
205 if request
.user
.is_superuser
is True or \
206 groups
.DRH_NIVEAU_1
in user_groupes
or \
207 groups
.DRH_NIVEAU_2
in user_groupes
or \
208 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
209 groups
.ADMINISTRATEURS
in user_groupes
or \
210 groups
.HAUTE_DIRECTION
in user_groupes
:
214 def has_change_permission(self
, request
, obj
=None):
215 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
216 if request
.user
.is_superuser
is True or \
217 groups
.DRH_NIVEAU_1
in user_groupes
or \
218 groups
.DRH_NIVEAU_2
in user_groupes
or \
219 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
220 groups
.ADMINISTRATEURS
in user_groupes
or \
221 groups
.HAUTE_DIRECTION
in user_groupes
:
225 def formfield_for_foreignkey(self
, db_field
, request
, **kwargs
):
226 if db_field
.name
== 'lieu_affectation':
227 employe
= groups
.get_employe_from_user(request
.user
)
228 kwargs
["queryset"] = Implantation
.objects
.filter(region
=employe
.implantation
.region
)
229 return db_field
.formfield(**kwargs
)
230 return super(OffreEmploiAdminMixin
, self
).formfield_for_foreignkey(db_field
, request
, **kwargs
)
233 class OffreEmploiAdmin(VersionAdmin
, OffreEmploiAdminMixin
):
237 class ProxyOffreEmploiAdmin(OffreEmploiAdminMixin
):
239 'nom', 'date_limite', 'region', 'statut', 'est_affiche'
242 'description', 'bureau', 'duree_affectation', 'renumeration',
243 'debut_affectation', 'lieu_affectation', 'nom', 'resume',
244 'date_limite', 'region', 'poste'
250 ('Description générale', {
251 'fields': ('description', 'date_limite',)
254 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
258 'debut_affectation', 'duree_affectation', 'renumeration',
264 ### Lieu de redirection après le change
265 def response_change(self
, request
, obj
):
266 return redirect('admin:recrutement_proxyoffreemploi_changelist')
269 def get_form(self
, request
, obj
=None, **kwargs
):
270 form
= super(OffreEmploiAdmin
, self
).get_form(request
, obj
, **kwargs
)
273 ### Permissions add, delete, change
274 def has_add_permission(self
, request
):
277 def has_delete_permission(self
, request
, obj
=None):
280 def has_change_permission(self
, request
, obj
=None):
284 return not super(ProxyOffreEmploiAdmin
, self
).has_change_permission(request
, obj
)
287 class CandidatPieceInline(admin
.TabularInline
):
288 model
= CandidatPiece
289 fields
= ('candidat', 'nom', 'path',)
294 class ReadOnlyCandidatPieceInline(CandidatPieceInline
):
295 readonly_fields
= ('candidat', 'nom', 'path', )
299 class CandidatEvaluationInlineFormSet(BaseInlineFormSet
):
301 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
303 def __init__(self
, *args
, **kwargs
):
304 super(CandidatEvaluationInlineFormSet
, self
).__init__(*args
, **kwargs
)
305 self
.can_delete
= False
308 class CandidatEvaluationInline(admin
.TabularInline
):
309 model
= CandidatEvaluation
310 fields
= ('evaluateur', 'note', 'commentaire')
313 formset
= CandidatEvaluationInlineFormSet
316 def get_readonly_fields(self
, request
, obj
=None):
318 Empêche la modification des évaluations
321 return self
.readonly_fields
+ ('evaluateur', 'note', 'commentaire')
322 return self
.readonly_fields
325 class CandidatAdminMixin(BaseAdmin
, ExportAdmin
):
326 search_fields
= ('nom', 'prenom')
327 exclude
= ('actif', )
328 list_editable
= ('statut', )
329 list_display
= ('_candidat', 'offre_emploi',
330 'voir_offre_emploi', 'calculer_moyenne',
331 'afficher_candidat', '_date_creation', 'statut', )
332 list_filter
= ('offre_emploi__nom', 'offre_emploi__region', 'statut', )
336 'fields': ('offre_emploi', )
338 ('Informations personnelles', {
340 'nom', 'prenom', 'genre', 'nationalite',
341 'situation_famille', 'nombre_dependant'
346 'telephone', 'email', 'adresse', 'ville', 'etat_province',
347 'code_postal', 'pays'
350 ('Informations professionnelles', {
352 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
353 'domaine_professionnel'
357 'fields': ('statut', )
362 CandidatEvaluationInline
,
364 actions
= ['envoyer_courriel_candidats', 'changer_statut']
366 export_fields
= ['statut', 'offre_emploi', 'prenom', 'nom', 'genre',
367 'nationalite', 'situation_famille', 'nombre_dependant',
368 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
369 'domaine_professionnel', 'telephone', 'email', 'adresse',
370 'ville', 'etat_province', 'code_postal', 'pays']
372 def _candidat(self
, obj
):
373 txt
= u
"%s %s (%s)" % (obj
.nom
.upper(), obj
.prenom
, obj
.genre
)
374 txt
= textwrap
.wrap(txt
, 30)
375 return "<br/>".join(txt
)
376 _candidat
.short_description
= "Candidat"
377 _candidat
.admin_order_field
= "nom"
378 _candidat
.allow_tags
= True
380 def _date_creation(self
, obj
):
381 return obj
.date_creation
382 _date_creation
.admin_order_field
= "date_creation"
383 _date_creation
.short_description
= "Date de réception"
385 ### Actions à afficher
386 def get_actions(self
, request
):
387 actions
= super(CandidatAdminMixin
, self
).get_actions(request
)
388 del actions
['delete_selected']
391 ### Envoyer un courriel à des candidats
392 def envoyer_courriel_candidats(modeladmin
, obj
, candidats
):
393 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
395 return HttpResponseRedirect(
396 reverse('selectionner_template') + "?ids=%s" % (",".join(selected
))
398 envoyer_courriel_candidats
.short_description
= u
'Envoyer courriel'
400 ### Changer le statut à des candidats
401 def changer_statut(modeladmin
, request
, queryset
):
402 if request
.POST
.get('post'):
403 queryset
.update(statut
=request
.POST
.get('statut'))
407 'action_checkbox_name': admin
.helpers
.ACTION_CHECKBOX_NAME
,
408 'queryset': queryset
,
409 'status': STATUT_CHOICES
,
412 return render_to_response("recrutement/selectionner_statut.html",
413 context
, context_instance
= RequestContext(request
))
415 changer_statut
.short_description
= u
'Changer statut'
417 ### Évaluer un candidat
418 def evaluer_candidat(self
, obj
):
419 return "<a href='%s?candidat__id__exact=%s'>" \
420 "Évaluer le candidat</a>" % (
421 reverse('admin:recrutement_candidatevaluation_changelist'),
424 evaluer_candidat
.allow_tags
= True
425 evaluer_candidat
.short_description
= 'Évaluation'
427 ### Afficher un candidat
428 def afficher_candidat(self
, obj
):
429 items
= [u
"<li><a href='%s%s'>%s</li>" % \
430 (settings
.OE_PRIVE_MEDIA_URL
, pj
.path
, pj
.get_nom_display()) \
431 for pj
in obj
.pieces_jointes()]
432 html
= "<a href='%s'>Candidature</a>" % (
433 reverse('admin:recrutement_proxycandidat_change', args
=(obj
.id,))
435 return "%s<ul>%s</ul>" % (html
, "\n".join(items
))
436 afficher_candidat
.allow_tags
= True
437 afficher_candidat
.short_description
= u
'Détails du candidat'
439 ### Voir l'offre d'emploi
440 def voir_offre_emploi(self
, obj
):
441 return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse(
442 'admin:recrutement_proxyoffreemploi_change',
443 args
=(obj
.offre_emploi
.id,)
445 voir_offre_emploi
.allow_tags
= True
446 voir_offre_emploi
.short_description
= "Afficher l'offre d'emploi"
448 ### Calculer la moyenne des notes
449 def calculer_moyenne(self
, obj
):
450 evaluations
= CandidatEvaluation
.objects
.filter(candidat
=obj
)
452 notes
= [evaluation
.note
for evaluation
in evaluations \
453 if evaluation
.note
is not None]
456 moyenne_votes
= round(float(sum(notes
)) / len(notes
), 2)
458 moyenne_votes
= "Non disponible"
460 totales
= len(evaluations
)
463 if obj
.statut
== 'REC':
464 if totales
== faites
:
466 elif faites
> 0 and float(totales
) / float(faites
) >= 2:
473 return """<span style="color: %s;">%s (%s/%s)</span>""" % (
474 color
, moyenne_votes
, faites
, totales
476 calculer_moyenne
.allow_tags
= True
477 calculer_moyenne
.short_description
= "Moyenne"
478 calculer_moyenne
.admin_order_field
= ""
480 ### Permissions add, delete, change
481 def has_add_permission(self
, request
):
482 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
483 if request
.user
.is_superuser
is True or \
484 groups
.CORRESPONDANT_RH
in user_groupes
or \
485 groups
.DRH_NIVEAU_1
in user_groupes
or \
486 groups
.DRH_NIVEAU_2
in user_groupes
or \
487 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
488 groups
.ADMINISTRATEURS
in user_groupes
or \
489 groups
.HAUTE_DIRECTION
in user_groupes
:
493 def has_delete_permission(self
, request
, obj
=None):
494 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
495 if request
.user
.is_superuser
is True or \
496 groups
.CORRESPONDANT_RH
in user_groupes
or \
497 groups
.DRH_NIVEAU_1
in user_groupes
or \
498 groups
.DRH_NIVEAU_2
in user_groupes
or \
499 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
500 groups
.ADMINISTRATEURS
in user_groupes
or \
501 groups
.HAUTE_DIRECTION
in user_groupes
:
505 def has_change_permission(self
, request
, obj
=None):
506 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
507 if request
.user
.is_superuser
is True or \
508 groups
.CORRESPONDANT_RH
in user_groupes
or \
509 groups
.DRH_NIVEAU_1
in user_groupes
or \
510 groups
.DRH_NIVEAU_2
in user_groupes
or \
511 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
512 groups
.ADMINISTRATEURS
in user_groupes
or \
513 groups
.HAUTE_DIRECTION
in user_groupes
:
517 def formfield_for_foreignkey(self
, db_field
, request
, **kwargs
):
518 if db_field
.name
== 'offre_emploi':
519 employe
= groups
.get_employe_from_user(request
.user
)
520 kwargs
["queryset"] = OffreEmploi
.objects
.filter(region
=employe
.implantation
.region
)
521 return db_field
.formfield(**kwargs
)
522 return super(CandidatAdminMixin
, self
).formfield_for_foreignkey(db_field
, request
, **kwargs
)
524 def get_changelist(self
, request
, **kwargs
):
525 return OrderedChangeList
527 def queryset(self
, request
):
529 Spécifie un queryset limité, autrement Django exécute un
530 select_related() sans paramètre, ce qui a pour effet de charger tous
531 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
532 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
533 génération d'une requête infinie.
535 qs
= self
.model
._default_manager
.get_query_set() \
536 .select_related('offre_emploi') \
537 .annotate(moyenne
=Avg('evaluations__note'))
539 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
540 if groups
.DRH_NIVEAU_1
in user_groupes
or \
541 groups
.DRH_NIVEAU_2
in user_groupes
or \
542 groups
.HAUTE_DIRECTION
in user_groupes
:
545 if groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
546 groups
.CORRESPONDANT_RH
in user_groupes
or \
547 groups
.ADMINISTRATEURS
in user_groupes
:
548 employe
= groups
.get_employe_from_user(request
.user
)
549 return qs
.filter(offre_emploi__region
=employe
.implantation
.region
)
551 if Evaluateur
.objects
.filter(user
=request
.user
).exists():
552 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
553 candidat_ids
= [e
.candidat
.id for e
in
554 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
)]
555 return qs
.filter(id__in
=candidat_ids
)
559 class CandidatAdmin(VersionAdmin
, CandidatAdminMixin
):
560 change_list_template
= 'admin/recrutement/candidat/change_list.html'
564 class ProxyCandidatAdmin(CandidatAdminMixin
):
565 change_list_template
= 'admin/recrutement/candidat/change_list.html'
568 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
569 'situation_famille', 'nombre_dependant', 'telephone', 'email',
570 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
571 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
572 'domaine_professionnel', 'pieces_jointes'
576 'fields': ('offre_emploi', )
578 ('Informations personnelles', {
580 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille',
586 'telephone', 'email', 'adresse', 'ville', 'etat_province',
587 'code_postal', 'pays'
590 ('Informations professionnelles', {
592 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
593 'domaine_professionnel'
597 inlines
= (CandidatEvaluationInline
, )
599 def has_add_permission(self
, request
):
602 def has_delete_permission(self
, request
, obj
=None):
605 def has_change_permission(self
, request
, obj
=None):
607 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
608 for e
in obj
.evaluations
.all():
609 if e
.evaluateur
== evaluateur
:
612 return not super(ProxyCandidatAdmin
, self
).has_change_permission(request
, obj
)
614 def get_actions(self
, request
):
618 class CandidatPieceAdmin(admin
.ModelAdmin
):
619 list_display
= ('nom', 'candidat', )
622 def queryset(self
, request
):
624 Spécifie un queryset limité, autrement Django exécute un
625 select_related() sans paramètre, ce qui a pour effet de charger tous
626 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
627 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
628 génération d'une requête infinie. Affiche la liste de candidats que
629 si le user connecté possède un Evaluateur
631 qs
= self
.model
._default_manager
.get_query_set()
632 return qs
.select_related('candidat')
635 class EvaluateurAdmin(BaseAdmin
, VersionAdmin
):
642 ### Actions à afficher
643 def get_actions(self
, request
):
644 actions
= super(EvaluateurAdmin
, self
).get_actions(request
)
645 del actions
['delete_selected']
648 ### Permissions add, delete, change
649 def has_add_permission(self
, request
):
650 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
651 if request
.user
.is_superuser
is True or \
652 groups
.DRH_NIVEAU_1
in user_groupes
or \
653 groups
.DRH_NIVEAU_2
in user_groupes
or \
654 groups
.HAUTE_DIRECTION
in user_groupes
:
658 def has_delete_permission(self
, request
, obj
=None):
659 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
660 if request
.user
.is_superuser
is True or \
661 groups
.DRH_NIVEAU_1
in user_groupes
or \
662 groups
.DRH_NIVEAU_2
in user_groupes
or \
663 groups
.HAUTE_DIRECTION
in user_groupes
:
667 def has_change_permission(self
, request
, obj
=None):
668 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
669 if request
.user
.is_superuser
is True or \
670 groups
.DRH_NIVEAU_1
in user_groupes
or \
671 groups
.DRH_NIVEAU_2
in user_groupes
or \
672 groups
.HAUTE_DIRECTION
in user_groupes
:
677 class CandidatEvaluationAdmin(BaseAdmin
):
678 search_fields
= ('candidat__nom', 'candidat__prenom')
680 '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
683 readonly_fields
= ('candidat', 'evaluateur')
684 list_filter
= ('candidat__statut', 'candidat__offre_emploi',)
686 ('Évaluation du candidat', {
687 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
691 def get_actions(self
, request
):
692 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
694 self
.evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
696 self
.evaluateur
= None
698 actions
= super(CandidatEvaluationAdmin
, self
).get_actions(request
)
699 del actions
['delete_selected']
703 def _note(self
, obj
):
705 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
706 un lien pour Évaluer le candidat.
707 Sinon afficher la note.
709 page
= self
.model
.__name__
.lower()
710 redirect_url
= 'admin:recrutement_%s_change' % page
713 label
= "Candidat non évalué"
717 if self
.evaluateur
== obj
.evaluateur
:
718 return "<a href='%s'>%s</a>" % (
719 reverse(redirect_url
, args
=(obj
.id,)), label
723 _note
.allow_tags
= True
724 _note
.short_description
= "Note"
725 _note
.admin_order_field
= 'note'
727 def _statut(self
, obj
):
728 return obj
.candidat
.get_statut_display()
729 _statut
.order_field
= 'candidat__statut'
730 _statut
.short_description
= 'Statut'
732 ### Lien en lecture seule vers le candidat
733 def _candidat(self
, obj
):
734 return "<a href='%s'>%s</a>" \
735 % (reverse('admin:recrutement_proxycandidat_change',
736 args
=(obj
.candidat
.id,)), obj
.candidat
)
737 _candidat
.allow_tags
= True
738 _candidat
.short_description
= 'Candidat'
740 ### Afficher commentaire
741 def _commentaire(self
, obj
):
743 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
744 dans le champ commentaire, Aucun au lieu de (None)
745 Sinon afficher la note.
747 if obj
.commentaire
is None:
749 return obj
.commentaire
750 _commentaire
.allow_tags
= True
751 _commentaire
.short_description
= "Commentaire"
753 ### Afficher offre d'emploi
754 def _offre_emploi(self
, obj
):
755 return "<a href='%s'>%s</a>" % \
756 (reverse('admin:recrutement_proxyoffreemploi_change',
757 args
=(obj
.candidat
.offre_emploi
.id,)), obj
.candidat
.offre_emploi
)
758 _offre_emploi
.allow_tags
= True
759 _offre_emploi
.short_description
= "Voir offre d'emploi"
761 def has_add_permission(self
, request
):
764 def has_delete_permission(self
, request
, obj
=None):
767 def has_change_permission(self
, request
, obj
=None):
769 Permettre la visualisation dans la changelist
770 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
773 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
775 if request
.user
.is_superuser
or \
776 groups
.CORRESPONDANT_RH
in user_groupes
or \
777 groups
.DRH_NIVEAU_1
in user_groupes
or \
778 groups
.DRH_NIVEAU_2
in user_groupes
or \
779 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
780 groups
.ADMINISTRATEURS
in user_groupes
or \
781 groups
.HAUTE_DIRECTION
in user_groupes
:
782 is_recrutement
= True
784 is_recrutement
= False
786 return is_recrutement
788 def queryset(self
, request
):
790 Afficher uniquement les évaluations de l'évaluateur, sauf si
791 l'utilisateur est dans les groupes suivants.
793 qs
= self
.model
._default_manager
.get_query_set() \
794 .select_related('offre_emploi')
795 user_groupes
= request
.user
.groups
.all()
796 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
798 if request
.user
.is_superuser
or \
799 groups
.CORRESPONDANT_RH
in user_groupes
or \
800 groups
.DRH_NIVEAU_1
in user_groupes
or \
801 groups
.DRH_NIVEAU_2
in user_groupes
or \
802 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
803 groups
.ADMINISTRATEURS
in user_groupes
or \
804 groups
.HAUTE_DIRECTION
in user_groupes
:
805 return qs
.filter(candidat__statut__in
=('REC', 'SEL'))
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
)
815 class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin
):
818 def has_change_permission(self
, request
, obj
=None):
820 Evaluateur
.objects
.get(user
=request
.user
)
823 is_evaluateur
= False
825 if obj
is None and is_evaluateur
:
829 return request
.user
== obj
.evaluateur
.user
833 def queryset(self
, request
):
834 qs
= self
.model
._default_manager
.get_query_set() \
835 .select_related('offre_emploi')
836 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
837 candidats_evaluations
= \
838 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
,
839 candidat__statut__in
=('REC', ))
840 candidats_evaluations_ids
= [ce
.id for ce
in candidats_evaluations
]
841 return qs
.filter(id__in
=candidats_evaluations_ids
)
844 class CourrielTemplateAdmin(BaseAdmin
, VersionAdmin
):
845 ### Actions à afficher
846 def get_actions(self
, request
):
847 actions
= super(CourrielTemplateAdmin
, self
).get_actions(request
)
848 del actions
['delete_selected']
851 admin
.site
.register(OffreEmploi
, OffreEmploiAdmin
)
852 admin
.site
.register(ProxyOffreEmploi
, ProxyOffreEmploiAdmin
)
853 admin
.site
.register(Candidat
, CandidatAdmin
)
854 admin
.site
.register(ProxyCandidat
, ProxyCandidatAdmin
)
855 admin
.site
.register(CandidatEvaluation
, CandidatEvaluationAdmin
)
856 admin
.site
.register(MesCandidatEvaluation
, MesCandidatEvaluationAdmin
)
857 admin
.site
.register(Evaluateur
, EvaluateurAdmin
)
858 admin
.site
.register(CourrielTemplate
, CourrielTemplateAdmin
)