conflit réglé merge master et regionalisation
authorDavin Baragiotta <davin.baragiotta@auf.org>
Tue, 5 Jun 2012 21:46:46 +0000 (17:46 -0400)
committerDavin BARAGIOTTA <davin.baragiotta@auf.org>
Tue, 5 Jun 2012 21:46:46 +0000 (17:46 -0400)
1  2 
project/dae/admin.py
project/decorators.py
project/menu.py
project/recrutement/admin.py
project/rh/admin.py
project/rh/models.py
project/rh/templatetags/rapports.py
project/rh/views.py
project/settings.py
versions.cfg

diff --combined project/dae/admin.py
@@@ -1,24 -1,19 +1,26 @@@
  # -*- encoding: utf-8 -*-
  
- from auf.django.workflow.models import WorkflowCommentaire
  from django import forms
  from django.contrib import admin
  from reversion.admin import VersionAdmin
  
+ from auf.django.workflow.models import WorkflowCommentaire
  from project.dae.models import Poste, Dossier
  
  
  class BaseAdmin(admin.ModelAdmin):
  
      class Media:
 -        css = {'screen': ('css/admin_custom.css',)}
 +        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 PosteAdmin(BaseAdmin, VersionAdmin):
diff --combined project/decorators.py
@@@ -2,25 -2,17 +2,17 @@@
  """
  Décorateurs AUF
  """
- from django.contrib.auth.decorators import user_passes_test
- from django.core.urlresolvers import reverse
  from django.http import HttpResponseRedirect
- from permissions import is_employe, is_admin
  from django.conf import settings
+ from django.contrib import messages
  from django.contrib.auth import REDIRECT_FIELD_NAME
+ from django.contrib.auth.decorators import user_passes_test
+ from django.core.urlresolvers import reverse
  from django.utils.http import urlquote
- from django.contrib import messages
  
- # Décorateurs des fonctions dans views (pour tester permissions dans views)
-     
- def admin_required(fn):
-     def inner(request, *args, **kwargs):
-         user = request.user
-         if is_admin(user):
-             return fn(request, *args, **kwargs)
-         else :
-             return redirect_interdiction(request)
-     return inner
+ from project.groups import grp_drh, grp_drh2, grp_correspondants_rh
+ from project.groups import get_employe_from_user
  
  def redirect_interdiction(request, msg=u"Vous n'avez pas accès à cette page"):
      """
      tup = login_url, REDIRECT_FIELD_NAME, path
      messages.add_message(request, messages.ERROR, "Votre compte ne permet pas d'accéder à cette partie de l'application.")
      return HttpResponseRedirect('%s?%s=%s' % tup)
+     
+ def in_drh_or_admin(user):
+     """
+     Teste si un user Django fait parti du groupe DRH, DRH2 ou s'il est admin
+     """
+     groups = user.groups.all()
+     if user.is_superuser or \
+             grp_drh in groups or \
+             grp_drh2 in groups:
+         return True
+     else:
+         return False
+         
+ def drh_or_admin_required(fn):
+     """
+     Teste si un user Django fait parti du groupe DRH, DRH2 ou s'il est admin
+     """
+     def inner(request, *args, **kwargs):
+         user = request.user
+         if in_drh_or_admin(user):
+             return fn(request, *args, **kwargs)
  
+         msg = u"Votre compte ne permet pas d'accéder à " \
+                 u"cette partie de l'application."
+         return redirect_interdiction(request, msg)
  
+     return inner
+     
+ def region_protected(model):
+     def wrapper(func):
+         def wrapped(request, id):
+             if request.user.is_superuser:
+                 return func(request, id)
+             user_groups = request.user.groups.all()
+             if grp_drh in user_groups:
+                 return func(request, id)
+             if grp_correspondants_rh in user_groups:
+                 employe = get_employe_from_user(request.user)
+                 q = Q(**{
+                     model.prefix_implantation: employe.implantation.region
+                 })
+                 qs = model.objects.filter(q)
+                 if int(id) in [o.id for o in qs]:
+                     return func(request, id)
+             return redirect_interdiction(request)
+         return wrapped
+     return wrapper
++    
++def in_one_of_group(groups):
++    """
++    Test si le user appartient au moins 1 des ces groupes
++    """
++    def wrapper(fn):
++        def wrapped(request, *args, **kwargs):
++            user_groups = request.user.groups.all()
++            for g in user_groups:
++                if g in groups:
++                    return fn(request, *args, **kwargs)
++            msg = u"Votre compte ne permet pas d'accéder à cette partie de l'application."
++            return redirect_interdiction(request, msg)
++        return wrapped
++    return wrapper
diff --combined project/menu.py
@@@ -12,8 -12,8 +12,10 @@@ from django.core.urlresolvers import re
  from django.utils.translation import ugettext_lazy as _
  
  from admin_tools.menu import items, Menu
- from project.rh.decorators import in_drh_or_admin
- from project.rh import groups
+ from project.decorators import in_drh_or_admin
++from project import groups
++
  
  class CustomMenu(Menu):
      """
          Use this method if you need to access the request context.
          """
          request = context['request']
 -        if in_drh_or_admin(request.user):
 +        user_groups = request.user.groups.all()
 +        if in_drh_or_admin(request.user) or\
 +           groups.grp_correspondants_rh in user_groups or\
 +           groups.grp_administrateurs in user_groups or\
 +           groups.grp_directeurs_bureau in user_groups:
              self.children += [
                  items.MenuItem('Rapports',
                                 children=[
                          items.MenuItem('Organigramme par bureau', reverse('admin:rh_regionproxy_changelist')),
                          ]
                      ),
+                 items.MenuItem('Requêtes',
+                     children=[
+                         items.MenuItem('Requêtes sauvegardées', reverse('admin:django_qbe_savedquery_changelist')),
+                         items.MenuItem('Constructeur de requêtes', reverse('qbe_form')),
+                         ]
+                     ),
              ]
          super(CustomMenu, self).init_with_context(context)
          
@@@ -1,41 -1,43 +1,50 @@@
  # -*- encoding: utf-8 -*-
  
  import textwrap
- from django.core.urlresolvers import reverse
- from django.http import HttpResponseRedirect
+ from django.conf import settings
  from django.contrib import admin
- from django.forms.models import BaseInlineFormSet
+ from django.core.urlresolvers import reverse
  from django.db.models import Avg
- from django.conf import settings
+ from django.forms.models import BaseInlineFormSet
+ from django.http import HttpResponseRedirect
+ from django.shortcuts import redirect
  from reversion.admin import VersionAdmin
- from datamaster_modeles.models import Region, Bureau
- from project.rh import models as rh
  
- from project.dae.utils import get_employe_from_user as get_emp
- from recrutement.models import *
- from recrutement.workflow import grp_drh_recrutement, grp_drh2_recrutement, \
-         grp_directeurs_bureau_recrutement, \
-         grp_administrateurs_recrutement, \
-         grp_correspondants_rh_recrutement, \
-         grp_haute_direction_recrutement
+ from auf.django.emploi.models import OffreEmploi, Candidat, CandidatPiece
+ from auf.django.references.models import Region, Bureau
+ from project.groups import get_employe_from_user as get_emp
+ from project.rh import models as rh
  
- from recrutement.forms import *
+ from project.recrutement.forms import OffreEmploiForm
+ from project.recrutement.groups import \
+         grp_drh, grp_drh2, \
+         grp_directeurs_bureau, \
+         grp_administrateurs, \
+         grp_correspondants_rh, \
+         grp_haute_direction
+ from project.recrutement.models import \
+         Evaluateur, CandidatEvaluation, \
+         ProxyOffreEmploi, ProxyCandidat, MesCandidatEvaluation, \
+         CourrielTemplate
+         
  
  ### CONSTANTES
  IMPLANTATIONS_CENTRALES = [15, 19]
  
  class BaseAdmin(admin.ModelAdmin):
  
      class Media:
 -        css = {'screen': ('css/admin_custom.css',)}
 +        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):
          qs = qs.order_by('-moyenne')
          return qs
  
  class OffreEmploiAdmin(BaseAdmin, VersionAdmin):
      date_hierarchy = 'date_creation'
-     list_display = ('nom', 'date_limite', 'region',  'statut', 
-                     'est_affiche', '_candidatsList', )
+     list_display = (
+         'nom', 'date_limite', 'region',  'statut', 'est_affiche',
+         '_candidatsList'
+     )
      exclude = ('actif', 'poste_nom', 'resume',)
      list_filter = ('statut',)
      actions = ['affecter_evaluateurs_offre_emploi', ]
          return actions
  
      ### Affecter un évaluateurs à des offres d'emploi
-     def affecter_evaluateurs_offre_emploi(modeladmin, obj, candidats):   
+     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))
+         )
+     affecter_evaluateurs_offre_emploi.short_description = \
+             u'Affecter évaluateur(s)'
  
      ### Afficher la liste des candidats pour l'offre d'emploi
-     def _candidatsList(self, obj):     
+     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 
+     _candidatsList.allow_tags = True
      _candidatsList.short_description = "Afficher la liste des candidats"
  
      ### Formulaire
          form = super(OffreEmploiAdmin, self).get_form(request, obj, **kwargs)
          employe = get_emp(request.user)
          user_groupes = request.user.groups.all()
-         
-     
          # Region
-         if form.declared_fields.has_key('region'):
+         if 'region' in form.declared_fields:
              region_field = form.declared_fields['region']
          else:
              region_field = form.base_fields['region']
  
-         if grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+         if grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_haute_direction in user_groupes:
              region_field.queryset = Region.objects.all()
          else:
              region_field.queryset = Region.objects.\
                                      filter(id=employe.implantation.region.id)
-         
          # Poste
-         if form.declared_fields.has_key('poste'):
+         if 'poste' in form.declared_fields:
              poste_field = form.declared_fields['poste']
          else:
              poste_field = form.base_fields['poste']
  
-         if grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+         if grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_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
-         if form.declared_fields.has_key('bureau'):
+         if 'bureau' in form.declared_fields:
              bureau_field = form.declared_fields['bureau']
          else:
              bureau_field = form.base_fields['bureau']
  
-         if grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+         if grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_haute_direction in user_groupes:
              bureau_field.queryset = Bureau.objects.all()
          else:
-             bureau_field.queryset = Bureau.objects.\
-                                     filter(region=employe.implantation.region)   
-          
+             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')
+         qs = self.model._default_manager.get_query_set() \
+                 .select_related('offre_emploi')
          user_groupes = request.user.groups.all()
-         if grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+         if grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_haute_direction in user_groupes:
              return qs
  
-         if grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes:
+         if grp_directeurs_bureau in user_groupes or \
+             grp_correspondants_rh in user_groupes or \
+             grp_administrateurs in user_groupes:
              employe = get_emp(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)]
+             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()
      def has_add_permission(self, request):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return True
-         return False  
+         return False
  
      def has_delete_permission(self, request, obj=None):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return True
-         return False   
+         return False
  
      def has_change_permission(self, request, obj=None):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return True
-         return False   
+         return False
  
  class ProxyOffreEmploiAdmin(OffreEmploiAdmin):
-     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')
+     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': ('description', 'date_limite', )        
+             'fields': ('description', 'date_limite',)
          }),
          ('Coordonnées', {
              'fields': ('lieu_affectation', 'bureau', 'region', 'poste',)
          }),
          ('Autre', {
-             'fields': ('debut_affectation', 'duree_affectation',
-                         'renumeration', )
+             'fields': (
+                 'debut_affectation', 'duree_affectation', 'renumeration',
+             )
          }),
-     )        
+     )
      inlines = []
  
-     ### Lieu de redirection après le change 
+     ### Lieu de redirection après le change
      def response_change(self, request, obj):
-         return HttpResponseRedirect(reverse\
-                             ('admin:recrutement_proxyoffreemploi_changelist'))
+         return redirect('admin:recrutement_proxyoffreemploi_changelist')
  
      ### Formulaire
      def get_form(self, request, obj=None, **kwargs):
      def has_change_permission(self, request, obj=None):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_correspondants_rh in user_groupes or \
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return True
  
          if obj is not None:
  
          return False
  
  class CandidatPieceInline(admin.TabularInline):
      model = CandidatPiece
      fields = ('candidat', 'nom', 'path',)
      extra = 1
      max_num = 3
  
  class ReadOnlyCandidatPieceInline(CandidatPieceInline):
      readonly_fields = ('candidat', 'nom', 'path', )
      cand_delete = False
@@@ -260,7 -279,8 +286,8 @@@ class CandidatEvaluationInlineFormSet(B
      """
      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
      extra = 0
      formset = CandidatEvaluationInlineFormSet
  
