1 # -*- encoding: utf-8 -*-
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
8 from reversion
.admin
import VersionAdmin
9 from datamaster_modeles
.models
import Employe
, Implantation
, Region
11 from recrutement
.models
import *
12 from recrutement
.workflow
import grp_administrateurs_recrutement
,\
13 grp_evaluateurs_recrutement
, grp_drh_recrutement
15 class OffreEmploiAdmin(VersionAdmin
):
16 date_hierarchy
= 'date_creation'
17 list_display
= ('nom', 'resume', 'date_limite', 'region', '_candidatsList')
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"
26 def queryset(self
, request
):
27 query
= 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
:
32 Filtrer les offre d'emploi pour afficher seulement les offres
35 qs
= query
.filter(date_limite__gte
=datetime
.date
.today())
37 Si le user n'est ni un évaluateur ni un administrateur régional,
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
)
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
)
52 if type(user
) is Evaluateur
:
53 candidats
= [g
for g
in user
.candidats
.all()]
54 offre_emploi_ids
= [c
.offre_emploi
.id for c
in candidats
]
55 return qs
.select_related('offre_emploi').\
56 filter(id__in
=offre_emploi_ids
)
58 return query
.select_related('offre_emploi')
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
:
67 class ProxyOffreEmploiAdmin(OffreEmploiAdmin
):
68 list_display
= ('nom', 'resume', 'date_limite', 'region', )
69 readonly_fields
= ('actif', 'description', 'poste', 'bureau',
70 'duree_affectation', 'renumeration',
71 'debut_affectation', 'lieu_affectation', 'nom',
72 'resume', 'date_limite', 'region')
77 ('Description générale', {
78 'fields': ('poste', 'resume','description', 'date_limite', )
81 'fields': ('lieu_affectation', 'bureau', 'region', )
84 'fields': ('debut_affectation', 'duree_affectation',
88 def has_add_permission(self
, request
):
91 def has_delete_permission(self
, request
, obj
=None):
94 def has_change_permission(self
, request
, obj
=None):
95 user_groupes
= request
.user
.groups
.all()
96 if grp_evaluateurs_recrutement
in user_groupes
or \
97 grp_drh_recrutement
in user_groupes
:
101 class ProxyCandidatPiece(CandidatPiece
):
103 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
108 verbose_name
= "pièce jointe"
109 verbose_name_plural
= "pièces jointes"
111 class CandidatPieceInline(admin
.TabularInline
):
112 model
= ProxyCandidatPiece
113 fields
= ('candidat', 'nom', 'path', )
116 class ProxyEvaluateur(Evaluateur
.candidats
.through
):
118 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
123 verbose_name
= "évaluateur"
125 class EvaluateurInline(admin
.TabularInline
):
126 model
= ProxyEvaluateur
127 fields
= ('evaluateur',)
130 class CandidatAdmin(VersionAdmin
):
131 date_hierarchy
= 'date_creation'
132 list_display
= ('nom', 'prenom', 'offre_emploi','statut',
133 'voir_offre_emploi', #'note_evaluateur',
134 'calculer_moyenne', 'afficher_candidat',)
135 list_filter
= ('offre_emploi', )
138 'fields': ('offre_emploi', )
140 ('Informations personnelles', {
141 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance',
142 'situation_famille', 'nombre_dependant',)
145 'fields': ('telephone', 'email', 'adresse', 'ville',
146 'etat_province', 'code_postal', 'pays', )
148 ('Informations professionnelles', {
149 'fields': ('niveau_diplome','employeur_actuel',
150 'poste_actuel', 'domaine_professionnel',)
152 ('Options avancées', {
153 'classes': ('collapse',),
154 'fields': ('actif', 'statut', )
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
)
167 return HttpResponseRedirect(reverse('affecter_evaluateurs_candidats')+
168 "?ids=%s" % (",".join(selected
)))
169 affecter_candidats_evaluateur
.short_description
= u
'Affecter évaluateur'
171 # Envoyer un courriel à des candidats
172 def envoyer_courriel_candidats(modeladmin
, obj
, candidats
):
173 selected
= obj
.POST
.getlist(admin
.ACTION_CHECKBOX_NAME
)
175 return HttpResponseRedirect(reverse('envoyer_courriel_candidats')+
176 "?ids=%s" % (",".join(selected
)))
177 envoyer_courriel_candidats
.short_description
= u
'Envoyer courriel'
179 # Évaluer un candidat
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)
182 def evaluer_candidat(self
, obj
):
183 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat </a>" % \
184 (reverse('admin:recrutement_candidatevaluation_changelist'),
186 evaluer_candidat
.allow_tags
= True
187 evaluer_candidat
.short_description
= 'Évaluation'
189 # Afficher un candidat
190 def afficher_candidat(self
, obj
):
191 return "<a href='%s'>Voir le candidat</a>" % (reverse('admin:recrutement_proxycandidat_change', args
=(obj
.id,)))
192 afficher_candidat
.allow_tags
= True
193 afficher_candidat
.short_description
= u
'Afficher les détails du candidat'
195 # Voir l'offre d'emploi
196 def voir_offre_emploi(self
, obj
):
197 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
198 (reverse('admin:recrutement_proxyoffreemploi_change',
199 args
=(obj
.offre_emploi
.id,)))
200 voir_offre_emploi
.allow_tags
= True
201 voir_offre_emploi
.short_description
= "Afficher l'offre d'emploi"
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
208 notes
= [evaluation
.note
for evaluation
in evaluations
.all() \
209 if evaluation
.note
is not None]
211 if len(notes
) > 0 and offre_emploi
.date_limite
<= datetime
.date
.today():
212 moyenne_votes
= float(sum(notes
)) / len(notes
)
214 moyenne_votes
= "Non disponible"
216 calculer_moyenne
.allow_tags
= True
217 calculer_moyenne
.short_description
= "Moyenne des notes"
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
:
226 def has_add_permission(self
, request
):
227 return self
.add_delete_permission(request
, request
)
229 def has_delete_permission(self
, request
, obj
=None):
230 return self
.add_delete_permission(request
, request
)
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 \
235 grp_administrateurs_recrutement
in user_groupes
:
239 def queryset(self
, obj
):
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.
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,
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)
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')
267 class ProxyCandidatAdmin(CandidatAdmin
):
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',)
277 'fields': ('offre_emploi', )
279 ('Informations personnelles', {
280 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance',
281 'situation_famille', 'nombre_dependant',)
284 'fields': ('telephone', 'email', 'adresse', 'ville',
285 'etat_province', 'code_postal', 'pays', )
287 ('Informations professionnelles', {
288 'fields': ('niveau_diplome','employeur_actuel',
289 'poste_actuel', 'domaine_professionnel',)
294 def has_add_permission(self
, request
):
297 def has_delete_permission(self
, request
, obj
=None):
300 def has_change_permission(self
, request
, obj
=None):
301 user_groupes
= request
.user
.groups
.all()
302 if grp_drh_recrutement
in user_groupes
or \
303 grp_administrateurs_recrutement
in user_groupes
or \
304 grp_evaluateurs_recrutement
in user_groupes
:
308 class CandidatPieceAdmin(admin
.ModelAdmin
):
309 list_display
= ('nom', 'candidat', )
311 def queryset(self
, request
):
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.
318 Affiche la liste de candidats que si le user connecté
319 possède un Evaluateur
321 qs
= self
.model
._default_manager
.get_query_set()
322 return qs
.select_related('candidat')
324 class EvaluateurAdmin(VersionAdmin
):
326 (None, {'fields': ('user', )}),
327 #(None, {'fields': ('candidats',)}),
330 class AdministrateurRegionalAdmin(VersionAdmin
):
333 class CandidatEvaluationAdmin(VersionAdmin
):
334 list_display
= ('_offre_emploi', '_candidat', '_note', '_commentaire',
336 readonly_fields
= ('candidat', 'evaluateur')
338 ('Évaluation du candidat', {
339 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
343 def _note(self
, obj
):
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.
350 return "<a href='%s'>Évaluer le candidat </a>" % \
351 (reverse('admin:recrutement_candidatevaluation_change',
352 args
=(obj
.candidat
.id,)))
354 _note
.allow_tags
= True
355 _note
.short_description
= "Votre note"
356 _note
.admin_order_field
= 'note'
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'
365 def _commentaire(self
, obj
):
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.
371 if obj
.commentaire
is None:
373 return obj
.commentaire
374 _commentaire
.allow_tags
= True
375 _commentaire
.short_description
= "Commentaire"
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'
386 def queryset(self
, request
):
388 Afficher uniquement les évaluations de l'évaluateur, sauf si
389 l'utilisateur est super admin.
391 qs
= self
.model
._default_manager
.get_query_set()
392 user_groupes
= request
.user
.groups
.all()
393 if grp_drh_recrutement
in user_groupes
:
394 return qs
.select_related('offre_emploi')
396 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
397 candidats_evaluations
= CandidatEvaluation
.objects
.\
398 filter(evaluateur
=evaluateur
)
399 candidats_evaluations_ids
= [ce
.id for ce
in \
400 candidats_evaluations
.all()]
401 return qs
.select_related('offre_emploi').\
402 filter(id__in
=candidats_evaluations_ids
)
404 class CourrielTemplateAdmin(VersionAdmin
):
407 admin
.site
.register(OffreEmploi
, OffreEmploiAdmin
)
408 admin
.site
.register(Candidat
, CandidatAdmin
)
409 admin
.site
.register(CandidatEvaluation
, CandidatEvaluationAdmin
)
410 #admin.site.register(CourrielTemplate, CourrielTemplateAdmin)
411 admin
.site
.register(Evaluateur
, EvaluateurAdmin
)
412 #admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
413 admin
.site
.register(ProxyOffreEmploi
, ProxyOffreEmploiAdmin
)
414 admin
.site
.register(ProxyCandidat
, ProxyCandidatAdmin
)