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