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