list_display contrat #1542
[auf_rh_dae.git] / project / rh / models.py
index 4156a81..e5bcfd4 100644 (file)
@@ -1,16 +1,15 @@
 # -=- encoding: utf-8 -=-
 
 # -=- encoding: utf-8 -=-
 
-import datetime
-
 from django.core.files.storage import FileSystemStorage
 from django.db import models
 from django.core.files.storage import FileSystemStorage
 from django.db import models
-import settings
-
+from django.conf import settings
+from auf.django.metadata.models import AUFMetadata
+from auf.django.metadata.managers import NoDeleteManager
 import datamaster_modeles.models as ref
 
 
 # Constantes
 import datamaster_modeles.models as ref
 
 
 # Constantes
-HELP_TEXT_DATE = u"format: aaaa-mm-jj"
+HELP_TEXT_DATE = "format: aaaa-mm-jj"
 REGIME_TRAVAIL_DEFAULT = 100.00
 REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT = 35.00
 
 REGIME_TRAVAIL_DEFAULT = 100.00
 REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT = 35.00
 
@@ -27,30 +26,8 @@ def dossier_piece_dispatch(instance, filename):
     path = "dossier/%s/%s" % (instance.dossier_id, filename)
     return path
 
     path = "dossier/%s/%s" % (instance.dossier_id, filename)
     return path
 
-# Abstracts
-class Metadata(models.Model):
-    """Méta-données AUF.
-    Metadata.actif = flag remplaçant la suppression.
-    actif == False : objet réputé supprimé.
-    """
-    actif = models.BooleanField(default=True)
-    date_creation = models.DateField(auto_now_add=True)
-    user_creation = models.ForeignKey('auth.User', 
-                            db_column='user_creation', related_name='+',
-                            null=True, blank=True)
-    date_modification = models.DateField(auto_now=True)
-    user_modification = models.ForeignKey('auth.User', 
-                            db_column='user_modification', related_name='+',
-                            null=True, blank=True)
-    date_desactivation = models.DateField(null=True, blank=True)
-    user_desactivation = models.ForeignKey('auth.User', 
-                            db_column='user_desactivation', related_name='+',
-                            null=True, blank=True)
-    
-    class Meta:
-        abstract = True
 
 
-class Commentaire(Metadata):
+class Commentaire(AUFMetadata):
     texte = models.TextField()
     owner = models.ForeignKey('auth.User', db_column='owner', related_name='+')
     
     texte = models.TextField()
     owner = models.ForeignKey('auth.User', db_column='owner', related_name='+')
     
@@ -69,51 +46,58 @@ POSTE_APPEL_CHOICES = (
     ('externe', 'Externe'),
 )
 
     ('externe', 'Externe'),
 )
 
-class Poste_(Metadata):
+class PosteManager(NoDeleteManager):
+    def get_query_set(self):
+        return super(PosteManager, self).get_query_set().select_related('implantation')
+
+class Poste_(AUFMetadata):
     """Un Poste est un emploi (job) à combler dans une implantation. 
     Un Poste peut être comblé par un Employe, auquel cas un Dossier est créé.
     Si on veut recruter 2 jardiniers, 2 Postes distincts existent.
     """
     """Un Poste est un emploi (job) à combler dans une implantation. 
     Un Poste peut être comblé par un Employe, auquel cas un Dossier est créé.
     Si on veut recruter 2 jardiniers, 2 Postes distincts existent.
     """
+
+    objects = PosteManager()
+
     # Identification
     nom = models.CharField(max_length=255, 
     # Identification
     nom = models.CharField(max_length=255, 
-                            verbose_name=u"Titre du poste", )
+                            verbose_name="Titre du poste", )
     nom_feminin = models.CharField(max_length=255,
     nom_feminin = models.CharField(max_length=255,
-                            verbose_name=u"Titre du poste (au féminin)",
+                            verbose_name="Titre du poste (au féminin)",
                             null=True)
     implantation = models.ForeignKey(ref.Implantation, 
                             db_column='implantation', related_name='+')
     type_poste = models.ForeignKey('TypePoste', db_column='type_poste',
                             related_name='+',
                             null=True)
                             null=True)
     implantation = models.ForeignKey(ref.Implantation, 
                             db_column='implantation', related_name='+')
     type_poste = models.ForeignKey('TypePoste', db_column='type_poste',
                             related_name='+',
                             null=True)
-    service = models.ForeignKey('Service', db_column='service', 
+    service = models.ForeignKey('Service', db_column='service', null=True,
                             related_name='+',
                             related_name='+',
-                            verbose_name=u"Direction/Service/Pôle support",
+                            verbose_name="Direction/Service/Pôle support",
                             default=1)  # default = Rectorat
     responsable = models.ForeignKey('Poste', db_column='responsable', 
                             default=1)  # default = Rectorat
     responsable = models.ForeignKey('Poste', db_column='responsable', 
-                            related_name='+',
-                            verbose_name=u"Poste du responsable",
+                            related_name='+', null=True,
+                            verbose_name="Poste du responsable",
                             default=149)    # default = Recteur
                                 
     # Contrat
     regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
                             default=149)    # default = Recteur
                                 
     # Contrat
     regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
-                            default=REGIME_TRAVAIL_DEFAULT, 
-                            verbose_name=u"Temps de travail", 
-                            help_text=u"% du temps complet")
+                            default=REGIME_TRAVAIL_DEFAULT, null=True,
+                            verbose_name="Temps de travail", 
+                            help_text="% du temps complet")
     regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
     regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
-                            decimal_places=2,
+                            decimal_places=2, null=True,
                             default=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT,
                             default=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT,
-                            verbose_name=u"Nb. heures par semaine")
+                            verbose_name="Nb. heures par semaine")
 
     # Recrutement
 
     # Recrutement
-    local = models.BooleanField(verbose_name=u"Local", default=True, 
-                            blank=True)
-    expatrie = models.BooleanField(verbose_name=u"Expatrié", default=False, 
-                            blank=True)
-    mise_a_disposition = models.BooleanField(
-                            verbose_name=u"Mise à disposition",
-                            default=False)
-    appel = models.CharField(max_length=10, 
-                            verbose_name=u"Appel à candidature",
+    local = models.NullBooleanField(verbose_name="Local", default=True, 
+                            null=True, blank=True)
+    expatrie = models.NullBooleanField(verbose_name="Expatrié", default=False, 
+                            null=True, blank=True)
+    mise_a_disposition = models.NullBooleanField(
+                            verbose_name="Mise à disposition",
+                            null=True, default=False)
+    appel = models.CharField(max_length=10, null=True,
+                            verbose_name="Appel à candidature",
                             choices=POSTE_APPEL_CHOICES,
                             default='interne')
 
                             choices=POSTE_APPEL_CHOICES,
                             default='interne')
 
