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