1 # -*- encoding: utf-8 -*-
5 from auf
.django
.emploi
.models
import CandidatPiece
, Candidat
, OffreEmploi
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
22 from project
.permissions
import get_user_groupnames
24 from project
.rh
import models
as rh
25 from project
.recrutement
.forms
import OffreEmploiForm
26 from project
.recrutement
.models
import \
27 Evaluateur
, CandidatEvaluation
, \
28 ProxyOffreEmploi
, ProxyCandidat
, MesCandidatEvaluation
, \
29 CourrielTemplate
, OffreEmploiEvaluateur
33 IMPLANTATIONS_CENTRALES
= [15, 19]
36 class BaseAdmin(admin
.ModelAdmin
):
40 'css/admin_custom.css',
41 'jquery-autocomplete/jquery.autocomplete.css',
44 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
45 'jquery-autocomplete/jquery.autocomplete.min.js',
49 class OrderedChangeList(admin
.views
.main
.ChangeList
):
51 Surcharge pour appliquer le order_by d'un annotate
53 def get_query_set(self
):
54 qs
= super(OrderedChangeList
, self
).get_query_set()
55 qs
= qs
.order_by('-moyenne')
59 class OffreEmploiAdminMixin(BaseAdmin
):
60 date_hierarchy
= 'date_creation'
62 'nom', 'date_limite', 'region', 'statut', 'est_affiche',
65 exclude
= ('actif', 'poste_nom', 'resume',)
66 list_filter
= ('statut',)
67 actions
= ['affecter_evaluateurs_offre_emploi', ]
68 form
= OffreEmploiForm
88 ### Actions à afficher
89 def get_actions(self
, request
):
90 actions
= super(OffreEmploiAdminMixin
, self
).get_actions(request
)
91 del actions
['delete_selected']
94 ### Affecter un évaluateurs à des offres d'emploi
95 def affecter_evaluateurs_offre_emploi(modeladmin
, obj
, candidats
):
96 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
98 return HttpResponseRedirect(
99 reverse('affecter_evaluateurs_offre_emploi') +
100 "?ids=%s" % (",".join(selected
))
103 affecter_evaluateurs_offre_emploi
.short_description
= \
104 u
'Affecter évaluateur(s)'
106 ### Afficher la liste des candidats pour l'offre d'emploi
107 def _candidatsList(self
, obj
):
108 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
109 </a>" % (reverse('admin:recrutement_proxycandidat_changelist'), obj
.id)
110 _candidatsList
.allow_tags
= True
111 _candidatsList
.short_description
= "Afficher la liste des candidats"
114 def get_form(self
, request
, obj
=None, **kwargs
):
115 form
= super(OffreEmploiAdminMixin
, self
).get_form(request
, obj
, **kwargs
)
116 employe
= groups
.get_employe_from_user(request
.user
)
117 user_groupes
= get_user_groupnames(request
.user
)
121 if 'region' in form
.declared_fields
.keys():
122 region_field
= form
.declared_fields
['region']
123 if 'region' in form
.base_fields
.keys():
124 region_field
= form
.base_fields
['region']
126 if groups
.DRH_NIVEAU_1
in user_groupes
or \
127 groups
.DRH_NIVEAU_2
in user_groupes
or \
128 groups
.HAUTE_DIRECTION
in user_groupes
:
129 region_field
.queryset
= Region
.objects
.all()
131 region_field
.queryset
= Region
.objects
.\
132 filter(id=employe
.implantation
.region
.id)
136 if 'poste' in form
.declared_fields
.keys():
137 poste_field
= form
.declared_fields
['poste']
138 if 'poste' in form
.base_fields
.keys():
139 poste_field
= form
.base_fields
['poste']
141 if groups
.DRH_NIVEAU_1
in user_groupes
or \
142 groups
.DRH_NIVEAU_2
in user_groupes
or \
143 groups
.HAUTE_DIRECTION
in user_groupes
:
144 poste_field
.queryset
= rh
.Poste
.objects
.all()
146 poste_field
.queryset
= rh
.Poste
.objects
.\
147 filter(implantation__region
=employe
.implantation
.region
).\
148 exclude(implantation__in
=IMPLANTATIONS_CENTRALES
)
152 if 'bureau' in form
.declared_fields
.keys():
153 bureau_field
= form
.declared_fields
['bureau']
154 if 'bureau' in form
.base_fields
.keys():
155 bureau_field
= form
.base_fields
['bureau']
157 if groups
.DRH_NIVEAU_1
in user_groupes
or \
158 groups
.DRH_NIVEAU_2
in user_groupes
or \
159 groups
.HAUTE_DIRECTION
in user_groupes
:
160 bureau_field
.queryset
= Bureau
.objects
.all()
162 bureau_field
.queryset
= \
163 Bureau
.objects
.filter(region
=employe
.implantation
.region
)
169 def queryset(self
, request
):
170 qs
= self
.model
._default_manager
.get_query_set() \
171 .select_related('offre_emploi')
172 user_groupes
= get_user_groupnames(request
.user
)
173 if groups
.DRH_NIVEAU_1
in user_groupes
or \
174 groups
.DRH_NIVEAU_2
in user_groupes
or \
175 groups
.HAUTE_DIRECTION
in user_groupes
:
178 if groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
179 groups
.CORRESPONDANT_RH
in user_groupes
or \
180 groups
.ADMINISTRATEURS
in user_groupes
:
181 employe
= groups
.get_employe_from_user(request
.user
)
182 return qs
.filter(region
=employe
.implantation
.region
)
184 if Evaluateur
.objects
.filter(user
=request
.user
).exists():
185 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
187 e
.candidat
.offre_emploi_id
188 for e
in CandidatEvaluation
.objects
189 .select_related('candidat')
190 .filter(evaluateur
=evaluateur
)
192 return qs
.filter(id__in
=offre_ids
)
196 ### Permission add, delete, change
197 def has_add_permission(self
, request
):
198 user_groupes
= get_user_groupnames(request
.user
)
199 if request
.user
.is_superuser
is True or \
200 groups
.DRH_NIVEAU_1
in user_groupes
or \
201 groups
.DRH_NIVEAU_2
in user_groupes
or \
202 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
203 groups
.ADMINISTRATEURS
in user_groupes
or \
204 groups
.HAUTE_DIRECTION
in user_groupes
:
208 def has_delete_permission(self
, request
, obj
=None):
209 user_groupes
= get_user_groupnames(request
.user
)
210 if request
.user
.is_superuser
is True or \
211 groups
.DRH_NIVEAU_1
in user_groupes
or \
212 groups
.DRH_NIVEAU_2
in user_groupes
or \
213 groups
.HAUTE_DIRECTION
in user_groupes
:
217 employe
= groups
.get_employe_from_user(request
.user
)
218 if (groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
219 groups
.ADMINISTRATEURS
in user_groupes
) and (
220 employe
.implantation
.region
== obj
.lieu_affectation
.region
):
225 def has_change_permission(self
, request
, obj
=None):
226 user_groupes
= get_user_groupnames(request
.user
)
227 if request
.user
.is_superuser
is True or \
228 groups
.DRH_NIVEAU_1
in user_groupes
or \
229 groups
.DRH_NIVEAU_2
in user_groupes
or \
230 groups
.HAUTE_DIRECTION
in user_groupes
:
234 employe
= groups
.get_employe_from_user(request
.user
)
235 if (groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
236 groups
.ADMINISTRATEURS
in user_groupes
) and (
237 employe
.implantation
.region
== obj
.lieu_affectation
.region
):
240 if groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
241 groups
.ADMINISTRATEURS
in user_groupes
:
247 def formfield_for_foreignkey(self
, db_field
, request
, **kwargs
):
248 if db_field
.name
== 'lieu_affectation':
249 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
250 if not (request
.user
.is_superuser
is True or \
251 groups
.DRH_NIVEAU_1
in user_groupes
or \
252 groups
.DRH_NIVEAU_2
in user_groupes
):
253 employe
= groups
.get_employe_from_user(request
.user
)
254 kwargs
["queryset"] = Implantation
.objects
.filter(region
=employe
.implantation
.region
)
255 return db_field
.formfield(**kwargs
)
256 return super(OffreEmploiAdminMixin
, self
).formfield_for_foreignkey(db_field
, request
, **kwargs
)
259 class OffreEmploiAdmin(VersionAdmin
, OffreEmploiAdminMixin
):
263 class ProxyOffreEmploiAdmin(OffreEmploiAdminMixin
):
265 'nom', 'date_limite', 'region', 'statut', 'est_affiche'
268 'description', 'bureau', 'duree_affectation', 'renumeration',
269 'debut_affectation', 'lieu_affectation', 'nom', 'resume',
270 'date_limite', 'region', 'poste'
276 ('Description générale', {
277 'fields': ('description', 'date_limite',)
280 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
284 'debut_affectation', 'duree_affectation', 'renumeration',
290 ### Lieu de redirection après le change
291 def response_change(self
, request
, obj
):
292 return redirect('admin:recrutement_proxyoffreemploi_changelist')
294 ### Permissions add, delete, change
295 def has_add_permission(self
, request
):
298 def has_delete_permission(self
, request
, obj
=None):
301 def has_change_permission(self
, request
, obj
=None):
305 return not super(ProxyOffreEmploiAdmin
, self
).has_change_permission(request
, obj
)
308 class CandidatPieceInline(admin
.TabularInline
):
309 model
= CandidatPiece
310 fields
= ('candidat', 'nom', 'path',)
315 class ReadOnlyCandidatPieceInline(CandidatPieceInline
):
316 readonly_fields
= ('candidat', 'nom', 'path', )
320 class CandidatEvaluationInlineFormSet(BaseInlineFormSet
):
322 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
324 def __init__(self
, *args
, **kwargs
):
325 super(CandidatEvaluationInlineFormSet
, self
).__init__(*args
, **kwargs
)
326 self
.can_delete
= False
329 class CandidatEvaluationInline(admin
.TabularInline
):
330 model
= CandidatEvaluation
331 fields
= ('evaluateur', 'note', 'commentaire')
334 formset
= CandidatEvaluationInlineFormSet
337 def get_readonly_fields(self
, request
, obj
=None):
339 Empêche la modification des évaluations
342 return self
.readonly_fields
+ ('evaluateur', 'note', 'commentaire')
343 return self
.readonly_fields
346 class CandidatAdminMixin(BaseAdmin
, ExportAdmin
):
347 search_fields
= ('nom', 'prenom')
348 exclude
= ('actif', )
349 list_editable
= ('statut', )
350 list_display
= ('_candidat', 'offre_emploi',
351 'voir_offre_emploi', 'calculer_moyenne',
352 'afficher_candidat', '_date_creation', 'statut', )
353 list_filter
= ('offre_emploi__nom', 'offre_emploi__region', 'statut', )
357 'fields': ('offre_emploi', )
359 ('Informations personnelles', {
361 'nom', 'prenom', 'genre', 'nationalite',
362 'situation_famille', 'nombre_dependant'
367 'telephone', 'email', 'adresse', 'ville', 'etat_province',
368 'code_postal', 'pays'
371 ('Informations professionnelles', {
373 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
374 'domaine_professionnel'
378 'fields': ('statut', )
383 CandidatEvaluationInline
,
385 actions
= ['envoyer_courriel_candidats', 'changer_statut']
387 export_fields
= ['statut', 'offre_emploi', 'prenom', 'nom', 'genre',
388 'nationalite', 'situation_famille', 'nombre_dependant',
389 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
390 'domaine_professionnel', 'telephone', 'email', 'adresse',
391 'ville', 'etat_province', 'code_postal', 'pays']
393 def _candidat(self
, obj
):
394 txt
= u
"%s %s (%s)" % (obj
.nom
.upper(), obj
.prenom
, obj
.genre
)
395 txt
= textwrap
.wrap(txt
, 30)
396 return "<br/>".join(txt
)
397 _candidat
.short_description
= "Candidat"
398 _candidat
.admin_order_field
= "nom"
399 _candidat
.allow_tags
= True
401 def _date_creation(self
, obj
):
402 return obj
.date_creation
403 _date_creation
.admin_order_field
= "date_creation"
404 _date_creation
.short_description
= "Date de réception"
406 ### Actions à afficher
407 def get_actions(self
, request
):
408 actions
= super(CandidatAdminMixin
, self
).get_actions(request
)
409 del actions
['delete_selected']
412 ### Envoyer un courriel à des candidats
413 def envoyer_courriel_candidats(modeladmin
, obj
, candidats
):
414 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
416 return HttpResponseRedirect(
417 reverse('selectionner_template') + "?ids=%s" % (",".join(selected
))
419 envoyer_courriel_candidats
.short_description
= u
'Envoyer courriel'
421 ### Changer le statut à des candidats
422 def changer_statut(modeladmin
, request
, queryset
):
423 if request
.POST
.get('post'):
424 queryset
.update(statut
=request
.POST
.get('statut'))
428 'action_checkbox_name': admin
.helpers
.ACTION_CHECKBOX_NAME
,
429 'queryset': queryset
,
430 'status': STATUT_CHOICES
,
433 return render_to_response("recrutement/selectionner_statut.html",
434 context
, context_instance
= RequestContext(request
))
436 changer_statut
.short_description
= u
'Changer statut'
438 ### Évaluer un candidat
439 def evaluer_candidat(self
, obj
):
440 return "<a href='%s?candidat__id__exact=%s'>" \
441 "Évaluer le candidat</a>" % (
442 reverse('admin:recrutement_candidatevaluation_changelist'),
445 evaluer_candidat
.allow_tags
= True
446 evaluer_candidat
.short_description
= 'Évaluation'
448 ### Afficher un candidat
449 def afficher_candidat(self
, obj
):
450 items
= [u
"<li><a href='%s%s'>%s</li>" % \
451 (settings
.OE_PRIVE_MEDIA_URL
, pj
.path
, pj
.get_nom_display()) \
452 for pj
in obj
.pieces_jointes()]
453 html
= "<a href='%s'>Candidature</a>" % (
454 reverse('admin:recrutement_proxycandidat_change', args
=(obj
.id,))
456 return "%s<ul>%s</ul>" % (html
, "\n".join(items
))
457 afficher_candidat
.allow_tags
= True
458 afficher_candidat
.short_description
= u
'Détails du candidat'
460 ### Voir l'offre d'emploi
461 def voir_offre_emploi(self
, obj
):
462 return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse(
463 'admin:recrutement_proxyoffreemploi_change',
464 args
=(obj
.offre_emploi
.id,)
466 voir_offre_emploi
.allow_tags
= True
467 voir_offre_emploi
.short_description
= "Afficher l'offre d'emploi"
469 ### Calculer la moyenne des notes
470 def calculer_moyenne(self
, obj
):
471 evaluations
= CandidatEvaluation
.objects
.filter(candidat
=obj
)
473 notes
= [evaluation
.note
for evaluation
in evaluations \
474 if evaluation
.note
is not None]
477 moyenne_votes
= round(float(sum(notes
)) / len(notes
), 2)
479 moyenne_votes
= "Non disponible"
481 totales
= len(evaluations
)
484 if obj
.statut
== 'REC':
485 if totales
== faites
:
487 elif faites
> 0 and float(totales
) / float(faites
) >= 2:
494 return """<span style="color: %s;">%s (%s/%s)</span>""" % (
495 color
, moyenne_votes
, faites
, totales
497 calculer_moyenne
.allow_tags
= True
498 calculer_moyenne
.short_description
= "Moyenne"
499 calculer_moyenne
.admin_order_field
= ""
501 ### Permissions add, delete, change
502 def has_add_permission(self
, request
):
503 user_groupes
= get_user_groupnames(request
.user
)
504 if request
.user
.is_superuser
is True or \
505 groups
.CORRESPONDANT_RH
in user_groupes
or \
506 groups
.DRH_NIVEAU_1
in user_groupes
or \
507 groups
.DRH_NIVEAU_2
in user_groupes
or \
508 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
509 groups
.ADMINISTRATEURS
in user_groupes
or \
510 groups
.HAUTE_DIRECTION
in user_groupes
:
514 def has_delete_permission(self
, request
, obj
=None):
515 user_groupes
= get_user_groupnames(request
.user
)
516 if request
.user
.is_superuser
is True or \
517 groups
.CORRESPONDANT_RH
in user_groupes
or \
518 groups
.DRH_NIVEAU_1
in user_groupes
or \
519 groups
.DRH_NIVEAU_2
in user_groupes
or \
520 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
521 groups
.ADMINISTRATEURS
in user_groupes
or \
522 groups
.HAUTE_DIRECTION
in user_groupes
:
526 def has_change_permission(self
, request
, obj
=None):
527 user_groupes
= get_user_groupnames(request
.user
)
528 if request
.user
.is_superuser
is True or \
529 groups
.CORRESPONDANT_RH
in user_groupes
or \
530 groups
.DRH_NIVEAU_1
in user_groupes
or \
531 groups
.DRH_NIVEAU_2
in user_groupes
or \
532 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
533 groups
.ADMINISTRATEURS
in user_groupes
or \
534 groups
.HAUTE_DIRECTION
in user_groupes
:
538 def formfield_for_foreignkey(self
, db_field
, request
, **kwargs
):
539 if db_field
.name
== 'offre_emploi':
540 employe
= groups
.get_employe_from_user(request
.user
)
541 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
542 if request
.user
.is_superuser
is True or \
543 groups
.CORRESPONDANT_RH
in user_groupes
or \
544 groups
.DRH_NIVEAU_1
in user_groupes
or \
545 groups
.DRH_NIVEAU_2
in user_groupes
:
546 qs_offres
= OffreEmploi
.objects
.all()
548 qs_offres
=OffreEmploi
.objects
.filter(region
=employe
.implantation
.region
)
549 kwargs
["queryset"] = qs_offres
550 return db_field
.formfield(**kwargs
)
551 return super(CandidatAdminMixin
, self
).formfield_for_foreignkey(db_field
, request
, **kwargs
)
553 # def get_changelist(self, request, **kwargs):
554 # return OrderedChangeList
556 def queryset(self
, request
):
558 Spécifie un queryset limité, autrement Django exécute un
559 select_related() sans paramètre, ce qui a pour effet de charger tous
560 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
561 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
562 génération d'une requête infinie.
564 qs
= self
.model
._default_manager
.get_query_set() \
565 .select_related('offre_emploi') \
566 .annotate(moyenne
=Avg('evaluations__note'))
568 user_groupes
= get_user_groupnames(request
.user
)
569 if groups
.DRH_NIVEAU_1
in user_groupes
or \
570 groups
.DRH_NIVEAU_2
in user_groupes
or \
571 groups
.HAUTE_DIRECTION
in user_groupes
:
574 if groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
575 groups
.CORRESPONDANT_RH
in user_groupes
or \
576 groups
.ADMINISTRATEURS
in user_groupes
:
577 employe
= groups
.get_employe_from_user(request
.user
)
578 return qs
.filter(offre_emploi__region
=employe
.implantation
.region
)
580 if Evaluateur
.objects
.filter(user
=request
.user
).exists():
581 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
582 candidat_ids
= [e
.candidat
.id for e
in
583 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
)]
584 return qs
.filter(id__in
=candidat_ids
)
588 class CandidatAdmin(VersionAdmin
, CandidatAdminMixin
):
589 change_list_template
= 'admin/recrutement/candidat/change_list.html'
593 class ProxyCandidatAdmin(CandidatAdminMixin
):
594 change_list_template
= 'admin/recrutement/candidat/change_list.html'
597 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
598 'situation_famille', 'nombre_dependant', 'telephone', 'email',
599 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
600 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
601 'domaine_professionnel', 'pieces_jointes'
605 'fields': ('offre_emploi', )
607 ('Informations personnelles', {
609 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille',
615 'telephone', 'email', 'adresse', 'ville', 'etat_province',
616 'code_postal', 'pays'
619 ('Informations professionnelles', {
621 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
622 'domaine_professionnel'
626 inlines
= (CandidatEvaluationInline
, )
628 def has_add_permission(self
, request
):
631 def has_delete_permission(self
, request
, obj
=None):
634 def has_change_permission(self
, request
, obj
=None):
636 return obj
in self
.queryset(request
)
638 # evaluateur = Evaluateur.objects.get(user=request.user)
639 # for e in obj.evaluations.all():
640 # if e.evaluateur == evaluateur:
645 return super(ProxyCandidatAdmin
, self
).has_change_permission(request
, obj
)
647 def get_actions(self
, request
):
651 class CandidatPieceAdmin(admin
.ModelAdmin
):
652 list_display
= ('nom', 'candidat', )
655 def queryset(self
, request
):
657 Spécifie un queryset limité, autrement Django exécute un
658 select_related() sans paramètre, ce qui a pour effet de charger tous
659 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
660 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
661 génération d'une requête infinie. Affiche la liste de candidats que
662 si le user connecté possède un Evaluateur
664 qs
= self
.model
._default_manager
.get_query_set()
665 return qs
.select_related('candidat')
668 class EvaluateurAdmin(BaseAdmin
, VersionAdmin
):
675 ### Actions à afficher
676 def get_actions(self
, request
):
677 actions
= super(EvaluateurAdmin
, self
).get_actions(request
)
678 del actions
['delete_selected']
681 ### Permissions add, delete, change
682 def has_add_permission(self
, request
):
683 user_groupes
= get_user_groupnames(request
.user
)
684 if request
.user
.is_superuser
is True or \
685 groups
.DRH_NIVEAU_1
in user_groupes
or \
686 groups
.DRH_NIVEAU_2
in user_groupes
or \
687 groups
.HAUTE_DIRECTION
in user_groupes
:
691 def has_delete_permission(self
, request
, obj
=None):
692 user_groupes
= get_user_groupnames(request
.user
)
693 if request
.user
.is_superuser
is True or \
694 groups
.DRH_NIVEAU_1
in user_groupes
or \
695 groups
.DRH_NIVEAU_2
in user_groupes
or \
696 groups
.HAUTE_DIRECTION
in user_groupes
:
700 def has_change_permission(self
, request
, obj
=None):
701 user_groupes
= get_user_groupnames(request
.user
)
702 if request
.user
.is_superuser
is True or \
703 groups
.DRH_NIVEAU_1
in user_groupes
or \
704 groups
.DRH_NIVEAU_2
in user_groupes
or \
705 groups
.HAUTE_DIRECTION
in user_groupes
:
710 class CandidatEvaluationAdmin(BaseAdmin
):
711 search_fields
= ('candidat__nom', 'candidat__prenom')
713 '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
716 readonly_fields
= ('candidat', 'evaluateur')
717 list_filter
= ('candidat__statut', 'candidat__offre_emploi',)
719 ('Évaluation du candidat', {
720 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
724 def get_actions(self
, request
):
725 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
727 self
.evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
729 self
.evaluateur
= None
731 actions
= super(CandidatEvaluationAdmin
, self
).get_actions(request
)
732 del actions
['delete_selected']
736 def _note(self
, obj
):
738 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
739 un lien pour Évaluer le candidat.
740 Sinon afficher la note.
742 page
= self
.model
.__name__
.lower()
743 redirect_url
= 'admin:recrutement_%s_change' % page
746 label
= "Candidat non évalué"
750 if self
.evaluateur
== obj
.evaluateur
:
751 return "<a href='%s'>%s</a>" % (
752 reverse(redirect_url
, args
=(obj
.id,)), label
756 _note
.allow_tags
= True
757 _note
.short_description
= "Note"
758 _note
.admin_order_field
= 'note'
760 def _statut(self
, obj
):
761 return obj
.candidat
.get_statut_display()
762 _statut
.order_field
= 'candidat__statut'
763 _statut
.short_description
= 'Statut'
765 ### Lien en lecture seule vers le candidat
766 def _candidat(self
, obj
):
767 return "<a href='%s'>%s</a>" \
768 % (reverse('admin:recrutement_proxycandidat_change',
769 args
=(obj
.candidat
.id,)), obj
.candidat
)
770 _candidat
.allow_tags
= True
771 _candidat
.short_description
= 'Candidat'
773 ### Afficher commentaire
774 def _commentaire(self
, obj
):
776 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
777 dans le champ commentaire, Aucun au lieu de (None)
778 Sinon afficher la note.
780 if obj
.commentaire
is None:
782 return obj
.commentaire
783 _commentaire
.allow_tags
= True
784 _commentaire
.short_description
= "Commentaire"
786 ### Afficher offre d'emploi
787 def _offre_emploi(self
, obj
):
788 return "<a href='%s'>%s</a>" % \
789 (reverse('admin:recrutement_proxyoffreemploi_change',
790 args
=(obj
.candidat
.offre_emploi
.id,)), obj
.candidat
.offre_emploi
)
791 _offre_emploi
.allow_tags
= True
792 _offre_emploi
.short_description
= "Voir offre d'emploi"
794 def has_add_permission(self
, request
):
797 def has_delete_permission(self
, request
, obj
=None):
800 def has_change_permission(self
, request
, obj
=None):
802 Permettre la visualisation dans la changelist
803 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
806 user_groupes
= get_user_groupnames(request
.user
)
808 if request
.user
.is_superuser
or \
809 groups
.CORRESPONDANT_RH
in user_groupes
or \
810 groups
.DRH_NIVEAU_1
in user_groupes
or \
811 groups
.DRH_NIVEAU_2
in user_groupes
or \
812 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
813 groups
.ADMINISTRATEURS
in user_groupes
or \
814 groups
.HAUTE_DIRECTION
in user_groupes
:
815 is_recrutement
= True
817 is_recrutement
= False
819 return is_recrutement
821 def queryset(self
, request
):
823 Afficher uniquement les évaluations de l'évaluateur, sauf si
824 l'utilisateur est dans les groupes suivants.
826 qs
= self
.model
._default_manager
.get_query_set() \
827 .select_related('offre_emploi')
828 user_groupes
= get_user_groupnames(request
.user
)
830 if request
.user
.is_superuser
or \
831 groups
.CORRESPONDANT_RH
in user_groupes
or \
832 groups
.DRH_NIVEAU_1
in user_groupes
or \
833 groups
.DRH_NIVEAU_2
in user_groupes
or \
834 groups
.DIRECTEUR_DE_BUREAU
in user_groupes
or \
835 groups
.ADMINISTRATEURS
in user_groupes
or \
836 groups
.HAUTE_DIRECTION
in user_groupes
:
837 return qs
.filter(candidat__statut__in
=('REC', 'SEL'))
839 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
840 candidats_evaluations
= \
841 CandidatEvaluation
.objects
.filter(evaluateur
=evaluateur
,
842 candidat__statut__in
=('REC', ))
843 candidats_evaluations_ids
= [ce
.id for ce
in candidats_evaluations
]
844 return qs
.filter(id__in
=candidats_evaluations_ids
)
847 class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin
):
850 def has_change_permission(self
, request
, obj
=None):
852 Evaluateur
.objects
.get(user
=request
.user
)
855 is_evaluateur
= False
857 if obj
is None and is_evaluateur
:
861 return request
.user
== obj
.evaluateur
.user
865 def queryset(self
, request
):
866 qs
= self
.model
._default_manager
.get_query_set() \
867 .select_related('offre_emploi')
868 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
870 # XXX: Pas l'idéal, mais on doit créer les objets CandidatEvaluation
871 # ici pour garder la liste à jour. Idéalement, il vaudrait peut-être
872 # mieux utiliser directement les objets Candidat.
873 for candidat
in Candidat
.objects
.filter(
874 offre_emploi__offreemploievaluateur__evaluateur
=evaluateur
,
875 offre_emploi__statut__in
=('AFFI', 'EVAL', 'ENTR')
876 ).exclude(evaluations__evaluateur
=evaluateur
):
877 CandidatEvaluation
.objects
.get_or_create(
878 candidat
=candidat
, evaluateur
=evaluateur
882 evaluateur
=evaluateur
, candidat__statut__in
=('NOUV', 'REC')
886 class OffreEmploiEvaluateurAdmin(BaseAdmin
):
890 class CourrielTemplateAdmin(BaseAdmin
, VersionAdmin
):
891 ### Actions à afficher
892 def get_actions(self
, request
):
893 actions
= super(CourrielTemplateAdmin
, self
).get_actions(request
)
894 del actions
['delete_selected']
897 admin
.site
.register(OffreEmploi
, OffreEmploiAdmin
)
898 admin
.site
.register(ProxyOffreEmploi
, ProxyOffreEmploiAdmin
)
899 admin
.site
.register(Candidat
, CandidatAdmin
)
900 admin
.site
.register(ProxyCandidat
, ProxyCandidatAdmin
)
901 admin
.site
.register(CandidatEvaluation
, CandidatEvaluationAdmin
)
902 admin
.site
.register(MesCandidatEvaluation
, MesCandidatEvaluationAdmin
)
903 admin
.site
.register(Evaluateur
, EvaluateurAdmin
)
904 admin
.site
.register(CourrielTemplate
, CourrielTemplateAdmin
)
905 admin
.site
.register(OffreEmploiEvaluateur
, OffreEmploiEvaluateurAdmin
)