@@ -130,25 +114,25 @@ class Poste_(Metadata):
     valeur_point_max = models.ForeignKey('ValeurPoint', 
                             db_column='valeur_point_max', related_name='+', 
                             null=True, blank=True)
     valeur_point_max = models.ForeignKey('ValeurPoint', 
                             db_column='valeur_point_max', related_name='+', 
                             null=True, blank=True)
-    devise_min = models.ForeignKey('Devise', db_column='devise_min', 
+    devise_min = models.ForeignKey('Devise', db_column='devise_min', null=True,
                             related_name='+', default=5)
                             related_name='+', default=5)
-    devise_max = models.ForeignKey('Devise', db_column='devise_max', 
+    devise_max = models.ForeignKey('Devise', db_column='devise_max', null=True,
                             related_name='+', default=5)
     salaire_min = models.DecimalField(max_digits=12, decimal_places=2,
                             related_name='+', default=5)
     salaire_min = models.DecimalField(max_digits=12, decimal_places=2,
-                            default=0)
+                            null=True, default=0)
     salaire_max = models.DecimalField(max_digits=12, decimal_places=2,
     salaire_max = models.DecimalField(max_digits=12, decimal_places=2,
-                            default=0)
+                            null=True, default=0)
     indemn_min = models.DecimalField(max_digits=12, decimal_places=2,
     indemn_min = models.DecimalField(max_digits=12, decimal_places=2,
-                            default=0)
+                            null=True, default=0)
     indemn_max = models.DecimalField(max_digits=12, decimal_places=2,
     indemn_max = models.DecimalField(max_digits=12, decimal_places=2,
-                            default=0)
+                            null=True, default=0)
     autre_min = models.DecimalField(max_digits=12, decimal_places=2,
     autre_min = models.DecimalField(max_digits=12, decimal_places=2,
-                            default=0)
+                            null=True, default=0)
     autre_max = models.DecimalField(max_digits=12, decimal_places=2,
     autre_max = models.DecimalField(max_digits=12, decimal_places=2,
-                            default=0)
+                            null=True, default=0)
 
     # Comparatifs de rémunération
 
     # Comparatifs de rémunération
-    devise_comparaison = models.ForeignKey('Devise', 
+    devise_comparaison = models.ForeignKey('Devise', null=True,
                             db_column='devise_comparaison', 
                             related_name='+',
                             default=5)
                             db_column='devise_comparaison', 
                             related_name='+',
                             default=5)
@@ -178,20 +162,33 @@ class Poste_(Metadata):
 
     # Autres Metadata
     date_validation = models.DateTimeField(null=True, blank=True)   # de dae
 
     # Autres Metadata
     date_validation = models.DateTimeField(null=True, blank=True)   # de dae
-    date_debut = models.DateField(verbose_name=u"Date de début",
+    date_debut = models.DateField(verbose_name="Date de début", null=True,
                             help_text=HELP_TEXT_DATE)
                             help_text=HELP_TEXT_DATE)
-    date_fin = models.DateField(verbose_name=u"Date de fin",
+    date_fin = models.DateField(verbose_name="Date de fin",
                             help_text=HELP_TEXT_DATE,
                             null=True, blank=True)
 
     class Meta:
         abstract = True
         ordering = ['implantation__nom', 'nom']
                             help_text=HELP_TEXT_DATE,
                             null=True, blank=True)
 
     class Meta:
         abstract = True
         ordering = ['implantation__nom', 'nom']
+        verbose_name = "Poste"
+        verbose_name_plural = "Postes"
 
     def __unicode__(self):
 
     def __unicode__(self):
-        # TODO : gérer si poste est vacant ou non dans affichage
-        # TODO : gérer le nom_feminin (autre méthode appelée par __unicode__ ?)
-        return u'%s - %s [%s]' % (self.implantation, self.nom, self.id)
+        representation = u'%s - %s [%s]' % (self.implantation, self.nom, 
+                            self.id)
+        if self.is_vacant():
+            representation = representation + u' (vacant)'
+        return representation
+        
+    def is_vacant(self):
+        # TODO : si existe un dossier actif pour ce poste, return False
+        # self.dossier_set.all() fonctionne pas
+        return False
+
+
+class Poste(Poste_):
+    __doc__ = Poste_.__doc__
 
 
 class Poste(Poste_):
 
 
 class Poste(Poste_):
@@ -204,32 +201,39 @@ POSTE_FINANCEMENT_CHOICES = (
     ('C', 'C - Autre')
 )
 
     ('C', 'C - Autre')
 )
 
-class PosteFinancement(models.Model):
+
+class PosteFinancement_(models.Model):
     """Pour un Poste, structure d'informations décrivant comment on prévoit
     financer ce Poste.
     """
     poste = models.ForeignKey('Poste', db_column='poste', 
     """Pour un Poste, structure d'informations décrivant comment on prévoit
     financer ce Poste.
     """
     poste = models.ForeignKey('Poste', db_column='poste', 
-                            related_name='financements')
+                            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,
     type = models.CharField(max_length=1, choices=POSTE_FINANCEMENT_CHOICES)
     pourcentage = models.DecimalField(max_digits=12, decimal_places=2,
-            help_text=u"ex.: 33.33 % (décimale avec point)")
+            help_text="ex.: 33.33 % (décimale avec point)")
     commentaire = models.TextField(
     commentaire = models.TextField(
-            help_text=u"Spécifiez la source de financement.")
+            help_text="Spécifiez la source de financement.")
 
     class Meta:
 
     class Meta:
+        abstract = True
         ordering = ['type']
         
     def __unicode__(self):
         return u'%s : %s %' % (self.type, self.pourcentage)
 
         ordering = ['type']
         
     def __unicode__(self):
         return u'%s : %s %' % (self.type, self.pourcentage)
 
+
+class PosteFinancement(PosteFinancement_):
+    __doc__ = PosteFinancement_.__doc__
+
+
 class PostePiece(models.Model):
     """Documents relatifs au Poste.
     Ex.: Description de poste
     """
 class PostePiece(models.Model):
     """Documents relatifs au Poste.
     Ex.: Description de poste
     """
