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