1 # -*- encoding: utf-8 -*-
3 from django
.core
.urlresolvers
import reverse
4 from django
.http
import HttpResponseRedirect
5 from django
.contrib
import admin
6 from django
.shortcuts
import get_object_or_404
8 from reversion
.admin
import VersionAdmin
9 from datamaster_modeles
.models
import Employe
, Implantation
, Region
11 from recrutement
.models
import *
12 from recrutement
.workflow
import grp_administrateurs_recrutement
,\
13 grp_evaluateurs_recrutement
, grp_drh_recrutement
15 class OffreEmploiAdmin(VersionAdmin
):
16 date_hierarchy
= 'date_creation'
17 list_display
= ('nom', 'resume', 'date_limite', 'region', 'statut',
18 'est_affiche', '_candidatsList')
19 list_filter
= ('statut', 'est_affiche', )
20 actions
= ['affecter_evaluateurs_offre_emploi', ]
21 # Affecter un évaluateurs à des offres d'emploi
22 def affecter_evaluateurs_offre_emploi(modeladmin
, obj
, candidats
):
23 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
25 return HttpResponseRedirect(reverse('affecter_evaluateurs_offre_emploi')+
26 "?ids=%s" % (",".join(selected
)))
27 affecter_evaluateurs_offre_emploi
.short_description
= u
'Affecter évaluateur(s)'
29 # Afficher la liste des candidats pour l'offre d'emploi
30 def _candidatsList(self
, obj
):
31 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
32 </a>" % (reverse('admin:recrutement_candidat_changelist'), obj
.id)
33 _candidatsList
.allow_tags
= True
34 _candidatsList
.short_description
= "Afficher la liste des candidats"
37 def queryset(self
, request
):
38 qs
= self
.model
._default_manager
.get_query_set()
39 # Si user est superuser afficher toutes les offres d'emploi
40 user_groupes
= request
.user
.groups
.all()
41 if not grp_drh_recrutement
in user_groupes
:
43 Si le user n'est ni un évaluateur ni un administrateur régional,
47 if grp_evaluateurs_recrutement
in user_groupes
:
49 user
= Evaluateur
.objects
.get(user
=request
.user
)
50 except Evaluateur
.DoesNotExist
:
52 elif grp_administrateurs_recrutement
in user_groupes
:
54 user
= AdministrateurRegional
.objects
.get(user
=request
.user
)
55 except AdministrateurRegional
.DoesNotExist
:
60 if type(user
) is AdministrateurRegional
:
61 region_ids
= [g
.id for g
in user
.regions
.all()]
62 return qs
.select_related('offre_emploi').\
63 filter(region__in
=region_ids
)
64 if type(user
) is Evaluateur
:
65 candidats
= [g
for g
in user
.candidats
.all()]
66 offre_emploi_ids
= [c
.offre_emploi
.id for c
in candidats
]
67 return qs
.select_related('offre_emploi').\
68 filter(id__in
=offre_emploi_ids
)
70 return qs
.select_related('offre_emploi')
72 def has_change_permission(self
, request
, obj
=None):
73 user_groupes
= request
.user
.groups
.all()
74 if grp_drh_recrutement
in user_groupes
or \
75 grp_administrateurs_recrutement
in user_groupes
:
79 class ProxyOffreEmploiAdmin(OffreEmploiAdmin
):
80 list_display
= ('nom', 'resume', 'date_limite', 'region', 'statut',
82 readonly_fields
= ('description', 'poste', 'bureau',
83 'duree_affectation', 'renumeration',
84 'debut_affectation', 'lieu_affectation', 'nom',
85 'resume', 'date_limite', 'region')
90 ('Description générale', {
91 'fields': ('poste', 'resume','description', 'date_limite', )
94 'fields': ('lieu_affectation', 'bureau', 'region', )
97 'fields': ('debut_affectation', 'duree_affectation',
101 def has_add_permission(self
, request
):
104 def has_delete_permission(self
, request
, obj
=None):
107 def has_change_permission(self
, request
, obj
=None):
108 user_groupes
= request
.user
.groups
.all()
109 if grp_evaluateurs_recrutement
in user_groupes
or \
110 grp_drh_recrutement
in user_groupes
:
114 class ProxyCandidatPiece(CandidatPiece
):
116 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
121 verbose_name
= "pièce jointe"
122 verbose_name_plural
= "pièces jointes"
124 class CandidatPieceInline(admin
.TabularInline
):
125 model
= ProxyCandidatPiece
126 fields
= ('candidat', 'nom', 'path', )
129 class ProxyEvaluateur(Evaluateur
.candidats
.through
):
131 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
136 verbose_name
= "évaluateur"
138 class EvaluateurInline(admin
.TabularInline
):
139 model
= ProxyEvaluateur
140 fields
= ('evaluateur',)
143 class CandidatAdmin(VersionAdmin
):
144 date_hierarchy
= 'date_creation'
145 list_display
= ('nom', 'prenom', 'offre_emploi','statut',
146 'voir_offre_emploi', 'calculer_moyenne',
147 'afficher_candidat',)
148 list_filter
= ('offre_emploi', )
151 'fields': ('offre_emploi', )
153 ('Informations personnelles', {
154 'fields': ('prenom','nom','genre', 'nationalite',
155 'situation_famille', 'nombre_dependant',)
158 'fields': ('telephone', 'email', 'adresse', 'ville',
159 'etat_province', 'code_postal', 'pays', )
161 ('Informations professionnelles', {
162 'fields': ('niveau_diplome','employeur_actuel',
163 'poste_actuel', 'domaine_professionnel',)
166 'fields': ('statut', )
174 actions
= ['affecter_candidats_evaluateur', 'envoyer_courriel_candidats']
175 # Affecter un évaluateurs à des candidats
176 def affecter_candidats_evaluateur(modeladmin
, obj
, candidats
):
177 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
179 return HttpResponseRedirect(reverse('affecter_evaluateurs_candidats')+
180 "?ids=%s" % (",".join(selected
)))
181 affecter_candidats_evaluateur
.short_description
= u
'Affecter évaluateur(s)'
183 # Envoyer un courriel à des candidats
184 def envoyer_courriel_candidats(modeladmin
, obj
, candidats
):
185 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
187 return HttpResponseRedirect(reverse('selectionner_template')+
188 "?ids=%s" % (",".join(selected
)))
189 envoyer_courriel_candidats
.short_description
= u
'Envoyer courriel'
191 # Évaluer un candidat
192 def evaluer_candidat(self
, obj
):
193 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat</a>" % \
194 (reverse('admin:recrutement_candidatevaluation_changelist'),
196 evaluer_candidat
.allow_tags
= True
197 evaluer_candidat
.short_description
= 'Évaluation'
199 # Afficher un candidat
200 def afficher_candidat(self
, obj
):
201 return "<a href='%s'>Voir le candidat</a>" % \
202 (reverse('admin:recrutement_proxycandidat_change', args
=(obj
.id,)))
203 afficher_candidat
.allow_tags
= True
204 afficher_candidat
.short_description
= u
'Afficher les détails du candidat'
206 # Voir l'offre d'emploi
207 def voir_offre_emploi(self
, obj
):
208 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
209 (reverse('admin:recrutement_proxyoffreemploi_change',
210 args
=(obj
.offre_emploi
.id,)))
211 voir_offre_emploi
.allow_tags
= True
212 voir_offre_emploi
.short_description
= "Afficher l'offre d'emploi"
214 # Calculer la moyenne des notes
215 def calculer_moyenne(self
, obj
):
216 evaluations
= CandidatEvaluation
.objects
.filter(candidat
=obj
)
217 offre_emploi
= obj
.offre_emploi
219 notes
= [evaluation
.note
for evaluation
in evaluations
.all() \
220 if evaluation
.note
is not None]
222 if len(notes
) > 0 and offre_emploi
.date_limite
<= datetime
.date
.today():
223 moyenne_votes
= float(sum(notes
)) / len(notes
)
225 moyenne_votes
= "Non disponible"
227 calculer_moyenne
.allow_tags
= True
228 calculer_moyenne
.short_description
= "Moyenne des notes"
230 def add_delete_permission(self
, request
, obj
=None) :
231 user_groupes
= request
.user
.groups
.all()
232 if grp_drh_recrutement
in user_groupes
or \
233 grp_administrateurs_recrutement
in user_groupes
:
237 def has_add_permission(self
, request
):
238 return self
.add_delete_permission(request
, request
)
240 def has_delete_permission(self
, request
, obj
=None):
241 return self
.add_delete_permission(request
, request
)
243 def has_change_permission(self
, request
, obj
=None):
244 user_groupes
= request
.user
.groups
.all()
245 if grp_drh_recrutement
in user_groupes
or \
246 grp_administrateurs_recrutement
in user_groupes
:
250 def queryset(self
, obj
):
252 Spécifie un queryset limité, autrement Django exécute un
253 select_related() sans paramètre, ce qui a pour effet de charger tous
254 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
255 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
256 génération d'une requête infinie.
259 qs
= self
.model
._default_manager
.get_query_set()
260 # Si user est superuser afficher tous les candidats
261 user_groupes
= obj
.user
.groups
.all()
262 if not grp_drh_recrutement
in user_groupes
:
263 # Si le user n'est ni un évaluateur ni un administrateur régional,
267 if grp_evaluateurs_recrutement
in user_groupes
:
269 user
= Evaluateur
.objects
.get(user
=obj
.user
)
270 except Evaluateur
.DoesNotExist
:
273 elif grp_administrateurs_recrutement in user_groupes:
275 user = AdministrateurRegional.objects.get(user=obj.user)
276 except AdministrateurRegional.DoesNotExist:
281 ids
= [c
.id for c
in user
.candidats
.all()]
282 return qs
.select_related('candidats').filter(id__in
=ids
)
283 return qs
.select_related('candidats')
285 class ProxyCandidatAdmin(CandidatAdmin
):
286 readonly_fields
= ('statut', 'offre_emploi', 'prenom', 'nom',
287 'genre', 'nationalite', 'situation_famille',
288 'nombre_dependant', 'telephone', 'email', 'adresse',
289 'ville', 'etat_province', 'code_postal', 'pays',
290 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
291 'domaine_professionnel',)
294 'fields': ('offre_emploi', )
296 ('Informations personnelles', {
297 'fields': ('prenom','nom','genre', 'nationalite',
298 'situation_famille', 'nombre_dependant',)
301 'fields': ('telephone', 'email', 'adresse', 'ville',
302 'etat_province', 'code_postal', 'pays', )
304 ('Informations professionnelles', {
305 'fields': ('niveau_diplome','employeur_actuel',
306 'poste_actuel', 'domaine_professionnel',)
311 def has_add_permission(self
, request
):
314 def has_delete_permission(self
, request
, obj
=None):
317 def has_change_permission(self
, request
, obj
=None):
318 user_groupes
= request
.user
.groups
.all()
319 if grp_drh_recrutement
in user_groupes
or \
320 grp_administrateurs_recrutement
in user_groupes
or \
321 grp_evaluateurs_recrutement
in user_groupes
:
325 class CandidatPieceAdmin(admin
.ModelAdmin
):
326 list_display
= ('nom', 'candidat', )
328 def queryset(self
, request
):
330 Spécifie un queryset limité, autrement Django exécute un
331 select_related() sans paramètre, ce qui a pour effet de charger tous
332 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
333 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
334 génération d'une requête infinie.
335 Affiche la liste de candidats que si le user connecté
336 possède un Evaluateur
338 qs
= self
.model
._default_manager
.get_query_set()
339 return qs
.select_related('candidat')
341 class EvaluateurAdmin(VersionAdmin
):
343 (None, {'fields': ('user', )}),
344 #(None, {'fields': ('candidats',)}),
347 class AdministrateurRegionalAdmin(VersionAdmin
):
350 class CandidatEvaluationAdmin(VersionAdmin
):
351 list_display
= ('_offre_emploi', '_candidat', 'evaluateur', '_note',
353 readonly_fields
= ('candidat', 'evaluateur')
355 ('Évaluation du candidat', {
356 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
360 def _note(self
, obj
):
362 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
363 un lien pour Évaluer le candidat.
364 Sinon afficher la note.
366 evaluateur
= obj
.evaluateur
367 candidat
= obj
.candidat
368 candidat_evaluation
= CandidatEvaluation
.objects
.\
369 get(candidat
=candidat
, evaluateur
=evaluateur
)
371 return "<a href='%s'>Candidat non évalué</a>" % \
372 (reverse('admin:recrutement_candidatevaluation_change',
373 args
=(candidat_evaluation
.id,)))
374 return "<a href='%s'>%s</a>" % \
375 (reverse('admin:recrutement_candidatevaluation_change',
376 args
=(candidat_evaluation
.id,)), obj
.note
)
378 _note
.allow_tags
= True
379 _note
.short_description
= "Votre note"
380 _note
.admin_order_field
= 'note'
382 def _candidat(self
, obj
):
383 return "<a href='%s'>%s</a>" \
384 % (reverse('admin:recrutement_proxycandidat_change',
385 args
=(obj
.candidat
.id,)), obj
.candidat
)
386 _candidat
.allow_tags
= True
387 _candidat
.short_description
= 'Candidat'
389 def _commentaire(self
, obj
):
391 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
392 dans le champ commentaire, Aucun au lieu de (None)
393 Sinon afficher la note.
395 if obj
.commentaire
is None:
397 return obj
.commentaire
398 _commentaire
.allow_tags
= True
399 _commentaire
.short_description
= "Commentaire"
402 def _offre_emploi(self
, obj
):
403 return "<a href='%s'>%s</a>" % \
404 (reverse('admin:recrutement_proxyoffreemploi_change',
405 args
=(obj
.candidat
.offre_emploi
.id,)), obj
.candidat
.offre_emploi
)
406 _offre_emploi
.allow_tags
= True
407 _offre_emploi
.short_description
= "Voir offre d'emploi"
408 _offre_emploi
.admin_order_field
= 'offre_emploi'
410 def has_change_permission(self
, request
, obj
=None):
412 Permettre la visualisation dans la changelist
413 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
416 return obj
is None or request
.user
== obj
.evaluateur
.user
418 def queryset(self
, request
):
420 Afficher uniquement les évaluations de l'évaluateur, sauf si
421 l'utilisateur est super admin.
423 qs
= self
.model
._default_manager
.get_query_set()
424 user_groupes
= request
.user
.groups
.all()
425 if grp_drh_recrutement
in user_groupes
:
426 return qs
.select_related('offre_emploi')
429 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
430 except Evaluateur
.DoesNotExist
:
433 candidats_evaluations
= CandidatEvaluation
.objects
.\
434 filter(evaluateur
=evaluateur
)
435 candidats_evaluations_ids
= [ce
.id for ce
in \
436 candidats_evaluations
.all()]
437 return qs
.select_related('offre_emploi').\
438 filter(id__in
=candidats_evaluations_ids
)
440 class CourrielTemplateAdmin(VersionAdmin
):
443 admin
.site
.register(OffreEmploi
, OffreEmploiAdmin
)
444 admin
.site
.register(ProxyOffreEmploi
, ProxyOffreEmploiAdmin
)
445 admin
.site
.register(Candidat
, CandidatAdmin
)
446 admin
.site
.register(ProxyCandidat
, ProxyCandidatAdmin
)
447 admin
.site
.register(CandidatEvaluation
, CandidatEvaluationAdmin
)
448 admin
.site
.register(Evaluateur
, EvaluateurAdmin
)
449 #admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
450 admin
.site
.register(CourrielTemplate
, CourrielTemplateAdmin
)