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