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