refact models (incomplet)
[auf_rh_dae.git] / project / rh / models.py
index 1cc2d26..380e3df 100644 (file)
@@ -9,6 +9,12 @@ import settings
 import datamaster_modeles.models as ref
 
 
+# Constantes
+HELP_TEXT_DATE = "format: aaaa-mm-jj"
+REGIME_TRAVAIL_DEFAULT=100.00
+REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT=35.00
+
+
 # Upload de fichiers
 storage_prive = FileSystemStorage(settings.PRIVE_MEDIA_ROOT, 
                             base_url=settings.PRIVE_MEDIA_URL)
@@ -21,20 +27,27 @@ def dossier_piece_dispatch(instance, filename):
     path = "dossier/%s/%s" % (instance.dossier_id, filename)
     return path
 
-# Commentaires
-class Commentaire(models.Model):
-    texte = models.TextField()
-    # Méta
-    date_creation = models.DateTimeField(auto_now_add=True)
+# Abstracts
+class Metadata(models.Model):
+    """Méta-données AUF.
+    """
+    actif = models.BooleanField(default=True)
+    date_creation = models.DateField(auto_now_add=True)
+    user_creation = models.ForeignKey("auth.User")
     date_modification = models.DateField(auto_now=True)
-    owner = models.ForeignKey("auth.User")
-    actif = models.BooleanField()
+    user_modification = models.ForeignKey("auth.User")
+    date_desactivation = models.DateField()
+    user_desactivation = models.ForeignKey("auth.User")
     
     class Meta:
         abstract = True
 
-# Constantes
-HELP_TEXT_DATE = "format: aaaa-mm-jj"
+class Commentaire(Metadata):
+    texte = models.TextField()
+    owner = models.ForeignKey("auth.User")
+    
+    class Meta:
+        abstract = True
 
 
 ### POSTE
@@ -44,50 +57,50 @@ POSTE_APPEL_CHOICES = (
     ('externe', 'Externe'),
 )
 
-class Poste(models.Model):
+class Poste(Metadata):
     # Identification
     id = models.IntegerField(primary_key=True)
-    nom = models.CharField(verbose_name="Titre du poste", max_length=255)
-    nom_feminin = models.CharField(verbose_name="Titre du poste", max_length=255)
+    nom = models.CharField(max_length=255, 
+                            verbose_name="Titre du poste", )
+    nom_feminin = models.CharField(max_length=255,
+                            verbose_name="Titre du poste (au féminin)")
     implantation = models.ForeignKey(ref.Implantation)
-    type_poste = models.ForeignKey(rh.TypePoste, null=True, related_name='+')
-    service = models.ForeignKey(rh.Service, related_name='+',
-                                verbose_name=u"Direction/Service/Pôle support")
-    responsable = models.ForeignKey(rh.Poste, related_name='+',
-                                verbose_name="Poste du responsable")
+    type_poste = models.ForeignKey('TypePoste', null=True, related_name='+')
+    service = models.ForeignKey('Service', related_name='+',
+                            verbose_name=u"Direction/Service/Pôle support")
+    responsable = models.ForeignKey('Poste', related_name='+',
+                            verbose_name="Poste du responsable")
                                 
     # Contrat
     regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
-                                default=100, 
-                                verbose_name="Temps de travail", 
-                                help_text="% du temps complet")
+                            default=REGIME_TRAVAIL_DEFAULT, 
+                            verbose_name="Temps de travail", 
+                            help_text="% du temps complet")
     regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
-                                decimal_places=2,
-                                default=35,
-                                verbose_name="Nb. heures par semaine")
+                            decimal_places=2,
+                            default=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT,
+                            verbose_name="Nb. heures par semaine")
 
     # Recrutement
     local = models.BooleanField(verbose_name="Local", default=True, blank=True)
     expatrie = models.BooleanField(verbose_name="Expatrié", default=False, 
                             blank=True)
