1 # -=- encoding: utf-8 -=-
4 from django
.conf
import settings
5 from django
.core
.files
.storage
import FileSystemStorage
6 from django
.db
import models
8 from workflow
import PosteWorkflow
, DossierWorkflow
9 from workflow
import DOSSIER_ETAT_DRH_FINALISATION
, DOSSIER_ETAT_REGION_FINALISATION
, \
11 from managers
import DossierManager
, PosteManager
, PosteComparaisonManager
, \
12 DossierComparaisonManager
13 import datamaster_modeles
.models
as ref
14 from rh
import models
as rh
18 HELP_TEXT_DATE
= "format: jj-mm-aaaa"
19 REGIME_TRAVAIL_DEFAULT
=100.00
20 REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
=35.00
23 UPLOAD_STORAGE
= FileSystemStorage(settings
.PRIVE_MEDIA_ROOT
)
28 POSTE_APPEL_CHOICES
= (
29 ('interne', 'Interne'),
30 ('externe', 'Externe'),
33 ('N', u
"Nouveau poste"),
34 ('M', u
"Poste existant"),
35 ('E', u
"Évolution de poste"),
39 class DeviseException(Exception):
40 silent_variable_failure
= True
43 class Poste(PosteWorkflow
, models
.Model
):
45 type_intervention
= models
.CharField(max_length
=1, choices
=POSTE_ACTION
, default
='N')
48 id_rh
= models
.ForeignKey(rh
.Poste
, null
=True, related_name
='+',
50 verbose_name
=u
"Mise à jour du poste")
51 nom
= models
.CharField(verbose_name
=u
"Titre du poste", max_length
=255)
52 implantation
= models
.ForeignKey(ref
.Implantation
)
53 type_poste
= models
.ForeignKey(rh
.TypePoste
, null
=True, related_name
='+')
54 service
= models
.ForeignKey(rh
.Service
, related_name
='+',
55 verbose_name
=u
"Direction/Service/Pôle support")
56 responsable
= models
.ForeignKey(rh
.Poste
, related_name
='+',
57 verbose_name
=u
"Poste du responsable")
60 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
61 default
=REGIME_TRAVAIL_DEFAULT
,
62 verbose_name
=u
"Temps de travail",
63 help_text
="% du temps complet")
64 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
66 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
67 verbose_name
=u
"Nb. heures par semaine")
70 local
= models
.BooleanField(verbose_name
=u
"Local", default
=True, blank
=True)
71 expatrie
= models
.BooleanField(verbose_name
=u
"Expatrié", default
=False,
73 mise_a_disposition
= models
.BooleanField(verbose_name
=u
"Mise à disposition")
74 appel
= models
.CharField(max_length
=10, default
='interne',
75 verbose_name
=u
"Appel à candidature",
76 choices
=POSTE_APPEL_CHOICES
)
79 classement_min
= models
.ForeignKey(rh
.Classement
, related_name
='+',
80 blank
=True, null
=True)
81 classement_max
= models
.ForeignKey(rh
.Classement
, related_name
='+',
82 blank
=True, null
=True)
83 valeur_point_min
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+',
84 blank
=True, null
=True)
85 valeur_point_max
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+',
86 blank
=True, null
=True)
87 devise_min
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
88 devise_max
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
89 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
91 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
92 indemn_expat_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
93 indemn_expat_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
94 indemn_fct_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
95 indemn_fct_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
96 charges_patronales_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
97 charges_patronales_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
98 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
99 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
101 # Comparatifs de rémunération
102 devise_comparaison
= models
.ForeignKey(rh
.Devise
, related_name
='+',
104 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
105 null
=True, blank
=True)
106 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
107 null
=True, blank
=True)
108 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
109 null
=True, blank
=True)
110 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
111 null
=True, blank
=True)
112 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
113 null
=True, blank
=True)
114 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
115 null
=True, blank
=True)
116 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
117 null
=True, blank
=True)
118 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
119 null
=True, blank
=True)
120 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
121 null
=True, blank
=True)
122 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
123 null
=True, blank
=True)
126 justification
= models
.TextField()
129 date_creation
= models
.DateTimeField(auto_now_add
=True)
130 date_modification
= models
.DateTimeField(auto_now
=True)
131 date_debut
= models
.DateField(verbose_name
=u
"Date de début",
132 help_text
=HELP_TEXT_DATE
,
133 null
=True, blank
=True)
134 date_fin
= models
.DateField(null
=True, blank
=True,
135 verbose_name
=u
"Date de fin",
136 help_text
=HELP_TEXT_DATE
)
137 actif
= models
.BooleanField(default
=True)
140 objects
= PosteManager()
144 Les vues sont montées selon une clef spéciale
145 pour identifier la provenance du poste.
146 Cette méthode fournit un moyen de reconstruire cette clef
147 afin de générer les URLs.
149 return "dae-%s" % self
.id
150 key
= property(_get_key
)
152 def get_dossiers(self
):
154 Liste tous les anciens dossiers liés à ce poste.
155 (Le nom de la relation sur le rh.Poste est mal choisi
156 poste1 au lieu de dossier1)
157 Note1 : seulement le dosssier principal fait l'objet de la recherche.
158 Note2 : les dossiers sont retournés du plus récent au plus vieux.
159 (Ce test est fait en fonction du id,
160 car les dates de création sont absentes de rh v1).
162 if self
.id_rh
is None:
164 return self
.id_rh
.dossiers
.all()
166 def get_complement_nom(self
):
168 Inspecte les modèles rh v1 pour trouver dans le dernier dossier
169 un complément de titre de poste.
171 dossiers
= self
.get_dossiers()
172 if len(dossiers
) > 0:
173 nom
= dossiers
[0].poste
.nom
178 def get_employe(self
):
180 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
182 dossiers
= self
.get_dossiers()
183 if len(dossiers
) > 0:
184 return dossiers
[0].employe
188 def get_default_devise(self
):
189 """Récupère la devise par défaut en fonction de l'implantation
193 implantation_devise
= rh
.TauxChange
.objects \
194 .filter(implantation
=self
.implantation
)[0].devise
196 implantation_devise
= 5 # EUR
197 return implantation_devise
199 #####################
200 # Classement de poste
201 #####################
203 def get_couts_minimum(self
):
204 return self
.salaire_min
+ self
.indemn_expat_min
+ self
.indemn_fct_min
+ self
.charges_patronales_min
+ self
.autre_min
206 def get_salaire_minimum(self
):
207 return self
.get_couts_minimum() - self
.charges_patronales_min
209 def get_taux_minimum(self
):
210 if self
.devise_min
.code
== 'EUR':
212 liste_taux
= self
.devise_min
.tauxchange_set
.order_by('-annee')
213 if len(liste_taux
) == 0:
214 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_min
, self
.implantation
))
216 return liste_taux
[0].taux
218 def get_couts_minimum_euros(self
):
219 return float(self
.get_couts_minimum()) * self
.get_taux_minimum()
221 def get_salaire_minimum_euros(self
):
222 return float(self
.get_salaire_minimum()) * self
.get_taux_minimum()
224 def get_couts_maximum(self
):
225 return self
.salaire_max
+ self
.indemn_expat_max
+ self
.indemn_fct_max
+ self
.charges_patronales_max
+ self
.autre_max
227 def get_salaire_maximum(self
):
228 return self
.get_couts_maximum() - self
.charges_patronales_max
230 def get_taux_maximum(self
):
231 if self
.devise_max
.code
== 'EUR':
233 liste_taux
= self
.devise_max
.tauxchange_set
.order_by('-annee')
234 if len(liste_taux
) == 0:
235 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_max
, self
.implantation
))
237 return liste_taux
[0].taux
239 def get_couts_maximum_euros(self
):
240 return float(self
.get_couts_maximum()) * self
.get_taux_maximum()
242 def get_salaire_maximum_euros(self
):
243 return float(self
.get_salaire_maximum()) * self
.get_taux_maximum()
245 def show_taux_minimum(self
):
247 return self
.get_taux_minimum()
248 except DeviseException
, e
:
251 def show_couts_minimum_euros(self
):
253 return self
.get_couts_minimum_euros()
254 except DeviseException
, e
:
257 def show_salaire_minimum_euros(self
):
259 return self
.get_salaire_minimum_euros()
260 except DeviseException
, e
:
263 def show_taux_maximum(self
):
265 return self
.get_taux_maximum()
266 except DeviseException
, e
:
269 def show_couts_maximum_euros(self
):
271 return self
.get_couts_maximum_euros()
272 except DeviseException
, e
:
275 def show_salaire_maximum_euros(self
):
277 return self
.get_salaire_maximum_euros()
278 except DeviseException
, e
:
282 ######################
283 # Comparaison de poste
284 ######################
286 def est_comparable(self
):
288 Si on a au moins une valeur de saisie dans les comparaisons, alors le poste
291 if self
.comp_universite_min
is None and \
292 self
.comp_fonctionpub_min
is None and \
293 self
.comp_locale_min
is None and \
294 self
.comp_ong_min
is None and \
295 self
.comp_autre_min
is None and \
296 self
.comp_universite_max
is None and \
297 self
.comp_fonctionpub_max
is None and \
298 self
.comp_locale_max
is None and \
299 self
.comp_ong_max
is None and \
300 self
.comp_autre_max
is None:
306 def get_taux_comparaison(self
):
308 return rh
.TauxChange
.objects
.filter(devise
=self
.devise_comparaison
)[0].taux
312 def get_comp_universite_min_euros(self
):
313 return (float)(self
.comp_universite_min
) * self
.get_taux_comparaison()
315 def get_comp_fonctionpub_min_euros(self
):
316 return (float)(self
.comp_fonctionpub_min
) * self
.get_taux_comparaison()
318 def get_comp_locale_min_euros(self
):
319 return (float)(self
.comp_locale_min
) * self
.get_taux_comparaison()
321 def get_comp_ong_min_euros(self
):
322 return (float)(self
.comp_ong_min
) * self
.get_taux_comparaison()
324 def get_comp_autre_min_euros(self
):
325 return (float)(self
.comp_autre_min
) * self
.get_taux_comparaison()
327 def get_comp_universite_max_euros(self
):
328 return (float)(self
.comp_universite_max
) * self
.get_taux_comparaison()
330 def get_comp_fonctionpub_max_euros(self
):
331 return (float)(self
.comp_fonctionpub_max
) * self
.get_taux_comparaison()
333 def get_comp_locale_max_euros(self
):
334 return (float)(self
.comp_locale_max
) * self
.get_taux_comparaison()
336 def get_comp_ong_max_euros(self
):
337 return (float)(self
.comp_ong_max
) * self
.get_taux_comparaison()
339 def get_comp_autre_max_euros(self
):
340 return (float)(self
.comp_autre_max
) * self
.get_taux_comparaison()
343 def __unicode__(self
):
345 Cette fonction est consommatrice SQL car elle cherche les dossiers
346 qui ont été liés à celui-ci.
348 complement_nom_poste
= self
.get_complement_nom()
349 if complement_nom_poste
is None:
350 complement_nom_poste
= ""
356 return u
'%s - %s (%s)' % data
359 # Tester l'enregistrement car les models.py sont importés au complet
360 if not reversion
.is_registered(Poste
):
361 reversion
.register(Poste
)
364 POSTE_FINANCEMENT_CHOICES
= (
365 ('A', 'A - Frais de personnel'),
366 ('B', 'B - Projet(s)-Titre(s)'),
370 class PosteFinancement(models
.Model
):
371 poste
= models
.ForeignKey('Poste', related_name
='financements')
372 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
373 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
374 help_text
="ex.: 33.33 % (décimale avec point)")
375 commentaire
= models
.TextField(
376 help_text
="Spécifiez la source de financement.")
381 def __unicode__(self
):
382 return u
"%s %.0f%% %s" % (self
.get_type_display(), self
.pourcentage
, self
.commentaire
)
385 class PostePiece(models
.Model
):
386 """Documents relatifs au Poste
387 Ex.: Description de poste
389 poste
= models
.ForeignKey("Poste")
390 nom
= models
.CharField(verbose_name
=u
"Nom", max_length
=255)
391 fichier
= models
.FileField(verbose_name
=u
"Fichier",
392 upload_to
='dae/poste',
393 storage
=UPLOAD_STORAGE
)
395 class PosteComparaison(models
.Model
):
396 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
397 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True, related_name
="+")
398 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+', verbose_name
=u
'Statut', null
=True, blank
=True, )
399 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+', verbose_name
=u
'Classement', null
=True, blank
=True, )
400 nom
= models
.CharField(verbose_name
=u
"Poste", max_length
=255, null
=True, blank
=True)
401 montant
= models
.IntegerField(
402 null
=True, verbose_name
="Rémunération totale sans les charges patronales"
404 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
406 objects
= PosteComparaisonManager()
408 def taux_devise(self
):
409 if self
.devise
.code
== 'EUR':
411 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee')
412 if len(liste_taux
) == 0:
413 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
415 return liste_taux
[0].taux
417 def montant_euros(self
):
418 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
423 # TODO : migration pour m -> M, f -> F
430 class Employe(models
.Model
):
433 id_rh
= models
.ForeignKey(rh
.Employe
, null
=True, related_name
='+',
434 verbose_name
=u
'Employé')
435 nom
= models
.CharField(max_length
=255)
436 prenom
= models
.CharField(max_length
=255, verbose_name
=u
'Prénom')
437 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
439 def __unicode__(self
):
440 return u
'%s %s' % (self
.prenom
, self
.nom
.upper())
445 STATUT_RESIDENCE_CHOICES
= (
447 ('expat', 'Expatrié'),
450 COMPTE_COMPTA_CHOICES
= (
456 class Dossier(DossierWorkflow
, models
.Model
):
459 employe
= models
.ForeignKey('Employe', related_name
='+', editable
=False)
460 poste
= models
.ForeignKey('Poste', related_name
='dossiers', editable
=False)
461 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+')
462 organisme_bstg
= models
.ForeignKey(rh
.OrganismeBstg
,
463 null
=True, blank
=True,
464 verbose_name
=u
"Organisme",
465 help_text
="Si détaché (DET) ou mis à disposition (MAD), \
466 préciser l'organisme.",
468 organisme_bstg_autre
= models
.CharField(max_length
=255,
469 verbose_name
=u
"Autre organisme",
470 help_text
="indiquer l'organisme ici s'il n'est pas dans la liste",
474 # Données antérieures de l'employé
475 statut_anterieur
= models
.ForeignKey(
476 rh
.Statut
, related_name
='+', null
=True, blank
=True,
477 verbose_name
=u
'Statut antérieur')
478 classement_anterieur
= models
.ForeignKey(
479 rh
.Classement
, related_name
='+', null
=True, blank
=True,
480 verbose_name
=u
'Classement précédent')
481 salaire_anterieur
= models
.DecimalField(
482 max_digits
=12, decimal_places
=2, null
=True, default
=None,
483 blank
=True, verbose_name
=u
'Salaire précédent')
484 devise_anterieur
= models
.ForeignKey(rh
.Devise
, related_name
='+',
485 null
=True, blank
=True)
486 type_contrat_anterieur
= models
.ForeignKey(rh
.TypeContrat
,
487 related_name
='+', null
=True, blank
=True,
488 verbose_name
=u
'Type contrat antérieur', )
490 # Données du titulaire précédent
491 employe_anterieur
= models
.ForeignKey(
492 rh
.Employe
, related_name
='+', null
=True, blank
=True,
493 verbose_name
=u
'Employé précédent')
494 statut_titulaire_anterieur
= models
.ForeignKey(
495 rh
.Statut
, related_name
='+', null
=True, blank
=True,
496 verbose_name
=u
'Statut titulaire précédent')
497 classement_titulaire_anterieur
= models
.ForeignKey(
498 rh
.Classement
, related_name
='+', null
=True, blank
=True,
499 verbose_name
=u
'Classement titulaire précédent')
500 salaire_titulaire_anterieur
= models
.DecimalField(
501 max_digits
=12, decimal_places
=2, default
=None, null
=True,
502 blank
=True, verbose_name
=u
'Salaire titulaire précédent')
503 devise_titulaire_anterieur
= models
.ForeignKey(rh
.Devise
, related_name
='+', null
=True, blank
=True)
506 remplacement
= models
.BooleanField()
507 statut_residence
= models
.CharField(max_length
=10, default
='local',
508 verbose_name
="Statut",
509 choices
=STATUT_RESIDENCE_CHOICES
)
512 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
513 null
=True, blank
=True,
514 verbose_name
=u
'Classement proposé')
515 salaire
= models
.DecimalField(max_digits
=12, decimal_places
=2,
516 verbose_name
=u
'Salaire de base',
517 null
=True, default
=None)
518 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
519 regime_travail
= models
.DecimalField(max_digits
=12,
521 default
=REGIME_TRAVAIL_DEFAULT
,
522 verbose_name
=u
"Régime de travail",
523 help_text
="% du temps complet")
524 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
526 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
527 verbose_name
=u
"Nb. heures par semaine")
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
)
536 justif_nouveau_statut_label
= u
'Justifier le statut que ce type de poste nécessite (national, expatrié, màd ou détachement)'
537 justif_nouveau_statut
= models
.TextField(verbose_name
=justif_nouveau_statut_label
, null
=True, blank
=True)
538 justif_nouveau_tmp_remplacement_label
= u
"Si l'employé effectue un remplacement temporaire, préciser"
539 justif_nouveau_tmp_remplacement
= models
.TextField(verbose_name
=justif_nouveau_tmp_remplacement_label
, null
=True, blank
=True)
540 justif_nouveau_salaire_label
= u
"Si le salaire de l'employé ne correspond pas au classement du poste ou est différent du salaire antérieur, justifier "
541 justif_nouveau_salaire
= models
.TextField(verbose_name
=justif_nouveau_salaire_label
, null
=True, blank
=True)
542 justif_nouveau_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
543 justif_nouveau_commentaire
= models
.TextField(verbose_name
=justif_nouveau_commentaire_label
, null
=True, blank
=True)
544 justif_rempl_type_contrat_label
= u
"Changement de type de contrat, ex : d'un CDD en CDI"
545 justif_rempl_type_contrat
= models
.TextField(verbose_name
=justif_rempl_type_contrat_label
, null
=True, blank
=True)
546 justif_rempl_statut_employe_label
= u
"Si le statut de l'employé a été modifié pour ce poste ; ex :national, expatrié, màd, détachement ? Si oui, justifier"
547 justif_rempl_statut_employe
= models
.TextField(verbose_name
=justif_rempl_statut_employe_label
, null
=True, blank
=True)
548 justif_rempl_evaluation_label
= u
"L'évaluation de l'employé est-elle favorable? Préciser"
549 justif_rempl_evaluation
= models
.TextField(verbose_name
=justif_rempl_evaluation_label
, null
=True, blank
=True)
550 justif_rempl_salaire_label
= u
"Si le salaire de l'employé est modifié et/ou ne correspond pas à son classement, justifier"
551 justif_rempl_salaire
= models
.TextField(verbose_name
=justif_rempl_salaire_label
, null
=True, blank
=True)
552 justif_rempl_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
553 justif_rempl_commentaire
= models
.TextField(verbose_name
=justif_rempl_commentaire_label
, null
=True, blank
=True)
556 compte_compta
= models
.CharField(max_length
=10, default
='aucun',
557 verbose_name
=u
'Compte comptabilité',
558 choices
=COMPTE_COMPTA_CHOICES
)
559 compte_courriel
= models
.BooleanField()
562 dae_numerisee
= models
.FileField(upload_to
='dae/dae_numerisee', storage
=UPLOAD_STORAGE
,
563 blank
=True, null
=True, verbose_name
="DAE numérisée")
566 date_creation
= models
.DateTimeField(auto_now_add
=True)
569 objects
= DossierManager()
571 def __unicode__(self
):
572 return u
'[%s] %s - %s' % (self
.poste
.implantation
, self
.poste
.nom
, self
.employe
)
574 def taux_devise(self
):
575 if self
.devise
.code
== 'EUR':
577 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee')
578 if len(liste_taux
) == 0:
579 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.poste
.implantation
))
581 return liste_taux
[0].taux
583 def get_salaire_anterieur_euros(self
):
584 if self
.devise_anterieur
.code
== 'EUR':
587 liste_taux
= self
.devise_anterieur
.tauxchange_set
.order_by('-annee')
588 if len(liste_taux
) == 0:
589 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_anterieur
, self
.poste
.implantation
))
590 tx
= liste_taux
[0].taux
591 return (float)(tx
) * (float)(self
.salaire_anterieur
)
593 def get_salaire_titulaire_anterieur_euros(self
):
594 if self
.devise_titulaire_anterieur
.code
== 'EUR':
597 liste_taux
= self
.devise_titulaire_anterieur
.tauxchange_set
.order_by('-annee')
598 if len(liste_taux
) == 0:
599 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_titulaire_anterieur
, self
.poste
.implantation
))
600 tx
= liste_taux
[0].taux
601 return (float)(tx
) * (float)(self
.salaire_titulaire_anterieur
)
603 def get_salaire_euros(self
):
604 tx
= self
.taux_devise()
605 return (float)(tx
) * (float)(self
.salaire
)
607 def get_remunerations_brutes(self
):
611 4 Indemnité d'expatriation
612 5 Indemnité pour frais
613 6 Indemnité de logement
614 7 Indemnité de fonction
615 8 Indemnité de responsabilité
616 9 Indemnité de transport
617 10 Indemnité compensatrice
618 11 Indemnité de subsistance
619 12 Indemnité différentielle
620 13 Prime d'installation
623 16 Indemnité de départ
624 18 Prime de 13ième mois
627 ids
= [1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19]
628 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
630 def get_charges_salariales(self
):
632 20 Charges salariales ?
635 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
637 def get_total_charges_salariales(self
):
639 for r
in self
.get_charges_salariales():
640 total
+= r
.montant_euro()
643 def get_charges_patronales(self
):
645 17 Charges patronales
648 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
650 def get_total_charges_patronales(self
):
652 for r
in self
.get_charges_patronales():
653 total
+= r
.montant_euro()
656 def get_salaire_brut(self
):
658 somme des rémuérations brutes
661 for r
in self
.get_remunerations_brutes():
662 total
+= r
.montant_euro()
665 def get_salaire_net(self
):
667 salaire brut - charges salariales
670 for r
in self
.get_charges_salariales():
671 total_charges
+= r
.montant_euro()
672 return self
.get_salaire_brut() - total_charges
674 def get_couts_auf(self
):
676 salaire net + charges patronales
679 for r
in self
.get_charges_patronales():
680 total_charges
+= r
.montant_euro()
681 return self
.get_salaire_net() + total_charges
683 def get_remunerations_tierces(self
):
687 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in (2, )]
689 def get_total_remunerations_tierces(self
):
691 for r
in self
.get_remunerations_tierces():
692 total
+= r
.montant_euro()
696 return self
.etat
in (DOSSIER_ETAT_REGION_FINALISATION
,
697 DOSSIER_ETAT_DRH_FINALISATION
,
698 DOSSIER_ETAT_FINALISE
)
701 # Tester l'enregistrement car les models.py sont importés au complet
702 if not reversion
.is_registered(Dossier
):
703 reversion
.register(Dossier
)
705 class DossierPiece(models
.Model
):
706 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
707 Ex.: Lettre de motivation.
709 dossier
= models
.ForeignKey("Dossier")
710 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
711 fichier
= models
.FileField(verbose_name
="Fichier",
712 upload_to
='dae/dossier',
713 storage
=UPLOAD_STORAGE
)
716 class DossierComparaison(models
.Model
):
718 Photo d'une comparaison salariale au moment de l'embauche.
720 dossier
= models
.ForeignKey('Dossier', related_name
='comparaisons')
721 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+',
722 verbose_name
='Statut', null
=True, blank
=True, )
723 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
724 verbose_name
='Classement', null
=True, blank
=True, )
725 implantation
= models
.ForeignKey(ref
.Implantation
, related_name
='+',
726 null
=True, blank
=True)
727 poste
= models
.CharField(max_length
=255, null
=True, blank
=True)
728 personne
= models
.CharField(max_length
=255, null
=True, blank
=True)
729 montant
= models
.IntegerField(null
=True)
730 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
732 objects
= DossierComparaisonManager()
734 def taux_devise(self
):
735 if self
.devise
.code
== 'EUR':
737 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee')
738 if len(liste_taux
) == 0:
739 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
741 return liste_taux
[0].taux
743 def montant_euros(self
):
744 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
750 class Remuneration(models
.Model
):
752 dossier
= models
.ForeignKey('Dossier', db_column
='dossier')
753 type = models
.ForeignKey(rh
.TypeRemuneration
, db_column
='type',
755 montant
= models
.DecimalField(max_digits
=12, decimal_places
=2,
757 devise
= models
.ForeignKey(rh
.Devise
, to_field
='code',
758 db_column
='devise', related_name
='+')
759 precision
= models
.CharField(max_length
=255, null
=True, blank
=True)
762 date_creation
= models
.DateField(auto_now_add
=True)
763 user_creation
= models
.IntegerField(null
=True, blank
=True) # TODO : user
765 def montant_mois(self
):
766 return round(self
.montant
/ 12, 2)
768 def taux_devise(self
):
769 if self
.devise
.code
== 'EUR':
771 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee')
772 if len(liste_taux
) == 0:
773 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.dossier
.poste
.implantation
))
775 return liste_taux
[0].taux
777 def montant_euro(self
):
778 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
780 def montant_euro_mois(self
):
781 return round(self
.montant_euro() / 12, 2)
786 class Contrat(models
.Model
):
787 dossier
= models
.ForeignKey(Dossier
, related_name
='contrats')
788 type = models
.ForeignKey(rh
.TypeContrat
, related_name
='+')
789 fichier
= models
.FileField(upload_to
='dae/contrats', storage
=UPLOAD_STORAGE
)