ff3d55b42bd8e86bf8d8e9993eedd3e564a1a78c
[auf_rh_dae.git] / project / recrutement / admin.py
1 # -*- encoding: utf-8 -*-
2
3 from django.core.urlresolvers import reverse
4 from django.http import HttpResponseRedirect
5 from django.contrib import admin
6 from django.shortcuts import get_object_or_404
7
8 from reversion.admin import VersionAdmin
9 from datamaster_modeles.models import Employe, Implantation, Region
10
11 from recrutement.models import *
12 from recrutement.workflow import grp_administrateurs_recrutement,\
13 grp_evaluateurs_recrutement, grp_drh_recrutement
14
15 class OffreEmploiAdmin(VersionAdmin):
16 date_hierarchy = 'date_creation'
17 list_display = ('nom', 'resume', 'date_limite', 'region', '_candidatsList')
18
19 # Afficher la liste des candidats pour l'offre d'emploi
20 def _candidatsList(self, obj):
21 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
22 </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id)
23 _candidatsList.allow_tags = True
24 _candidatsList.short_description = "Afficher la liste des candidats"
25
26 def queryset(self, request):
27 qs = self.model._default_manager.get_query_set()
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:
31 # Si le user n'est ni un évaluateur ni un administrateur régional,
32 # retourner none
33 # Vérifier groupes
34 if grp_evaluateurs_recrutement in user_groupes:
35 user = Evaluateur.objects.get(user=request.user)
36 elif grp_administrateurs_recrutement in user_groupes:
37 user = AdministrateurRegional.objects.get(user=request.user)
38 else:
39 return qs.none()
40
41 if type(user) is AdministrateurRegional:
42 region_ids = [g.id for g in user.regions.all()]
43 return qs.select_related('offre_emploi').\
44 filter(region__in=region_ids)
45 if type(user) is Evaluateur:
46
47 candidats = [g for g in user.candidats.all()]
48 offre_emploi_ids = [offre.id for offre in candidats]
49 return qs.select_related('offre_emploi').\
50 filter(id__in=offre_emploi_ids)
51
52 return qs.none()
53 return qs.select_related('offre_emploi')
54
55 def has_change_permission(self, request, obj=None):
56 user_groupes = request.user.groups.all()
57 if grp_drh_recrutement in user_groupes or \
58 grp_administrateurs_recrutement in user_groupes:
59 return True
60 return False
61
62 class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
63 list_display = ('nom', 'resume', 'date_limite', 'region', '_candidatsList', )
64 readonly_fields = ('actif', 'description', 'poste', 'bureau',
65 'duree_affectation', 'renumeration',
66 'debut_affectation', 'lieu_affectation', 'nom',
67 'resume', 'date_limite', 'region')
68 fieldsets = (
69 (None, {
70 'fields': ('nom', )
71 }),
72 (None, {
73 'fields': ('poste', 'resume','description', 'date_limite', )
74 }),
75 (None, {
76 'fields': ('lieu_affectation', 'bureau', 'region', )
77 }),
78 (None, {
79 'fields': ('debut_affectation', 'duree_affectation',
80 'renumeration', )
81 }),
82 )
83 def has_add_permission(self, request):
84 return False
85
86 def has_delete_permission(self, request, obj=None):
87 return False
88
89 def has_change_permission(self, request, obj=None):
90 user_groupes = request.user.groups.all()
91 if grp_evaluateurs_recrutement in user_groupes:
92 return True
93 return False
94
95 def _candidatsList(self, obj):
96 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
97 </a>" % (reverse('admin:recrutement_proxycandidat_changelist'),
98 obj.id)
99 _candidatsList.allow_tags = True
100 _candidatsList.short_description = "Afficher la liste des candidats"
101
102 class ProxyCandidatPiece(CandidatPiece):
103 """
104 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
105 plus ergonomique.
106 """
107 class Meta:
108 proxy = True
109 verbose_name = "pièce jointe"
110 verbose_name_plural = "pièces jointes"
111
112 class CandidatPieceInline(admin.TabularInline):
113 model = ProxyCandidatPiece
114 fields = ('candidat', 'nom', 'path', )
115 extra = 1
116
117 class ProxyEvaluateur(Evaluateur.candidats.through):
118 """
119 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
120 plus ergonomique.
121 """
122 class Meta:
123 proxy = True
124 verbose_name = "évaluateur"
125
126 class EvaluateurInline(admin.TabularInline):
127 model = ProxyEvaluateur
128 extra = 1
129
130 class CandidatAdmin(VersionAdmin):
131 date_hierarchy = 'date_creation'
132 list_display = ('nom', 'prenom', 'offre_emploi','statut',
133 'voir_offre_emploi', 'evaluer_candidat', #'note_evaluateur',
134 'calculer_moyenne', 'afficher_candidat',)
135 list_filter = ('offre_emploi', )
136 fieldsets = (
137 ("Offre d'emploi", {
138 'fields': ('offre_emploi', )
139 }),
140 ('Informations personnelles', {
141 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance',
142 'situation_famille', 'nombre_dependant',)
143 }),
144 ('Coordonnées', {
145 'fields': ('telephone', 'email', 'adresse', 'ville',
146 'etat_province', 'code_postal', 'pays', )
147 }),
148 ('Informations professionnelles', {
149 'fields': ('niveau_diplome','employeur_actuel',
150 'poste_actuel', 'domaine_professionnel',)
151 }),
152 ('Options avancées', {
153 'classes': ('collapse',),
154 'fields': ('actif', 'statut', )
155 }),
156 )
157 inlines = [
158 CandidatPieceInline,
159 EvaluateurInline,
160 ]
161
162 actions = ['affecter_candidats_evaluateur', 'envoyer_courriel_candidats']
163 # Affecter un évaluateurs à des candidats
164 def affecter_candidats_evaluateur(modeladmin, obj, candidats):
165 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
166
167 return HttpResponseRedirect(reverse('affecter_evaluateurs_candidats')+
168 "?ids=%s" % (",".join(selected)))
169 affecter_candidats_evaluateur.short_description = u'Affecter évaluateur'
170
171 # Envoyer un courriel à des candidats
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
179 # Évaluer un candidat
180 def evaluer_candidat(self, obj):
181 return "<a href='%s?id=%s'>Évaluer le candidat \
182 </a>" % (reverse('evaluer_candidat'), obj.id)
183 evaluer_candidat.allow_tags = True
184 evaluer_candidat.short_description = 'Évaluer'
185
186 # Afficher un candidat
187 def afficher_candidat(self, obj):
188 return "<a href='%s?id=%s'>Voir le candidat \
189 </a>" % (reverse('recrutement_proxycandidat_change'), obj.id)
190 afficher_candidat.allow_tags = True
191 afficher_candidat.short_description = u'Afficher les détails du candidat'
192
193 # Voir l'offre d'emploi
194 def voir_offre_emploi(self, obj):
195 return "<a href='%s?id=%s'>Voir l'offre d'emploi</a> \
196 " % (reverse('admin:recrutement_offreemploi_changelist'),
197 obj.offre_emploi.id)
198 voir_offre_emploi.allow_tags = True
199 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
200
201 """ # Afficher note poster par l'évaluateur
202 def note_evaluateur(self, obj):
203 import pdb;pdb.set_trace()
204 evaluateur = Evaluateur.objects.get(user=obj.user)
205 import pdb;pdb.set_trace()
206 note_eval = CandidatEvaluation.objects.filter(evaluateur=evaluateur,
207 candidat=obj.user)
208 return "blabla"
209 note_evaluateur.allow_tags = True
210 note_evaluateur.short_description = "Votre note"
211 """
212
213 # Calculer la moyenne des notes
214 def calculer_moyenne(self, obj):
215 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
216 offre_emploi = obj.offre_emploi
217
218 notes = [evaluation.note for evaluation in evaluations.all() \
219 if evaluation.note is not None]
220
221 if len(notes) > 0 and offre_emploi.date_limite <= datetime.date.today():
222 moyenne_votes = float(sum(notes)) / len(notes)
223 else:
224 moyenne_votes = "Non disponible"
225 return moyenne_votes
226 calculer_moyenne.allow_tags = True
227 calculer_moyenne.short_description = "Moyenne des notes"
228
229 def add_delete_permission(self, request, obj=None) :
230 user_groupes = request.user.groups.all()
231 if grp_drh_recrutement in user_groupes or \
232 grp_administrateurs_recrutement in user_groupes:
233 return True
234 return False
235
236 def has_add_permission(self, request):
237 return self.add_delete_permission(request, request)
238
239 def has_delete_permission(self, request, obj=None):
240 return self.add_delete_permission(request, request)
241
242 def has_change_permission(self, request, obj=None):
243 user_groupes = request.user.groups.all()
244 if grp_drh_recrutement in user_groupes or \
245 grp_administrateurs_recrutement in user_groupes:
246 return True
247 return False
248
249 def queryset(self, obj):
250 """
251 Spécifie un queryset limité, autrement Django exécute un
252 select_related() sans paramètre, ce qui a pour effet de charger tous
253 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
254 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
255 génération d'une requête infinie.
256
257 """
258 qs = self.model._default_manager.get_query_set()
259 # Si user est superuser afficher tous les candidats
260 user_groupes = obj.user.groups.all()
261 if not grp_drh_recrutement in user_groupes:
262 # Si le user n'est ni un évaluateur ni un administrateur régional,
263 # retourner none
264
265 # Vérifier groupes
266 if grp_evaluateurs_recrutement in user_groupes:
267 user = Evaluateur.objects.get(user=obj.user)
268 #elif grp_administrateurs_recrutement in user_groupes:
269 # user = AdministrateurRegional.objects.get(user=obj.user)
270 else:
271 return qs.none()
272
273 ids = [c.id for c in user.candidats.all()]
274 return qs.select_related('candidats').filter(id__in=ids)
275 return qs.select_related('candidats')
276
277 class ProxyCandidatAdmin(CandidatAdmin):
278 #TODO: init boucler sur les fields pour le readonly
279 list_display = ('nom', 'prenom', 'offre_emploi','statut',
280 'voir_offre_emploi', 'evaluer_candidat', #'note_evaluateur',
281 'calculer_moyenne',)
282 readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom',
283 'genre', 'nationalite', 'date_naissance',
284 'situation_famille', 'nombre_dependant', 'telephone',
285 'email', 'adresse', 'ville', 'etat_province',
286 'code_postal', 'pays', 'niveau_diplome',
287 'employeur_actuel', 'poste_actuel',
288 'domaine_professionnel',)
289 fieldsets = (
290 ("Offre d'emploi", {
291 'fields': ('offre_emploi', )
292 }),
293 ('Informations personnelles', {
294 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance',
295 'situation_famille', 'nombre_dependant',)
296 }),
297 ('Coordonnées', {
298 'fields': ('telephone', 'email', 'adresse', 'ville',
299 'etat_province', 'code_postal', 'pays', )
300 }),
301 ('Informations professionnelles', {
302 'fields': ('niveau_diplome','employeur_actuel',
303 'poste_actuel', 'domaine_professionnel',)
304 }),
305 )
306 inlines = []
307
308 def has_add_permission(self, request):
309 return False
310
311 def has_delete_permission(self, request, obj=None):
312 return False
313
314 def has_change_permission(self, request, obj=None):
315 user_groupes = request.user.groups.all()
316 if grp_evaluateurs_recrutement in user_groupes:
317 return True
318 return False
319
320 def voir_offre_emploi(self, obj):
321 return "<a href='%s?id=%s'>Voir l'offre d'emploi</a> \
322 " % (reverse('admin:recrutement_proxyoffreemploi_changelist'),
323 obj.offre_emploi.id)
324 voir_offre_emploi.allow_tags = True
325 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
326
327 class CandidatPieceAdmin(admin.ModelAdmin):
328 list_display = ('nom', 'candidat', )
329
330 def queryset(self, request):
331 """
332 Spécifie un queryset limité, autrement Django exécute un
333 select_related() sans paramètre, ce qui a pour effet de charger tous
334 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
335 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
336 génération d'une requête infinie.
337 Affiche la liste de candidats que si le user connecté
338 possède un Evaluateur
339 """
340 qs = self.model._default_manager.get_query_set()
341 return qs.select_related('candidat')
342
343 class EvaluateurAdmin(VersionAdmin):
344 fieldsets = (
345 (None, {'fields': ('user', )}),
346 (None, {'fields': ('candidats',)}),
347 )
348
349 # Peut-être qu'on peut enlever cette def, à cause des permissions
350 def queryset(self, request):
351 """
352 Affiche la liste d'évaluateur que si le user connecté
353 possède un Evaluateur
354 """
355 user_groupes = obj.user.groups.all()
356 if grp_drh_recrutement in user_groupes:
357 return self.model._default_manager.get_query_set()
358
359 return qs.none()
360
361 class AdministrateurRegionalAdmin(VersionAdmin):
362 pass
363
364 class CandidatEvaluationAdmin(VersionAdmin):
365 list_display = ('candidat', 'evaluateur', 'note', 'commentaire', 'date', )
366
367 class CourrielTemplateAdmin(VersionAdmin):
368 pass
369
370 admin.site.register(OffreEmploi, OffreEmploiAdmin)
371 admin.site.register(Candidat, CandidatAdmin)
372 admin.site.register(CourrielTemplate, CourrielTemplateAdmin)
373 admin.site.register(Evaluateur, EvaluateurAdmin)
374 admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
375 admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
376 admin.site.register(ProxyCandidat, ProxyCandidatAdmin)