[#3265] ajout candidature : limiter les offres d'emploi à la région du user
[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):
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', )
ee7a7cf8 314 list_filter = ('offre_emploi__nom', '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()]
9a633e32 414 html = "<a href='%s'>Candidature</a>" % (
b31ce2d7
EMS
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
4f456c0b
PP
499 def formfield_for_foreignkey(self, db_field, request, **kwargs):
500 if db_field.name == 'offre_emploi':
501 employe = get_emp(request.user)
502 kwargs["queryset"] = OffreEmploi.objects.filter(region=employe.implantation.region)
503 return db_field.formfield(**kwargs)
504 return super(CandidatAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)
505
97b168d6
OL
506 def get_changelist(self, request, **kwargs):
507 return OrderedChangeList
4896b661 508
d46075cb 509 def queryset(self, request):
f9983b5a 510 """
b31ce2d7
EMS
511 Spécifie un queryset limité, autrement Django exécute un
512 select_related() sans paramètre, ce qui a pour effet de charger tous
513 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
514 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
8ea41642 515 génération d'une requête infinie.
f9983b5a 516 """
b31ce2d7
EMS
517 qs = self.model._default_manager.get_query_set() \
518 .select_related('offre_emploi') \
519 .annotate(moyenne=Avg('evaluations__note'))
97b168d6 520
d46075cb 521 user_groupes = request.user.groups.all()
86e4bb65
DB
522 if grp_drh in user_groupes or \
523 grp_drh2 in user_groupes or \
524 grp_haute_direction in user_groupes:
d6790a12 525 return qs
7d9736ba 526
86e4bb65
DB
527 if grp_directeurs_bureau in user_groupes or \
528 grp_correspondants_rh in user_groupes or \
529 grp_administrateurs in user_groupes:
7d9736ba 530 employe = get_emp(request.user)
d6790a12 531 return qs.filter(offre_emploi__region=employe.implantation.region)
7d9736ba 532
c69ecb4f 533 if Evaluateur.objects.filter(user=request.user).exists():
940c9dd8
OL
534 evaluateur = Evaluateur.objects.get(user=request.user)
535 candidat_ids = [e.candidat.id for e in
536 CandidatEvaluation.objects.filter(evaluateur=evaluateur)]
d6790a12 537 return qs.filter(id__in=candidat_ids)
b31ce2d7 538 return qs.none()
f6724c20 539
613e8dfe 540
f6724c20 541class ProxyCandidatAdmin(CandidatAdmin):
940c9dd8 542 list_editable = ()
b31ce2d7
EMS
543 readonly_fields = (
544 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
545 'situation_famille', 'nombre_dependant', 'telephone', 'email',
546 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
547 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
548 'domaine_professionnel', 'pieces_jointes'
549 )
2d083449
NBV
550 fieldsets = (
551 ("Offre d'emploi", {
552 'fields': ('offre_emploi', )
553 }),
554 ('Informations personnelles', {
b31ce2d7
EMS
555 'fields': (
556 'prenom', 'nom', 'genre', 'nationalite', 'situation_famille',
557 'nombre_dependant'
558 )
2d083449
NBV
559 }),
560 ('Coordonnées', {
b31ce2d7
EMS
561 'fields': (
562 'telephone', 'email', 'adresse', 'ville', 'etat_province',
563 'code_postal', 'pays'
564 )
2d083449
NBV
565 }),
566 ('Informations professionnelles', {
b31ce2d7
EMS
567 'fields': (
568 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
569 'domaine_professionnel'
570 )
571 }),
2d083449 572 )
c69ecb4f 573 inlines = (CandidatEvaluationInline, )
2d083449 574
f6724c20
NBV
575 def has_add_permission(self, request):
576 return False
577
578 def has_delete_permission(self, request, obj=None):
579 return False
2adf9e0c 580
2d083449 581 def has_change_permission(self, request, obj=None):
71aec2c3
OL
582 user_groupes = request.user.groups.all()
583 if request.user.is_superuser is True or \
86e4bb65
DB
584 grp_correspondants_rh in user_groupes or \
585 grp_drh in user_groupes or \
586 grp_drh2 in user_groupes or \
587 grp_directeurs_bureau in user_groupes or \
588 grp_administrateurs in user_groupes or \
589 grp_haute_direction in user_groupes:
71aec2c3 590 return True
b44ee2a0
OL
591
592 if obj is not None:
593 evaluateur = Evaluateur.objects.get(user=request.user)
594 for e in obj.evaluations.all():
595 if e.evaluateur == evaluateur:
596 return True
597
71aec2c3 598 return False
2d083449 599
fe6fe6bb
OL
600 def get_actions(self, request):
601 return None
602
b31ce2d7 603
2e9ee615 604class CandidatPieceAdmin(admin.ModelAdmin):
170c9aa2 605 list_display = ('nom', 'candidat', )
606
7d9736ba 607 ### Queryset
170c9aa2 608 def queryset(self, request):
609 """
b31ce2d7
EMS
610 Spécifie un queryset limité, autrement Django exécute un
611 select_related() sans paramètre, ce qui a pour effet de charger tous
612 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
613 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
614 génération d'une requête infinie. Affiche la liste de candidats que
615 si le user connecté possède un Evaluateur
170c9aa2 616 """
617 qs = self.model._default_manager.get_query_set()
618 return qs.select_related('candidat')
2e9ee615 619
b31ce2d7 620
08a9b6fc 621class EvaluateurAdmin(BaseAdmin, VersionAdmin):
eb579d40 622 fieldsets = (
540dfae4
NBV
623 ("Utilisateur", {
624 'fields': ('user',)
625 }),
eb579d40 626 )
4418c732 627
7d9736ba 628 ### Actions à afficher
a029f641
NBV
629 def get_actions(self, request):
630 actions = super(EvaluateurAdmin, self).get_actions(request)
631 del actions['delete_selected']
540dfae4 632 return actions
a029f641 633
7d9736ba
NBV
634 ### Permissions add, delete, change
635 def has_add_permission(self, request):
636 user_groupes = request.user.groups.all()
26add0fd 637 if request.user.is_superuser is True or \
86e4bb65
DB
638 grp_drh in user_groupes or \
639 grp_drh2 in user_groupes or \
640 grp_haute_direction in user_groupes:
7d9736ba 641 return True
b31ce2d7 642 return False
7d9736ba
NBV
643
644 def has_delete_permission(self, request, obj=None):
645 user_groupes = request.user.groups.all()
26add0fd 646 if request.user.is_superuser is True or \
86e4bb65
DB
647 grp_drh in user_groupes or \
648 grp_drh2 in user_groupes or \
649 grp_haute_direction in user_groupes:
7d9736ba 650 return True
b31ce2d7 651 return False
7d9736ba
NBV
652
653 def has_change_permission(self, request, obj=None):
654 user_groupes = request.user.groups.all()
26add0fd 655 if request.user.is_superuser is True or \
86e4bb65
DB
656 grp_drh in user_groupes or \
657 grp_drh2 in user_groupes or \
658 grp_haute_direction in user_groupes:
7d9736ba 659 return True
b31ce2d7
EMS
660 return False
661
27c81d11 662
08a9b6fc 663class CandidatEvaluationAdmin(BaseAdmin):
b31ce2d7
EMS
664 search_fields = ('candidat__nom', 'candidat__prenom')
665 list_display = (
666 '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
667 '_commentaire'
668 )
940c9dd8
OL
669 readonly_fields = ('candidat', 'evaluateur')
670 list_filter = ('candidat__statut', 'candidat__offre_emploi',)
beef7690
NBV
671 fieldsets = (
672 ('Évaluation du candidat', {
b31ce2d7 673 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
beef7690
NBV
674 }),
675 )
676
a029f641 677 def get_actions(self, request):
5fe6986f
OL
678 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
679 try:
680 self.evaluateur = Evaluateur.objects.get(user=request.user)
681 except:
682 self.evaluateur = None
683
a029f641
NBV
684 actions = super(CandidatEvaluationAdmin, self).get_actions(request)
685 del actions['delete_selected']
540dfae4 686 return actions
a029f641 687
7d9736ba 688 ### Afficher la note
beef7690
NBV
689 def _note(self, obj):
690 """
691 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
692 un lien pour Évaluer le candidat.
693 Sinon afficher la note.
694 """
c44cb3de
OL
695 page = self.model.__name__.lower()
696 redirect_url = 'admin:recrutement_%s_change' % page
b31ce2d7 697
beef7690 698 if obj.note is None:
5fe6986f
OL
699 label = "Candidat non évalué"
700 else:
701 label = obj.note
702
703 if self.evaluateur == obj.evaluateur:
b31ce2d7
EMS
704 return "<a href='%s'>%s</a>" % (
705 reverse(redirect_url, args=(obj.id,)), label
706 )
5fe6986f
OL
707 else:
708 return label
beef7690 709 _note.allow_tags = True
b31ce2d7
EMS
710 _note.short_description = "Note"
711 _note.admin_order_field = 'note'
beef7690 712
940c9dd8
OL
713 def _statut(self, obj):
714 return obj.candidat.get_statut_display()
715 _statut.order_field = 'candidat__statut'
716 _statut.short_description = 'Statut'
717
7d9736ba 718 ### Lien en lecture seule vers le candidat
beef7690
NBV
719 def _candidat(self, obj):
720 return "<a href='%s'>%s</a>" \
b31ce2d7 721 % (reverse('admin:recrutement_proxycandidat_change',
beef7690 722 args=(obj.candidat.id,)), obj.candidat)
b31ce2d7 723 _candidat.allow_tags = True
beef7690
NBV
724 _candidat.short_description = 'Candidat'
725
7d9736ba 726 ### Afficher commentaire
beef7690
NBV
727 def _commentaire(self, obj):
728 """
729 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
730 dans le champ commentaire, Aucun au lieu de (None)
731 Sinon afficher la note.
732 """
733 if obj.commentaire is None:
734 return "Aucun"
735 return obj.commentaire
736 _commentaire.allow_tags = True
b31ce2d7 737 _commentaire.short_description = "Commentaire"
720c3ad5 738
7d9736ba 739 ### Afficher offre d'emploi
beef7690
NBV
740 def _offre_emploi(self, obj):
741 return "<a href='%s'>%s</a>" % \
b31ce2d7 742 (reverse('admin:recrutement_proxyoffreemploi_change',
dc7faf2b 743 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
beef7690
NBV
744 _offre_emploi.allow_tags = True
745 _offre_emploi.short_description = "Voir offre d'emploi"
b31ce2d7 746
7d9736ba 747 def has_add_permission(self, request):
940c9dd8
OL
748 return False
749
750 def has_delete_permission(self, request, obj=None):
751 return False
7d9736ba 752
21b02da5
NBV
753 def has_change_permission(self, request, obj=None):
754 """
755 Permettre la visualisation dans la changelist
756 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
757 le request.user
758 """
f133459f
OL
759 user_groupes = request.user.groups.all()
760
3bc5ea42 761 if request.user.is_superuser or \
86e4bb65
DB
762 grp_drh in user_groupes or \
763 grp_drh2 in user_groupes or \
764 grp_correspondants_rh in user_groupes or \
765 grp_directeurs_bureau in user_groupes or \
766 grp_administrateurs in user_groupes or \
767 grp_haute_direction in user_groupes:
c5a263d6 768 is_recrutement = True
f133459f 769 else:
6c6c51bb 770 is_recrutement = False
f133459f 771
f6996aa3 772 return is_recrutement
f133459f 773
720c3ad5 774 def queryset(self, request):
beef7690 775 """
b31ce2d7 776 Afficher uniquement les évaluations de l'évaluateur, sauf si
7d9736ba 777 l'utilisateur est dans les groupes suivants.
beef7690 778 """
b31ce2d7
EMS
779 qs = self.model._default_manager.get_query_set() \
780 .select_related('offre_emploi')
beef7690 781 user_groupes = request.user.groups.all()
940c9dd8 782
86e4bb65
DB
783 if grp_drh in user_groupes or \
784 grp_drh2 in user_groupes or \
785 grp_correspondants_rh in user_groupes or \
786 grp_directeurs_bureau in user_groupes or \
787 grp_administrateurs in user_groupes or \
788 grp_haute_direction in user_groupes:
816f434c 789 return qs.filter(candidat__statut__in=('REC', 'SEL'))
940c9dd8 790
b31ce2d7 791 evaluateur = Evaluateur.objects.get(user=request.user)
940c9dd8
OL
792 candidats_evaluations = \
793 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
794 candidat__statut__in=('REC', ))
795 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
796 return qs.filter(id__in=candidats_evaluations_ids)
596fe324 797
3bc5ea42
OL
798
799class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin):
5f69d459 800 list_filter = []
3bc5ea42
OL
801
802 def has_change_permission(self, request, obj=None):
803 try:
804 Evaluateur.objects.get(user=request.user)
805 is_evaluateur = True
806 except:
807 is_evaluateur = False
808
5fe6986f 809 if obj is None and is_evaluateur:
3bc5ea42
OL
810 return True
811
812 try:
813 return request.user == obj.evaluateur.user
814 except:
815 return False
816
817 def queryset(self, request):
b31ce2d7
EMS
818 qs = self.model._default_manager.get_query_set() \
819 .select_related('offre_emploi')
820 evaluateur = Evaluateur.objects.get(user=request.user)
3bc5ea42
OL
821 candidats_evaluations = \
822 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
823 candidat__statut__in=('REC', ))
824 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
825 return qs.filter(id__in=candidats_evaluations_ids)
826
827
08a9b6fc 828class CourrielTemplateAdmin(BaseAdmin, VersionAdmin):
7d9736ba 829 ### Actions à afficher
a029f641
NBV
830 def get_actions(self, request):
831 actions = super(CourrielTemplateAdmin, self).get_actions(request)
832 del actions['delete_selected']
540dfae4 833 return actions
4e8340cf 834
df59fcab 835admin.site.register(OffreEmploi, OffreEmploiAdmin)
382501c1 836admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
df59fcab 837admin.site.register(Candidat, CandidatAdmin)
382501c1 838admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
720c3ad5 839admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
3bc5ea42 840admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin)
27c81d11 841admin.site.register(Evaluateur, EvaluateurAdmin)
32834000 842admin.site.register(CourrielTemplate, CourrielTemplateAdmin)