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