refact ergo + page perso (vide)
[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
8e0d552d 7from django.core.files.storage import default_storage
38df74bb 8
6067184b 9from reversion.admin import VersionAdmin
38df74bb 10from datamaster_modeles.models import Employe, Implantation, Region
572c8d08 11from django.forms.models import BaseInlineFormSet
6067184b 12
e2968e84 13from project.rh import models as rh
df59fcab 14from recrutement.models import *
f6724c20
NBV
15from recrutement.workflow import grp_administrateurs_recrutement,\
16 grp_evaluateurs_recrutement, grp_drh_recrutement
a084e988 17from recrutement.forms import *
df59fcab 18
a029f641
NBV
19"""
20class MetaAdmin(VersionAdmin):
21 def get_actions(self, request):
22
23Pour refactoring
24"""
b8b74dee
NBV
25
26class ProxyEvaluateur(Evaluateur.offres_emploi.through):
27 """
28 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
29 plus ergonomique.
30 """
31 class Meta:
32 proxy = True
33 verbose_name = "évaluateur"
34
35class EvaluateurInline(admin.TabularInline):
36 model = ProxyEvaluateur
37 fields = ('evaluateur',)
38 extra = 1
39
d2b30f5f 40class OffreEmploiAdmin(VersionAdmin):
7f9e891e 41 date_hierarchy = 'date_creation'
4fd0c4a2 42 list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
e2968e84
NBV
43 'est_affiche', '_candidatsList', )
44 exclude = ('poste_nom',)
514db699 45 list_filter = ('statut', 'est_affiche', )
c4874d66 46 actions = ['affecter_evaluateurs_offre_emploi', ]
a084e988 47 form = OffreEmploiForm
b8b74dee 48 inlines = [EvaluateurInline, ]
2c3c54ee 49
a029f641
NBV
50 def get_actions(self, request):
51 actions = super(OffreEmploiAdmin, self).get_actions(request)
52 del actions['delete_selected']
540dfae4 53 return actions
a029f641 54
c4874d66
NBV
55 # Affecter un évaluateurs à des offres d'emploi
56 def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):
57 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
58
59 return HttpResponseRedirect(reverse('affecter_evaluateurs_offre_emploi')+
60 "?ids=%s" % (",".join(selected)))
61 affecter_evaluateurs_offre_emploi.short_description = u'Affecter évaluateur(s)'
62
8941aee7 63 # Afficher la liste des candidats pour l'offre d'emploi
596fe324 64 def _candidatsList(self, obj):
8ea41642 65 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
66 </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id)
2f78949d 67 _candidatsList.allow_tags = True
f6724c20 68 _candidatsList.short_description = "Afficher la liste des candidats"
362a3534 69
2f78949d 70 def queryset(self, request):
382501c1 71 qs = self.model._default_manager.get_query_set()
f6724c20
NBV
72 # Si user est superuser afficher toutes les offres d'emploi
73 user_groupes = request.user.groups.all()
d46075cb
NBV
74 if not grp_drh_recrutement in user_groupes and \
75 not request.user.is_superuser:
beef7690 76 """
beef7690
NBV
77 Si le user n'est ni un évaluateur ni un administrateur régional,
78 retourner none
79 Vérifier groupes
80 """
f6724c20 81 if grp_evaluateurs_recrutement in user_groupes:
ca73c3c6
NBV
82 try:
83 user = Evaluateur.objects.get(user=request.user)
84 except Evaluateur.DoesNotExist:
85 return qs.none()
f6724c20 86 elif grp_administrateurs_recrutement in user_groupes:
ca73c3c6
NBV
87 try:
88 user = AdministrateurRegional.objects.get(user=request.user)
89 except AdministrateurRegional.DoesNotExist:
90 return qs.none()
f6724c20
NBV
91 else:
92 return qs.none()
93
94 if type(user) is AdministrateurRegional:
95 region_ids = [g.id for g in user.regions.all()]
96 return qs.select_related('offre_emploi').\
97 filter(region__in=region_ids)
beef7690 98 if type(user) is Evaluateur:
f6724c20 99 candidats = [g for g in user.candidats.all()]
beef7690 100 offre_emploi_ids = [c.offre_emploi.id for c in candidats]
f6724c20 101 return qs.select_related('offre_emploi').\
beef7690 102 filter(id__in=offre_emploi_ids)
3bcef02d 103 return qs.none()
382501c1 104 return qs.select_related('offre_emploi')
f6724c20
NBV
105
106 def has_change_permission(self, request, obj=None):
107 user_groupes = request.user.groups.all()
108 if grp_drh_recrutement in user_groupes or \
d46075cb
NBV
109 grp_administrateurs_recrutement in user_groupes or \
110 request.user.is_superuser:
f6724c20
NBV
111 return True
112 return False
113
114class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
4fd0c4a2
NBV
115 list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
116 'est_affiche')
14e06ff6 117 readonly_fields = ('description', 'bureau',
f6724c20
NBV
118 'duree_affectation', 'renumeration',
119 'debut_affectation', 'lieu_affectation', 'nom',
120 'resume', 'date_limite', 'region')
121 fieldsets = (
720c3ad5 122 ('Nom', {
f6724c20
NBV
123 'fields': ('nom', )
124 }),
720c3ad5 125 ('Description générale', {
14e06ff6 126 'fields': ('resume','description', 'date_limite', )
f6724c20 127 }),
720c3ad5 128 ('Coordonnées', {
f6724c20
NBV
129 'fields': ('lieu_affectation', 'bureau', 'region', )
130 }),
720c3ad5 131 ('Autre', {
f6724c20
NBV
132 'fields': ('debut_affectation', 'duree_affectation',
133 'renumeration', )
134 }),
135 )
a029f641 136
b8778e64
NBV
137 def get_actions(self, request):
138 actions = super(ProxyOffreEmploiAdmin, self).get_actions(request)
139 del actions['affecter_evaluateurs_offre_emploi']
140 return actions
141
a029f641
NBV
142 def response_change(self, request, obj):
143 response = super(ProxyOffreEmploiAdmin, self).response_change(request, obj)
144 user_groupes = request.user.groups.all()
145 if grp_drh_recrutement in user_groupes or \
146 request.user.is_superuser:
147 return HttpResponseRedirect(reverse('admin:recrutement_offreemploi_changelist'))
148 return HttpResponseRedirect(reverse('admin:recrutement_proxyoffreemploi_changelist'))
149
f6724c20
NBV
150 def has_add_permission(self, request):
151 return False
152
153 def has_delete_permission(self, request, obj=None):
154 return False
155
2d083449
NBV
156 def has_change_permission(self, request, obj=None):
157 user_groupes = request.user.groups.all()
beef7690 158 if grp_evaluateurs_recrutement in user_groupes or \
d46075cb
NBV
159 grp_drh_recrutement in user_groupes or \
160 request.user.is_superuser:
2d083449
NBV
161 return True
162 return False
163
572c8d08
NBV
164class CandidatPieceInline(admin.TabularInline):
165 model = CandidatPiece
166 fields = ('candidat', 'nom', 'path',)
167 extra = 1
168 max_num = 3
169
572c8d08
NBV
170class CandidatEvaluationInlineFormSet(BaseInlineFormSet):
171 """
172 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
173 """
174 def __init__(self, *args, **kwargs):
175 super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs)
176 self.can_delete = False
177
178class CandidatEvaluationInline(admin.TabularInline):
179 model = CandidatEvaluation
180 fields = ('evaluateur', 'note', 'commentaire')
181 max_num = 0
182 extra = 0
183 formset = CandidatEvaluationInlineFormSet
184
185 def get_readonly_fields(self, request, obj=None):
186 """
187 Empêche la modification des évaluations
188 """
189 if obj:
190 return self.readonly_fields+('evaluateur', 'note', 'commentaire')
191 return self.readonly_fields
192
d2b30f5f 193class CandidatAdmin(VersionAdmin):
7f9e891e 194 date_hierarchy = 'date_creation'
0fd8a26d 195 list_display = ('nom', 'prenom', 'offre_emploi','statut',
dc7faf2b
NBV
196 'voir_offre_emploi', 'calculer_moyenne',
197 'afficher_candidat',)
8ea41642 198 list_filter = ('offre_emploi', )
7f9e891e 199 fieldsets = (
4896b661 200 ("Offre d'emploi", {
201 'fields': ('offre_emploi', )
202 }),
7f9e891e 203 ('Informations personnelles', {
4fd0c4a2 204 'fields': ('prenom','nom','genre', 'nationalite',
7f9e891e 205 'situation_famille', 'nombre_dependant',)
206 }),
ec517164 207 ('Coordonnées', {
208 'fields': ('telephone', 'email', 'adresse', 'ville',
209 'etat_province', 'code_postal', 'pays', )
7f9e891e 210 }),
211 ('Informations professionnelles', {
4896b661 212 'fields': ('niveau_diplome','employeur_actuel',
8ea41642 213 'poste_actuel', 'domaine_professionnel',)
7f9e891e 214 }),
65c4cbd9
NBV
215 ('Traitement', {
216 'fields': ('statut', )
7f9e891e 217 }),
218 )
170c9aa2 219 inlines = [
220 CandidatPieceInline,
572c8d08 221 CandidatEvaluationInline,
170c9aa2 222 ]
f9983b5a 223
540dfae4 224 actions = ['envoyer_courriel_candidats']
a029f641
NBV
225
226 def get_actions(self, request):
227 actions = super(CandidatAdmin, self).get_actions(request)
228 del actions['delete_selected']
540dfae4 229 return actions
362a3534 230
4e8340cf 231 # Envoyer un courriel à des candidats
52765380 232 def envoyer_courriel_candidats(modeladmin, obj, candidats):
233 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
234
32834000 235 return HttpResponseRedirect(reverse('selectionner_template')+
52765380 236 "?ids=%s" % (",".join(selected)))
237 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
238
05503d56 239 # Évaluer un candidat
596fe324 240 def evaluer_candidat(self, obj):
dc7faf2b 241 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat</a>" % \
beef7690
NBV
242 (reverse('admin:recrutement_candidatevaluation_changelist'),
243 obj.id)
596fe324 244 evaluer_candidat.allow_tags = True
beef7690 245 evaluer_candidat.short_description = 'Évaluation'
596fe324 246
7d82fd33 247 # Afficher un candidat
248 def afficher_candidat(self, obj):
382501c1
NBV
249 return "<a href='%s'>Voir le candidat</a>" % \
250 (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
7d82fd33 251 afficher_candidat.allow_tags = True
8e0d552d 252 afficher_candidat.short_description = u'Détails du candidat'
7d82fd33 253
8941aee7 254 # Voir l'offre d'emploi
255 def voir_offre_emploi(self, obj):
720c3ad5
NBV
256 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
257 (reverse('admin:recrutement_proxyoffreemploi_change',
258 args=(obj.offre_emploi.id,)))
8941aee7 259 voir_offre_emploi.allow_tags = True
260 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
261
8941aee7 262 # Calculer la moyenne des notes
263 def calculer_moyenne(self, obj):
264 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
265 offre_emploi = obj.offre_emploi
266
f6724c20
NBV
267 notes = [evaluation.note for evaluation in evaluations.all() \
268 if evaluation.note is not None]
8941aee7 269
270 if len(notes) > 0 and offre_emploi.date_limite <= datetime.date.today():
271 moyenne_votes = float(sum(notes)) / len(notes)
272 else:
273 moyenne_votes = "Non disponible"
274 return moyenne_votes
275 calculer_moyenne.allow_tags = True
276 calculer_moyenne.short_description = "Moyenne des notes"
277
f6724c20
NBV
278 def add_delete_permission(self, request, obj=None) :
279 user_groupes = request.user.groups.all()
280 if grp_drh_recrutement in user_groupes or \
d46075cb
NBV
281 grp_administrateurs_recrutement in user_groupes or \
282 request.user.is_superuser:
f6724c20
NBV
283 return True
284 return False
4896b661 285
f6724c20
NBV
286 def has_add_permission(self, request):
287 return self.add_delete_permission(request, request)
4896b661 288
f6724c20
NBV
289 def has_delete_permission(self, request, obj=None):
290 return self.add_delete_permission(request, request)
291
292 def has_change_permission(self, request, obj=None):
293 user_groupes = request.user.groups.all()
294 if grp_drh_recrutement in user_groupes or \
d46075cb
NBV
295 grp_administrateurs_recrutement in user_groupes or \
296 request.user.is_superuser:
f6724c20
NBV
297 return True
298 return False
4896b661 299
d46075cb 300 def queryset(self, request):
f9983b5a 301 """
8ea41642 302 Spécifie un queryset limité, autrement Django exécute un
303 select_related() sans paramètre, ce qui a pour effet de charger tous
304 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
305 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
306 génération d'une requête infinie.
d835c9f3 307
f9983b5a 308 """
f6724c20
NBV
309 qs = self.model._default_manager.get_query_set()
310 # Si user est superuser afficher tous les candidats
d46075cb
NBV
311 user_groupes = request.user.groups.all()
312 if not grp_drh_recrutement in user_groupes and \
313 not request.user.is_superuser:
f6724c20
NBV
314 # Si le user n'est ni un évaluateur ni un administrateur régional,
315 # retourner none
316
317 # Vérifier groupes
318 if grp_evaluateurs_recrutement in user_groupes:
ca73c3c6 319 try:
2c3c54ee 320 user = Evaluateur.objects.get(user=request.user)
ca73c3c6
NBV
321 except Evaluateur.DoesNotExist:
322 return qs.none()
efedc086
NBV
323 """
324 elif grp_administrateurs_recrutement in user_groupes:
325 try:
326 user = AdministrateurRegional.objects.get(user=obj.user)
327 except AdministrateurRegional.DoesNotExist:
328 return qs.none()
329 """
f6724c20
NBV
330 else:
331 return qs.none()
f6724c20
NBV
332 ids = [c.id for c in user.candidats.all()]
333 return qs.select_related('candidats').filter(id__in=ids)
334 return qs.select_related('candidats')
335
336class ProxyCandidatAdmin(CandidatAdmin):
f6724c20 337 readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom',
4fd0c4a2
NBV
338 'genre', 'nationalite', 'situation_famille',
339 'nombre_dependant', 'telephone', 'email', 'adresse',
340 'ville', 'etat_province', 'code_postal', 'pays',
341 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
8e0d552d 342 'domaine_professionnel', 'pieces_jointes',)
2d083449
NBV
343 fieldsets = (
344 ("Offre d'emploi", {
345 'fields': ('offre_emploi', )
346 }),
347 ('Informations personnelles', {
4fd0c4a2 348 'fields': ('prenom','nom','genre', 'nationalite',
2d083449
NBV
349 'situation_famille', 'nombre_dependant',)
350 }),
351 ('Coordonnées', {
352 'fields': ('telephone', 'email', 'adresse', 'ville',
353 'etat_province', 'code_postal', 'pays', )
354 }),
355 ('Informations professionnelles', {
356 'fields': ('niveau_diplome','employeur_actuel',
357 'poste_actuel', 'domaine_professionnel',)
8e0d552d 358 }),
2d083449 359 )
f6724c20 360 inlines = []
2d083449 361
a029f641
NBV
362 def response_change(self, request, obj):
363 response = super(ProxyCandidatAdmin, self).response_change(request, obj)
364 user_groupes = request.user.groups.all()
365 if grp_drh_recrutement in user_groupes or \
366 request.user.is_superuser:
367 return HttpResponseRedirect(reverse('admin:recrutement_candidat_changelist'))
368 return HttpResponseRedirect(reverse('admin:recrutement_proxycandidat_changelist'))
369
f6724c20
NBV
370 def has_add_permission(self, request):
371 return False
372
373 def has_delete_permission(self, request, obj=None):
374 return False
2adf9e0c 375
2d083449
NBV
376 def has_change_permission(self, request, obj=None):
377 user_groupes = request.user.groups.all()
beef7690
NBV
378 if grp_drh_recrutement in user_groupes or \
379 grp_administrateurs_recrutement in user_groupes or \
d46075cb
NBV
380 grp_evaluateurs_recrutement in user_groupes or \
381 request.user.is_superuser:
2d083449
NBV
382 return True
383 return False
384
2e9ee615 385class CandidatPieceAdmin(admin.ModelAdmin):
170c9aa2 386 list_display = ('nom', 'candidat', )
387
388 def queryset(self, request):
389 """
390 Spécifie un queryset limité, autrement Django exécute un
391 select_related() sans paramètre, ce qui a pour effet de charger tous
392 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
393 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
394 génération d'une requête infinie.
d835c9f3 395 Affiche la liste de candidats que si le user connecté
27c81d11 396 possède un Evaluateur
170c9aa2 397 """
398 qs = self.model._default_manager.get_query_set()
399 return qs.select_related('candidat')
2e9ee615 400
d2b30f5f 401class EvaluateurAdmin(VersionAdmin):
eb579d40 402 fieldsets = (
540dfae4
NBV
403 ("Utilisateur", {
404 'fields': ('user',)
405 }),
406 ("Offres d'emploi à évaluer", {
407 'fields': ('offres_emploi',)
408 }),
eb579d40 409 )
4418c732 410
a029f641
NBV
411 def get_actions(self, request):
412 actions = super(EvaluateurAdmin, self).get_actions(request)
413 del actions['delete_selected']
540dfae4 414 return actions
a029f641 415
b89fef74 416class AdministrateurRegionalAdmin(VersionAdmin):
27c81d11 417 pass
418
d2b30f5f 419class CandidatEvaluationAdmin(VersionAdmin):
2c3c54ee 420 list_display = ('_candidat', '_offre_emploi', 'evaluateur', '_note',
b903198b 421 '_commentaire', )
beef7690
NBV
422 readonly_fields = ('candidat', 'evaluateur')
423 fieldsets = (
424 ('Évaluation du candidat', {
425 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
426 }),
427 )
428
a029f641
NBV
429 def get_actions(self, request):
430 actions = super(CandidatEvaluationAdmin, self).get_actions(request)
431 del actions['delete_selected']
540dfae4 432 return actions
a029f641 433
beef7690
NBV
434 def _note(self, obj):
435 """
436 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
437 un lien pour Évaluer le candidat.
438 Sinon afficher la note.
439 """
b903198b
NBV
440 evaluateur = obj.evaluateur
441 candidat = obj.candidat
442 candidat_evaluation = CandidatEvaluation.objects.\
443 get(candidat=candidat, evaluateur=evaluateur)
beef7690 444 if obj.note is None:
b903198b 445 return "<a href='%s'>Candidat non évalué</a>" % \
beef7690 446 (reverse('admin:recrutement_candidatevaluation_change',
b903198b
NBV
447 args=(candidat_evaluation.id,)))
448 return "<a href='%s'>%s</a>" % \
449 (reverse('admin:recrutement_candidatevaluation_change',
450 args=(candidat_evaluation.id,)), obj.note)
451 return
beef7690
NBV
452 _note.allow_tags = True
453 _note.short_description = "Votre note"
454 _note.admin_order_field = 'note'
455
456 def _candidat(self, obj):
457 return "<a href='%s'>%s</a>" \
458 % (reverse('admin:recrutement_proxycandidat_change',
459 args=(obj.candidat.id,)), obj.candidat)
460 _candidat.allow_tags = True
461 _candidat.short_description = 'Candidat'
462
463 def _commentaire(self, obj):
464 """
465 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
466 dans le champ commentaire, Aucun au lieu de (None)
467 Sinon afficher la note.
468 """
469 if obj.commentaire is None:
470 return "Aucun"
471 return obj.commentaire
472 _commentaire.allow_tags = True
473 _commentaire.short_description = "Commentaire"
720c3ad5 474
720c3ad5 475
beef7690
NBV
476 def _offre_emploi(self, obj):
477 return "<a href='%s'>%s</a>" % \
478 (reverse('admin:recrutement_proxyoffreemploi_change',
dc7faf2b 479 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
beef7690
NBV
480 _offre_emploi.allow_tags = True
481 _offre_emploi.short_description = "Voir offre d'emploi"
beef7690 482
21b02da5
NBV
483 def has_change_permission(self, request, obj=None):
484 """
485 Permettre la visualisation dans la changelist
486 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
487 le request.user
488 """
489 return obj is None or request.user == obj.evaluateur.user
490
720c3ad5 491 def queryset(self, request):
beef7690
NBV
492 """
493 Afficher uniquement les évaluations de l'évaluateur, sauf si
494 l'utilisateur est super admin.
495 """
720c3ad5 496 qs = self.model._default_manager.get_query_set()
beef7690 497 user_groupes = request.user.groups.all()
d46075cb
NBV
498 if grp_drh_recrutement in user_groupes or \
499 request.user.is_superuser:
beef7690
NBV
500 return qs.select_related('offre_emploi')
501
ca73c3c6 502 try:
d069cdf1 503 evaluateur = Evaluateur.objects.get(user=request.user)
ca73c3c6
NBV
504 except Evaluateur.DoesNotExist:
505 return qs.none()
506
507 candidats_evaluations = CandidatEvaluation.objects.\
508 filter(evaluateur=evaluateur)
509 candidats_evaluations_ids = [ce.id for ce in \
510 candidats_evaluations.all()]
511 return qs.select_related('offre_emploi').\
512 filter(id__in=candidats_evaluations_ids)
596fe324 513
4e8340cf 514class CourrielTemplateAdmin(VersionAdmin):
a029f641
NBV
515 def get_actions(self, request):
516 actions = super(CourrielTemplateAdmin, self).get_actions(request)
517 del actions['delete_selected']
540dfae4 518 return actions
4e8340cf 519
df59fcab 520admin.site.register(OffreEmploi, OffreEmploiAdmin)
382501c1 521admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
df59fcab 522admin.site.register(Candidat, CandidatAdmin)
382501c1 523admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
720c3ad5 524admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
27c81d11 525admin.site.register(Evaluateur, EvaluateurAdmin)
beef7690 526#admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
32834000 527admin.site.register(CourrielTemplate, CourrielTemplateAdmin)