[#2658] Retrait du hack app_label() dans rh.models
[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 project.rh import models as rh
23 from project.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 poste = models.ForeignKey(
386 Poste, db_column='poste', related_name='dae_financements'
387 )
388
389
390 class PostePiece(rh.PostePiece_):
391 poste = models.ForeignKey(
392 Poste, db_column='poste', related_name='dae_pieces'
393 )
394
395
396 class PosteComparaison(rh.PosteComparaison_):
397 poste = models.ForeignKey(
398 Poste, related_name='dae_comparaisons_internes'
399 )
400 statut = models.ForeignKey(
401 rh.Statut, related_name='+', verbose_name=u'Statut', null=True,
402 blank=True
403 )
404 classement = models.ForeignKey(
405 rh.Classement, related_name='+', verbose_name=u'Classement',
406 null=True, blank=True
407 )
408
409 ### EMPLOYÉ/PERSONNE
410
411 # TODO : migration pour m -> M, f -> F
412
413 GENRE_CHOICES = (
414 ('m', 'Homme'),
415 ('f', 'Femme'),
416 )
417
418
419 class Employe(AUFMetadata):
420
421 # Modèle existant
422 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+',
423 verbose_name=u'Employé')
424 nom = models.CharField(max_length=255)
425 prenom = models.CharField(max_length=255, verbose_name=u'Prénom')
426 genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
427
428 def __unicode__(self):
429 return u'%s %s' % (self.prenom, self.nom.upper())
430
431 def dans_rh(self):
432 """
433 Retourne l'employé RH associé à cet employé DAE.
434 """
435 return self.id_rh
436
437 def importer_dans_rh(self):
438 """
439 Importe l'employé DAE dans un employé RH existant ou nouveau.
440 """
441 employe_rh = self.dans_rh() or rh.Employe.objects.create(
442 nom=self.nom,
443 prenom=self.prenom,
444 genre=self.genre
445 )
446 self.id_rh = employe_rh
447 self.save()
448 return employe_rh
449
450
451 ### DOSSIER
452
453 STATUT_RESIDENCE_CHOICES = (
454 ('local', 'Local'),
455 ('expat', 'Expatrié'),
456 )
457
458 COMPTE_COMPTA_CHOICES = (
459 ('coda', 'CODA'),
460 ('scs', 'SCS'),
461 ('aucun', 'Aucun'),
462 )
463
464
465 class Dossier(DossierWorkflow, rh.Dossier_):
466 poste = models.ForeignKey(
467 'Poste', db_column='poste', related_name='dae_dossiers'
468 )
469 employe = models.ForeignKey(
470 'Employe', db_column='employe',
471 related_name='rh_dossiers', verbose_name=u"Employé"
472 )
473 organisme_bstg_autre = models.CharField(max_length=255,
474 verbose_name=u"Autre organisme",
475 help_text="indiquer l'organisme ici s'il n'est pas dans la liste",
476 null=True,
477 blank=True,)
478
479 # Lien avec le dossier
480 dossier_rh = models.ForeignKey(
481 rh.Dossier, related_name='dossiers_dae', null=True, blank=True
482 )
483
484 # Données antérieures de l'employé
485 statut_anterieur = models.ForeignKey(
486 rh.Statut, related_name='+', null=True, blank=True,
487 verbose_name=u'Statut antérieur')
488 classement_anterieur = models.ForeignKey(
489 rh.Classement, related_name='+', null=True, blank=True,
490 verbose_name=u'Classement précédent')
491 salaire_anterieur = models.DecimalField(
492 max_digits=12, decimal_places=2, null=True, default=None,
493 blank=True, verbose_name=u'Salaire précédent')
494 devise_anterieur = models.ForeignKey(
495 rh.Devise, related_name='+', null=True, blank=True
496 )
497 type_contrat_anterieur = models.ForeignKey(
498 rh.TypeContrat, related_name='+', null=True, blank=True,
499 verbose_name=u'Type contrat antérieur'
500 )
501
502 # Données du titulaire précédent
503 employe_anterieur = models.ForeignKey(
504 rh.Employe, related_name='+', null=True, blank=True,
505 verbose_name=u'Employé précédent')
506 statut_titulaire_anterieur = models.ForeignKey(
507 rh.Statut, related_name='+', null=True, blank=True,
508 verbose_name=u'Statut titulaire précédent')
509 classement_titulaire_anterieur = models.ForeignKey(
510 rh.Classement, related_name='+', null=True, blank=True,
511 verbose_name=u'Classement titulaire précédent')
512 salaire_titulaire_anterieur = models.DecimalField(
513 max_digits=12, decimal_places=2, default=None, null=True,
514 blank=True, verbose_name=u'Salaire titulaire précédent')
515 devise_titulaire_anterieur = models.ForeignKey(
516 rh.Devise, related_name='+', null=True, blank=True
517 )
518
519 # Rémunération
520 salaire = models.DecimalField(max_digits=13, decimal_places=2,
521 verbose_name=u'Salaire de base',
522 null=True, default=None)
523 devise = models.ForeignKey(rh.Devise, default=5, related_name='+')
524
525 # Contrat
526 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
527 contrat_date_debut = models.DateField(help_text=HELP_TEXT_DATE)
528 contrat_date_fin = models.DateField(null=True, blank=True,
529 help_text=HELP_TEXT_DATE)
530
531 # Justifications
532 justif_nouveau_statut_label = u'Justifier le statut que ce type ' \
533 u'de poste nécessite (national, expatrié, màd ou détachement)'
534 justif_nouveau_statut = models.TextField(
535 verbose_name=justif_nouveau_statut_label, null=True, blank=True
536 )
537 justif_nouveau_tmp_remplacement_label = u"Si l'employé effectue un " \
538 u"remplacement temporaire, préciser"
539 justif_nouveau_tmp_remplacement = models.TextField(
540 verbose_name=justif_nouveau_tmp_remplacement_label, null=True,
541 blank=True
542 )
543 justif_nouveau_salaire_label = u"Si le salaire de l'employé ne " \
544 u"correspond pas au classement du poste ou est différent " \
545 u"du salaire antérieur, justifier "
546 justif_nouveau_salaire = models.TextField(
547 verbose_name=justif_nouveau_salaire_label, null=True, blank=True
548 )
549 justif_nouveau_commentaire_label = u"COMMENTAIRES ADDITIONNELS"
550 justif_nouveau_commentaire = models.TextField(
551 verbose_name=justif_nouveau_commentaire_label, null=True, blank=True
552 )
553 justif_rempl_type_contrat_label = \
554 u"Changement de type de contrat, ex : d'un CDD en CDI"
555 justif_rempl_type_contrat = models.TextField(
556 verbose_name=justif_rempl_type_contrat_label, null=True, blank=True
557 )
558 justif_rempl_statut_employe_label = \
559 u"Si le statut de l'employé a été modifié pour ce poste ; " \
560 u"ex : national, expatrié, màd, détachement ? Si oui, justifier"
561 justif_rempl_statut_employe = models.TextField(
562 verbose_name=justif_rempl_statut_employe_label, null=True, blank=True
563 )
564 justif_rempl_evaluation_label = \
565 u"L'évaluation de l'employé est-elle favorable? Préciser"
566 justif_rempl_evaluation = models.TextField(
567 verbose_name=justif_rempl_evaluation_label, null=True, blank=True
568 )
569 justif_rempl_salaire_label = \
570 u"Si le salaire de l'employé est modifié et/ou ne correspond " \
571 u"pas à son classement, justifier"
572 justif_rempl_salaire = models.TextField(
573 verbose_name=justif_rempl_salaire_label, null=True, blank=True
574 )
575 justif_rempl_commentaire_label = u"COMMENTAIRES ADDITIONNELS"
576 justif_rempl_commentaire = models.TextField(
577 verbose_name=justif_rempl_commentaire_label, null=True, blank=True
578 )
579
580 # Comptes
581 compte_compta = models.CharField(max_length=10, default='aucun',
582 verbose_name=u'Compte comptabilité',
583 choices=COMPTE_COMPTA_CHOICES)
584 compte_courriel = models.BooleanField()
585
586 # DAE numérisée
587 dae_numerisee = models.FileField(
588 upload_to='dae/dae_numerisee', storage=UPLOAD_STORAGE, blank=True,
589 null=True, verbose_name="DAE numérisée"
590 )
591
592 # Managers
593 objects = DossierManager()
594
595 def __init__(self, *args, **kwargs):
596 # Bouchon pour créer une date fictive necessaire pour valider un
597 # dossier à cause de l'héritage
598 super(rh.Dossier_, self).__init__(*args, **kwargs)
599 super(DossierWorkflow, self).__init__(*args, **kwargs)
600 import datetime
601 self.date_debut = datetime.datetime.today()
602
603 def __unicode__(self):
604 return u'[%s] %s - %s' % (
605 self.poste.implantation, self.poste.nom, self.employe
606 )
607
608 def dans_rh(self):
609 """
610 Retourne le dossier associé dans le système RH ou ``None`` s'il n'y
611 en a pas.
612 """
613 if self.dossier_rh:
614 return self.dossier_rh
615 today = date.today()
616 poste_rh = self.poste.dans_rh()
617 if poste_rh is None:
618 return None
619 employe_rh = self.employe.dans_rh()
620 if employe_rh is None:
621 return None
622 try:
623 return rh.Dossier.objects.get(
624 Q(date_debut=None) | Q(date_debut__lte=today),
625 Q(date_fin=None) | Q(date_fin__gte=today),
626 poste=poste_rh,
627 employe=employe_rh
628 )
629 except rh.Dossier.DoesNotExist:
630 return None
631
632 def importer_dans_rh(self):
633 """
634 Importe les données du dossier DAE dans un dossier RH existant ou
635 nouveau.
636 """
637 poste_rh = self.poste.importer_dans_rh()
638 employe_rh = self.employe.importer_dans_rh()
639 dossier_rh = self.dans_rh() or \
640 rh.Dossier(poste=poste_rh, employe=employe_rh)
641
642 dossier_rh.statut = self.statut
643 dossier_rh.organisme_bstg = self.organisme_bstg
644 dossier_rh.remplacement = self.remplacement
645 dossier_rh.remplacement_de = self.remplacement_de
646 dossier_rh.statut_residence = self.statut_residence
647 dossier_rh.classement = self.classement
648 dossier_rh.regime_travail = self.regime_travail
649 dossier_rh.regime_travail_nb_heure_semaine = \
650 self.regime_travail_nb_heure_semaine
651 dossier_rh.date_debut = self.contrat_date_debut
652 dossier_rh.date_fin = self.contrat_date_fin
653 dossier_rh.save()
654
655 rh.DossierComparaison.objects.filter(dossier=dossier_rh).delete()
656 for comp in self.dae_comparaisons.all():
657 dossier_rh.rh_comparaisons.create(
658 implantation=comp.implantation,
659 poste=comp.poste,
660 personne=comp.personne,
661 montant=comp.montant,
662 devise=comp.devise
663 )
664
665 for contrat in self.dae_contrats.all():
666 contrat_rh = dossier_rh.rh_contrats.create(
667 type_contrat=self.type_contrat,
668 date_debut=self.contrat_date_debut,
669 date_fin=self.contrat_date_fin,
670 )
671 contrat_rh.fichier.save(
672 os.path.basename(contrat.fichier.name), contrat.fichier
673 )
674
675 for piece in self.dae_dossierpieces.all():
676 piece_rh = dossier_rh.rh_dossierpieces.create(
677 nom=piece.nom
678 )
679 piece_rh.fichier.save(
680 os.path.basename(piece.fichier.name), piece.fichier
681 )
682
683 if self.dae_numerisee:
684 dae_numerisee_rh = dossier_rh.rh_dossierpieces.create(
685 nom=u'DAE numérisée'
686 )
687 dae_numerisee_rh.fichier.save(
688 os.path.basename(self.dae_numerisee.name),
689 self.dae_numerisee
690 )
691
692 # Fermer les rémunérations qui commencent avant le début du contrat
693 dossier_rh.rh_remunerations.filter(
694 Q(date_debut=None) | Q(date_debut__lt=self.contrat_date_debut),
695 Q(date_fin=None) | Q(date_fin__gte=self.contrat_date_debut)
696 ).update(date_fin=self.contrat_date_debut - timedelta(1))
697
698 # Effacer les rémunérations qui commencent à la date du contrat
699 dossier_rh.rh_remunerations \
700 .filter(date_debut=self.contrat_date_debut) \
701 .delete()
702
703 for remun in self.dae_remunerations.all():
704 dossier_rh.rh_remunerations.get_or_create(
705 type=remun.type,
706 type_revalorisation=remun.type_revalorisation,
707 montant=remun.montant,
708 devise=remun.devise,
709 commentaire=remun.commentaire,
710 date_debut=self.contrat_date_debut,
711 date_fin=self.contrat_date_fin
712 )
713
714 # Enregistrer le lien avec le dossier RH
715 self.dossier_rh = dossier_rh
716 self.save()
717
718 return dossier_rh
719
720 def get_salaire_anterieur_euros(self):
721 if self.devise_anterieur is None:
722 return None
723 try:
724 taux = self.taux_devise(self.devise_anterieur)
725 except Exception, e:
726 return e
727 if not taux:
728 return None
729 return int(round(float(self.salaire_anterieur) * float(taux), 2))
730
731 def get_salaire_titulaire_anterieur_euros(self):
732 if self.devise_titulaire_anterieur is None:
733 return None
734 try:
735 taux = self.taux_devise(self.devise_titulaire_anterieur)
736 except Exception, e:
737 return e
738 if not taux:
739 return None
740 return int(round(
741 float(self.salaire_titulaire_anterieur) * float(taux), 2
742 ))
743
744 def valide(self):
745 return self.etat in (DOSSIER_ETAT_REGION_FINALISATION,
746 DOSSIER_ETAT_DRH_FINALISATION,
747 DOSSIER_ETAT_FINALISE)
748
749
750 # Tester l'enregistrement car les models.py sont importés au complet
751 if not reversion.is_registered(Dossier):
752 reversion.register(Dossier)
753
754
755 class DossierPiece(rh.DossierPiece_):
756 """
757 Documents relatifs au Dossier (à l'occupation de ce poste par employé).
758 Ex.: Lettre de motivation.
759 """
760 dossier = models.ForeignKey(
761 Dossier, db_column='dossier', related_name='dae_dossierpieces'
762 )
763
764
765 class DossierComparaison(rh.DossierComparaison_):
766 """
767 Photo d'une comparaison salariale au moment de l'embauche.
768 """
769 dossier = models.ForeignKey(
770 Dossier, related_name='dae_comparaisons'
771 )
772 statut = models.ForeignKey(
773 rh.Statut, related_name='+', verbose_name='Statut', null=True,
774 blank=True
775 )
776 classement = models.ForeignKey(
777 rh.Classement, related_name='+', verbose_name='Classement',
778 null=True, blank=True
779 )
780
781
782 ### RÉMUNÉRATION
783
784 class Remuneration(rh.Remuneration_):
785 dossier = models.ForeignKey(
786 Dossier, db_column='dossier', related_name='dae_remunerations'
787 )
788
789
790 ### CONTRATS
791
792 class Contrat(rh.Contrat_):
793 dossier = models.ForeignKey(
794 Dossier, db_column='dossier', related_name='dae_contrats'
795 )