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 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
:
32 Si le user n'est ni un évaluateur ni un administrateur régional,
36 if grp_evaluateurs_recrutement
in user_groupes
:
38 user
= Evaluateur
.objects
.get(user
=request
.user
)
39 except Evaluateur
.DoesNotExist
:
41 elif grp_administrateurs_recrutement
in user_groupes
:
43 user
= AdministrateurRegional
.objects
.get(user
=request
.user
)
44 except AdministrateurRegional
.DoesNotExist
:
49 if type(user
) is AdministrateurRegional
:
50 region_ids
= [g
.id for g
in user
.regions
.all()]
51 return qs
.select_related('offre_emploi').\
52 filter(region__in
=region_ids
)
53 if type(user
) is Evaluateur
:
54 candidats
= [g
for g
in user
.candidats
.all()]
55 offre_emploi_ids
= [c
.offre_emploi
.id for c
in candidats
]
56 return qs
.select_related('offre_emploi').\
57 filter(id__in
=offre_emploi_ids
)
59 return qs
.select_related('offre_emploi')
61 def has_change_permission(self
, request
, obj
=None):
62 user_groupes
= request
.user
.groups
.all()
63 if grp_drh_recrutement
in user_groupes
or \
64 grp_administrateurs_recrutement
in user_groupes
:
68 class ProxyOffreEmploiAdmin(OffreEmploiAdmin
):
69 list_display
= ('nom', 'resume', 'date_limite', 'region', )
70 readonly_fields
= ('description', 'poste', 'bureau',
71 'duree_affectation', 'renumeration',
72 'debut_affectation', 'lieu_affectation', 'nom',
73 'resume', 'date_limite', 'region')
78 ('Description générale', {
79 'fields': ('poste', 'resume','description', 'date_limite', )
82 'fields': ('lieu_affectation', 'bureau', 'region', )
85 'fields': ('debut_affectation', 'duree_affectation',
89 def has_add_permission(self
, request
):
92 def has_delete_permission(self
, request
, obj
=None):
95 def has_change_permission(self
, request
, obj
=None):
96 user_groupes
= request
.user
.groups
.all()
97 if grp_evaluateurs_recrutement
in user_groupes
or \
98 grp_drh_recrutement
in user_groupes
:
102 class ProxyCandidatPiece(CandidatPiece
):
104 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
109 verbose_name
= "pièce jointe"
110 verbose_name_plural
= "pièces jointes"
112 class CandidatPieceInline(admin
.TabularInline
):
113 model
= ProxyCandidatPiece
114 fields
= ('candidat', 'nom', 'path', )
117 class ProxyEvaluateur(Evaluateur
.candidats
.through
):
119 Ce proxy sert uniquement dans l'admin à disposer d'un libellé
124 verbose_name
= "évaluateur"
126 class EvaluateurInline(admin
.TabularInline
):
127 model
= ProxyEvaluateur
128 fields
= ('evaluateur',)
131 class CandidatAdmin(VersionAdmin
):
132 date_hierarchy
= 'date_creation'
133 list_display
= ('nom', 'prenom', 'offre_emploi','statut',
134 'voir_offre_emploi', #'note_evaluateur',
135 'calculer_moyenne', 'afficher_candidat',)
136 list_filter
= ('offre_emploi', )
139 'fields': ('offre_emploi', )
141 ('Informations personnelles', {
142 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance',
143 'situation_famille', 'nombre_dependant',)
146 'fields': ('telephone', 'email', 'adresse', 'ville',
147 'etat_province', 'code_postal', 'pays', )
149 ('Informations professionnelles', {
150 'fields': ('niveau_diplome','employeur_actuel',
151 'poste_actuel', 'domaine_professionnel',)
154 'fields': ('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 def evaluer_candidat(self
, obj
):
181 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat </a>" % \
182 (reverse('admin:recrutement_candidatevaluation_changelist'),
184 evaluer_candidat
.allow_tags
= True
185 evaluer_candidat
.short_description
= 'Évaluation'
187 # Afficher un candidat
188 def afficher_candidat(self
, obj
):
189 return "<a href='%s'>Voir le candidat</a>" % \
190 (reverse('admin:recrutement_proxycandidat_change', args
=(obj
.id,)))
191 afficher_candidat
.allow_tags
= True
192 afficher_candidat
.short_description
= u
'Afficher les détails du candidat'
194 # Voir l'offre d'emploi
195 def voir_offre_emploi(self
, obj
):
196 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
197 (reverse('admin:recrutement_proxyoffreemploi_change',
198 args
=(obj
.offre_emploi
.id,)))
199 voir_offre_emploi
.allow_tags
= True
200 voir_offre_emploi
.short_description
= "Afficher l'offre d'emploi"
202 # Calculer la moyenne des notes
203 def calculer_moyenne(self
, obj
):
204 evaluations
= CandidatEvaluation
.objects
.filter(candidat
=obj
)
205 offre_emploi
= obj
.offre_emploi
207 notes
= [evaluation
.note
for evaluation
in evaluations
.all() \
208 if evaluation
.note
is not None]
210 if len(notes
) > 0 and offre_emploi
.date_limite
<= datetime
.date
.today():
211 moyenne_votes
= float(sum(notes
)) / len(notes
)
213 moyenne_votes
= "Non disponible"
215 calculer_moyenne
.allow_tags
= True
216 calculer_moyenne
.short_description
= "Moyenne des notes"
218 def add_delete_permission(self
, request
, obj
=None) :
219 user_groupes
= request
.user
.groups
.all()
220 if grp_drh_recrutement
in user_groupes
or \
221 grp_administrateurs_recrutement
in user_groupes
:
225 def has_add_permission(self
, request
):
226 return self
.add_delete_permission(request
, request
)
228 def has_delete_permission(self
, request
, obj
=None):
229 return self
.add_delete_permission(request
, request
)
231 def has_change_permission(self
, request
, obj
=None):
232 user_groupes
= request
.user
.groups
.all()
233 if grp_drh_recrutement
in user_groupes
or \
234 grp_administrateurs_recrutement
in user_groupes
:
238 def queryset(self
, obj
):
240 Spécifie un queryset limité, autrement Django exécute un
241 select_related() sans paramètre, ce qui a pour effet de charger tous
242 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
243 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
244 génération d'une requête infinie.
247 qs
= self
.model
._default_manager
.get_query_set()
248 # Si user est superuser afficher tous les candidats
249 user_groupes
= obj
.user
.groups
.all()
250 if not grp_drh_recrutement
in user_groupes
:
251 # Si le user n'est ni un évaluateur ni un administrateur régional,
255 if grp_evaluateurs_recrutement
in user_groupes
:
257 user
= Evaluateur
.objects
.get(user
=obj
.user
)
258 except Evaluateur
.DoesNotExist
:
261 elif grp_administrateurs_recrutement in user_groupes:
263 user = AdministrateurRegional.objects.get(user=obj.user)
264 except AdministrateurRegional.DoesNotExist:
269 ids
= [c
.id for c
in user
.candidats
.all()]
270 return qs
.select_related('candidats').filter(id__in
=ids
)
271 return qs
.select_related('candidats')
273 class ProxyCandidatAdmin(CandidatAdmin
):
274 readonly_fields
= ('statut', 'offre_emploi', 'prenom', 'nom',
275 'genre', 'nationalite', 'date_naissance',
276 'situation_famille', 'nombre_dependant', 'telephone',
277 'email', 'adresse', 'ville', 'etat_province',
278 'code_postal', 'pays', 'niveau_diplome',
279 'employeur_actuel', 'poste_actuel',
280 'domaine_professionnel',)
283 'fields': ('offre_emploi', )
285 ('Informations personnelles', {
286 'fields': ('prenom','nom','genre', 'nationalite', 'date_naissance',
287 'situation_famille', 'nombre_dependant',)
290 'fields': ('telephone', 'email', 'adresse', 'ville',
291 'etat_province', 'code_postal', 'pays', )
293 ('Informations professionnelles', {
294 'fields': ('niveau_diplome','employeur_actuel',
295 'poste_actuel', 'domaine_professionnel',)
300 def has_add_permission(self
, request
):
303 def has_delete_permission(self
, request
, obj
=None):
306 def has_change_permission(self
, request
, obj
=None):
307 user_groupes
= request
.user
.groups
.all()
308 if grp_drh_recrutement
in user_groupes
or \
309 grp_administrateurs_recrutement
in user_groupes
or \
310 grp_evaluateurs_recrutement
in user_groupes
:
314 class CandidatPieceAdmin(admin
.ModelAdmin
):
315 list_display
= ('nom', 'candidat', )
317 def queryset(self
, request
):
319 Spécifie un queryset limité, autrement Django exécute un
320 select_related() sans paramètre, ce qui a pour effet de charger tous
321 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
322 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
323 génération d'une requête infinie.
324 Affiche la liste de candidats que si le user connecté
325 possède un Evaluateur
327 qs
= self
.model
._default_manager
.get_query_set()
328 return qs
.select_related('candidat')
330 class EvaluateurAdmin(VersionAdmin
):
332 (None, {'fields': ('user', )}),
333 #(None, {'fields': ('candidats',)}),
336 class AdministrateurRegionalAdmin(VersionAdmin
):
339 class CandidatEvaluationAdmin(VersionAdmin
):
340 list_display
= ('_offre_emploi', '_candidat', '_note', '_commentaire',
342 readonly_fields
= ('candidat', 'evaluateur')
344 ('Évaluation du candidat', {
345 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
349 def _note(self
, obj
):
351 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
352 un lien pour Évaluer le candidat.
353 Sinon afficher la note.
356 return "<a href='%s'>Évaluer le candidat </a>" % \
357 (reverse('admin:recrutement_candidatevaluation_change',
358 args
=(obj
.candidat
.id,)))
360 _note
.allow_tags
= True
361 _note
.short_description
= "Votre note"
362 _note
.admin_order_field
= 'note'
364 def _candidat(self
, obj
):
365 return "<a href='%s'>%s</a>" \
366 % (reverse('admin:recrutement_proxycandidat_change',
367 args
=(obj
.candidat
.id,)), obj
.candidat
)
368 _candidat
.allow_tags
= True
369 _candidat
.short_description
= 'Candidat'
371 def _commentaire(self
, obj
):
373 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
374 dans le champ commentaire, Aucun au lieu de (None)
375 Sinon afficher la note.
377 if obj
.commentaire
is None:
379 return obj
.commentaire
380 _commentaire
.allow_tags
= True
381 _commentaire
.short_description
= "Commentaire"
384 def _offre_emploi(self
, obj
):
385 return "<a href='%s'>%s</a>" % \
386 (reverse('admin:recrutement_proxyoffreemploi_change',
387 args
=(obj
.candidat
.offre_emploi
.id,)), obj
.candidat
.offre_emploi
)
388 _offre_emploi
.allow_tags
= True
389 _offre_emploi
.short_description
= "Voir offre d'emploi"
390 _offre_emploi
.admin_order_field
= 'offre_emploi'
392 def queryset(self
, request
):
394 Afficher uniquement les évaluations de l'évaluateur, sauf si
395 l'utilisateur est super admin.
397 qs
= self
.model
._default_manager
.get_query_set()
398 user_groupes
= request
.user
.groups
.all()
399 if grp_drh_recrutement
in user_groupes
:
400 return qs
.select_related('offre_emploi')
403 evaluateur
= Evaluateur
.objects
.get(user
=request
.user
)
404 except Evaluateur
.DoesNotExist
:
407 candidats_evaluations
= CandidatEvaluation
.objects
.\
408 filter(evaluateur
=evaluateur
)
409 candidats_evaluations_ids
= [ce
.id for ce
in \
410 candidats_evaluations
.all()]
411 return qs
.select_related('offre_emploi').\
412 filter(id__in
=candidats_evaluations_ids
)
414 class CourrielTemplateAdmin(VersionAdmin
):
417 admin
.site
.register(OffreEmploi
, OffreEmploiAdmin
)
418 admin
.site
.register(ProxyOffreEmploi
, ProxyOffreEmploiAdmin
)
419 admin
.site
.register(Candidat
, CandidatAdmin
)
420 admin
.site
.register(ProxyCandidat
, ProxyCandidatAdmin
)
421 admin
.site
.register(CandidatEvaluation
, CandidatEvaluationAdmin
)
422 admin
.site
.register(Evaluateur
, EvaluateurAdmin
)
423 #admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
424 #admin.site.register(CourrielTemplate, CourrielTemplateAdmin)