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