fix #1448 #1453
[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 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
79 class Dossier(models.Model):
80 # Identification
81 id = models.IntegerField(primary_key=True)
82 code = models.CharField(max_length=10, unique=True)
83 employe = models.ForeignKey('Employe', db_column='employe')
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)
91 complement1 = models.TextField(null=True, blank=True)
92 responsable_implantation1 = models.IntegerField()
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)
100 complement2 = models.TextField(null=True, blank=True)
101 responsable_implantation2 = models.IntegerField()
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)
111 type = models.CharField(max_length=1, choices=TYPE_DOSSIER_CHOICES)
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)
120 regime_travail = models.IntegerField()
121 # Mandat
122 mandat_date_debut = models.DateField()
123 mandat_date_fin = models.DateField(null=True, blank=True)
124 # Contrat
125 contrat_date_debut = models.DateField()
126 contrat_date_fin = models.DateField()
127 type_contrat = models.ForeignKey('TypeContrat', db_column='type_contrat',
128 blank=True, null=True)
129 # Meta
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
134 # Managers
135 objects = DossierManager()
136
137 def __unicode__(self):
138 return u'%s : %s %s' % (self.employe, self.poste1, self.complement1)
139
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:
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
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 """
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, )
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 """
173 return "%s EUR" % (self.get_dernier_salaire_remun().en_euros())
174
175 LIEN_PARENTE_CHOICES = (
176 ('Conjoint', 'Conjoint'),
177 ('Conjointe', 'Conjointe'),
178 ('Fille', 'Fille'),
179 ('Fils', 'Fils'),
180 )
181
182 class AyantDroit(models.Model):
183 # Identification
184 id = models.IntegerField(primary_key=True)
185 nom = models.CharField(max_length=255)
186 prenom = models.CharField(max_length=255)
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
193 commentaire = models.TextField(null=True, blank=True)
194 actif = models.BooleanField()
195
196
197 class Remuneration(models.Model):
198 # Identification
199 id = models.IntegerField(primary_key=True)
200 dossier = models.ForeignKey('Dossier', db_column='dossier')
201 type = models.ForeignKey('TypeRemuneration', db_column='type')
202 type_revalorisation = models.ForeignKey('TypeRevalorisation',
203 db_column='type_revalorisation',
204 null=True, blank=True)
205 montant = models.FloatField(null=True, blank=True)
206 devise = models.ForeignKey('Devise', to_field='id', db_column='devise', null=True, blank=True)
207 date_effective = models.DateField(null=True, blank=True)
208 pourcentage = models.IntegerField(null=True, blank=True)
209 # Méta
210 date_creation = models.DateField(auto_now_add=True)
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é
218
219 def __unicode__(self):
220 try:
221 devise = self.devise.code
222 except:
223 devise = "???"
224 return "%s %s (%s EUR - %s)" % (self.montant, devise, self.en_euros(), self.get_taux_historique(), )
225
226 def get_taux_historique(self):
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
236
237 def en_euros(self):
238 tauxchange = self.get_taux_historique()
239 if tauxchange is not None:
240 return int(self.montant * tauxchange.taux)
241 else:
242 return 0
243
244 class FamilleEmploi(models.Model):
245 # Identification
246 id = models.IntegerField(primary_key=True)
247 nom = models.CharField(max_length=255)
248 # Méta
249 actif = models.BooleanField()
250
251 class TypePoste(models.Model):
252 # Identification
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()
258 famille_emploi = models.ForeignKey('FamilleEmploi',
259 db_column='famille_emploi')
260 # Méta
261 date_modification = models.DateField(auto_now=True)
262 actif = models.BooleanField()
263
264 def __unicode__(self):
265 return u'%s' % self.nom
266
267 class Meta:
268 ordering = ['nom']
269
270
271 TYPE_PAIEMENT_CHOICES = (
272 ('Régulier', 'Régulier'),
273 ('Ponctuel', 'Ponctuel'),
274 )
275
276 NATURE_REMUNERATION_CHOICES = (
277 ('Accessoire', 'Accessoire'),
278 ('Charges', 'Charges'),
279 ('Indemnité', 'Indemnité'),
280 ('RAS', 'RAS'),
281 ('Traitement', 'Traitement'),
282 )
283
284 class TypeRemuneration(models.Model):
285 # Identification
286 id = models.IntegerField(primary_key=True)
287 nom = models.CharField(max_length=255)
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
293 actif = models.BooleanField()
294
295 def __unicode__(self):
296 return u'%s' % self.nom
297
298
299 class TypeRevalorisation(models.Model):
300 # Identification
301 id = models.IntegerField(primary_key=True)
302 nom = models.CharField(max_length=255)
303 # Méta
304 actif = models.BooleanField()
305
306 PROPORTION_CHOICES = (
307 ('0.5', '0.5'),
308 ('1', '1'),
309 )
310
311 class PosteManager(SecurityManager):
312 """
313 Chargement de tous les objets FK existants sur chaque QuerySet.
314 """
315 prefixe_implantation = 'implantation'
316
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
324 class Poste(models.Model):
325 # Identification
326 id = models.IntegerField(primary_key=True)
327 implantation = models.ForeignKey('datamaster_modeles.Implantation',
328 db_column='implantation', related_name='+')
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%)
332 # Méta
333 date_modification = models.DateField(auto_now=True)
334 actif = models.BooleanField()
335
336 # Managers
337 objects = PosteManager()
338
339 def __unicode__(self):
340 return u'%s - %s [%s]' % (self.implantation, self.type_poste.nom,
341 self.id)
342
343
344 class Service(models.Model):
345 # Identification
346 id = models.IntegerField(primary_key=True)
347 nom = models.CharField(max_length=255)
348 # Méta
349 actif = models.BooleanField()
350
351 def __unicode__(self):
352 return u'%s' % self.nom
353
354 class Meta:
355 ordering = ['nom']
356
357
358 TYPE_ORGANISME_CHOICES = (
359 ('MAD', 'Mise à disposition'),
360 ('DET', 'Détachement'),
361 )
362
363 class OrganismeBstg(models.Model):
364 # Identification
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)
368 # Méta
369 actif = models.BooleanField()
370
371 def __unicode__(self):
372 return u'%s (%s)' % (self.nom, self.type)
373
374 class Meta:
375 ordering = ['type', 'nom']
376
377
378 CONTRAT_CATEGORIE_CHOICES= (
379 ('A', 'A'),
380 ('C', 'C'),
381 )
382 class Statut(models.Model):
383 # Identification
384 id = models.IntegerField(primary_key=True)
385 code = models.CharField(max_length=25, unique=True)
386 nom = models.CharField(max_length=255)
387 type_contrat_categorie = models.CharField(max_length=10,
388 choices=CONTRAT_CATEGORIE_CHOICES)
389 #CHOICES A, C (veut dire quoi?) voir TypeContrat.categorie
390 # Méta
391 actif = models.BooleanField()
392
393 def __unicode__(self):
394 return u'%s : %s' % (self.code, self.nom)
395
396 TYPE_CLASSEMENT_CHOICES = (
397 ('S', 'S'),
398 ('T', 'T'),
399 )
400
401 class 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
412 class Classement(models.Model):
413 # Identification
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()
419 # Méta
420 commentaire = models.TextField(null=True, blank=True)
421 date_modification = models.DateField(auto_now=True)
422 actif = models.BooleanField()
423
424 # managers
425 objects = ClassementManager()
426
427 def __unicode__(self):
428 return u'%s.%s.%s' % (self.type, self.echelon, self.degre )
429
430 class Meta:
431 ordering = ['type','echelon','degre','coefficient']
432
433 class TauxChange(models.Model):
434 # Identification
435 id = models.IntegerField(primary_key=True)
436 devise = models.ForeignKey('Devise', to_field='id', db_column='devise')
437 annee = models.IntegerField()
438 taux = models.FloatField()
439 # Relations
440 implantation = models.ForeignKey('datamaster_modeles.Implantation',
441 db_column='implantation',
442 related_name='taux_change')
443
444 def __unicode__(self):
445 return u"%s %s : %s" % (self.devise, self.annee, self.taux)
446
447 class 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
465
466 class ValeurPoint(models.Model):
467 # Identification
468 id = models.IntegerField(primary_key=True)
469 valeur = models.FloatField()
470 implantation = models.ForeignKey('datamaster_modeles.Implantation',
471 db_column='implantation',
472 related_name='valeurs_point')
473 # Méta
474 annee = models.IntegerField()
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
490
491 def __unicode__(self):
492 tx = self.get_tauxchange_courant()
493 if tx:
494 devise_code = tx.devise.code
495 else:
496 devise_code = "??"
497 return u'%s %s (%s-%s)' % (self.valeur, devise_code, self.implantation_id, self.annee)
498
499 class Meta:
500 ordering = ['valeur']
501
502 objects = models.Manager()
503 actuelles = ValeurPointManager()
504
505
506 class 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
511 def __unicode__(self):
512 return u'%s - %s' % (self.code, self.nom)
513
514
515 class TypeContrat(models.Model):
516 # Identification
517 id = models.IntegerField(primary_key=True)
518 nom = models.CharField(max_length=255)
519 nom_long = models.CharField(max_length=255) #description
520 categorie = models.CharField(max_length=10,
521 choices=CONTRAT_CATEGORIE_CHOICES)
522 # Méta
523 actif = models.BooleanField()
524
525 def __unicode__(self):
526 return u'%s' % (self.nom)