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