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