-    poste = models.ForeignKey("Poste", db_column='poste', 
+    poste = models.ForeignKey('Poste', db_column='poste', 
                             related_name='pieces')
                             related_name='pieces')
-    nom = models.CharField(verbose_name=u"Nom", max_length=255)
-    fichier = models.FileField(verbose_name=u"Fichier", 
+    nom = models.CharField(verbose_name="Nom", max_length=255)
+    fichier = models.FileField(verbose_name="Fichier", 
                             upload_to=poste_piece_dispatch, 
                             storage=storage_prive)
 
                             upload_to=poste_piece_dispatch, 
                             storage=storage_prive)
 
@@ -239,8 +243,20 @@ class PostePiece(models.Model):
     def __unicode__(self):
         return u'%s' % (self.nom)
 
     def __unicode__(self):
         return u'%s' % (self.nom)
 
+class PosteComparaison(models.Model):
+    """
+    De la même manière qu'un dossier, un poste peut-être comparé à un autre poste.
+    """
+    poste = models.ForeignKey('Poste', related_name='comparaisons_internes')
+    implantation = models.ForeignKey(ref.Implantation, null=True, blank=True, related_name="+")
+    nom = models.CharField(verbose_name="Poste", max_length=255, null=True, blank=True)
+    montant = models.IntegerField(null=True)
+    devise = models.ForeignKey("Devise", default=5, related_name='+', null=True, blank=True)
+    montant_euros = models.IntegerField(null=True)
+
+
 class PosteCommentaire(Commentaire):
 class PosteCommentaire(Commentaire):
-    poste = models.ForeignKey("Poste", db_column='poste', related_name='+')
+    poste = models.ForeignKey('Poste', db_column='poste', related_name='+')
 
 
 ### EMPLOYÉ/PERSONNE
 
 
 ### EMPLOYÉ/PERSONNE
@@ -255,7 +271,7 @@ SITUATION_CHOICES = (
     ('M', 'Marié'),
 )
 
     ('M', 'Marié'),
 )
 
-class Employe(Metadata):
+class Employe(AUFMetadata):
     """Personne occupant ou ayant occupé un Poste. Un Employe aura autant de 
     Dossiers qu'il occupe ou a occupé de Postes.
     
     """Personne occupant ou ayant occupé un Poste. Un Employe aura autant de 
     Dossiers qu'il occupe ou a occupé de Postes.
     
@@ -264,29 +280,35 @@ class Employe(Metadata):
     """
     # Identification
     nom = models.CharField(max_length=255)
     """
     # Identification
     nom = models.CharField(max_length=255)
-    prenom = models.CharField(max_length=255, verbose_name=u"Prénom")
-    # TODO : nom_affichage doit être obligatoire, pas nom et prenom
+    prenom = models.CharField(max_length=255, verbose_name="Prénom")
     nom_affichage = models.CharField(max_length=255, 
     nom_affichage = models.CharField(max_length=255, 
-                            verbose_name=u"Nom d'affichage",
+                            verbose_name="Nom d'affichage",
                             null=True, blank=True)
     nationalite = models.ForeignKey(ref.Pays, to_field='code', 
                             db_column='nationalite',
                             null=True, blank=True)
     nationalite = models.ForeignKey(ref.Pays, to_field='code', 
                             db_column='nationalite',
-                            related_name='employes_nationalite')
+                            related_name='employes_nationalite',
+                            verbose_name="Nationalité")
     date_naissance = models.DateField(help_text=HELP_TEXT_DATE,
     date_naissance = models.DateField(help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de naissance",
                             null=True, blank=True)
     genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     
     # Infos personnelles
     situation_famille = models.CharField(max_length=1, 
                             choices=SITUATION_CHOICES,
                             null=True, blank=True)
     genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     
     # Infos personnelles
     situation_famille = models.CharField(max_length=1, 
                             choices=SITUATION_CHOICES,
+                            verbose_name="Situation familiale",
                             null=True, blank=True)
                             null=True, blank=True)
-    date_entree = models.DateField(verbose_name=u"Date d'entrée à l'AUF",
+    date_entree = models.DateField(verbose_name="Date d'entrée à l'AUF",
                             help_text=HELP_TEXT_DATE, 
                             null=True, blank=True)
     
     # Coordonnées
                             help_text=HELP_TEXT_DATE, 
                             null=True, blank=True)
     
     # Coordonnées
-    tel_domicile = models.CharField(max_length=255, null=True, blank=True)
-    tel_cellulaire = models.CharField(max_length=255, null=True, blank=True)
+    tel_domicile = models.CharField(max_length=255, 
+                            verbose_name="Tél. domicile",
+                            null=True, blank=True)
+    tel_cellulaire = models.CharField(max_length=255, 
+                            verbose_name="Tél. cellulaire",
+                            null=True, blank=True)
     adresse = models.CharField(max_length=255, null=True, blank=True)
     ville = models.CharField(max_length=255, null=True, blank=True)
     province = models.CharField(max_length=255, null=True, blank=True)
     adresse = models.CharField(max_length=255, null=True, blank=True)
     ville = models.CharField(max_length=255, null=True, blank=True)
     province = models.CharField(max_length=255, null=True, blank=True)
@@ -296,20 +318,27 @@ class Employe(Metadata):
                             null=True, blank=True)
 
     class Meta:
                             null=True, blank=True)
 
     class Meta:
-        ordering = ['nom_affichage']
+        ordering = ['nom_affichage','nom','prenom']
+        verbose_name = "Employé"
+        verbose_name_plural = "Employés"
         
     def __unicode__(self):
         
     def __unicode__(self):
-        # TODO : gérer nom d'affichage
-        return u'%s' % (self.nom_affichage)
+        return u'%s' % (self.get_nom())
+        
+    def get_nom(self):
+        nom_affichage = self.nom_affichage
+        if not nom_affichage:
+            nom_affichage = u'%s %s' % (self.nom.upper(), self.prenom)
+        return nom_affichage
 
 class EmployePiece(models.Model):
     """Documents relatifs à un employé.
     Ex.: CV...
     """
 
 class EmployePiece(models.Model):
     """Documents relatifs à un employé.
     Ex.: CV...
     """
-    employe = models.ForeignKey("Employe", db_column='employe', 
+    employe = models.ForeignKey('Employe', db_column='employe', 
                             related_name='+')
                             related_name='+')
