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
22 storage_prive
= FileSystemStorage(settings
.PRIVE_MEDIA_ROOT
,
23 base_url
=settings
.PRIVE_MEDIA_URL
)
25 def poste_piece_dispatch(instance
, filename
):
26 path
= "poste/%s/%s" % (instance
.poste_id
, filename
)
29 def dossier_piece_dispatch(instance
, filename
):
30 path
= "dossier/%s/%s" % (instance
.dossier_id
, filename
)
36 POSTE_APPEL_CHOICES
= (
37 ('interne', 'Interne'),
38 ('externe', 'Externe'),
41 ('N', u
"Nouveau poste"),
42 ('M', u
"Poste existant"),
43 ('E', u
"Évolution de poste"),
47 class DeviseException(Exception):
48 silent_variable_failure
= True
51 class Poste(PosteWorkflow
, models
.Model
):
53 type_intervention
= models
.CharField(max_length
=1, choices
=POSTE_ACTION
, default
='N')
56 id_rh
= models
.ForeignKey(rh
.Poste
, null
=True, related_name
='+',
58 verbose_name
="Mise à jour du poste")
59 nom
= models
.CharField(verbose_name
="Titre du poste", max_length
=255)
60 implantation
= models
.ForeignKey(ref
.Implantation
)
61 type_poste
= models
.ForeignKey(rh
.TypePoste
, null
=True, related_name
='+')
62 service
= models
.ForeignKey(rh
.Service
, related_name
='+',
63 verbose_name
=u
"Direction/Service/Pôle support")
64 responsable
= models
.ForeignKey(rh
.Poste
, related_name
='+',
65 verbose_name
="Poste du responsable")
68 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
69 default
=REGIME_TRAVAIL_DEFAULT
,
70 verbose_name
="Temps de travail",
71 help_text
="% du temps complet")
72 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
74 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
75 verbose_name
="Nb. heures par semaine")
78 local
= models
.BooleanField(verbose_name
="Local", default
=True, blank
=True)
79 expatrie
= models
.BooleanField(verbose_name
="Expatrié", default
=False,
81 mise_a_disposition
= models
.BooleanField(verbose_name
="Mise à disposition")
82 appel
= models
.CharField(max_length
=10, default
='interne',
83 verbose_name
="Appel à candidature",
84 choices
=POSTE_APPEL_CHOICES
)
87 classement_min
= models
.ForeignKey(rh
.Classement
, related_name
='+',
88 blank
=True, null
=True)
89 classement_max
= models
.ForeignKey(rh
.Classement
, related_name
='+',
90 blank
=True, null
=True)
91 valeur_point_min
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+',
92 blank
=True, null
=True)
93 valeur_point_max
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+',
94 blank
=True, null
=True)
95 devise_min
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
96 devise_max
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
97 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
99 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
100 indemn_expat_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
101 indemn_expat_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
102 indemn_fct_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
103 indemn_fct_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
104 charges_patronales_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
105 charges_patronales_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
106 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
107 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
109 # Comparatifs de rémunération
110 devise_comparaison
= models
.ForeignKey(rh
.Devise
, related_name
='+',
112 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
113 null
=True, blank
=True)
114 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
115 null
=True, blank
=True)
116 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
117 null
=True, blank
=True)
118 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
119 null
=True, blank
=True)
120 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
121 null
=True, blank
=True)
122 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
123 null
=True, blank
=True)
124 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
125 null
=True, blank
=True)
126 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
127 null
=True, blank
=True)
128 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
129 null
=True, blank
=True)
130 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
131 null
=True, blank
=True)
134 justification
= models
.TextField()
137 date_creation
= models
.DateTimeField(auto_now_add
=True)
138 date_modification
= models
.DateTimeField(auto_now
=True)
139 date_debut
= models
.DateField(verbose_name
="Date de début",
140 help_text
=HELP_TEXT_DATE
,
141 null
=True, blank
=True)
142 date_fin
= models
.DateField(null
=True, blank
=True,
143 verbose_name
="Date de fin",
144 help_text
=HELP_TEXT_DATE
)
145 actif
= models
.BooleanField(default
=True)
148 objects
= PosteManager()
152 Les vues sont montées selon une clef spéciale
153 pour identifier la provenance du poste.
154 Cette méthode fournit un moyen de reconstruire cette clef
155 afin de générer les URLs.
157 return "dae-%s" % self
.id
158 key
= property(_get_key
)
160 def get_dossiers(self
):
162 Liste tous les anciens dossiers liés à ce poste.
163 (Le nom de la relation sur le rh.Poste est mal choisi
164 poste1 au lieu de dossier1)
165 Note1 : seulement le dosssier principal fait l'objet de la recherche.
166 Note2 : les dossiers sont retournés du plus récent au plus vieux.
167 (Ce test est fait en fonction du id,
168 car les dates de création sont absentes de rh v1).
170 if self
.id_rh
is None:
172 postes
= [p
for p
in self
.id_rh
.poste1
.all()]
173 return sorted(postes
, key
=lambda poste
: poste
.id, reverse
=True)
175 def get_complement_nom(self
):
177 Inspecte les modèles rh v1 pour trouver dans le dernier dossier
178 un complément de titre de poste.
180 dossiers
= self
.get_dossiers()
181 if len(dossiers
) > 0:
182 nom
= dossiers
[0].complement1
187 def get_employe(self
):
189 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
191 dossiers
= self
.get_dossiers()
192 if len(dossiers
) > 0:
193 return dossiers
[0].employe
197 def get_default_devise(self
):
198 """Récupère la devise par défaut en fonction de l'implantation
202 implantation_devise
= rh
.TauxChange
.objects \
203 .filter(implantation
=self
.implantation
)[0].devise
205 implantation_devise
= 5 # EUR
206 return implantation_devise
208 #####################
209 # Classement de poste
210 #####################
212 def get_couts_minimum(self
):
213 return (float)(self
.salaire_min
+ self
.indemn_expat_min
+ + self
.indemn_fct_min
+ self
.charges_patronales_min
+ self
.autre_min
)
215 def get_taux_minimum(self
):
216 taux_changes
= rh
.TauxChange
.objects
.filter(devise
=self
.devise_min
).order_by('annee')
217 for t
in taux_changes
:
218 if t
.implantation
== self
.implantation
:
220 if len(taux_changes
) > 0:
221 return taux_changes
[0].taux
223 raise DeviseException('Taux indisponible pour la devise %s (%s)' % (self
.devise_min
, self
.implantation
))
225 def get_couts_minimum_euros(self
):
226 return self
.get_couts_minimum() * self
.get_taux_minimum()
228 def get_couts_maximum(self
):
229 return (float)(self
.salaire_max
+ self
.indemn_expat_max
+ + self
.indemn_fct_max
+ self
.charges_patronales_max
+ self
.autre_max
)
231 def get_taux_maximum(self
):
232 taux_changes
= rh
.TauxChange
.objects
.filter(devise
=self
.devise_max
).order_by('annee')
233 for t
in taux_changes
:
234 if t
.implantation
== self
.implantation
:
236 if len(taux_changes
) > 0:
237 return taux_changes
[0].taux
239 raise DeviseException('Taux indisponible pour la devise %s (%s)' % (self
.devise_max
, self
.implantation
))
241 def get_couts_maximum_euros(self
):
242 return self
.get_couts_maximum() * self
.get_taux_maximum()
245 def show_taux_minimum(self
):
247 return self
.get_taux_minimum()
251 def show_couts_minimum_euros(self
):
253 return self
.get_couts_minimum_euros()
257 def show_taux_maximum(self
):
259 return self
.get_taux_maximum()
263 def show_couts_maximum_euros(self
):
265 return self
.get_couts_maximum_euros()
270 ######################
271 # Comparaison de poste
272 ######################
274 def est_comparable(self
):
276 Si on a au moins une valeur de saisie dans les comparaisons, alors le poste
279 if self
.comp_universite_min
is None and \
280 self
.comp_fonctionpub_min
is None and \
281 self
.comp_locale_min
is None and \
282 self
.comp_ong_min
is None and \
283 self
.comp_autre_min
is None and \
284 self
.comp_universite_max
is None and \
285 self
.comp_fonctionpub_max
is None and \
286 self
.comp_locale_max
is None and \
287 self
.comp_ong_max
is None and \
288 self
.comp_autre_max
is None:
294 def get_taux_comparaison(self
):
296 return rh
.TauxChange
.objects
.filter(implantation
=self
.implantation
, devise
=self
.devise_comparaison
)[0].taux
300 def get_comp_universite_min_euros(self
):
301 return (float)(self
.comp_universite_min
) * self
.get_taux_comparaison()
303 def get_comp_fonctionpub_min_euros(self
):
304 return (float)(self
.comp_fonctionpub_min
) * self
.get_taux_comparaison()
306 def get_comp_locale_min_euros(self
):
307 return (float)(self
.comp_locale_min
) * self
.get_taux_comparaison()
309 def get_comp_ong_min_euros(self
):
310 return (float)(self
.comp_ong_min
) * self
.get_taux_comparaison()
312 def get_comp_autre_min_euros(self
):
313 return (float)(self
.comp_autre_min
) * self
.get_taux_comparaison()
315 def get_comp_universite_max_euros(self
):
316 return (float)(self
.comp_universite_max
) * self
.get_taux_comparaison()
318 def get_comp_fonctionpub_max_euros(self
):
319 return (float)(self
.comp_fonctionpub_max
) * self
.get_taux_comparaison()
321 def get_comp_locale_max_euros(self
):
322 return (float)(self
.comp_locale_max
) * self
.get_taux_comparaison()
324 def get_comp_ong_max_euros(self
):
325 return (float)(self
.comp_ong_max
) * self
.get_taux_comparaison()
327 def get_comp_autre_max_euros(self
):
328 return (float)(self
.comp_autre_max
) * self
.get_taux_comparaison()
331 def __unicode__(self
):
333 Cette fonction est consommatrice SQL car elle cherche les dossiers
334 qui ont été liés à celui-ci.
336 complement_nom_poste
= self
.get_complement_nom()
337 if complement_nom_poste
is None:
338 complement_nom_poste
= ""
344 return u
'%s - %s (%s)' % data
347 # Tester l'enregistrement car les models.py sont importés au complet
348 if not reversion
.is_registered(Poste
):
349 reversion
.register(Poste
)
352 POSTE_FINANCEMENT_CHOICES
= (
353 ('A', 'A - Frais de personnel'),
354 ('B', 'B - Projet(s)-Titre(s)'),
358 class PosteFinancement(models
.Model
):
359 poste
= models
.ForeignKey('Poste', related_name
='financements')
360 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
361 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
362 help_text
="ex.: 33.33 % (décimale avec point)")
363 commentaire
= models
.TextField(
364 help_text
="Spécifiez la source de financement.")
369 def __unicode__(self
):
370 return u
"%s %s %s" % (self
.get_type_display(), self
.pourcentage
, self
.commentaire
)
373 class PostePiece(models
.Model
):
374 """Documents relatifs au Poste
375 Ex.: Description de poste
377 poste
= models
.ForeignKey("Poste")
378 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
379 fichier
= models
.FileField(verbose_name
="Fichier",
380 upload_to
=poste_piece_dispatch
,
381 storage
=storage_prive
)
383 class PosteComparaison(models
.Model
):
384 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
385 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+', verbose_name
='Statut', null
=True, blank
=True, )
386 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+', verbose_name
='Classement', null
=True, blank
=True, )
387 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True)
388 nom
= models
.CharField(verbose_name
="Poste", max_length
=255, null
=True, blank
=True)
389 montant
= models
.IntegerField(null
=True)
390 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
392 def taux_devise(self
):
393 if self
.devise
.code
== 'EUR':
395 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
396 if len(liste_taux
) == 0:
397 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
399 return liste_taux
[0].taux
401 def montant_euros(self
):
402 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
407 # TODO : migration pour m -> M, f -> F
414 class Employe(models
.Model
):
417 id_rh
= models
.ForeignKey(rh
.Employe
, null
=True, related_name
='+',
418 verbose_name
='Employé')
419 nom
= models
.CharField(max_length
=255)
420 prenom
= models
.CharField(max_length
=255, verbose_name
='Prénom')
421 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
423 def __unicode__(self
):
424 return u
'%s %s' % (self
.prenom
, self
.nom
.upper())
429 STATUT_RESIDENCE_CHOICES
= (
431 ('expat', 'Expatrié'),
434 COMPTE_COMPTA_CHOICES
= (
440 class Dossier(DossierWorkflow
, models
.Model
):
443 employe
= models
.ForeignKey('Employe', related_name
='+', editable
=False)
444 poste
= models
.ForeignKey('Poste', related_name
='dossiers', editable
=False)
445 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+')
446 organisme_bstg
= models
.ForeignKey(rh
.OrganismeBstg
,
447 null
=True, blank
=True,
448 verbose_name
="Organisme",
449 help_text
="Si détaché (DET) ou mis à disposition (MAD), \
450 préciser l'organisme.",
452 organisme_bstg_autre
= models
.CharField(max_length
=255,
453 verbose_name
="Autre organisme",
454 help_text
="indiquer l'organisme ici s'il n'est pas dans la liste",
458 # Données antérieures de l'employé
459 statut_anterieur
= models
.ForeignKey(
460 rh
.Statut
, related_name
='+', null
=True, blank
=True,
461 verbose_name
='Statut antérieur')
462 classement_anterieur
= models
.ForeignKey(
463 rh
.Classement
, related_name
='+', null
=True, blank
=True,
464 verbose_name
='Classement précédent')
465 salaire_anterieur
= models
.DecimalField(
466 max_digits
=12, decimal_places
=2, null
=True, default
=None,
467 blank
=True, verbose_name
='Salaire précédent')
468 devise_anterieur
= models
.ForeignKey(rh
.Devise
, related_name
='+', null
=True, blank
=True)
470 # Données du titulaire précédent
471 employe_anterieur
= models
.ForeignKey(
472 rh
.Employe
, related_name
='+', null
=True, blank
=True,
473 verbose_name
='Employé précédent')
474 statut_titulaire_anterieur
= models
.ForeignKey(
475 rh
.Statut
, related_name
='+', null
=True, blank
=True,
476 verbose_name
='Statut titulaire précédent')
477 classement_titulaire_anterieur
= models
.ForeignKey(
478 rh
.Classement
, related_name
='+', null
=True, blank
=True,
479 verbose_name
='Classement titulaire précédent')
480 salaire_titulaire_anterieur
= models
.DecimalField(
481 max_digits
=12, decimal_places
=2, default
=None, null
=True,
482 blank
=True, verbose_name
='Salaire titulaire précédent')
483 devise_titulaire_anterieur
= models
.ForeignKey(rh
.Devise
, related_name
='+', null
=True, blank
=True)
486 remplacement
= models
.BooleanField()
487 statut_residence
= models
.CharField(max_length
=10, default
='local',
488 verbose_name
="Statut",
489 choices
=STATUT_RESIDENCE_CHOICES
)
492 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
493 null
=True, blank
=True,
494 verbose_name
='Classement proposé')
495 salaire
= models
.DecimalField(max_digits
=12, decimal_places
=2,
496 verbose_name
='Salaire de base',
497 null
=True, default
=None)
498 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
499 regime_travail
= models
.DecimalField(max_digits
=12,
501 default
=REGIME_TRAVAIL_DEFAULT
,
502 verbose_name
="Régime de travail",
503 help_text
="% du temps complet")
504 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
506 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
507 verbose_name
="Nb. heures par semaine")
510 type_contrat
= models
.ForeignKey(rh
.TypeContrat
, related_name
='+')
511 contrat_date_debut
= models
.DateField(help_text
="format: aaaa-mm-jj")
512 contrat_date_fin
= models
.DateField(null
=True, blank
=True,
513 help_text
="format: aaaa-mm-jj")
516 justif_nouveau_statut_label
= u
'Justifier le statut que ce type de poste nécessite (national, expatrié, màd ou détachement)'
517 justif_nouveau_statut
= models
.TextField(verbose_name
=justif_nouveau_statut_label
, null
=True, blank
=True)
518 justif_nouveau_tmp_remplacement_label
= u
"Si l'employé effectue un remplacement temporaire, préciser"
519 justif_nouveau_tmp_remplacement
= models
.TextField(verbose_name
=justif_nouveau_tmp_remplacement_label
, null
=True, blank
=True)
520 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 "
521 justif_nouveau_salaire
= models
.TextField(verbose_name
=justif_nouveau_salaire_label
, null
=True, blank
=True)
522 justif_nouveau_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
523 justif_nouveau_commentaire
= models
.TextField(verbose_name
=justif_nouveau_commentaire_label
, null
=True, blank
=True)
524 justif_rempl_type_contrat_label
= u
"Changement de type de contrat, ex : d'un CDD en CDI"
525 justif_rempl_type_contrat
= models
.TextField(verbose_name
=justif_rempl_type_contrat_label
, null
=True, blank
=True)
526 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"
527 justif_rempl_statut_employe
= models
.TextField(verbose_name
=justif_rempl_statut_employe_label
, null
=True, blank
=True)
528 justif_rempl_evaluation_label
= u
"L'évaluation de l'employé est-elle favorable? Préciser"
529 justif_rempl_evaluation
= models
.TextField(verbose_name
=justif_rempl_evaluation_label
, null
=True, blank
=True)
530 justif_rempl_salaire_label
= u
"Si le salaire de l'employé est modifié et/ou ne correspond pas à son classement, justifier"
531 justif_rempl_salaire
= models
.TextField(verbose_name
=justif_rempl_salaire_label
, null
=True, blank
=True)
532 justif_rempl_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
533 justif_rempl_commentaire
= models
.TextField(verbose_name
=justif_rempl_commentaire_label
, null
=True, blank
=True)
536 compte_compta
= models
.CharField(max_length
=10, default
='aucun',
537 verbose_name
=u
'Compte comptabilité',
538 choices
=COMPTE_COMPTA_CHOICES
)
539 compte_courriel
= models
.BooleanField()
542 date_creation
= models
.DateTimeField(auto_now_add
=True)
545 objects
= DossierManager()
547 def __unicode__(self
):
548 return u
'[%s] %s - %s' % (self
.poste
.implantation
, self
.poste
.nom
, self
.employe
)
550 def taux_devise(self
):
551 if self
.devise
.code
== 'EUR':
553 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.poste
.implantation
)
554 if len(liste_taux
) == 0:
555 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.poste
.implantation
))
557 return liste_taux
[0].taux
559 def get_salaire_anterieur_euros(self
):
560 if self
.devise_anterieur
.code
== 'EUR':
563 liste_taux
= self
.devise_anterieur
.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_anterieur
, self
.poste
.implantation
))
566 tx
= liste_taux
[0].taux
567 return (float)(tx
) * (float)(self
.salaire_anterieur
)
569 def get_salaire_titulaire_anterieur_euros(self
):
570 if self
.devise_anterieur
.code
== 'EUR':
573 liste_taux
= self
.devise_titulaire_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_titulaire_anterieur
, self
.poste
.implantation
))
576 tx
= liste_taux
[0].taux
577 return (float)(tx
) * (float)(self
.salaire_titulaire_anterieur
)
579 def get_salaire_euros(self
):
580 tx
= self
.taux_devise()
581 return (float)(tx
) * (float)(self
.salaire
)
583 def get_remunerations_brutes(self
):
587 4 Indemnité d'expatriation
588 5 Indemnité pour frais
589 6 Indemnité de logement
590 7 Indemnité de fonction
591 8 Indemnité de responsabilité
592 9 Indemnité de transport
593 10 Indemnité compensatrice
594 11 Indemnité de subsistance
595 12 Indemnité différentielle
596 13 Prime d'installation
599 16 Indemnité de départ
600 18 Prime de 13ième mois
603 ids
= [1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19]
604 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
606 def get_charges_salariales(self
):
608 20 Charges salariales ?
611 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
613 def get_total_charges_salariales(self
):
615 for r
in self
.get_charges_salariales():
616 total
+= r
.montant_euro()
619 def get_charges_patronales(self
):
621 17 Charges patronales
624 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
626 def get_total_charges_patronales(self
):
628 for r
in self
.get_charges_patronales():
629 total
+= r
.montant_euro()
632 def get_salaire_brut(self
):
634 somme des rémuérations brutes
637 for r
in self
.get_remunerations_brutes():
638 total
+= r
.montant_euro()
641 def get_salaire_net(self
):
643 salaire brut - charges salariales
646 for r
in self
.get_charges_salariales():
647 total_charges
+= r
.montant_euro()
648 return self
.get_salaire_brut() - total_charges
650 def get_couts_auf(self
):
652 salaire net + charges patronales
655 for r
in self
.get_charges_patronales():
656 total_charges
+= r
.montant_euro()
657 return self
.get_salaire_net() + total_charges
659 def get_remunerations_tierces(self
):
663 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in (2, )]
665 def get_total_remunerations_tierces(self
):
667 for r
in self
.get_remunerations_tierces():
668 total
+= r
.montant_euro()
672 # Tester l'enregistrement car les models.py sont importés au complet
673 if not reversion
.is_registered(Dossier
):
674 reversion
.register(Dossier
)
676 class DossierPiece(models
.Model
):
677 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
678 Ex.: Lettre de motivation.
680 dossier
= models
.ForeignKey("Dossier")
681 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
682 fichier
= models
.FileField(verbose_name
="Fichier",
683 upload_to
=dossier_piece_dispatch
,
684 storage
=storage_prive
)
687 class DossierComparaison(models
.Model
):
689 Photo d'une comparaison salariale au moment de l'embauche.
691 dossier
= models
.ForeignKey('Dossier', related_name
='comparaisons')
692 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+', verbose_name
='Statut', null
=True, blank
=True, )
693 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+', verbose_name
='Classement', null
=True, blank
=True, )
694 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True)
695 poste
= models
.CharField(max_length
=255, null
=True, blank
=True)
696 personne
= models
.CharField(max_length
=255, null
=True, blank
=True)
697 montant
= models
.IntegerField(null
=True)
698 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
700 def taux_devise(self
):
701 if self
.devise
.code
== 'EUR':
703 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
704 if len(liste_taux
) == 0:
705 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
707 return liste_taux
[0].taux
709 def montant_euros(self
):
710 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
716 class Remuneration(models
.Model
):
718 dossier
= models
.ForeignKey('Dossier', db_column
='dossier')
719 type = models
.ForeignKey(rh
.TypeRemuneration
, db_column
='type',
721 montant
= models
.DecimalField(max_digits
=12, decimal_places
=2,
723 devise
= models
.ForeignKey(rh
.Devise
, to_field
='code',
724 db_column
='devise', related_name
='+')
725 precision
= models
.CharField(max_length
=255, null
=True, blank
=True)
728 date_creation
= models
.DateField(auto_now_add
=True)
729 user_creation
= models
.IntegerField(null
=True, blank
=True) # TODO : user
731 def montant_mois(self
):
732 return round(self
.montant
/ 12, 2)
734 def taux_devise(self
):
735 if self
.devise
.code
== 'EUR':
737 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.dossier
.poste
.implantation
)
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
.dossier
.poste
.implantation
))
741 return liste_taux
[0].taux
743 def montant_euro(self
):
744 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
746 def montant_euro_mois(self
):
747 return round(self
.montant_euro() / 12, 2)