[#3059] Page intermédiaire à l'importation d'une DAE
[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.exporter import DossierCopier, PosteCopier
14 from project.dae.managers import \
15 PosteManager, DossierManager, DossierFinaliseManager, \
16 PosteFinaliseManager
17 from project.dae.workflow import PosteWorkflow, DossierWorkflow
18 from project.dae.workflow import \
19 DOSSIER_ETAT_DRH_FINALISATION, DOSSIER_ETAT_REGION_FINALISATION, \
20 DOSSIER_ETAT_FINALISE
21
22 # XXX: Saloperie, il faut importer rh.models à partir d'un autre namespace
23 # à cause du hack app_context() dans project.rh.models. Très fragile. Il
24 # faut régler ça aussi vite que possible.
25 from rh import models as rh
26 from rh.models import HELP_TEXT_DATE
27
28 # Upload de fichiers
29 UPLOAD_STORAGE = FileSystemStorage(settings.PRIVE_MEDIA_ROOT)
30
31
32 ### POSTE
33
34 POSTE_APPEL_CHOICES = (
35 ('interne', 'Interne'),
36 ('externe', 'Externe'),
37 )
38 POSTE_ACTION = (
39 ('N', u"Nouveau poste"),
40 ('M', u"Poste existant"),
41 ('E', u"Évolution de poste"),
42 )
43
44
45 class DeviseException(Exception):
46 silent_variable_failure = True
47
48
49 class Poste(PosteWorkflow, rh.Poste_):
50
51 type_intervention = models.CharField(
52 max_length=1, choices=POSTE_ACTION, default='N'
53 )
54
55 # Modèle existant
56 id_rh = models.ForeignKey(rh.Poste, null=True, related_name='+',
57 editable=False,
58 verbose_name=u"Mise à jour du poste")
59
60 # Rémunération
61 indemn_expat_min = models.DecimalField(
62 max_digits=13, decimal_places=2, default=0
63 )
64 indemn_expat_max = models.DecimalField(
65 max_digits=12, decimal_places=2, default=0
66 )
67 indemn_fct_min = models.DecimalField(
68 max_digits=12, decimal_places=2, default=0
69 )
70 indemn_fct_max = models.DecimalField(
71 max_digits=12, decimal_places=2, default=0
72 )
73 charges_patronales_min = models.DecimalField(
74 max_digits=12, decimal_places=2, default=0
75 )
76 charges_patronales_max = models.DecimalField(
77 max_digits=12, decimal_places=2, default=0
78 )
79
80 # Managers
81 objects = PosteManager()
82
83 def _get_key(self):
84 """
85 Les vues sont montées selon une clef spéciale
86 pour identifier la provenance du poste.
87 Cette méthode fournit un moyen de reconstruire cette clef
88 afin de générer les URLs.
89 """
90 return "dae-%s" % self.id
91 key = property(_get_key)
92
93 def get_dossiers(self):
94 """
95 Liste tous les anciens dossiers liés à ce poste.
96 (Le nom de la relation sur le rh.Poste est mal choisi
97 poste1 au lieu de dossier1)
98 Note1 : seulement le dosssier principal fait l'objet de la recherche.
99 Note2 : les dossiers sont retournés du plus récent au plus vieux.
100 (Ce test est fait en fonction du id,
101 car les dates de création sont absentes de rh v1).
102 """
103 if self.id_rh is None:
104 return []
105 return self.id_rh.rh_dossiers.all()
106
107 def rh_importation(self):
108 if ImportPoste.objects.filter(dae=self).exists():
109 return ImportPoste.objects.get(dae=self).rh
110 else:
111 return None
112
113 def importer(self, verbosity=0, dry_run=False):
114 copieur = PosteCopier(verbosity=verbosity, dry_run=dry_run)
115 return copieur.copy(self)
116
117 def dans_rh(self):
118 return self.id_rh or None
119
120 def importer_dans_rh(self):
121 poste_rh = self.dans_rh() or rh.Poste()
122 poste_rh.nom = self.nom
123 poste_rh.implantation = self.implantation
124 poste_rh.type_poste = self.type_poste
125 poste_rh.service = self.service
126 poste_rh.responsable = self.responsable
127 poste_rh.regime_travail = self.regime_travail
128 poste_rh.regime_travail_nb_heure_semaine = \
129 self.regime_travail_nb_heure_semaine
130 poste_rh.local = self.local
131 poste_rh.expatrie = self.expatrie
132 poste_rh.mise_a_disposition = self.mise_a_disposition
133 poste_rh.appel = self.appel
134 poste_rh.classement_min = self.classement_min
135 poste_rh.classement_max = self.classement_max
136 poste_rh.valeur_point_min = self.valeur_point_min
137 poste_rh.valeur_point_max = self.valeur_point_max
138 poste_rh.devise_min = self.devise_min
139 poste_rh.devise_max = self.devise_max
140 poste_rh.salaire_min = self.salaire_min
141 poste_rh.salaire_max = self.salaire_max
142 poste_rh.indemn_min = self.indemn_min
143 poste_rh.indemn_max = self.indemn_max
144 poste_rh.autre_min = self.autre_min
145 poste_rh.autre_max = self.autre_max
146 poste_rh.devise_comparaison = self.devise_comparaison
147 poste_rh.comp_locale_min = self.comp_locale_min
148 poste_rh.comp_locale_max = self.comp_locale_max
149 poste_rh.comp_universite_min = self.comp_universite_min
150 poste_rh.comp_universite_max = self.comp_universite_max
151 poste_rh.comp_fonctionpub_min = self.comp_fonctionpub_min
152 poste_rh.comp_fonctionpub_max = self.comp_fonctionpub_max
153 poste_rh.comp_ong_min = self.comp_ong_min
154 poste_rh.comp_ong_max = self.comp_ong_max
155 poste_rh.comp_autre_min = self.comp_autre_min
156 poste_rh.comp_autre_max = self.comp_autre_max
157 poste_rh.justification = self.justification
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 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 pass
384
385
386 class PostePiece(rh.PostePiece_):
387 pass
388
389
390 class PosteComparaison(rh.PosteComparaison_):
391 statut = models.ForeignKey(
392 rh.Statut, related_name='+', verbose_name=u'Statut', null=True,
393 blank=True
394 )
395 classement = models.ForeignKey(
396 rh.Classement, related_name='+', verbose_name=u'Classement',
397 null=True, blank=True
398 )
399
400 ### EMPLOYÉ/PERSONNE
401
402 # TODO : migration pour m -> M, f -> F
403
404 GENRE_CHOICES = (
405 ('m', 'Homme'),
406 ('f', 'Femme'),
407 )
408
409
410 class Employe(AUFMetadata):
411
412 # Modèle existant
413 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+',
414 verbose_name=u'Employé')
415 nom = models.CharField(max_length=255)
416 prenom = models.CharField(max_length=255, verbose_name=u'Prénom')
417 genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
418
419 def __unicode__(self):
420 return u'%s %s' % (self.prenom, self.nom.upper())
421
422 def dans_rh(self):
423 return self.id_rh or None
424
425 def importer_dans_rh(self):
426 return self.dans_rh() or rh.Employe.objects.create(
427 nom=self.nom,
428 prenom=self.prenom,
429 genre=self.genre
430 )
431
432
433 ### DOSSIER
434
435 STATUT_RESIDENCE_CHOICES = (
436 ('local', 'Local'),
437 ('expat', 'Expatrié'),
438 )
439
440 COMPTE_COMPTA_CHOICES = (
441 ('coda', 'CODA'),
442 ('scs', 'SCS'),
443 ('aucun', 'Aucun'),
444 )
445
446
447 class Dossier(DossierWorkflow, rh.Dossier_):
448 poste = models.ForeignKey(
449 'Poste', db_column='poste', related_name='%(app_label)s_dossiers'
450 )
451 employe = models.ForeignKey(
452 'Employe', db_column='employe',
453 related_name='%(app_label)s_dossiers', verbose_name=u"Employé"
454 )
455 organisme_bstg_autre = models.CharField(max_length=255,
456 verbose_name=u"Autre organisme",
457 help_text="indiquer l'organisme ici s'il n'est pas dans la liste",
458 null=True,
459 blank=True,)
460
461 # Données antérieures de l'employé
462 statut_anterieur = models.ForeignKey(
463 rh.Statut, related_name='+', null=True, blank=True,
464 verbose_name=u'Statut antérieur')
465 classement_anterieur = models.ForeignKey(
466 rh.Classement, related_name='+', null=True, blank=True,
467 verbose_name=u'Classement précédent')
468 salaire_anterieur = models.DecimalField(
469 max_digits=12, decimal_places=2, null=True, default=None,
470 blank=True, verbose_name=u'Salaire précédent')
471 devise_anterieur = models.ForeignKey(
472 rh.Devise, related_name='+', null=True, blank=True
473 )
474 type_contrat_anterieur = models.ForeignKey(
475 rh.TypeContrat, related_name='+', null=True, blank=True,
476 verbose_name=u'Type contrat antérieur'
477 )
478
479 # Données du titulaire précédent
480 employe_anterieur = models.ForeignKey(
481 rh.Employe, related_name='+', null=True, blank=True,
482 verbose_name=u'Employé précédent')
483 statut_titulaire_anterieur = models.ForeignKey(
484 rh.Statut, related_name='+', null=True, blank=True,
485 verbose_name=u'Statut titulaire précédent')
486 classement_titulaire_anterieur = models.ForeignKey(
487 rh.Classement, related_name='+', null=True, blank=True,
488 verbose_name=u'Classement titulaire précédent')
489 salaire_titulaire_anterieur = models.DecimalField(
490 max_digits=12, decimal_places=2, default=None, null=True,
491 blank=True, verbose_name=u'Salaire titulaire précédent')
492 devise_titulaire_anterieur = models.ForeignKey(
493 rh.Devise, related_name='+', null=True, blank=True
494 )
495
496 # Rémunération
497 salaire = models.DecimalField(max_digits=13, decimal_places=2,
498 verbose_name=u'Salaire de base',
499 null=True, default=None)
500 devise = models.ForeignKey(rh.Devise, default=5, related_name='+')
501
502 # Contrat
503 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
504 contrat_date_debut = models.DateField(help_text=HELP_TEXT_DATE)
505 contrat_date_fin = models.DateField(null=True, blank=True,
506 help_text=HELP_TEXT_DATE)
507
508 # Justifications
509 justif_nouveau_statut_label = u'Justifier le statut que ce type ' \
510 u'de poste nécessite (national, expatrié, màd ou détachement)'
511 justif_nouveau_statut = models.TextField(
512 verbose_name=justif_nouveau_statut_label, null=True, blank=True
513 )
514 justif_nouveau_tmp_remplacement_label = u"Si l'employé effectue un " \
515 u"remplacement temporaire, préciser"
516 justif_nouveau_tmp_remplacement = models.TextField(
517 verbose_name=justif_nouveau_tmp_remplacement_label, null=True,
518 blank=True
519 )
520 justif_nouveau_salaire_label = u"Si le salaire de l'employé ne " \
521 u"correspond pas au classement du poste ou est différent " \
522 u"du salaire antérieur, justifier "
523 justif_nouveau_salaire = models.TextField(
524 verbose_name=justif_nouveau_salaire_label, null=True, blank=True
525 )
526 justif_nouveau_commentaire_label = u"COMMENTAIRES ADDITIONNELS"
527 justif_nouveau_commentaire = models.TextField(
528 verbose_name=justif_nouveau_commentaire_label, null=True, blank=True
529 )
530 justif_rempl_type_contrat_label = \
531 u"Changement de type de contrat, ex : d'un CDD en CDI"
532 justif_rempl_type_contrat = models.TextField(
533 verbose_name=justif_rempl_type_contrat_label, null=True, blank=True
534 )
535 justif_rempl_statut_employe_label = \
536 u"Si le statut de l'employé a été modifié pour ce poste ; " \
537 u"ex : national, expatrié, màd, détachement ? Si oui, justifier"
538 justif_rempl_statut_employe = models.TextField(
539 verbose_name=justif_rempl_statut_employe_label, null=True, blank=True
540 )
541 justif_rempl_evaluation_label = \
542 u"L'évaluation de l'employé est-elle favorable? Préciser"
543 justif_rempl_evaluation = models.TextField(
544 verbose_name=justif_rempl_evaluation_label, null=True, blank=True
545 )
546 justif_rempl_salaire_label = \
547 u"Si le salaire de l'employé est modifié et/ou ne correspond " \
548 u"pas à son classement, justifier"
549 justif_rempl_salaire = models.TextField(
550 verbose_name=justif_rempl_salaire_label, null=True, blank=True
551 )
552 justif_rempl_commentaire_label = u"COMMENTAIRES ADDITIONNELS"
553 justif_rempl_commentaire = models.TextField(
554 verbose_name=justif_rempl_commentaire_label, null=True, blank=True
555 )
556
557 # Comptes
558 compte_compta = models.CharField(max_length=10, default='aucun',
559 verbose_name=u'Compte comptabilité',
560 choices=COMPTE_COMPTA_CHOICES)
561 compte_courriel = models.BooleanField()
562
563 # DAE numérisée
564 dae_numerisee = models.FileField(
565 upload_to='dae/dae_numerisee', storage=UPLOAD_STORAGE, blank=True,
566 null=True, verbose_name="DAE numérisée"
567 )
568
569 # Managers
570 objects = DossierManager()
571
572 def __init__(self, *args, **kwargs):
573 # Bouchon pour créer une date fictive necessaire pour valider un
574 # dossier à cause de l'héritage
575 super(rh.Dossier_, self).__init__(*args, **kwargs)
576 super(DossierWorkflow, self).__init__(*args, **kwargs)
577 import datetime
578 self.date_debut = datetime.datetime.today()
579
580 def __unicode__(self):
581 return u'[%s] %s - %s' % (
582 self.poste.implantation, self.poste.nom, self.employe
583 )
584
585 def importer(self, verbosity=0, dry_run=False):
586 copieur = DossierCopier(verbosity=verbosity, dry_run=dry_run)
587 return copieur.copy(self)
588
589 def dans_rh(self):
590 """
591 Retourne le dossier associé dans le système RH ou ``None`` s'il n'y
592 en a pas.
593 """
594 today = date.today()
595 poste_rh = self.poste.dans_rh()
596 if poste_rh is None:
597 return None
598 employe_rh = self.employe.dans_rh()
599 if employe_rh is None:
600 return None
601 try:
602 return rh.Dossier.objects.get(
603 Q(date_debut=None) | Q(date_debut__lte=today),
604 Q(date_fin=None) | Q(date_fin__gte=today),
605 poste=poste_rh,
606 employe=employe_rh
607 )
608 except rh.Dossier.DoesNotExist:
609 return None
610
611 def importer_dans_rh(self):
612 poste_rh = self.poste.importer_dans_rh()
613 employe_rh = self.employe.importer_dans_rh()
614 dossier_rh = self.dans_rh() or \
615 rh.Dossier(poste=poste_rh, employe=employe_rh)
616
617 dossier_rh.statut = self.statut
618 dossier_rh.organisme_bstg = self.organisme_bstg
619 dossier_rh.remplacement = self.remplacement
620 dossier_rh.remplacement_de = self.remplacement_de
621 dossier_rh.statut_residence = self.statut_residence
622 dossier_rh.classement = self.classement
623 dossier_rh.regime_travail = self.regime_travail
624 dossier_rh.regime_travail_nb_heure_semaine = \
625 self.regime_travail_nb_heure_semaine
626 dossier_rh.date_debut = self.date_debut
627 dossier_rh.date_fin = self.date_fin
628 dossier_rh.save()
629
630 rh.DossierComparaison.objects.filter(dossier=dossier_rh).delete()
631 for comp in self.dae_comparaisons.all():
632 dossier_rh.rh_comparaisons.create(
633 implantation=comp.implantation,
634 poste=comp.poste,
635 personne=comp.personne,
636 montant=comp.montant,
637 devise=comp.devise
638 )
639
640 if not dossier_rh.rh_contrats.filter(
641 type_contrat=self.type_contrat,
642 date_debut=self.contrat_date_debut,
643 date_fin=self.contrat_date_fin
644 ).exists():
645 dossier_rh.rh_contrats.create(
646 type_contrat=self.type_contrat,
647 date_debut=self.contrat_date_debut,
648 date_fin=self.contrat_date_fin,
649 )
650
651 for piece in self.dae_dossierpieces.all():
652 piece_rh = dossier_rh.rh_dossierpieces.create(
653 nom=piece.nom
654 )
655 piece_rh.fichier.save(
656 os.path.basename(piece.fichier.name), piece.fichier
657 )
658
659 # Fermer les rémunérations qui commencent avant le début du contrat
660 dossier_rh.rh_remunerations.filter(
661 Q(date_debut=None) | Q(date_debut__lt=self.contrat_date_debut),
662 Q(date_fin=None) | Q(date_fin__gte=self.contrat_date_debut)
663 ).update(date_fin=self.contrat_date_debut - timedelta(1))
664
665 # Effacer les rémunérations qui commencent à la date du contrat
666 dossier_rh.rh_remunerations \
667 .filter(date_debut=self.contrat_date_debut) \
668 .delete()
669
670 for remun in self.dae_remunerations.all():
671 dossier_rh.rh_remunerations.get_or_create(
672 type=remun.type,
673 type_revalorisation=remun.type_revalorisation,
674 montant=remun.montant,
675 devise=remun.devise,
676 commentaire=remun.commentaire,
677 date_debut=self.contrat_date_debut,
678 date_fin=self.contrat_date_fin
679 )
680
681 return dossier_rh
682
683 def get_salaire_anterieur_euros(self):
684 if self.devise_anterieur is None:
685 return None
686 try:
687 taux = self.taux_devise(self.devise_anterieur)
688 except Exception, e:
689 return e
690 if not taux:
691 return None
692 return int(round(float(self.salaire_anterieur) * float(taux), 2))
693
694 def get_salaire_titulaire_anterieur_euros(self):
695 if self.devise_titulaire_anterieur is None:
696 return None
697 try:
698 taux = self.taux_devise(self.devise_titulaire_anterieur)
699 except Exception, e:
700 return e
701 if not taux:
702 return None
703 return int(round(
704 float(self.salaire_titulaire_anterieur) * float(taux), 2
705 ))
706
707 def valide(self):
708 return self.etat in (DOSSIER_ETAT_REGION_FINALISATION,
709 DOSSIER_ETAT_DRH_FINALISATION,
710 DOSSIER_ETAT_FINALISE)
711
712
713 # Tester l'enregistrement car les models.py sont importés au complet
714 if not reversion.is_registered(Dossier):
715 reversion.register(Dossier)
716
717
718 class DossierPiece(rh.DossierPiece_):
719 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
720 Ex.: Lettre de motivation.
721 """
722 pass
723
724
725 class DossierComparaison(rh.DossierComparaison_):
726 """
727 Photo d'une comparaison salariale au moment de l'embauche.
728 """
729 statut = models.ForeignKey(
730 rh.Statut, related_name='+', verbose_name='Statut', null=True,
731 blank=True
732 )
733 classement = models.ForeignKey(
734 rh.Classement, related_name='+', verbose_name='Classement',
735 null=True, blank=True
736 )
737
738
739 ### RÉMUNÉRATION
740
741 class Remuneration(rh.Remuneration_):
742 pass
743
744
745 ### CONTRATS
746
747 class Contrat(rh.Contrat_):
748 pass
749
750
751 class DossierFinalise(Dossier):
752
753 objects = DossierFinaliseManager()
754
755 class Meta:
756 proxy = True
757 verbose_name = "Import d'un dossier dans RH"
758 verbose_name_plural = "Import des dossiers dans RH"
759
760
761 class PosteFinalise(Poste):
762
763 objects = PosteFinaliseManager()
764
765 class Meta:
766 proxy = True
767 verbose_name = "Import d'un poste dans RH"
768 verbose_name_plural = "Import des postes dans RH"
769
770
771 # modèle de liaison entre les systèmes
772
773 class ImportDossier(models.Model):
774 dae = models.ForeignKey('dae.Dossier', related_name='+')
775 rh = models.ForeignKey('rh.Dossier', related_name='+')
776
777
778 class ImportPoste(models.Model):
779 dae = models.ForeignKey('dae.Poste', related_name='+')
780 rh = models.ForeignKey('rh.Poste', related_name='+')