-    nom = models.CharField(verbose_name=u"Nom", max_length=255)
-    fichier = models.FileField(verbose_name=u"Fichier", 
+    nom = models.CharField(verbose_name="Nom", max_length=255)
+    fichier = models.FileField(verbose_name="Fichier", 
                             upload_to=dossier_piece_dispatch, 
                             storage=storage_prive)
 
                             upload_to=dossier_piece_dispatch, 
                             storage=storage_prive)
 
@@ -320,7 +349,7 @@ class EmployePiece(models.Model):
         return u'%s' % (self.nom)
 
 class EmployeCommentaire(Commentaire):
         return u'%s' % (self.nom)
 
 class EmployeCommentaire(Commentaire):
-    employe = models.ForeignKey("Employe", db_column='employe',
+    employe = models.ForeignKey('Employe', db_column='employe',
                             related_name='+')
 
 
                             related_name='+')
 
 
@@ -331,38 +360,50 @@ LIEN_PARENTE_CHOICES = (
     ('Fils', 'Fils'),
 )
 
     ('Fils', 'Fils'),
 )
 
-class AyantDroit(Metadata):
+class AyantDroit(AUFMetadata):
     """Personne en relation avec un Employe.
     """
     # Identification
     nom = models.CharField(max_length=255)
     """Personne en relation avec un Employe.
     """
     # Identification
     nom = models.CharField(max_length=255)
-    prenom = models.CharField(max_length=255)
-    # TODO : nom_affichage doit être obligatoire, pas nom et prenom
+    prenom = models.CharField(max_length=255,
+                            verbose_name="Prénom",)
     nom_affichage = models.CharField(max_length=255, 
     nom_affichage = models.CharField(max_length=255, 
-                            verbose_name=u"Nom d'affichage",
+                            verbose_name="Nom d'affichage",
                             null=True, blank=True)
     nationalite = models.ForeignKey(ref.Pays, to_field='code', 
                             db_column='nationalite',
                             null=True, blank=True)
     nationalite = models.ForeignKey(ref.Pays, to_field='code', 
                             db_column='nationalite',
-                            related_name='ayantdroits_nationalite')
+                            related_name='ayantdroits_nationalite',
+                            verbose_name="Nationalité")
     date_naissance = models.DateField(help_text=HELP_TEXT_DATE,
     date_naissance = models.DateField(help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de naissance",
                             null=True, blank=True)
     genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     
     # Relation
     employe = models.ForeignKey('Employe', db_column='employe', 
                             null=True, blank=True)
     genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     
     # Relation
     employe = models.ForeignKey('Employe', db_column='employe', 
-                            related_name='ayantdroits')
+                            related_name='ayantdroits',
+                            verbose_name="Employé")
     lien_parente = models.CharField(max_length=10, 
                             choices=LIEN_PARENTE_CHOICES,
     lien_parente = models.CharField(max_length=10, 
                             choices=LIEN_PARENTE_CHOICES,
+                            verbose_name="Lien de parenté",
                             null=True, blank=True)
 
     class Meta:
         ordering = ['nom_affichage']
                             null=True, blank=True)
 
     class Meta:
         ordering = ['nom_affichage']
+        verbose_name = "Ayant droit"
+        verbose_name_plural = "Ayants droit"
+        
     def __unicode__(self):
     def __unicode__(self):
-        # TODO : gérer nom d'affichage
-        return u'%s %s' % (self.prenom, self.nom.upper())
+        return u'%s' % (self.get_nom())
+        
+    def get_nom(self):
+        nom_affichage = self.nom_affichage
+        if not nom_affichage:
+            nom_affichage = u'%s %s' % (self.nom.upper(), self.prenom)
+        return nom_affichage
 
 class AyantDroitCommentaire(Commentaire):
 
 class AyantDroitCommentaire(Commentaire):
-    ayant_droit = models.ForeignKey("AyantDroit", db_column='ayant_droit',
+    ayant_droit = models.ForeignKey('AyantDroit', db_column='ayant_droit',
                             related_name='+')
 
 
                             related_name='+')
 
 
@@ -379,7 +420,7 @@ COMPTE_COMPTA_CHOICES = (
     ('aucun', 'Aucun'),
 )
 
     ('aucun', 'Aucun'),
 )
 
-class Dossier_(Metadata):
+class Dossier_(AUFMetadata):
     """Le Dossier regroupe les informations relatives à l'occupation
     d'un Poste par un Employe. Un seul Dossier existe par Poste occupé
     par un Employe.
     """Le Dossier regroupe les informations relatives à l'occupation
     d'un Poste par un Employe. Un seul Dossier existe par Poste occupé
     par un Employe.
@@ -390,15 +431,16 @@ class Dossier_(Metadata):
     """
     # Identification
     employe = models.ForeignKey('Employe', db_column='employe', 
     """
     # Identification
     employe = models.ForeignKey('Employe', db_column='employe', 
-                            related_name='+')
-    poste = models.ForeignKey('Poste', db_column='poste', 
-                            related_name='+', editable=False)
-    statut = models.ForeignKey('Statut', related_name='+', default=3)
+                            related_name='+',
+                            verbose_name="Employé")
+    poste = models.ForeignKey('Poste', db_column='poste', related_name='+')
+    statut = models.ForeignKey('Statut', related_name='+', default=3,
+                            null=True)
     organisme_bstg = models.ForeignKey('OrganismeBstg', 
                             db_column='organisme_bstg',
                             related_name='+',
     organisme_bstg = models.ForeignKey('OrganismeBstg', 
                             db_column='organisme_bstg',
                             related_name='+',
-                            verbose_name=u"Organisme", 
-                            help_text=u"Si détaché (DET) ou \
+                            verbose_name="Organisme", 
+                            help_text="Si détaché (DET) ou \
                                     mis à disposition (MAD), \
                                     préciser l'organisme.",
                             null=True, blank=True)
                                     mis à disposition (MAD), \
                                     préciser l'organisme.",
                             null=True, blank=True)
@@ -406,28 +448,28 @@ class Dossier_(Metadata):
     # Recrutement
     remplacement = models.BooleanField(default=False)
     statut_residence = models.CharField(max_length=10, default='local', 
     # Recrutement
     remplacement = models.BooleanField(default=False)
     statut_residence = models.CharField(max_length=10, default='local', 
-                            verbose_name=u"Statut",
+                            verbose_name="Statut", null=True,
                             choices=STATUT_RESIDENCE_CHOICES)
    
     # Rémunération
     classement = models.ForeignKey('Classement', db_column='classement', 
                             related_name='+',
                             null=True, blank=True)
                             choices=STATUT_RESIDENCE_CHOICES)
    
     # Rémunération
     classement = models.ForeignKey('Classement', db_column='classement', 
                             related_name='+',
                             null=True, blank=True)
