i18n
[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.forms.models import BaseInlineFormSet
7 from django.db.models import Avg
8 from django.conf import settings
9
10 from reversion.admin import VersionAdmin
11 from datamaster_modeles.models import Region, Bureau
12 from project.rh import models as rh
13
14 from project.dae.utils import get_employe_from_user as get_emp
15 from recrutement.models import *
16 from recrutement.workflow import grp_drh_recrutement, grp_directeurs_bureau_recrutement, \
17 grp_administrateurs_recrutement, \
18 grp_correspondants_rh_recrutement
19
20 from recrutement.forms import *
21
22 ### CONSTANTES
23 IMPLANTATIONS_CENTRALES = [15, 19]
24
25 class OrderedChangeList(admin.views.main.ChangeList):
26 """
27 Surcharge pour appliquer le order_by d'un annotate
28 """
29 def get_query_set(self):
30 qs = super(OrderedChangeList, self).get_query_set()
31 qs = qs.order_by('-moyenne')
32 return qs
33
34 class OffreEmploiAdmin(VersionAdmin):
35 date_hierarchy = 'date_creation'
36 list_display = ('nom', 'date_limite', 'region', 'statut',
37 'est_affiche', '_candidatsList', )
38 exclude = ('actif', 'poste_nom', 'resume',)
39 list_filter = ('statut',)
40 actions = ['affecter_evaluateurs_offre_emploi', ]
41 form = OffreEmploiForm
42
43 ### Actions à afficher
44 def get_actions(self, request):
45 actions = super(OffreEmploiAdmin, self).get_actions(request)
46 del actions['delete_selected']
47 return actions
48
49 ### Affecter un évaluateurs à des offres d'emploi
50 def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):
51 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
52
53 return HttpResponseRedirect(reverse('affecter_evaluateurs_offre_emploi')+
54 "?ids=%s" % (",".join(selected)))
55 affecter_evaluateurs_offre_emploi.short_description = u'Affecter évaluateur(s)'
56
57 ### Afficher la liste des candidats pour l'offre d'emploi
58 def _candidatsList(self, obj):
59 return "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
60 </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id)
61 _candidatsList.allow_tags = True
62 _candidatsList.short_description = "Afficher la liste des candidats"
63
64 ### Formulaire
65 def get_form(self, request, obj=None, **kwargs):
66 form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs)
67 employe = get_emp(request.user)
68 user_groupes = request.user.groups.all()
69
70
71 # Region
72 if form.declared_fields.has_key('region'):
73 region_field = form.declared_fields['region']
74 else:
75 region_field = form.base_fields['region']
76
77 if grp_drh_recrutement in user_groupes:
78 region_field.queryset = Region.objects.all()
79 else:
80 region_field.queryset = Region.objects.\
81 filter(id=employe.implantation.region.id)
82
83 # Poste
84 if form.declared_fields.has_key('poste'):
85 poste_field = form.declared_fields['poste']
86 else:
87 poste_field = form.base_fields['poste']
88
89 if grp_drh_recrutement in user_groupes:
90 poste_field.queryset = rh.Poste.objects.all()
91 else:
92 poste_field.queryset = rh.Poste.objects.\
93 filter(implantation__region=employe.implantation.region).\
94 exclude(implantation__in=IMPLANTATIONS_CENTRALES)
95
96 # Bureau
97 if form.declared_fields.has_key('bureau'):
98 bureau_field = form.declared_fields['bureau']
99 else:
100 bureau_field = form.base_fields['bureau']
101
102 if grp_drh_recrutement in user_groupes:
103 bureau_field.queryset = Bureau.objects.all()
104 else:
105 bureau_field.queryset = Bureau.objects.\
106 filter(region=employe.implantation.region)
107
108 return form
109
110 ### Queryset
111 def queryset(self, request):
112 qs = self.model._default_manager.get_query_set().select_related('offre_emploi')
113 user_groupes = request.user.groups.all()
114 if grp_drh_recrutement in user_groupes:
115 return qs
116
117 if grp_directeurs_bureau_recrutement in user_groupes or \
118 grp_correspondants_rh_recrutement in user_groupes or \
119 grp_administrateurs_recrutement in user_groupes:
120 employe = get_emp(request.user)
121 return qs.filter(region=employe.implantation.region)
122
123 if Evaluateur.objects.filter(user=request.user).exists():
124 evaluateur = Evaluateur.objects.get(user=request.user)
125 offre_ids = [e.candidat.offre_emploi_id for e in
126 CandidatEvaluation.objects.select_related('candidat').filter(evaluateur=evaluateur)]
127 return qs.filter(id__in=offre_ids)
128
129 return qs.none()
130
131 ### Permission add, delete, change
132 def has_add_permission(self, request):
133 user_groupes = request.user.groups.all()
134 if request.user.is_superuser is True or \
135 grp_drh_recrutement in user_groupes or \
136 grp_directeurs_bureau_recrutement in user_groupes or \
137 grp_administrateurs_recrutement in user_groupes:
138 return True
139 return False
140
141 def has_delete_permission(self, request, obj=None):
142 user_groupes = request.user.groups.all()
143 if request.user.is_superuser is True or \
144 grp_drh_recrutement in user_groupes or \
145 grp_directeurs_bureau_recrutement in user_groupes or \
146 grp_administrateurs_recrutement in user_groupes:
147 return True
148 return False
149
150 def has_change_permission(self, request, obj=None):
151 user_groupes = request.user.groups.all()
152 if request.user.is_superuser is True or \
153 grp_drh_recrutement in user_groupes or \
154 grp_directeurs_bureau_recrutement in user_groupes or \
155 grp_administrateurs_recrutement in user_groupes:
156 return True
157 return False
158
159 class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
160 list_display = ('nom', 'date_limite', 'region', 'statut',
161 'est_affiche')
162 readonly_fields = ('description', 'bureau', 'duree_affectation',
163 'renumeration', 'debut_affectation', 'lieu_affectation',
164 'nom', 'resume', 'date_limite', 'region', 'poste')
165 fieldsets = (
166 ('Nom', {
167 'fields': ('nom', )
168 }),
169 ('Description générale', {
170 'fields': ('description', 'date_limite', )
171 }),
172 ('Coordonnées', {
173 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
174 }),
175 ('Autre', {
176 'fields': ('debut_affectation', 'duree_affectation',
177 'renumeration', )
178 }),
179 )
180 inlines = []
181
182
183 ### Lieu de redirection après le change
184 def response_change(self, request, obj):
185 return HttpResponseRedirect(reverse\
186 ('admin:recrutement_proxyoffreemploi_changelist'))
187
188 ### Formulaire
189 def get_form(self, request, obj=None, **kwargs):
190 form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs)
191 return form
192
193 ### Permissions add, delete, change
194 def has_add_permission(self, request):
195 return False
196
197 def has_delete_permission(self, request, obj=None):
198 return False
199
200 def has_change_permission(self, request, obj=None):
201 return True
202
203 class CandidatPieceInline(admin.TabularInline):
204 model = CandidatPiece
205 fields = ('candidat', 'nom', 'path',)
206 extra = 1
207 max_num = 3
208
209 class ReadOnlyCandidatPieceInline(CandidatPieceInline):
210 readonly_fields = ('candidat', 'nom', 'path', )
211 cand_delete = False
212
213
214 class CandidatEvaluationInlineFormSet(BaseInlineFormSet):
215 """
216 Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
217 """
218 def __init__(self, *args, **kwargs):
219 super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs)
220 self.can_delete = False
221
222 class CandidatEvaluationInline(admin.TabularInline):
223 model = CandidatEvaluation
224 fields = ('evaluateur', 'note', 'commentaire')
225 max_num = 0
226 extra = 0
227 formset = CandidatEvaluationInlineFormSet
228
229 ### Fields readonly
230 def get_readonly_fields(self, request, obj=None):
231 """
232 Empêche la modification des évaluations
233 """
234 if obj:
235 return self.readonly_fields+('evaluateur', 'note', 'commentaire')
236 return self.readonly_fields
237
238 class CandidatAdmin(VersionAdmin):
239 search_fields = ('nom', 'prenom' )
240 exclude = ('actif', )
241 list_editable = ('statut', )
242 list_display = ('nom', 'prenom', 'offre_emploi',
243 'voir_offre_emploi', 'calculer_moyenne',
244 'afficher_candidat', '_date_creation', 'statut', )
245 list_filter = ('offre_emploi', 'offre_emploi__region', 'statut', )
246
247 fieldsets = (
248 ("Offre d'emploi", {
249 'fields': ('offre_emploi', )
250 }),
251 ('Informations personnelles', {
252 'fields': ('prenom','nom','genre', 'nationalite',
253 'situation_famille', 'nombre_dependant',)
254 }),
255 ('Coordonnées', {
256 'fields': ('telephone', 'email', 'adresse', 'ville',
257 'etat_province', 'code_postal', 'pays', )
258 }),
259 ('Informations professionnelles', {
260 'fields': ('niveau_diplome','employeur_actuel',
261 'poste_actuel', 'domaine_professionnel',)
262 }),
263 ('Traitement', {
264 'fields': ('statut', )
265 }),
266 )
267 inlines = [
268 CandidatPieceInline,
269 CandidatEvaluationInline,
270 ]
271
272 actions = ['envoyer_courriel_candidats']
273
274 def _date_creation(self, obj):
275 return obj.date_creation
276 _date_creation.order_field = "date_creation"
277 _date_creation.short_description = "Date de création"
278
279 ### Actions à afficher
280 def get_actions(self, request):
281 actions = super(CandidatAdmin, self).get_actions(request)
282 del actions['delete_selected']
283 return actions
284
285 ### Envoyer un courriel à des candidats
286 def envoyer_courriel_candidats(modeladmin, obj, candidats):
287 selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
288
289 return HttpResponseRedirect(reverse('selectionner_template')+
290 "?ids=%s" % (",".join(selected)))
291 envoyer_courriel_candidats.short_description = u'Envoyer courriel'
292
293 ### Évaluer un candidat
294 def evaluer_candidat(self, obj):
295 return "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat</a>" % \
296 (reverse('admin:recrutement_candidatevaluation_changelist'),
297 obj.id)
298 evaluer_candidat.allow_tags = True
299 evaluer_candidat.short_description = 'Évaluation'
300
301 ### Afficher un candidat
302 def afficher_candidat(self, obj):
303 items = [u"<li><a href='%s%s'>%s</li>" % \
304 (settings.OE_PRIVE_MEDIA_URL, pj.path, pj.get_nom_display()) \
305 for pj in obj.pieces_jointes()]
306 html = "<a href='%s'>Voir le candidat</a>" % \
307 (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
308 return "%s<ul>%s</ul>" % (html, "\n".join(items))
309 afficher_candidat.allow_tags = True
310 afficher_candidat.short_description = u'Détails du candidat'
311
312 ### Voir l'offre d'emploi
313 def voir_offre_emploi(self, obj):
314 return "<a href='%s'>Voir l'offre d'emploi</a>" % \
315 (reverse('admin:recrutement_proxyoffreemploi_change',
316 args=(obj.offre_emploi.id,)))
317 voir_offre_emploi.allow_tags = True
318 voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
319
320 ### Calculer la moyenne des notes
321 def calculer_moyenne(self, obj):
322 evaluations = CandidatEvaluation.objects.filter(candidat=obj)
323
324 notes = [evaluation.note for evaluation in evaluations \
325 if evaluation.note is not None]
326
327 if len(notes) > 0:
328 moyenne_votes = round(float(sum(notes)) / len(notes), 2)
329 else:
330 moyenne_votes = "Non disponible"
331
332 totales = len(evaluations)
333 faites = len(notes)
334
335 if obj.statut == 'REC':
336 if totales == faites:
337 color = "green"
338 elif faites > 0 and float(totales) / float(faites) >= 2:
339 color = "orange"
340 else:
341 color = "red"
342 else:
343 color = "black"
344
345 return """<span style="color: %s;">%s (%s/%s)</span>""" % (color, moyenne_votes, faites, totales)
346 calculer_moyenne.allow_tags = True
347 calculer_moyenne.short_description = "Moyenne"
348 calculer_moyenne.admin_order_field = ""
349
350 ### Permissions add, delete, change
351 def has_add_permission(self, request):
352 user_groupes = request.user.groups.all()
353 if request.user.is_superuser is True or \
354 grp_correspondants_rh_recrutement in user_groupes or \
355 grp_drh_recrutement in user_groupes or \
356 grp_directeurs_bureau_recrutement in user_groupes or \
357 grp_administrateurs_recrutement in user_groupes:
358 return True
359 return False
360
361 def has_delete_permission(self, request, obj=None):
362 user_groupes = request.user.groups.all()
363 if request.user.is_superuser is True or \
364 grp_correspondants_rh_recrutement in user_groupes or \
365 grp_drh_recrutement in user_groupes or \
366 grp_directeurs_bureau_recrutement in user_groupes or \
367 grp_administrateurs_recrutement in user_groupes:
368 return True
369 return False
370
371 def has_change_permission(self, request, obj=None):
372 user_groupes = request.user.groups.all()
373 if request.user.is_superuser is True or \
374 grp_correspondants_rh_recrutement in user_groupes or \
375 grp_drh_recrutement in user_groupes or \
376 grp_directeurs_bureau_recrutement in user_groupes or \
377 grp_administrateurs_recrutement in user_groupes:
378 return True
379 return False
380
381 def get_changelist(self, request, **kwargs):
382 return OrderedChangeList
383
384 def queryset(self, request):
385 """
386 Spécifie un queryset limité, autrement Django exécute un
387 select_related() sans paramètre, ce qui a pour effet de charger tous
388 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
389 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
390 génération d'une requête infinie.
391
392 """
393
394 qs = self.model._default_manager.get_query_set().select_related('offre_emploi').annotate(moyenne=Avg('evaluations__note'))
395
396 user_groupes = request.user.groups.all()
397 if grp_drh_recrutement in user_groupes:
398 return qs
399
400 if grp_directeurs_bureau_recrutement in user_groupes or \
401 grp_correspondants_rh_recrutement in user_groupes or \
402 grp_administrateurs_recrutement in user_groupes:
403 employe = get_emp(request.user)
404 return qs.filter(offre_emploi__region=employe.implantation.region)
405
406 if Evaluateur.objects.filter(user=request.user).exists():
407 evaluateur = Evaluateur.objects.get(user=request.user)
408 candidat_ids = [e.candidat.id for e in
409 CandidatEvaluation.objects.filter(evaluateur=evaluateur)]
410 return qs.filter(id__in=candidat_ids)
411 return qs.none()
412
413
414 class ProxyCandidatAdmin(CandidatAdmin):
415 list_editable = ()
416 readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom',
417 'genre', 'nationalite', 'situation_famille',
418 'nombre_dependant', 'telephone', 'email', 'adresse',
419 'ville', 'etat_province', 'code_postal', 'pays',
420 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
421 'domaine_professionnel', 'pieces_jointes',)
422 fieldsets = (
423 ("Offre d'emploi", {
424 'fields': ('offre_emploi', )
425 }),
426 ('Informations personnelles', {
427 'fields': ('prenom','nom','genre', 'nationalite',
428 'situation_famille', 'nombre_dependant',)
429 }),
430 ('Coordonnées', {
431 'fields': ('telephone', 'email', 'adresse', 'ville',
432 'etat_province', 'code_postal', 'pays', )
433 }),
434 ('Informations professionnelles', {
435 'fields': ('niveau_diplome','employeur_actuel',
436 'poste_actuel', 'domaine_professionnel',)
437 }),
438 )
439 inlines = (CandidatEvaluationInline, )
440
441 def has_add_permission(self, request):
442 return False
443
444 def has_delete_permission(self, request, obj=None):
445 return False
446
447 def has_change_permission(self, request, obj=None):
448 return True
449
450 def get_actions(self, request):
451 return None
452
453 class CandidatPieceAdmin(admin.ModelAdmin):
454 list_display = ('nom', 'candidat', )
455
456 ### Queryset
457 def queryset(self, request):
458 """
459 Spécifie un queryset limité, autrement Django exécute un
460 select_related() sans paramètre, ce qui a pour effet de charger tous
461 les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
462 modèles de Region, il existe plusieurs boucles, ce qui conduit à la
463 génération d'une requête infinie.
464 Affiche la liste de candidats que si le user connecté
465 possède un Evaluateur
466 """
467 qs = self.model._default_manager.get_query_set()
468 return qs.select_related('candidat')
469
470 class EvaluateurAdmin(VersionAdmin):
471 fieldsets = (
472 ("Utilisateur", {
473 'fields': ('user',)
474 }),
475 )
476
477 ### Actions à afficher
478 def get_actions(self, request):
479 actions = super(EvaluateurAdmin, self).get_actions(request)
480 del actions['delete_selected']
481 return actions
482
483 ### Permissions add, delete, change
484 def has_add_permission(self, request):
485 user_groupes = request.user.groups.all()
486 if request.user.is_superuser is True or \
487 grp_drh_recrutement in user_groupes:
488 return True
489 return False
490
491 def has_delete_permission(self, request, obj=None):
492 user_groupes = request.user.groups.all()
493 if request.user.is_superuser is True or \
494 grp_drh_recrutement in user_groupes:
495 return True
496 return False
497
498 def has_change_permission(self, request, obj=None):
499 user_groupes = request.user.groups.all()
500 if request.user.is_superuser is True or \
501 grp_drh_recrutement in user_groupes:
502 return True
503 return False
504
505 class CandidatEvaluationAdmin(admin.ModelAdmin):
506 search_fields = ('candidat__nom', 'candidat__prenom' )
507 list_display = ('_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
508 '_commentaire', )
509 readonly_fields = ('candidat', 'evaluateur')
510 list_filter = ('candidat__statut', 'candidat__offre_emploi',)
511 fieldsets = (
512 ('Évaluation du candidat', {
513 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
514 }),
515 )
516
517 def get_actions(self, request):
518 # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
519 try:
520 self.evaluateur = Evaluateur.objects.get(user=request.user)
521 except:
522 self.evaluateur = None
523
524 actions = super(CandidatEvaluationAdmin, self).get_actions(request)
525 del actions['delete_selected']
526 return actions
527
528 ### Afficher la note
529 def _note(self, obj):
530 """
531 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
532 un lien pour Évaluer le candidat.
533 Sinon afficher la note.
534 """
535 page = self.model.__name__.lower()
536 redirect_url = 'admin:recrutement_%s_change' % page
537
538 if obj.note is None:
539 label = "Candidat non évalué"
540 else:
541 label = obj.note
542
543 if self.evaluateur == obj.evaluateur:
544 return "<a href='%s'>%s</a>" % (reverse(redirect_url, args=(obj.id,)), label)
545 else:
546 return label
547 _note.allow_tags = True
548 _note.short_description = "Note"
549 _note.admin_order_field = 'note'
550
551 def _statut(self, obj):
552 return obj.candidat.get_statut_display()
553 _statut.order_field = 'candidat__statut'
554 _statut.short_description = 'Statut'
555
556
557 ### Lien en lecture seule vers le candidat
558 def _candidat(self, obj):
559 return "<a href='%s'>%s</a>" \
560 % (reverse('admin:recrutement_proxycandidat_change',
561 args=(obj.candidat.id,)), obj.candidat)
562 _candidat.allow_tags = True
563 _candidat.short_description = 'Candidat'
564
565 ### Afficher commentaire
566 def _commentaire(self, obj):
567 """
568 Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
569 dans le champ commentaire, Aucun au lieu de (None)
570 Sinon afficher la note.
571 """
572 if obj.commentaire is None:
573 return "Aucun"
574 return obj.commentaire
575 _commentaire.allow_tags = True
576 _commentaire.short_description = "Commentaire"
577
578 ### Afficher offre d'emploi
579 def _offre_emploi(self, obj):
580 return "<a href='%s'>%s</a>" % \
581 (reverse('admin:recrutement_proxyoffreemploi_change',
582 args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
583 _offre_emploi.allow_tags = True
584 _offre_emploi.short_description = "Voir offre d'emploi"
585
586 def has_add_permission(self, request):
587 return False
588
589 def has_delete_permission(self, request, obj=None):
590 return False
591
592 def has_change_permission(self, request, obj=None):
593 """
594 Permettre la visualisation dans la changelist
595 mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
596 le request.user
597 """
598 user_groupes = request.user.groups.all()
599
600 if request.user.is_superuser or \
601 grp_drh_recrutement in user_groupes or \
602 grp_correspondants_rh_recrutement in user_groupes or \
603 grp_directeurs_bureau_recrutement in user_groupes or \
604 grp_administrateurs_recrutement in user_groupes:
605 is_recrutement = True
606 else:
607 is_recrutement = False
608
609 try:
610 Evaluateur.objects.get(user=request.user)
611 is_evaluateur = True
612 except:
613 is_evaluateur = False
614
615 if obj is None and (is_recrutement or is_evaluateur):
616 return True
617
618 if request.user.is_superuser is True:
619 return True
620
621 try:
622 return request.user == obj.evaluateur.user
623 except:
624 return False
625
626 ### Queryset
627 def queryset(self, request):
628 """
629 Afficher uniquement les évaluations de l'évaluateur, sauf si
630 l'utilisateur est dans les groupes suivants.
631 """
632 qs = self.model._default_manager.get_query_set().select_related('offre_emploi')
633 user_groupes = request.user.groups.all()
634
635 if grp_drh_recrutement in user_groupes or \
636 grp_correspondants_rh_recrutement in user_groupes or \
637 grp_directeurs_bureau_recrutement in user_groupes or \
638 grp_administrateurs_recrutement in user_groupes:
639 return qs
640
641 evaluateur = Evaluateur.objects.get(user=request.user)
642 candidats_evaluations = \
643 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
644 candidat__statut__in=('REC', ))
645 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
646 return qs.filter(id__in=candidats_evaluations_ids)
647
648
649 class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin):
650
651 def has_change_permission(self, request, obj=None):
652 try:
653 Evaluateur.objects.get(user=request.user)
654 is_evaluateur = True
655 except:
656 is_evaluateur = False
657
658 if obj is None and is_evaluateur:
659 return True
660
661 try:
662 return request.user == obj.evaluateur.user
663 except:
664 return False
665
666 def queryset(self, request):
667 qs = self.model._default_manager.get_query_set().select_related('offre_emploi')
668 evaluateur = Evaluateur.objects.get(user=request.user)
669 candidats_evaluations = \
670 CandidatEvaluation.objects.filter(evaluateur=evaluateur,
671 candidat__statut__in=('REC', ))
672 candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
673 return qs.filter(id__in=candidats_evaluations_ids)
674
675
676 class CourrielTemplateAdmin(VersionAdmin):
677 ### Actions à afficher
678 def get_actions(self, request):
679 actions = super(CourrielTemplateAdmin, self).get_actions(request)
680 del actions['delete_selected']
681 return actions
682
683 admin.site.register(OffreEmploi, OffreEmploiAdmin)
684 admin.site.register(ProxyOffreEmploi, ProxyOffreEmploiAdmin)
685 admin.site.register(Candidat, CandidatAdmin)
686 admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
687 admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
688 admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin)
689 admin.site.register(Evaluateur, EvaluateurAdmin)
690 admin.site.register(CourrielTemplate, CourrielTemplateAdmin)