Mise en place de auf.django.export pour recrutement.Candidat
[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 \
90 </a>" % (reverse('admin:recrutement_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):
71aec2c3
OL
253 user_groupes = request.user.groups.all()
254 if request.user.is_superuser is True or \
86e4bb65
DB
255 grp_correspondants_rh in user_groupes or \
256 grp_drh in user_groupes or \
257 grp_drh2 in user_groupes or \
258 grp_directeurs_bureau in user_groupes or \
259 grp_administrateurs in user_groupes or \
260 grp_haute_direction in user_groupes:
71aec2c3 261 return True
46c508f5
OL
262
263 if obj is not None:
264 return True
265
71aec2c3 266 return False
2d083449 267
b31ce2d7 268
572c8d08
NBV
269class CandidatPieceInline(admin.TabularInline):
270 model = CandidatPiece
271 fields = ('candidat', 'nom', 'path',)
272 extra = 1
273 max_num = 3
274
b31ce2d7 275
c69ecb4f
OL
276class ReadOnlyCandidatPieceInline(CandidatPieceInline):
277 readonly_fields = ('candidat', 'nom', 'path', )
278 cand_delete = False
279
280
572c8d08
NBV
281class CandidatEvaluationInlineFormSet(BaseInlineFormSet):
282 """
283 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
284 """
285 def __init__(self, *args, **kwargs):
286 super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs)
b31ce2d7
EMS
287 self.can_delete = False
288
572c8d08
NBV
289
290class CandidatEvaluationInline(admin.TabularInline):
291 model = CandidatEvaluation
292 fields = ('evaluateur', 'note', 'commentaire')
293 max_num = 0
294 extra = 0
295 formset = CandidatEvaluationInlineFormSet
7d9736ba 296
b31ce2d7 297 ### Fields readonly
572c8d08
NBV
298 def get_readonly_fields(self, request, obj=None):
299 """
300 Empêche la modification des évaluations
301 """
302 if obj:
b31ce2d7 303 return self.readonly_fields + ('evaluateur', 'note', 'commentaire')
572c8d08
NBV
304 return self.readonly_fields
305
bdbc1f13
PP
306class CandidatAdmin(BaseAdmin, VersionAdmin, ExportAdmin):
307 change_list_template = 'admin/recrutement/candidat/change_list.html'
b31ce2d7 308 search_fields = ('nom', 'prenom')
7d0ae1ba 309 exclude = ('actif', )
940c9dd8 310 list_editable = ('statut', )
1b4c8020 311 list_display = ('_candidat', 'offre_emploi',
940c9dd8
OL
312 'voir_offre_emploi', 'calculer_moyenne',
313 'afficher_candidat', '_date_creation', 'statut', )
314 list_filter = ('offre_emploi', 'offre_emploi__region', 'statut', )
7d0ae1ba 315
7f9e891e 316 fieldsets = (
4896b661 317 ("Offre d'emploi", {
318 'fields': ('offre_emploi', )
319 }),
7f9e891e 320 ('Informations personnelles', {
b31ce2d7
EMS
321 'fields': (
322 'prenom', 'nom', 'genre', 'nationalite',
323 'situation_famille', 'nombre_dependant'
324 )
7f9e891e 325 }),
ec517164 326 ('Coordonnées', {
b31ce2d7
EMS
327 'fields': (
328 'telephone', 'email', 'adresse', 'ville', 'etat_province',
329 'code_postal', 'pays'
330 )
7f9e891e 331 }),
332 ('Informations professionnelles', {
b31ce2d7
EMS
333 'fields': (
334 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
335 'domaine_professionnel'
336 )
337 }),
65c4cbd9
NBV
338 ('Traitement', {
339 'fields': ('statut', )
7f9e891e 340 }),
341 )
170c9aa2 342 inlines = [
343 CandidatPieceInline,
572c8d08 344 CandidatEvaluationInline,
170c9aa2 345 ]
0b9dea96 346 actions = ['envoyer_courriel_candidats', 'changer_statut']
a029f641 347
bdbc1f13
PP
348 export_fields = ['statut', 'offre_emploi', 'prenom', 'nom', 'genre',
349 'nationalite', 'situation_famille', 'nombre_dependant',
350 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
351 'domaine_professionnel', 'telephone', 'email', 'adresse',
352 'ville', 'etat_province', 'code_postal', 'pays']
353
1b4c8020 354 def _candidat(self, obj):
b31ce2d7 355 txt = u"%s %s (%s)" % (obj.nom.upper(), obj.prenom, obj.genre)
1b4c8020
OL
356 txt = textwrap.wrap(txt, 30)
357 return "<br/>".join(txt)
358 _candidat.short_description = "Candidat"
359 _candidat.admin_order_field = "nom"
360 _candidat.allow_tags = True
361
940c9dd8
OL
362 def _date_creation(self, obj):
363 return obj.date_creation
1b4c8020
OL
364 _date_creation.admin_order_field = "date_creation"
365 _date_creation.short_description = "Date de réception"
940c9dd8 366
7d9736ba 367 ### Actions à afficher
a029f641
NBV
368 def get_actions(self, request):
369 actions = super(CandidatAdmin, self).get_actions(request)
370 del actions['delete_selected']
540dfae4 371 return actions
362a3534 372
7d9736ba 373 ### Envoyer un courriel à des candidats
b31ce2d7 374 def envoyer_courriel_candidats(modeladmin, obj, candidats):
52765380 375 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
376
b31ce2d7
EMS
377 return HttpResponseRedirect(
378 reverse('selectionner_template') + "?ids=%s" % (",".join(selected))
379 )
52765380 380 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
381
0b9dea96
PP
382 ### Changer le statut à des candidats
383 def changer_statut(modeladmin, request, queryset):
384 if request.POST.get('post'):
385 queryset.update(statut=request.POST.get('statut'))
386 return None
387
388 context = {
389 'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
390 'queryset': queryset,
391 'status': STATUT_CHOICES,
392 }
393
394 return render_to_response("recrutement/selectionner_statut.html",
395 context, context_instance = RequestContext(request))
396
397 changer_statut.short_description = u'Changer statut'
398
7d9736ba 399 ### Évaluer un candidat
596fe324 400 def evaluer_candidat(self, obj):
b31ce2d7
EMS
401 return "<a href='%s?candidat__id__exact=%s'>" \
402 "Évaluer le candidat</a>" % (
403 reverse('admin:recrutement_candidatevaluation_changelist'),
404 obj.id
405 )
406 evaluer_candidat.allow_tags = True
beef7690 407 evaluer_candidat.short_description = 'Évaluation'
596fe324 408
7d9736ba 409 ### Afficher un candidat
7d82fd33 410 def afficher_candidat(self, obj):
d2cbe75d
OL
411 items = [u"<li><a href='%s%s'>%s</li>" % \
412 (settings.OE_PRIVE_MEDIA_URL, pj.path, pj.get_nom_display()) \
413 for pj in obj.pieces_jointes()]
b31ce2d7
EMS
414 html = "<a href='%s'>Voir le candidat</a>" % (
415 reverse('admin:recrutement_proxycandidat_change', args=(obj.id,))
416 )
d2cbe75d 417 return "%s<ul>%s</ul>" % (html, "\n".join(items))
b31ce2d7 418 afficher_candidat.allow_tags = True
8e0d552d 419 afficher_candidat.short_description = u'Détails du candidat'
7d82fd33 420
7d9736ba 421 ### Voir l'offre d'emploi
8941aee7 422 def voir_offre_emploi(self, obj):
b31ce2d7
EMS
423 return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse(
424 'admin:recrutement_proxyoffreemploi_change',
425 args=(obj.offre_emploi.id,)
426 ))
8941aee7 427 voir_offre_emploi.allow_tags = True
428 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
429
7d9736ba 430 ### Calculer la moyenne des notes
8941aee7 431 def calculer_moyenne(self, obj):
432 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
8941aee7 433
940c9dd8 434 notes = [evaluation.note for evaluation in evaluations \
f6724c20 435 if evaluation.note is not None]
b31ce2d7 436
7d0ae1ba 437 if len(notes) > 0:
d6790a12 438 moyenne_votes = round(float(sum(notes)) / len(notes), 2)
8941aee7 439 else:
440 moyenne_votes = "Non disponible"
940c9dd8
OL
441
442 totales = len(evaluations)
443 faites = len(notes)
444
b31ce2d7 445 if obj.statut == 'REC':
940c9dd8
OL
446 if totales == faites:
447 color = "green"
448 elif faites > 0 and float(totales) / float(faites) >= 2:
449 color = "orange"
450 else:
451 color = "red"
452 else:
453 color = "black"
454
b31ce2d7
EMS
455 return """<span style="color: %s;">%s (%s/%s)</span>""" % (
456 color, moyenne_votes, faites, totales
457 )
8941aee7 458 calculer_moyenne.allow_tags = True
3eb0be91 459 calculer_moyenne.short_description = "Moyenne"
d6790a12 460 calculer_moyenne.admin_order_field = ""
8941aee7 461
7d9736ba 462 ### Permissions add, delete, change
3a542b85 463 def has_add_permission(self, request):
f6724c20 464 user_groupes = request.user.groups.all()
26add0fd 465 if request.user.is_superuser is True or \
86e4bb65
DB
466 grp_correspondants_rh in user_groupes or \
467 grp_drh in user_groupes or \
468 grp_drh2 in user_groupes or \
469 grp_directeurs_bureau in user_groupes or \
470 grp_administrateurs in user_groupes or \
471 grp_haute_direction in user_groupes:
f6724c20 472 return True
b31ce2d7 473 return False
4896b661 474
f6724c20 475 def has_delete_permission(self, request, obj=None):
3a542b85 476 user_groupes = request.user.groups.all()
26add0fd 477 if request.user.is_superuser is True or \
86e4bb65
DB
478 grp_correspondants_rh in user_groupes or \
479 grp_drh in user_groupes or \
480 grp_drh2 in user_groupes or \
481 grp_directeurs_bureau in user_groupes or \
482 grp_administrateurs in user_groupes or \
483 grp_haute_direction in user_groupes:
3a542b85 484 return True
b31ce2d7 485 return False
f6724c20
NBV
486
487 def has_change_permission(self, request, obj=None):
488 user_groupes = request.user.groups.all()
26add0fd 489 if request.user.is_superuser is True or \
86e4bb65
DB
490 grp_correspondants_rh in user_groupes or \
491 grp_drh in user_groupes or \
492 grp_drh2 in user_groupes or \
493 grp_directeurs_bureau in user_groupes or \
494 grp_administrateurs in user_groupes or \
495 grp_haute_direction in user_groupes:
f6724c20 496 return True
97b168d6
OL
497 return False
498
499 def get_changelist(self, request, **kwargs):
500 return OrderedChangeList
4896b661 501
d46075cb 502 def queryset(self, request):
f9983b5a 503 """
b31ce2d7
EMS
504 Spécifie un queryset limité, autrement Django exécute un
505 select_related() sans paramètre, ce qui a pour effet de charger tous
506 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
507 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
8ea41642 508 génération d'une requête infinie.
f9983b5a 509 """
b31ce2d7
EMS
510 qs = self.model._default_manager.get_query_set() \
511 .select_related('offre_emploi') \
512 .annotate(moyenne=Avg('evaluations__note'))
97b168d6 513
d46075cb 514 user_groupes = request.user.groups.all()
86e4bb65
DB
515 if grp_drh in user_groupes or \
516 grp_drh2 in user_groupes or \
517 grp_haute_direction in user_groupes:
d6790a12 518 return qs
7d9736ba 519
86e4bb65
DB
520 if grp_directeurs_bureau in user_groupes or \
521 grp_correspondants_rh in user_groupes or \
522 grp_administrateurs in user_groupes:
7d9736ba 523 employe = get_emp(request.user)
d6790a12 524 return qs.filter(offre_emploi__region=employe.implantation.region)
7d9736ba 525
c69ecb4f 526 if Evaluateur.objects.filter(user=request.user).exists():
940c9dd8
OL
527 evaluateur = Evaluateur.objects.get(user=request.user)
528 candidat_ids = [e.candidat.id for e in
529 CandidatEvaluation.objects.filter(evaluateur=evaluateur)]
d6790a12 530 return qs.filter(id__in=candidat_ids)
b31ce2d7 531 return qs.none()
f6724c20 532
613e8dfe 533
f6724c20 534class ProxyCandidatAdmin(CandidatAdmin):
940c9dd8 535 list_editable = ()
b31ce2d7
EMS
536 readonly_fields = (
537 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
538 'situation_famille', 'nombre_dependant', 'telephone', 'email',
539 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
540 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
541 'domaine_professionnel', 'pieces_jointes'
542 )
2d083449
NBV
543 fieldsets = (
544 ("Offre d'emploi", {
545 'fields': ('offre_emploi', )
546 }),
547 ('Informations personnelles', {
b31ce2d7
EMS
548 'fields': (
549 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille',
550 'nombre_dependant'
551 )
2d083449
NBV
552 }),
553 ('Coordonnées', {
b31ce2d7
EMS
554 'fields': (
555 'telephone', 'email', 'adresse', 'ville', 'etat_province',
556 'code_postal', 'pays'
557 )
2d083449
NBV
558 }),
559 ('Informations professionnelles', {
b31ce2d7
EMS
560 'fields': (
561 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
562 'domaine_professionnel'
563 )
564 }),
2d083449 565 )
c69ecb4f 566 inlines = (CandidatEvaluationInline, )
2d083449 567
f6724c20
NBV
568 def has_add_permission(self, request):
569 return False
570
571 def has_delete_permission(self, request, obj=None):
572 return False
2adf9e0c 573
2d083449 574 def has_change_permission(self, request, obj=None):
71aec2c3
OL
575 user_groupes = request.user.groups.all()
576 if request.user.is_superuser is True or \
86e4bb65
DB
577 grp_correspondants_rh in user_groupes or \
578 grp_drh in user_groupes or \
579 grp_drh2 in user_groupes or \
580 grp_directeurs_bureau in user_groupes or \
581 grp_administrateurs in user_groupes or \
582 grp_haute_direction in user_groupes:
71aec2c3 583 return True
b44ee2a0
OL
584
585 if obj is not None:
586 evaluateur = Evaluateur.objects.get(user=request.user)
587 for e in obj.evaluations.all():
588 if e.evaluateur == evaluateur:
589 return True
590
71aec2c3 591 return False
2d083449 592
fe6fe6bb
OL
593 def get_actions(self, request):
594 return None
595
b31ce2d7 596
2e9ee615 597class CandidatPieceAdmin(admin.ModelAdmin):
170c9aa2 598 list_display = ('nom', 'candidat', )
599
7d9736ba 600 ### Queryset
170c9aa2 601 def queryset(self, request):
602 """
b31ce2d7
EMS
603 Spécifie un queryset limité, autrement Django exécute un
604 select_related() sans paramètre, ce qui a pour effet de charger tous
605 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
606 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
607 génération d'une requête infinie. Affiche la liste de candidats que
608 si le user connecté possède un Evaluateur
170c9aa2 609 """
610 qs = self.model._default_manager.get_query_set()
611 return qs.select_related('candidat')
2e9ee615 612
b31ce2d7 613
08a9b6fc 614class EvaluateurAdmin(BaseAdmin, VersionAdmin):
eb579d40 615 fieldsets = (
540dfae4
NBV
616 ("Utilisateur", {
617 'fields': ('user',)
618 }),
eb579d40 619 )
4418c732 620
7d9736ba 621 ### Actions à afficher
a029f641
NBV
622 def get_actions(self, request):
623 actions = super(EvaluateurAdmin, self).get_actions(request)
624 del actions['delete_selected']
540dfae4 625 return actions
a029f641 626
7d9736ba
NBV
627 ### Permissions add, delete, change
628 def has_add_permission(self, request):
629 user_groupes = request.user.groups.all()
26add0fd 630 if request.user.is_superuser is True or \
86e4bb65
DB
631 grp_drh in user_groupes or \
632 grp_drh2 in user_groupes or \
633 grp_haute_direction in user_groupes:
7d9736ba 634 return True
b31ce2d7 635 return False
7d9736ba
NBV
636
637 def has_delete_permission(self, request, obj=None):
638 user_groupes = request.user.groups.all()
26add0fd 639 if request.user.is_superuser is True or \
86e4bb65
DB
640 grp_drh in user_groupes or \
641 grp_drh2 in user_groupes or \
642 grp_haute_direction in user_groupes:
7d9736ba 643 return True
b31ce2d7 644 return False
7d9736ba
NBV
645
646 def has_change_permission(self, request, obj=None):
647 user_groupes = request.user.groups.all()
26add0fd 648 if request.user.is_superuser is True or \
86e4bb65
DB
649 grp_drh in user_groupes or \
650 grp_drh2 in user_groupes or \
651 grp_haute_direction in user_groupes:
7d9736ba 652 return True
b31ce2d7
EMS
653 return False
654
27c81d11 655
08a9b6fc 656class CandidatEvaluationAdmin(BaseAdmin):
b31ce2d7
EMS
657 search_fields = ('candidat__nom', 'candidat__prenom')
658 list_display = (
659 '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
660 '_commentaire'
661 )
940c9dd8
OL
662 readonly_fields = ('candidat', 'evaluateur')
663 list_filter = ('candidat__statut', 'candidat__offre_emploi',)
beef7690
NBV
664 fieldsets = (
665 ('Évaluation du candidat', {
b31ce2d7 666 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
beef7690
NBV
667 }),
668 )
669
a029f641 670 def get_actions(self, request):
5fe6986f
OL
671 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
672 try:
673 self.evaluateur = Evaluateur.objects.get(user=request.user)
674 except:
675 self.evaluateur = None
676
a029f641
NBV
677 actions = super(CandidatEvaluationAdmin, self).get_actions(request)
678 del actions['delete_selected']
540dfae4 679 return actions
a029f641 680
7d9736ba 681 ### Afficher la note
beef7690
NBV
682 def _note(self, obj):
683 """
684 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
685 un lien pour Évaluer le candidat.
686 Sinon afficher la note.
687 """
c44cb3de
OL
688 page = self.model.__name__.lower()
689 redirect_url = 'admin:recrutement_%s_change' % page
b31ce2d7 690
beef7690 691 if obj.note is None:
5fe6986f
OL
692 label = "Candidat non évalué"
693 else:
694 label = obj.note
695
696 if self.evaluateur == obj.evaluateur:
b31ce2d7
EMS
697 return "<a href='%s'>%s</a>" % (
698 reverse(redirect_url, args=(obj.id,)), label
699 )
5fe6986f
OL
700 else:
701 return label
beef7690 702 _note.allow_tags = True
b31ce2d7
EMS
703 _note.short_description = "Note"
704 _note.admin_order_field = 'note'
beef7690 705
940c9dd8
OL
706 def _statut(self, obj):
707 return obj.candidat.get_statut_display()
708 _statut.order_field = 'candidat__statut'
709 _statut.short_description = 'Statut'
710
7d9736ba 711 ### Lien en lecture seule vers le candidat
beef7690
NBV
712 def _candidat(self, obj):
713 return "<a href='%s'>%s</a>" \
b31ce2d7 714 % (reverse('admin:recrutement_proxycandidat_change',
beef7690 715 args=(obj.candidat.id,)), obj.candidat)
b31ce2d7 716 _candidat.allow_tags = True
beef7690
NBV
717 _candidat.short_description = 'Candidat'
718
7d9736ba 719 ### Afficher commentaire
beef7690
NBV
720 def _commentaire(self, obj):
721 """
722 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
723 dans le champ commentaire, Aucun au lieu de (None)
724 Sinon afficher la note.
725 """
726 if obj.commentaire is None:
727 return "Aucun"
728 return obj.commentaire
729 _commentaire.allow_tags = True
b31ce2d7 730 _commentaire.short_description = "Commentaire"
720c3ad5 731
7d9736ba 732 ### Afficher offre d'emploi
beef7690
NBV
733 def _offre_emploi(self, obj):
734 return "<a href='%s'>%s</a>" % \
b31ce2d7 735 (reverse('admin:recrutement_proxyoffreemploi_change',
dc7faf2b 736 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
beef7690
NBV
737 _offre_emploi.allow_tags = True
738 _offre_emploi.short_description = "Voir offre d'emploi"
b31ce2d7 739
7d9736ba 740 def has_add_permission(self, request):
940c9dd8
OL
741 return False
742
743 def has_delete_permission(self, request, obj=None):
744 return False
7d9736ba 745
21b02da5
NBV
746 def has_change_permission(self, request, obj=None):
747 """
748 Permettre la visualisation dans la changelist
749 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
750 le request.user
751 """
f133459f
OL
752 user_groupes = request.user.groups.all()
753
3bc5ea42 754 if request.user.is_superuser or \
86e4bb65
DB
755 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:
c5a263d6 761 is_recrutement = True
f133459f 762 else:
6c6c51bb 763 is_recrutement = False
f133459f 764
f6996aa3 765 return is_recrutement
f133459f 766
720c3ad5 767 def queryset(self, request):
beef7690 768 """
b31ce2d7 769 Afficher uniquement les évaluations de l'évaluateur, sauf si
7d9736ba 770 l'utilisateur est dans les groupes suivants.
beef7690 771 """
b31ce2d7
EMS
772 qs = self.model._default_manager.get_query_set() \
773 .select_related('offre_emploi')
beef7690 774 user_groupes = request.user.groups.all()
940c9dd8 775
86e4bb65
DB
776 if grp_drh in user_groupes or \
777 grp_drh2 in user_groupes or \
778 grp_correspondants_rh in user_groupes or \
779 grp_directeurs_bureau in user_groupes or \
780 grp_administrateurs in user_groupes or \
781 grp_haute_direction in user_groupes:
940c9dd8
OL
782 return qs
783
b31ce2d7 784 evaluateur = Evaluateur.objects.get(user=request.user)
940c9dd8
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)
596fe324 790
3bc5ea42
OL
791
792class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin):
793
794 def has_change_permission(self, request, obj=None):
795 try:
796 Evaluateur.objects.get(user=request.user)
797 is_evaluateur = True
798 except:
799 is_evaluateur = False
800
5fe6986f 801 if obj is None and is_evaluateur:
3bc5ea42
OL
802 return True
803
804 try:
805 return request.user == obj.evaluateur.user
806 except:
807 return False
808
809 def queryset(self, request):
b31ce2d7
EMS
810 qs = self.model._default_manager.get_query_set() \
811 .select_related('offre_emploi')
812 evaluateur = Evaluateur.objects.get(user=request.user)
3bc5ea42
OL
813 candidats_evaluations = \
814 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
815 candidat__statut__in=('REC', ))
816 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
817 return qs.filter(id__in=candidats_evaluations_ids)
818
819
08a9b6fc 820class CourrielTemplateAdmin(BaseAdmin, VersionAdmin):
7d9736ba 821 ### Actions à afficher
a029f641
NBV
822 def get_actions(self, request):
823 actions = super(CourrielTemplateAdmin, self).get_actions(request)
824 del actions['delete_selected']
540dfae4 825 return actions
4e8340cf 826
df59fcab 827admin.site.register(OffreEmploi, OffreEmploiAdmin)
382501c1 828admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
df59fcab 829admin.site.register(Candidat, CandidatAdmin)
382501c1 830admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
720c3ad5 831admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
3bc5ea42 832admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin)
27c81d11 833admin.site.register(Evaluateur, EvaluateurAdmin)
32834000 834admin.site.register(CourrielTemplate, CourrielTemplateAdmin)