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