-
-    # TODO null?
     mise_a_disposition = models.BooleanField(verbose_name="Mise à disposition")
     appel = models.CharField(max_length=10, default='interne',
-                             verbose_name="Appel à candidature",
-                             choices=POSTE_APPEL_CHOICES)
+                            verbose_name="Appel à candidature",
+                            choices=POSTE_APPEL_CHOICES)
 
     # Rémunération
-    classement_min = models.ForeignKey(rh.Classement, related_name='+',
+    classement_min = models.ForeignKey('Classement', related_name='+',
                             blank=True, null=True)
-    classement_max = models.ForeignKey(rh.Classement, related_name='+',
+    classement_max = models.ForeignKey('Classement', related_name='+',
                             blank=True, null=True)
-    valeur_point_min = models.ForeignKey(rh.ValeurPoint, related_name='+', 
+    valeur_point_min = models.ForeignKey('ValeurPoint', related_name='+', 
                             blank=True, null=True)
-    valeur_point_max = models.ForeignKey(rh.ValeurPoint, related_name='+', 
+    valeur_point_max = models.ForeignKey('ValeurPoint', related_name='+', 
                             blank=True, null=True)
-    devise_min = models.ForeignKey(rh.Devise, default=5, related_name='+')
-    devise_max = models.ForeignKey(rh.Devise, default=5, related_name='+')
+    devise_min = models.ForeignKey('Devise', default=5, related_name='+')
+    devise_max = models.ForeignKey('Devise', default=5, related_name='+')
     salaire_min = models.DecimalField(max_digits=12, decimal_places=2,
                                       default=0)
     salaire_max = models.DecimalField(max_digits=12, decimal_places=2,
@@ -102,7 +115,7 @@ class Poste(models.Model):
                                       default=0)
 
     # Comparatifs de rémunération
-    devise_comparaison = models.ForeignKey(rh.Devise, related_name='+',
+    devise_comparaison = models.ForeignKey('Devise', related_name='+',
                                            default=5)
     comp_locale_min = models.DecimalField(max_digits=12, decimal_places=2,
                                           null=True, blank=True)
@@ -128,19 +141,16 @@ class Poste(models.Model):
     # Justification
     justification = models.TextField()
 
-    # Méta
+    # Autres Metadata
     date_validation = models.DateTimeField(null=True, blank=True)   # de dae
-    date_creation = models.DateTimeField(auto_now_add=True)
-    date_modification = models.DateTimeField(auto_now=True)
     date_debut = models.DateField(verbose_name="Date de début",
                                     help_text=HELP_TEXT_DATE)
     date_fin = models.DateField(null=True, blank=True,
                                     verbose_name="Date de fin",
-                                    help_text=)
-    actif = models.BooleanField(default=True)
+                                    help_text=HELP_TEXT_DATE)
             
     def __unicode__(self):
-        # gérer si poste est vacant ou non dans affichage
+        # TODO : gérer si poste est vacant ou non dans affichage
         return u'%s - %s [%s]' % (self.implantation, self.nom, self.id)
 
 
@@ -174,6 +184,7 @@ class PostePiece(models.Model):
 class PosteCommentaire(Commentaire):
     poste = models.ForeignKey("Poste")
 
+
 ### EMPLOYÉ/PERSONNE
 
 GENRE_CHOICES = (
@@ -186,18 +197,18 @@ SITUATION_CHOICES = (
     ('M', 'Marié'),
 )
 
-class Employe(models.Model):
+class Employe(Metadata):
     # Identification
     id = models.IntegerField(primary_key=True)
     nom = models.CharField(max_length=255)
-    prenom = models.CharField(max_length=255)
+    prenom = models.CharField(max_length=255, verbose_name='Prénom')
     nationalite = models.ForeignKey(ref.Pays, to_field='code', 
                             related_name='employes_nationalite', 
                             db_column='nationalite')
     date_naissance = models.DateField(null=True, blank=True)
+    genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     
     # Infos personnelles
-    genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     situation_famille = models.CharField(max_length=1, null=True, blank=True,
                             choices=SITUATION_CHOICES)
     date_entree = models.DateField(verbose_name="Date d'entrée à l'AUF", 
@@ -214,13 +225,9 @@ class Employe(models.Model):
     pays = models.ForeignKey(ref.Pays, to_field='code', 
                             null=True, blank=True, 
                             related_name='employes', db_column='pays')
-                            
-    # Métas
-    date_creation = models.DateField(auto_now_add=True)
-    date_maj = models.DateField(auto_now=True)  # date_modification
 
     def __unicode__(self):
-        return u'%s %s' % (self.prenom, self.nom)
+        return u'%s %s' % (self.prenom, self.nom.upper())
 
 class EmployePiece(models.Model):
     """Documents relatifs à l'employé
@@ -235,6 +242,7 @@ class EmployePiece(models.Model):
 class EmployeCommentaire(Commentaire):
     employe = models.ForeignKey("Employe")
 
+
 LIEN_PARENTE_CHOICES = (
     ('Conjoint', 'Conjoint'),
     ('Conjointe', 'Conjointe'),
@@ -242,28 +250,27 @@ LIEN_PARENTE_CHOICES = (
     ('Fils', 'Fils'),
 )
 
-class AyantDroit(models.Model):
+class AyantDroit(Metadata):
     # Identification
     id = models.IntegerField(primary_key=True)
     nom = models.CharField(max_length=255)
     prenom = models.CharField(max_length=255)
-    # nationalite facult
-    # date_naissance facultatif
-    # genre facultafif
+    nationalite = models.ForeignKey(ref.Pays, to_field='code', 
+                            related_name='ayantdroits_nationalite', 
+                            db_column='nationalite')
+    date_naissance = models.DateField(null=True, blank=True)
+    genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
     
     # Relation
     employe = models.ForeignKey('Employe', db_column='employe', 
                             related_name='ayants_droit')
     lien_parente = models.CharField(max_length=10, null=True, blank=True, 
                             choices=LIEN_PARENTE_CHOICES)
-                            
-    # Méta
-    commentaire = models.TextField(null=True, blank=True) 
-    actif = models.BooleanField()
 
 class AyantDroitCommentaire(Commentaire):
     ayant_droit = models.ForeignKey("AyantDroit")
 
+
 ### DOSSIER
 
 STATUT_RESIDENCE_CHOICES = (
@@ -277,13 +284,12 @@ COMPTE_COMPTA_CHOICES = (
     ('aucun', 'Aucun'),
 )
 
-class Dossier(models.Model):
+class Dossier(Metadata):
     # Identification
     id = models.IntegerField(primary_key=True)
-    #code = models.CharField(max_length=10, unique=True)
     employe = models.ForeignKey('Employe', db_column='employe')
     poste = models.ForeignKey('Poste', related_name='+', editable=False)
-    statut = models.ForeignKey('Statut', related_name='+')  # blank=True, null=True ?
+    statut = models.ForeignKey('Statut', related_name='+')
     organisme_bstg = models.ForeignKey('OrganismeBstg', 
             null=True, blank=True,
             verbose_name="Organisme", 
@@ -292,38 +298,35 @@ class Dossier(models.Model):
             related_name='+')
         
     # Recrutement
-    remplacement = models.BooleanField()     # default False
+    remplacement = models.BooleanField(default=False)
     statut_residence = models.CharField(max_length=10, default='local', 
-                                        verbose_name="Statut",
-                                        choices=STATUT_RESIDENCE_CHOICES)
+                            verbose_name="Statut",
+                            choices=STATUT_RESIDENCE_CHOICES)
    
     # Rémunération
-    classement = models.ForeignKey(rh.Classement, related_name='+',
-                            null=True, blank=True)
-    regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
-                                         verbose_name="Régime de travail",
-                                         help_text="% du temps complet")     # default = 100
+    classement = models.ForeignKey('Classement', related_name='+',
+                          null=True, blank=True)
+    regime_travail = models.DecimalField(max_digits=12, 
+                            decimal_places=2,
+                            default=REGIME_TRAVAIL_DEFAULT,
+                            verbose_name="Régime de travail",
+                            help_text="% du temps complet")
     regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
-            decimal_places=2, verbose_name="Nb. heures par semaine")    # default = 35
+                            decimal_places=2, 
+                            default=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT,
+                            verbose_name="Nb. heures par semaine")
 
     # Occupation du Poste par cet Employe (anciennement "mandat")
     date_debut = models.DateField(help_text=HELP_TEXT_DATE,
                             verbose_name="Date de début d'occupation de poste")
-    date_fin = models.DateField(help_text=HELP_TEXT_DATE,
-                            null=True, blank=True,
-                            verbose_name="Date de fin d'occupation de poste")
-
-    date_debut = models.DateField(verbose_name="Date de début",
-                                    help_text=HELP_TEXT_DATE)
     date_fin = models.DateField(null=True, blank=True,
-                                    verbose_name="Date de fin",
-                                    help_text=HELP_TEXT_DATE)
+                            help_text=HELP_TEXT_DATE,
+                            verbose_name="Date de fin d'occupation de poste")
     # Contrat
-    # m2m Contrat
+    # TODO : m2m Contrat
     
-    # Méta
-    date_creation = models.DateTimeField(auto_now_add=True)
-    date_modification = models.DateField(auto_now=True)
+    # Comptes
+    # TODO?
     
     def __unicode__(self):
         return u'%s - %s' % (self.poste.nom, self.employe)
@@ -341,34 +344,37 @@ class DossierPiece(models.Model):
 class DossierCommentaire(Commentaire):
     dossier = models.ForeignKey("Dossier")
 
+
 ### RÉMUNÉRATION
     
-class Remuneration(models.Model):
+class RemunerationMixin(Metadata):
     # Identification
     id = models.IntegerField(primary_key=True)
     dossier = models.ForeignKey('Dossier', db_column='dossier')
     type = models.ForeignKey('TypeRemuneration', db_column='type', 
                             related_name='+')
-    # TODO: what's that?
     type_revalorisation = models.ForeignKey('TypeRevalorisation', 
                             db_column='type_revalorisation', 
                             null=True, blank=True)
-    montant = models.FloatField(null=True, blank=True)  # Annuel (12 mois, 52 semaines, 364 jours)
-    devise = models.ForeignKey('Devise', to_field='code', db_column='devise')#, 
-                            #null=True, blank=True)
-    commentaire = models.CharField(max_length=255, null=True, blank=True) # commentaire = precision
-    date_debut = models.DateField(null=True, blank=True)    # anciennement date_effectif
-    #date_fin = null=True
+    montant = models.FloatField(max_digits=12, decimal_places=2, 
+                            null=True, blank=True)
+                            # Annuel (12 mois, 52 semaines, 364 jours?)
+    devise = models.ForeignKey('Devise', to_field='code',
+                               db_column='devise', related_name='+')
+    # commentaire = precision
+    commentaire = models.CharField(max_length=255, null=True, blank=True)
+    # date_debut = anciennement date_effectif
+    date_debut = models.DateField(null=True, blank=True)
+    date_fin = models.DateField(null=True, blank=True)
     
-    # Méta
-    date_creation = models.DateField(auto_now_add=True)
-    user_creation = models.IntegerField(null=True, blank=True) #User ou employé
-#    desactivation = models.BooleanField(null=True, blank=True) #
-#    date_desactivation = models.DateField(null=True, blank=True)
-#    user_desactivation = models.IntegerField(null=True, blank=True) #User ou employé
-#    annulation = models.BooleanField(null=True, blank=True)
-#    date_annulation = models.DateField(null=True, blank=True)
-#    user_annulation = models.IntegerField(null=True, blank=True) #User ou employé
+    class Meta: 
+        abstract = True
+    
+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.    
+    """
 
     def montant_mois(self):
         return round(self.montant / 12, 2)
@@ -389,9 +395,32 @@ class Remuneration(models.Model):
             devise = "???"
         return "%s %s" % (self.montant, devise)
 
-class HistoriqueRemuneration(models.Model):
+
+### CONTRATS
+        
+class Contrat(Metadata):
+    """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.
+    """
     dossier = models.ForeignKey("Dossier")
-    # toujours pertinent si pour chaque Remuneration j'ai dd et df?
+    type_contrat = models.ForeignKey('TypeContrat', related_name='+')
+    date_debut = models.DateField(help_text=HELP_TEXT_DATE)
+    date_fin = models.DateField(null=True, blank=True,
+                                        help_text=HELP_TEXT_DATE)
+    
+
+### ÉVÉNEMENTS
+
+class Evenement(models.Models):
+    pass
+    # nom
+    # date_debut
+    # date_fin
+    
+class EvenementRemuneration(RemunerationMixin):
+    pass
+    # evenement
 
 
 ### RÉFÉRENCES RH 
@@ -525,7 +554,7 @@ class Classement(models.Model):
     type = models.CharField(max_length=10, choices=TYPE_CLASSEMENT_CHOICES)
     echelon = models.IntegerField()
     degre = models.IntegerField()
-    coefficient = models.FloatField()
+    coefficient = models.FloatField(null=True)
     # annee # au lieu de date_debut et date_fin
     # Méta
     commentaire = models.TextField(null=True, blank=True) 
@@ -559,7 +588,8 @@ class ValeurPoint(models.Model):
     # Méta
     annee = models.IntegerField()
 
-    # Stockage de tous les taux de change pour optimiser la recherche de la devise associée
+    # 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)
 
@@ -569,7 +599,8 @@ class ValeurPoint(models.Model):
             devise_code = tx.devise.code
         else:
             devise_code = "??"
-        return u'%s %s (%s-%s)' % (self.valeur, devise_code, self.implantation_id, self.annee)
+        return u'%s %s (%s-%s)' % (self.valeur, devise_code, 
+                            self.implantation_id, self.annee)
         
     class Meta:
         ordering = ['valeur']
@@ -586,7 +617,7 @@ class TypeContrat(models.Model):
     # Identification
     id = models.IntegerField(primary_key=True)
     nom = models.CharField(max_length=255)
-    nom_long = models.CharField(max_length=255) #description
+    nom_long = models.CharField(max_length=255) # description
     categorie = models.CharField(max_length=10, 
                             choices=CONTRAT_CATEGORIE_CHOICES) # A, C?
     # Méta
@@ -595,6 +626,9 @@ class TypeContrat(models.Model):
     def __unicode__(self):
         return u'%s' % (self.nom)
         
+        
+### AUTRES
+
 class ResponsableImplantation(models.Model):
     """Le responsable d'une implantation. 
     Anciennement géré sur le Dossier du responsable.
@@ -607,21 +641,3 @@ class ResponsableImplantation(models.Model):
         
     class Meta:
         ordering = ['implantation__nom']
-        
-class Contrat(models.Model):
-    dossier = models.ForeignKey("Dossier") # 1 contrat peut être dans plusieurs dossier Dossier.contrat = m2m Contrat
-    type_contrat = models.ForeignKey('TypeContrat', related_name='+')
-    date_debut = models.DateField(help_text=HELP_TEXT_DATE)
-    date_fin = models.DateField(null=True, blank=True,
-                                        help_text=HELP_TEXT_DATE)
-    
-class Evenement(models.Models):
-    pass
-    # nom
-    # date_debut
-    # date_fin
-    
-class EvenementRemuneration(models.Model):
-    pass
-    # evenement
-    # structure de rémunération hérité de abstract ici