Ajout des pièces jointes. 1763: Absence visualisation pièces jointes
[auf_rh_dae.git] / project / recrutement / admin.py
CommitLineData
df59fcab 1# -*- encoding: utf-8 -*-
2
6067184b 3from django.core.urlresolvers import reverse
4from django.http import HttpResponseRedirect
df59fcab 5from django.contrib import admin
38df74bb 6from django.shortcuts import get_object_or_404
8e0d552d 7from django.core.files.storage import default_storage
38df74bb 8
6067184b 9from reversion.admin import VersionAdmin
38df74bb 10from datamaster_modeles.models import Employe, Implantation, Region
6067184b 11
df59fcab 12from recrutement.models import *
f6724c20
NBV
13from recrutement.workflow import grp_administrateurs_recrutement,\
14 grp_evaluateurs_recrutement, grp_drh_recrutement
df59fcab 15
d2b30f5f 16class OffreEmploiAdmin(VersionAdmin):
7f9e891e 17 date_hierarchy = 'date_creation'
4fd0c4a2
NBV
18 list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
19 'est_affiche', '_candidatsList')
514db699 20 list_filter = ('statut', 'est_affiche', )
c4874d66
NBV
21 actions = ['affecter_evaluateurs_offre_emploi', ]
22 # Affecter un évaluateurs à des offres d'emploi
23 def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):
24 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
25
26 return HttpResponseRedirect(reverse('affecter_evaluateurs_offre_emploi')+
27 "?ids=%s" % (",".join(selected)))
28 affecter_evaluateurs_offre_emploi.short_description = u'Affecter évaluateur(s)'
29
8941aee7 30 # Afficher la liste des candidats pour l'offre d'emploi
596fe324 31 def _candidatsList(self, obj):
8ea41642 32 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
33 </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id)
2f78949d 34 _candidatsList.allow_tags = True
f6724c20 35 _candidatsList.short_description = "Afficher la liste des candidats"
362a3534 36
c4874d66 37
2f78949d 38 def queryset(self, request):
382501c1 39 qs = self.model._default_manager.get_query_set()
f6724c20
NBV
40 # Si user est superuser afficher toutes les offres d'emploi
41 user_groupes = request.user.groups.all()
d46075cb
NBV
42 if not grp_drh_recrutement in user_groupes and \
43 not request.user.is_superuser:
beef7690 44 """
beef7690
NBV
45 Si le user n'est ni un évaluateur ni un administrateur régional,
46 retourner none
47 Vérifier groupes
48 """
f6724c20 49 if grp_evaluateurs_recrutement in user_groupes:
ca73c3c6
NBV
50 try:
51 user = Evaluateur.objects.get(user=request.user)
52 except Evaluateur.DoesNotExist:
53 return qs.none()
f6724c20 54 elif grp_administrateurs_recrutement in user_groupes:
ca73c3c6
NBV
55 try:
56 user = AdministrateurRegional.objects.get(user=request.user)
57 except AdministrateurRegional.DoesNotExist:
58 return qs.none()
f6724c20
NBV
59 else:
60 return qs.none()
61
62 if type(user) is AdministrateurRegional:
63 region_ids = [g.id for g in user.regions.all()]
64 return qs.select_related('offre_emploi').\
65 filter(region__in=region_ids)
beef7690 66 if type(user) is Evaluateur:
f6724c20 67 candidats = [g for g in user.candidats.all()]
beef7690 68 offre_emploi_ids = [c.offre_emploi.id for c in candidats]
f6724c20 69 return qs.select_related('offre_emploi').\
beef7690 70 filter(id__in=offre_emploi_ids)
3bcef02d 71 return qs.none()
382501c1 72 return qs.select_related('offre_emploi')
f6724c20
NBV
73
74 def has_change_permission(self, request, obj=None):
75 user_groupes = request.user.groups.all()
76 if grp_drh_recrutement in user_groupes or \
d46075cb
NBV
77 grp_administrateurs_recrutement in user_groupes or \
78 request.user.is_superuser:
f6724c20
NBV
79 return True
80 return False
81
82class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
4fd0c4a2
NBV
83 list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
84 'est_affiche')
14e06ff6 85 readonly_fields = ('description', 'bureau',
f6724c20
NBV
86 'duree_affectation', 'renumeration',
87 'debut_affectation', 'lieu_affectation', 'nom',
88 'resume', 'date_limite', 'region')
89 fieldsets = (
720c3ad5 90 ('Nom', {
f6724c20
NBV
91 'fields': ('nom', )
92 }),
720c3ad5 93 ('Description générale', {
14e06ff6 94 'fields': ('resume','description', 'date_limite', )
f6724c20 95 }),
720c3ad5 96 ('Coordonnées', {
f6724c20
NBV
97 'fields': ('lieu_affectation', 'bureau', 'region', )
98 }),
720c3ad5 99 ('Autre', {
f6724c20
NBV
100 'fields': ('debut_affectation', 'duree_affectation',
101 'renumeration', )
102 }),
103 )
104 def has_add_permission(self, request):
105 return False
106
107 def has_delete_permission(self, request, obj=None):
108 return False
109
2d083449
NBV
110 def has_change_permission(self, request, obj=None):
111 user_groupes = request.user.groups.all()
beef7690 112 if grp_evaluateurs_recrutement in user_groupes or \
d46075cb
NBV
113 grp_drh_recrutement in user_groupes or \
114 request.user.is_superuser:
2d083449
NBV
115 return True
116 return False
117
cced6a23 118class ProxyCandidatPiece(CandidatPiece):
cced6a23 119 class Meta:
120 proxy = True
121 verbose_name = "pièce jointe"
74cbc7a7 122 verbose_name_plural = "pièces jointes"
cced6a23 123
170c9aa2 124class CandidatPieceInline(admin.TabularInline):
cced6a23 125 model = ProxyCandidatPiece
8e0d552d 126 fields = ('candidat', 'nom', 'path',)
170c9aa2 127 extra = 1
8e0d552d 128 max_num = 3
170c9aa2 129
27c81d11 130class ProxyEvaluateur(Evaluateur.candidats.through):
cced6a23 131 """
132 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
133 plus ergonomique.
134 """
135 class Meta:
136 proxy = True
137 verbose_name = "évaluateur"
138
eb579d40 139class EvaluateurInline(admin.TabularInline):
cced6a23 140 model = ProxyEvaluateur
720c3ad5 141 fields = ('evaluateur',)
eb579d40 142 extra = 1
143
d2b30f5f 144class CandidatAdmin(VersionAdmin):
7f9e891e 145 date_hierarchy = 'date_creation'
0fd8a26d 146 list_display = ('nom', 'prenom', 'offre_emploi','statut',
dc7faf2b
NBV
147 'voir_offre_emploi', 'calculer_moyenne',
148 'afficher_candidat',)
8ea41642 149 list_filter = ('offre_emploi', )
7f9e891e 150 fieldsets = (
4896b661 151 ("Offre d'emploi", {
152 'fields': ('offre_emploi', )
153 }),
7f9e891e 154 ('Informations personnelles', {
4fd0c4a2 155 'fields': ('prenom','nom','genre', 'nationalite',
7f9e891e 156 'situation_famille', 'nombre_dependant',)
157 }),
ec517164 158 ('Coordonnées', {
159 'fields': ('telephone', 'email', 'adresse', 'ville',
160 'etat_province', 'code_postal', 'pays', )
7f9e891e 161 }),
162 ('Informations professionnelles', {
4896b661 163 'fields': ('niveau_diplome','employeur_actuel',
8ea41642 164 'poste_actuel', 'domaine_professionnel',)
7f9e891e 165 }),
65c4cbd9
NBV
166 ('Traitement', {
167 'fields': ('statut', )
7f9e891e 168 }),
169 )
170c9aa2 170 inlines = [
171 CandidatPieceInline,
eb579d40 172 EvaluateurInline,
170c9aa2 173 ]
f9983b5a 174
4e8340cf 175 actions = ['affecter_candidats_evaluateur', 'envoyer_courriel_candidats']
362a3534 176 # Affecter un évaluateurs à des candidats
7061f835 177 def affecter_candidats_evaluateur(modeladmin, obj, candidats):
596fe324 178 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
2adf9e0c 179
8ea41642 180 return HttpResponseRedirect(reverse('affecter_evaluateurs_candidats')+
181 "?ids=%s" % (",".join(selected)))
c4874d66 182 affecter_candidats_evaluateur.short_description = u'Affecter évaluateur(s)'
362a3534 183
4e8340cf 184 # Envoyer un courriel à des candidats
52765380 185 def envoyer_courriel_candidats(modeladmin, obj, candidats):
186 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
187
32834000 188 return HttpResponseRedirect(reverse('selectionner_template')+
52765380 189 "?ids=%s" % (",".join(selected)))
190 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
191
05503d56 192 # Évaluer un candidat
596fe324 193 def evaluer_candidat(self, obj):
dc7faf2b 194 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat</a>" % \
beef7690
NBV
195 (reverse('admin:recrutement_candidatevaluation_changelist'),
196 obj.id)
596fe324 197 evaluer_candidat.allow_tags = True
beef7690 198 evaluer_candidat.short_description = 'Évaluation'
596fe324 199
7d82fd33 200 # Afficher un candidat
201 def afficher_candidat(self, obj):
382501c1
NBV
202 return "<a href='%s'>Voir le candidat</a>" % \
203 (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
7d82fd33 204 afficher_candidat.allow_tags = True
8e0d552d 205 afficher_candidat.short_description = u'Détails du candidat'
7d82fd33 206
8941aee7 207 # Voir l'offre d'emploi
208 def voir_offre_emploi(self, obj):
720c3ad5
NBV
209 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
210 (reverse('admin:recrutement_proxyoffreemploi_change',
211 args=(obj.offre_emploi.id,)))
8941aee7 212 voir_offre_emploi.allow_tags = True
213 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
214
8941aee7 215 # Calculer la moyenne des notes
216 def calculer_moyenne(self, obj):
217 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
218 offre_emploi = obj.offre_emploi
219
f6724c20
NBV
220 notes = [evaluation.note for evaluation in evaluations.all() \
221 if evaluation.note is not None]
8941aee7 222
223 if len(notes) > 0 and offre_emploi.date_limite <= datetime.date.today():
224 moyenne_votes = float(sum(notes)) / len(notes)
225 else:
226 moyenne_votes = "Non disponible"
227 return moyenne_votes
228 calculer_moyenne.allow_tags = True
229 calculer_moyenne.short_description = "Moyenne des notes"
230
f6724c20
NBV
231 def add_delete_permission(self, request, obj=None) :
232 user_groupes = request.user.groups.all()
233 if grp_drh_recrutement in user_groupes or \
d46075cb
NBV
234 grp_administrateurs_recrutement in user_groupes or \
235 request.user.is_superuser:
f6724c20
NBV
236 return True
237 return False
4896b661 238
f6724c20
NBV
239 def has_add_permission(self, request):
240 return self.add_delete_permission(request, request)
4896b661 241
f6724c20
NBV
242 def has_delete_permission(self, request, obj=None):
243 return self.add_delete_permission(request, request)
244
245 def has_change_permission(self, request, obj=None):
246 user_groupes = request.user.groups.all()
247 if grp_drh_recrutement in user_groupes or \
d46075cb
NBV
248 grp_administrateurs_recrutement in user_groupes or \
249 request.user.is_superuser:
f6724c20
NBV
250 return True
251 return False
4896b661 252
d46075cb 253 def queryset(self, request):
f9983b5a 254 """
8ea41642 255 Spécifie un queryset limité, autrement Django exécute un
256 select_related() sans paramètre, ce qui a pour effet de charger tous
257 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
258 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
259 génération d'une requête infinie.
d835c9f3 260
f9983b5a 261 """
f6724c20
NBV
262 qs = self.model._default_manager.get_query_set()
263 # Si user est superuser afficher tous les candidats
d46075cb
NBV
264 user_groupes = request.user.groups.all()
265 if not grp_drh_recrutement in user_groupes and \
266 not request.user.is_superuser:
f6724c20
NBV
267 # Si le user n'est ni un évaluateur ni un administrateur régional,
268 # retourner none
269
270 # Vérifier groupes
271 if grp_evaluateurs_recrutement in user_groupes:
ca73c3c6
NBV
272 try:
273 user = Evaluateur.objects.get(user=obj.user)
274 except Evaluateur.DoesNotExist:
275 return qs.none()
efedc086
NBV
276 """
277 elif grp_administrateurs_recrutement in user_groupes:
278 try:
279 user = AdministrateurRegional.objects.get(user=obj.user)
280 except AdministrateurRegional.DoesNotExist:
281 return qs.none()
282 """
f6724c20
NBV
283 else:
284 return qs.none()
f6724c20
NBV
285 ids = [c.id for c in user.candidats.all()]
286 return qs.select_related('candidats').filter(id__in=ids)
287 return qs.select_related('candidats')
288
289class ProxyCandidatAdmin(CandidatAdmin):
f6724c20 290 readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom',
4fd0c4a2
NBV
291 'genre', 'nationalite', 'situation_famille',
292 'nombre_dependant', 'telephone', 'email', 'adresse',
293 'ville', 'etat_province', 'code_postal', 'pays',
294 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
8e0d552d 295 'domaine_professionnel', 'pieces_jointes',)
2d083449
NBV
296 fieldsets = (
297 ("Offre d'emploi", {
298 'fields': ('offre_emploi', )
299 }),
300 ('Informations personnelles', {
4fd0c4a2 301 'fields': ('prenom','nom','genre', 'nationalite',
2d083449
NBV
302 'situation_famille', 'nombre_dependant',)
303 }),
304 ('Coordonnées', {
305 'fields': ('telephone', 'email', 'adresse', 'ville',
306 'etat_province', 'code_postal', 'pays', )
307 }),
308 ('Informations professionnelles', {
309 'fields': ('niveau_diplome','employeur_actuel',
310 'poste_actuel', 'domaine_professionnel',)
8e0d552d 311 }),
2d083449 312 )
f6724c20 313 inlines = []
2d083449 314
f6724c20
NBV
315 def has_add_permission(self, request):
316 return False
317
318 def has_delete_permission(self, request, obj=None):
319 return False
2adf9e0c 320
2d083449
NBV
321 def has_change_permission(self, request, obj=None):
322 user_groupes = request.user.groups.all()
beef7690
NBV
323 if grp_drh_recrutement in user_groupes or \
324 grp_administrateurs_recrutement in user_groupes or \
d46075cb
NBV
325 grp_evaluateurs_recrutement in user_groupes or \
326 request.user.is_superuser:
2d083449
NBV
327 return True
328 return False
329
2e9ee615 330class CandidatPieceAdmin(admin.ModelAdmin):
170c9aa2 331 list_display = ('nom', 'candidat', )
332
333 def queryset(self, request):
334 """
335 Spécifie un queryset limité, autrement Django exécute un
336 select_related() sans paramètre, ce qui a pour effet de charger tous
337 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
338 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
339 génération d'une requête infinie.
d835c9f3 340 Affiche la liste de candidats que si le user connecté
27c81d11 341 possède un Evaluateur
170c9aa2 342 """
343 qs = self.model._default_manager.get_query_set()
344 return qs.select_related('candidat')
2e9ee615 345
d2b30f5f 346class EvaluateurAdmin(VersionAdmin):
eb579d40 347 fieldsets = (
f6724c20 348 (None, {'fields': ('user', )}),
720c3ad5 349 #(None, {'fields': ('candidats',)}),
eb579d40 350 )
4418c732 351
b89fef74 352class AdministrateurRegionalAdmin(VersionAdmin):
27c81d11 353 pass
354
d2b30f5f 355class CandidatEvaluationAdmin(VersionAdmin):
b903198b
NBV
356 list_display = ('_offre_emploi', '_candidat', 'evaluateur', '_note',
357 '_commentaire', )
beef7690
NBV
358 readonly_fields = ('candidat', 'evaluateur')
359 fieldsets = (
360 ('Évaluation du candidat', {
361 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
362 }),
363 )
364
365 def _note(self, obj):
366 """
367 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
368 un lien pour Évaluer le candidat.
369 Sinon afficher la note.
370 """
b903198b
NBV
371 evaluateur = obj.evaluateur
372 candidat = obj.candidat
373 candidat_evaluation = CandidatEvaluation.objects.\
374 get(candidat=candidat, evaluateur=evaluateur)
beef7690 375 if obj.note is None:
b903198b 376 return "<a href='%s'>Candidat non évalué</a>" % \
beef7690 377 (reverse('admin:recrutement_candidatevaluation_change',
b903198b
NBV
378 args=(candidat_evaluation.id,)))
379 return "<a href='%s'>%s</a>" % \
380 (reverse('admin:recrutement_candidatevaluation_change',
381 args=(candidat_evaluation.id,)), obj.note)
382 return
beef7690
NBV
383 _note.allow_tags = True
384 _note.short_description = "Votre note"
385 _note.admin_order_field = 'note'
386
387 def _candidat(self, obj):
388 return "<a href='%s'>%s</a>" \
389 % (reverse('admin:recrutement_proxycandidat_change',
390 args=(obj.candidat.id,)), obj.candidat)
391 _candidat.allow_tags = True
392 _candidat.short_description = 'Candidat'
393
394 def _commentaire(self, obj):
395 """
396 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
397 dans le champ commentaire, Aucun au lieu de (None)
398 Sinon afficher la note.
399 """
400 if obj.commentaire is None:
401 return "Aucun"
402 return obj.commentaire
403 _commentaire.allow_tags = True
404 _commentaire.short_description = "Commentaire"
720c3ad5 405
720c3ad5 406
beef7690
NBV
407 def _offre_emploi(self, obj):
408 return "<a href='%s'>%s</a>" % \
409 (reverse('admin:recrutement_proxyoffreemploi_change',
dc7faf2b 410 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
beef7690
NBV
411 _offre_emploi.allow_tags = True
412 _offre_emploi.short_description = "Voir offre d'emploi"
413 _offre_emploi.admin_order_field = 'offre_emploi'
414
21b02da5
NBV
415 def has_change_permission(self, request, obj=None):
416 """
417 Permettre la visualisation dans la changelist
418 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
419 le request.user
420 """
421 return obj is None or request.user == obj.evaluateur.user
422
720c3ad5 423 def queryset(self, request):
beef7690
NBV
424 """
425 Afficher uniquement les évaluations de l'évaluateur, sauf si
426 l'utilisateur est super admin.
427 """
720c3ad5 428 qs = self.model._default_manager.get_query_set()
beef7690 429 user_groupes = request.user.groups.all()
d46075cb
NBV
430 if grp_drh_recrutement in user_groupes or \
431 request.user.is_superuser:
beef7690
NBV
432 return qs.select_related('offre_emploi')
433
ca73c3c6 434 try:
d069cdf1 435 evaluateur = Evaluateur.objects.get(user=request.user)
ca73c3c6
NBV
436 except Evaluateur.DoesNotExist:
437 return qs.none()
438
439 candidats_evaluations = CandidatEvaluation.objects.\
440 filter(evaluateur=evaluateur)
441 candidats_evaluations_ids = [ce.id for ce in \
442 candidats_evaluations.all()]
443 return qs.select_related('offre_emploi').\
444 filter(id__in=candidats_evaluations_ids)
596fe324 445
4e8340cf 446class CourrielTemplateAdmin(VersionAdmin):
447 pass
448
df59fcab 449admin.site.register(OffreEmploi, OffreEmploiAdmin)
382501c1 450admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
df59fcab 451admin.site.register(Candidat, CandidatAdmin)
382501c1 452admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
720c3ad5 453admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
27c81d11 454admin.site.register(Evaluateur, EvaluateurAdmin)
beef7690 455#admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
32834000 456admin.site.register(CourrielTemplate, CourrielTemplateAdmin)