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