# -*- 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 "<a href='%s?offre_emploi__id__exact=%s'>Voir les candidats \
- </a>" % (reverse('admin:recrutement_candidat_changelist'), obj.id)
- _candidatsList.allow_tags = True
+ </a>" % (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
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
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
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', )
}),
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 "<br/>".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 "<a href='%s?candidat__id__exact=%s'>Évaluer le candidat</a>" % \
- (reverse('admin:recrutement_candidatevaluation_changelist'),
- obj.id)
- evaluer_candidat.allow_tags = True
+ return "<a href='%s?candidat__id__exact=%s'>" \
+ "Évaluer le candidat</a>" % (
+ 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 "<a href='%s'>Voir le candidat</a>" % \
- (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
- afficher_candidat.allow_tags = True
+ items = [u"<li><a href='%s%s'>%s</li>" % \
+ (settings.OE_PRIVE_MEDIA_URL, pj.path, pj.get_nom_display()) \
+ for pj in obj.pieces_jointes()]
+ html = "<a href='%s'>Candidature</a>" % (
+ reverse('admin:recrutement_proxycandidat_change', args=(obj.id,))
+ )
+ return "%s<ul>%s</ul>" % (html, "\n".join(items))
+ afficher_candidat.allow_tags = True
afficher_candidat.short_description = u'Détails du candidat'
- # Voir l'offre d'emploi
+ ### Voir l'offre d'emploi
def voir_offre_emploi(self, obj):
- return "<a href='%s'>Voir l'offre d'emploi</a>" % \
- (reverse('admin:recrutement_proxyoffreemploi_change',
- args=(obj.offre_emploi.id,)))
+ return "<a href='%s'>Voir l'offre d'emploi</a>" % (reverse(
+ 'admin:recrutement_proxyoffreemploi_change',
+ args=(obj.offre_emploi.id,)
+ ))
voir_offre_emploi.allow_tags = True
voir_offre_emploi.short_description = "Afficher l'offre d'emploi"
- # Calculer la moyenne des notes
+ ### Calculer la moyenne des notes
def calculer_moyenne(self, obj):
evaluations = CandidatEvaluation.objects.filter(candidat=obj)
- offre_emploi = obj.offre_emploi
- notes = [evaluation.note for evaluation in evaluations.all() \
+ notes = [evaluation.note for evaluation in evaluations \
if evaluation.note is not None]
-
- if len(notes) > 0 and offre_emploi.date_limite <= datetime.date.today():
- moyenne_votes = float(sum(notes)) / len(notes)
+
+ if len(notes) > 0:
+ moyenne_votes = round(float(sum(notes)) / len(notes), 2)
else:
moyenne_votes = "Non disponible"
- return moyenne_votes
- calculer_moyenne.allow_tags = True
- calculer_moyenne.short_description = "Moyenne des notes"
- def add_delete_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:
- return True
- return False
+ totales = len(evaluations)
+ faites = len(notes)
+
+ if obj.statut == 'REC':
+ if totales == faites:
+ color = "green"
+ elif faites > 0 and float(totales) / float(faites) >= 2:
+ color = "orange"
+ else:
+ color = "red"
+ else:
+ color = "black"
+
+ return """<span style="color: %s;">%s (%s/%s)</span>""" % (
+ color, moyenne_votes, faites, totales
+ )
+ calculer_moyenne.allow_tags = True
+ calculer_moyenne.short_description = "Moyenne"
+ calculer_moyenne.admin_order_field = ""
+ ### Permissions add, delete, change
def has_add_permission(self, request):
- return self.add_delete_permission(request, request)
+ user_groupes = get_user_groupnames(request.user)
+ if request.user.is_superuser is True or \
+ groups.CORRESPONDANT_RH in user_groupes 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):
- return self.add_delete_permission(request, request)
+ user_groupes = get_user_groupnames(request.user)
+ if request.user.is_superuser is True or \
+ groups.CORRESPONDANT_RH in user_groupes 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_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.CORRESPONDANT_RH in user_groupes 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
+ return False
+
+ def formfield_for_foreignkey(self, db_field, request, **kwargs):
+ if db_field.name == 'offre_emploi':
+ employe = groups.get_employe_from_user(request.user)
+ user_groupes = [g.name for g in request.user.groups.all()]
+ if request.user.is_superuser is True or \
+ groups.CORRESPONDANT_RH in user_groupes or \
+ groups.DRH_NIVEAU_1 in user_groupes or \
+ groups.DRH_NIVEAU_2 in user_groupes:
+ qs_offres = OffreEmploi.objects.all()
+ else:
+ qs_offres =OffreEmploi.objects.filter(region=employe.implantation.region)
+ kwargs["queryset"] = qs_offres
+ return db_field.formfield(**kwargs)
+ return super(CandidatAdminMixin, self).formfield_for_foreignkey(db_field, request, **kwargs)
+
+ def get_changelist(self, request, **kwargs):
+ return OrderedChangeList
def queryset(self, request):
"""
- Spécifie un queryset limité, autrement Django exécute un
- select_related() sans paramètre, ce qui a pour effet de charger tous
- les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
- modèles de Region, il existe plusieurs boucles, ce qui conduit à la
+ Spécifie un queryset limité, autrement Django exécute un
+ select_related() sans paramètre, ce qui a pour effet de charger tous
+ les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
+ modèles de Region, il existe plusieurs boucles, ce qui conduit à la
génération d'une requête infinie.
-
"""
- qs = self.model._default_manager.get_query_set()
- # Si user est superuser afficher tous les candidats
- 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=obj.user)
- except AdministrateurRegional.DoesNotExist:
- return qs.none()
- """
- else:
- return qs.none()
- ids = [c.id for c in user.candidats.all()]
- return qs.select_related('candidats').filter(id__in=ids)
- return qs.select_related('candidats')
-
-class ProxyCandidatAdmin(CandidatAdmin):
- readonly_fields = ('statut', 'offre_emploi', 'prenom', 'nom',
- 'genre', 'nationalite', 'situation_famille',
- 'nombre_dependant', 'telephone', 'email', 'adresse',
- 'ville', 'etat_province', 'code_postal', 'pays',
- 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
- 'domaine_professionnel', 'pieces_jointes',)
+ qs = self.model._default_manager.get_query_set() \
+ .select_related('offre_emploi') \
+ .annotate(moyenne=Avg('evaluations__note'))
+
+ 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(offre_emploi__region=employe.implantation.region)
+
+ if Evaluateur.objects.filter(user=request.user).exists():
+ evaluateur = Evaluateur.objects.get(user=request.user)
+ candidat_ids = [e.candidat.id for e in
+ CandidatEvaluation.objects.filter(evaluateur=evaluateur)]
+ return qs.filter(id__in=candidat_ids)
+ return qs.none()
+
+
+class CandidatAdmin(VersionAdmin, CandidatAdminMixin):
+ change_list_template = 'admin/recrutement/candidat/change_list.html'
+ pass
+
+
+class ProxyCandidatAdmin(CandidatAdminMixin):
+ change_list_template = 'admin/recrutement/candidat/change_list.html'
+ list_editable = ()
+ readonly_fields = (
+ 'statut', 'offre_emploi', 'prenom', 'nom', 'genre', 'nationalite',
+ 'situation_famille', 'nombre_dependant', 'telephone', 'email',
+ 'adresse', 'ville', 'etat_province', 'code_postal', 'pays',
+ 'niveau_diplome', 'employeur_actuel', 'poste_actuel',
+ 'domaine_professionnel', 'pieces_jointes'
+ )
fieldsets = (
("Offre d'emploi", {
'fields': ('offre_emploi', )
}),
('Informations personnelles', {
- 'fields': ('prenom','nom','genre', 'nationalite',
- 'situation_famille', 'nombre_dependant',)
+ 'fields': (
+ 'prenom', 'nom', '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'
+ )
+ }),
)
- inlines = []
-
- def response_change(self, request, obj):
- response = super(ProxyCandidatAdmin, 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_candidat_changelist'))
- return HttpResponseRedirect(reverse('admin:recrutement_proxycandidat_changelist'))
+ inlines = (CandidatEvaluationInline, )
def has_add_permission(self, request):
return False
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 \
- grp_evaluateurs_recrutement in user_groupes or \
- request.user.is_superuser:
- return True
- return False
+ if obj is not None:
+ return obj in self.queryset(request)
+ #try:
+ # evaluateur = Evaluateur.objects.get(user=request.user)
+ # for e in obj.evaluations.all():
+ # if e.evaluateur == evaluateur:
+ # return True
+ # return False
+ #except:
+ # pass
+ return super(ProxyCandidatAdmin, self).has_change_permission(request, obj)
+
+ def get_actions(self, request):
+ return None
+
class CandidatPieceAdmin(admin.ModelAdmin):
list_display = ('nom', 'candidat', )
+ ### Queryset
def queryset(self, request):
"""
- Spécifie un queryset limité, autrement Django exécute un
- select_related() sans paramètre, ce qui a pour effet de charger tous
- les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
- modèles de Region, il existe plusieurs boucles, ce qui conduit à la
- génération d'une requête infinie.
- Affiche la liste de candidats que si le user connecté
- possède un Evaluateur
+ Spécifie un queryset limité, autrement Django exécute un
+ select_related() sans paramètre, ce qui a pour effet de charger tous
+ les objets FK, sans limite de profondeur. Dès qu'on arrive, dans les
+ modèles de Region, il existe plusieurs boucles, ce qui conduit à la
+ génération d'une requête infinie. Affiche la liste de candidats que
+ si le user connecté possède un Evaluateur
"""
qs = self.model._default_manager.get_query_set()
return qs.select_related('candidat')
-class EvaluateurAdmin(VersionAdmin):
+
+class EvaluateurAdmin(BaseAdmin, VersionAdmin):
fieldsets = (
("Utilisateur", {
'fields': ('user',)
}),
- ("Offres d'emploi à évaluer", {
- 'fields': ('offres_emploi',)
- }),
)
+ ### Actions à afficher
def get_actions(self, request):
actions = super(EvaluateurAdmin, self).get_actions(request)
del actions['delete_selected']
return actions
-class AdministrateurRegionalAdmin(VersionAdmin):
- pass
+ ### Permissions 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.HAUTE_DIRECTION in user_groupes:
+ return True
+ return False
-class CandidatEvaluationAdmin(VersionAdmin):
- list_display = ('_candidat', '_offre_emploi', 'evaluateur', '_note',
- '_commentaire', )
+ 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
+ return False
+
+ def has_change_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
+ return False
+
+
+class CandidatEvaluationAdmin(BaseAdmin):
+ search_fields = ('candidat__nom', 'candidat__prenom')
+ list_display = (
+ '_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note',
+ '_commentaire'
+ )
readonly_fields = ('candidat', 'evaluateur')
+ list_filter = ('candidat__statut', 'candidat__offre_emploi',)
fieldsets = (
('Évaluation du candidat', {
- 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
+ 'fields': ('candidat', 'evaluateur', 'note', 'commentaire', )
}),
)
def get_actions(self, request):
+ # on stocke l'evaluateur connecté (pas forcément la meilleure place...)
+ try:
+ self.evaluateur = Evaluateur.objects.get(user=request.user)
+ except:
+ self.evaluateur = None
+
actions = super(CandidatEvaluationAdmin, self).get_actions(request)
del actions['delete_selected']
return actions
+ ### Afficher la note
def _note(self, obj):
"""
Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
un lien pour Évaluer le candidat.
Sinon afficher la note.
"""
- evaluateur = obj.evaluateur
- candidat = obj.candidat
- candidat_evaluation = CandidatEvaluation.objects.\
- get(candidat=candidat, evaluateur=evaluateur)
+ page = self.model.__name__.lower()
+ redirect_url = 'admin:recrutement_%s_change' % page
+
if obj.note is None:
- return "<a href='%s'>Candidat non évalué</a>" % \
- (reverse('admin:recrutement_candidatevaluation_change',
- args=(candidat_evaluation.id,)))
- return "<a href='%s'>%s</a>" % \
- (reverse('admin:recrutement_candidatevaluation_change',
- args=(candidat_evaluation.id,)), obj.note)
- return
+ label = "Candidat non évalué"
+ else:
+ label = obj.note
+
+ if self.evaluateur == obj.evaluateur:
+ return "<a href='%s'>%s</a>" % (
+ reverse(redirect_url, args=(obj.id,)), label
+ )
+ else:
+ return label
_note.allow_tags = True
- _note.short_description = "Votre note"
- _note.admin_order_field = 'note'
+ _note.short_description = "Note"
+ _note.admin_order_field = 'note'
+ def _statut(self, obj):
+ return obj.candidat.get_statut_display()
+ _statut.order_field = 'candidat__statut'
+ _statut.short_description = 'Statut'
+
+ ### Lien en lecture seule vers le candidat
def _candidat(self, obj):
return "<a href='%s'>%s</a>" \
- % (reverse('admin:recrutement_proxycandidat_change',
+ % (reverse('admin:recrutement_proxycandidat_change',
args=(obj.candidat.id,)), obj.candidat)
- _candidat.allow_tags = True
+ _candidat.allow_tags = True
_candidat.short_description = 'Candidat'
+ ### Afficher commentaire
def _commentaire(self, obj):
"""
Si l'évaluateur n'a pas encore donné de note au candidat, indiquer
return "Aucun"
return obj.commentaire
_commentaire.allow_tags = True
- _commentaire.short_description = "Commentaire"
-
+ _commentaire.short_description = "Commentaire"
+ ### Afficher offre d'emploi
def _offre_emploi(self, obj):
return "<a href='%s'>%s</a>" % \
- (reverse('admin:recrutement_proxyoffreemploi_change',
+ (reverse('admin:recrutement_proxyoffreemploi_change',
args=(obj.candidat.offre_emploi.id,)), obj.candidat.offre_emploi)
_offre_emploi.allow_tags = True
_offre_emploi.short_description = "Voir offre d'emploi"
-
+
+ def has_add_permission(self, request):
+ return False
+
+ def has_delete_permission(self, request, obj=None):
+ return False
+
def has_change_permission(self, request, obj=None):
"""
Permettre la visualisation dans la changelist
mais interdire l'accès à modifier l'objet si l'évaluateur n'est pas
le request.user
"""
- return obj is None or request.user == obj.evaluateur.user
+ user_groupes = get_user_groupnames(request.user)
+
+ if request.user.is_superuser or \
+ groups.CORRESPONDANT_RH in user_groupes 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:
+ is_recrutement = True
+ else:
+ is_recrutement = False
+
+ return is_recrutement
def queryset(self, request):
"""
- Afficher uniquement les évaluations de l'évaluateur, sauf si
- l'utilisateur est super admin.
+ Afficher uniquement les évaluations de l'évaluateur, sauf si
+ l'utilisateur est dans les groupes suivants.
"""
- qs = self.model._default_manager.get_query_set()
- user_groupes = request.user.groups.all()
- if grp_drh_recrutement in user_groupes or \
- request.user.is_superuser:
- return qs.select_related('offre_emploi')
+ qs = self.model._default_manager.get_query_set() \
+ .select_related('offre_emploi')
+ user_groupes = get_user_groupnames(request.user)
+
+ if request.user.is_superuser or \
+ groups.CORRESPONDANT_RH in user_groupes 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 qs.filter(candidat__statut__in=('REC', 'SEL'))
+
+ evaluateur = Evaluateur.objects.get(user=request.user)
+ candidats_evaluations = \
+ CandidatEvaluation.objects.filter(evaluateur=evaluateur,
+ candidat__statut__in=('REC', ))
+ candidats_evaluations_ids = [ce.id for ce in candidats_evaluations]
+ return qs.filter(id__in=candidats_evaluations_ids)
+
+
+class MesCandidatEvaluationAdmin(CandidatEvaluationAdmin):
+ list_filter = []
+
+ def has_change_permission(self, request, obj=None):
+ try:
+ Evaluateur.objects.get(user=request.user)
+ is_evaluateur = True
+ except:
+ is_evaluateur = False
+
+ if obj is None and is_evaluateur:
+ return True
try:
- evaluateur = Evaluateur.objects.get(user=request.user)
- except Evaluateur.DoesNotExist:
- return qs.none()
-
- candidats_evaluations = CandidatEvaluation.objects.\
- filter(evaluateur=evaluateur)
- candidats_evaluations_ids = [ce.id for ce in \
- candidats_evaluations.all()]
- return qs.select_related('offre_emploi').\
- filter(id__in=candidats_evaluations_ids)
-
-class CourrielTemplateAdmin(VersionAdmin):
+ return request.user == obj.evaluateur.user
+ except:
+ return False
+
+ def queryset(self, request):
+ qs = self.model._default_manager.get_query_set() \
+ .select_related('offre_emploi')
+ evaluateur = Evaluateur.objects.get(user=request.user)
+
+ # XXX: Pas l'idéal, mais on doit créer les objets CandidatEvaluation
+ # ici pour garder la liste à jour. Idéalement, il vaudrait peut-être
+ # mieux utiliser directement les objets Candidat.
+ for candidat in Candidat.objects .filter(
+ offre_emploi__offreemploievaluateur__evaluateur=evaluateur,
+ ).exclude(evaluations__evaluateur=evaluateur):
+ print candidat, candidat.offre_emploi
+ CandidatEvaluation.objects.get_or_create(
+ candidat=candidat, evaluateur=evaluateur
+ )
+
+ return qs.filter(
+ evaluateur=evaluateur, candidat__statut__in=('NOUV', 'REC')
+ )
+
+
+class OffreEmploiEvaluateurAdmin(BaseAdmin):
+ pass
+
+
+class CourrielTemplateAdmin(BaseAdmin, VersionAdmin):
+ ### Actions à afficher
def get_actions(self, request):
actions = super(CourrielTemplateAdmin, self).get_actions(request)
del actions['delete_selected']
admin.site.register(Candidat, CandidatAdmin)
admin.site.register(ProxyCandidat, ProxyCandidatAdmin)
admin.site.register(CandidatEvaluation, CandidatEvaluationAdmin)
+admin.site.register(MesCandidatEvaluation, MesCandidatEvaluationAdmin)
admin.site.register(Evaluateur, EvaluateurAdmin)
-#admin.site.register(AdministrateurRegional, AdministrateurRegionalAdmin)
admin.site.register(CourrielTemplate, CourrielTemplateAdmin)
+admin.site.register(OffreEmploiEvaluateur, OffreEmploiEvaluateurAdmin)