-    regime_travail = models.DecimalField(max_digits=12, 
+    regime_travail = models.DecimalField(max_digits=12, null=True,
                             decimal_places=2,
                             default=REGIME_TRAVAIL_DEFAULT,
                             decimal_places=2,
                             default=REGIME_TRAVAIL_DEFAULT,
-                            verbose_name=u"Régime de travail",
-                            help_text=u"% du temps complet")
+                            verbose_name="Régime de travail",
+                            help_text="% du temps complet")
     regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
     regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
-                            decimal_places=2, 
+                            decimal_places=2, null=True,
                             default=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT,
                             default=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT,
-                            verbose_name=u"Nb. heures par semaine")
+                            verbose_name="Nb. heures par semaine")
 
     # Occupation du Poste par cet Employe (anciennement "mandat")
 
     # Occupation du Poste par cet Employe (anciennement "mandat")
-    date_debut = models.DateField(verbose_name=u"Date de début d'occupation \
+    date_debut = models.DateField(verbose_name="Date de début d'occupation \
                             de poste",
                             help_text=HELP_TEXT_DATE)
                             de poste",
                             help_text=HELP_TEXT_DATE)
-    date_fin = models.DateField(verbose_name=u"Date de fin d'occupation \
+    date_fin = models.DateField(verbose_name="Date de fin d'occupation \
                             de poste",
                             help_text=HELP_TEXT_DATE,
                             null=True, blank=True)
                             de poste",
                             help_text=HELP_TEXT_DATE,
                             null=True, blank=True)
@@ -437,10 +479,20 @@ class Dossier_(Metadata):
     
     class Meta:
         abstract = True
     
     class Meta:
         abstract = True
-        ordering = ['poste__nom', 'employe__nom_affichage']
+        ordering = ['employe__nom_affichage', 'employe__nom', 'poste__nom']
+        verbose_name = "Dossier"
+        verbose_name_plural = "Dossiers"
         
     def __unicode__(self):
         
     def __unicode__(self):
-        return u'%s - %s' % (self.poste.nom, self.employe)
+        poste = self.poste.nom
+        if self.employe.genre == 'F':
+            poste = self.poste.nom_feminin            
+        return u'%s - %s' % (self.employe, poste)
+
+
+class Dossier(Dossier_):
+    __doc__ = Dossier_.__doc__
+
 
 
 class Dossier(Dossier_):
 
 
 class Dossier(Dossier_):
@@ -451,10 +503,10 @@ class DossierPiece(models.Model):
     """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
     Ex.: Lettre de motivation.
     """
     """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
     Ex.: Lettre de motivation.
     """
-    dossier = models.ForeignKey("Dossier", db_column='dossier', 
+    dossier = models.ForeignKey('Dossier', db_column='dossier', 
                             related_name='+')
                             related_name='+')
-    nom = models.CharField(verbose_name=u"Nom", max_length=255)
-    fichier = models.FileField(verbose_name=u"Fichier", 
+    nom = models.CharField(verbose_name="Nom", max_length=255)
+    fichier = models.FileField(verbose_name="Fichier", 
                             upload_to=dossier_piece_dispatch, 
                             storage=storage_prive)
 
                             upload_to=dossier_piece_dispatch, 
                             storage=storage_prive)
 
@@ -465,20 +517,23 @@ class DossierPiece(models.Model):
         return u'%s' % (self.nom)
 
 class DossierCommentaire(Commentaire):
         return u'%s' % (self.nom)
 
 class DossierCommentaire(Commentaire):
-    dossier = models.ForeignKey("Dossier", db_column='dossier', 
+    dossier = models.ForeignKey('Dossier', db_column='dossier', 
                             related_name='+')
 
 
 ### RÉMUNÉRATION
     
                             related_name='+')
 
 
 ### RÉMUNÉRATION
     
-class RemunerationMixin(Metadata):
+class RemunerationMixin(AUFMetadata):
     # Identification
     # Identification
-    dossier = models.ForeignKey('Dossier', db_column='dossier')
+    dossier = models.ForeignKey('Dossier', db_column='dossier',
+                        related_name='%(app_label)s_%(class)s_remunerations')
     type = models.ForeignKey('TypeRemuneration', db_column='type', 
     type = models.ForeignKey('TypeRemuneration', db_column='type', 
-                            related_name='+')
+                            related_name='+',
+                            verbose_name="Type de rémunération")
     type_revalorisation = models.ForeignKey('TypeRevalorisation', 
                             db_column='type_revalorisation', 
                             related_name='+',
     type_revalorisation = models.ForeignKey('TypeRevalorisation', 
                             db_column='type_revalorisation', 
                             related_name='+',
+                            verbose_name="Type de revalorisation",
                             null=True, blank=True)
     montant = models.FloatField(null=True, blank=True,
                             default=0)
                             null=True, blank=True)
     montant = models.FloatField(null=True, blank=True,
                             default=0)
@@ -489,9 +544,11 @@ class RemunerationMixin(Metadata):
     # commentaire = precision
     commentaire = models.CharField(max_length=255, null=True, blank=True)
     # date_debut = anciennement date_effectif
     # commentaire = precision
     commentaire = models.CharField(max_length=255, null=True, blank=True)
     # date_debut = anciennement date_effectif
-    date_debut = models.DateField(help_text=HELP_TEXT_DATE, 
+    date_debut = models.DateField(help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de début",
                             null=True, blank=True)
     date_fin = models.DateField(help_text=HELP_TEXT_DATE,
                             null=True, blank=True)
     date_fin = models.DateField(help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de fin",
                             null=True, blank=True)
     
     class Meta: 
                             null=True, blank=True)
     
     class Meta: 
@@ -501,7 +558,7 @@ class RemunerationMixin(Metadata):
     def __unicode__(self):
         return u'%s %s (%s)' % (self.montant, self.devise.code, self.type.nom)
     
     def __unicode__(self):
         return u'%s %s (%s)' % (self.montant, self.devise.code, self.type.nom)
     
-class Remuneration(RemunerationMixin):
+class Remuneration_(RemunerationMixin):
     """Structure de rémunération (données budgétaires) en situation normale
     pour un Dossier. Si un Evenement existe, utiliser la structure de 
     rémunération EvenementRemuneration de cet événement.    
     """Structure de rémunération (données budgétaires) en situation normale
     pour un Dossier. Si un Evenement existe, utiliser la structure de 
     rémunération EvenementRemuneration de cet événement.    
