[#3059] Retrait du mécanisme d'importation précédent
[auf_rh_dae.git] / project / dae / models.py
1 # -=- encoding: utf-8 -=-
2
3 import os
4 from datetime import date, timedelta
5
6 import reversion
7 from auf.django.metadata.models import AUFMetadata
8 from django.conf import settings
9 from django.core.files.storage import FileSystemStorage
10 from django.db import models
11 from django.db.models import Q
12
13 from project.dae.managers import PosteManager, DossierManager
14 from project.dae.workflow import PosteWorkflow, DossierWorkflow
15 from project.dae.workflow import \
16 DOSSIER_ETAT_DRH_FINALISATION, DOSSIER_ETAT_REGION_FINALISATION, \
17 DOSSIER_ETAT_FINALISE
18
19 # XXX: Saloperie, il faut importer rh.models à partir d'un autre namespace
20 # à cause du hack app_context() dans project.rh.models. Très fragile. Il
21 # faut régler ça aussi vite que possible.
22 from rh import models as rh
23 from rh.models import HELP_TEXT_DATE
24
25 # Upload de fichiers
26 UPLOAD_STORAGE = FileSystemStorage(settings.PRIVE_MEDIA_ROOT)
27
28
29 ### POSTE
30
31 POSTE_APPEL_CHOICES = (
32 ('interne', 'Interne'),
33 ('externe', 'Externe'),
34 )
35 POSTE_ACTION = (
36 ('N', u"Nouveau poste"),
37 ('M', u"Poste existant"),
38 ('E', u"Évolution de poste"),
39 )
40
41
42 class DeviseException(Exception):
43 silent_variable_failure = True
44
45
46 class Poste(PosteWorkflow, rh.Poste_):
47
48 type_intervention = models.CharField(
49 max_length=1, choices=POSTE_ACTION, default='N'
50 )
51
52 # Modèle existant
53 id_rh = models.ForeignKey(
54 rh.Poste, null=True, related_name='postes_dae', editable=False,
55 verbose_name=u"Mise à jour du poste"
56 )
57
58 # Rémunération
59 indemn_expat_min = models.DecimalField(
60 max_digits=13, decimal_places=2, default=0
61 )
62 indemn_expat_max = models.DecimalField(
63 max_digits=12, decimal_places=2, default=0
64 )
65 indemn_fct_min = models.DecimalField(
66 max_digits=12, decimal_places=2, default=0
67 )
68 indemn_fct_max = models.DecimalField(
69 max_digits=12, decimal_places=2, default=0
70 )
71 charges_patronales_min = models.DecimalField(
72 max_digits=12, decimal_places=2, default=0
73 )
74 charges_patronales_max = models.DecimalField(
75 max_digits=12, decimal_places=2, default=0
76 )
77
78 # Managers
79 objects = PosteManager()
80
81 def _get_key(self):
82 """
83 Les vues sont montées selon une clef spéciale
84 pour identifier la provenance du poste.
85 Cette méthode fournit un moyen de reconstruire cette clef
86 afin de générer les URLs.
87 """
88 return "dae-%s" % self.id
89 key = property(_get_key)
90
91 def get_dossiers(self):
92 """
93 Liste tous les anciens dossiers liés à ce poste.
94 (Le nom de la relation sur le rh.Poste est mal choisi
95 poste1 au lieu de dossier1)
96 Note1 : seulement le dosssier principal fait l'objet de la recherche.
97 Note2 : les dossiers sont retournés du plus récent au plus vieux.
98 (Ce test est fait en fonction du id,
99 car les dates de création sont absentes de rh v1).
100 """
101 if self.id_rh is None:
102 return []
103 return self.id_rh.rh_dossiers.all()
104
105 def dans_rh(self):
106 """
107 Retourne le poste RH s'il existe.
108 """
109 return self.id_rh
110
111 def importer_dans_rh(self):
112 """
113 Importe le poste DAE dans un poste RH existant ou nouveau.
114 """
115 poste_rh = self.dans_rh() or rh.Poste()
116 poste_rh.nom = self.nom
117 poste_rh.implantation = self.implantation
118 poste_rh.type_poste = self.type_poste
119 poste_rh.service = self.service
120 poste_rh.responsable = self.responsable
121 poste_rh.regime_travail = self.regime_travail
122 poste_rh.regime_travail_nb_heure_semaine = \
123 self.regime_travail_nb_heure_semaine
124 poste_rh.local = self.local
125 poste_rh.expatrie = self.expatrie
126 poste_rh.mise_a_disposition = self.mise_a_disposition
127 poste_rh.appel = self.appel
128 poste_rh.classement_min = self.classement_min
129 poste_rh.classement_max = self.classement_max
130 poste_rh.valeur_point_min = self.valeur_point_min
131 poste_rh.valeur_point_max = self.valeur_point_max
132 poste_rh.devise_min = self.devise_min
133 poste_rh.devise_max = self.devise_max
134 poste_rh.salaire_min = self.salaire_min
135 poste_rh.salaire_max = self.salaire_max
136 poste_rh.indemn_min = self.indemn_min
137 poste_rh.indemn_max = self.indemn_max
138 poste_rh.autre_min = self.autre_min
139 poste_rh.autre_max = self.autre_max
140 poste_rh.devise_comparaison = self.devise_comparaison
141 poste_rh.comp_locale_min = self.comp_locale_min
142 poste_rh.comp_locale_max = self.comp_locale_max
143 poste_rh.comp_universite_min = self.comp_universite_min
144 poste_rh.comp_universite_max = self.comp_universite_max
145 poste_rh.comp_fonctionpub_min = self.comp_fonctionpub_min
146 poste_rh.comp_fonctionpub_max = self.comp_fonctionpub_max
147 poste_rh.comp_ong_min = self.comp_ong_min
148 poste_rh.comp_ong_max = self.comp_ong_max
149 poste_rh.comp_autre_min = self.comp_autre_min
150 poste_rh.comp_autre_max = self.comp_autre_max
151 poste_rh.justification = self.justification
152 poste_rh.date_debut = self.date_debut
153 poste_rh.date_fin = self.date_fin
154 poste_rh.save()
155
156 for piece in self.dae_pieces.all():
157 piece_rh = poste_rh.rh_pieces.create(
158 poste=poste_rh,
159 nom=piece.nom
160 )
161 piece_rh.fichier.save(
162 os.path.basename(piece.fichier.name), piece.fichier
163 )
164
165 rh.PosteComparaison.objects.filter(poste=poste_rh).delete()
166 for comp in self.dae_comparaisons_internes.all():
167 poste_rh.rh_comparaisons_internes.create(
168 implantation=comp.implantation,
169 nom=comp.nom,
170 montant=comp.montant,
171 devise=comp.devise
172 )
173
174 rh.PosteFinancement.objects.filter(poste=poste_rh).delete()
175 for financement in self.dae_financements.all():
176 poste_rh.rh_financements.create(
177 type=financement.type,
178 pourcentage=financement.pourcentage,
179 commentaire=financement.commentaire
180 )
181
182 self.id_rh = poste_rh
183 self.save()
184 return poste_rh
185
186 def get_employe(self):
187 """
188 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
189 """
190 dossiers = self.get_dossiers()
191 if len(dossiers) > 0:
192 return dossiers[0].employe
193 else:
194 return None
195
196 def get_default_devise(self):
197 """Récupère la devise par défaut en fonction de l'implantation
198 (EUR autrement)
199 """
200 try:
201 implantation_devise = rh.TauxChange.objects \
202 .filter(implantation=self.implantation)[0].devise
203 except:
204 implantation_devise = 5 # EUR
205 return implantation_devise
206
207 #####################
208 # Classement de poste
209 #####################
210
211 def get_couts_minimum(self):
212 return self.salaire_min + self.indemn_expat_min + \
213 self.indemn_fct_min + self.charges_patronales_min + \
214 self.autre_min
215
216 def get_salaire_minimum(self):
217 return self.get_couts_minimum() - self.charges_patronales_min
218
219 def get_taux_minimum(self):
220 if self.devise_min.code == 'EUR':
221 return 1
222 liste_taux = self.devise_min.tauxchange_set.order_by('-annee')
223 if len(liste_taux) == 0:
224 raise DeviseException(
225 u"La devise %s n'a pas de taux pour l'implantation %s" %
226 (self.devise_min, self.implantation))
227 else:
228 return liste_taux[0].taux
229
230 def get_couts_minimum_euros(self):
231 return float(self.get_couts_minimum()) * self.get_taux_minimum()
232
233 def get_salaire_minimum_euros(self):
234 return float(self.get_salaire_minimum()) * self.get_taux_minimum()
235
236 def get_couts_maximum(self):
237 return self.salaire_max + self.indemn_expat_max + \
238 self.indemn_fct_max + self.charges_patronales_max + \
239 self.autre_max
240
241 def get_salaire_maximum(self):
242 return self.get_couts_maximum() - self.charges_patronales_max
243
244 def get_taux_maximum(self):
245 if self.devise_max.code == 'EUR':
246 return 1
247 liste_taux = self.devise_max.tauxchange_set.order_by('-annee')
248 if len(liste_taux) == 0:
249 raise DeviseException(
250 u"La devise %s n'a pas de taux pour l'implantation %s" %
251 (self.devise_max, self.implantation)
252 )
253 else:
254 return liste_taux[0].taux
255
256 def get_couts_maximum_euros(self):
257 return float(self.get_couts_maximum()) * self.get_taux_maximum()
258
259 def get_salaire_maximum_euros(self):
260 return float(self.get_salaire_maximum()) * self.get_taux_maximum()
261
262 def show_taux_minimum(self):
263 try:
264 return self.get_taux_minimum()
265 except DeviseException, e:
266 return e
267
268 def show_couts_minimum_euros(self):
269 try:
270 return self.get_couts_minimum_euros()
271 except DeviseException, e:
272 return e
273
274 def show_salaire_minimum_euros(self):
275 try:
276 return self.get_salaire_minimum_euros()
277 except DeviseException, e:
278 return e
279
280 def show_taux_maximum(self):
281 try:
282 return self.get_taux_maximum()
283 except DeviseException, e:
284 return e
285
286 def show_couts_maximum_euros(self):
287 try:
288 return self.get_couts_maximum_euros()
289 except DeviseException, e:
290 return e
291
292 def show_salaire_maximum_euros(self):
293 try:
294 return self.get_salaire_maximum_euros()
295 except DeviseException, e:
296 return e
297
298 # Comparaison de poste
299 def est_comparable(self):
300 """
301 Si on a au moins une valeur de saisie dans les comparaisons, alors
302 le poste est comparable.
303 """
304 if self.comp_universite_min is None and \
305 self.comp_fonctionpub_min is None and \
306 self.comp_locale_min is None and \
307 self.comp_ong_min is None and \
308 self.comp_autre_min is None and \
309 self.comp_universite_max is None and \
310 self.comp_fonctionpub_max is None and \
311 self.comp_locale_max is None and \
312 self.comp_ong_max is None and \
313 self.comp_autre_max is None:
314 return False
315 else:
316 return True
317
318 def get_taux_comparaison(self):
319 try:
320 return rh.TauxChange.objects \
321 .filter(devise=self.devise_comparaison)[0].taux
322 except:
323 return 1
324
325 def get_comp_universite_min_euros(self):
326 return (float)(self.comp_universite_min) * self.get_taux_comparaison()
327
328 def get_comp_fonctionpub_min_euros(self):
329 return (float)(self.comp_fonctionpub_min) * self.get_taux_comparaison()
330
331 def get_comp_locale_min_euros(self):
332 return (float)(self.comp_locale_min) * self.get_taux_comparaison()
333
334 def get_comp_ong_min_euros(self):
335 return (float)(self.comp_ong_min) * self.get_taux_comparaison()
336
337 def get_comp_autre_min_euros(self):
338 return (float)(self.comp_autre_min) * self.get_taux_comparaison()
339
340 def get_comp_universite_max_euros(self):
341 return (float)(self.comp_universite_max) * self.get_taux_comparaison()
342
343 def get_comp_fonctionpub_max_euros(self):
344 return (float)(self.comp_fonctionpub_max) * self.get_taux_comparaison()
345
346 def get_comp_locale_max_euros(self):
347 return (float)(self.comp_locale_max) * self.get_taux_comparaison()
348
349 def get_comp_ong_max_euros(self):
350 return (float)(self.comp_ong_max) * self.get_taux_comparaison()
351
352 def get_comp_autre_max_euros(self):
353 return (float)(self.comp_autre_max) * self.get_taux_comparaison()
354
355 def __unicode__(self):
356 """
357 Cette fonction est consommatrice SQL car elle cherche les dossiers
358 qui ont été liés à celui-ci.
359 """
360 data = (
361 self.implantation,
362 self.type_poste.nom,
363 self.nom,
364 )
365 return u'%s - %s (%s)' % data
366
367 # Tester l'enregistrement car les models.py sont importés au complet
368 if not reversion.is_registered(Poste):
369 reversion.register(Poste)
370
371 POSTE_FINANCEMENT_CHOICES = (
372 ('A', 'A - Frais de personnel'),
373 ('B', 'B - Projet(s)-Titre(s)'),
374 ('C', 'C - Autre')
375 )
376
377
378 class PosteFinancement(rh.PosteFinancement_):
379 pass
380
381
382 class PostePiece(rh.PostePiece_):
383 pass
384
385
386 class PosteComparaison(rh.PosteComparaison_):
387 statut = models.ForeignKey(
388 rh.Statut, related_name='+', verbose_name=u'Statut', null=True,
389 blank=True
390 )
391 classement = models.ForeignKey(
392 rh.Classement, related_name='+', verbose_name=u'Classement',
393 null=True, blank=True
394 )
395
396 ### EMPLOYÉ/PERSONNE
397
398 # TODO : migration pour m -> M, f -> F
399
400 GENRE_CHOICES = (
401 ('m', 'Homme'),
402 ('f', 'Femme'),
403 )
404
405
406 class Employe(AUFMetadata):
407
408 # Modèle existant
409 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+',
410 verbose_name=u'Employé')
411 nom = models.CharField(max_length=255)
412 prenom = models.CharField(max_length=255, verbose_name=u'Prénom')
413 genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
414
415 def __unicode__(self):
416 return u'%s %s' % (self.prenom, self.nom.upper())
417
418 def dans_rh(self):
419 """
420 Retourne l'employé RH associé à cet employé DAE.
421 """
422 return self.id_rh
423
424 def importer_dans_rh(self):
425 """
426 Importe l'employé DAE dans un employé RH existant ou nouveau.
427 """
428 employe_rh = self.dans_rh() or rh.Employe.objects.create(
429 nom=self.nom,
430 prenom=self.prenom,
431 genre=self.genre
432 )
433 self.id_rh = employe_rh
434 self.save()
435 return employe_rh
436
437
438 ### DOSSIER
439
440 STATUT_RESIDENCE_CHOICES = (
441 ('local', 'Local'),
442 ('expat', 'Expatrié'),
443 )
444
445 COMPTE_COMPTA_CHOICES = (
446 ('coda', 'CODA'),
447 ('scs', 'SCS'),
448 ('aucun', 'Aucun'),
449 )
450
451
452 class Dossier(DossierWorkflow, rh.Dossier_):
453 poste = models.ForeignKey(
454 'Poste', db_column='poste', related_name='%(app_label)s_dossiers'
455 )
456 employe = models.ForeignKey(
457 'Employe', db_column='employe',
458 related_name='%(app_label)s_dossiers', verbose_name=u"Employé"
459 )
460 organisme_bstg_autre = models.CharField(max_length=255,
461 verbose_name=u"Autre organisme",
462 help_text="indiquer l'organisme ici s'il n'est pas dans la liste",
463 null=True,
464 blank=True,)
465
466 # Lien avec le dossier
467 dossier_rh = models.ForeignKey(
468 rh.Dossier, related_name='dossiers_dae', null=True, blank=True
469 )
470
471 # Données antérieures de l'employé
472 statut_anterieur = models.ForeignKey(
473 rh.Statut, related_name='+', null=True, blank=True,
474 verbose_name=u'Statut antérieur')
475 classement_anterieur = models.ForeignKey(
476 rh.Classement, related_name='+', null=True, blank=True,
477 verbose_name=u'Classement précédent')
478 salaire_anterieur = models.DecimalField(
479 max_digits=12, decimal_places=2, null=True, default=None,
480 blank=True, verbose_name=u'Salaire précédent')
481 devise_anterieur = models.ForeignKey(
482 rh.Devise, related_name='+', null=True, blank=True
483 )
484 type_contrat_anterieur = models.ForeignKey(
485 rh.TypeContrat, related_name='+', null=True, blank=True,
486 verbose_name=u'Type contrat antérieur'
487 )
488
489 # Données du titulaire précédent
490 employe_anterieur = models.ForeignKey(
491 rh.Employe, related_name='+', null=True, blank=True,
492 verbose_name=u'Employé précédent')
493 statut_titulaire_anterieur = models.ForeignKey(
494 rh.Statut, related_name='+', null=True, blank=True,
495 verbose_name=u'Statut titulaire précédent')
496 classement_titulaire_anterieur = models.ForeignKey(
497 rh.Classement, related_name='+', null=True, blank=True,
498 verbose_name=u'Classement titulaire précédent')
499 salaire_titulaire_anterieur = models.DecimalField(
500 max_digits=12, decimal_places=2, default=None, null=True,
501 blank=True, verbose_name=u'Salaire titulaire précédent')
502 devise_titulaire_anterieur = models.ForeignKey(
503 rh.Devise, related_name='+', null=True, blank=True
504 )
505
506 # Rémunération
507 salaire = models.DecimalField(max_digits=13, decimal_places=2,
508 verbose_name=u'Salaire de base',
509 null=True, default=None)
510 devise = models.ForeignKey(rh.Devise, default=5, related_name='+')
511
512 # Contrat
513 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
514 contrat_date_debut = models.DateField(help_text=HELP_TEXT_DATE)
515 contrat_date_fin = models.DateField(null=True, blank=True,
516 help_text=HELP_TEXT_DATE)
517
518 # Justifications
519 justif_nouveau_statut_label = u'Justifier le statut que ce type ' \
520 u'de poste nécessite (national, expatrié, màd ou détachement)'
521 justif_nouveau_statut = models.TextField(
522 verbose_name=justif_nouveau_statut_label, null=True, blank=True
523 )
524 justif_nouveau_tmp_remplacement_label = u"Si l'employé effectue un " \
525 u"remplacement temporaire, préciser"
526 justif_nouveau_tmp_remplacement = models.TextField(
527 verbose_name=justif_nouveau_tmp_remplacement_label, null=True,
528 blank=True
529 )
530 justif_nouveau_salaire_label = u"Si le salaire de l'employé ne " \
531 u"correspond pas au classement du poste ou est différent " \
532 u"du salaire antérieur, justifier "
533 justif_nouveau_salaire = models.TextField(
534 verbose_name=justif_nouveau_salaire_label, null=True, blank=True
535 )
536 justif_nouveau_commentaire_label = u"COMMENTAIRES ADDITIONNELS"
537 justif_nouveau_commentaire = models.TextField(
538 verbose_name=justif_nouveau_commentaire_label, null=True, blank=True
539 )
540 justif_rempl_type_contrat_label = \
541 u"Changement de type de contrat, ex : d'un CDD en CDI"
542 justif_rempl_type_contrat = models.TextField(
543 verbose_name=justif_rempl_type_contrat_label, null=True, blank=True
544 )
545 justif_rempl_statut_employe_label = \
546 u"Si le statut de l'employé a été modifié pour ce poste ; " \
547 u"ex : national, expatrié, màd, détachement ? Si oui, justifier"
548 justif_rempl_statut_employe = models.TextField(
549 verbose_name=justif_rempl_statut_employe_label, null=True, blank=True
550 )
551 justif_rempl_evaluation_label = \
552 u"L'évaluation de l'employé est-elle favorable? Préciser"
553 justif_rempl_evaluation = models.TextField(
554 verbose_name=justif_rempl_evaluation_label, null=True, blank=True
555 )
556 justif_rempl_salaire_label = \
557 u"Si le salaire de l'employé est modifié et/ou ne correspond " \
558 u"pas à son classement, justifier"
559 justif_rempl_salaire = models.TextField(
560 verbose_name=justif_rempl_salaire_label, null=True, blank=True
561 )
562 justif_rempl_commentaire_label = u"COMMENTAIRES ADDITIONNELS"
563 justif_rempl_commentaire = models.TextField(
564 verbose_name=justif_rempl_commentaire_label, null=True, blank=True
565 )
566
567 # Comptes
568 compte_compta = models.CharField(max_length=10, default='aucun',
569 verbose_name=u'Compte comptabilité',
570 choices=COMPTE_COMPTA_CHOICES)
571 compte_courriel = models.BooleanField()
572
573 # DAE numérisée
574 dae_numerisee = models.FileField(
575 upload_to='dae/dae_numerisee', storage=UPLOAD_STORAGE, blank=True,
576 null=True, verbose_name="DAE numérisée"
577 )
578
579 # Managers
580 objects = DossierManager()
581
582 def __init__(self, *args, **kwargs):
583 # Bouchon pour créer une date fictive necessaire pour valider un
584 # dossier à cause de l'héritage
585 super(rh.Dossier_, self).__init__(*args, **kwargs)
586 super(DossierWorkflow, self).__init__(*args, **kwargs)
587 import datetime
588 self.date_debut = datetime.datetime.today()
589
590 def __unicode__(self):
591 return u'[%s] %s - %s' % (
592 self.poste.implantation, self.poste.nom, self.employe
593 )
594
595 def dans_rh(self):
596 """
597 Retourne le dossier associé dans le système RH ou ``None`` s'il n'y
598 en a pas.
599 """
600 if self.dossier_rh:
601 return self.dossier_rh
602 today = date.today()
603 poste_rh = self.poste.dans_rh()
604 if poste_rh is None:
605 return None
606 employe_rh = self.employe.dans_rh()
607 if employe_rh is None:
608 return None
609 try:
610 return rh.Dossier.objects.get(
611 Q(date_debut=None) | Q(date_debut__lte=today),
612 Q(date_fin=None) | Q(date_fin__gte=today),
613 poste=poste_rh,
614 employe=employe_rh
615 )
616 except rh.Dossier.DoesNotExist:
617 return None
618
619 def importer_dans_rh(self):
620 """
621 Importe les données du dossier DAE dans un dossier RH existant ou
622 nouveau.
623 """
624 poste_rh = self.poste.importer_dans_rh()
625 employe_rh = self.employe.importer_dans_rh()
626 dossier_rh = self.dans_rh() or \
627 rh.Dossier(poste=poste_rh, employe=employe_rh)
628
629 dossier_rh.statut = self.statut
630 dossier_rh.organisme_bstg = self.organisme_bstg
631 dossier_rh.remplacement = self.remplacement
632 dossier_rh.remplacement_de = self.remplacement_de
633 dossier_rh.statut_residence = self.statut_residence
634 dossier_rh.classement = self.classement
635 dossier_rh.regime_travail = self.regime_travail
636 dossier_rh.regime_travail_nb_heure_semaine = \
637 self.regime_travail_nb_heure_semaine
638 dossier_rh.date_debut = self.date_debut
639 dossier_rh.date_fin = self.date_fin
640 dossier_rh.save()
641
642 rh.DossierComparaison.objects.filter(dossier=dossier_rh).delete()
643 for comp in self.dae_comparaisons.all():
644 dossier_rh.rh_comparaisons.create(
645 implantation=comp.implantation,
646 poste=comp.poste,
647 personne=comp.personne,
648 montant=comp.montant,
649 devise=comp.devise
650 )
651
652 if not dossier_rh.rh_contrats.filter(
653 type_contrat=self.type_contrat,
654 date_debut=self.contrat_date_debut,
655 date_fin=self.contrat_date_fin
656 ).exists():
657 dossier_rh.rh_contrats.create(
658 type_contrat=self.type_contrat,
659 date_debut=self.contrat_date_debut,
660 date_fin=self.contrat_date_fin,
661 )
662
663 for piece in self.dae_dossierpieces.all():
664 piece_rh = dossier_rh.rh_dossierpieces.create(
665 nom=piece.nom
666 )
667 piece_rh.fichier.save(
668 os.path.basename(piece.fichier.name), piece.fichier
669 )
670
671 # Fermer les rémunérations qui commencent avant le début du contrat
672 dossier_rh.rh_remunerations.filter(
673 Q(date_debut=None) | Q(date_debut__lt=self.contrat_date_debut),
674 Q(date_fin=None) | Q(date_fin__gte=self.contrat_date_debut)
675 ).update(date_fin=self.contrat_date_debut - timedelta(1))
676
677 # Effacer les rémunérations qui commencent à la date du contrat
678 dossier_rh.rh_remunerations \
679 .filter(date_debut=self.contrat_date_debut) \
680 .delete()
681
682 for remun in self.dae_remunerations.all():
683 dossier_rh.rh_remunerations.get_or_create(
684 type=remun.type,
685 type_revalorisation=remun.type_revalorisation,
686 montant=remun.montant,
687 devise=remun.devise,
688 commentaire=remun.commentaire,
689 date_debut=self.contrat_date_debut,
690 date_fin=self.contrat_date_fin
691 )
692
693 # Enregistrer le lien avec le dossier RH
694 self.dossier_rh = dossier_rh
695 self.save()
696
697 return dossier_rh
698
699 def get_salaire_anterieur_euros(self):
700 if self.devise_anterieur is None:
701 return None
702 try:
703 taux = self.taux_devise(self.devise_anterieur)
704 except Exception, e:
705 return e
706 if not taux:
707 return None
708 return int(round(float(self.salaire_anterieur) * float(taux), 2))
709
710 def get_salaire_titulaire_anterieur_euros(self):
711 if self.devise_titulaire_anterieur is None:
712 return None
713 try:
714 taux = self.taux_devise(self.devise_titulaire_anterieur)
715 except Exception, e:
716 return e
717 if not taux:
718 return None
719 return int(round(
720 float(self.salaire_titulaire_anterieur) * float(taux), 2
721 ))
722
723 def valide(self):
724 return self.etat in (DOSSIER_ETAT_REGION_FINALISATION,
725 DOSSIER_ETAT_DRH_FINALISATION,
726 DOSSIER_ETAT_FINALISE)
727
728
729 # Tester l'enregistrement car les models.py sont importés au complet
730 if not reversion.is_registered(Dossier):
731 reversion.register(Dossier)
732
733
734 class DossierPiece(rh.DossierPiece_):
735 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
736 Ex.: Lettre de motivation.
737 """
738 pass
739
740
741 class DossierComparaison(rh.DossierComparaison_):
742 """
743 Photo d'une comparaison salariale au moment de l'embauche.
744 """
745 statut = models.ForeignKey(
746 rh.Statut, related_name='+', verbose_name='Statut', null=True,
747 blank=True
748 )
749 classement = models.ForeignKey(
750 rh.Classement, related_name='+', verbose_name='Classement',
751 null=True, blank=True
752 )
753
754
755 ### RÉMUNÉRATION
756
757 class Remuneration(rh.Remuneration_):
758 pass
759
760
761 ### CONTRATS
762
763 class Contrat(rh.Contrat_):
764 pass