Mauvaise redirection apres affectation d'évaluateurs
[auf_rh_dae.git] / project / recrutement / admin.py
CommitLineData
df59fcab 1# -*- encoding: utf-8 -*-
2
1b4c8020 3import textwrap
4ba84959 4
75f0e87b 5from django.conf import settings
df59fcab 6from django.contrib import admin
75f0e87b 7from django.core.urlresolvers import reverse
97b168d6 8from django.db.models import Avg
0b9dea96
PP
9from django.shortcuts import render_to_response
10from django.template import RequestContext
38df74bb 11
0b9dea96 12from auf.django.emploi.models import STATUT_CHOICES
75f0e87b
DB
13from django.forms.models import BaseInlineFormSet
14from django.http import HttpResponseRedirect
b31ce2d7 15from django.shortcuts import redirect
6067184b 16from reversion.admin import VersionAdmin
7d9736ba 17
e949324b 18from auf.django.emploi.models import OffreEmploi, Candidat, CandidatPiece
ad831560 19from auf.django.references.models import Region, Bureau, Implantation
bdbc1f13 20from auf.django.export.admin import ExportAdmin
7d9736ba 21
afd3be54 22from project.groups import get_employe_from_user as get_emp
17c90428 23from project.rh import models as rh
3bc5ea42 24
b31ce2d7 25from project.recrutement.forms import OffreEmploiForm
86e4bb65
DB
26from project.recrutement.groups import \
27 grp_drh, grp_drh2, \
28 grp_directeurs_bureau, \
29 grp_administrateurs, \
30 grp_correspondants_rh, \
31 grp_haute_direction
b31ce2d7 32from project.recrutement.models import \
4ba84959
EMS
33 Evaluateur, CandidatEvaluation, \
34 ProxyOffreEmploi, ProxyCandidat, MesCandidatEvaluation, \
b31ce2d7 35 CourrielTemplate
8bf241db 36
df59fcab 37
7d9736ba 38### CONSTANTES
d333c690
NBV
39IMPLANTATIONS_CENTRALES = [15, 19]
40
b31ce2d7 41
08a9b6fc
EMS
42class BaseAdmin(admin.ModelAdmin):
43
44 class Media:
45 css = {'screen': ('css/admin_custom.css',)}
46
47
97b168d6
OL
48class OrderedChangeList(admin.views.main.ChangeList):
49 """
50 Surcharge pour appliquer le order_by d'un annotate
51 """
52 def get_query_set(self):
53 qs = super(OrderedChangeList, self).get_query_set()
54 qs = qs.order_by('-moyenne')
55 return qs
56
b31ce2d7 57
08a9b6fc 58class OffreEmploiAdmin(BaseAdmin, VersionAdmin):
7f9e891e 59 date_hierarchy = 'date_creation'
b31ce2d7
EMS
60 list_display = (
61 'nom', 'date_limite', 'region', 'statut', 'est_affiche',
62 '_candidatsList'
63 )
7d0ae1ba
NBV
64 exclude = ('actif', 'poste_nom', 'resume',)
65 list_filter = ('statut',)
c4874d66 66 actions = ['affecter_evaluateurs_offre_emploi', ]
a084e988 67 form = OffreEmploiForm
2c3c54ee 68
7d9736ba 69 ### Actions à afficher
a029f641
NBV
70 def get_actions(self, request):
71 actions = super(OffreEmploiAdmin, self).get_actions(request)
72 del actions['delete_selected']
540dfae4 73 return actions
a029f641 74
7d9736ba 75 ### Affecter un évaluateurs à des offres d'emploi
b31ce2d7 76 def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):
c4874d66
NBV
77 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
78
b31ce2d7
EMS
79 return HttpResponseRedirect(
80 reverse('affecter_evaluateurs_offre_emploi') +
81 "?ids=%s" % (",".join(selected))
82 )
83
84 affecter_evaluateurs_offre_emploi.short_description = \
85 u'Affecter évaluateur(s)'
c4874d66 86
7d9736ba 87 ### Afficher la liste des candidats pour l'offre d'emploi
b31ce2d7 88 def _candidatsList(self, obj):
8ea41642 89 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
1b981c9d 90 </a>" % (reverse('admin:emploi_candidat_changelist'), obj.id)
b31ce2d7 91 _candidatsList.allow_tags = True
f6724c20 92 _candidatsList.short_description = "Afficher la liste des candidats"
362a3534 93
7d9736ba 94 ### Formulaire
3a542b85
NBV
95 def get_form(self, request, obj=None, **kwargs):
96 form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs)
97 employe = get_emp(request.user)
3a542b85 98 user_groupes = request.user.groups.all()
b31ce2d7 99
7d9736ba 100 # Region
b31ce2d7 101 if 'region' in form.declared_fields:
d333c690
NBV
102 region_field = form.declared_fields['region']
103 else:
104 region_field = form.base_fields['region']
105
86e4bb65
DB
106 if grp_drh in user_groupes or \
107 grp_drh2 in user_groupes or \
108 grp_haute_direction in user_groupes:
d333c690
NBV
109 region_field.queryset = Region.objects.all()
110 else:
111 region_field.queryset = Region.objects.\
112 filter(id=employe.implantation.region.id)
b31ce2d7 113
7d9736ba 114 # Poste
b31ce2d7 115 if 'poste' in form.declared_fields:
d333c690
NBV
116 poste_field = form.declared_fields['poste']
117 else:
118 poste_field = form.base_fields['poste']
119
86e4bb65
DB
120 if grp_drh in user_groupes or \
121 grp_drh2 in user_groupes or \
122 grp_haute_direction in user_groupes:
d333c690
NBV
123 poste_field.queryset = rh.Poste.objects.all()
124 else:
7d9736ba
NBV
125 poste_field.queryset = rh.Poste.objects.\
126 filter(implantation__region=employe.implantation.region).\
127 exclude(implantation__in=IMPLANTATIONS_CENTRALES)
b31ce2d7 128
7d9736ba 129 # Bureau
b31ce2d7 130 if 'bureau' in form.declared_fields:
d333c690
NBV
131 bureau_field = form.declared_fields['bureau']
132 else:
133 bureau_field = form.base_fields['bureau']
134
86e4bb65
DB
135 if grp_drh in user_groupes or \
136 grp_drh2 in user_groupes or \
137 grp_haute_direction in user_groupes:
d333c690
NBV
138 bureau_field.queryset = Bureau.objects.all()
139 else:
b31ce2d7
EMS
140 bureau_field.queryset = \
141 Bureau.objects.filter(region=employe.implantation.region)
142
3a542b85 143 return form
b31ce2d7 144
7d9736ba 145 ### Queryset
b31ce2d7 146
2f78949d 147 def queryset(self, request):
b31ce2d7
EMS
148 qs = self.model._default_manager.get_query_set() \
149 .select_related('offre_emploi')
f6724c20 150 user_groupes = request.user.groups.all()
86e4bb65
DB
151 if grp_drh in user_groupes or \
152 grp_drh2 in user_groupes or \
153 grp_haute_direction in user_groupes:
940c9dd8 154 return qs
f6724c20 155
86e4bb65
DB
156 if grp_directeurs_bureau in user_groupes or \
157 grp_correspondants_rh in user_groupes or \
158 grp_administrateurs in user_groupes:
7d9736ba 159 employe = get_emp(request.user)
940c9dd8 160 return qs.filter(region=employe.implantation.region)
7d9736ba 161
c69ecb4f 162 if Evaluateur.objects.filter(user=request.user).exists():
940c9dd8 163 evaluateur = Evaluateur.objects.get(user=request.user)
b31ce2d7
EMS
164 offre_ids = [
165 e.candidat.offre_emploi_id
166 for e in CandidatEvaluation.objects
167 .select_related('candidat')
168 .filter(evaluateur=evaluateur)
169 ]
940c9dd8
OL
170 return qs.filter(id__in=offre_ids)
171
7d9736ba
NBV
172 return qs.none()
173
174 ### Permission add, delete, change
3a542b85
NBV
175 def has_add_permission(self, request):
176 user_groupes = request.user.groups.all()
26add0fd 177 if request.user.is_superuser is True or \
86e4bb65
DB
178 grp_drh in user_groupes or \
179 grp_drh2 in user_groupes or \
180 grp_directeurs_bureau in user_groupes or \
181 grp_administrateurs in user_groupes or \
182 grp_haute_direction in user_groupes:
3a542b85 183 return True
b31ce2d7 184 return False
3a542b85 185
7d9736ba
NBV
186 def has_delete_permission(self, request, obj=None):
187 user_groupes = request.user.groups.all()
26add0fd 188 if request.user.is_superuser is True or \
86e4bb65
DB
189 grp_drh in user_groupes or \
190 grp_drh2 in user_groupes or \
191 grp_directeurs_bureau in user_groupes or \
192 grp_administrateurs in user_groupes or \
193 grp_haute_direction in user_groupes:
7d9736ba 194 return True
b31ce2d7 195 return False
7d9736ba 196
f6724c20
NBV
197 def has_change_permission(self, request, obj=None):
198 user_groupes = request.user.groups.all()
26add0fd 199 if request.user.is_superuser is True or \
86e4bb65
DB
200 grp_drh in user_groupes or \
201 grp_drh2 in user_groupes or \
202 grp_directeurs_bureau in user_groupes or \
203 grp_administrateurs in user_groupes or \
204 grp_haute_direction in user_groupes:
f6724c20 205 return True
b31ce2d7
EMS
206 return False
207
ad831560
PP
208 def formfield_for_foreignkey(self, db_field, request, **kwargs):
209 if db_field.name == 'lieu_affectation':
210 employe = get_emp(request.user)
211 kwargs["queryset"] = Implantation.objects.filter(region=employe.implantation.region)
212 return db_field.formfield(**kwargs)
213 return super(OffreEmploiAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
214
f6724c20
NBV
215
216class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
b31ce2d7
EMS
217 list_display = (
218 'nom', 'date_limite', 'region', 'statut', 'est_affiche'
219 )
220 readonly_fields = (
221 'description', 'bureau', 'duree_affectation', 'renumeration',
222 'debut_affectation', 'lieu_affectation', 'nom', 'resume',
223 'date_limite', 'region', 'poste'
224 )
f6724c20 225 fieldsets = (
720c3ad5 226 ('Nom', {
b31ce2d7 227 'fields': ('nom',)
f6724c20 228 }),
720c3ad5 229 ('Description générale', {
b31ce2d7 230 'fields': ('description', 'date_limite',)
f6724c20 231 }),
720c3ad5 232 ('Coordonnées', {
13389dae 233 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
f6724c20 234 }),
720c3ad5 235 ('Autre', {
b31ce2d7
EMS
236 'fields': (
237 'debut_affectation', 'duree_affectation', 'renumeration',
238 )
f6724c20 239 }),
b31ce2d7 240 )
464e5825 241 inlines = []
7d9736ba 242
b31ce2d7 243 ### Lieu de redirection après le change
a029f641 244 def response_change(self, request, obj):
b31ce2d7 245 return redirect('admin:recrutement_proxyoffreemploi_changelist')
a029f641 246
be343ed2
NBV
247 ### Formulaire
248 def get_form(self, request, obj=None, **kwargs):
249 form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs)
250 return form
251
7d9736ba 252 ### Permissions add, delete, change
f6724c20
NBV
253 def has_add_permission(self, request):
254 return False
255
256 def has_delete_permission(self, request, obj=None):
257 return False
258
2d083449 259 def has_change_permission(self, request, obj=None):
46c508f5
OL
260 if obj is not None:
261 return True
262
7b11d9ce 263 return not super(ProxyOffreEmploiAdmin, self).has_change_permission(request, obj)
2d083449 264
b31ce2d7 265
572c8d08
NBV
266class CandidatPieceInline(admin.TabularInline):
267 model = CandidatPiece
268 fields = ('candidat', 'nom', 'path',)
269 extra = 1
270 max_num = 3
271
b31ce2d7 272
c69ecb4f
OL
273class ReadOnlyCandidatPieceInline(CandidatPieceInline):
274 readonly_fields = ('candidat', 'nom', 'path', )
275 cand_delete = False
276
277
572c8d08
NBV
278class CandidatEvaluationInlineFormSet(BaseInlineFormSet):
279 """
280 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
281 """
282 def __init__(self, *args, **kwargs):
283 super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs)
b31ce2d7
EMS
284 self.can_delete = False
285
572c8d08
NBV
286
287class CandidatEvaluationInline(admin.TabularInline):
288 model = CandidatEvaluation
289 fields = ('evaluateur', 'note', 'commentaire')
290 max_num = 0
291 extra = 0
292 formset = CandidatEvaluationInlineFormSet
7d9736ba 293
b31ce2d7 294 ### Fields readonly
572c8d08
NBV
295 def get_readonly_fields(self, request, obj=None):
296 """
297 Empêche la modification des évaluations
298 """
299 if obj:
b31ce2d7 300 return self.readonly_fields + ('evaluateur', 'note', 'commentaire')
572c8d08
NBV
301 return self.readonly_fields
302
bdbc1f13
PP
303class CandidatAdmin(BaseAdmin, VersionAdmin, ExportAdmin):
304 change_list_template = 'admin/recrutement/candidat/change_list.html'
b31ce2d7 305 search_fields = ('nom', 'prenom')
7d0ae1ba 306 exclude = ('actif', )
940c9dd8 307 list_editable = ('statut', )
1b4c8020 308 list_display = ('_candidat', 'offre_emploi',
940c9dd8
OL
309 'voir_offre_emploi', 'calculer_moyenne',
310 'afficher_candidat', '_date_creation', 'statut', )
ee7a7cf8 311 list_filter = ('offre_emploi__nom', 'offre_emploi__region', 'statut', )
7d0ae1ba 312
7f9e891e 313 fieldsets = (
4896b661 314 ("Offre d'emploi", {
315 'fields': ('offre_emploi', )
316 }),
7f9e891e 317 ('Informations personnelles', {
b31ce2d7
EMS
318 'fields': (
319 'prenom', 'nom', 'genre', 'nationalite',
320 'situation_famille', 'nombre_dependant'
321 )
7f9e891e 322 }),
ec517164 323 ('Coordonnées', {
b31ce2d7
EMS
324 'fields': (
325 'telephone', 'email', 'adresse', 'ville', 'etat_province',
326 'code_postal', 'pays'
327 )
7f9e891e 328 }),
329 ('Informations professionnelles', {
b31ce2d7
EMS
330 'fields': (
331 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
332 'domaine_professionnel'
333 )
334 }),
65c4cbd9
NBV
335 ('Traitement', {
336 'fields': ('statut', )
7f9e891e 337 }),
338 )
170c9aa2 339 inlines = [
340 CandidatPieceInline,
572c8d08 341 CandidatEvaluationInline,
170c9aa2 342 ]
0b9dea96 343 actions = ['envoyer_courriel_candidats', 'changer_statut']
a029f641 344
bdbc1f13
PP
345 export_fields = ['statut', 'offre_emploi', 'prenom', 'nom', 'genre',
346 'nationalite', 'situation_famille', 'nombre_dependant',
347 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
348 'domaine_professionnel', 'telephone', 'email', 'adresse',
349 'ville', 'etat_province', 'code_postal', 'pays']
350
1b4c8020 351 def _candidat(self, obj):
b31ce2d7 352 txt = u"%s %s (%s)" % (obj.nom.upper(), obj.prenom, obj.genre)
1b4c8020
OL
353 txt = textwrap.wrap(txt, 30)
354 return "<br/>".join(txt)
355 _candidat.short_description = "Candidat"
356 _candidat.admin_order_field = "nom"
357 _candidat.allow_tags = True
358
940c9dd8
OL
359 def _date_creation(self, obj):
360 return obj.date_creation
1b4c8020
OL
361 _date_creation.admin_order_field = "date_creation"
362 _date_creation.short_description = "Date de réception"
940c9dd8 363
7d9736ba 364 ### Actions à afficher
a029f641
NBV
365 def get_actions(self, request):
366 actions = super(CandidatAdmin, self).get_actions(request)
367 del actions['delete_selected']
540dfae4 368 return actions
362a3534 369
7d9736ba 370 ### Envoyer un courriel à des candidats
b31ce2d7 371 def envoyer_courriel_candidats(modeladmin, obj, candidats):
52765380 372 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
373
b31ce2d7
EMS
374 return HttpResponseRedirect(
375 reverse('selectionner_template') + "?ids=%s" % (",".join(selected))
376 )
52765380 377 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
378
0b9dea96
PP
379 ### Changer le statut à des candidats
380 def changer_statut(modeladmin, request, queryset):
381 if request.POST.get('post'):
382 queryset.update(statut=request.POST.get('statut'))
383 return None
384
385 context = {
386 'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
387 'queryset': queryset,
388 'status': STATUT_CHOICES,
389 }
390
391 return render_to_response("recrutement/selectionner_statut.html",
392 context, context_instance = RequestContext(request))
393
394 changer_statut.short_description = u'Changer statut'
395
7d9736ba 396 ### Évaluer un candidat
596fe324 397 def evaluer_candidat(self, obj):
b31ce2d7
EMS
398 return "<a href='%s?candidat__id__exact=%s'>" \
399 "Évaluer le candidat</a>" % (
400 reverse('admin:recrutement_candidatevaluation_changelist'),
401 obj.id
402 )
403 evaluer_candidat.allow_tags = True
beef7690 404 evaluer_candidat.short_description = 'Évaluation'
596fe324 405
7d9736ba 406 ### Afficher un candidat
7d82fd33 407 def afficher_candidat(self, obj):
d2cbe75d
OL
408 items = [u"<li><a href='%s%s'>%s</li>" % \
409 (settings.OE_PRIVE_MEDIA_URL, pj.path, pj.get_nom_display()) \
410 for pj in obj.pieces_jointes()]
9a633e32 411 html = "<a href='%s'>Candidature</a>" % (
b31ce2d7
EMS
412 reverse('admin:recrutement_proxycandidat_change', args=(obj.id,))
413 )
d2cbe75d 414 return "%s<ul>%s</ul>" % (html, "\n".join(items))
b31ce2d7 415 afficher_candidat.allow_tags = True
8e0d552d 416 afficher_candidat.short_description = u'Détails du candidat'
7d82fd33 417
7d9736ba 418 ### Voir l'offre d'emploi
8941aee7 419 def voir_offre_emploi(self, obj):
b31ce2d7
EMS
420 return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse(
421 'admin:recrutement_proxyoffreemploi_change',
422 args=(obj.offre_emploi.id,)
423 ))
8941aee7 424 voir_offre_emploi.allow_tags = True
425 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
426
7d9736ba 427 ### Calculer la moyenne des notes
8941aee7 428 def calculer_moyenne(self, obj):
429 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
8941aee7 430
940c9dd8 431 notes = [evaluation.note for evaluation in evaluations \
f6724c20 432 if evaluation.note is not None]
b31ce2d7 433
7d0ae1ba 434 if len(notes) > 0:
d6790a12 435 moyenne_votes = round(float(sum(notes)) / len(notes), 2)
8941aee7 436 else:
437 moyenne_votes = "Non disponible"
940c9dd8
OL
438
439 totales = len(evaluations)
440 faites = len(notes)
441
b31ce2d7 442 if obj.statut == 'REC':
940c9dd8
OL
443 if totales == faites:
444 color = "green"
445 elif faites > 0 and float(totales) / float(faites) >= 2:
446 color = "orange"
447 else:
448 color = "red"
449 else:
450 color = "black"
451
b31ce2d7
EMS
452 return """<span style="color: %s;">%s (%s/%s)</span>""" % (
453 color, moyenne_votes, faites, totales
454 )
8941aee7 455 calculer_moyenne.allow_tags = True
3eb0be91 456 calculer_moyenne.short_description = "Moyenne"
d6790a12 457 calculer_moyenne.admin_order_field = ""
8941aee7 458
7d9736ba 459 ### Permissions add, delete, change
3a542b85 460 def has_add_permission(self, request):
f6724c20 461 user_groupes = request.user.groups.all()
26add0fd 462 if request.user.is_superuser is True or \
86e4bb65
DB
463 grp_correspondants_rh in user_groupes or \
464 grp_drh in user_groupes or \
465 grp_drh2 in user_groupes or \
466 grp_directeurs_bureau in user_groupes or \
467 grp_administrateurs in user_groupes or \
468 grp_haute_direction in user_groupes:
f6724c20 469 return True
b31ce2d7 470 return False
4896b661 471
f6724c20 472 def has_delete_permission(self, request, obj=None):
3a542b85 473 user_groupes = request.user.groups.all()
26add0fd 474 if request.user.is_superuser is True or \
86e4bb65
DB
475 grp_correspondants_rh in user_groupes or \
476 grp_drh in user_groupes or \
477 grp_drh2 in user_groupes or \
478 grp_directeurs_bureau in user_groupes or \
479 grp_administrateurs in user_groupes or \
480 grp_haute_direction in user_groupes:
3a542b85 481 return True
b31ce2d7 482 return False
f6724c20
NBV
483
484 def has_change_permission(self, request, obj=None):
485 user_groupes = request.user.groups.all()
26add0fd 486 if request.user.is_superuser is True or \
86e4bb65
DB
487 grp_correspondants_rh in user_groupes or \
488 grp_drh in user_groupes or \
489 grp_drh2 in user_groupes or \
490 grp_directeurs_bureau in user_groupes or \
491 grp_administrateurs in user_groupes or \
492 grp_haute_direction in user_groupes:
f6724c20 493 return True
97b168d6
OL
494 return False
495
4f456c0b
PP
496 def formfield_for_foreignkey(self, db_field, request, **kwargs):
497 if db_field.name == 'offre_emploi':
498 employe = get_emp(request.user)
499 kwargs["queryset"] = OffreEmploi.objects.filter(region=employe.implantation.region)
500 return db_field.formfield(**kwargs)
501 return super(CandidatAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
502
97b168d6
OL
503 def get_changelist(self, request, **kwargs):
504 return OrderedChangeList
4896b661 505
d46075cb 506 def queryset(self, request):
f9983b5a 507 """
b31ce2d7
EMS
508 Spécifie un queryset limité, autrement Django exécute un
509 select_related() sans paramètre, ce qui a pour effet de charger tous
510 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
511 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
8ea41642 512 génération d'une requête infinie.
f9983b5a 513 """
b31ce2d7
EMS
514 qs = self.model._default_manager.get_query_set() \
515 .select_related('offre_emploi') \
516 .annotate(moyenne=Avg('evaluations__note'))
97b168d6 517
d46075cb 518 user_groupes = request.user.groups.all()
86e4bb65
DB
519 if grp_drh in user_groupes or \
520 grp_drh2 in user_groupes or \
521 grp_haute_direction in user_groupes:
d6790a12 522 return qs
7d9736ba 523
86e4bb65
DB
524 if grp_directeurs_bureau in user_groupes or \
525 grp_correspondants_rh in user_groupes or \
526 grp_administrateurs in user_groupes:
7d9736ba 527 employe = get_emp(request.user)
d6790a12 528 return qs.filter(offre_emploi__region=employe.implantation.region)
7d9736ba 529
c69ecb4f 530 if Evaluateur.objects.filter(user=request.user).exists():
940c9dd8
OL
531 evaluateur = Evaluateur.objects.get(user=request.user)
532 candidat_ids = [e.candidat.id for e in
533 CandidatEvaluation.objects.filter(evaluateur=evaluateur)]
d6790a12 534 return qs.filter(id__in=candidat_ids)
b31ce2d7 535 return qs.none()
f6724c20 536
613e8dfe 537
f6724c20 538class ProxyCandidatAdmin(CandidatAdmin):
940c9dd8 539 list_editable = ()
b31ce2d7
EMS
540 readonly_fields = (
541 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
542 'situation_famille', 'nombre_dependant', 'telephone', 'email',
543 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
544 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
545 'domaine_professionnel', 'pieces_jointes'
546 )
2d083449
NBV
547 fieldsets = (
548 ("Offre d'emploi", {
549 'fields': ('offre_emploi', )
550 }),
551 ('Informations personnelles', {
b31ce2d7
EMS
552 'fields': (
553 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille',
554 'nombre_dependant'
555 )
2d083449
NBV
556 }),
557 ('Coordonnées', {
b31ce2d7
EMS
558 'fields': (
559 'telephone', 'email', 'adresse', 'ville', 'etat_province',
560 'code_postal', 'pays'
561 )
2d083449
NBV
562 }),
563 ('Informations professionnelles', {
b31ce2d7
EMS
564 'fields': (
565 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
566 'domaine_professionnel'
567 )
568 }),
2d083449 569 )
c69ecb4f 570 inlines = (CandidatEvaluationInline, )
2d083449 571
f6724c20
NBV
572 def has_add_permission(self, request):
573 return False
574
575 def has_delete_permission(self, request, obj=None):
576 return False
2adf9e0c 577
2d083449 578 def has_change_permission(self, request, obj=None):
b44ee2a0
OL
579 if obj is not None:
580 evaluateur = Evaluateur.objects.get(user=request.user)
581 for e in obj.evaluations.all():
582 if e.evaluateur == evaluateur:
583 return True
584
7b11d9ce 585 return not super(ProxyCandidatAdmin, self).has_change_permission(request, obj)
2d083449 586
fe6fe6bb
OL
587 def get_actions(self, request):
588 return None
589
b31ce2d7 590
2e9ee615 591class CandidatPieceAdmin(admin.ModelAdmin):
170c9aa2 592 list_display = ('nom', 'candidat', )
593
7d9736ba 594 ### Queryset
170c9aa2 595 def queryset(self, request):
596 """
b31ce2d7
EMS
597 Spécifie un queryset limité, autrement Django exécute un
598 select_related() sans paramètre, ce qui a pour effet de charger tous
599 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
600 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
601 génération d'une requête infinie. Affiche la liste de candidats que
602 si le user connecté possède un Evaluateur
170c9aa2 603 """
604 qs = self.model._default_manager.get_query_set()
605 return qs.select_related('candidat')
2e9ee615 606
b31ce2d7 607
08a9b6fc 608class EvaluateurAdmin(BaseAdmin, VersionAdmin):
eb579d40 609 fieldsets = (
540dfae4
NBV
610 ("Utilisateur", {
611 'fields': ('user',)
612 }),
eb579d40 613 )
4418c732 614
7d9736ba 615 ### Actions à afficher
a029f641
NBV
616 def get_actions(self, request):
617 actions = super(EvaluateurAdmin, self).get_actions(request)
618 del actions['delete_selected']
540dfae4 619 return actions
a029f641 620
7d9736ba
NBV
621 ### Permissions add, delete, change
622 def has_add_permission(self, request):
623 user_groupes = request.user.groups.all()
26add0fd 624 if request.user.is_superuser is True or \
86e4bb65
DB
625 grp_drh in user_groupes or \
626 grp_drh2 in user_groupes or \
627 grp_haute_direction in user_groupes:
7d9736ba 628 return True
b31ce2d7 629 return False
7d9736ba
NBV
630
631 def has_delete_permission(self, request, obj=None):
632 user_groupes = request.user.groups.all()
26add0fd 633 if request.user.is_superuser is True or \
86e4bb65
DB
634 grp_drh in user_groupes or \
635 grp_drh2 in user_groupes or \
636 grp_haute_direction in user_groupes:
7d9736ba 637 return True
b31ce2d7 638 return False
7d9736ba
NBV
639
640 def has_change_permission(self, request, obj=None):
641 user_groupes = request.user.groups.all()
26add0fd 642 if request.user.is_superuser is True or \
86e4bb65
DB
643 grp_drh in user_groupes or \
644 grp_drh2 in user_groupes or \
645 grp_haute_direction in user_groupes:
7d9736ba 646 return True
b31ce2d7
EMS
647 return False
648
27c81d11 649
08a9b6fc 650class CandidatEvaluationAdmin(BaseAdmin):
b31ce2d7
EMS
651 search_fields = ('candidat__nom', 'candidat__prenom')
652 list_display = (
653 '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
654 '_commentaire'
655 )
940c9dd8
OL
656 readonly_fields = ('candidat', 'evaluateur')
657 list_filter = ('candidat__statut', 'candidat__offre_emploi',)
beef7690
NBV
658 fieldsets = (
659 ('Évaluation du candidat', {
b31ce2d7 660 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
beef7690
NBV
661 }),
662 )
663
a029f641 664 def get_actions(self, request):
5fe6986f
OL
665 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
666 try:
667 self.evaluateur = Evaluateur.objects.get(user=request.user)
668 except:
669 self.evaluateur = None
670
a029f641
NBV
671 actions = super(CandidatEvaluationAdmin, self).get_actions(request)
672 del actions['delete_selected']
540dfae4 673 return actions
a029f641 674
7d9736ba 675 ### Afficher la note
beef7690
NBV
676 def _note(self, obj):
677 """
678 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
679 un lien pour Évaluer le candidat.
680 Sinon afficher la note.
681 """
c44cb3de
OL
682 page = self.model.__name__.lower()
683 redirect_url = 'admin:recrutement_%s_change' % page
b31ce2d7 684
beef7690 685 if obj.note is None:
5fe6986f
OL
686 label = "Candidat non évalué"
687 else:
688 label = obj.note
689
690 if self.evaluateur == obj.evaluateur:
b31ce2d7
EMS
691 return "<a href='%s'>%s</a>" % (
692 reverse(redirect_url, args=(obj.id,)), label
693 )
5fe6986f
OL
694 else:
695 return label
beef7690 696 _note.allow_tags = True
b31ce2d7
EMS
697 _note.short_description = "Note"
698 _note.admin_order_field = 'note'
beef7690 699
940c9dd8
OL
700 def _statut(self, obj):
701 return obj.candidat.get_statut_display()
702 _statut.order_field = 'candidat__statut'
703 _statut.short_description = 'Statut'
704
7d9736ba 705 ### Lien en lecture seule vers le candidat
beef7690
NBV
706 def _candidat(self, obj):
707 return "<a href='%s'>%s</a>" \
b31ce2d7 708 % (reverse('admin:recrutement_proxycandidat_change',
beef7690 709 args=(obj.candidat.id,)), obj.candidat)
b31ce2d7 710 _candidat.allow_tags = True
beef7690
NBV
711 _candidat.short_description = 'Candidat'
712
7d9736ba 713 ### Afficher commentaire
beef7690
NBV
714 def _commentaire(self, obj):
715 """
716 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
717 dans le champ commentaire, Aucun au lieu de (None)
718 Sinon afficher la note.
719 """
720 if obj.commentaire is None:
721 return "Aucun"
722 return obj.commentaire
723 _commentaire.allow_tags = True
b31ce2d7 724 _commentaire.short_description = "Commentaire"
720c3ad5 725
7d9736ba 726 ### Afficher offre d'emploi
beef7690
NBV
727 def _offre_emploi(self, obj):
728 return "<a href='%s'>%s</a>" % \
b31ce2d7 729 (reverse('admin:recrutement_proxyoffreemploi_change',
dc7faf2b 730 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
beef7690
NBV
731 _offre_emploi.allow_tags = True
732 _offre_emploi.short_description = "Voir offre d'emploi"
b31ce2d7 733
7d9736ba 734 def has_add_permission(self, request):
940c9dd8
OL
735 return False
736
737 def has_delete_permission(self, request, obj=None):
738 return False
7d9736ba 739
21b02da5
NBV
740 def has_change_permission(self, request, obj=None):
741 """
742 Permettre la visualisation dans la changelist
743 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
744 le request.user
745 """
f133459f
OL
746 user_groupes = request.user.groups.all()
747
3bc5ea42 748 if request.user.is_superuser or \
86e4bb65
DB
749 grp_drh in user_groupes or \
750 grp_drh2 in user_groupes or \
751 grp_correspondants_rh in user_groupes or \
752 grp_directeurs_bureau in user_groupes or \
753 grp_administrateurs in user_groupes or \
754 grp_haute_direction in user_groupes:
c5a263d6 755 is_recrutement = True
f133459f 756 else:
6c6c51bb 757 is_recrutement = False
f133459f 758
f6996aa3 759 return is_recrutement
f133459f 760
720c3ad5 761 def queryset(self, request):
beef7690 762 """
b31ce2d7 763 Afficher uniquement les évaluations de l'évaluateur, sauf si
7d9736ba 764 l'utilisateur est dans les groupes suivants.
beef7690 765 """
b31ce2d7
EMS
766 qs = self.model._default_manager.get_query_set() \
767 .select_related('offre_emploi')
beef7690 768 user_groupes = request.user.groups.all()
940c9dd8 769
86e4bb65
DB
770 if grp_drh in user_groupes or \
771 grp_drh2 in user_groupes or \
772 grp_correspondants_rh in user_groupes or \
773 grp_directeurs_bureau in user_groupes or \
774 grp_administrateurs in user_groupes or \
775 grp_haute_direction in user_groupes:
816f434c 776 return qs.filter(candidat__statut__in=('REC', 'SEL'))
940c9dd8 777
b31ce2d7 778 evaluateur = Evaluateur.objects.get(user=request.user)
940c9dd8
OL
779 candidats_evaluations = \
780 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
781 candidat__statut__in=('REC', ))
782 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
783 return qs.filter(id__in=candidats_evaluations_ids)
596fe324 784
3bc5ea42
OL
785
786class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin):
5f69d459 787 list_filter = []
3bc5ea42
OL
788
789 def has_change_permission(self, request, obj=None):
790 try:
791 Evaluateur.objects.get(user=request.user)
792 is_evaluateur = True
793 except:
794 is_evaluateur = False
795
5fe6986f 796 if obj is None and is_evaluateur:
3bc5ea42
OL
797 return True
798
799 try:
800 return request.user == obj.evaluateur.user
801 except:
802 return False
803
804 def queryset(self, request):
b31ce2d7
EMS
805 qs = self.model._default_manager.get_query_set() \
806 .select_related('offre_emploi')
807 evaluateur = Evaluateur.objects.get(user=request.user)
3bc5ea42
OL
808 candidats_evaluations = \
809 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
810 candidat__statut__in=('REC', ))
811 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
812 return qs.filter(id__in=candidats_evaluations_ids)
813
814
08a9b6fc 815class CourrielTemplateAdmin(BaseAdmin, VersionAdmin):
7d9736ba 816 ### Actions à afficher
a029f641
NBV
817 def get_actions(self, request):
818 actions = super(CourrielTemplateAdmin, self).get_actions(request)
819 del actions['delete_selected']
540dfae4 820 return actions
4e8340cf 821
df59fcab 822admin.site.register(OffreEmploi, OffreEmploiAdmin)
382501c1 823admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
df59fcab 824admin.site.register(Candidat, CandidatAdmin)
382501c1 825admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
720c3ad5 826admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
3bc5ea42 827admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin)
27c81d11 828admin.site.register(Evaluateur, EvaluateurAdmin)
32834000 829admin.site.register(CourrielTemplate, CourrielTemplateAdmin)