fix #1448 #1453
[auf_rh_dae.git] / project / rh_v1 / models.py
CommitLineData
a3121a38
AJ
1# -=- encoding: utf-8 -=-
2
6301bd59 3import datetime
a3121a38
AJ
4from django.db import models
5from datamaster_modeles.models import Pays, Implantation
f258e4e7 6from dae.managers import SecurityManager
a3121a38
AJ
7
8GENRE_CHOICES = (
139686f2
NC
9 ('m', 'Homme'),
10 ('f', 'Femme'),
a3121a38
AJ
11)
12SITUATION_CHOICES = (
13 ('C', 'Célibataire'),
14 ('F', 'Fiancé'),
15 ('M', 'Marié'),
16)
17
18class Employe(models.Model):
9afaa55e 19 # Identification
a3121a38
AJ
20 id = models.IntegerField(primary_key=True)
21 nom = models.CharField(max_length=255)
22 prenom = models.CharField(max_length=255)
9afaa55e 23 nationalite = models.ForeignKey('datamaster_modeles.Pays', to_field='code',
24 related_name='nationalite',
25 db_column='nationalite')
a3121a38 26 date_naissance = models.DateField(null=True, blank=True)
9afaa55e 27 # Infos personnelles
28 genre = models.CharField(max_length=1, null=True, blank=True,
29 choices=GENRE_CHOICES)
30 situation_famille = models.CharField(max_length=1, null=True, blank=True,
31 choices=SITUATION_CHOICES)
a3121a38 32 date_entree = models.DateField(null=True, blank=True) #devrait pas être là
9afaa55e 33 # Coordonnées
a3121a38
AJ
34 tel_domicile = models.CharField(max_length=255, null=True, blank=True)
35 tel_cellulaire = models.CharField(max_length=255, null=True, blank=True)
36 adresse = models.CharField(max_length=255, null=True, blank=True)
37 no_rue = models.CharField(max_length=255, null=True, blank=True)
38 ville = models.CharField(max_length=255, null=True, blank=True)
39 province = models.CharField(max_length=255, null=True, blank=True)
40 code_postal = models.CharField(max_length=255, null=True, blank=True)
9afaa55e 41 pays = models.ForeignKey('datamaster_modeles.Pays', to_field='code',
42 null=True, blank=True,
43 related_name='pays', db_column='pays')
44 # Métas
a3121a38
AJ
45 date_creation = models.DateField(auto_now_add=True)
46 date_maj = models.DateField(auto_now=True)
47 commentaire = models.TextField(null=True, blank=True)
139686f2
NC
48
49 def __unicode__(self):
50 return u'%s %s' % (self.prenom, self.nom)
51
52
a3121a38
AJ
53TYPE_DOSSIER_CHOICES = (
54 ('2', 'Local'),
55 ('1', 'Expatrié'),
56)
57
1c7d67ce
OL
58class DossierManager(models.Manager):
59 """
60 Chargement de tous les objets FK existants sur chaque QuerySet.
61 """
62 def get_query_set(self):
63 fkeys = (
64 'employe',
65 'poste1',
66 'implantation1',
67 'poste2',
68 'implantation2',
69 'service',
70 'responsable',
71 'remplacement_de',
72 'statut',
73 'organisme_bstg',
74 'classement',
75 'type_contrat',
76 )
77 return super(DossierManager, self).get_query_set().select_related(*fkeys).all()
78
a3121a38 79class Dossier(models.Model):
9afaa55e 80 # Identification
a3121a38
AJ
81 id = models.IntegerField(primary_key=True)
82 code = models.CharField(max_length=10, unique=True)
83 employe = models.ForeignKey('Employe', db_column='employe')
9afaa55e 84 # Postes
85 poste1 = models.ForeignKey('Poste', db_column='poste1',
86 related_name='poste1')
87 implantation1 = models.ForeignKey('datamaster_modeles.Implantation',
88 db_column='implantation1',
89 related_name='implantation1',
90 blank=True, null=True)
a3121a38
AJ
91 complement1 = models.TextField(null=True, blank=True)
92 responsable_implantation1 = models.IntegerField()
9afaa55e 93 poste2 = models.ForeignKey('Poste', db_column='poste2',
94 related_name='poste2',
95 blank=True, null=True)
96 implantation2 = models.ForeignKey('datamaster_modeles.Implantation',
97 db_column='implantation2',
98 related_name='implantation2',
99 null=True, blank=True)
a3121a38
AJ
100 complement2 = models.TextField(null=True, blank=True)
101 responsable_implantation2 = models.IntegerField()
9afaa55e 102 # Relations
103 service = models.ForeignKey('Service', db_column='service',
104 blank=True, null=True)
105 responsable = models.ForeignKey('Employe', db_column='responsable',
106 related_name='responsable',
107 blank=True, null=True)
108 remplacement_de = models.ForeignKey('Employe', db_column='remplacement_de',
109 related_name='remplacement_de',
110 blank=True, null=True)
a3121a38 111 type = models.CharField(max_length=1, choices=TYPE_DOSSIER_CHOICES)
9afaa55e 112 statut = models.ForeignKey('Statut', db_column='statut',
113 blank=True, null=True)
114 organisme_bstg = models.ForeignKey('OrganismeBstg',
115 db_column='organisme_bstg',
116 blank=True, null=True)
117 # Rémunération
118 classement = models.ForeignKey('Classement', db_column='classement',
119 blank=True, null=True)
a3121a38 120 regime_travail = models.IntegerField()
9afaa55e 121 # Mandat
a3121a38 122 mandat_date_debut = models.DateField()
f48decfd 123 mandat_date_fin = models.DateField(null=True, blank=True)
9afaa55e 124 # Contrat
a3121a38
AJ
125 contrat_date_debut = models.DateField()
126 contrat_date_fin = models.DateField()
9afaa55e 127 type_contrat = models.ForeignKey('TypeContrat', db_column='type_contrat',
128 blank=True, null=True)
129 # Meta
a3121a38
AJ
130 date_creation = models.DateField(auto_now_add=True)
131 date_maj = models.DateField(auto_now=True)
132 commentaire = models.TextField(null=True, blank=True)
133
1c7d67ce
OL
134 # Managers
135 objects = DossierManager()
0f23302a 136
137 def __unicode__(self):
138 return u'%s : %s %s' % (self.employe, self.poste1, self.complement1)
1c7d67ce 139
03b395db
OL
140 def get_dernier_salaire_remun(self):
141 remun = [r for r in self.remuneration_set.all() if r.type_id == 1] # type salaire de base
142 if len(remun) == 0:
143 return None
144 else:
03b395db
OL
145 return remun[0]
146
147 def get_salaire(self):
148 remun = self.get_dernier_salaire_remun()
149 if remun is not None:
150 return int(remun.montant)
151 else:
152 return None
153
7e43f9b6
OL
154 def get_salaire_display(self):
155 """
156 Moyen rapide de récupérer le salaire correspodant à un dossier. Par contre,
157 toutes les rémuérations n'ont pas de devise associées, c'est pourquoi on récupère
158 les anciennes rémunérations pour rechercher si elle existait auparavant.
159 """
d9aed39d
OL
160 if self.dernier_salaire_remun() is not None:
161 devise_code = self.dernier_salaire_remun().devise.code
162 else:
163 devise_code = '???'
164 return "%s %s" % (self.get_salaire(), devise_code, )
62dbbb71
OL
165
166 def get_salaire_euro_display(self):
167 """
168 Moyen rapide de récupérer le salaire correspodant à un dossier. Par contre,
169 toutes les rémuérations n'ont pas de devise associées, c'est pourquoi on récupère
170 les anciennes rémunérations pour rechercher si elle existait auparavant.
171 La valeur est est affichée en Euros en se servant du taux actuel.
172 """
03b395db 173 return "%s EUR" % (self.get_dernier_salaire_remun().en_euros())
7e43f9b6 174
a3121a38
AJ
175LIEN_PARENTE_CHOICES = (
176 ('Conjoint', 'Conjoint'),
177 ('Conjointe', 'Conjointe'),
178 ('Fille', 'Fille'),
179 ('Fils', 'Fils'),
180)
181
182class AyantDroit(models.Model):
9afaa55e 183 # Identification
a3121a38
AJ
184 id = models.IntegerField(primary_key=True)
185 nom = models.CharField(max_length=255)
186 prenom = models.CharField(max_length=255)
9afaa55e 187 # Relation
188 employe = models.ForeignKey('Employe', db_column='employe',
189 related_name='employe')
190 lien_parente = models.CharField(max_length=10, null=True, blank=True,
191 choices=LIEN_PARENTE_CHOICES)
192 # Méta
a3121a38
AJ
193 commentaire = models.TextField(null=True, blank=True)
194 actif = models.BooleanField()
195
196
197class Remuneration(models.Model):
9afaa55e 198 # Identification
a3121a38
AJ
199 id = models.IntegerField(primary_key=True)
200 dossier = models.ForeignKey('Dossier', db_column='dossier')
201 type = models.ForeignKey('TypeRemuneration', db_column='type')
9afaa55e 202 type_revalorisation = models.ForeignKey('TypeRevalorisation',
203 db_column='type_revalorisation',
204 null=True, blank=True)
139686f2 205 montant = models.FloatField(null=True, blank=True)
03b395db 206 devise = models.ForeignKey('Devise', to_field='id', db_column='devise', null=True, blank=True)
139686f2
NC
207 date_effective = models.DateField(null=True, blank=True)
208 pourcentage = models.IntegerField(null=True, blank=True)
9afaa55e 209 # Méta
a3121a38 210 date_creation = models.DateField(auto_now_add=True)
139686f2
NC
211 user_creation = models.IntegerField(null=True, blank=True) #User ou employé
212 desactivation = models.NullBooleanField(null=True, blank=True) #
213 date_desactivation = models.DateField(null=True, blank=True)
214 user_desactivation = models.IntegerField(null=True, blank=True) #User ou employé
215 annulation = models.NullBooleanField(null=True, blank=True)
216 date_annulation = models.DateField(null=True, blank=True)
217 user_annulation = models.IntegerField(null=True, blank=True) #User ou employé
a3121a38 218
7e43f9b6
OL
219 def __unicode__(self):
220 try:
221 devise = self.devise.code
222 except:
223 devise = "???"
03b395db
OL
224 return "%s %s (%s EUR - %s)" % (self.montant, devise, self.en_euros(), self.get_taux_historique(), )
225
226 def get_taux_historique(self):
d9aed39d
OL
227 """
228 Retourne le taux en vigueur durant l'année considérée. Un taux de 0 est crée, si le taux de change
229 n'existe pas.
230 """
231 taux = TauxChange.objects.filter(devise=self.devise, annee=self.date_creation.year)
232 if len(taux) > 0:
233 return taux[0]
234 else:
235 return None
03b395db
OL
236
237 def en_euros(self):
d9aed39d
OL
238 tauxchange = self.get_taux_historique()
239 if tauxchange is not None:
240 return int(self.montant * tauxchange.taux)
241 else:
242 return 0
7e43f9b6 243
a3121a38 244class FamilleEmploi(models.Model):
9afaa55e 245 # Identification
a3121a38
AJ
246 id = models.IntegerField(primary_key=True)
247 nom = models.CharField(max_length=255)
9afaa55e 248 # Méta
a3121a38
AJ
249 actif = models.BooleanField()
250
251class TypePoste(models.Model):
9afaa55e 252 # Identification
a3121a38
AJ
253 id = models.IntegerField(primary_key=True)
254 nom = models.CharField(max_length=255)
255 nom_feminin = models.CharField(max_length=255)
256 description = models.CharField(max_length=255)
257 is_responsable = models.BooleanField()
9afaa55e 258 famille_emploi = models.ForeignKey('FamilleEmploi',
259 db_column='famille_emploi')
260 # Méta
a3121a38
AJ
261 date_modification = models.DateField(auto_now=True)
262 actif = models.BooleanField()
263
5d680e84
NC
264 def __unicode__(self):
265 return u'%s' % self.nom
6d704629 266
267 class Meta:
268 ordering = ['nom']
5d680e84
NC
269
270
a3121a38
AJ
271TYPE_PAIEMENT_CHOICES = (
272 ('Régulier', 'Régulier'),
273 ('Ponctuel', 'Ponctuel'),
274)
275
276NATURE_REMUNERATION_CHOICES = (
277 ('Accessoire', 'Accessoire'),
278 ('Charges', 'Charges'),
279 ('Indemnité', 'Indemnité'),
280 ('RAS', 'RAS'),
281 ('Traitement', 'Traitement'),
282)
283
284class TypeRemuneration(models.Model):
9afaa55e 285 # Identification
a3121a38
AJ
286 id = models.IntegerField(primary_key=True)
287 nom = models.CharField(max_length=255)
9afaa55e 288 type_paiement = models.CharField(max_length=30,
289 choices=TYPE_PAIEMENT_CHOICES)
290 nature_remuneration = models.CharField(max_length=30,
291 choices=NATURE_REMUNERATION_CHOICES)
292 # Méta
a3121a38 293 actif = models.BooleanField()
cb1d62b5
NC
294
295 def __unicode__(self):
296 return u'%s' % self.nom
297
298
a3121a38 299class TypeRevalorisation(models.Model):
9afaa55e 300 # Identification
a3121a38
AJ
301 id = models.IntegerField(primary_key=True)
302 nom = models.CharField(max_length=255)
9afaa55e 303 # Méta
a3121a38
AJ
304 actif = models.BooleanField()
305
306PROPORTION_CHOICES = (
307 ('0.5', '0.5'),
308 ('1', '1'),
309)
310
f258e4e7 311class PosteManager(SecurityManager):
1c7d67ce
OL
312 """
313 Chargement de tous les objets FK existants sur chaque QuerySet.
314 """
f258e4e7
OL
315 prefixe_implantation = 'implantation'
316
1c7d67ce
OL
317 def get_query_set(self):
318 fkeys = (
319 'implantation',
320 'type_poste',
321 )
322 return super(PosteManager, self).get_query_set().select_related(*fkeys).all()
323
a3121a38 324class Poste(models.Model):
9afaa55e 325 # Identification
a3121a38 326 id = models.IntegerField(primary_key=True)
5d680e84 327 implantation = models.ForeignKey('datamaster_modeles.Implantation',
9afaa55e 328 db_column='implantation', related_name='+')
a3121a38
AJ
329 type_poste = models.ForeignKey('TypePoste', db_column='type_poste')
330 proportion = models.CharField(max_length=10, choices=PROPORTION_CHOICES)
331 #(sert à quoi?) renommer "regime_travail" ou autre? convertir data en % (data * 100; ex: 1 = 100%)
9afaa55e 332 # Méta
a3121a38
AJ
333 date_modification = models.DateField(auto_now=True)
334 actif = models.BooleanField()
335
1c7d67ce
OL
336 # Managers
337 objects = PosteManager()
338
5d680e84 339 def __unicode__(self):
9afaa55e 340 return u'%s - %s [%s]' % (self.implantation, self.type_poste.nom,
341 self.id)
5d680e84
NC
342
343
a3121a38 344class Service(models.Model):
9afaa55e 345 # Identification
a3121a38
AJ
346 id = models.IntegerField(primary_key=True)
347 nom = models.CharField(max_length=255)
9afaa55e 348 # Méta
a3121a38
AJ
349 actif = models.BooleanField()
350
5d680e84
NC
351 def __unicode__(self):
352 return u'%s' % self.nom
6d704629 353
354 class Meta:
355 ordering = ['nom']
5d680e84
NC
356
357
a3121a38
AJ
358TYPE_ORGANISME_CHOICES = (
359 ('MAD', 'Mise à disposition'),
360 ('DET', 'Détachement'),
361)
362
363class OrganismeBstg(models.Model):
9afaa55e 364 # Identification
a3121a38
AJ
365 id = models.IntegerField(primary_key=True)
366 nom = models.CharField(max_length=255)
367 type = models.CharField(max_length=10, choices=TYPE_ORGANISME_CHOICES)
9afaa55e 368 # Méta
a3121a38
AJ
369 actif = models.BooleanField()
370
139686f2
NC
371 def __unicode__(self):
372 return u'%s (%s)' % (self.nom, self.type)
373
0f23302a 374 class Meta:
375 ordering = ['type', 'nom']
376
139686f2 377
a3121a38
AJ
378CONTRAT_CATEGORIE_CHOICES= (
379 ('A', 'A'),
380 ('C', 'C'),
381)
382class Statut(models.Model):
9afaa55e 383 # Identification
a3121a38
AJ
384 id = models.IntegerField(primary_key=True)
385 code = models.CharField(max_length=25, unique=True)
386 nom = models.CharField(max_length=255)
9afaa55e 387 type_contrat_categorie = models.CharField(max_length=10,
388 choices=CONTRAT_CATEGORIE_CHOICES)
a3121a38 389 #CHOICES A, C (veut dire quoi?) voir TypeContrat.categorie
9afaa55e 390 # Méta
a3121a38
AJ
391 actif = models.BooleanField()
392
139686f2 393 def __unicode__(self):
0f23302a 394 return u'%s : %s' % (self.code, self.nom)
139686f2 395
a3121a38
AJ
396TYPE_CLASSEMENT_CHOICES = (
397 ('S', 'S'),
398 ('T', 'T'),
399)
aa50a11e
OL
400
401class ClassementManager(models.Manager):
402 """
403 Ordonner les spcéfiquement les classements.
404 """
405 def get_query_set(self):
406 qs = super(self.__class__, self).get_query_set()
407 qs = qs.extra(select={'ponderation': 'FIND_IN_SET(type,"SO,HG,S,T,P,C,D")'})
408 qs = qs.extra(order_by=('ponderation', ))
409 return qs.all()
410
411
a3121a38 412class Classement(models.Model):
9afaa55e 413 # Identification
a3121a38
AJ
414 id = models.IntegerField(primary_key=True)
415 type = models.CharField(max_length=10, choices=TYPE_CLASSEMENT_CHOICES)
416 echelon = models.IntegerField()
417 degre = models.IntegerField()
418 coefficient = models.FloatField()
9afaa55e 419 # Méta
a3121a38
AJ
420 commentaire = models.TextField(null=True, blank=True)
421 date_modification = models.DateField(auto_now=True)
422 actif = models.BooleanField()
423
aa50a11e
OL
424 # managers
425 objects = ClassementManager()
426
5d680e84 427 def __unicode__(self):
aa50a11e
OL
428 return u'%s.%s.%s' % (self.type, self.echelon, self.degre )
429
e57fb3d8 430 class Meta:
431 ordering = ['type','echelon','degre','coefficient']
5d680e84 432
6301bd59 433class TauxChange(models.Model):
9afaa55e 434 # Identification
6301bd59 435 id = models.IntegerField(primary_key=True)
d9aed39d 436 devise = models.ForeignKey('Devise', to_field='id', db_column='devise')
6301bd59
OL
437 annee = models.IntegerField()
438 taux = models.FloatField()
9afaa55e 439 # Relations
440 implantation = models.ForeignKey('datamaster_modeles.Implantation',
441 db_column='implantation',
442 related_name='taux_change')
6301bd59 443
03b395db
OL
444 def __unicode__(self):
445 return u"%s %s : %s" % (self.devise, self.annee, self.taux)
446
6301bd59
OL
447class ValeurPointManager(models.Manager):
448 """
449 Manager qui travaille uniquement sur les valeurs du point de l'année en cours.
450 """
451 mois = datetime.datetime.now().month
452 annee_courante = datetime.datetime.now().year
453
454 # Pour le mois de janvier et décembre on mets les 2 années pour faire la transition
455 if mois == 1:
456 filtre_annee = (annee_courante-1, annee_courante)
457 elif mois == 12:
458 filtre_annee = (annee_courante, annee_courante+1)
459 else:
460 filtre_annee = (annee_courante,)
461
462 def get_query_set(self):
463 return super(ValeurPointManager, self).get_query_set().select_related('implantation').filter(annee__in=self.filtre_annee)
464
5d680e84 465
a3121a38 466class ValeurPoint(models.Model):
9afaa55e 467 # Identification
a3121a38
AJ
468 id = models.IntegerField(primary_key=True)
469 valeur = models.FloatField()
9afaa55e 470 implantation = models.ForeignKey('datamaster_modeles.Implantation',
471 db_column='implantation',
472 related_name='valeurs_point')
473 # Méta
a3121a38 474 annee = models.IntegerField()
6301bd59
OL
475
476 # Stockage de tous les taux de change pour optimiser la recherche de la devise associée
477 annee_courante = datetime.datetime.now().year
478 tauxchange = TauxChange.objects.select_related('devise').filter(annee=annee_courante)
479
480 def get_tauxchange_courant(self):
481 """
482 Recherche le taux courant associé à la valeur d'un point.
483 Tous les taux de l'année courante sont chargés, pour optimiser un affichage en liste.
484 (On pourrait probablement améliorer le manager pour lui greffer le taux courant sous forme de JOIN)
485 """
486 for tauxchange in self.tauxchange:
487 if tauxchange.implantation_id == self.implantation_id:
488 return tauxchange
489 return None
a3121a38 490
5d680e84 491 def __unicode__(self):
17353922
OL
492 tx = self.get_tauxchange_courant()
493 if tx:
494 devise_code = tx.devise.code
495 else:
496 devise_code = "??"
da3ca955 497 return u'%s %s (%s-%s)' % (self.valeur, devise_code, self.implantation_id, self.annee)
6d704629 498
499 class Meta:
500 ordering = ['valeur']
5d680e84 501
4dd75e7b 502 objects = models.Manager()
6301bd59 503 actuelles = ValeurPointManager()
a3121a38 504
5d680e84 505
a3121a38
AJ
506class Devise(models.Model):
507 id = models.IntegerField(primary_key=True)
508 code = models.CharField(max_length=10, unique=True)
509 nom = models.CharField(max_length=255)
510
5d680e84
NC
511 def __unicode__(self):
512 return u'%s - %s' % (self.code, self.nom)
513
514
a3121a38 515class TypeContrat(models.Model):
9afaa55e 516 # Identification
a3121a38
AJ
517 id = models.IntegerField(primary_key=True)
518 nom = models.CharField(max_length=255)
519 nom_long = models.CharField(max_length=255) #description
9afaa55e 520 categorie = models.CharField(max_length=10,
521 choices=CONTRAT_CATEGORIE_CHOICES)
522 # Méta
a3121a38
AJ
523 actif = models.BooleanField()
524
139686f2 525 def __unicode__(self):
0f23302a 526 return u'%s' % (self.nom)