#2785 devisable mixin
[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
3f5cbabe 8from rh import models as rh
afc204bf 9from workflow import PosteWorkflow, DossierWorkflow
c511cd1f
EMS
10from workflow import DOSSIER_ETAT_DRH_FINALISATION, DOSSIER_ETAT_REGION_FINALISATION, \
11 DOSSIER_ETAT_FINALISE
bf6f2712 12import auf.django.references.models as ref
a2c3ad52 13from auf.django.metadata.models import AUFMetadata
3f5cbabe 14from managers import *
4047b783 15from rh.models import HELP_TEXT_DATE
bd28238f 16
bd28238f 17
d766bf2c 18# Upload de fichiers
34dad720 19UPLOAD_STORAGE = FileSystemStorage(settings.PRIVE_MEDIA_ROOT)
d766bf2c 20
36341125 21
2d4d2fcf 22### POSTE
23
24POSTE_APPEL_CHOICES = (
25 ('interne', 'Interne'),
26 ('externe', 'Externe'),
27)
c3be904d
OL
28POSTE_ACTION = (
29 ('N', u"Nouveau poste"),
30 ('M', u"Poste existant"),
31 ('E', u"Évolution de poste"),
32)
33
36341125 34
ae5c920b
OL
35class DeviseException(Exception):
36 silent_variable_failure = True
37
1c7d67ce 38
3f5cbabe 39class Poste(PosteWorkflow, rh.Poste_):
c3be904d
OL
40
41 type_intervention = models.CharField(max_length=1, choices=POSTE_ACTION, default='N')
42
bd28238f 43 # Modèle existant
5d680e84 44 id_rh = models.ForeignKey(rh.Poste, null=True, related_name='+',
2d4d2fcf 45 editable=False,
c1195471 46 verbose_name=u"Mise à jour du poste")
bd28238f
NC
47
48 # Rémunération
3f5cbabe 49 indemn_expat_min = models.DecimalField(max_digits=13, decimal_places=2, default=0)
5f61bccb
OL
50 indemn_expat_max = models.DecimalField(max_digits=12, decimal_places=2, default=0)
51 indemn_fct_min = models.DecimalField(max_digits=12, decimal_places=2, default=0)
52 indemn_fct_max = models.DecimalField(max_digits=12, decimal_places=2, default=0)
53 charges_patronales_min = models.DecimalField(max_digits=12, decimal_places=2, default=0)
54 charges_patronales_max = models.DecimalField(max_digits=12, decimal_places=2, default=0)
bd28238f 55
1c7d67ce
OL
56 # Managers
57 objects = PosteManager()
58
317ce433
OL
59
60 def est_importe(self):
61 """Test si le poste a déjà été importé"""
62 return ImportPoste.objects.filter(dae=self).exists()
63
64 def importer(self):
65 from django.db.models import AutoField
66 if self.est_importe():
67 return ImportPoste.objects.get(dae=self)
68 rh_poste = rh.Poste()
69 # Faire une copie profonde de l'objet.
70 # PosteFinancement, PosteComparaison, Remun modele a ajuster...
a184c555
OL
71
72 def copy_model(src, dst, exclude=[]):
73 keys = [f.name for f in src._meta.fields if f.name not in ['id', ] + exclude]
74 for k in keys:
75 setattr(dst, k, getattr(src, k))
76 return dst
77
78 rh_poste = copy_model(self, rh_poste)
79 rh_poste.save()
80 print rh_poste.id
81
82 for o in self.dae_financements.all():
83 rh_financement = rh.PosteFinancement()
84 rh_financement = copy_model(o, rh_financement, exclude=['poste',])
85 rh_financement.poste = rh_poste
86 rh_financement.save()
87
88 for o in self.dae_pieces.all():
89 rh_piece = rh.PostePiece()
90 rh_piece = copy_model(o, rh_piece, exclude=['poste',])
91 rh_piece.poste = rh_poste
92 rh_piece.save()
93
94 for o in self.dae_comparaisons_internes.all():
95 rh_comp = rh.PosteComparaison()
96 rh_comp = copy_model(o, rh_financement, exclude=['poste',])
97 rh_comp.poste = rh_poste
98 rh_comp.save()
99
317ce433
OL
100 return rh_poste
101
03858ba5
OL
102 def _get_key(self):
103 """
1bc84af4 104 Les vues sont montées selon une clef spéciale
2d4d2fcf 105 pour identifier la provenance du poste.
1bc84af4 106 Cette méthode fournit un moyen de reconstruire cette clef
2d4d2fcf 107 afin de générer les URLs.
03858ba5
OL
108 """
109 return "dae-%s" % self.id
110 key = property(_get_key)
111
f3333b0e
OL
112 def get_dossiers(self):
113 """
114 Liste tous les anciens dossiers liés à ce poste.
1bc84af4 115 (Le nom de la relation sur le rh.Poste est mal choisi
2d4d2fcf 116 poste1 au lieu de dossier1)
f3333b0e 117 Note1 : seulement le dosssier principal fait l'objet de la recherche.
1bc84af4
EMS
118 Note2 : les dossiers sont retournés du plus récent au plus vieux.
119 (Ce test est fait en fonction du id,
2d4d2fcf 120 car les dates de création sont absentes de rh v1).
f3333b0e
OL
121 """
122 if self.id_rh is None:
123 return []
16b1454e 124 return self.id_rh.rh_dossiers.all()
428e3c0b 125
f3333b0e
OL
126
127 def get_employe(self):
128 """
129 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
130 """
131 dossiers = self.get_dossiers()
132 if len(dossiers) > 0:
133 return dossiers[0].employe
134 else:
135 return None
136
179f6b49 137 def get_default_devise(self):
1bc84af4 138 """Récupère la devise par défaut en fonction de l'implantation
2d4d2fcf 139 (EUR autrement)
140 """
179f6b49 141 try:
6e4600ef 142 implantation_devise = rh.TauxChange.objects \
143 .filter(implantation=self.implantation)[0].devise
179f6b49
OL
144 except:
145 implantation_devise = 5 # EUR
146 return implantation_devise
147
c0413a6f
OL
148 #####################
149 # Classement de poste
150 #####################
151
152 def get_couts_minimum(self):
83b94a87
EMS
153 return self.salaire_min + self.indemn_expat_min + self.indemn_fct_min + self.charges_patronales_min + self.autre_min
154
155 def get_salaire_minimum(self):
156 return self.get_couts_minimum() - self.charges_patronales_min
c0413a6f
OL
157
158 def get_taux_minimum(self):
4e439a89
OL
159 if self.devise_min.code == 'EUR':
160 return 1
2455f48d 161 liste_taux = self.devise_min.tauxchange_set.order_by('-annee')
4e439a89
OL
162 if len(liste_taux) == 0:
163 raise DeviseException(u"La devise %s n'a pas de taux pour l'implantation %s" % (self.devise_min, self.implantation))
b6825282 164 else:
4e439a89 165 return liste_taux[0].taux
c0413a6f
OL
166
167 def get_couts_minimum_euros(self):
fa5b95ed 168 return float(self.get_couts_minimum()) * self.get_taux_minimum()
c0413a6f 169
83b94a87 170 def get_salaire_minimum_euros(self):
fa5b95ed 171 return float(self.get_salaire_minimum()) * self.get_taux_minimum()
83b94a87 172
c0413a6f 173 def get_couts_maximum(self):
83b94a87
EMS
174 return self.salaire_max + self.indemn_expat_max + self.indemn_fct_max + self.charges_patronales_max + self.autre_max
175
176 def get_salaire_maximum(self):
177 return self.get_couts_maximum() - self.charges_patronales_max
c0413a6f
OL
178
179 def get_taux_maximum(self):
4e439a89
OL
180 if self.devise_max.code == 'EUR':
181 return 1
2455f48d 182 liste_taux = self.devise_max.tauxchange_set.order_by('-annee')
4e439a89
OL
183 if len(liste_taux) == 0:
184 raise DeviseException(u"La devise %s n'a pas de taux pour l'implantation %s" % (self.devise_max, self.implantation))
b6825282 185 else:
4e439a89 186 return liste_taux[0].taux
c0413a6f
OL
187
188 def get_couts_maximum_euros(self):
fa5b95ed 189 return float(self.get_couts_maximum()) * self.get_taux_maximum()
c0413a6f 190
83b94a87 191 def get_salaire_maximum_euros(self):
fa5b95ed 192 return float(self.get_salaire_maximum()) * self.get_taux_maximum()
12c7f8a7
OL
193
194 def show_taux_minimum(self):
195 try:
196 return self.get_taux_minimum()
83b94a87 197 except DeviseException, e:
12c7f8a7
OL
198 return e
199
200 def show_couts_minimum_euros(self):
201 try:
202 return self.get_couts_minimum_euros()
83b94a87
EMS
203 except DeviseException, e:
204 return e
205
206 def show_salaire_minimum_euros(self):
207 try:
208 return self.get_salaire_minimum_euros()
209 except DeviseException, e:
12c7f8a7
OL
210 return e
211
212 def show_taux_maximum(self):
213 try:
214 return self.get_taux_maximum()
83b94a87 215 except DeviseException, e:
12c7f8a7
OL
216 return e
217
218 def show_couts_maximum_euros(self):
219 try:
220 return self.get_couts_maximum_euros()
83b94a87
EMS
221 except DeviseException, e:
222 return e
223
224 def show_salaire_maximum_euros(self):
225 try:
226 return self.get_salaire_maximum_euros()
227 except DeviseException, e:
12c7f8a7
OL
228 return e
229
230
c0413a6f
OL
231 ######################
232 # Comparaison de poste
233 ######################
a3fee9c5
OL
234
235 def est_comparable(self):
236 """
237 Si on a au moins une valeur de saisie dans les comparaisons, alors le poste
238 est comparable.
239 """
240 if self.comp_universite_min is None and \
241 self.comp_fonctionpub_min is None and \
242 self.comp_locale_min is None and \
243 self.comp_ong_min is None and \
244 self.comp_autre_min is None and \
245 self.comp_universite_max is None and \
246 self.comp_fonctionpub_max is None and \
247 self.comp_locale_max is None and \
248 self.comp_ong_max is None and \
249 self.comp_autre_max is None:
250 return False
251 else:
252 return True
1bc84af4 253
a3fee9c5 254
c0413a6f
OL
255 def get_taux_comparaison(self):
256 try:
2455f48d 257 return rh.TauxChange.objects.filter(devise=self.devise_comparaison)[0].taux
c0413a6f
OL
258 except:
259 return 1
260
261 def get_comp_universite_min_euros(self):
262 return (float)(self.comp_universite_min) * self.get_taux_comparaison()
263
264 def get_comp_fonctionpub_min_euros(self):
265 return (float)(self.comp_fonctionpub_min) * self.get_taux_comparaison()
266
267 def get_comp_locale_min_euros(self):
268 return (float)(self.comp_locale_min) * self.get_taux_comparaison()
269
270 def get_comp_ong_min_euros(self):
271 return (float)(self.comp_ong_min) * self.get_taux_comparaison()
272
273 def get_comp_autre_min_euros(self):
274 return (float)(self.comp_autre_min) * self.get_taux_comparaison()
275
276 def get_comp_universite_max_euros(self):
277 return (float)(self.comp_universite_max) * self.get_taux_comparaison()
278
279 def get_comp_fonctionpub_max_euros(self):
280 return (float)(self.comp_fonctionpub_max) * self.get_taux_comparaison()
281
282 def get_comp_locale_max_euros(self):
283 return (float)(self.comp_locale_max) * self.get_taux_comparaison()
284
285 def get_comp_ong_max_euros(self):
286 return (float)(self.comp_ong_max) * self.get_taux_comparaison()
287
288 def get_comp_autre_max_euros(self):
289 return (float)(self.comp_autre_max) * self.get_taux_comparaison()
290
a9e52624 291
5d680e84 292 def __unicode__(self):
f3333b0e 293 """
1bc84af4 294 Cette fonction est consommatrice SQL car elle cherche les dossiers
2d4d2fcf 295 qui ont été liés à celui-ci.
f3333b0e 296 """
f3333b0e
OL
297 data = (
298 self.implantation,
299 self.type_poste.nom,
300 self.nom,
f3333b0e 301 )
a7c68130 302 return u'%s - %s (%s)' % data
5d680e84 303
bd28238f 304
a9c281dd
OL
305# Tester l'enregistrement car les models.py sont importés au complet
306if not reversion.is_registered(Poste):
307 reversion.register(Poste)
308
bd28238f 309
5d680e84
NC
310POSTE_FINANCEMENT_CHOICES = (
311 ('A', 'A - Frais de personnel'),
312 ('B', 'B - Projet(s)-Titre(s)'),
313 ('C', 'C - Autre')
314)
bd28238f 315
317ce433 316class PosteFinancement(rh.PosteFinancement_):
a4125771 317 pass
1d0f4eef 318
317ce433 319class PostePiece(rh.PostePiece_):
a4125771 320 pass
068d1462 321
317ce433 322class PosteComparaison(rh.PosteComparaison_):
766ca378
OL
323 statut = models.ForeignKey(rh.Statut, related_name='+', verbose_name=u'Statut', null=True, blank=True, )
324 classement = models.ForeignKey(rh.Classement, related_name='+', verbose_name=u'Classement', null=True, blank=True, )
068d1462 325
2d4d2fcf 326### EMPLOYÉ/PERSONNE
327
328# TODO : migration pour m -> M, f -> F
c589d980 329
bd28238f 330GENRE_CHOICES = (
139686f2
NC
331 ('m', 'Homme'),
332 ('f', 'Femme'),
bd28238f
NC
333)
334
a2c3ad52 335class Employe(AUFMetadata):
bd28238f
NC
336
337 # Modèle existant
428e3c0b 338 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+',
c1195471 339 verbose_name=u'Employé')
bd28238f 340 nom = models.CharField(max_length=255)
c1195471 341 prenom = models.CharField(max_length=255, verbose_name=u'Prénom')
07b40eda 342 genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
bd28238f 343
139686f2 344 def __unicode__(self):
2d4d2fcf 345 return u'%s %s' % (self.prenom, self.nom.upper())
139686f2 346
bd28238f 347
2d4d2fcf 348### DOSSIER
349
350STATUT_RESIDENCE_CHOICES = (
351 ('local', 'Local'),
352 ('expat', 'Expatrié'),
353)
354
bd28238f 355COMPTE_COMPTA_CHOICES = (
494ff2be
NC
356 ('coda', 'CODA'),
357 ('scs', 'SCS'),
358 ('aucun', 'Aucun'),
bd28238f
NC
359)
360
16b1454e
OL
361class Dossier(DossierWorkflow, rh.Dossier_):
362 poste = models.ForeignKey('Poste', db_column='poste', related_name='%(app_label)s_dossiers')
363 employe = models.ForeignKey('Employe', db_column='employe',
364 related_name='%(app_label)s_dossiers',
365 verbose_name=u"Employé")
0288adb5 366 organisme_bstg_autre = models.CharField(max_length=255,
c1195471 367 verbose_name=u"Autre organisme",
0288adb5
OL
368 help_text="indiquer l'organisme ici s'il n'est pas dans la liste",
369 null=True,
370 blank=True,)
bd28238f 371
139686f2
NC
372 # Données antérieures de l'employé
373 statut_anterieur = models.ForeignKey(
374 rh.Statut, related_name='+', null=True, blank=True,
c1195471 375 verbose_name=u'Statut antérieur')
139686f2
NC
376 classement_anterieur = models.ForeignKey(
377 rh.Classement, related_name='+', null=True, blank=True,
c1195471 378 verbose_name=u'Classement précédent')
139686f2
NC
379 salaire_anterieur = models.DecimalField(
380 max_digits=12, decimal_places=2, null=True, default=None,
481fbd33 381 blank=True, verbose_name=u'Salaire précédent')
e158c6de
DB
382 devise_anterieur = models.ForeignKey(rh.Devise, related_name='+',
383 null=True, blank=True)
384 type_contrat_anterieur = models.ForeignKey(rh.TypeContrat,
385 related_name='+', null=True, blank=True,
386 verbose_name=u'Type contrat antérieur', )
139686f2
NC
387
388 # Données du titulaire précédent
389 employe_anterieur = models.ForeignKey(
390 rh.Employe, related_name='+', null=True, blank=True,
c1195471 391 verbose_name=u'Employé précédent')
139686f2
NC
392 statut_titulaire_anterieur = models.ForeignKey(
393 rh.Statut, related_name='+', null=True, blank=True,
c1195471 394 verbose_name=u'Statut titulaire précédent')
139686f2
NC
395 classement_titulaire_anterieur = models.ForeignKey(
396 rh.Classement, related_name='+', null=True, blank=True,
c1195471 397 verbose_name=u'Classement titulaire précédent')
139686f2
NC
398 salaire_titulaire_anterieur = models.DecimalField(
399 max_digits=12, decimal_places=2, default=None, null=True,
481fbd33 400 blank=True, verbose_name=u'Salaire titulaire précédent')
f8c7c0b8 401 devise_titulaire_anterieur = models.ForeignKey(rh.Devise, related_name='+', null=True, blank=True)
494ff2be 402
bd28238f 403 # Rémunération
16b1454e 404 salaire = models.DecimalField(max_digits=13, decimal_places=2,
c1195471 405 verbose_name=u'Salaire de base',
2d4d2fcf 406 null=True, default=None)
e8e75458 407 devise = models.ForeignKey(rh.Devise, default=5, related_name='+')
bd28238f
NC
408
409 # Contrat
5d680e84 410 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
b666864e 411 contrat_date_debut = models.DateField(help_text=HELP_TEXT_DATE)
1f109689 412 contrat_date_fin = models.DateField(null=True, blank=True,
b666864e 413 help_text=HELP_TEXT_DATE)
bd28238f 414
29dffede
OL
415 # Justifications
416 justif_nouveau_statut_label = u'Justifier le statut que ce type de poste nécessite (national, expatrié, màd ou détachement)'
417 justif_nouveau_statut = models.TextField(verbose_name=justif_nouveau_statut_label, null=True, blank=True)
a83daab3 418 justif_nouveau_tmp_remplacement_label = u"Si l'employé effectue un remplacement temporaire, préciser"
29dffede 419 justif_nouveau_tmp_remplacement = models.TextField(verbose_name=justif_nouveau_tmp_remplacement_label, null=True, blank=True)
a83daab3 420 justif_nouveau_salaire_label = u"Si le salaire de l'employé ne correspond pas au classement du poste ou est différent du salaire antérieur, justifier "
29dffede 421 justif_nouveau_salaire = models.TextField(verbose_name=justif_nouveau_salaire_label, null=True, blank=True)
a83daab3 422 justif_nouveau_commentaire_label = u"COMMENTAIRES ADDITIONNELS"
29dffede
OL
423 justif_nouveau_commentaire = models.TextField(verbose_name=justif_nouveau_commentaire_label, null=True, blank=True)
424 justif_rempl_type_contrat_label = u"Changement de type de contrat, ex : d'un CDD en CDI"
425 justif_rempl_type_contrat = models.TextField(verbose_name=justif_rempl_type_contrat_label, null=True, blank=True)
a83daab3 426 justif_rempl_statut_employe_label = u"Si le statut de l'employé a été modifié pour ce poste ; ex :national, expatrié, màd, détachement ? Si oui, justifier"
29dffede 427 justif_rempl_statut_employe = models.TextField(verbose_name=justif_rempl_statut_employe_label, null=True, blank=True)
a83daab3 428 justif_rempl_evaluation_label = u"L'évaluation de l'employé est-elle favorable? Préciser"
29dffede
OL
429 justif_rempl_evaluation = models.TextField(verbose_name=justif_rempl_evaluation_label, null=True, blank=True)
430 justif_rempl_salaire_label = u"Si le salaire de l'employé est modifié et/ou ne correspond pas à son classement, justifier"
431 justif_rempl_salaire = models.TextField(verbose_name=justif_rempl_salaire_label, null=True, blank=True)
a83daab3 432 justif_rempl_commentaire_label = u"COMMENTAIRES ADDITIONNELS"
29dffede
OL
433 justif_rempl_commentaire = models.TextField(verbose_name=justif_rempl_commentaire_label, null=True, blank=True)
434
bd28238f 435 # Comptes
dfc2c344 436 compte_compta = models.CharField(max_length=10, default='aucun',
437 verbose_name=u'Compte comptabilité',
438 choices=COMPTE_COMPTA_CHOICES)
bd28238f 439 compte_courriel = models.BooleanField()
428e3c0b 440
c3f0b49f
EMS
441 # DAE numérisée
442 dae_numerisee = models.FileField(upload_to='dae/dae_numerisee', storage=UPLOAD_STORAGE,
5be87e56 443 blank=True, null=True, verbose_name="DAE numérisée")
c3f0b49f 444
e4f56614
OL
445 # Managers
446 objects = DossierManager()
428e3c0b 447
16b1454e
OL
448 def __init__(self, *args, **kwargs):
449 # Bouchon pour créer une date fictive necessaire pour valider un dossier
450 # à cause de l'héritage
451 super(rh.Dossier_, self).__init__(*args, **kwargs)
452 super(DossierWorkflow, self).__init__(*args, **kwargs)
453 import datetime
454 self.date_debut = datetime.datetime.today()
455
aec2c91e 456 def __unicode__(self):
e4f56614 457 return u'[%s] %s - %s' % (self.poste.implantation, self.poste.nom, self.employe)
bd28238f 458
317ce433
OL
459 def est_importe(self):
460 """Test si le dossier a déjà été importé"""
461 return dae.ImportDossier.objects.filter(dae=self).exists()
462
463 def importer(self):
464 if not self.poste.est_importe():
465 raise Exception('Le poste de cette DAE doît être importé')
466 return True
467
a7186cbb
OL
468 def taux_devise(self):
469 if self.devise.code == 'EUR':
470 return 1
2455f48d 471 liste_taux = self.devise.tauxchange_set.order_by('-annee')
a7186cbb
OL
472 if len(liste_taux) == 0:
473 raise DeviseException(u"La devise %s n'a pas de taux pour l'implantation %s" % (self.devise, self.poste.implantation))
474 else:
475 return liste_taux[0].taux
476
eed93931
OL
477 def get_salaire_anterieur_euros(self):
478 if self.devise_anterieur.code == 'EUR':
479 tx = 1
480 else:
2455f48d 481 liste_taux = self.devise_anterieur.tauxchange_set.order_by('-annee')
eed93931
OL
482 if len(liste_taux) == 0:
483 raise DeviseException(u"La devise %s n'a pas de taux pour l'implantation %s" % (self.devise_anterieur, self.poste.implantation))
484 tx = liste_taux[0].taux
485 return (float)(tx) * (float)(self.salaire_anterieur)
486
487 def get_salaire_titulaire_anterieur_euros(self):
16b1454e
OL
488 if self.devise_titulaire_anterieur is None:
489 return None
2626f449 490 if self.devise_titulaire_anterieur.code == 'EUR':
eed93931
OL
491 tx = 1
492 else:
2455f48d 493 liste_taux = self.devise_titulaire_anterieur.tauxchange_set.order_by('-annee')
eed93931
OL
494 if len(liste_taux) == 0:
495 raise DeviseException(u"La devise %s n'a pas de taux pour l'implantation %s" % (self.devise_titulaire_anterieur, self.poste.implantation))
496 tx = liste_taux[0].taux
497 return (float)(tx) * (float)(self.salaire_titulaire_anterieur)
498
b1baa306 499 def get_salaire_euros(self):
a7186cbb 500 tx = self.taux_devise()
b1baa306
OL
501 return (float)(tx) * (float)(self.salaire)
502
bf6fbbcf 503 def get_remunerations_brutes(self):
57bd966c 504 """
bf6fbbcf
OL
505 1 Salaire de base
506 3 Indemnité de base
507 4 Indemnité d'expatriation
508 5 Indemnité pour frais
509 6 Indemnité de logement
510 7 Indemnité de fonction
511 8 Indemnité de responsabilité
512 9 Indemnité de transport
513 10 Indemnité compensatrice
514 11 Indemnité de subsistance
515 12 Indemnité différentielle
516 13 Prime d'installation
517 14 Billet d'avion
518 15 Déménagement
519 16 Indemnité de départ
520 18 Prime de 13ième mois
521 19 Prime d'intérim
57bd966c 522 """
bf6fbbcf 523 ids = [1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19]
a4125771 524 return [r for r in self.dae_remunerations.all() if r.type_id in ids]
bf6fbbcf
OL
525
526 def get_charges_salariales(self):
527 """
528 20 Charges salariales ?
529 """
530 ids = [20, ]
a4125771 531 return [r for r in self.dae_remunerations.all() if r.type_id in ids]
bf6fbbcf
OL
532
533 def get_total_charges_salariales(self):
534 total = 0.0
535 for r in self.get_charges_salariales():
e84c8ef1 536 total += r.montant_euros()
bf6fbbcf
OL
537 return total
538
539 def get_charges_patronales(self):
540 """
541 17 Charges patronales
542 """
543 ids = [17, ]
a4125771 544 return [r for r in self.dae_remunerations.all() if r.type_id in ids]
bf6fbbcf
OL
545
546 def get_total_charges_patronales(self):
a9e52624 547 total = 0.0
bf6fbbcf 548 for r in self.get_charges_patronales():
e84c8ef1 549 total += r.montant_euros()
a9e52624 550 return total
57bd966c 551
bf6fbbcf
OL
552 def get_salaire_brut(self):
553 """
554 somme des rémuérations brutes
555 """
556 total = 0.0
557 for r in self.get_remunerations_brutes():
e84c8ef1 558 total += r.montant_euros()
bf6fbbcf
OL
559 return total
560
561 def get_salaire_net(self):
562 """
563 salaire brut - charges salariales
564 """
565 total_charges = 0.0
566 for r in self.get_charges_salariales():
e84c8ef1 567 total_charges += r.montant_euros()
bf6fbbcf
OL
568 return self.get_salaire_brut() - total_charges
569
570 def get_couts_auf(self):
571 """
572 salaire net + charges patronales
573 """
574 total_charges = 0.0
575 for r in self.get_charges_patronales():
e84c8ef1 576 total_charges += r.montant_euros()
bf6fbbcf
OL
577 return self.get_salaire_net() + total_charges
578
579 def get_remunerations_tierces(self):
57bd966c 580 """
bf6fbbcf 581 2 Salaire MAD
57bd966c 582 """
a4125771 583 return [r for r in self.dae_remunerations.all() if r.type_id in (2, )]
57bd966c 584
bf6fbbcf 585 def get_total_remunerations_tierces(self):
a9e52624 586 total = 0.0
1bc84af4 587 for r in self.get_remunerations_tierces():
e84c8ef1 588 total += r.montant_euros()
a9e52624
OL
589 return total
590
c511cd1f
EMS
591 def valide(self):
592 return self.etat in (DOSSIER_ETAT_REGION_FINALISATION,
593 DOSSIER_ETAT_DRH_FINALISATION,
594 DOSSIER_ETAT_FINALISE)
595
bd28238f 596
0140cbd2 597# Tester l'enregistrement car les models.py sont importés au complet
598if not reversion.is_registered(Dossier):
599 reversion.register(Dossier)
bd28238f 600
a4125771 601class DossierPiece(rh.DossierPiece_):
2d4d2fcf 602 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
603 Ex.: Lettre de motivation.
604 """
a4125771 605 pass
2d4d2fcf 606
a4125771 607class DossierComparaison(rh.DossierComparaison_):
03b395db
OL
608 """
609 Photo d'une comparaison salariale au moment de l'embauche.
610 """
766ca378
OL
611 statut = models.ForeignKey(rh.Statut, related_name='+', verbose_name='Statut', null=True, blank=True, )
612 classement = models.ForeignKey(rh.Classement, related_name='+', verbose_name='Classement', null=True, blank=True, )
03b395db 613
c589d980 614
2d4d2fcf 615### RÉMUNÉRATION
616
a4125771
OL
617class Remuneration(rh.Remuneration_):
618 pass
c1834169
EMS
619
620### CONTRATS
621
a4125771
OL
622class Contrat(rh.Contrat_):
623 pass
317ce433
OL
624
625# modèle de liaison entre les systèmes
626
627class ImportDossier(models.Model):
628 dae = models.ForeignKey('dae.Dossier', related_name='+')
629 rh = models.ForeignKey('rh.Dossier', related_name='+')
630
631class ImportPoste(models.Model):
632 dae = models.ForeignKey('dae.Poste', related_name='+')
633 rh = models.ForeignKey('rh.Poste', related_name='+')