X-Git-Url: http://git.auf.org/?p=auf_rh_dae.git;a=blobdiff_plain;f=project%2Frecrutement%2Fadmin.py;h=c2b14aa4bafe9a16b1b7d9cb753bb335fb29a484;hp=ddbddd839d938db69e9e89e5118779d7ee2848b8;hb=bad00d312daf1bf886ca1d5b2708c1d3e4e91650;hpb=c281435b9cf6345a33b44ff0d126f8e69a1e36ee
diff --git a/project/recrutement/admin.py b/project/recrutement/admin.py
index ddbddd8..c2b14aa 100644
--- a/project/recrutement/admin.py
+++ b/project/recrutement/admin.py
@@ -1,152 +1,297 @@
# -*- encoding: utf-8 -*-
-from django.core.urlresolvers import reverse
-from django.http import HttpResponseRedirect
+import textwrap
+
+from auf.django.emploi.models import CandidatPiece, Candidat, OffreEmploi
+from auf.django.references.models import Region, Bureau, Implantation
+from django.conf import settings
from django.contrib import admin
-from django.shortcuts import get_object_or_404
-from django.core.files.storage import default_storage
+from django.core.urlresolvers import reverse
+from django.db.models import Avg
+from django.shortcuts import render_to_response
+from django.template import RequestContext
-from reversion.admin import VersionAdmin
-from datamaster_modeles.models import Employe, Implantation, Region
+from auf.django.export.admin import ExportAdmin
+from auf.django.emploi.models import STATUT_CHOICES
from django.forms.models import BaseInlineFormSet
+from django.http import HttpResponseRedirect
+from django.shortcuts import redirect
+from reversion.admin import VersionAdmin
+
+from project import groups
+from project.permissions import get_user_groupnames
from project.rh import models as rh
-from recrutement.models import *
-from recrutement.workflow import grp_administrateurs_recrutement,\
- grp_evaluateurs_recrutement, grp_drh_recrutement
-from recrutement.forms import *
+from project.recrutement.forms import OffreEmploiForm
+from project.recrutement.models import \
+ Evaluateur, CandidatEvaluation, \
+ ProxyOffreEmploi, ProxyCandidat, MesCandidatEvaluation, \
+ CourrielTemplate, OffreEmploiEvaluateur
-"""
-class MetaAdmin(VersionAdmin):
- def get_actions(self, request):
-
-Pour refactoring
-"""
-class ProxyEvaluateur(Evaluateur.offres_emploi.through):
+### CONSTANTES
+IMPLANTATIONS_CENTRALES = [15, 19]
+
+
+class BaseAdmin(admin.ModelAdmin):
+
+ class Media:
+ css = {'screen': (
+ 'css/admin_custom.css',
+ 'jquery-autocomplete/jquery.autocomplete.css',
+ )}
+ js = (
+ 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js',
+ 'jquery-autocomplete/jquery.autocomplete.min.js',
+ )
+
+
+class OrderedChangeList(admin.views.main.ChangeList):
"""
- Ce proxy sert uniquement dans l'admin à disposer d'un libellé
- plus ergonomique.
+ Surcharge pour appliquer le order_by d'un annotate
"""
- class Meta:
- proxy = True
- verbose_name = "évaluateur"
+ def get_query_set(self):
+ qs = super(OrderedChangeList, self).get_query_set()
+ qs = qs.order_by('-moyenne')
+ return qs
-class EvaluateurInline(admin.TabularInline):
- model = ProxyEvaluateur
- fields = ('evaluateur',)
- extra = 1
-class OffreEmploiAdmin(VersionAdmin):
+class OffreEmploiAdminMixin(BaseAdmin):
date_hierarchy = 'date_creation'
- list_display = ('nom', 'date_limite', 'region', 'statut',
- 'est_affiche', '_candidatsList', )
- exclude = ('poste_nom', 'resume',)
- list_filter = ('statut', 'est_affiche', )
+ list_display = (
+ 'nom', 'date_limite', 'region', 'statut', 'est_affiche',
+ '_candidatsList'
+ )
+ exclude = ('actif', 'poste_nom', 'resume',)
+ list_filter = ('statut',)
actions = ['affecter_evaluateurs_offre_emploi', ]
form = OffreEmploiForm
- inlines = [EvaluateurInline, ]
+ fieldsets = (
+ (None, {
+ 'fields': (
+ 'est_affiche',
+ 'statut',
+ 'date_limite',
+ 'nom',
+ 'description',
+ 'poste',
+ 'region',
+ 'lieu_affectation',
+ 'bureau',
+ 'debut_affectation',
+ 'duree_affectation',
+ 'renumeration',
+ )
+ }),
+ )
+ ### Actions à afficher
def get_actions(self, request):
- actions = super(OffreEmploiAdmin, self).get_actions(request)
+ actions = super(OffreEmploiAdminMixin, self).get_actions(request)
del actions['delete_selected']
return actions
- # Affecter un évaluateurs à des offres d'emploi
- def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):
+ ### Affecter un évaluateurs à des offres d'emploi
+ def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):
selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
- return HttpResponseRedirect(reverse('affecter_evaluateurs_offre_emploi')+
- "?ids=%s" % (",".join(selected)))
- affecter_evaluateurs_offre_emploi.short_description = u'Affecter évaluateur(s)'
+ return HttpResponseRedirect(
+ reverse('affecter_evaluateurs_offre_emploi') +
+ "?ids=%s" % (",".join(selected))
+ )
- # Afficher la liste des candidats pour l'offre d'emploi
- def _candidatsList(self, obj):
+ affecter_evaluateurs_offre_emploi.short_description = \
+ u'Affecter évaluateur(s)'
+
+ ### Afficher la liste des candidats pour l'offre d'emploi
+ def _candidatsList(self, obj):
return "Voir les candidats \
- " % (reverse('admin:recrutement_candidat_changelist'), obj.id)
- _candidatsList.allow_tags = True
+ " % (reverse('admin:recrutement_proxycandidat_changelist'), obj.id)
+ _candidatsList.allow_tags = True
_candidatsList.short_description = "Afficher la liste des candidats"
- def queryset(self, request):
- qs = self.model._default_manager.get_query_set()
- # Si user est superuser afficher toutes les offres d'emploi
- user_groupes = request.user.groups.all()
- if not grp_drh_recrutement in user_groupes and \
- not request.user.is_superuser:
- """
- Si le user n'est ni un évaluateur ni un administrateur régional,
- retourner none
- Vérifier groupes
- """
- if grp_evaluateurs_recrutement in user_groupes:
- try:
- user = Evaluateur.objects.get(user=request.user)
- except Evaluateur.DoesNotExist:
- return qs.none()
- elif grp_administrateurs_recrutement in user_groupes:
- try:
- user = AdministrateurRegional.objects.get(user=request.user)
- except AdministrateurRegional.DoesNotExist:
- return qs.none()
+ ### Formulaire
+ def get_form(self, request, obj=None, **kwargs):
+ form = super(OffreEmploiAdminMixin, self).get_form(request, obj, **kwargs)
+ employe = groups.get_employe_from_user(request.user)
+ user_groupes = get_user_groupnames(request.user)
+
+ # Region
+ region_field = None
+ if 'region' in form.declared_fields.keys():
+ region_field = form.declared_fields['region']
+ if 'region' in form.base_fields.keys():
+ region_field = form.base_fields['region']
+ if region_field:
+ if groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes or \
+ groups.HAUTE_DIRECTION in user_groupes:
+ region_field.queryset = Region.objects.all()
+ else:
+ region_field.queryset = Region.objects.\
+ filter(id=employe.implantation.region.id)
+
+ # Poste
+ poste_field = None
+ if 'poste' in form.declared_fields.keys():
+ poste_field = form.declared_fields['poste']
+ if 'poste' in form.base_fields.keys():
+ poste_field = form.base_fields['poste']
+ if poste_field:
+ if groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes or \
+ groups.HAUTE_DIRECTION in user_groupes:
+ poste_field.queryset = rh.Poste.objects.all()
+ else:
+ poste_field.queryset = rh.Poste.objects.\
+ filter(implantation__region=employe.implantation.region).\
+ exclude(implantation__in=IMPLANTATIONS_CENTRALES)
+
+ # Bureau
+ bureau_field = None
+ if 'bureau' in form.declared_fields.keys():
+ bureau_field = form.declared_fields['bureau']
+ if 'bureau' in form.base_fields.keys():
+ bureau_field = form.base_fields['bureau']
+ if bureau_field:
+ if groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes or \
+ groups.HAUTE_DIRECTION in user_groupes:
+ bureau_field.queryset = Bureau.objects.all()
else:
- return qs.none()
-
- if type(user) is AdministrateurRegional:
- region_ids = [g.id for g in user.regions.all()]
- return qs.select_related('offre_emploi').\
- filter(region__in=region_ids)
- if type(user) is Evaluateur:
- candidats = [g for g in user.candidats.all()]
- offre_emploi_ids = [c.offre_emploi.id for c in candidats]
- return qs.select_related('offre_emploi').\
- filter(id__in=offre_emploi_ids)
- return qs.none()
- return qs.select_related('offre_emploi')
+ bureau_field.queryset = \
+ Bureau.objects.filter(region=employe.implantation.region)
+
+ return form
+
+ ### Queryset
+
+ def queryset(self, request):
+ qs = self.model._default_manager.get_query_set() \
+ .select_related('offre_emploi')
+ user_groupes = get_user_groupnames(request.user)
+ if groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes or \
+ groups.HAUTE_DIRECTION in user_groupes:
+ return qs
+
+ if groups.DIRECTEUR_DE_BUREAU in user_groupes or \
+ groups.CORRESPONDANT_RH in user_groupes or \
+ groups.ADMINISTRATEURS in user_groupes:
+ employe = groups.get_employe_from_user(request.user)
+ return qs.filter(region=employe.implantation.region)
+
+ if Evaluateur.objects.filter(user=request.user).exists():
+ evaluateur = Evaluateur.objects.get(user=request.user)
+ offre_ids = [
+ e.candidat.offre_emploi_id
+ for e in CandidatEvaluation.objects
+ .select_related('candidat')
+ .filter(evaluateur=evaluateur)
+ ]
+ return qs.filter(id__in=offre_ids)
+
+ return qs.none()
+
+ ### Permission add, delete, change
+ def has_add_permission(self, request):
+ user_groupes = get_user_groupnames(request.user)
+ if request.user.is_superuser is True or \
+ groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes or \
+ groups.DIRECTEUR_DE_BUREAU in user_groupes or \
+ groups.ADMINISTRATEURS in user_groupes or \
+ groups.HAUTE_DIRECTION in user_groupes:
+ return True
+ return False
+
+ def has_delete_permission(self, request, obj=None):
+ user_groupes = get_user_groupnames(request.user)
+ if request.user.is_superuser is True or \
+ groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes or \
+ groups.HAUTE_DIRECTION in user_groupes:
+ return True
+
+ if obj is not None:
+ employe = groups.get_employe_from_user(request.user)
+ if (groups.DIRECTEUR_DE_BUREAU in user_groupes or \
+ groups.ADMINISTRATEURS in user_groupes) and (
+ employe.implantation.region == obj.lieu_affectation.region):
+ return True
+
+ return False
def has_change_permission(self, request, obj=None):
- user_groupes = request.user.groups.all()
- if grp_drh_recrutement in user_groupes or \
- grp_administrateurs_recrutement in user_groupes or \
- request.user.is_superuser:
+ user_groupes = get_user_groupnames(request.user)
+ if request.user.is_superuser is True or \
+ groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes or \
+ groups.HAUTE_DIRECTION in user_groupes:
return True
- return False
-
-class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
- list_display = ('nom', 'resume', 'date_limite', 'region', 'statut',
- 'est_affiche')
- readonly_fields = ('description', 'bureau',
- 'duree_affectation', 'renumeration',
- 'debut_affectation', 'lieu_affectation', 'nom',
- 'resume', 'date_limite', 'region')
+
+ if obj is not None:
+ employe = groups.get_employe_from_user(request.user)
+ if (groups.DIRECTEUR_DE_BUREAU in user_groupes or \
+ groups.ADMINISTRATEURS in user_groupes) and (
+ employe.implantation.region == obj.lieu_affectation.region):
+ return True
+ else:
+ if groups.DIRECTEUR_DE_BUREAU in user_groupes or \
+ groups.ADMINISTRATEURS in user_groupes:
+ return True
+
+
+ return False
+
+ def formfield_for_foreignkey(self, db_field, request, **kwargs):
+ if db_field.name == 'lieu_affectation':
+ user_groupes = [g.name for g in request.user.groups.all()]
+ if not (request.user.is_superuser is True or \
+ groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes):
+ employe = groups.get_employe_from_user(request.user)
+ kwargs["queryset"] = Implantation.objects.filter(region=employe.implantation.region)
+ return db_field.formfield(**kwargs)
+ return super(OffreEmploiAdminMixin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+
+class OffreEmploiAdmin(VersionAdmin, OffreEmploiAdminMixin):
+ pass
+
+
+class ProxyOffreEmploiAdmin(OffreEmploiAdminMixin):
+ list_display = (
+ 'nom', 'date_limite', 'region', 'statut', 'est_affiche'
+ )
+ readonly_fields = (
+ 'description', 'bureau', 'duree_affectation', 'renumeration',
+ 'debut_affectation', 'lieu_affectation', 'nom', 'resume',
+ 'date_limite', 'region', 'poste'
+ )
fieldsets = (
('Nom', {
- 'fields': ('nom', )
+ 'fields': ('nom',)
}),
('Description générale', {
- 'fields': ('resume','description', 'date_limite', )
+ 'fields': ('description', 'date_limite',)
}),
('Coordonnées', {
- 'fields': ('lieu_affectation', 'bureau', 'region', )
+ 'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
}),
('Autre', {
- 'fields': ('debut_affectation', 'duree_affectation',
- 'renumeration', )
+ 'fields': (
+ 'debut_affectation', 'duree_affectation', 'renumeration',
+ )
}),
- )
-
- def get_actions(self, request):
- actions = super(ProxyOffreEmploiAdmin, self).get_actions(request)
- del actions['affecter_evaluateurs_offre_emploi']
- return actions
+ )
+ inlines = []
+ ### Lieu de redirection après le change
def response_change(self, request, obj):
- response = super(ProxyOffreEmploiAdmin, self).response_change(request, obj)
- user_groupes = request.user.groups.all()
- if grp_drh_recrutement in user_groupes or \
- request.user.is_superuser:
- return HttpResponseRedirect(reverse('admin:recrutement_offreemploi_changelist'))
- return HttpResponseRedirect(reverse('admin:recrutement_proxyoffreemploi_changelist'))
+ return redirect('admin:recrutement_proxyoffreemploi_changelist')
+ ### Permissions add, delete, change
def has_add_permission(self, request):
return False
@@ -154,12 +299,11 @@ class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
return False
def has_change_permission(self, request, obj=None):
- user_groupes = request.user.groups.all()
- if grp_evaluateurs_recrutement in user_groupes or \
- grp_drh_recrutement in user_groupes or \
- request.user.is_superuser:
+ if obj is not None:
return True
- return False
+
+ return not super(ProxyOffreEmploiAdmin, self).has_change_permission(request, obj)
+
class CandidatPieceInline(admin.TabularInline):
model = CandidatPiece
@@ -167,13 +311,20 @@ class CandidatPieceInline(admin.TabularInline):
extra = 1
max_num = 3
+
+class ReadOnlyCandidatPieceInline(CandidatPieceInline):
+ readonly_fields = ('candidat', 'nom', 'path', )
+ cand_delete = False
+
+
class CandidatEvaluationInlineFormSet(BaseInlineFormSet):
"""
Empêche la suppression d'une évaluation pour le CandidatEvaluationInline
"""
def __init__(self, *args, **kwargs):
super(CandidatEvaluationInlineFormSet, self).__init__(*args, **kwargs)
- self.can_delete = False
+ self.can_delete = False
+
class CandidatEvaluationInline(admin.TabularInline):
model = CandidatEvaluation
@@ -181,37 +332,48 @@ class CandidatEvaluationInline(admin.TabularInline):
max_num = 0
extra = 0
formset = CandidatEvaluationInlineFormSet
-
+
+ ### Fields readonly
def get_readonly_fields(self, request, obj=None):
"""
Empêche la modification des évaluations
"""
if obj:
- return self.readonly_fields+('evaluateur', 'note', 'commentaire')
+ return self.readonly_fields + ('evaluateur', 'note', 'commentaire')
return self.readonly_fields
-class CandidatAdmin(VersionAdmin):
- date_hierarchy = 'date_creation'
- list_display = ('nom', 'prenom', 'offre_emploi','statut',
- 'voir_offre_emploi', 'calculer_moyenne',
- 'afficher_candidat',)
- list_filter = ('offre_emploi', )
+
+class CandidatAdminMixin(BaseAdmin, ExportAdmin):
+ search_fields = ('nom', 'prenom')
+ exclude = ('actif', )
+ list_editable = ('statut', )
+ list_display = ('_candidat', 'offre_emploi',
+ 'voir_offre_emploi', 'calculer_moyenne',
+ 'afficher_candidat', '_date_creation', 'statut', )
+ list_filter = ('offre_emploi__nom', 'offre_emploi__region', 'statut', )
+
fieldsets = (
("Offre d'emploi", {
'fields': ('offre_emploi', )
}),
('Informations personnelles', {
- 'fields': ('prenom','nom','genre', 'nationalite',
- 'situation_famille', 'nombre_dependant',)
+ 'fields': (
+ 'nom', 'prenom', 'genre', 'nationalite',
+ 'situation_famille', 'nombre_dependant'
+ )
}),
('Coordonnées', {
- 'fields': ('telephone', 'email', 'adresse', 'ville',
- 'etat_province', 'code_postal', 'pays', )
+ 'fields': (
+ 'telephone', 'email', 'adresse', 'ville', 'etat_province',
+ 'code_postal', 'pays'
+ )
}),
('Informations professionnelles', {
- 'fields': ('niveau_diplome','employeur_actuel',
- 'poste_actuel', 'domaine_professionnel',)
- }),
+ 'fields': (
+ 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
+ 'domaine_professionnel'
+ )
+ }),
('Traitement', {
'fields': ('statut', )
}),
@@ -220,152 +382,248 @@ class CandidatAdmin(VersionAdmin):
CandidatPieceInline,
CandidatEvaluationInline,
]
+ actions = ['envoyer_courriel_candidats', 'changer_statut']
- actions = ['envoyer_courriel_candidats']
+ export_fields = ['statut', 'offre_emploi', 'prenom', 'nom', 'genre',
+ 'nationalite', 'situation_famille', 'nombre_dependant',
+ 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
+ 'domaine_professionnel', 'telephone', 'email', 'adresse',
+ 'ville', 'etat_province', 'code_postal', 'pays']
+ def _candidat(self, obj):
+ txt = u"%s %s (%s)" % (obj.nom.upper(), obj.prenom, obj.genre)
+ txt = textwrap.wrap(txt, 30)
+ return "
".join(txt)
+ _candidat.short_description = "Candidat"
+ _candidat.admin_order_field = "nom"
+ _candidat.allow_tags = True
+
+ def _date_creation(self, obj):
+ return obj.date_creation
+ _date_creation.admin_order_field = "date_creation"
+ _date_creation.short_description = "Date de réception"
+
+ ### Actions à afficher
def get_actions(self, request):
- actions = super(CandidatAdmin, self).get_actions(request)
+ actions = super(CandidatAdminMixin, self).get_actions(request)
del actions['delete_selected']
return actions
- # Envoyer un courriel à des candidats
- def envoyer_courriel_candidats(modeladmin, obj, candidats):
+ ### Envoyer un courriel à des candidats
+ def envoyer_courriel_candidats(modeladmin, obj, candidats):
selected = obj.POST.getlist(admin.ACTION_CHECKBOX_NAME)
- return HttpResponseRedirect(reverse('selectionner_template')+
- "?ids=%s" % (",".join(selected)))
+ return HttpResponseRedirect(
+ reverse('selectionner_template') + "?ids=%s" % (",".join(selected))
+ )
envoyer_courriel_candidats.short_description = u'Envoyer courriel'
- # Ãvaluer un candidat
+ ### Changer le statut à des candidats
+ def changer_statut(modeladmin, request, queryset):
+ if request.POST.get('post'):
+ queryset.update(statut=request.POST.get('statut'))
+ return None
+
+ context = {
+ 'action_checkbox_name': admin.helpers.ACTION_CHECKBOX_NAME,
+ 'queryset': queryset,
+ 'status': STATUT_CHOICES,
+ }
+
+ return render_to_response("recrutement/selectionner_statut.html",
+ context, context_instance = RequestContext(request))
+
+ changer_statut.short_description = u'Changer statut'
+
+ ### Ãvaluer un candidat
def evaluer_candidat(self, obj):
- return "Ãvaluer le candidat" % \
- (reverse('admin:recrutement_candidatevaluation_changelist'),
- obj.id)
- evaluer_candidat.allow_tags = True
+ return "" \
+ "Ãvaluer le candidat" % (
+ reverse('admin:recrutement_candidatevaluation_changelist'),
+ obj.id
+ )
+ evaluer_candidat.allow_tags = True
evaluer_candidat.short_description = 'Ãvaluation'
- # Afficher un candidat
+ ### Afficher un candidat
def afficher_candidat(self, obj):
- return "Voir le candidat" % \
- (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
- afficher_candidat.allow_tags = True
+ items = [u"