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
10 from managers
import DossierManager
, PosteManager
11 import datamaster_modeles
.models
as ref
12 from rh_v1
import models
as rh
16 HELP_TEXT_DATE
= "format: aaaa-mm-jj"
17 REGIME_TRAVAIL_DEFAULT
=100.00
18 REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
=35.00
21 UPLOAD_STORAGE
= FileSystemStorage(settings
.PRIVE_MEDIA_ROOT
)
26 POSTE_APPEL_CHOICES
= (
27 ('interne', 'Interne'),
28 ('externe', 'Externe'),
31 ('N', u
"Nouveau poste"),
32 ('M', u
"Poste existant"),
33 ('E', u
"Évolution de poste"),
37 class DeviseException(Exception):
38 silent_variable_failure
= True
41 class Poste(PosteWorkflow
, models
.Model
):
43 type_intervention
= models
.CharField(max_length
=1, choices
=POSTE_ACTION
, default
='N')
46 id_rh
= models
.ForeignKey(rh
.Poste
, null
=True, related_name
='+',
48 verbose_name
="Mise à jour du poste")
49 nom
= models
.CharField(verbose_name
="Titre du poste", max_length
=255)
50 implantation
= models
.ForeignKey(ref
.Implantation
)
51 type_poste
= models
.ForeignKey(rh
.TypePoste
, null
=True, related_name
='+')
52 service
= models
.ForeignKey(rh
.Service
, related_name
='+',
53 verbose_name
=u
"Direction/Service/Pôle support")
54 responsable
= models
.ForeignKey(rh
.Poste
, related_name
='+',
55 verbose_name
="Poste du responsable")
58 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
59 default
=REGIME_TRAVAIL_DEFAULT
,
60 verbose_name
="Temps de travail",
61 help_text
="% du temps complet")
62 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
64 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
65 verbose_name
="Nb. heures par semaine")
68 local
= models
.BooleanField(verbose_name
="Local", default
=True, blank
=True)
69 expatrie
= models
.BooleanField(verbose_name
="Expatrié", default
=False,
71 mise_a_disposition
= models
.BooleanField(verbose_name
="Mise à disposition")
72 appel
= models
.CharField(max_length
=10, default
='interne',
73 verbose_name
="Appel à candidature",
74 choices
=POSTE_APPEL_CHOICES
)
77 classement_min
= models
.ForeignKey(rh
.Classement
, related_name
='+',
78 blank
=True, null
=True)
79 classement_max
= models
.ForeignKey(rh
.Classement
, related_name
='+',
80 blank
=True, null
=True)
81 valeur_point_min
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+',
82 blank
=True, null
=True)
83 valeur_point_max
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+',
84 blank
=True, null
=True)
85 devise_min
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
86 devise_max
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
87 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
89 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
90 indemn_expat_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
91 indemn_expat_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
92 indemn_fct_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
93 indemn_fct_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
94 charges_patronales_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
95 charges_patronales_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
96 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
97 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
99 # Comparatifs de rémunération
100 devise_comparaison
= models
.ForeignKey(rh
.Devise
, related_name
='+',
102 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
103 null
=True, blank
=True)
104 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
105 null
=True, blank
=True)
106 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
107 null
=True, blank
=True)
108 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
109 null
=True, blank
=True)
110 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
111 null
=True, blank
=True)
112 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
113 null
=True, blank
=True)
114 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
115 null
=True, blank
=True)
116 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
117 null
=True, blank
=True)
118 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
119 null
=True, blank
=True)
120 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
121 null
=True, blank
=True)
124 justification
= models
.TextField()
127 date_creation
= models
.DateTimeField(auto_now_add
=True)
128 date_modification
= models
.DateTimeField(auto_now
=True)
129 date_debut
= models
.DateField(verbose_name
="Date de début",
130 help_text
=HELP_TEXT_DATE
,
131 null
=True, blank
=True)
132 date_fin
= models
.DateField(null
=True, blank
=True,
133 verbose_name
="Date de fin",
134 help_text
=HELP_TEXT_DATE
)
135 actif
= models
.BooleanField(default
=True)
138 objects
= PosteManager()
142 Les vues sont montées selon une clef spéciale
143 pour identifier la provenance du poste.
144 Cette méthode fournit un moyen de reconstruire cette clef
145 afin de générer les URLs.
147 return "dae-%s" % self
.id
148 key
= property(_get_key
)
150 def get_dossiers(self
):
152 Liste tous les anciens dossiers liés à ce poste.
153 (Le nom de la relation sur le rh.Poste est mal choisi
154 poste1 au lieu de dossier1)
155 Note1 : seulement le dosssier principal fait l'objet de la recherche.
156 Note2 : les dossiers sont retournés du plus récent au plus vieux.
157 (Ce test est fait en fonction du id,
158 car les dates de création sont absentes de rh v1).
160 if self
.id_rh
is None:
162 postes
= [p
for p
in self
.id_rh
.poste1
.all()]
163 return sorted(postes
, key
=lambda poste
: poste
.id, reverse
=True)
165 def get_complement_nom(self
):
167 Inspecte les modèles rh v1 pour trouver dans le dernier dossier
168 un complément de titre de poste.
170 dossiers
= self
.get_dossiers()
171 if len(dossiers
) > 0:
172 nom
= dossiers
[0].complement1
177 def get_employe(self
):
179 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
181 dossiers
= self
.get_dossiers()
182 if len(dossiers
) > 0:
183 return dossiers
[0].employe
187 def get_default_devise(self
):
188 """Récupère la devise par défaut en fonction de l'implantation
192 implantation_devise
= rh
.TauxChange
.objects \
193 .filter(implantation
=self
.implantation
)[0].devise
195 implantation_devise
= 5 # EUR
196 return implantation_devise
198 #####################
199 # Classement de poste
200 #####################
202 def get_couts_minimum(self
):
203 return self
.salaire_min
+ self
.indemn_expat_min
+ self
.indemn_fct_min
+ self
.charges_patronales_min
+ self
.autre_min
205 def get_salaire_minimum(self
):
206 return self
.get_couts_minimum() - self
.charges_patronales_min
208 def get_taux_minimum(self
):
209 if self
.devise_min
.code
== 'EUR':
211 liste_taux
= self
.devise_min
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
212 if len(liste_taux
) == 0:
213 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_min
, self
.implantation
))
215 return liste_taux
[0].taux
217 def get_couts_minimum_euros(self
):
218 return float(self
.get_couts_minimum()) * self
.get_taux_minimum()
220 def get_salaire_minimum_euros(self
):
221 return float(self
.get_salaire_minimum()) * self
.get_taux_minimum()
223 def get_couts_maximum(self
):
224 return self
.salaire_max
+ self
.indemn_expat_max
+ self
.indemn_fct_max
+ self
.charges_patronales_max
+ self
.autre_max
226 def get_salaire_maximum(self
):
227 return self
.get_couts_maximum() - self
.charges_patronales_max
229 def get_taux_maximum(self
):
230 if self
.devise_max
.code
== 'EUR':
232 liste_taux
= self
.devise_max
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
233 if len(liste_taux
) == 0:
234 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_max
, self
.implantation
))
236 return liste_taux
[0].taux
238 def get_couts_maximum_euros(self
):
239 return float(self
.get_couts_maximum()) * self
.get_taux_maximum()
241 def get_salaire_maximum_euros(self
):
242 return float(self
.get_salaire_maximum()) * self
.get_taux_maximum()
244 def show_taux_minimum(self
):
246 return self
.get_taux_minimum()
247 except DeviseException
, e
:
250 def show_couts_minimum_euros(self
):
252 return self
.get_couts_minimum_euros()
253 except DeviseException
, e
:
256 def show_salaire_minimum_euros(self
):
258 return self
.get_salaire_minimum_euros()
259 except DeviseException
, e
:
262 def show_taux_maximum(self
):
264 return self
.get_taux_maximum()
265 except DeviseException
, e
:
268 def show_couts_maximum_euros(self
):
270 return self
.get_couts_maximum_euros()
271 except DeviseException
, e
:
274 def show_salaire_maximum_euros(self
):
276 return self
.get_salaire_maximum_euros()
277 except DeviseException
, e
:
281 ######################
282 # Comparaison de poste
283 ######################
285 def est_comparable(self
):
287 Si on a au moins une valeur de saisie dans les comparaisons, alors le poste
290 if self
.comp_universite_min
is None and \
291 self
.comp_fonctionpub_min
is None and \
292 self
.comp_locale_min
is None and \
293 self
.comp_ong_min
is None and \
294 self
.comp_autre_min
is None and \
295 self
.comp_universite_max
is None and \
296 self
.comp_fonctionpub_max
is None and \
297 self
.comp_locale_max
is None and \
298 self
.comp_ong_max
is None and \
299 self
.comp_autre_max
is None:
305 def get_taux_comparaison(self
):
307 return rh
.TauxChange
.objects
.filter(implantation
=self
.implantation
, devise
=self
.devise_comparaison
)[0].taux
311 def get_comp_universite_min_euros(self
):
312 return (float)(self
.comp_universite_min
) * self
.get_taux_comparaison()
314 def get_comp_fonctionpub_min_euros(self
):
315 return (float)(self
.comp_fonctionpub_min
) * self
.get_taux_comparaison()
317 def get_comp_locale_min_euros(self
):
318 return (float)(self
.comp_locale_min
) * self
.get_taux_comparaison()
320 def get_comp_ong_min_euros(self
):
321 return (float)(self
.comp_ong_min
) * self
.get_taux_comparaison()
323 def get_comp_autre_min_euros(self
):
324 return (float)(self
.comp_autre_min
) * self
.get_taux_comparaison()
326 def get_comp_universite_max_euros(self
):
327 return (float)(self
.comp_universite_max
) * self
.get_taux_comparaison()
329 def get_comp_fonctionpub_max_euros(self
):
330 return (float)(self
.comp_fonctionpub_max
) * self
.get_taux_comparaison()
332 def get_comp_locale_max_euros(self
):
333 return (float)(self
.comp_locale_max
) * self
.get_taux_comparaison()
335 def get_comp_ong_max_euros(self
):
336 return (float)(self
.comp_ong_max
) * self
.get_taux_comparaison()
338 def get_comp_autre_max_euros(self
):
339 return (float)(self
.comp_autre_max
) * self
.get_taux_comparaison()
342 def __unicode__(self
):
344 Cette fonction est consommatrice SQL car elle cherche les dossiers
345 qui ont été liés à celui-ci.
347 complement_nom_poste
= self
.get_complement_nom()
348 if complement_nom_poste
is None:
349 complement_nom_poste
= ""
355 return u
'%s - %s (%s)' % data
358 # Tester l'enregistrement car les models.py sont importés au complet
359 if not reversion
.is_registered(Poste
):
360 reversion
.register(Poste
)
363 POSTE_FINANCEMENT_CHOICES
= (
364 ('A', 'A - Frais de personnel'),
365 ('B', 'B - Projet(s)-Titre(s)'),
369 class PosteFinancement(models
.Model
):
370 poste
= models
.ForeignKey('Poste', related_name
='financements')
371 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
372 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
373 help_text
="ex.: 33.33 % (décimale avec point)")
374 commentaire
= models
.TextField(
375 help_text
="Spécifiez la source de financement.")
380 def __unicode__(self
):
381 return u
"%s %s %s" % (self
.get_type_display(), self
.pourcentage
, self
.commentaire
)
384 class PostePiece(models
.Model
):
385 """Documents relatifs au Poste
386 Ex.: Description de poste
388 poste
= models
.ForeignKey("Poste")
389 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
390 fichier
= models
.FileField(verbose_name
="Fichier", upload_to
='dae/poste', storage
=UPLOAD_STORAGE
)
392 class PosteComparaison(models
.Model
):
393 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
394 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+', verbose_name
='Statut', null
=True, blank
=True, )
395 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+', verbose_name
='Classement', null
=True, blank
=True, )
396 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True)
397 nom
= models
.CharField(verbose_name
="Poste", max_length
=255, null
=True, blank
=True)
398 montant
= models
.IntegerField(null
=True)
399 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
401 def taux_devise(self
):
402 if self
.devise
.code
== 'EUR':
404 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
405 if len(liste_taux
) == 0:
406 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
408 return liste_taux
[0].taux
410 def montant_euros(self
):
411 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
416 # TODO : migration pour m -> M, f -> F
423 class Employe(models
.Model
):
426 id_rh
= models
.ForeignKey(rh
.Employe
, null
=True, related_name
='+',
427 verbose_name
='Employé')
428 nom
= models
.CharField(max_length
=255)
429 prenom
= models
.CharField(max_length
=255, verbose_name
='Prénom')
430 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
432 def __unicode__(self
):
433 return u
'%s %s' % (self
.prenom
, self
.nom
.upper())
438 STATUT_RESIDENCE_CHOICES
= (
440 ('expat', 'Expatrié'),
443 COMPTE_COMPTA_CHOICES
= (
449 class Dossier(DossierWorkflow
, models
.Model
):
452 employe
= models
.ForeignKey('Employe', related_name
='+', editable
=False)
453 poste
= models
.ForeignKey('Poste', related_name
='dossiers', editable
=False)
454 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+')
455 organisme_bstg
= models
.ForeignKey(rh
.OrganismeBstg
,
456 null
=True, blank
=True,
457 verbose_name
="Organisme",
458 help_text
="Si détaché (DET) ou mis à disposition (MAD), \
459 préciser l'organisme.",
461 organisme_bstg_autre
= models
.CharField(max_length
=255,
462 verbose_name
="Autre organisme",
463 help_text
="indiquer l'organisme ici s'il n'est pas dans la liste",
467 # Données antérieures de l'employé
468 statut_anterieur
= models
.ForeignKey(
469 rh
.Statut
, related_name
='+', null
=True, blank
=True,
470 verbose_name
='Statut antérieur')
471 classement_anterieur
= models
.ForeignKey(
472 rh
.Classement
, related_name
='+', null
=True, blank
=True,
473 verbose_name
='Classement précédent')
474 salaire_anterieur
= models
.DecimalField(
475 max_digits
=12, decimal_places
=2, null
=True, default
=None,
476 blank
=True, verbose_name
='Salaire précédent')
477 devise_anterieur
= models
.ForeignKey(rh
.Devise
, related_name
='+', null
=True, blank
=True)
478 type_contrat_anterieur
= models
.ForeignKey(rh
.TypeContrat
, related_name
='+', null
=True, blank
=True, verbose_name
=u
'Type contrat antérieur', )
480 # Données du titulaire précédent
481 employe_anterieur
= models
.ForeignKey(
482 rh
.Employe
, related_name
='+', null
=True, blank
=True,
483 verbose_name
='Employé précédent')
484 statut_titulaire_anterieur
= models
.ForeignKey(
485 rh
.Statut
, related_name
='+', null
=True, blank
=True,
486 verbose_name
='Statut titulaire précédent')
487 classement_titulaire_anterieur
= models
.ForeignKey(
488 rh
.Classement
, related_name
='+', null
=True, blank
=True,
489 verbose_name
='Classement titulaire précédent')
490 salaire_titulaire_anterieur
= models
.DecimalField(
491 max_digits
=12, decimal_places
=2, default
=None, null
=True,
492 blank
=True, verbose_name
='Salaire titulaire précédent')
493 devise_titulaire_anterieur
= models
.ForeignKey(rh
.Devise
, related_name
='+', null
=True, blank
=True)
496 remplacement
= models
.BooleanField()
497 statut_residence
= models
.CharField(max_length
=10, default
='local',
498 verbose_name
="Statut",
499 choices
=STATUT_RESIDENCE_CHOICES
)
502 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
503 null
=True, blank
=True,
504 verbose_name
='Classement proposé')
505 salaire
= models
.DecimalField(max_digits
=12, decimal_places
=2,
506 verbose_name
='Salaire de base',
507 null
=True, default
=None)
508 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
509 regime_travail
= models
.DecimalField(max_digits
=12,
511 default
=REGIME_TRAVAIL_DEFAULT
,
512 verbose_name
="Régime de travail",
513 help_text
="% du temps complet")
514 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
516 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
517 verbose_name
="Nb. heures par semaine")
520 type_contrat
= models
.ForeignKey(rh
.TypeContrat
, related_name
='+')
521 contrat_date_debut
= models
.DateField(help_text
="format: aaaa-mm-jj")
522 contrat_date_fin
= models
.DateField(null
=True, blank
=True,
523 help_text
="format: aaaa-mm-jj")
526 justif_nouveau_statut_label
= u
'Justifier le statut que ce type de poste nécessite (national, expatrié, màd ou détachement)'
527 justif_nouveau_statut
= models
.TextField(verbose_name
=justif_nouveau_statut_label
, null
=True, blank
=True)
528 justif_nouveau_tmp_remplacement_label
= u
"Si l'employé effectue un remplacement temporaire, préciser"
529 justif_nouveau_tmp_remplacement
= models
.TextField(verbose_name
=justif_nouveau_tmp_remplacement_label
, null
=True, blank
=True)
530 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 "
531 justif_nouveau_salaire
= models
.TextField(verbose_name
=justif_nouveau_salaire_label
, null
=True, blank
=True)
532 justif_nouveau_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
533 justif_nouveau_commentaire
= models
.TextField(verbose_name
=justif_nouveau_commentaire_label
, null
=True, blank
=True)
534 justif_rempl_type_contrat_label
= u
"Changement de type de contrat, ex : d'un CDD en CDI"
535 justif_rempl_type_contrat
= models
.TextField(verbose_name
=justif_rempl_type_contrat_label
, null
=True, blank
=True)
536 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"
537 justif_rempl_statut_employe
= models
.TextField(verbose_name
=justif_rempl_statut_employe_label
, null
=True, blank
=True)
538 justif_rempl_evaluation_label
= u
"L'évaluation de l'employé est-elle favorable? Préciser"
539 justif_rempl_evaluation
= models
.TextField(verbose_name
=justif_rempl_evaluation_label
, null
=True, blank
=True)
540 justif_rempl_salaire_label
= u
"Si le salaire de l'employé est modifié et/ou ne correspond pas à son classement, justifier"
541 justif_rempl_salaire
= models
.TextField(verbose_name
=justif_rempl_salaire_label
, null
=True, blank
=True)
542 justif_rempl_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
543 justif_rempl_commentaire
= models
.TextField(verbose_name
=justif_rempl_commentaire_label
, null
=True, blank
=True)
546 compte_compta
= models
.CharField(max_length
=10, default
='aucun',
547 verbose_name
=u
'Compte comptabilité',
548 choices
=COMPTE_COMPTA_CHOICES
)
549 compte_courriel
= models
.BooleanField()
552 date_creation
= models
.DateTimeField(auto_now_add
=True)
555 objects
= DossierManager()
557 def __unicode__(self
):
558 return u
'[%s] %s - %s' % (self
.poste
.implantation
, self
.poste
.nom
, self
.employe
)
560 def taux_devise(self
):
561 if self
.devise
.code
== 'EUR':
563 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.poste
.implantation
)
564 if len(liste_taux
) == 0:
565 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.poste
.implantation
))
567 return liste_taux
[0].taux
569 def get_salaire_anterieur_euros(self
):
570 if self
.devise_anterieur
.code
== 'EUR':
573 liste_taux
= self
.devise_anterieur
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.poste
.implantation
)
574 if len(liste_taux
) == 0:
575 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_anterieur
, self
.poste
.implantation
))
576 tx
= liste_taux
[0].taux
577 return (float)(tx
) * (float)(self
.salaire_anterieur
)
579 def get_salaire_titulaire_anterieur_euros(self
):
580 if self
.devise_titulaire_anterieur
.code
== 'EUR':
583 liste_taux
= self
.devise_titulaire_anterieur
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.poste
.implantation
)
584 if len(liste_taux
) == 0:
585 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_titulaire_anterieur
, self
.poste
.implantation
))
586 tx
= liste_taux
[0].taux
587 return (float)(tx
) * (float)(self
.salaire_titulaire_anterieur
)
589 def get_salaire_euros(self
):
590 tx
= self
.taux_devise()
591 return (float)(tx
) * (float)(self
.salaire
)
593 def get_remunerations_brutes(self
):
597 4 Indemnité d'expatriation
598 5 Indemnité pour frais
599 6 Indemnité de logement
600 7 Indemnité de fonction
601 8 Indemnité de responsabilité
602 9 Indemnité de transport
603 10 Indemnité compensatrice
604 11 Indemnité de subsistance
605 12 Indemnité différentielle
606 13 Prime d'installation
609 16 Indemnité de départ
610 18 Prime de 13ième mois
613 ids
= [1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19]
614 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
616 def get_charges_salariales(self
):
618 20 Charges salariales ?
621 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
623 def get_total_charges_salariales(self
):
625 for r
in self
.get_charges_salariales():
626 total
+= r
.montant_euro()
629 def get_charges_patronales(self
):
631 17 Charges patronales
634 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
636 def get_total_charges_patronales(self
):
638 for r
in self
.get_charges_patronales():
639 total
+= r
.montant_euro()
642 def get_salaire_brut(self
):
644 somme des rémuérations brutes
647 for r
in self
.get_remunerations_brutes():
648 total
+= r
.montant_euro()
651 def get_salaire_net(self
):
653 salaire brut - charges salariales
656 for r
in self
.get_charges_salariales():
657 total_charges
+= r
.montant_euro()
658 return self
.get_salaire_brut() - total_charges
660 def get_couts_auf(self
):
662 salaire net + charges patronales
665 for r
in self
.get_charges_patronales():
666 total_charges
+= r
.montant_euro()
667 return self
.get_salaire_net() + total_charges
669 def get_remunerations_tierces(self
):
673 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in (2, )]
675 def get_total_remunerations_tierces(self
):
677 for r
in self
.get_remunerations_tierces():
678 total
+= r
.montant_euro()
682 # Tester l'enregistrement car les models.py sont importés au complet
683 if not reversion
.is_registered(Dossier
):
684 reversion
.register(Dossier
)
686 class DossierPiece(models
.Model
):
687 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
688 Ex.: Lettre de motivation.
690 dossier
= models
.ForeignKey("Dossier")
691 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
692 fichier
= models
.FileField(verbose_name
="Fichier", upload_to
='dae/dossier', storage
=UPLOAD_STORAGE
)
695 class DossierComparaison(models
.Model
):
697 Photo d'une comparaison salariale au moment de l'embauche.
699 dossier
= models
.ForeignKey('Dossier', related_name
='comparaisons')
700 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+', verbose_name
='Statut', null
=True, blank
=True, )
701 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+', verbose_name
='Classement', null
=True, blank
=True, )
702 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True)
703 poste
= models
.CharField(max_length
=255, null
=True, blank
=True)
704 personne
= models
.CharField(max_length
=255, null
=True, blank
=True)
705 montant
= models
.IntegerField(null
=True)
706 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
708 def taux_devise(self
):
709 if self
.devise
.code
== 'EUR':
711 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
712 if len(liste_taux
) == 0:
713 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
715 return liste_taux
[0].taux
717 def montant_euros(self
):
718 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
724 class Remuneration(models
.Model
):
726 dossier
= models
.ForeignKey('Dossier', db_column
='dossier')
727 type = models
.ForeignKey(rh
.TypeRemuneration
, db_column
='type',
729 montant
= models
.DecimalField(max_digits
=12, decimal_places
=2,
731 devise
= models
.ForeignKey(rh
.Devise
, to_field
='code',
732 db_column
='devise', related_name
='+')
733 precision
= models
.CharField(max_length
=255, null
=True, blank
=True)
736 date_creation
= models
.DateField(auto_now_add
=True)
737 user_creation
= models
.IntegerField(null
=True, blank
=True) # TODO : user
739 def montant_mois(self
):
740 return round(self
.montant
/ 12, 2)
742 def taux_devise(self
):
743 if self
.devise
.code
== 'EUR':
745 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.dossier
.poste
.implantation
)
746 if len(liste_taux
) == 0:
747 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.dossier
.poste
.implantation
))
749 return liste_taux
[0].taux
751 def montant_euro(self
):
752 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
754 def montant_euro_mois(self
):
755 return round(self
.montant_euro() / 12, 2)