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