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