@@ -526,34 +583,56 @@ class Remuneration(RemunerationMixin):
             devise = "???"
         return "%s %s" % (self.montant, devise)
 
             devise = "???"
         return "%s %s" % (self.montant, devise)
 
+    class Meta:
+        abstract = True
+        verbose_name = "Rémunération"
+        verbose_name_plural = "Rémunérations"
+
+
+class Remuneration(Remuneration_):
+    __doc__ = Remuneration_.__doc__
+
 
 ### CONTRATS
 
 ### CONTRATS
+
+class ContratManager(NoDeleteManager):
+    def get_query_set(self):
+        return super(ContratManager, self).get_query_set().select_related('dossier', 'dossier__poste')
+
         
         
-class Contrat(Metadata):
+class Contrat(AUFMetadata):
     """Document juridique qui encadre la relation de travail d'un Employe
     pour un Poste particulier. Pour un Dossier (qui documente cette 
     relation de travail) plusieurs contrats peuvent être associés.
     """
     """Document juridique qui encadre la relation de travail d'un Employe
     pour un Poste particulier. Pour un Dossier (qui documente cette 
     relation de travail) plusieurs contrats peuvent être associés.
     """
+
+    objects = ContratManager()
+
     dossier = models.ForeignKey('Dossier', db_column='dossier', 
                             related_name='+')
     type_contrat = models.ForeignKey('TypeContrat', db_column='type_contrat', 
     dossier = models.ForeignKey('Dossier', db_column='dossier', 
                             related_name='+')
     type_contrat = models.ForeignKey('TypeContrat', db_column='type_contrat', 
-                            related_name='+')
-    date_debut = models.DateField(help_text=HELP_TEXT_DATE)
+                            related_name='+',
+                            verbose_name="Type de contrat")
+    date_debut = models.DateField(help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de début")
     date_fin = models.DateField(help_text=HELP_TEXT_DATE,
     date_fin = models.DateField(help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de fin",
                             null=True, blank=True)
 
     class Meta:
         ordering = ['dossier__employe__nom_affichage']
                             null=True, blank=True)
 
     class Meta:
         ordering = ['dossier__employe__nom_affichage']
+        verbose_name = "Contrat"
+        verbose_name_plural = "Contrats"
         
     def __unicode__(self):
         
     def __unicode__(self):
-        return u'%s - %s' % (self.dossier.employe.nom_affichage, self.id)
+        return u'%s - %s' % (self.dossier, self.id)
         
 # TODO? class ContratPiece(models.Model):
     
 
 ### ÉVÉNEMENTS
 
         
 # TODO? class ContratPiece(models.Model):
     
 
 ### ÉVÉNEMENTS
 
-class Evenement(Metadata):
+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).
     """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).
@@ -565,54 +644,94 @@ class Evenement(Metadata):
     conserver le Dossier intact afin d'éviter une re-saisie des données lors
     du retour à la normale.
     """
     conserver le Dossier intact afin d'éviter une re-saisie des données lors
     du retour à la normale.
     """
-    dossier = models.ForeignKey("Dossier", db_column='dossier', 
+    dossier = models.ForeignKey('Dossier', db_column='dossier', 
                             related_name='+')
     nom = models.CharField(max_length=255)
                             related_name='+')
     nom = models.CharField(max_length=255)
-    date_debut = models.DateField(help_text=HELP_TEXT_DATE)
-    date_fin = models.DateField(help_text=HELP_TEXT_DATE, 
+    date_debut = models.DateField(help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de début")
+    date_fin = models.DateField(help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de fin",
                             null=True, blank=True)
                             null=True, blank=True)
+
     class Meta:
     class Meta:
+        abstract = True
         ordering = ['nom']
         ordering = ['nom']
+        verbose_name = "Évènement"
+        verbose_name_plural = "Évènements"
                             
     def __unicode__(self):
         return u'%s' % (self.nom)
                             
     def __unicode__(self):
         return u'%s' % (self.nom)
+
+
+class Evenement(Evenement_):
+    __doc__ = Evenement_.__doc__
+
     
     
-class EvenementRemuneration(RemunerationMixin):
+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',
     """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='+')
+                            related_name='+',
+                            verbose_name="É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 = "Évènement - rémunération"
+        verbose_name_plural = "Évènements - rémunérations"
+
+
+class EvenementRemuneration(EvenementRemuneration_):
+    __doc__ = EvenementRemuneration_.__doc__
+
+    class Meta:
+        abstract = True
+
+
+class EvenementRemuneration(EvenementRemuneration_):
+    __doc__ = EvenementRemuneration_.__doc__
 
 
 ### RÉFÉRENCES RH 
 
 
 
 ### RÉFÉRENCES RH 
 
-class FamilleEmploi(Metadata):
+class FamilleEmploi(AUFMetadata):
     """Catégorie utilisée dans la gestion des Postes.
     Catégorie supérieure à TypePoste.
     """
     nom = models.CharField(max_length=255)
     
     """Catégorie utilisée dans la gestion des Postes.
     Catégorie supérieure à TypePoste.
     """
     nom = models.CharField(max_length=255)
     
+    class Meta:
+        ordering = ['nom']
+        verbose_name = "Famille d'emploi"
+        verbose_name_plural = "Familles d'emploi"
+    
     def __unicode__(self):
         return u'%s' % (self.nom)
 
     def __unicode__(self):
         return u'%s' % (self.nom)
 
-class TypePoste(Metadata):
+class TypePoste(AUFMetadata):
     """Catégorie de Poste.
     """
     nom = models.CharField(max_length=255)
     """Catégorie de Poste.
     """
     nom = models.CharField(max_length=255)
-    nom_feminin = models.CharField(max_length=255)
+    nom_feminin = models.CharField(max_length=255,
+                            verbose_name="Nom féminin")
     
     
-    is_responsable = models.BooleanField(default=False)
+    is_responsable = models.BooleanField(default=False,
+                            verbose_name="Poste de responsabilité")
     famille_emploi = models.ForeignKey('FamilleEmploi', 
                             db_column='famille_emploi',
     famille_emploi = models.ForeignKey('FamilleEmploi', 
                             db_column='famille_emploi',
-                            related_name='+')
+                            related_name='+',
+                            verbose_name="Famille d'emploi")
 
     class Meta:
         ordering = ['nom']
 
     class Meta:
         ordering = ['nom']
