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