-     ### Fields readonly    
+     ### 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(BaseAdmin, VersionAdmin):
-     search_fields = ('nom', 'prenom' )
+     search_fields = ('nom', 'prenom')
      exclude = ('actif', )
      list_editable = ('statut', )
      list_display = ('_candidat', 'offre_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'
+             )
+         }),
          ('Traitement', {
              'fields': ('statut', )
          }),
      actions = ['envoyer_courriel_candidats']
  
      def _candidat(self, obj):
-         txt = u"%s %s (%s)" % ( obj.nom.upper(), obj.prenom,
-                 obj.genre)
+         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"
          return actions
  
      ### Envoyer un courriel à des candidats
-     def envoyer_courriel_candidats(modeladmin, obj, 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
      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
          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'>Voir le candidat</a>" % \
-             (reverse('admin:recrutement_proxycandidat_change', args=(obj.id,)))
+         html = "<a href='%s'>Voir le candidat</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.allow_tags = True
      afficher_candidat.short_description = u'Détails du candidat'
  
      ### 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"
  
  
          notes = [evaluation.note for evaluation in evaluations \
                      if evaluation.note is not None]
-  
          if len(notes) > 0:
              moyenne_votes = round(float(sum(notes)) / len(notes), 2)
          else:
          totales = len(evaluations)
          faites = len(notes)
  
-         if obj.statut  == 'REC':
+         if obj.statut == 'REC':
              if totales == faites:
                  color = "green"
              elif faites > 0 and float(totales) / float(faites) >= 2:
          else:
              color = "black"
  
-         return """<span style="color: %s;">%s (%s/%s)</span>""" % (color, moyenne_votes, faites, totales)
+         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 = ""
      def has_add_permission(self, request):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_correspondants_rh in user_groupes or \
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return True
-         return False   
+         return False
  
      def has_delete_permission(self, request, obj=None):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_correspondants_rh in user_groupes or \
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return True
-         return False   
+         return False
  
      def has_change_permission(self, request, obj=None):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_correspondants_rh in user_groupes or \
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return True
          return False
  
  
      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().select_related('offre_emploi').annotate(moyenne=Avg('evaluations__note'))
+         qs = self.model._default_manager.get_query_set() \
+                 .select_related('offre_emploi') \
+                 .annotate(moyenne=Avg('evaluations__note'))
  
          user_groupes = request.user.groups.all()
-         if grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+         if grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_haute_direction in user_groupes:
              return qs
  
-         if grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes:
+         if grp_directeurs_bureau in user_groupes or \
+             grp_correspondants_rh in user_groupes or \
+             grp_administrateurs in user_groupes:
              employe = get_emp(request.user)
              return qs.filter(offre_emploi__region=employe.implantation.region)
  
              candidat_ids = [e.candidat.id for e in
                      CandidatEvaluation.objects.filter(evaluateur=evaluateur)]
              return qs.filter(id__in=candidat_ids)
-         return qs.none()    
+         return qs.none()
  
  
  class ProxyCandidatAdmin(CandidatAdmin):
      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',)
+     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 = (CandidatEvaluationInline, )
  
      def has_change_permission(self, request, obj=None):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_correspondants_rh in user_groupes or \
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return True
  
          if obj is not None:
      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(BaseAdmin, VersionAdmin):
      fieldsets = (
          ("Utilisateur", {
      def has_add_permission(self, request):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-                 grp_drh_recrutement in user_groupes or \
-                 grp_drh2_recrutement in user_groupes or \
-                 grp_haute_direction_recrutement in user_groupes:
+                 grp_drh in user_groupes or \
+                 grp_drh2 in user_groupes or \
+                 grp_haute_direction in user_groupes:
              return True
-         return False   
+         return False
  
      def has_delete_permission(self, request, obj=None):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-                 grp_drh_recrutement in user_groupes or \
-                 grp_drh2_recrutement in user_groupes or \
-                 grp_haute_direction_recrutement in user_groupes:
+                 grp_drh in user_groupes or \
+                 grp_drh2 in user_groupes or \
+                 grp_haute_direction in user_groupes:
              return True
-         return False   
+         return False
  
      def has_change_permission(self, request, obj=None):
          user_groupes = request.user.groups.all()
          if request.user.is_superuser is True or \
-                 grp_drh_recrutement in user_groupes or \
-                 grp_drh2_recrutement in user_groupes or \
-                 grp_haute_direction_recrutement in user_groupes:
+                 grp_drh in user_groupes or \
+                 grp_drh2 in user_groupes or \
+                 grp_haute_direction in user_groupes:
              return True
-         return False   
+         return False
  
  class CandidatEvaluationAdmin(BaseAdmin):
-     search_fields = ('candidat__nom', 'candidat__prenom' )
-     list_display = ('_candidat', '_statut', '_offre_emploi', 'evaluateur', '_note', 
-                     '_commentaire', )
+     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', )
          }),
      )
  
          """
          page = self.model.__name__.lower()
          redirect_url = 'admin:recrutement_%s_change' % page
-         
          if obj.note is None:
              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)
+             return "<a href='%s'>%s</a>" % (
+                 reverse(redirect_url,  args=(obj.id,)), label
+             )
          else:
              return label
      _note.allow_tags = True
-     _note.short_description = "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
              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
  
          user_groupes = request.user.groups.all()
  
          if request.user.is_superuser or \
-             grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+             grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_correspondants_rh in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              is_recrutement = True
          else:
              is_recrutement = False
  
      def queryset(self, request):
          """
-         Afficher uniquement les évaluations de l'évaluateur, sauf si 
+         Afficher uniquement les évaluations de l'évaluateur, sauf si
          l'utilisateur est dans les groupes suivants.
          """
-         qs = self.model._default_manager.get_query_set().select_related('offre_emploi')
+         qs = self.model._default_manager.get_query_set() \
+                 .select_related('offre_emploi')
          user_groupes = request.user.groups.all()
  
-         if grp_drh_recrutement in user_groupes or \
-             grp_drh2_recrutement in user_groupes or \
-             grp_correspondants_rh_recrutement in user_groupes or \
-             grp_directeurs_bureau_recrutement in user_groupes or \
-             grp_administrateurs_recrutement in user_groupes or \
-             grp_haute_direction_recrutement in user_groupes:
+         if grp_drh in user_groupes or \
+             grp_drh2 in user_groupes or \
+             grp_correspondants_rh in user_groupes or \
+             grp_directeurs_bureau in user_groupes or \
+             grp_administrateurs in user_groupes or \
+             grp_haute_direction in user_groupes:
              return qs
  
-         evaluateur = Evaluateur.objects.get(user=request.user) 
+         evaluateur = Evaluateur.objects.get(user=request.user)
          candidats_evaluations = \
              CandidatEvaluation.objects.filter(evaluateur=evaluateur,
                      candidat__statut__in=('REC', ))
@@@ -733,8 -779,9 +786,9 @@@ class MesCandidatEvaluationAdmin(Candid
              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) 
+         qs = self.model._default_manager.get_query_set() \
+                 .select_related('offre_emploi')
+         evaluateur = Evaluateur.objects.get(user=request.user)
          candidats_evaluations = \
              CandidatEvaluation.objects.filter(evaluateur=evaluateur,
                      candidat__statut__in=('REC', ))
diff --combined project/rh/admin.py
@@@ -1,38 -1,34 +1,41 @@@
  # -*- encoding: utf-8 -*-
  
  import datetime
- from ajax_select import make_ajax_form
- from auf.django.metadata.admin import \
-         AUFMetadataAdminMixin, AUFMetadataInlineAdminMixin, \
-         AUF_METADATA_READONLY_FIELDS
+         
  from django.core.urlresolvers import reverse
  from django.contrib import admin
  from django.conf import settings
  from django.db.models import Q, Count
  from django.template.defaultfilters import date
  
+ from ajax_select import make_ajax_form
+ from auf.django.metadata.admin import \
+         AUFMetadataAdminMixin, AUFMetadataInlineAdminMixin, \
+         AUF_METADATA_READONLY_FIELDS
  import auf.django.references.models as ref
- import models as rh
- from forms import \
++from project import groups
+ from project.decorators import in_drh_or_admin
 -from project.groups import grp_correspondants_rh
+ from project.groups import get_employe_from_user
+ import project.rh.models as rh
+ from project.rh.forms import \
          ContratForm, AyantDroitForm, EmployeAdminForm, AjaxSelect, DossierForm
- from dae.utils import get_employe_from_user
- from change_list import ChangeList
- from project.rh import groups
- from decorators import in_drh_or_admin
+ from project.rh.change_list import ChangeList
  
  
  class BaseAdmin(admin.ModelAdmin):
  
      class Media:
 -        css = {'screen': ('css/admin_custom.css',)}
 +        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 ArchiveMixin(object):
@@@ -56,7 -52,6 +59,7 @@@
  class RegionProxy(ref.Region):
      """ Proxy utilisé pour les organigrammes par région """
      class Meta:
 +        managed = False
          proxy = True
          verbose_name = u"Organigramme par région"
          verbose_name_plural = u"Organigramme par région"
@@@ -65,7 -60,6 +68,7 @@@
  class ImplantationProxy(ref.Implantation):
      """ Proxy utilisé pour les organigrammes par implantation """
      class Meta:
 +        managed = False
          proxy = True
          verbose_name = u"Organigramme par implantations"
          verbose_name_plural = u"Organigramme par implantations"
@@@ -75,7 -69,6 +78,7 @@@ class ServiceProxy(rh.Service)
      """ Proxy utilisé pour les organigrammes opar service """
  
      class Meta:
 +        managed = False
          proxy = True
          verbose_name = u"Organigramme par services"
          verbose_name_plural = u"Organigramme par services"
@@@ -84,7 -77,6 +87,7 @@@
  class EmployeProxy(rh.Employe):
      """ Proxy utilisé pour les organigrammes des employés """
      class Meta:
 +        managed = False
          proxy = True
          verbose_name = u"Organigramme des employés"
          verbose_name_plural = u"Organigramme des employés"
@@@ -128,9 -120,7 +131,9 @@@ class ProtectRegionMixin(object)
          if in_drh_or_admin(request.user):
              return qs
  
 -        if grp_correspondants_rh in user_groups:
 +        if groups.grp_correspondants_rh in user_groups or\
 +           groups.grp_administrateurs in user_groups or\
 +           groups.grp_directeurs_bureau in user_groups:
              employe = get_employe_from_user(request.user)
              q = Q(**{self.model.prefix_implantation: \
                      employe.implantation.region})
      def has_change_permission(self, request, obj=None):
          user_groups = request.user.groups.all()
  
 -        # Lock pour autoriser uniquement les DRH à utiliser RH
 -        if not in_drh_or_admin(request.user):
 -            return False
 -
          if len(user_groups) == 0 and not request.user.is_superuser:
              return False
  
@@@ -376,18 -370,6 +379,18 @@@ class DossierAdmin(DateRangeMixin, AUFM
          'remplacement_de': 'dossiers',
      }, superclass=DossierForm)
  
 +    def has_add_permission(self, request):
 +        user_groups = request.user.groups.all()
 +        if groups.grp_correspondants_rh in user_groups or \
 +           groups.grp_administrateurs in user_groups or \
 +           groups.grp_directeurs_bureau in user_groups or \
 +           in_drh_or_admin(request.user):
 +            return True
 +        return False
 +
 +    def has_delete_permission(self, request, obj=None):
 +        return in_drh_or_admin(request.user)
 +
      def lookup_allowed(self, key, value):
          if key in (
              'employe__nom__istartswith',
          apercu_link = u"""<a title="Aperçu du dossier"
                               onclick="return showAddAnotherPopup(this);"
                               href='%s'>
-                              <img src="%simg/loupe.png" />
+                              <img src="%simg/dossier-apercu.png" />
                               </a>""" % \
                  (reverse('dossier_apercu', args=(d.id,)),
                   settings.STATIC_URL,
      def _poste(self, dossier):
          link = u"""<a title="Aperçu du poste"
                        onclick="return showAddAnotherPopup(this);"
-                       href='%s'><img src="%simg/loupe.png" />
+                       href='%s'><img src="%simg/poste-apercu.png" />
                      </a>
                      <a href="%s" title="Modifier le poste">%s</a>""" % \
                  (reverse('poste_apercu', args=(dossier.poste.id,)),
          view = u"""<a href="%s"
                        title="Aperçu l'employé"
                        onclick="return showAddAnotherPopup(this);">
-                       <img src="%simg/loupe.png" />
+                       <img src="%simg/employe-apercu.png" />
                      </a>""" % (view_link, settings.STATIC_URL,)
          return u"""%s<a href='%s' style="%s;">%s</a>""" % \
          (view, edit_link, style, employe)
@@@ -557,23 -539,11 +560,23 @@@ class EmployeAdmin(DateRangeMixin, AUFM
              ),
          )
  
 +    def has_add_permission(self, request):
 +        user_groups = request.user.groups.all()
 +        if groups.grp_correspondants_rh in user_groups or \
 +           groups.grp_administrateurs in user_groups or \
 +           groups.grp_directeurs_bureau in user_groups or \
 +           in_drh_or_admin(request.user):
 +            return True
 +        return False
 +
 +    def has_delete_permission(self, request, obj=None):
 +        return in_drh_or_admin(request.user)
 +
      def _apercu(self, obj):
          return u"""<a title="Aperçu de l'employé"
                        onclick="return showAddAnotherPopup(this);"
                        href='%s'>
-                       <img src="%simg/loupe.png" />
+                       <img src="%simg/employe-apercu.png" />
                      </a>""" % \
              (reverse('employe_apercu', args=(obj.id,)), settings.STATIC_URL)
      _apercu.allow_tags = True
                               href="%s"
                               onclick="return showAddAnotherPopup(this);"
                               title="Aperçu du dossier">
-                              <img src="%simg/loupe.png" />
+                              <img src="%simg/dossier-apercu.png" />
                            </a>
                            <a href="%s">Dossier</a>
                            &nbsp;""" % \
                             href="%s"
                             onclick="return showAddAnotherPopup(this);"
                             title="Aperçu du poste">
-                            <img src="%simg/loupe.png" />
+                            <img src="%simg/poste-apercu.png" />
                          </a>
                          <a href="%s">Poste</a>
                          &nbsp;""" % \
@@@ -668,15 -638,6 +671,15 @@@ class EmployeProxyAdmin(EmployeAdmin)
      def has_add_permission(self, obj):
          return False
  
 +    def has_change_permission(self, request, obj=None):
 +        user_groups = request.user.groups.all()
 +        if groups.grp_correspondants_rh in user_groups or \
 +           groups.grp_administrateurs in user_groups or \
 +           groups.grp_directeurs_bureau in user_groups or \
 +           in_drh_or_admin(request.user):
 +            return True
 +        return False
 +
      def _organigramme(self, obj):
          l = []
          for d in rh.Dossier.objects.filter(
@@@ -840,18 -801,6 +843,18 @@@ class PosteAdmin(DateRangeMixin, AUFMet
                 PosteComparaisonInline,
                 PosteCommentaireInline, )
  
 +    def has_add_permission(self, request):
 +        user_groups = request.user.groups.all()
 +        if groups.grp_correspondants_rh in user_groups or \
 +           groups.grp_administrateurs in user_groups or \
 +           groups.grp_directeurs_bureau in user_groups or \
 +           in_drh_or_admin(request.user):
 +            return True
 +        return False
 +
 +    def has_delete_permission(self, request, obj=None):
 +        return in_drh_or_admin(request.user)
 +
      def lookup_allowed(self, key, value):
          return key in (
              'date_debut__gte', 'date_debut__isnull', 'date_fin__lte',
          view_link = u"""<a onclick="return showAddAnotherPopup(this);"
                             title="Aperçu du poste"
                             href='%s'>
-                         <img src="%simg/loupe.png" />
+                         <img src="%simg/poste-apercu.png" />
                          </a>""" % \
                  (reverse('poste_apercu', args=(poste.id,)),
                   settings.STATIC_URL,)
          try:
              responsable = u"""<a href="%s"
                                   onclick="return showAddAnotherPopup(this)">
-                                 <img src="%simg/loupe.png"
+                                 <img src="%simg/poste-apercu.png"
                                       title="Aperçu du poste" />
                                </a>
                                <a href="%s">%s</a>
              employe_html = u"""<br />
                      <a href="%s"
                         onclick="return showAddAnotherPopup(this)">
-                        <img src="%simg/loupe.png"
+                        <img src="%simg/employe-apercu.png"
                              title="Aperçu de l'employé">
                      </a>
                      <a href="%s">%s</a>""" % \
              l = []
              for e in employes:
                  link = u"""<a href='%s'
-                               title='Aperçu de l\'employer'
+                               title='Aperçu de l\'employé'
                                onclick='return showAddAnotherPopup(this)'>
-                               <img src='%simg/loupe.png' />
+                               <img src='%simg/employe-apercu.png' />
                              </a>
                              <a href='%s'>%s</a>""" % \
                       (reverse('employe_apercu', args=(e.id,)),
@@@ -1000,11 -949,21 +1003,21 @@@ class ResponsableInline(admin.TabularIn
  class ResponsableImplantationAdmin(BaseAdmin):
      actions = None
      list_filter = ('region', 'statut', )
-     list_display = ('nom', 'statut', '_responsable', )
+     list_display = ('_region', '_nom', 'statut', '_responsable', )
      readonly_fields = ('nom', )
      fields = ('nom', )
      inlines = (ResponsableInline, )
+     
+     def _region(self, obj):
+         return obj.region.code
+     _region.short_description = u"Région"
+     _region.admin_order_field = 'region__code'
+     
+     def _nom(self, obj):
+         return obj.nom
+     _nom.short_description = u"Implantation"
+     _nom.admin_order_field = 'nom'
+     
      def _responsable(self, obj):
          try:
              employe = obj.responsable.employe
@@@ -1071,13 -1030,7 +1084,13 @@@ class ServiceProxyAdmin(ServiceAdmin)
          return False
  
      def has_change_permission(self, request, obj=None):
 -        return in_drh_or_admin(request.user)
 +        user_groups = request.user.groups.all()
 +        if groups.grp_correspondants_rh in user_groups or \
 +           groups.grp_administrateurs in user_groups or \
 +           groups.grp_directeurs_bureau in user_groups or \
 +           in_drh_or_admin(request.user):
 +            return True
 +        return False
  
      def _organigramme(self, obj):
          return """<a href="%s"><strong>Organigramme</strong></a>""" % \
@@@ -1248,13 -1201,7 +1261,13 @@@ class ImplantationProxyAdmin(BaseAdmin)
          return False
  
      def has_change_permission(self, request, obj=None):
 -        return in_drh_or_admin(request.user)
 +        user_groups = request.user.groups.all()
 +        if groups.grp_correspondants_rh in user_groups or \
 +           groups.grp_administrateurs in user_groups or \
 +           groups.grp_directeurs_bureau in user_groups or \
 +           in_drh_or_admin(request.user):
 +            return True
 +        return False
  
      def _organigramme(self, obj):
          return '<a href="%s"><strong>Organigramme</strong></a>' % (
@@@ -1276,13 -1223,7 +1289,13 @@@ class RegionProxyAdmin(BaseAdmin)
          return False
  
      def has_change_permission(self, request, obj=None):
 -        return in_drh_or_admin(request.user)
 +        user_groups = request.user.groups.all()
 +        if groups.grp_correspondants_rh in user_groups or \
 +           groups.grp_administrateurs in user_groups or \
 +           groups.grp_directeurs_bureau in user_groups or \
 +           in_drh_or_admin(request.user):
 +            return True
 +        return False
  
      def _organigramme(self, obj):
          return """<a href="%s"><strong>Organigramme</strong></a>""" % (
diff --combined project/rh/models.py
@@@ -4,35 -4,25 +4,25 @@@ import datetim
  from datetime import date
  from decimal import Decimal
  
+ from django.core.files.storage import FileSystemStorage
+ from django.db import models
+ from django.db.models import Q
+ from django.conf import settings
  from auf.django.emploi.models import \
          GENRE_CHOICES, SITUATION_CHOICES  # devrait plutot être dans references
  from auf.django.metadata.models import AUFMetadata
  from auf.django.metadata.managers import NoDeleteManager
  from auf.django.references import models as ref
- from django.core.files.storage import FileSystemStorage
- from django.db import models
- from django.db.models import Q
- from django.conf import settings
  
- from change_list import \
+ from project.rh.change_list import \
          RechercheTemporelle, KEY_STATUT, STATUT_ACTIF, STATUT_INACTIF, \
          STATUT_FUTUR
- from managers import \
+ from project.rh.managers import \
          PosteManager, DossierManager, DossierComparaisonManager, \
          PosteComparaisonManager, DeviseManager, ServiceManager, \
          TypeRemunerationManager
- from validators import validate_date_passee
- # Gruick hack pour déterminer d'ou provient l'instanciation d'une classe
- # pour l'héritage.  Cela permet de faire du dynamic loading par app sans
- # avoir à redéfinir dans DAE la FK
- def app_context():
-     import inspect
-     models_stack = [s[1].split('/')[-2]
-                     for s in inspect.stack()
-                     if s[1].endswith('models.py')]
-     return models_stack[-1]
+ from project.rh.validators import validate_date_passee
  
  
  # Constantes
@@@ -362,10 -352,6 +352,6 @@@ class PosteFinancement_(models.Model)
      Pour un Poste, structure d'informations décrivant comment on prévoit
      financer ce Poste.
      """
-     poste = models.ForeignKey(
-         '%s.Poste' % app_context(), db_column='poste',
-         related_name='%(app_label)s_financements'
-     )
      type = models.CharField(max_length=1, choices=POSTE_FINANCEMENT_CHOICES)
      pourcentage = models.DecimalField(
          max_digits=12, decimal_places=2,
  
  
  class PosteFinancement(PosteFinancement_):
-     pass
+     poste = models.ForeignKey(
+         Poste, db_column='poste', related_name='rh_financements'
+     )
  
  
  class PostePiece_(models.Model):
      Documents relatifs au Poste.
      Ex.: Description de poste
      """
-     poste = models.ForeignKey(
-         '%s.Poste' % app_context(), db_column='poste',
-         related_name='%(app_label)s_pieces'
-     )
      nom = models.CharField(u"Nom", max_length=255)
      fichier = models.FileField(
          u"Fichier", upload_to=poste_piece_dispatch, storage=storage_prive
  
  
  class PostePiece(PostePiece_):
-     pass
+     poste = models.ForeignKey(
+         Poste, db_column='poste', related_name='rh_pieces'
+     )
  
  
  class PosteComparaison_(AUFMetadata, DevisableMixin):
      De la même manière qu'un dossier, un poste peut-être comparé à un autre
      poste.
      """
-     poste = models.ForeignKey(
-         '%s.Poste' % app_context(),
-         related_name='%(app_label)s_comparaisons_internes'
-     )
      objects = PosteComparaisonManager()
  
      implantation = models.ForeignKey(
  
  
  class PosteComparaison(PosteComparaison_):
+     poste = models.ForeignKey(
+         Poste, related_name='rh_comparaisons_internes'
+     )
      objects = NoDeleteManager()
  
  
- class PosteCommentaire_(Commentaire):
+ class PosteCommentaire(Commentaire):
      poste = models.ForeignKey(
-         '%s.Poste' % app_context(), db_column='poste', related_name='+'
+         Poste, db_column='poste', related_name='commentaires'
      )
  
-     class Meta:
-         abstract = True
- class PosteCommentaire(PosteCommentaire_):
-     pass
  
  
  ### EMPLOYÉ/PERSONNE
@@@ -976,15 -956,15 +956,15 @@@ class Dossier_(AUFMetadata, DevisableMi
  
  class Dossier(Dossier_):
      __doc__ = Dossier_.__doc__
-     poste = models.ForeignKey('%s.Poste' % app_context(),
-         db_column='poste',
-         related_name='%(app_label)s_dossiers',
+     poste = models.ForeignKey(
+         Poste, db_column='poste', related_name='rh_dossiers',
          help_text=u"Taper le nom du poste ou du type de poste",
-         )
+     )
      employe = models.ForeignKey(
          'Employe', db_column='employe',
          help_text=u"Taper le nom de l'employé",
-         related_name='%(app_label)s_dossiers', verbose_name=u"employé")
+         related_name='rh_dossiers', verbose_name=u"employé"
+     )
      principal = models.BooleanField(
          u"dossier principal", default=True,
          help_text=(
@@@ -998,10 -978,6 +978,6 @@@ class DossierPiece_(models.Model)
      Documents relatifs au Dossier (à l'occupation de ce poste par employé).
      Ex.: Lettre de motivation.
      """
-     dossier = models.ForeignKey(
-         '%s.Dossier' % app_context(),
-         db_column='dossier', related_name='%(app_label)s_dossierpieces'
-     )
      nom = models.CharField(max_length=255)
      fichier = models.FileField(
          upload_to=dossier_piece_dispatch, storage=storage_prive
  
  
  class DossierPiece(DossierPiece_):
-     pass
- class DossierCommentaire_(Commentaire):
      dossier = models.ForeignKey(
-         '%s.Dossier' % app_context(), db_column='dossier', related_name='+'
+         Dossier, db_column='dossier', related_name='rh_dossierpieces'
      )
  
-     class Meta:
-         abstract = True
  
  
- class DossierCommentaire(DossierCommentaire_):
-     pass
+ class DossierCommentaire(Commentaire):
+     dossier = models.ForeignKey(
+         Dossier, db_column='dossier', related_name='commentaires'
+     )
  
  
  class DossierComparaison_(models.Model, DevisableMixin):
      """
      Photo d'une comparaison salariale au moment de l'embauche.
      """
-     dossier = models.ForeignKey(
-         '%s.Dossier' % app_context(), related_name='%(app_label)s_comparaisons'
-     )
      objects = DossierComparaisonManager()
  
      implantation = models.ForeignKey(
  
  
  class DossierComparaison(DossierComparaison_):
-     pass
+     dossier = models.ForeignKey(
+         Dossier, related_name='rh_comparaisons'
+     )
  
  
  ### RÉMUNÉRATION
  
  class RemunerationMixin(AUFMetadata):
-     dossier = models.ForeignKey(
-         '%s.Dossier' % app_context(), db_column='dossier',
-         related_name='%(app_label)s_remunerations'
-     )
  
      # Identification
      type = models.ForeignKey(
@@@ -1131,7 -1098,9 +1098,9 @@@ class Remuneration_(RemunerationMixin, 
  
  
  class Remuneration(Remuneration_):
-     pass
+     dossier = models.ForeignKey(
+         Dossier, db_column='dossier', related_name='rh_remunerations'
+     )
  
  
  ### CONTRATS
@@@ -1149,10 -1118,6 +1118,6 @@@ class Contrat_(AUFMetadata)
      relation de travail) plusieurs contrats peuvent être associés.
      """
      objects = ContratManager()
-     dossier = models.ForeignKey(
-         '%s.Dossier' % app_context(), db_column='dossier',
-         related_name='%(app_label)s_contrats'
-     )
      type_contrat = models.ForeignKey(
          'TypeContrat', db_column='type_contrat',
          verbose_name=u'type de contrat', related_name='+'
  
  
  class Contrat(Contrat_):
-     pass
- ### ÉVÉNEMENTS
- #class Evenement_(AUFMetadata):
- #    """
- #    Un Evenement sert à déclarer une situation temporaire (exceptionnelle)
- #    d'un Dossier qui vient altérer des informations normales liées à un
- #    Dossier (ex.: la Remuneration).
- #
- #    Ex.: congé de maternité, maladie...
- #
- #    Lors de ces situations exceptionnelles, l'Employe a un régime de travail
- #    différent et une rémunération en conséquence. On souhaite toutefois
- #    conserver le Dossier intact afin d'éviter une re-saisie des données lors
- #    du retour à la normale.
- #    """
- #    dossier = models.ForeignKey(
- #        '%s.Dossier' % app_context(), db_column='dossier',
- #        related_name='+'
- #    )
- #    nom = models.CharField(max_length=255)
- #    date_debut = models.DateField(verbose_name = u"Date de début")
- #    date_fin = models.DateField(verbose_name = u"Date de fin",
- #                            null=True, blank=True)
- #
- #    class Meta:
- #        abstract = True
- #        ordering = ['nom']
- #        verbose_name = u"Évènement"
- #        verbose_name_plural = u"Évènements"
- #
- #    def __unicode__(self):
- #        return u'%s' % (self.nom)
- #
- #
- #class Evenement(Evenement_):
- #    __doc__ = Evenement_.__doc__
- #
- #
- #class EvenementRemuneration_(RemunerationMixin):
- #    """
- #    Structure de rémunération liée à un Evenement qui remplace
- #    temporairement la Remuneration normale d'un Dossier, pour toute la durée
- #    de l'Evenement.
- #    """
- #    evenement = models.ForeignKey("Evenement", db_column='evenement',
- #                            related_name='+',
- #                            verbose_name = u"Évènement")
- #    # TODO : le champ dossier hérité de Remuneration doit être dérivé
- #    # de l'Evenement associé
- #
- #    class Meta:
- #        abstract = True
- #        ordering = ['evenement', 'type__nom', '-date_fin']
- #        verbose_name = u"Évènement - rémunération"
- #        verbose_name_plural = u"Évènements - rémunérations"
- #
- #
- #class EvenementRemuneration(EvenementRemuneration_):
- #    __doc__ = EvenementRemuneration_.__doc__
- #
- #    class Meta:
- #        abstract = True
- #
- #
- #class EvenementRemuneration(EvenementRemuneration_):
- #    __doc__ = EvenementRemuneration_.__doc__
- # TODO? class ContratPiece(models.Model):
+     dossier = models.ForeignKey(
+         Dossier, db_column='dossier', related_name='rh_contrats'
+     )
  
  
  ### RÉFÉRENCES RH
@@@ -1612,7 -1511,6 +1511,7 @@@ class TypeContrat(AUFMetadata)
  class ResponsableImplantationProxy(ref.Implantation):
  
      class Meta:
 +        managed = False
          proxy = True
          verbose_name = u"Responsable d'implantation"
          verbose_name_plural = u"Responsables d'implantation"
@@@ -6,11 -6,10 +6,12 @@@ from django.utils.encoding import smart
  from django.template import Library
  from django.utils.http import urlencode
  
- from datamaster_modeles.models import Implantation, Region
- from rh.models import TypeContrat
- from project.rh import groups
- # pas de reference a DAE devrait etre refactorisé
- from dae.utils import get_employe_from_user
+ from auf.django.references.models import Implantation, Region
 -from project.rh.models import TypeContrat
++from project import groups
++from project.groups import get_employe_from_user
++from project.rh.models import TypeContrat
  
  register = Library()
  
@@@ -20,146 -19,204 +21,211 @@@ COMBLE_CHOICES = (('c', 'Comblé'), ('n
  
  @register.inclusion_tag('admin/filter.html', takes_context=True)
  def filter_comble(context):
-     return {'title': 'comblé',
-             'choices': prepare_choices(COMBLE_CHOICES, 'comble', context)}
+     return {
+         'title': 'comblé',
+         'choices': prepare_choices(COMBLE_CHOICES, 'comble', context)
+     }
  
  
  @register.inclusion_tag('admin/filter.html', takes_context=True)
  def filter_region(context, prefix=None):
      label = "".join([prefix or "", "implantation__region"])
-     return {'title': u"région",
-             'choices': prepare_choices(Region.objects.values_list('id', 'nom'), label, context, remove=['pays', 'nord_sud'])}
+     return {
+         'title': u"région",
+         'choices': prepare_choices(
+             Region.objects.values_list('id', 'nom'), label, context,
+             remove=['pays', 'nord_sud']
+         )
+     }
  
  
  @register.inclusion_tag('admin/filter.html', takes_context=True)
  def filter_implantation(context, prefix=None):
      label = "".join([prefix or "", "implantation"])
-     return {'title': u"implantation",
-             'choices': prepare_choices(Implantation.objects.values_list('id', 'nom'), label, context)}
+     return {
+         'title': u"implantation",
+         'choices': prepare_choices(
+             Implantation.objects.values_list('id', 'nom'), label, context
+         )
+     }
  
  
  @register.inclusion_tag('admin/filter.html', takes_context=True)
  def filter_region_contrat(context):
 -    return {
 -        'title': u"région",
 -        'choices': prepare_choices(
 -            Region.objects.values_list('id', 'nom'),
 -            'dossier__poste__implantation__region', context,
 -            remove=['pays', 'nord_sud']
 -        )
 -    }
 +    request = context['request']
 +    user_groups = request.user.groups.all()
 +    if groups.grp_correspondants_rh in user_groups or\
 +         groups.grp_administrateurs in user_groups or\
 +         groups.grp_directeurs_bureau in user_groups:
 +        employe = get_employe_from_user(request.user)
 +        regions = Region.objects.filter(id=employe.implantation.region.id)
 +    else:
 +       regions = Region.objects.all()
 +    return {'title': u"région",
 +            'choices': prepare_choices(regions.values_list('id', 'nom'), 'dossier__poste__implantation__region', context, remove=['pays', 'nord_sud'])}
  
  @register.inclusion_tag('admin/filter.html', takes_context=True)
  def filter_region_dossier(context):
-     return {'title': u"région",
-             'choices': prepare_choices(Region.objects.values_list('id', 'nom'), 'poste__implantation__region', context, remove=['pays', 'nord_sud'])}
+     return {
+         'title': u"région",
+         'choices': prepare_choices(
+             Region.objects.values_list('id', 'nom'),
+             'poste__implantation__region', context,
+             remove=['pays', 'nord_sud']
+         )
+     }
  
  @register.inclusion_tag('admin/filter.html', takes_context=True)
  def filter_implantation_dossier(context):
-     return {'title': u"implantation",
-             'choices': prepare_choices(Implantation.objects.values_list('id', 'nom'), 'poste__implantation', context)}
+     return {
+         'title': u"implantation",
+         'choices': prepare_choices(
+             Implantation.objects.values_list('id', 'nom'),
+             'poste__implantation', context
+         )
+     }
  
  
  @register.inclusion_tag('admin/filter.html', takes_context=True)
  def filter_implantation_contrat(context):
 -    return {
 -        'title': u"implantation",
 -        'choices': prepare_choices(
 -            Implantation.objects.values_list('id', 'nom'),
 -            'dossier__poste__implantation', context
 -        )
 -    }
 +    request = context['request']
 +    user_groups = request.user.groups.all()
 +    if groups.grp_correspondants_rh in user_groups or\
 +         groups.grp_administrateurs in user_groups or\
 +         groups.grp_directeurs_bureau in user_groups:
 +        employe = get_employe_from_user(request.user)
 +        implantations = Implantation.objects.filter(region=employe.implantation.region)
 +    else:
 +       implantations = Implantation.objects.all()
 +    return {'title': u"implantation",
 +            'choices': prepare_choices(implantations.values_list('id', 'nom'), 'dossier__poste__implantation', context)}
  
  
  @register.inclusion_tag('admin/filter.html', takes_context=True)
  def filter_type_contrat(context):
-     return {'title': u"type de contrat",
-             'choices': prepare_choices(TypeContrat.objects.values_list('id', 'nom'), 'type_contrat', context)}
+     return {
+         'title': u"type de contrat",
+         'choices': prepare_choices(
+             TypeContrat.objects.values_list('id', 'nom'), 'type_contrat',
+             context
+         )
+     }
  
  @register.inclusion_tag('admin/filter_select.html', takes_context=True)
  def filter_echeance_contrat(context):
      today = datetime.date.today()
-     three_months = today + datetime.timedelta(days=3*30)
-     six_months = today + datetime.timedelta(days=6*30)
-     twelve_months = today + datetime.timedelta(days=12*30)
+     three_months = today + datetime.timedelta(days=3 * 30)
+     six_months = today + datetime.timedelta(days=6 * 30)
+     twelve_months = today + datetime.timedelta(days=12 * 30)
  
      field_name = 'date_fin'
      return {'title': u"échéance",
              'choices': prepare_choices_date(field_name, context, links=(
                  ('Tous', {}),
-                 ('moins de 3 mois', {'%s__gte' % field_name: today.strftime('%Y-%m-%d'),
-                                     '%s__lte' % field_name: three_months.strftime('%Y-%m-%d')}),
-                 ('3 à 6 mois', {'%s__gte' % field_name: three_months.strftime('%Y-%m-%d'),
-                                 '%s__lte' % field_name: six_months.strftime('%Y-%m-%d')}),
-                 ('6 à 12 mois', {'%s__gte' % field_name: six_months.strftime('%Y-%m-%d'),
-                                 '%s__lte' % field_name: twelve_months.strftime('%Y-%m-%d')}),
+                 ('moins de 3 mois', {
+                     '%s__gte' % field_name: today.strftime('%Y-%m-%d'),
+                     '%s__lte' % field_name: three_months.strftime('%Y-%m-%d')
+                 }),
+                 ('3 à 6 mois', {
+                     '%s__gte' % field_name: three_months.strftime('%Y-%m-%d'),
+                     '%s__lte' % field_name: six_months.strftime('%Y-%m-%d')
+                 }),
+                 ('6 à 12 mois', {
+                     '%s__gte' % field_name: six_months.strftime('%Y-%m-%d'),
+                     '%s__lte' % field_name: twelve_months.strftime('%Y-%m-%d')
+                 }),
              )
      )}
  
  @register.inclusion_tag('admin/filter_select.html', takes_context=True)
  def filter_debut_contrat(context):
      year = datetime.date.today().timetuple()[0]
      this_year = datetime.date(year, 1, 1)
      next_year = datetime.date(year + 1, 1, 1)
-     last_year = datetime.date(year - 1, 12,31)
+     last_year = datetime.date(year - 1, 12, 31)
  
      field_name = 'date_debut'
      return {'title': u"date début",
              'choices': prepare_choices_date(field_name, context, links=(
                  ('Tous', {}),
-                 ('années à venir', {'%s__gte' % field_name: next_year.strftime('%Y-%m-%d')}),
-                 ('cette anneée', {'%s__gte' % field_name: this_year.strftime('%Y-%m-%d'),
-                                 '%s__lt' % field_name: next_year.strftime('%Y-%m-%d')}),
-                 ('années passées', {'%s__lte' % field_name: last_year.strftime('%Y-%m-%d')}),
+                 ('années à venir', {
+                     '%s__gte' % field_name: next_year.strftime('%Y-%m-%d')
+                 }),
+                 ('cette anneée', {
+                     '%s__gte' % field_name: this_year.strftime('%Y-%m-%d'),
+                     '%s__lt' % field_name: next_year.strftime('%Y-%m-%d')
+                 }),
+                 ('années passées', {
+                     '%s__lte' % field_name: last_year.strftime('%Y-%m-%d')
+                 }),
              )
      )}
  
  @register.inclusion_tag('admin/filter_select.html', takes_context=True)
  def filter_a_venir(context):
      today = datetime.date.today()
      year, month, day = datetime.date.today().timetuple()[:3]
-     mois_prochain  = datetime.date(year+((month+1)/13), (month+1)%12, 1)
-     this_month  = datetime.date(year, month, 1)
+     mois_prochain = datetime.date(
+         year + (month + 1) / 13, (month + 1) % 12, 1
+     )
+     this_month = datetime.date(year, month, 1)
  
      field_name = 'date_debut'
      return {'title': u"à venir",
              'choices': prepare_choices_date(field_name, context, links=(
                  ('Tous', {}),
-                 ('à venir', {'%s__gt' % field_name: today.strftime('%Y-%m-%d')}),
-                 ('à venir mois prochain', {'%s__gte' % field_name: mois_prochain.strftime('%Y-%m-%d')}),
-                 ('à venir ce mois', {'%s__gte' % field_name: this_month.strftime('%Y-%m-%d'),
-                                     '%s__lt' % field_name: mois_prochain.strftime('%Y-%m-%d')}),
+                 ('à venir', {
+                     '%s__gt' % field_name: today.strftime('%Y-%m-%d')
+                 }),
+                 ('à venir mois prochain', {
+                     '%s__gte' % field_name: mois_prochain.strftime('%Y-%m-%d')
+                 }),
+                 ('à venir ce mois', {
+                     '%s__gte' % field_name: this_month.strftime('%Y-%m-%d'),
+                     '%s__lt' % field_name: mois_prochain.strftime('%Y-%m-%d')
+                 }),
              )
      )}
  
  
  @register.inclusion_tag('admin/filter_select.html', takes_context=True)
  def filter_region_remun(context):
-     return {'title': u"région",
-             'choices': prepare_choices(Region.objects.values_list('id', 'nom'), 'dossiers__poste__implantation__region', context, remove=['pays', 'nord_sud'])}
+     return {
+         'title': u"région",
+         'choices': prepare_choices(
+             Region.objects.values_list('id', 'nom'),
+             'dossiers__poste__implantation__region', context,
+             remove=['pays', 'nord_sud']
+         )
+     }
  
  
  @register.inclusion_tag('admin/filter_select.html', takes_context=True)
  def filter_implantation_remun(context):
-     return {'title': u"implantation",
-             'choices': prepare_choices(Implantation.objects.values_list('id', 'nom'), 'dossiers__poste__implantation', context)}
+     return {
+         'title': u"implantation",
+         'choices': prepare_choices(
+             Implantation.objects.values_list('id', 'nom'),
+             'dossiers__poste__implantation', context
+         )
+     }
  
  @register.inclusion_tag('rh/rapports/table_header.html', takes_context=True)
  def table_header(context, headers):
      return {'headers': headers}
  
  def get_query_string(request, new_params=None, remove=None):
-     if new_params is None: new_params = {}
-     if remove is None: remove = []
+     if new_params is None:
+         new_params = {}
+     if remove is None:
+         remove = []
      p = dict(request.GET.items())
      for r in remove:
          for k in p.keys():
  def prepare_choices(choices, query_param, context, remove=[]):
      request = context['request']
      query_val = request.GET.get(query_param)
-     result = [{'selected': query_val is None,
-                'query_string': get_query_string(request, {}, [query_param] + remove),
-                'display': 'Tout'}]
+     result = [{
+         'selected': query_val is None,
+         'query_string': get_query_string(request, {}, [query_param] + remove),
+         'display': 'Tout'
+     }]
      for k, v in choices:
-         result.append({'selected': smart_unicode(k) == query_val,
-                        'query_string': get_query_string(request, {query_param: k}, remove),
-                        'display': v})
+         result.append({
+             'selected': smart_unicode(k) == query_val,
+             'query_string': get_query_string(
+                 request, {query_param: k}, remove
+             ),
+             'display': v
+         })
      return result
  
  
@@@ -191,19 -254,25 +263,25 @@@ def prepare_choices_date(field_name, co
      request = context['request']
      params = request.GET
      field_generic = '%s__' % field_name
-     date_params = dict([(k, v) for k, v in params.items() if k.startswith(field_generic)])
+     date_params = dict([
+         (k, v) for k, v in params.items() if k.startswith(field_generic)
+     ])
  
-     
      result = []
      for title, param_dict in links:
-         result.append({'selected': date_params == param_dict,
-                        'query_string': get_query_string(request, param_dict, [field_generic]),
-                        'display': title})
+         result.append({
+             'selected': date_params == param_dict,
+             'query_string': get_query_string(
+                 request, param_dict, [field_generic]
+             ),
+             'display': title
+         })
      return result
  
  class SortHeaders:
-     def __init__(self, request, headers, order_field_type, order_field, default_order_type="asc", not_sortable=[]):
+     def __init__(self, request, headers, order_field_type, order_field,
+                  default_order_type="asc", not_sortable=[]):
          self.request = request
          self.order_field_type = order_field_type
          self.order_field = order_field
          if default_order_type not in ('asc', 'desc'):
              raise AttributeError(u"L'ordre par défaut n'est pas valide")
          self.default_order_type = default_order_type
-         self.current_order_field = self.params[self.order_field][0] if self.order_field in self.params else None
-         self.current_order_field_type = self.params[self.order_field_type][0] if self.order_field_type in self.params else None
+         self.current_order_field = \
+                 self.params[self.order_field][0] \
+                 if self.order_field in self.params else None
+         self.current_order_field_type = self.params[self.order_field_type][0] \
+                 if self.order_field_type in self.params else None
          self.not_sortable = not_sortable
  
      def headers(self):
          for h in self.header_defs:
              params = self.params
              if h[0] == self.current_order_field:
-                 order_type = {'asc': 'desc', 'desc': 'asc'}[self.current_order_field_type]
+                 order_type = {
+                     'asc': 'desc', 'desc': 'asc'
+                 }[self.current_order_field_type]
                  class_order = "%sending" % self.current_order_field_type
              else:
                  order_type = self.default_order_type
                  class_order = ""
              params[self.order_field_type] = [order_type]
              params[self.order_field] = [h[0]]
-             url = "?%s" % "&".join(['%s=%s' % (param, value[0]) for param, value in params.items()])
+             url = "?%s" % "&".join([
+                 '%s=%s' % (param, value[0]) for param, value in params.items()
+             ])
              yield {
-                     "class_attr": "sorted %s" % class_order if self.field_sorted(h[0]) else "",
+                     "class_attr": (
+                         "sorted %s" % class_order
+                         if self.field_sorted(h[0]) else ""
+                     ),
                      "sortable": self.field_sorted(h[0]),
                      "url": url,
                      "text": h[1],
      def field_sorted(self, field):
          return True if field not in self.not_sortable else False
  
  @register.filter
  def split(str, splitter):
      return str.split(splitter)
  
  @register.filter
  def hash(h, key):
      if key in h:
      else:
          raise Exception("%s does not exist" % key)
  
  @register.filter
  def is_float(v):
      if type(v) == type(float()):
          return True
  
  @register.filter()
  def contains(value, arg):
-     return arg in value 
+     return arg in value
diff --combined project/rh/views.py
@@@ -6,49 -6,44 +6,46 @@@ from itertools import izi
  import StringIO
  
  import pygraphviz as pgv
- from datamaster_modeles import models as ref
- from django.core.urlresolvers import reverse
- from django.db.models import Q
- from django.utils.encoding import smart_str
- from django.shortcuts import render_to_response, get_object_or_404
- from django.template import RequestContext
- from django.http import HttpResponse
  from django import forms
+ from django.conf import settings
  from django.contrib.auth.decorators import login_required
  from django.core.servers.basehttp import FileWrapper
+ from django.core.urlresolvers import reverse
+ from django.db.models import Q
+ from django.http import HttpResponse
+ from django.shortcuts import render, get_object_or_404
  
- from rh import models as rh
- from rh.lib import calc_remun
- from project.rh.decorators import drh_or_admin_required, in_one_of_group
- from rh.templatetags.rapports import SortHeaders
- from rh.change_list import RechercheTemporelle
- from rh import graph as rh_graph
- from rh.masse_salariale import MasseSalariale
- # pas de reference a DAE devrait etre refactorisé
- from dae.utils import get_employe_from_user
- from dae.decorators import redirect_interdiction
- from django.conf import settings
- from project.rh.decorators import in_drh_or_admin
- from project.rh import groups
+ from auf.django.references import models as ref
++from project import groups
++from project.decorators import drh_or_admin_required, in_one_of_group
+ from project.decorators import redirect_interdiction
 -from project.decorators import drh_or_admin_required
+ from project.decorators import region_protected
+ from project.groups import get_employe_from_user
 -from project.groups import grp_drh, grp_correspondants_rh
+ from project.rh import models as rh
+ from project.rh import graph as rh_graph
+ from project.rh.change_list import RechercheTemporelle
+ from project.rh.lib import calc_remun, get_lookup_params
+ from project.rh.masse_salariale import MasseSalariale
+ from project.rh.templatetags.rapports import SortHeaders
  
  
  @login_required
 +@drh_or_admin_required
  def profil(request):
      """Profil personnel de l'employé - éditable"""
-     rc = RequestContext(request)
-     c = {}
-     employe = rc['this_employe']
-     c['user'] = request.user
-     c['employe'] = employe
-     return render_to_response('rh/profil.html', c, rc)
+     employe = get_employe_from_user(user)
+     c = {
+       'user': request.user,
+       'employe': employe,
+     }
+     return render(request, 'rh/profil.html', c)
  
  
  @login_required
 +@drh_or_admin_required
  def employes_liste(request):
      """Liste des employés."""
      today = date.today()
          'user': request.user,
          'employes': employes,
          }
-     return render_to_response('rh/employes_liste.html',
-             c,
-             RequestContext(request))
+     return render(request, 'rh/employes_liste.html', c)
  
  
  @login_required
 +@drh_or_admin_required
  def employe(request, id):
      """Information publique sur un employé."""
      try:
          'user': request.user,
          'employe': employe,
          }
-     return render_to_response('rh/employe.html', c, RequestContext(request))
- @login_required
- @drh_or_admin_required
- def rapports_poste(request):
-     lookup_params = dict(request.GET.items())
-     for key, value in lookup_params.items():
-         if key == 'o' or key == 'ot':
-             del lookup_params[key]
-             continue
-         if not isinstance(key, str):
-             # 'key' will be used as a keyword argument later, so Python
-             # requires it to be a string.
-             del lookup_params[key]
-             lookup_params[smart_str(key)] = value
-         if key == 'comble':
-             del lookup_params[key]
-     sort_order = 'ASC' if request.GET.get('ot') == 'asc' else 'DESC'
-     postes = rh.Poste.objects.select_related('implantation') \
-             .extra(select={
-                 'employe_id':
-                 'SELECT GROUP_CONCAT(employe SEPARATOR "|") '
-                 'FROM rh_dossier '
-                 'WHERE poste = rh_poste.id '
-                 'AND rh_dossier.date_fin IS NULL ' + (
-                     'ORDER BY employe ' + sort_order
-                     if request.GET.get('o') == 'employe_id' else ''
-                 )
-             }) \
-             .extra(select={
-                 'employe_nom':
-                 'SELECT GROUP_CONCAT(rh_employe.nom SEPARATOR "|") '
-                 'FROM rh_dossier INNER JOIN rh_employe '
-                 'ON rh_dossier.employe = rh_employe.id '
-                 'WHERE poste = rh_poste.id '
-                 'AND rh_dossier.date_fin IS NULL ' + (
-                     'ORDER BY rh_employe.nom ' + sort_order
-                     if request.GET.get('o') == 'employe_nom' else ''
-                 )
-             }) \
-             .extra(select={
-                 'employe_prenom':
-                 'SELECT GROUP_CONCAT(rh_employe.prenom SEPARATOR "|") '
-                 'FROM rh_dossier INNER JOIN rh_employe '
-                 'ON rh_dossier.employe = rh_employe.id '
-                 'WHERE poste = rh_poste.id '
-                 'AND rh_dossier.date_fin IS NULL ' + (
-                     'ORDER BY rh_employe.prenom ' + sort_order
-                     if request.GET.get('o') == 'employe_prenom' else ''
-                 )
-             })
-     postes = postes.filter(**lookup_params)
-     if 'o' in request.GET:
-         postes = postes.order_by(
-             ('-' if sort_order == "DESC" else '') + request.GET['o']
-         )
-     out = []
-     for p in postes:
-         out.append({
-             'id': p.id,
-             'nom': p.nom,
-             'implantation': p.implantation,
-             'employes': [] if not p.employe_id else [
-                 {'id': id, 'nom': nom, 'prenom': prenom}
-                 for id, nom, prenom in izip(
-                     p.employe_id.split('|'),
-                     p.employe_nom.split('|'),
-                     p.employe_prenom.split('|')
-                 )
-             ]
-         })
-     headers = [
-         ("id", u"# du poste"),
-         ("nom", u"Nom du poste"),
-         ("implantation__id", u"Implantation"),
-         ("employe_nom", u"Nom"),
-     ]
-     h = SortHeaders(request, headers, order_field_type="ot", order_field="o")
-     c = {
-         'title': 'Rapport des postes',
-         'postes': out,
-         'count': len(out),
-         'headers': list(h.headers()),
-     }
-     return render_to_response(
-         'rh/rapports/postes.html', c, RequestContext(request)
-     )
+     return render(request, 'rh/employe.html', c)
  
  
  @login_required
 -@drh_or_admin_required
 +@in_one_of_group((groups.grp_correspondants_rh,
 +    groups.grp_administrateurs,
 +    groups.grp_directeurs_bureau,
 +    groups.grp_drh,
 +    groups.grp_drh2))
  def rapports_contrat(request):
      if 'HTTP_REFERER' in request.META.keys():
          referer = request.META['HTTP_REFERER']
              params.update({'statut': 'Actif'})
              request.GET = params
  
-     lookup_params = dict(request.GET.items())
-     if 'ot' in lookup_params:
-         del lookup_params['ot']
-     if 'o' in lookup_params:
-         del lookup_params['o']
-     for key, value in lookup_params.items():
-         if not isinstance(key, str):
-             # 'key' will be used as a keyword argument later, so Python
-             # requires it to be a string.
-             del lookup_params[key]
-             lookup_params[smart_str(key)] = value
+     lookup_params = get_lookup_params(request)
  
      contrats = rh.Contrat.objects.select_related(
          'dossier', 'dossier__poste', 'dossier__poste__implantation',
      lookup_params = cl.purge_params(lookup_params)
      q_temporel = cl.get_q_temporel(contrats)
      q = Q(**lookup_params) & q_temporel
 +    user_groups = request.user.groups.all()
 +    if groups.grp_correspondants_rh in user_groups or\
 +       groups.grp_administrateurs in user_groups or\
 +       groups.grp_directeurs_bureau in user_groups:
 +        employe = get_employe_from_user(request.user)
 +        q = q & Q(dossier__poste__implantation__region=employe.implantation.region)
 +
      contrats = contrats.filter(q).exclude(dossier__employe__supprime=1)
  
      if 'o' in request.GET:
      headers = [
          ("dossier__employe__id", u"# de l'employé"),
          ("dossier__employe__nom", u"Employé"),
-         ("type_contrat__nom", u"Poste"),
+         ("dossier__poste__nom", u"Poste"),
          ("dossier__poste__implantation__region", u"Région"),
          ("dossier__poste__implantation", u"Implantation"),
          ("type_contrat__nom", u"Type de contrat"),
          'headers': list(h.headers()),
      }
  
-     return render_to_response(
-         'rh/rapports/contrats.html', c, RequestContext(request)
-     )
+     return render(request, 'rh/rapports/contrats.html', c)
  
  
  @login_required
 -@drh_or_admin_required
 +@in_one_of_group((groups.grp_correspondants_rh,
 +    groups.grp_administrateurs,
 +    groups.grp_directeurs_bureau,
 +    groups.grp_drh,
 +    groups.grp_drh2))
  def rapports_masse_salariale(request):
  
      class RechercheTemporelle(forms.Form):
 -        CHOICE_ANNEES = range(
 -            rh.Remuneration.objects.exclude(date_debut=None)
 -            .order_by('date_debut')[0].date_debut.year,
 -            date.today().year + 1
 -        )
 +        remunerations = rh.Remuneration.objects.exclude(date_debut=None)
 +        if len(remunerations) > 0:
 +            annee_debut = remunerations.order_by('date_debut')[0].date_debut.year
 +        else:
 +            annee_debut = 1982
 +        CHOICE_ANNEES = range(annee_debut, date.today().year + 1)
  
          annee = forms.CharField(
              initial=date.today().year,
              )
          )
  
 +        user_groups = request.user.groups.all()
 +        if groups.grp_correspondants_rh in user_groups or\
 +           groups.grp_administrateurs in user_groups or\
 +           groups.grp_directeurs_bureau in user_groups:
 +            employe = get_employe_from_user(request.user)
 +            regions = ref.Region.objects.filter(id=employe.implantation.region.id)
 +            implantations = ref.Implantation.objects.filter(region=employe.implantation.region)
 +        else:
 +            regions = ref.Region.objects.all()
 +            implantations = ref.Implantation.objects.all()
 +
          region = forms.CharField(
                  widget=forms.Select(choices=[('', '')] +
 -                    [(i.id, i) for i in ref.Region.objects.all()]
 +                    [(i.id, i) for i in regions]
                  )
              )
  
          implantation = forms.CharField(
                  widget=forms.Select(choices=[('', '')] +
 -                    [(i.id, i) for i in ref.Implantation.objects.all()]
 +                    [(i.id, i) for i in implantations]
                  )
              )
  
      if region:
          custom_filter['dossier__poste__implantation__region'] = region
  
 +    # on force la région dans tous les cas pour les membres de ce groupe
 +    user_groups = request.user.groups.all()
 +    if groups.grp_correspondants_rh in user_groups or\
 +       groups.grp_administrateurs in user_groups or\
 +       groups.grp_directeurs_bureau in user_groups:
 +        employe = get_employe_from_user(request.user)
 +        custom_filter['dossier__poste__implantation__region'] = employe.implantation.region.id
 +
 +
      c = {
              'title': 'Rapport de masse salariale',
              'form': form,
                  c['url_ods'] = "%s?%s" % (
                          reverse('rhr_masse_salariale'), query_string)
  
-     return render_to_response(
-         'rh/rapports/masse_salariale.html', c, RequestContext(request)
-     )
- @login_required
- @drh_or_admin_required
- def rapports_remuneration(request):
-     lookup_params = dict(request.GET.items())
-     if 'ot' in lookup_params:
-         del lookup_params['ot']
-     if 'o' in lookup_params:
-         del lookup_params['o']
-     for key, value in lookup_params.items():
-         if not isinstance(key, str):
-             # 'key' will be used as a keyword argument later, so Python
-             # requires it to be a string.
-             del lookup_params[key]
-             lookup_params[smart_str(key)] = value
-     employes = rh.Employe.objects.all()
-     if 'o' in request.GET:
-         employes = employes.order_by(
-             ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
-         )
-     employes = employes.filter(**lookup_params)
-     output = []
-     headers = [
-             ("id", u"# de l'employé"),
-             ("nom", u"Nom"),
-             ("prenom", u"Prénom"),
-             ("", u"Salaire"),
-             ("", u"RAS"),
-             ("", u"Indemnités"),
-             ("", u"Accessoire"),
-             ("", u"Charges patronales"),
-             ("", u"Total"),
-     ]
-     h = SortHeaders(request, headers, order_field_type="ot", order_field="o")
-     for employe in employes:
-         line = {}
-         output.append(line)
-         dossiers = employe.rh_dossiers.all()
-         remun = {}
-         remun_sum_euro = 0
-         for dossier in dossiers:
-             this_remun, this_remun_sum, this_remun_sum_euro = \
-                     calc_remun(dossier)
-             for item in this_remun:
-                 if item not in remun:
-                     remun[item] = this_remun[item]
-                 else:
-                     remun[item][0] += this_remun[item][0]
-                     remun[item][1] += this_remun[item][1]
-             remun_sum_euro += this_remun_sum_euro
-         line['remun_sum_euro'] = remun_sum_euro
-         for r in remun:
-             if r == u'Indemnité':
-                 line['Indemnite'] = remun[r][1]
-             else:
-                 line[r] = remun[r][1]
-         line['id'] = employe.id
-         line['nom'] = employe.nom
-         line['prenom'] = employe.prenom
-     c = {
-         'title': 'Rapport de remuneration',
-         'employes': output,
-         'headers': list(h.headers()),
-     }
-     return render_to_response(
-         'rh/rapports/remuneration.html', c, RequestContext(request)
-     )
+     return render(request, 'rh/rapports/masse_salariale.html', c)
  
  
  @login_required
 -@drh_or_admin_required
 +@in_one_of_group((groups.grp_correspondants_rh,
 +    groups.grp_administrateurs,
 +    groups.grp_directeurs_bureau,
 +    groups.grp_drh,
 +    groups.grp_drh2))
- def rapports_employe_sans_contrat(request):
-     lookup_params = dict(request.GET.items())
-     if 'ot' in lookup_params:
-         del lookup_params['ot']
-     if 'o' in lookup_params:
-         del lookup_params['o']
-     for key, value in lookup_params.items():
-         if not isinstance(key, str):
-             # 'key' will be used as a keyword argument later, so Python
-             # requires it to be a string.
-             del lookup_params[key]
-             lookup_params[smart_str(key)] = value
-     employes_query = rh.Employe.objects
-     if 'o' in request.GET:
-         employes_query = employes_query.order_by(
-             ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
-         )
-     employes = {}
+ def rapports_employes_sans_contrat(request):
+     lookup_params = get_lookup_params(request)
  
++    # régionalisation
 +    user_groups = request.user.groups.all()
 +    q_region = Q()
 +    if groups.grp_correspondants_rh in user_groups or\
 +       groups.grp_administrateurs in user_groups or\
 +       groups.grp_directeurs_bureau in user_groups:
 +        employe = get_employe_from_user(request.user)
 +        q_region = Q(poste__implantation__region=employe.implantation.region)
 +
-     dossiers_en_cours = rh.Dossier.objects.filter(q_region & (
-         Q(date_fin=None) | Q(date_fin__gt=date.today()))
-     )
-     tous_contrats_echus = rh.Contrat.objects.filter(
-         date_fin__lt=date.today(), dossier__in=dossiers_en_cours
-     )
-     contrats = tous_contrats_echus.filter(**lookup_params).all()
-     for c in contrats:
-         if c.dossier.employe.id not in employes.keys():
-             employes[c.dossier.employe.id] = {
-                 'employe': c.dossier.employe,
-                 'dossiers': []
-             }
-         employes[c.dossier.employe.id]['dossiers'] += [c.dossier]
+     # contrats échus
+     contrats_echus = rh.Contrat.objects.filter(
+             date_fin__lt=date.today()
+         ).filter(
+             **lookup_params
+         )
+     # dossiers en cours sans contrat
 -    dossiers_sans_contrat = rh.Dossier.objects.filter(
 -            Q(date_fin=None) | Q(date_fin__gt=date.today()),
++    dossiers_sans_contrat = rh.Dossier.objects.filter(q_region & (
++            Q(date_fin=None) | Q(date_fin__gt=date.today())),
+         ).exclude(
+             date_debut__gt=date.today()
+         ).filter(
+             rh_contrats__in=contrats_echus
+         )
+     
+     # employés sans contrat
+     employes = rh.Employe.objects.filter(rh_dossiers__in=dossiers_sans_contrat).distinct()
+     if 'o' in request.GET:
+         employes = employes.order_by(
+             ('-' if request.GET.get('ot') == "desc" else '') + request.GET['o']
+         )
  
+     # affichage
      headers = [
          ("id", u"# de l'employé"),
-         ("nom", u"Nom"),
-         ("prenom", u"Prénom"),
-         ("dossier", u"Dossiers"),
+         ("nom", u"Employé"),
+         ("dossier", u"Dossier : Poste"),
+         ("dossier_date_debut", u"Début occupation poste"),
+         ("dossier_date_fin", u"Fin occupation poste"),
      ]
      h = SortHeaders(
          request, headers, order_field_type="ot", order_field="o",
-         not_sortable=('dossier',)
+         not_sortable=('dossier','dossier_date_debut','dossier_date_fin',)
      )
  
      c = {
          'title': u'Rapport des employés sans contrat',
          'employes': employes,
-         'count': len(employes),
+         'dossiers_sans_contrat':dossiers_sans_contrat,
          'headers': list(h.headers()),
      }
  
-     return render_to_response(
-         'rh/rapports/employes_sans_contrat.html', c, RequestContext(request)
-     )
+     return render(request, 'rh/rapports/employes_sans_contrat.html', c)
  
  
  @login_required
@@@ -577,9 -314,7 +366,7 @@@ def rapports_postes_modelisation(reques
  
      c['data'] = data
  
-     return render_to_response(
-         'rh/rapports/postes_modelisation.html', c, RequestContext(request)
-     )
+     return render(request, 'rh/rapports/postes_modelisation.html', c)
  
  
  @login_required
@@@ -602,9 -337,7 +389,7 @@@ def rapports_postes_implantation(reques
  
      c['data'] = data
  
-     return render_to_response(
-         'rh/rapports/postes_implantation.html', c, RequestContext(request)
-     )
+     return render(request, 'rh/rapports/postes_implantation.html', c)
  
  
  @login_required
@@@ -618,33 -351,7 +403,7 @@@ def rapports_postes_service(request)
          data.append({'service': s, 'num_postes': num_postes, 'postes': postes})
  
      c['data'] = data
-     return render_to_response(
-         'rh/rapports/postes_service.html', c, RequestContext(request)
-     )
- def region_protected(model):
-     def wrapper(func):
-         def wrapped(request, id):
-             if request.user.is_superuser:
-                 return func(request, id)
-             user_groups = request.user.groups.all()
-             if in_drh_or_admin(request.user):
-                 return func(request, id)
-             if groups.grp_correspondants_rh in user_groups or\
-                groups.grp_administrateurs in user_groups or\
-                groups.grp_directeurs_bureau in user_groups:
-                 employe = get_employe_from_user(request.user)
-                 q = Q(**{
-                     model.prefix_implantation: employe.implantation.region
-                 })
-                 qs = model.objects.filter(q)
-                 if int(id) in [o.id for o in qs]:
-                     return func(request, id)
-             return redirect_interdiction(request)
-         return wrapped
-     return wrapper
+     return render(request, 'rh/rapports/postes_service.html', c)
  
  @region_protected(rh.Dossier)
  def dossier_apercu(request, dossier_id):
          'commentaires': rh.DossierCommentaire.objects.filter(dossier=d).all(),
          'media_url': settings.PRIVE_MEDIA_URL,
      }
-     return render_to_response(
-         'admin/rh/dossier/apercu.html', c, RequestContext(request)
-     )
+     return render(request, 'admin/rh/dossier/apercu.html', c)
  
  
  @region_protected(rh.Poste)
@@@ -686,25 -391,23 +443,23 @@@ def poste_apercu(request, poste_id)
          ),
          'media_url': settings.PRIVE_MEDIA_URL,
      }
-     return render_to_response(
-         'admin/rh/poste/apercu.html', c, RequestContext(request)
-     )
+     return render(request, 'admin/rh/poste/apercu.html', c)
  
 -
 +@region_protected(rh.Employe)
  def employe_apercu(request, employe_id):
      employe = get_object_or_404(rh.Employe, pk=employe_id)
      user_groups = request.user.groups.all()
      dossiers = None
  
 -    if request.user.is_superuser or \
 -       grp_drh in user_groups:
 +    if in_drh_or_admin(request.user):
          q = Q(employe=employe)
 -    if grp_correspondants_rh in user_groups:
 -        regions = [
 -            d.poste.implantation.region for d in employe.rh_dossiers.all()
 -        ]
 -        q = Q(employe=employe) & Q(implantation__region__in=regions)
  
 +    if groups.grp_correspondants_rh in user_groups or\
 +       groups.grp_administrateurs in user_groups or\
 +       groups.grp_directeurs_bureau in user_groups:
 +        employe_connecte = get_employe_from_user(request.user)
 +        q = Q(employe=employe) & Q(poste__implantation__region=employe_connecte.implantation.region)
 +    
      dossiers = rh.Dossier.objects.filter(q).order_by('-date_debut')
  
      c = {
          'dossiers': dossiers,
          'media_url': settings.PRIVE_MEDIA_URL,
      }
-     return render_to_response(
-         'admin/rh/employe/apercu.html', c, RequestContext(request)
-     )
+     return render(request, 'admin/rh/employe/apercu.html', c)
  
  
  @login_required
 -@drh_or_admin_required
 +@in_one_of_group((groups.grp_correspondants_rh,
 +    groups.grp_administrateurs,
 +    groups.grp_directeurs_bureau,
 +    groups.grp_drh,
 +    groups.grp_drh2))
  def organigrammes_employe(request, id, level="all"):
  
      poste = get_object_or_404(rh.Poste, pk=id)
      }
  
      if 'forcer' in request.GET:
-         response = HttpResponse(svg, mimetype='image/svg+xml')
+         response = HttpResponse(svg, content_type='image/svg+xml')
          response['Content-Disposition'] = \
                  'attachment; filename=organigramme.svg'
          return response
  
-     return render_to_response(
-         'rh/organigrammes/employe.html', c, RequestContext(request),
-         mimetype="image/svg+xml"
+     return render(request, 'rh/organigrammes/employe.html', c,
+         content_type="image/svg+xml"
      )
  
  
  @login_required
 -@drh_or_admin_required
 +@in_one_of_group((groups.grp_correspondants_rh,
 +    groups.grp_administrateurs,
 +    groups.grp_directeurs_bureau,
 +    groups.grp_drh,
 +    groups.grp_drh2))
  def organigrammes_service(request, id):
  
      service = get_object_or_404(rh.Service, pk=id)
          'svg': svg
      }
  
-     return render_to_response(
-         'rh/organigrammes/vide.html', c, RequestContext(request),
-         mimetype="image/svg+xml"
+     return render(request, 'rh/organigrammes/vide.html', c, 
+         content_type="image/svg+xml"
      )
  
  
  @login_required
 -@drh_or_admin_required
 +@in_one_of_group((groups.grp_correspondants_rh,
 +    groups.grp_administrateurs,
 +    groups.grp_directeurs_bureau,
 +    groups.grp_drh,
 +    groups.grp_drh2))
  def organigrammes_implantation(request, id):
  
      implantation = get_object_or_404(ref.Implantation, pk=id)
          'svg': svg
      }
  
-     return render_to_response(
-         'rh/organigrammes/vide.html', c, RequestContext(request),
-         mimetype="image/svg+xml"
+     return render(request, 'rh/organigrammes/vide.html', c, 
+         content_type="image/svg+xml"
      )
  
  
  @login_required
 -@drh_or_admin_required
 +@in_one_of_group((groups.grp_correspondants_rh,
 +    groups.grp_administrateurs,
 +    groups.grp_directeurs_bureau,
 +    groups.grp_drh,
 +    groups.grp_drh2))
  def organigrammes_region(request, id):
  
      region = get_object_or_404(ref.Region, pk=id)
          'svg': svg
      }
  
-     return render_to_response(
-         'rh/organigrammes/vide.html', c, RequestContext(request),
-         mimetype="image/svg+xml"
+     return render(request, 
+         'rh/organigrammes/vide.html', c, 
+         content_type="image/svg+xml"
      )
diff --combined project/settings.py
@@@ -2,7 -2,8 +2,8 @@@
  
  import os
  import socket
- from conf import *
+ from project.conf import *  # NOQA
  PROJET_TITRE = "Ressources humaines"
  
  # Rapports d'erreurs
@@@ -17,8 -18,8 +18,8 @@@ MANAGERS = ADMIN
  TIME_ZONE = 'America/Montreal'
  DATE_FORMAT = 'd-m-Y'
  DATE_INPUT_FORMATS = (
-     '%d-%m-%Y', '%d/%m/%Y', '%d %m %Y', 
-     '%d-%m-%y', '%d/%m/%y', '%d %m %y', 
+     '%d-%m-%Y', '%d/%m/%Y', '%d %m %Y',
+     '%d-%m-%y', '%d/%m/%y', '%d %m %y',
  )
  
  SESSION_SAVE_EVERY_REQUEST = True
@@@ -69,6 -70,11 +70,11 @@@ ROOT_URLCONF = 'project.urls
  INSTALLED_APPS = (
      'auf.django.skin',
      'auf.django.references',
+     'auf.django.emploi',
+     'auf.django.admingroup',
+     'auf.django.workflow',
+     'auf.django.permissions',
+     'auf.django.emploi',
      'admin_tools',
      'admin_tools.theming',
      'admin_tools.menu',
      'django.contrib.admin',
      'django.contrib.staticfiles',
      'django_qbe',
      'ajax_select',
      'south',
      'reversion',
-     'auf.django.workflow',
-     'auf.django.permissions',
-     #'project.rh_v1',
-     'project.rh',
-     'project.dae',
-     'project.legacy',
      'alphafilter',
      'form_utils',
      'tinymce',
      'captcha',
+     'project.rh',
+     'project.dae',
+     'project.recrutement',
  )
  
  TEMPLATE_CONTEXT_PROCESSORS = (
      'django.contrib.messages.context_processors.messages',
      'django.core.context_processors.request',
      'auf.django.skin.context_processors.auf',
-     'project.context_processors.this_employe',
-     'project.context_processors.user_is_admin',
      'project.dae.context_processors.user_in_dae_groupes',
-     'project.recrutement.context_processors.user_in_recrutement_groupes',
  )
  
  AUTHENTICATION_BACKENDS = (
@@@ -130,49 -127,72 +127,73 @@@ ADMIN_TOOLS_APP_INDEX_DASHBOARD = 'proj
  ADMIN_TOOLS_MENU = 'project.menu.CustomMenu'
  
  AJAX_LOOKUP_CHANNELS = {
-     'responsables' : ('dae.catalogues', 'Responsable'),
-     'dossiers' : ('dae.catalogues', 'Dossier'),
-     'dae_postes' : ('dae.catalogues', 'Poste'),
-     'pays' : ('rh.catalogues', 'Pays'),
-     'implantations' : ('rh.catalogues', 'Implantation'),
-     'typepostes' : ('rh.catalogues', 'TypePoste'),
-     'postes' : ('rh.catalogues', 'Poste'),
-     'valeurpoints' : ('rh.catalogues', 'ValeurPoint'),
-     'employes' : ('rh.catalogues', 'Employe'),
-     'dossiers' : ('rh.catalogues', 'Dossier'),
+     'responsables': ('project.dae.catalogues', 'Responsable'),
+     'dossiers': ('project.dae.catalogues', 'Dossier'),
+     'dae_postes': ('project.dae.catalogues', 'Poste'),
+     'pays': ('project.rh.catalogues', 'Pays'),
+     'implantations': ('project.rh.catalogues', 'Implantation'),
+     'typepostes': ('project.rh.catalogues', 'TypePoste'),
+     'postes': ('project.rh.catalogues', 'Poste'),
+     'valeurpoints': ('project.rh.catalogues', 'ValeurPoint'),
+     'employes': ('project.rh.catalogues', 'Employe'),
+     'dossiers': ('project.rh.catalogues', 'Dossier'),
  }
 -AJAX_SELECT_BOOTSTRAP = True
  AJAX_SELECT_INLINES = 'inline'
  
  
  TINYMCE_DEFAULT_CONFIG = {
- 'theme': "advanced",
- 'plugins':"paste",
- 'theme_advanced_buttons1' : "bold,italic,underline,|,formatselect,|,bullist,numlist,|,undo,redo,|,link,unlink",
- 'theme_advanced_buttons2' : "",
- 'theme_advanced_buttons3' : "",
- 'theme_advanced_statusbar_location' : "bottom",
- 'theme_advanced_toolbar_align' : "left",
- 'theme_advanced_styles' : "Titre=titre;Sous-titre=sous-titre;Normal=normal",
- 'width' : "800",
- 'height' : "200",
- 'theme_advanced_resizing' : "true",
- 'custom_undo_redo_levels': 10,
- 'theme_advanced_toolbar_location' : 'top',
- 'inline_styles' : 'false',
- 'paste_use_dialog' : 'false',
- 'paste_auto_cleanup_on_paste' : 'true',
- 'paste_convert_headers_to_strong' : 'false',
- 'paste_strip_class_attributes' : 'all',
- 'paste_remove_spans' : 'true',
- 'paste_remove_styles' : 'true',
- 'content_css' : '/media/css/tinymce.css',
+     'theme': "advanced",
+     'plugins': "paste",
+     'theme_advanced_buttons1': (
+         "bold,italic,underline,|,formatselect,|,bullist,numlist,|,undo,redo,|,"
+         "link,unlink"
+     ),
+     'theme_advanced_buttons2': "",
+     'theme_advanced_buttons3': "",
+     'theme_advanced_statusbar_location': "bottom",
+     'theme_advanced_toolbar_align': "left",
+     'theme_advanced_styles': "Titre=titre;Sous-titre=sous-titre;Normal=normal",
+     'width': "800",
+     'height': "200",
+     'theme_advanced_resizing': "true",
+     'custom_undo_redo_levels': 10,
+     'theme_advanced_toolbar_location': 'top',
+     'inline_styles': 'false',
+     'paste_use_dialog': 'false',
+     'paste_auto_cleanup_on_paste': 'true',
+     'paste_convert_headers_to_strong': 'false',
+     'paste_strip_class_attributes': 'all',
+     'paste_remove_spans': 'true',
+     'paste_remove_styles': 'true',
+     'content_css': '/media/css/tinymce.css',
  }
  
  # django-sendfile
  SENDFILE_BACKEND = 'sendfile.backends.simple'
  
+ QBE_DISPLAY_DATABASES = False
+ # Il est *très* important de respecter la case.
+ QBE_CUSTOM_MODELS = {'Rh': {
+     'Employe': {},
+     'Poste': {},
+     'Dossier': {},
+     'Remuneration': {},
+     'Contrat': {},
+ }}
+ QBE_ALLOWED_FIELDS = {'Rh': {
+     'Employe': [
+         'nom', 'prenom', 'genre', 'date_naissance', 'situation_familiale',
+         'date_entree'
+     ],
+     'Poste': ['nom', 'date_debut', 'date_fin'],
+     'Dossier': [
+         'statut_residence', 'regime_travail',
+         'regime_travail_nb_heure_semaine', 'date_debut', 'date_fin'
+     ],
+     'Remuneration': ['montant', 'date_debut', 'date_fin'],
+     'Contrat': ['date_debut', 'date_fin'],
+ }}
++
 +SOUTH_TESTS_MIGRATE = False
diff --combined versions.cfg
@@@ -4,6 -4,7 +4,7 @@@ south = 0.
  django-admin-tools = 0.4.1
  django-ajax-selects = 1.1.4
  django-alphafilter = 0.5.3auf4
+ django-picklefield = 0.2.1
  django-reversion = 1.3.3
  django-sendfile = 0.2.1
  django-urldecorators = 0.3
@@@ -11,9 -12,9 +12,9 @@@ auf.django.auth = 0.5.5de
  auf.django.emploi = 1.0dev
  auf.django.metadata = 0.6dev
  auf.django.permissions = 0.1
 -auf.django.references = 0.11
++auf.django.references = 0.17
  auf.django.skin = 1.5
  auf.django.workflow = 0.15dev
- auf.django.references = 0.17
  odfpy = 0.9.4
  pygraphviz = 0.36
  
@@@ -53,3 -54,9 +54,9 @@@ simplejson = 2.5.
  # Required by:
  # auf.django.emploi==1.0dev
  httplib2 = 0.7.4
+ # Added by Buildout Versions at 2012-06-01 12:21:26.475594
+ setuptools = 0.6c12dev-r88846
+ # Added by Buildout Versions at 2012-05-30 13:39:28.023002
+ django-picklefield = 0.2.1