round remun fix #1456
[auf_rh_dae.git] / project / dae / models.py
CommitLineData
bd28238f 1# -=- encoding: utf-8 -=-
3f3cf5f3 2
36341125 3import os
5633fa41 4from django.conf import settings
36341125 5from django.core.files.storage import FileSystemStorage
a9c281dd
OL
6from django.db import models
7import reversion
afc204bf 8from workflow import PosteWorkflow, DossierWorkflow
f258e4e7 9from managers import DossierManager, PosteManager
bd28238f 10import datamaster_modeles.models as ref
a9c281dd 11from rh_v1 import models as rh
bd28238f 12
bd28238f 13
2d4d2fcf 14# Constantes
15HELP_TEXT_DATE = "format: aaaa-mm-jj"
16REGIME_TRAVAIL_DEFAULT=100.00
17REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT=35.00
bd28238f 18
bd28238f 19
d766bf2c 20# Upload de fichiers
2d4d2fcf 21storage_prive = FileSystemStorage(settings.PRIVE_MEDIA_ROOT,
22 base_url=settings.PRIVE_MEDIA_URL)
36341125
OL
23
24def poste_piece_dispatch(instance, filename):
fe13cd48 25 path = "poste/%s/%s" % (instance.poste_id, filename)
36341125
OL
26 return path
27
d766bf2c 28def dossier_piece_dispatch(instance, filename):
fe13cd48 29 path = "dossier/%s/%s" % (instance.dossier_id, filename)
d766bf2c
OL
30 return path
31
36341125 32
2d4d2fcf 33### POSTE
34
35POSTE_APPEL_CHOICES = (
36 ('interne', 'Interne'),
37 ('externe', 'Externe'),
38)
36341125 39
1c7d67ce 40
8fa94e8b 41class Poste(PosteWorkflow, models.Model):
bd28238f 42 # Modèle existant
5d680e84 43 id_rh = models.ForeignKey(rh.Poste, null=True, related_name='+',
2d4d2fcf 44 editable=False,
45 verbose_name="Mise à jour du poste")
ce110fb9 46 nom = models.CharField(verbose_name="Titre du poste", max_length=255)
5d680e84
NC
47 implantation = models.ForeignKey(ref.Implantation)
48 type_poste = models.ForeignKey(rh.TypePoste, null=True, related_name='+')
98d51b59 49 service = models.ForeignKey(rh.Service, related_name='+',
2d4d2fcf 50 verbose_name=u"Direction/Service/Pôle support")
98d51b59 51 responsable = models.ForeignKey(rh.Poste, related_name='+',
2d4d2fcf 52 verbose_name="Poste du responsable")
9a85768a 53
2d4d2fcf 54 # Contrat
5d680e84 55 regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
2d4d2fcf 56 default=REGIME_TRAVAIL_DEFAULT,
57 verbose_name="Temps de travail",
58 help_text="% du temps complet")
5d680e84 59 regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
2d4d2fcf 60 decimal_places=2,
61 default=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT,
62 verbose_name="Nb. heures par semaine")
bd28238f
NC
63
64 # Recrutement
154677c3 65 local = models.BooleanField(verbose_name="Local", default=True, blank=True)
2d4d2fcf 66 expatrie = models.BooleanField(verbose_name="Expatrié", default=False,
67 blank=True)
a3508c67 68 mise_a_disposition = models.BooleanField(verbose_name="Mise à disposition")
98d51b59 69 appel = models.CharField(max_length=10, default='interne',
2d4d2fcf 70 verbose_name="Appel à candidature",
71 choices=POSTE_APPEL_CHOICES)
bd28238f
NC
72
73 # Rémunération
2d4d2fcf 74 classement_min = models.ForeignKey(rh.Classement, related_name='+',
75 blank=True, null=True)
76 classement_max = models.ForeignKey(rh.Classement, related_name='+',
77 blank=True, null=True)
78 valeur_point_min = models.ForeignKey(rh.ValeurPoint, related_name='+',
79 blank=True, null=True)
80 valeur_point_max = models.ForeignKey(rh.ValeurPoint, related_name='+',
81 blank=True, null=True)
3d627bfd 82 devise_min = models.ForeignKey(rh.Devise, default=5, related_name='+')
83 devise_max = models.ForeignKey(rh.Devise, default=5, related_name='+')
5d680e84
NC
84 salaire_min = models.DecimalField(max_digits=12, decimal_places=2,
85 default=0)
86 salaire_max = models.DecimalField(max_digits=12, decimal_places=2,
87 default=0)
88 indemn_min = models.DecimalField(max_digits=12, decimal_places=2,
89 default=0)
90 indemn_max = models.DecimalField(max_digits=12, decimal_places=2,
91 default=0)
92 autre_min = models.DecimalField(max_digits=12, decimal_places=2,
93 default=0)
94 autre_max = models.DecimalField(max_digits=12, decimal_places=2,
95 default=0)
96
97 # Comparatifs de rémunération
98 devise_comparaison = models.ForeignKey(rh.Devise, related_name='+',
a3508c67 99 default=5)
5d680e84
NC
100 comp_locale_min = models.DecimalField(max_digits=12, decimal_places=2,
101 null=True, blank=True)
102 comp_locale_max = models.DecimalField(max_digits=12, decimal_places=2,
103 null=True, blank=True)
104 comp_universite_min = models.DecimalField(max_digits=12, decimal_places=2,
105 null=True, blank=True)
106 comp_universite_max = models.DecimalField(max_digits=12, decimal_places=2,
107 null=True, blank=True)
108 comp_fonctionpub_min = models.DecimalField(max_digits=12, decimal_places=2,
109 null=True, blank=True)
110 comp_fonctionpub_max = models.DecimalField(max_digits=12, decimal_places=2,
111 null=True, blank=True)
112 comp_ong_min = models.DecimalField(max_digits=12, decimal_places=2,
113 null=True, blank=True)
114 comp_ong_max = models.DecimalField(max_digits=12, decimal_places=2,
115 null=True, blank=True)
116 comp_autre_min = models.DecimalField(max_digits=12, decimal_places=2,
117 null=True, blank=True)
118 comp_autre_max = models.DecimalField(max_digits=12, decimal_places=2,
119 null=True, blank=True)
bd28238f 120
2e092e0c
OL
121 # Justification
122 justification = models.TextField()
123
bd28238f 124 # Méta
5d680e84
NC
125 date_creation = models.DateTimeField(auto_now_add=True)
126 date_modification = models.DateTimeField(auto_now=True)
98d51b59 127 date_debut = models.DateField(verbose_name="Date de début",
2d4d2fcf 128 help_text=HELP_TEXT_DATE)
9fb2ccd9 129 date_fin = models.DateField(null=True, blank=True,
130 verbose_name="Date de fin",
2d4d2fcf 131 help_text=HELP_TEXT_DATE)
bd28238f
NC
132 actif = models.BooleanField(default=True)
133
1c7d67ce
OL
134 # Managers
135 objects = PosteManager()
136
03858ba5
OL
137 def _get_key(self):
138 """
2d4d2fcf 139 Les vues sont montées selon une clef spéciale
140 pour identifier la provenance du poste.
141 Cette méthode fournit un moyen de reconstruire cette clef
142 afin de générer les URLs.
03858ba5
OL
143 """
144 return "dae-%s" % self.id
145 key = property(_get_key)
146
f3333b0e
OL
147 def get_dossiers(self):
148 """
149 Liste tous les anciens dossiers liés à ce poste.
2d4d2fcf 150 (Le nom de la relation sur le rh.Poste est mal choisi
151 poste1 au lieu de dossier1)
f3333b0e 152 Note1 : seulement le dosssier principal fait l'objet de la recherche.
2d4d2fcf 153 Note2 : les dossiers sont retournés du plus récent au plus vieux.
154 (Ce test est fait en fonction du id,
155 car les dates de création sont absentes de rh v1).
f3333b0e
OL
156 """
157 if self.id_rh is None:
158 return []
159 postes = [p for p in self.id_rh.poste1.all()]
160 return sorted(postes, key=lambda poste: poste.id, reverse=True)
161
162 def get_complement_nom(self):
163 """
2d4d2fcf 164 Inspecte les modèles rh v1 pour trouver dans le dernier dossier
165 un complément de titre de poste.
f3333b0e
OL
166 """
167 dossiers = self.get_dossiers()
168 if len(dossiers) > 0:
169 nom = dossiers[0].complement1
170 else:
171 nom = ""
a9c281dd 172 return nom
f3333b0e
OL
173
174 def get_employe(self):
175 """
176 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
177 """
178 dossiers = self.get_dossiers()
179 if len(dossiers) > 0:
180 return dossiers[0].employe
181 else:
182 return None
183
179f6b49 184 def get_default_devise(self):
2d4d2fcf 185 """Récupère la devise par défaut en fonction de l'implantation
186 (EUR autrement)
187 """
179f6b49 188 try:
6e4600ef 189 implantation_devise = rh.TauxChange.objects \
190 .filter(implantation=self.implantation)[0].devise
179f6b49
OL
191 except:
192 implantation_devise = 5 # EUR
193 return implantation_devise
194
c0413a6f
OL
195 #####################
196 # Classement de poste
197 #####################
198
199 def get_couts_minimum(self):
200 return (float)(self.salaire_min + self.indemn_min + self.autre_min)
201
202 def get_taux_minimum(self):
b6825282
OL
203 taux_changes = rh.TauxChange.objects.filter(devise=self.devise_min).order_by('annee')
204 for t in taux_changes:
205 if t.implantation == self.implantation:
206 return t.taux
207 if len(taux_changes) > 0:
208 return taux_changes[0].taux
209 else:
12c7f8a7 210 raise Exception('Taux indisponible pour la devise %s (%s)' % (self.devise_min, self.implantation))
c0413a6f
OL
211
212 def get_couts_minimum_euros(self):
213 return self.get_couts_minimum() * self.get_taux_minimum()
214
215 def get_couts_maximum(self):
216 return (float)(self.salaire_max + self.indemn_max + self.autre_max)
217
218 def get_taux_maximum(self):
b6825282
OL
219 taux_changes = rh.TauxChange.objects.filter(devise=self.devise_max).order_by('annee')
220 for t in taux_changes:
221 if t.implantation == self.implantation:
222 return t.taux
223 if len(taux_changes) > 0:
224 return taux_changes[0].taux
225 else:
12c7f8a7 226 raise Exception('Taux indisponible pour la devise %s (%s)' % (self.devise_max, self.implantation))
c0413a6f
OL
227
228 def get_couts_maximum_euros(self):
229 return self.get_couts_maximum() * self.get_taux_maximum()
230
12c7f8a7
OL
231
232 def show_taux_minimum(self):
233 try:
234 return self.get_taux_minimum()
235 except Exception, e:
236 return e
237
238 def show_couts_minimum_euros(self):
239 try:
240 return self.get_couts_minimum_euros()
241 except Exception, e:
242 return e
243
244 def show_taux_maximum(self):
245 try:
246 return self.get_taux_maximum()
247 except Exception, e:
248 return e
249
250 def show_couts_maximum_euros(self):
251 try:
252 return self.get_couts_maximum_euros()
253 except Exception, e:
254 return e
255
256
c0413a6f
OL
257 ######################
258 # Comparaison de poste
259 ######################
a3fee9c5
OL
260
261 def est_comparable(self):
262 """
263 Si on a au moins une valeur de saisie dans les comparaisons, alors le poste
264 est comparable.
265 """
266 if self.comp_universite_min is None and \
267 self.comp_fonctionpub_min is None and \
268 self.comp_locale_min is None and \
269 self.comp_ong_min is None and \
270 self.comp_autre_min is None and \
271 self.comp_universite_max is None and \
272 self.comp_fonctionpub_max is None and \
273 self.comp_locale_max is None and \
274 self.comp_ong_max is None and \
275 self.comp_autre_max is None:
276 return False
277 else:
278 return True
c0413a6f 279
a3fee9c5 280
c0413a6f
OL
281 def get_taux_comparaison(self):
282 try:
283 return rh.TauxChange.objects.filter(implantation=self.implantation, devise=self.devise_comparaison)[0].taux
284 except:
285 return 1
286
287 def get_comp_universite_min_euros(self):
288 return (float)(self.comp_universite_min) * self.get_taux_comparaison()
289
290 def get_comp_fonctionpub_min_euros(self):
291 return (float)(self.comp_fonctionpub_min) * self.get_taux_comparaison()
292
293 def get_comp_locale_min_euros(self):
294 return (float)(self.comp_locale_min) * self.get_taux_comparaison()
295
296 def get_comp_ong_min_euros(self):
297 return (float)(self.comp_ong_min) * self.get_taux_comparaison()
298
299 def get_comp_autre_min_euros(self):
300 return (float)(self.comp_autre_min) * self.get_taux_comparaison()
301
302 def get_comp_universite_max_euros(self):
303 return (float)(self.comp_universite_max) * self.get_taux_comparaison()
304
305 def get_comp_fonctionpub_max_euros(self):
306 return (float)(self.comp_fonctionpub_max) * self.get_taux_comparaison()
307
308 def get_comp_locale_max_euros(self):
309 return (float)(self.comp_locale_max) * self.get_taux_comparaison()
310
311 def get_comp_ong_max_euros(self):
312 return (float)(self.comp_ong_max) * self.get_taux_comparaison()
313
314 def get_comp_autre_max_euros(self):
315 return (float)(self.comp_autre_max) * self.get_taux_comparaison()
316
a9e52624 317
5d680e84 318 def __unicode__(self):
f3333b0e 319 """
2d4d2fcf 320 Cette fonction est consommatrice SQL car elle cherche les dossiers
321 qui ont été liés à celui-ci.
f3333b0e
OL
322 """
323 complement_nom_poste = self.get_complement_nom()
c7a4aa2b
OL
324 if complement_nom_poste is None:
325 complement_nom_poste = ""
f3333b0e
OL
326 data = (
327 self.implantation,
328 self.type_poste.nom,
329 self.nom,
f3333b0e 330 )
a7c68130 331 return u'%s - %s (%s)' % data
5d680e84 332
bd28238f 333
a9c281dd
OL
334# Tester l'enregistrement car les models.py sont importés au complet
335if not reversion.is_registered(Poste):
336 reversion.register(Poste)
337
bd28238f 338
5d680e84
NC
339POSTE_FINANCEMENT_CHOICES = (
340 ('A', 'A - Frais de personnel'),
341 ('B', 'B - Projet(s)-Titre(s)'),
342 ('C', 'C - Autre')
343)
bd28238f 344
5d680e84 345class PosteFinancement(models.Model):
5d680e84
NC
346 poste = models.ForeignKey('Poste', related_name='financements')
347 type = models.CharField(max_length=1, choices=POSTE_FINANCEMENT_CHOICES)
43d04712 348 pourcentage = models.DecimalField(max_digits=12, decimal_places=2,
349 help_text="ex.: 33.33 % (décimale avec point)")
350 commentaire = models.TextField(
351 help_text="Spécifiez la source de financement.")
bd28238f 352
43d04712 353 class Meta:
354 ordering = ['type']
bd28238f 355
c0413a6f
OL
356 def __unicode__(self):
357 return u"%s %s %s" % (self.get_type_display(), self.pourcentage, self.commentaire)
358
c589d980 359
2d4d2fcf 360class PostePiece(models.Model):
361 """Documents relatifs au Poste
362 Ex.: Description de poste
363 """
364 poste = models.ForeignKey("Poste")
365 nom = models.CharField(verbose_name="Nom", max_length=255)
366 fichier = models.FileField(verbose_name="Fichier",
367 upload_to=poste_piece_dispatch,
368 storage=storage_prive)
369
370### EMPLOYÉ/PERSONNE
371
372# TODO : migration pour m -> M, f -> F
c589d980 373
bd28238f 374GENRE_CHOICES = (
139686f2
NC
375 ('m', 'Homme'),
376 ('f', 'Femme'),
bd28238f
NC
377)
378
bd28238f 379class Employe(models.Model):
bd28238f
NC
380
381 # Modèle existant
da3ca955 382 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+',
383 verbose_name='Employé')
bd28238f 384 nom = models.CharField(max_length=255)
da3ca955 385 prenom = models.CharField(max_length=255, verbose_name='Prénom')
07b40eda 386 genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
bd28238f 387
139686f2 388 def __unicode__(self):
2d4d2fcf 389 return u'%s %s' % (self.prenom, self.nom.upper())
139686f2 390
bd28238f 391
2d4d2fcf 392### DOSSIER
393
394STATUT_RESIDENCE_CHOICES = (
395 ('local', 'Local'),
396 ('expat', 'Expatrié'),
397)
398
bd28238f 399COMPTE_COMPTA_CHOICES = (
494ff2be
NC
400 ('coda', 'CODA'),
401 ('scs', 'SCS'),
402 ('aucun', 'Aucun'),
bd28238f
NC
403)
404
afc204bf 405class Dossier(DossierWorkflow, models.Model):
bd28238f
NC
406
407 # Modèle existant
139686f2
NC
408 employe = models.ForeignKey('Employe', related_name='+', editable=False)
409 poste = models.ForeignKey('Poste', related_name='+', editable=False)
5d680e84 410 statut = models.ForeignKey(rh.Statut, related_name='+')
dfc2c344 411 organisme_bstg = models.ForeignKey(rh.OrganismeBstg,
1f109689 412 null=True, blank=True,
dfc2c344 413 verbose_name="Organisme",
414 help_text="Si détaché (DET) ou mis à disposition (MAD), \
415 préciser l'organisme.",
416 related_name='+')
0288adb5
OL
417 organisme_bstg_autre = models.CharField(max_length=255,
418 verbose_name="Autre organisme",
419 help_text="indiquer l'organisme ici s'il n'est pas dans la liste",
420 null=True,
421 blank=True,)
bd28238f 422
139686f2
NC
423 # Données antérieures de l'employé
424 statut_anterieur = models.ForeignKey(
425 rh.Statut, related_name='+', null=True, blank=True,
da3ca955 426 verbose_name='Statut antérieur')
139686f2
NC
427 classement_anterieur = models.ForeignKey(
428 rh.Classement, related_name='+', null=True, blank=True,
429 verbose_name='Classement précédent')
430 salaire_anterieur = models.DecimalField(
431 max_digits=12, decimal_places=2, null=True, default=None,
432 blank=True, verbose_name='Salaire précédent')
433
434 # Données du titulaire précédent
435 employe_anterieur = models.ForeignKey(
436 rh.Employe, related_name='+', null=True, blank=True,
437 verbose_name='Employé précédent')
438 statut_titulaire_anterieur = models.ForeignKey(
439 rh.Statut, related_name='+', null=True, blank=True,
440 verbose_name='Statut titulaire précédent')
441 classement_titulaire_anterieur = models.ForeignKey(
442 rh.Classement, related_name='+', null=True, blank=True,
443 verbose_name='Classement titulaire précédent')
444 salaire_titulaire_anterieur = models.DecimalField(
445 max_digits=12, decimal_places=2, default=None, null=True,
446 blank=True, verbose_name='Salaire titulaire précédent')
494ff2be 447
bd28238f
NC
448 # Recrutement
449 remplacement = models.BooleanField()
4d25e2ba 450 statut_residence = models.CharField(max_length=10, default='local',
2d4d2fcf 451 verbose_name="Statut",
452 choices=STATUT_RESIDENCE_CHOICES)
bd28238f
NC
453
454 # Rémunération
494ff2be 455 classement = models.ForeignKey(rh.Classement, related_name='+',
2d4d2fcf 456 null=True, blank=True,
457 verbose_name='Classement proposé')
494ff2be 458 salaire = models.DecimalField(max_digits=12, decimal_places=2,
2d4d2fcf 459 verbose_name='Salaire de base',
460 null=True, default=None)
e8e75458 461 devise = models.ForeignKey(rh.Devise, default=5, related_name='+')
2d4d2fcf 462 regime_travail = models.DecimalField(max_digits=12,
463 decimal_places=2,
464 default=REGIME_TRAVAIL_DEFAULT,
465 verbose_name="Régime de travail",
466 help_text="% du temps complet")
139686f2 467 regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
2d4d2fcf 468 decimal_places=2,
469 default=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT,
470 verbose_name="Nb. heures par semaine")
bd28238f
NC
471
472 # Contrat
5d680e84 473 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
4d25e2ba 474 contrat_date_debut = models.DateField(help_text="format: aaaa-mm-jj")
1f109689 475 contrat_date_fin = models.DateField(null=True, blank=True,
476 help_text="format: aaaa-mm-jj")
bd28238f
NC
477
478 # Comptes
dfc2c344 479 compte_compta = models.CharField(max_length=10, default='aucun',
480 verbose_name=u'Compte comptabilité',
481 choices=COMPTE_COMPTA_CHOICES)
bd28238f 482 compte_courriel = models.BooleanField()
0140cbd2 483
484 # Méta
485 date_creation = models.DateTimeField(auto_now_add=True)
e4f56614
OL
486
487 # Managers
488 objects = DossierManager()
489
aec2c91e 490 def __unicode__(self):
e4f56614 491 return u'[%s] %s - %s' % (self.poste.implantation, self.poste.nom, self.employe)
bd28238f 492
b1baa306
OL
493 def get_salaire_euros(self):
494 try:
495 tx = rh.TauxChange.objects.filter(implantation=self.poste.implantation, devise=self.devise)[0].taux
496 except:
497 tx = 1
498 return (float)(tx) * (float)(self.salaire)
499
57bd966c
OL
500 def get_couts_auf(self):
501 """
502 On retire les MAD BSTG
503 """
504 return [r for r in self.remuneration_set.all() if r.type_id not in (2, )]
a9e52624
OL
505
506 def get_total_couts_auf(self):
507 total = 0.0
508 for r in self.get_couts_auf():
509 total += r.montant_euro()
510 return total
57bd966c
OL
511
512 def get_aides_auf(self):
513 """
514 On récupère les MAD BSTG
515 """
516 return [r for r in self.remuneration_set.all() if r.type_id in (2, )]
517
a9e52624
OL
518 def get_total_aides_auf(self):
519 total = 0.0
520 for r in self.get_aides_auf():
521 total += r.montant_euro()
522 return total
523
524 def get_total_remun(self):
525 return self.get_total_couts_auf() + self.get_total_aides_auf()
bd28238f 526
0140cbd2 527# Tester l'enregistrement car les models.py sont importés au complet
528if not reversion.is_registered(Dossier):
529 reversion.register(Dossier)
bd28238f 530
2d4d2fcf 531class DossierPiece(models.Model):
532 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
533 Ex.: Lettre de motivation.
534 """
535 dossier = models.ForeignKey("Dossier")
536 nom = models.CharField(verbose_name="Nom", max_length=255)
537 fichier = models.FileField(verbose_name="Fichier",
538 upload_to=dossier_piece_dispatch,
539 storage=storage_prive)
540
541
03b395db
OL
542class DossierComparaison(models.Model):
543 """
544 Photo d'une comparaison salariale au moment de l'embauche.
545 """
546 dossier = models.ForeignKey('Dossier', related_name='comparaisons')
547 implantation = models.ForeignKey(ref.Implantation, null=True, blank=True)
548 poste = models.CharField(max_length=255, null=True, blank=True)
549 personne = models.CharField(max_length=255, null=True, blank=True)
550 montant = models.IntegerField(null=True)
551 devise = models.ForeignKey(rh.Devise, default=5, related_name='+', null=True, blank=True)
552 montant_euros = models.IntegerField(null=True)
553
c589d980 554
2d4d2fcf 555### RÉMUNÉRATION
556
bd28238f 557class Remuneration(models.Model):
5d680e84 558 # Identification
bd28238f 559 dossier = models.ForeignKey('Dossier', db_column='dossier')
cb1d62b5
NC
560 type = models.ForeignKey(rh.TypeRemuneration, db_column='type',
561 related_name='+')
cb1d62b5
NC
562 montant = models.DecimalField(max_digits=12, decimal_places=2,
563 null=True) # Annuel
494ff2be 564 devise = models.ForeignKey(rh.Devise, to_field='code',
5d680e84 565 db_column='devise', related_name='+')
cb1d62b5 566 precision = models.CharField(max_length=255, null=True, blank=True)
bd28238f 567
5d680e84 568 # Méta
bd28238f 569 date_creation = models.DateField(auto_now_add=True)
2d4d2fcf 570 user_creation = models.IntegerField(null=True, blank=True) # TODO : user
bd28238f 571
ee91bc95
NC
572 def montant_mois(self):
573 return round(self.montant / 12, 2)
574
575 def taux_devise(self):
576 return self.devise.tauxchange_set.order_by('-annee').all()[0].taux
577
578 def montant_euro(self):
a9e52624 579 return round(float(self.montant) * float(self.taux_devise()), 2)
ee91bc95
NC
580
581 def montant_euro_mois(self):
582 return round(self.montant_euro() / 12, 2)
bd28238f
NC
583
584
2d4d2fcf 585### JUSTIFICATIONS
586
72db8238
OL
587TYPE_JUSTIFICATIONS = (
588 ('N', 'Nouvel employé'),
589 ('R', 'Renouvellement employé'),
590)
bd28238f 591
72db8238
OL
592class JustificationQuestion(models.Model):
593 question = models.CharField(max_length=255)
594 type = models.CharField(max_length=255, choices=TYPE_JUSTIFICATIONS)
595
596 def __unicode__(self,):
597 return self.question
bd28238f 598
72db8238
OL
599class JustificationNouvelEmploye(models.Model):
600 dossier = models.ForeignKey("Dossier")
601 question = models.ForeignKey("JustificationQuestion")
602 reponse = models.TextField()
bd28238f 603
72db8238
OL
604class JustificationAutreEmploye(models.Model):
605 dossier = models.ForeignKey("Dossier")
606 question = models.ForeignKey("JustificationQuestion")
607 reponse = models.TextField()