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