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