+        verbose_name = "Type de poste"
+        verbose_name_plural = "Types de poste"
         
     def __unicode__(self):
         
     def __unicode__(self):
-        # TODO : gérer nom féminin
         return u'%s' % (self.nom)
 
 
         return u'%s' % (self.nom)
 
 
@@ -629,34 +748,48 @@ NATURE_REMUNERATION_CHOICES = (
     ('Traitement', 'Traitement'),
 )
 
     ('Traitement', 'Traitement'),
 )
 
-class TypeRemuneration(Metadata):
+class TypeRemuneration(AUFMetadata):
     """Catégorie de Remuneration.
     """
     nom = models.CharField(max_length=255)
     type_paiement = models.CharField(max_length=30, 
     """Catégorie de Remuneration.
     """
     nom = models.CharField(max_length=255)
     type_paiement = models.CharField(max_length=30, 
-                            choices=TYPE_PAIEMENT_CHOICES)
+                            choices=TYPE_PAIEMENT_CHOICES,
+                            verbose_name="Type de paiement")
     nature_remuneration = models.CharField(max_length=30, 
     nature_remuneration = models.CharField(max_length=30, 
-                            choices=NATURE_REMUNERATION_CHOICES)
+                            choices=NATURE_REMUNERATION_CHOICES,
+                            verbose_name="Nature de la rémunération")
+                            
+    class Meta:
+        ordering = ['nom']
+        verbose_name = "Type de rémunération"
+        verbose_name_plural = "Types de rémunération"
 
     def __unicode__(self):
         return u'%s' % (self.nom)
         
 
     def __unicode__(self):
         return u'%s' % (self.nom)
         
-class TypeRevalorisation(Metadata):
+class TypeRevalorisation(AUFMetadata):
     """Justification du changement de la Remuneration.
     (Actuellement utilisé dans aucun traitement informatique.)
     """
     nom = models.CharField(max_length=255)
     """Justification du changement de la Remuneration.
     (Actuellement utilisé dans aucun traitement informatique.)
     """
     nom = models.CharField(max_length=255)
+    
+    class Meta:
+        ordering = ['nom']
+        verbose_name = "Type de revalorisation"
+        verbose_name_plural = "Types de revalorisation"
 
     def __unicode__(self):
         return u'%s' % (self.nom)
     
 
     def __unicode__(self):
         return u'%s' % (self.nom)
     
-class Service(Metadata):
+class Service(AUFMetadata):
     """Unité administrative où les Postes sont rattachés.
     """
     nom = models.CharField(max_length=255)
         
     class Meta:
         ordering = ['nom']
     """Unité administrative où les Postes sont rattachés.
     """
     nom = models.CharField(max_length=255)
         
     class Meta:
         ordering = ['nom']
+        verbose_name = "Service"
+        verbose_name_plural = "Services"
 
     def __unicode__(self):
         return u'%s' % (self.nom)
 
     def __unicode__(self):
         return u'%s' % (self.nom)
@@ -667,7 +800,7 @@ TYPE_ORGANISME_CHOICES = (
     ('DET', 'Détachement'),
 )
 
     ('DET', 'Détachement'),
 )
 
-class OrganismeBstg(Metadata):
+class OrganismeBstg(AUFMetadata):
     """Organisation d'où provient un Employe mis à disposition (MAD) de 
     ou détaché (DET) à l'AUF à titre gratuit.
     
     """Organisation d'où provient un Employe mis à disposition (MAD) de 
     ou détaché (DET) à l'AUF à titre gratuit.
     
@@ -682,11 +815,13 @@ class OrganismeBstg(Metadata):
 
     class Meta:
         ordering = ['type', 'nom']
 
     class Meta:
         ordering = ['type', 'nom']
+        verbose_name = "Organisme BSTG"
+        verbose_name_plural = "Organismes BSTG"
 
     def __unicode__(self):
 
     def __unicode__(self):
-        return u'%s (%s)' % (self.nom, self.type)
+        return u'%s (%s)' % (self.nom, self.get_type_display())
 
 
-class Statut(Metadata):
+class Statut(AUFMetadata):
     """Statut de l'Employe dans le cadre d'un Dossier particulier.
     """
     # Identification
     """Statut de l'Employe dans le cadre d'un Dossier particulier.
     """
     # Identification
@@ -695,6 +830,8 @@ class Statut(Metadata):
 
     class Meta:
         ordering = ['code']
 
     class Meta:
         ordering = ['code']
+        verbose_name = "Statut d'employé"
+        verbose_name_plural = "Statuts d'employé"
         
     def __unicode__(self):
         return u'%s : %s' % (self.code, self.nom)
         
     def __unicode__(self):
         return u'%s : %s' % (self.code, self.nom)
@@ -710,7 +847,8 @@ TYPE_CLASSEMENT_CHOICES = (
     ('HG', 'HG - Hors grille [direction]'),
 )
 
     ('HG', 'HG - Hors grille [direction]'),
 )
 
-class Classement(Metadata):
+
+class Classement_(AUFMetadata):
     """Éléments de classement de la 
     "Grille générique de classement hiérarchique".
     
     """Éléments de classement de la 
     "Grille générique de classement hiérarchique".
     
@@ -721,74 +859,97 @@ class Classement(Metadata):
     """
     # Identification
     type = models.CharField(max_length=10, choices=TYPE_CLASSEMENT_CHOICES)
     """
     # Identification
     type = models.CharField(max_length=10, choices=TYPE_CLASSEMENT_CHOICES)
-    echelon = models.IntegerField()
-    degre = models.IntegerField()
-    coefficient = models.FloatField(default=0)
+    echelon = models.IntegerField(verbose_name="Échelon")
+    degre = models.IntegerField(verbose_name="Degré")
+    coefficient = models.FloatField(default=0, verbose_name="Coéfficient",
+                                    null=True)
     # Méta
     # annee # au lieu de date_debut et date_fin
     commentaire = models.TextField(null=True, blank=True)
     
     class Meta:
     # Méta
     # annee # au lieu de date_debut et date_fin
     commentaire = models.TextField(null=True, blank=True)
     
     class Meta:
+        abstract = True
         ordering = ['type','echelon','degre','coefficient']
         ordering = ['type','echelon','degre','coefficient']
+        verbose_name = "Classement"
+        verbose_name_plural = "Classements"
 
     def __unicode__(self):
         return u'%s.%s.%s (%s)' % (self.type, self.echelon, self.degre,
                                    self.coefficient)
 
 
     def __unicode__(self):
         return u'%s.%s.%s (%s)' % (self.type, self.echelon, self.degre,
                                    self.coefficient)
 
