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