[#2518] Scripts de migration du RH en PHP vers le nouveau système RH
[auf_rh_dae.git] / project / rh_v1 / models.py
CommitLineData
a3121a38
AJ
1# -=- encoding: utf-8 -=-
2
6301bd59 3import datetime
a3121a38 4from django.db import models
bf6f2712 5from auf.django.references.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)
bf6f2712 23 nationalite = models.ForeignKey(Pays, to_field='code',
9afaa55e 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)
bf6f2712 41 pays = models.ForeignKey(Pays, to_field='code',
9afaa55e 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')
bf6f2712 90 implantation1 = models.ForeignKey(Implantation,
9afaa55e 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)
bf6f2712 99 implantation2 = models.ForeignKey(Implantation,
9afaa55e 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 318 prefixe_implantation = "implantation__region"
f258e4e7 319
1c7d67ce
OL
320 def get_query_set(self):
321 fkeys = (
322 'implantation',
323 'type_poste',
324 )
325 return super(PosteManager, self).get_query_set().select_related(*fkeys).all()
326
a3121a38 327class Poste(models.Model):
9afaa55e 328 # Identification
a3121a38 329 id = models.IntegerField(primary_key=True)
bf6f2712 330 implantation = models.ForeignKey(Implantation,
9afaa55e 331 db_column='implantation', related_name='+')
a3121a38
AJ
332 type_poste = models.ForeignKey('TypePoste', db_column='type_poste')
333 proportion = models.CharField(max_length=10, choices=PROPORTION_CHOICES)
334 #(sert à quoi?) renommer "regime_travail" ou autre? convertir data en % (data * 100; ex: 1 = 100%)
9afaa55e 335 # Méta
a3121a38
AJ
336 date_modification = models.DateField(auto_now=True)
337 actif = models.BooleanField()
338
1c7d67ce
OL
339 # Managers
340 objects = PosteManager()
341
5d680e84 342 def __unicode__(self):
9afaa55e 343 return u'%s - %s [%s]' % (self.implantation, self.type_poste.nom,
344 self.id)
5d680e84
NC
345
346
a3121a38 347class Service(models.Model):
9afaa55e 348 # Identification
a3121a38
AJ
349 id = models.IntegerField(primary_key=True)
350 nom = models.CharField(max_length=255)
9afaa55e 351 # Méta
a3121a38
AJ
352 actif = models.BooleanField()
353
5d680e84
NC
354 def __unicode__(self):
355 return u'%s' % self.nom
6d704629 356
357 class Meta:
358 ordering = ['nom']
5d680e84
NC
359
360
a3121a38
AJ
361TYPE_ORGANISME_CHOICES = (
362 ('MAD', 'Mise à disposition'),
363 ('DET', 'Détachement'),
364)
365
366class OrganismeBstg(models.Model):
9afaa55e 367 # Identification
a3121a38
AJ
368 id = models.IntegerField(primary_key=True)
369 nom = models.CharField(max_length=255)
370 type = models.CharField(max_length=10, choices=TYPE_ORGANISME_CHOICES)
9afaa55e 371 # Méta
a3121a38
AJ
372 actif = models.BooleanField()
373
139686f2
NC
374 def __unicode__(self):
375 return u'%s (%s)' % (self.nom, self.type)
376
0f23302a 377 class Meta:
378 ordering = ['type', 'nom']
379
139686f2 380
a3121a38
AJ
381CONTRAT_CATEGORIE_CHOICES= (
382 ('A', 'A'),
383 ('C', 'C'),
384)
385class Statut(models.Model):
9afaa55e 386 # Identification
a3121a38
AJ
387 id = models.IntegerField(primary_key=True)
388 code = models.CharField(max_length=25, unique=True)
389 nom = models.CharField(max_length=255)
9afaa55e 390 type_contrat_categorie = models.CharField(max_length=10,
391 choices=CONTRAT_CATEGORIE_CHOICES)
a3121a38 392 #CHOICES A, C (veut dire quoi?) voir TypeContrat.categorie
9afaa55e 393 # Méta
a3121a38
AJ
394 actif = models.BooleanField()
395
139686f2 396 def __unicode__(self):
0f23302a 397 return u'%s : %s' % (self.code, self.nom)
139686f2 398
a3121a38
AJ
399TYPE_CLASSEMENT_CHOICES = (
400 ('S', 'S'),
401 ('T', 'T'),
402)
d8813f19
OL
403
404class ClassementManager(models.Manager):
405 """
406 Ordonner les spcéfiquement les classements.
407 """
408 def get_query_set(self):
409 qs = super(self.__class__, self).get_query_set()
410 qs = qs.extra(select={'ponderation': 'FIND_IN_SET(type,"SO,HG,S,T,P,C,D")'})
411 qs = qs.extra(order_by=('ponderation', ))
412 return qs.all()
413
414
a3121a38 415class Classement(models.Model):
9afaa55e 416 # Identification
a3121a38
AJ
417 id = models.IntegerField(primary_key=True)
418 type = models.CharField(max_length=10, choices=TYPE_CLASSEMENT_CHOICES)
419 echelon = models.IntegerField()
420 degre = models.IntegerField()
421 coefficient = models.FloatField()
9afaa55e 422 # Méta
a3121a38
AJ
423 commentaire = models.TextField(null=True, blank=True)
424 date_modification = models.DateField(auto_now=True)
425 actif = models.BooleanField()
426
d8813f19
OL
427 # managers
428 objects = ClassementManager()
429
5d680e84 430 def __unicode__(self):
d8813f19
OL
431 return u'%s.%s.%s' % (self.type, self.echelon, self.degre )
432
e57fb3d8 433 class Meta:
434 ordering = ['type','echelon','degre','coefficient']
5d680e84 435
6301bd59 436class TauxChange(models.Model):
9afaa55e 437 # Identification
6301bd59 438 id = models.IntegerField(primary_key=True)
b1f7765e 439 devise = models.ForeignKey('Devise', to_field='id', db_column='devise')
6301bd59
OL
440 annee = models.IntegerField()
441 taux = models.FloatField()
9afaa55e 442 # Relations
bf6f2712 443 implantation = models.ForeignKey(Implantation,
9afaa55e 444 db_column='implantation',
445 related_name='taux_change')
6301bd59 446
03b395db
OL
447 def __unicode__(self):
448 return u"%s %s : %s" % (self.devise, self.annee, self.taux)
449
6301bd59
OL
450class ValeurPointManager(models.Manager):
451 """
452 Manager qui travaille uniquement sur les valeurs du point de l'année en cours.
453 """
454 mois = datetime.datetime.now().month
455 annee_courante = datetime.datetime.now().year
456
457 # Pour le mois de janvier et décembre on mets les 2 années pour faire la transition
458 if mois == 1:
459 filtre_annee = (annee_courante-1, annee_courante)
460 elif mois == 12:
461 filtre_annee = (annee_courante, annee_courante+1)
462 else:
463 filtre_annee = (annee_courante,)
464
465 def get_query_set(self):
466 return super(ValeurPointManager, self).get_query_set().select_related('implantation').filter(annee__in=self.filtre_annee)
467
5d680e84 468
a3121a38 469class ValeurPoint(models.Model):
9afaa55e 470 # Identification
a3121a38
AJ
471 id = models.IntegerField(primary_key=True)
472 valeur = models.FloatField()
bf6f2712 473 implantation = models.ForeignKey(Implantation,
9afaa55e 474 db_column='implantation',
475 related_name='valeurs_point')
476 # Méta
a3121a38 477 annee = models.IntegerField()
6301bd59
OL
478
479 # Stockage de tous les taux de change pour optimiser la recherche de la devise associée
480 annee_courante = datetime.datetime.now().year
481 tauxchange = TauxChange.objects.select_related('devise').filter(annee=annee_courante)
482
483 def get_tauxchange_courant(self):
484 """
485 Recherche le taux courant associé à la valeur d'un point.
486 Tous les taux de l'année courante sont chargés, pour optimiser un affichage en liste.
487 (On pourrait probablement améliorer le manager pour lui greffer le taux courant sous forme de JOIN)
488 """
489 for tauxchange in self.tauxchange:
490 if tauxchange.implantation_id == self.implantation_id:
491 return tauxchange
492 return None
a3121a38 493
5d680e84 494 def __unicode__(self):
17353922
OL
495 tx = self.get_tauxchange_courant()
496 if tx:
497 devise_code = tx.devise.code
498 else:
499 devise_code = "??"
09a606d0 500 return u'%s %s (%s-%s)' % (self.valeur, devise_code, self.implantation.nom, self.annee)
6d704629 501
502 class Meta:
503 ordering = ['valeur']
5d680e84 504
4dd75e7b 505 objects = models.Manager()
6301bd59 506 actuelles = ValeurPointManager()
a3121a38 507
ae5c920b
OL
508class DeviseManager(models.Manager):
509 """
510 On oublie le US et le CAN
511 """
512 def get_query_set(self):
513 return super(DeviseManager, self).get_query_set().exclude(id__in=(3, 15))
5d680e84 514
a3121a38 515class Devise(models.Model):
ae5c920b
OL
516
517 objects = DeviseManager()
518
a3121a38
AJ
519 id = models.IntegerField(primary_key=True)
520 code = models.CharField(max_length=10, unique=True)
521 nom = models.CharField(max_length=255)
522
5d680e84
NC
523 def __unicode__(self):
524 return u'%s - %s' % (self.code, self.nom)
525
526
a3121a38 527class TypeContrat(models.Model):
9afaa55e 528 # Identification
a3121a38
AJ
529 id = models.IntegerField(primary_key=True)
530 nom = models.CharField(max_length=255)
531 nom_long = models.CharField(max_length=255) #description
9afaa55e 532 categorie = models.CharField(max_length=10,
533 choices=CONTRAT_CATEGORIE_CHOICES)
534 # Méta
a3121a38
AJ
535 actif = models.BooleanField()
536
139686f2 537 def __unicode__(self):
0f23302a 538 return u'%s' % (self.nom)