-class TauxChange(Metadata):
+class Classement(Classement_):
+    __doc__ = Classement_.__doc__
+
+
+class TauxChange_(AUFMetadata):
     """Taux de change de la devise vers l'euro (EUR) 
     pour chaque année budgétaire.
     """
     # Identification
     """Taux de change de la devise vers l'euro (EUR) 
     pour chaque année budgétaire.
     """
     # Identification
-    devise = models.ForeignKey('Devise', to_field='code', db_column='devise',
+    devise = models.ForeignKey('Devise', db_column='devise',
                             related_name='+')
                             related_name='+')
-    annee = models.IntegerField()
-    taux = models.FloatField()
-    
+    annee = models.IntegerField(verbose_name="Année")
+    taux = models.FloatField(verbose_name="Taux vers l'euro")
+
     class Meta:
     class Meta:
-        ordering = ['annee', 'devise__code']
+        abstract = True
+        ordering = ['-annee', 'devise__code']
+        verbose_name = "Taux de change"
+        verbose_name_plural = "Taux de change"
     
     def __unicode__(self):
     
     def __unicode__(self):
-        return u'%s : %s €' % (self.devise.code, self.taux)
+        return u'%s : %s € (%s)' % (self.devise, self.taux, self.annee)
 
 
-class ValeurPoint(Metadata):
+
+class TauxChange(TauxChange_):
+    __doc__ = TauxChange_.__doc__
+
+
+class ValeurPoint_(AUFMetadata):
     """Utile pour connaître, pour un Dossier, le salaire de base théorique lié 
     au classement dans la grille. La ValeurPoint s'obtient par l'implantation 
     """Utile pour connaître, pour un Dossier, le salaire de base théorique lié 
     au classement dans la grille. La ValeurPoint s'obtient par l'implantation 
-    du POste de ce Dossier : dossier.poste.implantation (pseudo code).
+    du Poste de ce Dossier : dossier.poste.implantation (pseudo code).
 
     salaire de base = coefficient * valeur du point de l'Implantation du Poste
     """
 
     salaire de base = coefficient * valeur du point de l'Implantation du Poste
     """
-    valeur = models.FloatField()
-    devise = models.ForeignKey('Devise', db_column='devise', 
+    valeur = models.FloatField(null=True)
+    devise = models.ForeignKey('Devise', db_column='devise', null=True,
                             related_name='+', default=5)
     implantation = models.ForeignKey(ref.Implantation, 
                             related_name='+', default=5)
     implantation = models.ForeignKey(ref.Implantation, 
-                            db_column='implantation', 
-                            related_name='valeur_point')
+                            db_column='implantation',
+                            related_name='%(app_label)s_valeur_point')
     # Méta
     annee = models.IntegerField()
 
     # Méta
     annee = models.IntegerField()
 
-    # Stockage de tous les taux de change 
-    # pour optimiser la recherche de la devise associée
-    annee_courante = datetime.datetime.now().year
-    tauxchange = TauxChange.objects.select_related('devise')    \
-                            .filter(annee=annee_courante)
-
     class Meta:
         ordering = ['annee', 'implantation__nom']
     class Meta:
         ordering = ['annee', 'implantation__nom']
-        
+        abstract = True
+        ordering = ['annee']
+        verbose_name = "Valeur du point"
+        verbose_name_plural = "Valeurs du point"
+
+    # TODO : cette fonction n'était pas présente dans la branche dev, utilité?
+    def get_tauxchange_courant(self):
+        """
+        Recherche le taux courant associé à la valeur d'un point.
+        Tous les taux de l'année courante sont chargés, pour optimiser un
+        affichage en liste. (On pourrait probablement améliorer le manager pour
+        lui greffer le taux courant sous forme de JOIN)
+        """
+        for tauxchange in self.tauxchange:
+            if tauxchange.implantation_id == self.implantation_id:
+                return tauxchange
+        return None
+
     def __unicode__(self):
     def __unicode__(self):
-        tx = self.get_tauxchange_courant()
-        if tx:
-            devise_code = tx.devise.code
-        else:
-            devise_code = "??"
-        return u'%s %s (%s-%s)' % (self.valeur, devise_code, 
-                            self.implantation_id, self.annee)
-        
-    class Meta:
-        ordering = ['valeur']
+        return u'%s %s (%s)' % (self.valeur, self.devise, self.annee)
+
+
+class ValeurPoint(ValeurPoint_):
+    __doc__ = ValeurPoint_.__doc__
+
 
 
-class Devise(Metadata):
+class Devise(AUFMetadata):
     """Devise monétaire.
     """
     code =  models.CharField(max_length=10, unique=True)
     """Devise monétaire.
     """
     code =  models.CharField(max_length=10, unique=True)
@@ -796,23 +957,30 @@ class Devise(Metadata):
 
     class Meta:
         ordering = ['code']
 
     class Meta:
         ordering = ['code']
+        verbose_name = "Devise"
+        verbose_name_plural = "Devises"
         
     def __unicode__(self):
         return u'%s - %s' % (self.code, self.nom)
 
         
     def __unicode__(self):
         return u'%s - %s' % (self.code, self.nom)
 
-class TypeContrat(Metadata):
+class TypeContrat(AUFMetadata):
     """Type de contrat.
     """
     nom = models.CharField(max_length=255)
     nom_long = models.CharField(max_length=255)
 
     """Type de contrat.
     """
     nom = models.CharField(max_length=255)
     nom_long = models.CharField(max_length=255)
 
+    class Meta:
+        ordering = ['nom']
+        verbose_name = "Type de contrat"
+        verbose_name_plural = "Types de contrat"
+
     def __unicode__(self):
         return u'%s' % (self.nom)
         
         
 ### AUTRES
 
     def __unicode__(self):
         return u'%s' % (self.nom)
         
         
 ### AUTRES
 
-class ResponsableImplantation(Metadata):
+class ResponsableImplantation(AUFMetadata):
     """Le responsable d'une implantation. 
     Anciennement géré sur le Dossier du responsable.
     """
     """Le responsable d'une implantation. 
     Anciennement géré sur le Dossier du responsable.
     """
@@ -828,3 +996,5 @@ class ResponsableImplantation(Metadata):
         
     class Meta:
         ordering = ['implantation__nom']
         
     class Meta:
         ordering = ['implantation__nom']
+        verbose_name = "Responsable d'implantation"
+        verbose_name_plural = "Responsables d'implantation"