activé l'app budget
[auf_rh_dae.git] / project / rh_v1 / models.py
1 # -=- encoding: utf-8 -=-
2
3 import datetime
4 from django.db import models
5 from datamaster_modeles.models import Pays, Implantation
6 from dae.managers import SecurityManager
7
8 GENRE_CHOICES = (
9 ('m', 'Homme'),
10 ('f', 'Femme'),
11 )
12 SITUATION_CHOICES = (
13 ('C', 'Célibataire'),
14 ('F', 'Fiancé'),
15 ('M', 'Marié'),
16 )
17
18 class Employe(models.Model):
19 # Identification
20 id = models.IntegerField(primary_key=True)
21 nom = models.CharField(max_length=255)
22 prenom = models.CharField(max_length=255)
23 nationalite = models.ForeignKey('datamaster_modeles.Pays', to_field='code',
24 related_name='nationalite',
25 db_column='nationalite')
26 date_naissance = models.DateField(null=True, blank=True)
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)
32 date_entree = models.DateField(null=True, blank=True) #devrait pas être là
33 # Coordonnées
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)
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
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)
48
49 def __unicode__(self):
50 return u'%s %s' % (self.prenom, self.nom)
51
52
53 TYPE_DOSSIER_CHOICES = (
54 ('2', 'Local'),
55 ('1', 'Expatrié'),
56 )
57
58 class DossierManager(models.Manager):
59 """
60 Chargement de tous les objets FK existants sur chaque QuerySet.
61 """
62 prefixe_service = "poste1__service"
63 prefixe_implantation = "poste1__implantation__region"
64
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
82 class Dossier(models.Model):
83 # Identification
84 id = models.IntegerField(primary_key=True)
85 code = models.CharField(max_length=10, unique=True)
86 employe = models.ForeignKey('Employe', db_column='employe')
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)
94 complement1 = models.TextField(null=True, blank=True)
95 responsable_implantation1 = models.IntegerField()
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)
103 complement2 = models.TextField(null=True, blank=True)
104 responsable_implantation2 = models.IntegerField()
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)
114 type = models.CharField(max_length=1, choices=TYPE_DOSSIER_CHOICES)
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)
123 regime_travail = models.IntegerField()
124 # Mandat
125 mandat_date_debut = models.DateField()
126 mandat_date_fin = models.DateField(null=True, blank=True)
127 # Contrat
128 contrat_date_debut = models.DateField()
129 contrat_date_fin = models.DateField()
130 type_contrat = models.ForeignKey('TypeContrat', db_column='type_contrat',
131 blank=True, null=True)
132 # Meta
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
137 # Managers
138 objects = DossierManager()
139
140 def __unicode__(self):
141 return u'%s : %s %s' % (self.employe, self.poste1, self.complement1)
142
143 def get_dernier_salaire_remun(self):
144 remun = [r for r in self.remuneration_set.all() if r.type_id == 1] # type salaire de base
145 if len(remun) == 0:
146 return None
147 else:
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
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 """
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, )
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 """
176 return "%s EUR" % (self.get_dernier_salaire_remun().en_euros())
177
178 LIEN_PARENTE_CHOICES = (
179 ('Conjoint', 'Conjoint'),
180 ('Conjointe', 'Conjointe'),
181 ('Fille', 'Fille'),
182 ('Fils', 'Fils'),
183 )
184
185 class AyantDroit(models.Model):
186 # Identification
187 id = models.IntegerField(primary_key=True)
188 nom = models.CharField(max_length=255)
189 prenom = models.CharField(max_length=255)
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
196 commentaire = models.TextField(null=True, blank=True)
197 actif = models.BooleanField()
198
199
200 class Remuneration(models.Model):
201 # Identification
202 id = models.IntegerField(primary_key=True)
203 dossier = models.ForeignKey('Dossier', db_column='dossier')
204 type = models.ForeignKey('TypeRemuneration', db_column='type')
205 type_revalorisation = models.ForeignKey('TypeRevalorisation',
206 db_column='type_revalorisation',
207 null=True, blank=True)
208 montant = models.FloatField(null=True, blank=True)
209 devise = models.ForeignKey('Devise', to_field='id', db_column='devise', null=True, blank=True)
210 date_effective = models.DateField(null=True, blank=True)
211 pourcentage = models.IntegerField(null=True, blank=True)
212 # Méta
213 date_creation = models.DateField(auto_now_add=True)
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é
221
222 def __unicode__(self):
223 try:
224 devise = self.devise.code
225 except:
226 devise = "???"
227 return "%s %s (%s EUR - %s)" % (self.montant, devise, self.en_euros(), self.get_taux_historique(), )
228
229 def get_taux_historique(self):
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
239
240 def en_euros(self):
241 tauxchange = self.get_taux_historique()
242 if tauxchange is not None:
243 return int(self.montant * tauxchange.taux)
244 else:
245 return 0
246
247 class FamilleEmploi(models.Model):
248 # Identification
249 id = models.IntegerField(primary_key=True)
250 nom = models.CharField(max_length=255)
251 # Méta
252 actif = models.BooleanField()
253
254 class TypePoste(models.Model):
255 # Identification
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()
261 famille_emploi = models.ForeignKey('FamilleEmploi',
262 db_column='famille_emploi')
263 # Méta
264 date_modification = models.DateField(auto_now=True)
265 actif = models.BooleanField()
266
267 def __unicode__(self):
268 return u'%s' % self.nom
269
270 class Meta:
271 ordering = ['nom']
272
273
274 TYPE_PAIEMENT_CHOICES = (
275 ('Régulier', 'Régulier'),
276 ('Ponctuel', 'Ponctuel'),
277 )
278
279 NATURE_REMUNERATION_CHOICES = (
280 ('Accessoire', 'Accessoire'),
281 ('Charges', 'Charges'),
282 ('Indemnité', 'Indemnité'),
283 ('RAS', 'RAS'),
284 ('Traitement', 'Traitement'),
285 )
286
287 class TypeRemuneration(models.Model):
288 # Identification
289 id = models.IntegerField(primary_key=True)
290 nom = models.CharField(max_length=255)
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
296 actif = models.BooleanField()
297
298 def __unicode__(self):
299 return u'%s' % self.nom
300
301
302 class TypeRevalorisation(models.Model):
303 # Identification
304 id = models.IntegerField(primary_key=True)
305 nom = models.CharField(max_length=255)
306 # Méta
307 actif = models.BooleanField()
308
309 PROPORTION_CHOICES = (
310 ('0.5', '0.5'),
311 ('1', '1'),
312 )
313
314 class PosteManager(SecurityManager):
315 """
316 Chargement de tous les objets FK existants sur chaque QuerySet.
317 """
318 prefixe_service = "service"
319 prefixe_implantation = "implantation__region"
320
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
328 class Poste(models.Model):
329 # Identification
330 id = models.IntegerField(primary_key=True)
331 implantation = models.ForeignKey('datamaster_modeles.Implantation',
332 db_column='implantation', related_name='+')
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%)
336 # Méta
337 date_modification = models.DateField(auto_now=True)
338 actif = models.BooleanField()
339
340 # Managers
341 objects = PosteManager()
342
343 def __unicode__(self):
344 return u'%s - %s [%s]' % (self.implantation, self.type_poste.nom,
345 self.id)
346
347
348 class Service(models.Model):
349 # Identification
350 id = models.IntegerField(primary_key=True)
351 nom = models.CharField(max_length=255)
352 # Méta
353 actif = models.BooleanField()
354
355 def __unicode__(self):
356 return u'%s' % self.nom
357
358 class Meta:
359 ordering = ['nom']
360
361
362 TYPE_ORGANISME_CHOICES = (
363 ('MAD', 'Mise à disposition'),
364 ('DET', 'Détachement'),
365 )
366
367 class OrganismeBstg(models.Model):
368 # Identification
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)
372 # Méta
373 actif = models.BooleanField()
374
375 def __unicode__(self):
376 return u'%s (%s)' % (self.nom, self.type)
377
378 class Meta:
379 ordering = ['type', 'nom']
380
381
382 CONTRAT_CATEGORIE_CHOICES= (
383 ('A', 'A'),
384 ('C', 'C'),
385 )
386 class Statut(models.Model):
387 # Identification
388 id = models.IntegerField(primary_key=True)
389 code = models.CharField(max_length=25, unique=True)
390 nom = models.CharField(max_length=255)
391 type_contrat_categorie = models.CharField(max_length=10,
392 choices=CONTRAT_CATEGORIE_CHOICES)
393 #CHOICES A, C (veut dire quoi?) voir TypeContrat.categorie
394 # Méta
395 actif = models.BooleanField()
396
397 def __unicode__(self):
398 return u'%s : %s' % (self.code, self.nom)
399
400 TYPE_CLASSEMENT_CHOICES = (
401 ('S', 'S'),
402 ('T', 'T'),
403 )
404
405 class 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
416 class Classement(models.Model):
417 # Identification
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()
423 # Méta
424 commentaire = models.TextField(null=True, blank=True)
425 date_modification = models.DateField(auto_now=True)
426 actif = models.BooleanField()
427
428 # managers
429 objects = ClassementManager()
430
431 def __unicode__(self):
432 return u'%s.%s.%s' % (self.type, self.echelon, self.degre )
433
434 class Meta:
435 ordering = ['type','echelon','degre','coefficient']
436
437 class TauxChange(models.Model):
438 # Identification
439 id = models.IntegerField(primary_key=True)
440 devise = models.ForeignKey('Devise', to_field='id', db_column='devise')
441 annee = models.IntegerField()
442 taux = models.FloatField()
443 # Relations
444 implantation = models.ForeignKey('datamaster_modeles.Implantation',
445 db_column='implantation',
446 related_name='taux_change')
447
448 def __unicode__(self):
449 return u"%s %s : %s" % (self.devise, self.annee, self.taux)
450
451 class 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
469
470 class ValeurPoint(models.Model):
471 # Identification
472 id = models.IntegerField(primary_key=True)
473 valeur = models.FloatField()
474 implantation = models.ForeignKey('datamaster_modeles.Implantation',
475 db_column='implantation',
476 related_name='valeurs_point')
477 # Méta
478 annee = models.IntegerField()
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
494
495 def __unicode__(self):
496 tx = self.get_tauxchange_courant()
497 if tx:
498 devise_code = tx.devise.code
499 else:
500 devise_code = "??"
501 return u'%s %s (%s-%s)' % (self.valeur, devise_code, self.implantation_id, self.annee)
502
503 class Meta:
504 ordering = ['valeur']
505
506 objects = models.Manager()
507 actuelles = ValeurPointManager()
508
509
510 class Devise(models.Model):
511 id = models.IntegerField(primary_key=True)
512 code = models.CharField(max_length=10, unique=True)
513 nom = models.CharField(max_length=255)
514
515 def __unicode__(self):
516 return u'%s - %s' % (self.code, self.nom)
517
518
519 class TypeContrat(models.Model):
520 # Identification
521 id = models.IntegerField(primary_key=True)
522 nom = models.CharField(max_length=255)
523 nom_long = models.CharField(max_length=255) #description
524 categorie = models.CharField(max_length=10,
525 choices=CONTRAT_CATEGORIE_CHOICES)
526 # Méta
527 actif = models.BooleanField()
528
529 def __unicode__(self):
530 return u'%s' % (self.nom)