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