1 # -*- encoding: utf-8 -*-
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
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
, \
25 IMPLANTATIONS_CENTRALES
= [15, 19]
28 class BaseAdmin(admin
.ModelAdmin
):
32 'css/admin_custom.css',
33 'jquery-autocomplete/jquery.autocomplete.css',
36 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
37 'jquery-autocomplete/jquery.autocomplete.min.js',
41 class OrderedChangeList(admin
.views
.main
.ChangeList
):
43 Surcharge pour appliquer le order_by d'un annotate
45 def get_query_set(self
):
46 qs
= super(OrderedChangeList
, self
).get_query_set()
47 qs
= qs
.order_by('-moyenne')
51 class OffreEmploiAdminMixin(BaseAdmin
):
52 date_hierarchy
= 'date_creation'
54 'nom', 'date_limite', 'region', 'statut', 'est_affiche',
57 exclude
= ('actif', 'poste_nom', 'resume',)
58 list_filter
= ('statut',)
59 actions
= ['affecter_evaluateurs_offre_emploi', ]
60 form
= OffreEmploiForm
62 ### Actions à afficher
63 def get_actions(self
, request
):
64 actions
= super(OffreEmploiAdminMixin
, self
).get_actions(request
)
65 del actions
['delete_selected']
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
)
72 return HttpResponseRedirect(
73 reverse('affecter_evaluateurs_offre_emploi') +
74 "?ids=%s" % (",".join(selected
))
77 affecter_evaluateurs_offre_emploi
.short_description
= \
78 u
'Affecter évaluateur(s)'
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"
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()]
95 if 'region' in form
.declared_fields
:
96 region_field
= form
.declared_fields
['region']
98 elif 'region' in form
.base_fields
:
99 region_field
= form
.base_fields
['region']
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()
110 region_field
.queryset
= Region
.objects
.\
111 filter(id=employe
.implantation
.region
.id)
114 if 'poste' in form
.declared_fields
:
115 poste_field
= form
.declared_fields
['poste']
117 elif 'poste' in form
.base_fields
:
118 poste_field
= form
.base_fields
['poste']
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()
129 poste_field
.queryset
= rh
.Poste
.objects
.\
130 filter(implantation__region
=employe
.implantation
.region
).\
131 exclude(implantation__in
=IMPLANTATIONS_CENTRALES
)
134 if 'bureau' in form
.declared_fields
:
135 bureau_field
= form
.declared_fields
['bureau']
137 elif 'bureau' in form
.base_fields
:
138 bureau_field
= form
.base_fields
['bureau']
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()
148 bureau_field
.queryset
= \
149 Bureau
.objects
.filter(region
=employe
.implantation
.region
)
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
:
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
)
170 if Evaluateur
.objects
.filter(user
=request
.user
).exists():
171 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
173 e
.candidat
.offre_emploi_id
174 for e
in CandidatEvaluation
.objects
175 .select_related('candidat')
176 .filter(evaluateur
=evaluateur
)
178 return qs
.filter(id__in
=offre_ids
)
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
:
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
.HAUTE_DIRECTION
in user_groupes
:
203 employe
= groups
.get_employe_from_user(request
.user
)
204 if (groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
205 groups
.ADMINISTRATEURS
in user_groupes
) and (
206 employe
.implantation
.region
== obj
.lieu_affectation
.region
):
211 def has_change_permission(self
, request
, obj
=None):
212 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
213 if request
.user
.is_superuser
is True or \
214 groups
.DRH_NIVEAU_1
in user_groupes
or \
215 groups
.DRH_NIVEAU_2
in user_groupes
or \
216 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
217 groups
.ADMINISTRATEURS
in user_groupes
or \
218 groups
.HAUTE_DIRECTION
in user_groupes
:
223 class OffreEmploiAdmin(VersionAdmin
, OffreEmploiAdminMixin
):
227 class ProxyOffreEmploiAdmin(OffreEmploiAdminMixin
):
229 'nom', 'date_limite', 'region', 'statut', 'est_affiche'
232 'description', 'bureau', 'duree_affectation', 'renumeration',
233 'debut_affectation', 'lieu_affectation', 'nom', 'resume',
234 'date_limite', 'region', 'poste'
240 ('Description générale', {
241 'fields': ('description', 'date_limite',)
244 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
248 'debut_affectation', 'duree_affectation', 'renumeration',
254 ### Lieu de redirection après le change
255 def response_change(self
, request
, obj
):
256 return redirect('admin:recrutement_proxyoffreemploi_changelist')
259 def get_form(self
, request
, obj
=None, **kwargs
):
260 form
= super(ProxyOffreEmploiAdmin
, self
).get_form(request
, obj
, **kwargs
)
263 ### Permissions add, delete, change
264 def has_add_permission(self
, request
):
267 def has_delete_permission(self
, request
, obj
=None):
270 def has_change_permission(self
, request
, obj
=None):
271 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
272 if request
.user
.is_superuser
is True or \
273 groups
.CORRESPONDANT_RH
in user_groupes
or \
274 groups
.DRH_NIVEAU_1
in user_groupes
or \
275 groups
.DRH_NIVEAU_2
in user_groupes
or \
276 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
277 groups
.ADMINISTRATEURS
in user_groupes
or \
278 groups
.HAUTE_DIRECTION
in user_groupes
:
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
):
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', 'offre_emploi__region', 'statut', )
336 'fields': ('offre_emploi', )
338 ('Informations personnelles', {
340 'prenom', 'nom', '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']
366 def _candidat(self
, obj
):
367 txt
= u
"%s %s (%s)" % (obj
.nom
.upper(), obj
.prenom
, obj
.genre
)
368 txt
= textwrap
.wrap(txt
, 30)
369 return "<br/>".join(txt
)
370 _candidat
.short_description
= "Candidat"
371 _candidat
.admin_order_field
= "nom"
372 _candidat
.allow_tags
= True
374 def _date_creation(self
, obj
):
375 return obj
.date_creation
376 _date_creation
.admin_order_field
= "date_creation"
377 _date_creation
.short_description
= "Date de réception"
379 ### Actions à afficher
380 def get_actions(self
, request
):
381 actions
= super(CandidatAdmin
, self
).get_actions(request
)
382 del actions
['delete_selected']
385 ### Envoyer un courriel à des candidats
386 def envoyer_courriel_candidats(modeladmin
, obj
, candidats
):
387 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
389 return HttpResponseRedirect(
390 reverse('selectionner_template') + "?ids=%s" % (",".join(selected
))
392 envoyer_courriel_candidats
.short_description
= u
'Envoyer courriel'
394 ### Évaluer un candidat
395 def evaluer_candidat(self
, obj
):
396 return "<a href='%s?candidat__id__exact=%s'>" \
397 "Évaluer le candidat</a>" % (
398 reverse('admin:recrutement_candidatevaluation_changelist'),
401 evaluer_candidat
.allow_tags
= True
402 evaluer_candidat
.short_description
= 'Évaluation'
404 ### Afficher un candidat
405 def afficher_candidat(self
, obj
):
406 items
= [u
"<li><a href='%s%s'>%s</li>" % \
407 (settings
.OE_PRIVE_MEDIA_URL
, pj
.path
, pj
.get_nom_display()) \
408 for pj
in obj
.pieces_jointes()]
409 html
= "<a href='%s'>Voir le candidat</a>" % (
410 reverse('admin:recrutement_proxycandidat_change', args
=(obj
.id,))
412 return "%s<ul>%s</ul>" % (html
, "\n".join(items
))
413 afficher_candidat
.allow_tags
= True
414 afficher_candidat
.short_description
= u
'Détails du candidat'
416 ### Voir l'offre d'emploi
417 def voir_offre_emploi(self
, obj
):
418 return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse(
419 'admin:recrutement_proxyoffreemploi_change',
420 args
=(obj
.offre_emploi
.id,)
422 voir_offre_emploi
.allow_tags
= True
423 voir_offre_emploi
.short_description
= "Afficher l'offre d'emploi"
425 ### Calculer la moyenne des notes
426 def calculer_moyenne(self
, obj
):
427 evaluations
= CandidatEvaluation
.objects
.filter(candidat
=obj
)
429 notes
= [evaluation
.note
for evaluation
in evaluations \
430 if evaluation
.note
is not None]
433 moyenne_votes
= round(float(sum(notes
)) / len(notes
), 2)
435 moyenne_votes
= "Non disponible"
437 totales
= len(evaluations
)
440 if obj
.statut
== 'REC':
441 if totales
== faites
:
443 elif faites
> 0 and float(totales
) / float(faites
) >= 2:
450 return """<span style="color: %s;">%s (%s/%s)</span>""" % (
451 color
, moyenne_votes
, faites
, totales
453 calculer_moyenne
.allow_tags
= True
454 calculer_moyenne
.short_description
= "Moyenne"
455 calculer_moyenne
.admin_order_field
= ""
457 ### Permissions add, delete, change
458 def has_add_permission(self
, request
):
459 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
460 if request
.user
.is_superuser
is True or \
461 groups
.CORRESPONDANT_RH
in user_groupes
or \
462 groups
.DRH_NIVEAU_1
in user_groupes
or \
463 groups
.DRH_NIVEAU_2
in user_groupes
or \
464 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
465 groups
.ADMINISTRATEURS
in user_groupes
or \
466 groups
.HAUTE_DIRECTION
in user_groupes
:
470 def has_delete_permission(self
, request
, obj
=None):
471 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
472 if request
.user
.is_superuser
is True or \
473 groups
.CORRESPONDANT_RH
in user_groupes
or \
474 groups
.DRH_NIVEAU_1
in user_groupes
or \
475 groups
.DRH_NIVEAU_2
in user_groupes
or \
476 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
477 groups
.ADMINISTRATEURS
in user_groupes
or \
478 groups
.HAUTE_DIRECTION
in user_groupes
:
482 def has_change_permission(self
, request
, obj
=None):
483 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
484 if request
.user
.is_superuser
is True or \
485 groups
.CORRESPONDANT_RH
in user_groupes
or \
486 groups
.DRH_NIVEAU_1
in user_groupes
or \
487 groups
.DRH_NIVEAU_2
in user_groupes
or \
488 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
489 groups
.ADMINISTRATEURS
in user_groupes
or \
490 groups
.HAUTE_DIRECTION
in user_groupes
:
494 def get_changelist(self
, request
, **kwargs
):
495 return OrderedChangeList
497 def queryset(self
, request
):
499 Spécifie un queryset limité, autrement Django exécute un
500 select_related() sans paramètre, ce qui a pour effet de charger tous
501 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
502 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
503 génération d'une requête infinie.
505 qs
= self
.model
._default_manager
.get_query_set() \
506 .select_related('offre_emploi') \
507 .annotate(moyenne
=Avg('evaluations__note'))
509 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
510 if groups
.DRH_NIVEAU_1
in user_groupes
or \
511 groups
.DRH_NIVEAU_2
in user_groupes
or \
512 groups
.HAUTE_DIRECTION
in user_groupes
:
515 if groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
516 groups
.CORRESPONDANT_RH
in user_groupes
or \
517 groups
.ADMINISTRATEURS
in user_groupes
:
518 employe
= groups
.get_employe_from_user(request
.user
)
519 return qs
.filter(offre_emploi__region
=employe
.implantation
.region
)
521 if Evaluateur
.objects
.filter(user
=request
.user
).exists():
522 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
523 candidat_ids
= [e
.candidat
.id for e
in
524 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
)]
525 return qs
.filter(id__in
=candidat_ids
)
529 class CandidatAdmin(VersionAdmin
, CandidatAdminMixin
):
533 class ProxyCandidatAdmin(CandidatAdminMixin
):
536 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
537 'situation_famille', 'nombre_dependant', 'telephone', 'email',
538 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
539 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
540 'domaine_professionnel', 'pieces_jointes'
544 'fields': ('offre_emploi', )
546 ('Informations personnelles', {
548 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille',
554 'telephone', 'email', 'adresse', 'ville', 'etat_province',
555 'code_postal', 'pays'
558 ('Informations professionnelles', {
560 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
561 'domaine_professionnel'
565 inlines
= (CandidatEvaluationInline
, )
567 def has_add_permission(self
, request
):
570 def has_delete_permission(self
, request
, obj
=None):
573 def has_change_permission(self
, request
, obj
=None):
574 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
575 if request
.user
.is_superuser
is True or \
576 groups
.CORRESPONDANT_RH
in user_groupes
or \
577 groups
.DRH_NIVEAU_1
in user_groupes
or \
578 groups
.DRH_NIVEAU_2
in user_groupes
or \
579 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
580 groups
.ADMINISTRATEURS
in user_groupes
or \
581 groups
.HAUTE_DIRECTION
in user_groupes
:
585 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
586 for e
in obj
.evaluations
.all():
587 if e
.evaluateur
== evaluateur
:
592 def get_actions(self
, request
):
596 class CandidatPieceAdmin(admin
.ModelAdmin
):
597 list_display
= ('nom', 'candidat', )
600 def queryset(self
, request
):
602 Spécifie un queryset limité, autrement Django exécute un
603 select_related() sans paramètre, ce qui a pour effet de charger tous
604 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
605 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
606 génération d'une requête infinie. Affiche la liste de candidats que
607 si le user connecté possède un Evaluateur
609 qs
= self
.model
._default_manager
.get_query_set()
610 return qs
.select_related('candidat')
613 class EvaluateurAdmin(BaseAdmin
, VersionAdmin
):
620 ### Actions à afficher
621 def get_actions(self
, request
):
622 actions
= super(EvaluateurAdmin
, self
).get_actions(request
)
623 del actions
['delete_selected']
626 ### Permissions add, delete, change
627 def has_add_permission(self
, request
):
628 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
629 if request
.user
.is_superuser
is True or \
630 groups
.DRH_NIVEAU_1
in user_groupes
or \
631 groups
.DRH_NIVEAU_2
in user_groupes
or \
632 groups
.HAUTE_DIRECTION
in user_groupes
:
636 def has_delete_permission(self
, request
, obj
=None):
637 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
638 if request
.user
.is_superuser
is True or \
639 groups
.DRH_NIVEAU_1
in user_groupes
or \
640 groups
.DRH_NIVEAU_2
in user_groupes
or \
641 groups
.HAUTE_DIRECTION
in user_groupes
:
645 def has_change_permission(self
, request
, obj
=None):
646 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
647 if request
.user
.is_superuser
is True or \
648 groups
.DRH_NIVEAU_1
in user_groupes
or \
649 groups
.DRH_NIVEAU_2
in user_groupes
or \
650 groups
.HAUTE_DIRECTION
in user_groupes
:
655 class CandidatEvaluationAdmin(BaseAdmin
):
656 search_fields
= ('candidat__nom', 'candidat__prenom')
658 '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
661 readonly_fields
= ('candidat', 'evaluateur')
662 list_filter
= ('candidat__statut', 'candidat__offre_emploi',)
664 ('Évaluation du candidat', {
665 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
669 def get_actions(self
, request
):
670 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
672 self
.evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
674 self
.evaluateur
= None
676 actions
= super(CandidatEvaluationAdmin
, self
).get_actions(request
)
677 del actions
['delete_selected']
681 def _note(self
, obj
):
683 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
684 un lien pour Évaluer le candidat.
685 Sinon afficher la note.
687 page
= self
.model
.__name__
.lower()
688 redirect_url
= 'admin:recrutement_%s_change' % page
691 label
= "Candidat non évalué"
695 if self
.evaluateur
== obj
.evaluateur
:
696 return "<a href='%s'>%s</a>" % (
697 reverse(redirect_url
, args
=(obj
.id,)), label
701 _note
.allow_tags
= True
702 _note
.short_description
= "Note"
703 _note
.admin_order_field
= 'note'
705 def _statut(self
, obj
):
706 return obj
.candidat
.get_statut_display()
707 _statut
.order_field
= 'candidat__statut'
708 _statut
.short_description
= 'Statut'
710 ### Lien en lecture seule vers le candidat
711 def _candidat(self
, obj
):
712 return "<a href='%s'>%s</a>" \
713 % (reverse('admin:recrutement_proxycandidat_change',
714 args
=(obj
.candidat
.id,)), obj
.candidat
)
715 _candidat
.allow_tags
= True
716 _candidat
.short_description
= 'Candidat'
718 ### Afficher commentaire
719 def _commentaire(self
, obj
):
721 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
722 dans le champ commentaire, Aucun au lieu de (None)
723 Sinon afficher la note.
725 if obj
.commentaire
is None:
727 return obj
.commentaire
728 _commentaire
.allow_tags
= True
729 _commentaire
.short_description
= "Commentaire"
731 ### Afficher offre d'emploi
732 def _offre_emploi(self
, obj
):
733 return "<a href='%s'>%s</a>" % \
734 (reverse('admin:recrutement_proxyoffreemploi_change',
735 args
=(obj
.candidat
.offre_emploi
.id,)), obj
.candidat
.offre_emploi
)
736 _offre_emploi
.allow_tags
= True
737 _offre_emploi
.short_description
= "Voir offre d'emploi"
739 def has_add_permission(self
, request
):
742 def has_delete_permission(self
, request
, obj
=None):
745 def has_change_permission(self
, request
, obj
=None):
747 Permettre la visualisation dans la changelist
748 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
751 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
753 if request
.user
.is_superuser
or \
754 groups
.CORRESPONDANT_RH
in user_groupes
or \
755 groups
.DRH_NIVEAU_1
in user_groupes
or \
756 groups
.DRH_NIVEAU_2
in user_groupes
or \
757 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
758 groups
.ADMINISTRATEURS
in user_groupes
or \
759 groups
.HAUTE_DIRECTION
in user_groupes
:
760 is_recrutement
= True
762 is_recrutement
= False
764 return is_recrutement
766 def queryset(self
, request
):
768 Afficher uniquement les évaluations de l'évaluateur, sauf si
769 l'utilisateur est dans les groupes suivants.
771 qs
= self
.model
._default_manager
.get_query_set() \
772 .select_related('offre_emploi')
773 user_groupes
= request
.user
.groups
.all()
774 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
776 if request
.user
.is_superuser
or \
777 groups
.CORRESPONDANT_RH
in user_groupes
or \
778 groups
.DRH_NIVEAU_1
in user_groupes
or \
779 groups
.DRH_NIVEAU_2
in user_groupes
or \
780 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
781 groups
.ADMINISTRATEURS
in user_groupes
or \
782 groups
.HAUTE_DIRECTION
in user_groupes
:
785 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
786 candidats_evaluations
= \
787 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
,
788 candidat__statut__in
=('REC', ))
789 candidats_evaluations_ids
= [ce
.id for ce
in candidats_evaluations
]
790 return qs
.filter(id__in
=candidats_evaluations_ids
)
793 class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin
):
795 def has_change_permission(self
, request
, obj
=None):
797 Evaluateur
.objects
.get(user
=request
.user
)
800 is_evaluateur
= False
802 if obj
is None and is_evaluateur
:
806 return request
.user
== obj
.evaluateur
.user
810 def queryset(self
, request
):
811 qs
= self
.model
._default_manager
.get_query_set() \
812 .select_related('offre_emploi')
813 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
814 candidats_evaluations
= \
815 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
,
816 candidat__statut__in
=('REC', ))
817 candidats_evaluations_ids
= [ce
.id for ce
in candidats_evaluations
]
818 return qs
.filter(id__in
=candidats_evaluations_ids
)
821 class CourrielTemplateAdmin(BaseAdmin
, VersionAdmin
):
822 ### Actions à afficher
823 def get_actions(self
, request
):
824 actions
= super(CourrielTemplateAdmin
, self
).get_actions(request
)
825 del actions
['delete_selected']
828 admin
.site
.register(OffreEmploi
, OffreEmploiAdmin
)
829 admin
.site
.register(ProxyOffreEmploi
, ProxyOffreEmploiAdmin
)
830 admin
.site
.register(Candidat
, CandidatAdmin
)
831 admin
.site
.register(ProxyCandidat
, ProxyCandidatAdmin
)
832 admin
.site
.register(CandidatEvaluation
, CandidatEvaluationAdmin
)
833 admin
.site
.register(MesCandidatEvaluation
, MesCandidatEvaluationAdmin
)
834 admin
.site
.register(Evaluateur
, EvaluateurAdmin
)
835 admin
.site
.register(CourrielTemplate
, CourrielTemplateAdmin
)