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