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
= 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):
281 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
282 if request
.user
.is_superuser
is True or \
283 groups
.CORRESPONDANT_RH
in user_groupes
or \
284 groups
.DRH_NIVEAU_1
in user_groupes
or \
285 groups
.DRH_NIVEAU_2
in user_groupes
or \
286 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
287 groups
.ADMINISTRATEURS
in user_groupes
or \
288 groups
.HAUTE_DIRECTION
in user_groupes
:
294 return not super(ProxyOffreEmploiAdmin
, self
).has_change_permission(request
, obj
)
297 class CandidatPieceInline(admin
.TabularInline
):
298 model
= CandidatPiece
299 fields
= ('candidat', 'nom', 'path',)
304 class ReadOnlyCandidatPieceInline(CandidatPieceInline
):
305 readonly_fields
= ('candidat', 'nom', 'path', )
309 class CandidatEvaluationInlineFormSet(BaseInlineFormSet
):
311 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
313 def __init__(self
, *args
, **kwargs
):
314 super(CandidatEvaluationInlineFormSet
, self
).__init__(*args
, **kwargs
)
315 self
.can_delete
= False
318 class CandidatEvaluationInline(admin
.TabularInline
):
319 model
= CandidatEvaluation
320 fields
= ('evaluateur', 'note', 'commentaire')
323 formset
= CandidatEvaluationInlineFormSet
326 def get_readonly_fields(self
, request
, obj
=None):
328 Empêche la modification des évaluations
331 return self
.readonly_fields
+ ('evaluateur', 'note', 'commentaire')
332 return self
.readonly_fields
335 class CandidatAdminMixin(BaseAdmin
, ExportAdmin
):
336 search_fields
= ('nom', 'prenom')
337 exclude
= ('actif', )
338 list_editable
= ('statut', )
339 list_display
= ('_candidat', 'offre_emploi',
340 'voir_offre_emploi', 'calculer_moyenne',
341 'afficher_candidat', '_date_creation', 'statut', )
342 list_filter
= ('offre_emploi__nom', 'offre_emploi__region', 'statut', )
346 'fields': ('offre_emploi', )
348 ('Informations personnelles', {
350 'nom', 'prenom', 'genre', 'nationalite',
351 'situation_famille', 'nombre_dependant'
356 'telephone', 'email', 'adresse', 'ville', 'etat_province',
357 'code_postal', 'pays'
360 ('Informations professionnelles', {
362 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
363 'domaine_professionnel'
367 'fields': ('statut', )
372 CandidatEvaluationInline
,
374 actions
= ['envoyer_courriel_candidats', 'changer_statut']
376 export_fields
= ['statut', 'offre_emploi', 'prenom', 'nom', 'genre',
377 'nationalite', 'situation_famille', 'nombre_dependant',
378 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
379 'domaine_professionnel', 'telephone', 'email', 'adresse',
380 'ville', 'etat_province', 'code_postal', 'pays']
382 def _candidat(self
, obj
):
383 txt
= u
"%s %s (%s)" % (obj
.nom
.upper(), obj
.prenom
, obj
.genre
)
384 txt
= textwrap
.wrap(txt
, 30)
385 return "<br/>".join(txt
)
386 _candidat
.short_description
= "Candidat"
387 _candidat
.admin_order_field
= "nom"
388 _candidat
.allow_tags
= True
390 def _date_creation(self
, obj
):
391 return obj
.date_creation
392 _date_creation
.admin_order_field
= "date_creation"
393 _date_creation
.short_description
= "Date de réception"
395 ### Actions à afficher
396 def get_actions(self
, request
):
397 actions
= super(CandidatAdminMixin
, self
).get_actions(request
)
398 del actions
['delete_selected']
401 ### Envoyer un courriel à des candidats
402 def envoyer_courriel_candidats(modeladmin
, obj
, candidats
):
403 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
405 return HttpResponseRedirect(
406 reverse('selectionner_template') + "?ids=%s" % (",".join(selected
))
408 envoyer_courriel_candidats
.short_description
= u
'Envoyer courriel'
410 ### Changer le statut à des candidats
411 def changer_statut(modeladmin
, request
, queryset
):
412 if request
.POST
.get('post'):
413 queryset
.update(statut
=request
.POST
.get('statut'))
417 'action_checkbox_name': admin
.helpers
.ACTION_CHECKBOX_NAME
,
418 'queryset': queryset
,
419 'status': STATUT_CHOICES
,
422 return render_to_response("recrutement/selectionner_statut.html",
423 context
, context_instance
= RequestContext(request
))
425 changer_statut
.short_description
= u
'Changer statut'
427 ### Évaluer un candidat
428 def evaluer_candidat(self
, obj
):
429 return "<a href='%s?candidat__id__exact=%s'>" \
430 "Évaluer le candidat</a>" % (
431 reverse('admin:recrutement_candidatevaluation_changelist'),
434 evaluer_candidat
.allow_tags
= True
435 evaluer_candidat
.short_description
= 'Évaluation'
437 ### Afficher un candidat
438 def afficher_candidat(self
, obj
):
439 items
= [u
"<li><a href='%s%s'>%s</li>" % \
440 (settings
.OE_PRIVE_MEDIA_URL
, pj
.path
, pj
.get_nom_display()) \
441 for pj
in obj
.pieces_jointes()]
442 html
= "<a href='%s'>Candidature</a>" % (
443 reverse('admin:recrutement_proxycandidat_change', args
=(obj
.id,))
445 return "%s<ul>%s</ul>" % (html
, "\n".join(items
))
446 afficher_candidat
.allow_tags
= True
447 afficher_candidat
.short_description
= u
'Détails du candidat'
449 ### Voir l'offre d'emploi
450 def voir_offre_emploi(self
, obj
):
451 return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse(
452 'admin:recrutement_proxyoffreemploi_change',
453 args
=(obj
.offre_emploi
.id,)
455 voir_offre_emploi
.allow_tags
= True
456 voir_offre_emploi
.short_description
= "Afficher l'offre d'emploi"
458 ### Calculer la moyenne des notes
459 def calculer_moyenne(self
, obj
):
460 evaluations
= CandidatEvaluation
.objects
.filter(candidat
=obj
)
462 notes
= [evaluation
.note
for evaluation
in evaluations \
463 if evaluation
.note
is not None]
466 moyenne_votes
= round(float(sum(notes
)) / len(notes
), 2)
468 moyenne_votes
= "Non disponible"
470 totales
= len(evaluations
)
473 if obj
.statut
== 'REC':
474 if totales
== faites
:
476 elif faites
> 0 and float(totales
) / float(faites
) >= 2:
483 return """<span style="color: %s;">%s (%s/%s)</span>""" % (
484 color
, moyenne_votes
, faites
, totales
486 calculer_moyenne
.allow_tags
= True
487 calculer_moyenne
.short_description
= "Moyenne"
488 calculer_moyenne
.admin_order_field
= ""
490 ### Permissions add, delete, change
491 def has_add_permission(self
, request
):
492 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
493 if request
.user
.is_superuser
is True or \
494 groups
.CORRESPONDANT_RH
in user_groupes
or \
495 groups
.DRH_NIVEAU_1
in user_groupes
or \
496 groups
.DRH_NIVEAU_2
in user_groupes
or \
497 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
498 groups
.ADMINISTRATEURS
in user_groupes
or \
499 groups
.HAUTE_DIRECTION
in user_groupes
:
503 def has_delete_permission(self
, request
, obj
=None):
504 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
505 if request
.user
.is_superuser
is True or \
506 groups
.CORRESPONDANT_RH
in user_groupes
or \
507 groups
.DRH_NIVEAU_1
in user_groupes
or \
508 groups
.DRH_NIVEAU_2
in user_groupes
or \
509 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
510 groups
.ADMINISTRATEURS
in user_groupes
or \
511 groups
.HAUTE_DIRECTION
in user_groupes
:
515 def has_change_permission(self
, request
, obj
=None):
516 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
517 if request
.user
.is_superuser
is True or \
518 groups
.CORRESPONDANT_RH
in user_groupes
or \
519 groups
.DRH_NIVEAU_1
in user_groupes
or \
520 groups
.DRH_NIVEAU_2
in user_groupes
or \
521 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
522 groups
.ADMINISTRATEURS
in user_groupes
or \
523 groups
.HAUTE_DIRECTION
in user_groupes
:
527 def formfield_for_foreignkey(self
, db_field
, request
, **kwargs
):
528 if db_field
.name
== 'offre_emploi':
529 employe
= groups
.get_employe_from_user(request
.user
)
530 kwargs
["queryset"] = OffreEmploi
.objects
.filter(region
=employe
.implantation
.region
)
531 return db_field
.formfield(**kwargs
)
532 return super(CandidatAdminMixin
, self
).formfield_for_foreignkey(db_field
, request
, **kwargs
)
534 def get_changelist(self
, request
, **kwargs
):
535 return OrderedChangeList
537 def queryset(self
, request
):
539 Spécifie un queryset limité, autrement Django exécute un
540 select_related() sans paramètre, ce qui a pour effet de charger tous
541 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
542 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
543 génération d'une requête infinie.
545 qs
= self
.model
._default_manager
.get_query_set() \
546 .select_related('offre_emploi') \
547 .annotate(moyenne
=Avg('evaluations__note'))
549 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
550 if groups
.DRH_NIVEAU_1
in user_groupes
or \
551 groups
.DRH_NIVEAU_2
in user_groupes
or \
552 groups
.HAUTE_DIRECTION
in user_groupes
:
555 if groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
556 groups
.CORRESPONDANT_RH
in user_groupes
or \
557 groups
.ADMINISTRATEURS
in user_groupes
:
558 employe
= groups
.get_employe_from_user(request
.user
)
559 return qs
.filter(offre_emploi__region
=employe
.implantation
.region
)
561 if Evaluateur
.objects
.filter(user
=request
.user
).exists():
562 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
563 candidat_ids
= [e
.candidat
.id for e
in
564 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
)]
565 return qs
.filter(id__in
=candidat_ids
)
569 class CandidatAdmin(VersionAdmin
, CandidatAdminMixin
):
570 change_list_template
= 'admin/recrutement/candidat/change_list.html'
574 class ProxyCandidatAdmin(CandidatAdminMixin
):
575 change_list_template
= 'admin/recrutement/candidat/change_list.html'
578 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
579 'situation_famille', 'nombre_dependant', 'telephone', 'email',
580 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
581 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
582 'domaine_professionnel', 'pieces_jointes'
586 'fields': ('offre_emploi', )
588 ('Informations personnelles', {
590 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille',
596 'telephone', 'email', 'adresse', 'ville', 'etat_province',
597 'code_postal', 'pays'
600 ('Informations professionnelles', {
602 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
603 'domaine_professionnel'
607 inlines
= (CandidatEvaluationInline
, )
609 def has_add_permission(self
, request
):
612 def has_delete_permission(self
, request
, obj
=None):
615 def has_change_permission(self
, request
, obj
=None):
616 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
617 if request
.user
.is_superuser
is True or \
618 groups
.CORRESPONDANT_RH
in user_groupes
or \
619 groups
.DRH_NIVEAU_1
in user_groupes
or \
620 groups
.DRH_NIVEAU_2
in user_groupes
or \
621 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
622 groups
.ADMINISTRATEURS
in user_groupes
or \
623 groups
.HAUTE_DIRECTION
in user_groupes
:
627 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
628 for e
in obj
.evaluations
.all():
629 if e
.evaluateur
== evaluateur
:
632 return not super(ProxyCandidatAdmin
, self
).has_change_permission(request
, obj
)
634 def get_actions(self
, request
):
638 class CandidatPieceAdmin(admin
.ModelAdmin
):
639 list_display
= ('nom', 'candidat', )
642 def queryset(self
, request
):
644 Spécifie un queryset limité, autrement Django exécute un
645 select_related() sans paramètre, ce qui a pour effet de charger tous
646 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
647 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
648 génération d'une requête infinie. Affiche la liste de candidats que
649 si le user connecté possède un Evaluateur
651 qs
= self
.model
._default_manager
.get_query_set()
652 return qs
.select_related('candidat')
655 class EvaluateurAdmin(BaseAdmin
, VersionAdmin
):
662 ### Actions à afficher
663 def get_actions(self
, request
):
664 actions
= super(EvaluateurAdmin
, self
).get_actions(request
)
665 del actions
['delete_selected']
668 ### Permissions add, delete, change
669 def has_add_permission(self
, request
):
670 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
671 if request
.user
.is_superuser
is True or \
672 groups
.DRH_NIVEAU_1
in user_groupes
or \
673 groups
.DRH_NIVEAU_2
in user_groupes
or \
674 groups
.HAUTE_DIRECTION
in user_groupes
:
678 def has_delete_permission(self
, request
, obj
=None):
679 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
680 if request
.user
.is_superuser
is True or \
681 groups
.DRH_NIVEAU_1
in user_groupes
or \
682 groups
.DRH_NIVEAU_2
in user_groupes
or \
683 groups
.HAUTE_DIRECTION
in user_groupes
:
687 def has_change_permission(self
, request
, obj
=None):
688 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
689 if request
.user
.is_superuser
is True or \
690 groups
.DRH_NIVEAU_1
in user_groupes
or \
691 groups
.DRH_NIVEAU_2
in user_groupes
or \
692 groups
.HAUTE_DIRECTION
in user_groupes
:
697 class CandidatEvaluationAdmin(BaseAdmin
):
698 search_fields
= ('candidat__nom', 'candidat__prenom')
700 '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
703 readonly_fields
= ('candidat', 'evaluateur')
704 list_filter
= ('candidat__statut', 'candidat__offre_emploi',)
706 ('Évaluation du candidat', {
707 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
711 def get_actions(self
, request
):
712 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
714 self
.evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
716 self
.evaluateur
= None
718 actions
= super(CandidatEvaluationAdmin
, self
).get_actions(request
)
719 del actions
['delete_selected']
723 def _note(self
, obj
):
725 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
726 un lien pour Évaluer le candidat.
727 Sinon afficher la note.
729 page
= self
.model
.__name__
.lower()
730 redirect_url
= 'admin:recrutement_%s_change' % page
733 label
= "Candidat non évalué"
737 if self
.evaluateur
== obj
.evaluateur
:
738 return "<a href='%s'>%s</a>" % (
739 reverse(redirect_url
, args
=(obj
.id,)), label
743 _note
.allow_tags
= True
744 _note
.short_description
= "Note"
745 _note
.admin_order_field
= 'note'
747 def _statut(self
, obj
):
748 return obj
.candidat
.get_statut_display()
749 _statut
.order_field
= 'candidat__statut'
750 _statut
.short_description
= 'Statut'
752 ### Lien en lecture seule vers le candidat
753 def _candidat(self
, obj
):
754 return "<a href='%s'>%s</a>" \
755 % (reverse('admin:recrutement_proxycandidat_change',
756 args
=(obj
.candidat
.id,)), obj
.candidat
)
757 _candidat
.allow_tags
= True
758 _candidat
.short_description
= 'Candidat'
760 ### Afficher commentaire
761 def _commentaire(self
, obj
):
763 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
764 dans le champ commentaire, Aucun au lieu de (None)
765 Sinon afficher la note.
767 if obj
.commentaire
is None:
769 return obj
.commentaire
770 _commentaire
.allow_tags
= True
771 _commentaire
.short_description
= "Commentaire"
773 ### Afficher offre d'emploi
774 def _offre_emploi(self
, obj
):
775 return "<a href='%s'>%s</a>" % \
776 (reverse('admin:recrutement_proxyoffreemploi_change',
777 args
=(obj
.candidat
.offre_emploi
.id,)), obj
.candidat
.offre_emploi
)
778 _offre_emploi
.allow_tags
= True
779 _offre_emploi
.short_description
= "Voir offre d'emploi"
781 def has_add_permission(self
, request
):
784 def has_delete_permission(self
, request
, obj
=None):
787 def has_change_permission(self
, request
, obj
=None):
789 Permettre la visualisation dans la changelist
790 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
793 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
795 if request
.user
.is_superuser
or \
796 groups
.CORRESPONDANT_RH
in user_groupes
or \
797 groups
.DRH_NIVEAU_1
in user_groupes
or \
798 groups
.DRH_NIVEAU_2
in user_groupes
or \
799 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
800 groups
.ADMINISTRATEURS
in user_groupes
or \
801 groups
.HAUTE_DIRECTION
in user_groupes
:
802 is_recrutement
= True
804 is_recrutement
= False
806 return is_recrutement
808 def queryset(self
, request
):
810 Afficher uniquement les évaluations de l'évaluateur, sauf si
811 l'utilisateur est dans les groupes suivants.
813 qs
= self
.model
._default_manager
.get_query_set() \
814 .select_related('offre_emploi')
815 user_groupes
= request
.user
.groups
.all()
816 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
818 if request
.user
.is_superuser
or \
819 groups
.CORRESPONDANT_RH
in user_groupes
or \
820 groups
.DRH_NIVEAU_1
in user_groupes
or \
821 groups
.DRH_NIVEAU_2
in user_groupes
or \
822 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
823 groups
.ADMINISTRATEURS
in user_groupes
or \
824 groups
.HAUTE_DIRECTION
in user_groupes
:
825 return qs
.filter(candidat__statut__in
=('REC', 'SEL'))
827 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
828 candidats_evaluations
= \
829 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
,
830 candidat__statut__in
=('REC', ))
831 candidats_evaluations_ids
= [ce
.id for ce
in candidats_evaluations
]
832 return qs
.filter(id__in
=candidats_evaluations_ids
)
835 class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin
):
838 def has_change_permission(self
, request
, obj
=None):
840 Evaluateur
.objects
.get(user
=request
.user
)
843 is_evaluateur
= False
845 if obj
is None and is_evaluateur
:
849 return request
.user
== obj
.evaluateur
.user
853 def queryset(self
, request
):
854 qs
= self
.model
._default_manager
.get_query_set() \
855 .select_related('offre_emploi')
856 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
857 candidats_evaluations
= \
858 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
,
859 candidat__statut__in
=('REC', ))
860 candidats_evaluations_ids
= [ce
.id for ce
in candidats_evaluations
]
861 return qs
.filter(id__in
=candidats_evaluations_ids
)
864 class CourrielTemplateAdmin(BaseAdmin
, VersionAdmin
):
865 ### Actions à afficher
866 def get_actions(self
, request
):
867 actions
= super(CourrielTemplateAdmin
, self
).get_actions(request
)
868 del actions
['delete_selected']
871 admin
.site
.register(OffreEmploi
, OffreEmploiAdmin
)
872 admin
.site
.register(ProxyOffreEmploi
, ProxyOffreEmploiAdmin
)
873 admin
.site
.register(Candidat
, CandidatAdmin
)
874 admin
.site
.register(ProxyCandidat
, ProxyCandidatAdmin
)
875 admin
.site
.register(CandidatEvaluation
, CandidatEvaluationAdmin
)
876 admin
.site
.register(MesCandidatEvaluation
, MesCandidatEvaluationAdmin
)
877 admin
.site
.register(Evaluateur
, EvaluateurAdmin
)
878 admin
.site
.register(CourrielTemplate
, CourrielTemplateAdmin
)