1734: Partie-1 - utilisation du package auf.django.emploi dans le site institutionnel
[auf_rh_dae.git] / project / recrutement / admin.py
CommitLineData
df59fcab 1# -*- encoding: utf-8 -*-
2
6067184b 3from django.core.urlresolvers import reverse
4from django.http import HttpResponseRedirect
df59fcab 5from django.contrib import admin
38df74bb 6from django.shortcuts import get_object_or_404
7
6067184b 8from reversion.admin import VersionAdmin
38df74bb 9from datamaster_modeles.models import Employe, Implantation, Region
6067184b 10
df59fcab 11from recrutement.models import *
f6724c20
NBV
12from recrutement.workflow import grp_administrateurs_recrutement,\
13 grp_evaluateurs_recrutement, grp_drh_recrutement
df59fcab 14
d2b30f5f 15class OffreEmploiAdmin(VersionAdmin):
7f9e891e 16 date_hierarchy = 'date_creation'
4fd0c4a2
NBV
17 list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
18 'est_affiche', '_candidatsList')
514db699 19 list_filter = ('statut', 'est_affiche', )
c4874d66
NBV
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)
24
25 return HttpResponseRedirect(reverse('affecter_evaluateurs_offre_emploi')+
26 "?ids=%s" % (",".join(selected)))
27 affecter_evaluateurs_offre_emploi.short_description = u'Affecter évaluateur(s)'
28
8941aee7 29 # Afficher la liste des candidats pour l'offre d'emploi
596fe324 30 def _candidatsList(self, obj):
8ea41642 31 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
32 </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id)
2f78949d 33 _candidatsList.allow_tags = True
f6724c20 34 _candidatsList.short_description = "Afficher la liste des candidats"
362a3534 35
c4874d66 36
2f78949d 37 def queryset(self, request):
382501c1 38 qs = self.model._default_manager.get_query_set()
f6724c20
NBV
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:
beef7690 42 """
beef7690
NBV
43 Si le user n'est ni un évaluateur ni un administrateur régional,
44 retourner none
45 Vérifier groupes
46 """
f6724c20 47 if grp_evaluateurs_recrutement in user_groupes:
ca73c3c6
NBV
48 try:
49 user = Evaluateur.objects.get(user=request.user)
50 except Evaluateur.DoesNotExist:
51 return qs.none()
f6724c20 52 elif grp_administrateurs_recrutement in user_groupes:
ca73c3c6
NBV
53 try:
54 user = AdministrateurRegional.objects.get(user=request.user)
55 except AdministrateurRegional.DoesNotExist:
56 return qs.none()
f6724c20
NBV
57 else:
58 return qs.none()
59
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)
beef7690 64 if type(user) is Evaluateur:
f6724c20 65 candidats = [g for g in user.candidats.all()]
beef7690 66 offre_emploi_ids = [c.offre_emploi.id for c in candidats]
f6724c20 67 return qs.select_related('offre_emploi').\
beef7690 68 filter(id__in=offre_emploi_ids)
3bcef02d 69 return qs.none()
382501c1 70 return qs.select_related('offre_emploi')
f6724c20
NBV
71
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:
76 return True
77 return False
78
79class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
4fd0c4a2
NBV
80 list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
81 'est_affiche')
14e06ff6 82 readonly_fields = ('description', 'bureau',
f6724c20
NBV
83 'duree_affectation', 'renumeration',
84 'debut_affectation', 'lieu_affectation', 'nom',
85 'resume', 'date_limite', 'region')
86 fieldsets = (
720c3ad5 87 ('Nom', {
f6724c20
NBV
88 'fields': ('nom', )
89 }),
720c3ad5 90 ('Description générale', {
14e06ff6 91 'fields': ('resume','description', 'date_limite', )
f6724c20 92 }),
720c3ad5 93 ('Coordonnées', {
f6724c20
NBV
94 'fields': ('lieu_affectation', 'bureau', 'region', )
95 }),
720c3ad5 96 ('Autre', {
f6724c20
NBV
97 'fields': ('debut_affectation', 'duree_affectation',
98 'renumeration', )
99 }),
100 )
101 def has_add_permission(self, request):
102 return False
103
104 def has_delete_permission(self, request, obj=None):
105 return False
106
2d083449
NBV
107 def has_change_permission(self, request, obj=None):
108 user_groupes = request.user.groups.all()
beef7690
NBV
109 if grp_evaluateurs_recrutement in user_groupes or \
110 grp_drh_recrutement in user_groupes:
2d083449
NBV
111 return True
112 return False
113
cced6a23 114class ProxyCandidatPiece(CandidatPiece):
115 """
116 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
117 plus ergonomique.
118 """
119 class Meta:
120 proxy = True
121 verbose_name = "pièce jointe"
74cbc7a7 122 verbose_name_plural = "pièces jointes"
cced6a23 123
170c9aa2 124class CandidatPieceInline(admin.TabularInline):
cced6a23 125 model = ProxyCandidatPiece
14e06ff6 126 fields = ('candidat', 'nom', )#'path', )
170c9aa2 127 extra = 1
128
27c81d11 129class ProxyEvaluateur(Evaluateur.candidats.through):
cced6a23 130 """
131 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
132 plus ergonomique.
133 """
134 class Meta:
135 proxy = True
136 verbose_name = "évaluateur"
137
eb579d40 138class EvaluateurInline(admin.TabularInline):
cced6a23 139 model = ProxyEvaluateur
720c3ad5 140 fields = ('evaluateur',)
eb579d40 141 extra = 1
142
d2b30f5f 143class CandidatAdmin(VersionAdmin):
7f9e891e 144 date_hierarchy = 'date_creation'
0fd8a26d 145 list_display = ('nom', 'prenom', 'offre_emploi','statut',
dc7faf2b
NBV
146 'voir_offre_emploi', 'calculer_moyenne',
147 'afficher_candidat',)
8ea41642 148 list_filter = ('offre_emploi', )
7f9e891e 149 fieldsets = (
4896b661 150 ("Offre d'emploi", {
151 'fields': ('offre_emploi', )
152 }),
7f9e891e 153 ('Informations personnelles', {
4fd0c4a2 154 'fields': ('prenom','nom','genre', 'nationalite',
7f9e891e 155 'situation_famille', 'nombre_dependant',)
156 }),
ec517164 157 ('Coordonnées', {
158 'fields': ('telephone', 'email', 'adresse', 'ville',
159 'etat_province', 'code_postal', 'pays', )
7f9e891e 160 }),
161 ('Informations professionnelles', {
4896b661 162 'fields': ('niveau_diplome','employeur_actuel',
8ea41642 163 'poste_actuel', 'domaine_professionnel',)
7f9e891e 164 }),
65c4cbd9
NBV
165 ('Traitement', {
166 'fields': ('statut', )
7f9e891e 167 }),
168 )
170c9aa2 169 inlines = [
170 CandidatPieceInline,
eb579d40 171 EvaluateurInline,
170c9aa2 172 ]
f9983b5a 173
4e8340cf 174 actions = ['affecter_candidats_evaluateur', 'envoyer_courriel_candidats']
362a3534 175 # Affecter un évaluateurs à des candidats
7061f835 176 def affecter_candidats_evaluateur(modeladmin, obj, candidats):
596fe324 177 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
2adf9e0c 178
8ea41642 179 return HttpResponseRedirect(reverse('affecter_evaluateurs_candidats')+
180 "?ids=%s" % (",".join(selected)))
c4874d66 181 affecter_candidats_evaluateur.short_description = u'Affecter évaluateur(s)'
362a3534 182
4e8340cf 183 # Envoyer un courriel à des candidats
52765380 184 def envoyer_courriel_candidats(modeladmin, obj, candidats):
185 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
186
32834000 187 return HttpResponseRedirect(reverse('selectionner_template')+
52765380 188 "?ids=%s" % (",".join(selected)))
189 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
190
05503d56 191 # Évaluer un candidat
596fe324 192 def evaluer_candidat(self, obj):
dc7faf2b 193 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat</a>" % \
beef7690
NBV
194 (reverse('admin:recrutement_candidatevaluation_changelist'),
195 obj.id)
596fe324 196 evaluer_candidat.allow_tags = True
beef7690 197 evaluer_candidat.short_description = 'Évaluation'
596fe324 198
7d82fd33 199 # Afficher un candidat
200 def afficher_candidat(self, obj):
382501c1
NBV
201 return "<a href='%s'>Voir le candidat</a>" % \
202 (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
7d82fd33 203 afficher_candidat.allow_tags = True
f6724c20 204 afficher_candidat.short_description = u'Afficher les détails du candidat'
7d82fd33 205
8941aee7 206 # Voir l'offre d'emploi
207 def voir_offre_emploi(self, obj):
720c3ad5
NBV
208 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
209 (reverse('admin:recrutement_proxyoffreemploi_change',
210 args=(obj.offre_emploi.id,)))
8941aee7 211 voir_offre_emploi.allow_tags = True
212 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
213
8941aee7 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
218
f6724c20
NBV
219 notes = [evaluation.note for evaluation in evaluations.all() \
220 if evaluation.note is not None]
8941aee7 221
222 if len(notes) > 0 and offre_emploi.date_limite <= datetime.date.today():
223 moyenne_votes = float(sum(notes)) / len(notes)
224 else:
225 moyenne_votes = "Non disponible"
226 return moyenne_votes
227 calculer_moyenne.allow_tags = True
228 calculer_moyenne.short_description = "Moyenne des notes"
229
f6724c20
NBV
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:
234 return True
235 return False
4896b661 236
f6724c20
NBV
237 def has_add_permission(self, request):
238 return self.add_delete_permission(request, request)
4896b661 239
f6724c20
NBV
240 def has_delete_permission(self, request, obj=None):
241 return self.add_delete_permission(request, request)
242
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 \
2d083449 246 grp_administrateurs_recrutement in user_groupes:
f6724c20
NBV
247 return True
248 return False
4896b661 249
596fe324 250 def queryset(self, obj):
f9983b5a 251 """
8ea41642 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.
d835c9f3 257
f9983b5a 258 """
f6724c20
NBV
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,
264 # retourner none
265
266 # Vérifier groupes
267 if grp_evaluateurs_recrutement in user_groupes:
ca73c3c6
NBV
268 try:
269 user = Evaluateur.objects.get(user=obj.user)
270 except Evaluateur.DoesNotExist:
271 return qs.none()
efedc086
NBV
272 """
273 elif grp_administrateurs_recrutement in user_groupes:
274 try:
275 user = AdministrateurRegional.objects.get(user=obj.user)
276 except AdministrateurRegional.DoesNotExist:
277 return qs.none()
278 """
f6724c20
NBV
279 else:
280 return qs.none()
f6724c20
NBV
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')
284
285class ProxyCandidatAdmin(CandidatAdmin):
f6724c20 286 readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom',
4fd0c4a2
NBV
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',
f6724c20 291 'domaine_professionnel',)
2d083449
NBV
292 fieldsets = (
293 ("Offre d'emploi", {
294 'fields': ('offre_emploi', )
295 }),
296 ('Informations personnelles', {
4fd0c4a2 297 'fields': ('prenom','nom','genre', 'nationalite',
2d083449
NBV
298 'situation_famille', 'nombre_dependant',)
299 }),
300 ('Coordonnées', {
301 'fields': ('telephone', 'email', 'adresse', 'ville',
302 'etat_province', 'code_postal', 'pays', )
303 }),
304 ('Informations professionnelles', {
305 'fields': ('niveau_diplome','employeur_actuel',
306 'poste_actuel', 'domaine_professionnel',)
307 }),
308 )
f6724c20 309 inlines = []
2d083449 310
f6724c20
NBV
311 def has_add_permission(self, request):
312 return False
313
314 def has_delete_permission(self, request, obj=None):
315 return False
2adf9e0c 316
2d083449
NBV
317 def has_change_permission(self, request, obj=None):
318 user_groupes = request.user.groups.all()
beef7690
NBV
319 if grp_drh_recrutement in user_groupes or \
320 grp_administrateurs_recrutement in user_groupes or \
321 grp_evaluateurs_recrutement in user_groupes:
2d083449
NBV
322 return True
323 return False
324
2e9ee615 325class CandidatPieceAdmin(admin.ModelAdmin):
170c9aa2 326 list_display = ('nom', 'candidat', )
327
328 def queryset(self, request):
329 """
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.
d835c9f3 335 Affiche la liste de candidats que si le user connecté
27c81d11 336 possède un Evaluateur
170c9aa2 337 """
338 qs = self.model._default_manager.get_query_set()
339 return qs.select_related('candidat')
2e9ee615 340
d2b30f5f 341class EvaluateurAdmin(VersionAdmin):
eb579d40 342 fieldsets = (
f6724c20 343 (None, {'fields': ('user', )}),
720c3ad5 344 #(None, {'fields': ('candidats',)}),
eb579d40 345 )
4418c732 346
b89fef74 347class AdministrateurRegionalAdmin(VersionAdmin):
27c81d11 348 pass
349
d2b30f5f 350class CandidatEvaluationAdmin(VersionAdmin):
b903198b
NBV
351 list_display = ('_offre_emploi', '_candidat', 'evaluateur', '_note',
352 '_commentaire', )
beef7690
NBV
353 readonly_fields = ('candidat', 'evaluateur')
354 fieldsets = (
355 ('Évaluation du candidat', {
356 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
357 }),
358 )
359
360 def _note(self, obj):
361 """
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.
365 """
b903198b
NBV
366 evaluateur = obj.evaluateur
367 candidat = obj.candidat
368 candidat_evaluation = CandidatEvaluation.objects.\
369 get(candidat=candidat, evaluateur=evaluateur)
beef7690 370 if obj.note is None:
b903198b 371 return "<a href='%s'>Candidat non évalué</a>" % \
beef7690 372 (reverse('admin:recrutement_candidatevaluation_change',
b903198b
NBV
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)
377 return
beef7690
NBV
378 _note.allow_tags = True
379 _note.short_description = "Votre note"
380 _note.admin_order_field = 'note'
381
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'
388
389 def _commentaire(self, obj):
390 """
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.
394 """
395 if obj.commentaire is None:
396 return "Aucun"
397 return obj.commentaire
398 _commentaire.allow_tags = True
399 _commentaire.short_description = "Commentaire"
720c3ad5 400
720c3ad5 401
beef7690
NBV
402 def _offre_emploi(self, obj):
403 return "<a href='%s'>%s</a>" % \
404 (reverse('admin:recrutement_proxyoffreemploi_change',
dc7faf2b 405 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
beef7690
NBV
406 _offre_emploi.allow_tags = True
407 _offre_emploi.short_description = "Voir offre d'emploi"
408 _offre_emploi.admin_order_field = 'offre_emploi'
409
21b02da5
NBV
410 def has_change_permission(self, request, obj=None):
411 """
412 Permettre la visualisation dans la changelist
413 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
414 le request.user
415 """
416 return obj is None or request.user == obj.evaluateur.user
417
720c3ad5 418 def queryset(self, request):
beef7690
NBV
419 """
420 Afficher uniquement les évaluations de l'évaluateur, sauf si
421 l'utilisateur est super admin.
422 """
720c3ad5 423 qs = self.model._default_manager.get_query_set()
beef7690
NBV
424 user_groupes = request.user.groups.all()
425 if grp_drh_recrutement in user_groupes:
426 return qs.select_related('offre_emploi')
427
ca73c3c6 428 try:
d069cdf1 429 evaluateur = Evaluateur.objects.get(user=request.user)
ca73c3c6
NBV
430 except Evaluateur.DoesNotExist:
431 return qs.none()
432
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)
596fe324 439
4e8340cf 440class CourrielTemplateAdmin(VersionAdmin):
441 pass
442
df59fcab 443admin.site.register(OffreEmploi, OffreEmploiAdmin)
382501c1 444admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
df59fcab 445admin.site.register(Candidat, CandidatAdmin)
382501c1 446admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
720c3ad5 447admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
27c81d11 448admin.site.register(Evaluateur, EvaluateurAdmin)
beef7690 449#admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
32834000 450admin.site.register(CourrielTemplate, CourrielTemplateAdmin)