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_v1
import models
as rh
18 HELP_TEXT_DATE
= "format: aaaa-mm-jj"
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 postes
= [p
for p
in self
.id_rh
.poste1
.all()]
165 return sorted(postes
, key
=lambda poste
: poste
.id, reverse
=True)
167 def get_complement_nom(self
):
169 Inspecte les modèles rh v1 pour trouver dans le dernier dossier
170 un complément de titre de poste.
172 dossiers
= self
.get_dossiers()
173 if len(dossiers
) > 0:
174 nom
= dossiers
[0].complement1
179 def get_employe(self
):
181 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
183 dossiers
= self
.get_dossiers()
184 if len(dossiers
) > 0:
185 return dossiers
[0].employe
189 def get_default_devise(self
):
190 """Récupère la devise par défaut en fonction de l'implantation
194 implantation_devise
= rh
.TauxChange
.objects \
195 .filter(implantation
=self
.implantation
)[0].devise
197 implantation_devise
= 5 # EUR
198 return implantation_devise
200 #####################
201 # Classement de poste
202 #####################
204 def get_couts_minimum(self
):
205 return self
.salaire_min
+ self
.indemn_expat_min
+ self
.indemn_fct_min
+ self
.charges_patronales_min
+ self
.autre_min
207 def get_salaire_minimum(self
):
208 return self
.get_couts_minimum() - self
.charges_patronales_min
210 def get_taux_minimum(self
):
211 if self
.devise_min
.code
== 'EUR':
213 liste_taux
= self
.devise_min
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
214 if len(liste_taux
) == 0:
215 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_min
, self
.implantation
))
217 return liste_taux
[0].taux
219 def get_couts_minimum_euros(self
):
220 return float(self
.get_couts_minimum()) * self
.get_taux_minimum()
222 def get_salaire_minimum_euros(self
):
223 return float(self
.get_salaire_minimum()) * self
.get_taux_minimum()
225 def get_couts_maximum(self
):
226 return self
.salaire_max
+ self
.indemn_expat_max
+ self
.indemn_fct_max
+ self
.charges_patronales_max
+ self
.autre_max
228 def get_salaire_maximum(self
):
229 return self
.get_couts_maximum() - self
.charges_patronales_max
231 def get_taux_maximum(self
):
232 if self
.devise_max
.code
== 'EUR':
234 liste_taux
= self
.devise_max
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
235 if len(liste_taux
) == 0:
236 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_max
, self
.implantation
))
238 return liste_taux
[0].taux
240 def get_couts_maximum_euros(self
):
241 return float(self
.get_couts_maximum()) * self
.get_taux_maximum()
243 def get_salaire_maximum_euros(self
):
244 return float(self
.get_salaire_maximum()) * self
.get_taux_maximum()
246 def show_taux_minimum(self
):
248 return self
.get_taux_minimum()
249 except DeviseException
, e
:
252 def show_couts_minimum_euros(self
):
254 return self
.get_couts_minimum_euros()
255 except DeviseException
, e
:
258 def show_salaire_minimum_euros(self
):
260 return self
.get_salaire_minimum_euros()
261 except DeviseException
, e
:
264 def show_taux_maximum(self
):
266 return self
.get_taux_maximum()
267 except DeviseException
, e
:
270 def show_couts_maximum_euros(self
):
272 return self
.get_couts_maximum_euros()
273 except DeviseException
, e
:
276 def show_salaire_maximum_euros(self
):
278 return self
.get_salaire_maximum_euros()
279 except DeviseException
, e
:
283 ######################
284 # Comparaison de poste
285 ######################
287 def est_comparable(self
):
289 Si on a au moins une valeur de saisie dans les comparaisons, alors le poste
292 if self
.comp_universite_min
is None and \
293 self
.comp_fonctionpub_min
is None and \
294 self
.comp_locale_min
is None and \
295 self
.comp_ong_min
is None and \
296 self
.comp_autre_min
is None and \
297 self
.comp_universite_max
is None and \
298 self
.comp_fonctionpub_max
is None and \
299 self
.comp_locale_max
is None and \
300 self
.comp_ong_max
is None and \
301 self
.comp_autre_max
is None:
307 def get_taux_comparaison(self
):
309 return rh
.TauxChange
.objects
.filter(implantation
=self
.implantation
, devise
=self
.devise_comparaison
)[0].taux
313 def get_comp_universite_min_euros(self
):
314 return (float)(self
.comp_universite_min
) * self
.get_taux_comparaison()
316 def get_comp_fonctionpub_min_euros(self
):
317 return (float)(self
.comp_fonctionpub_min
) * self
.get_taux_comparaison()
319 def get_comp_locale_min_euros(self
):
320 return (float)(self
.comp_locale_min
) * self
.get_taux_comparaison()
322 def get_comp_ong_min_euros(self
):
323 return (float)(self
.comp_ong_min
) * self
.get_taux_comparaison()
325 def get_comp_autre_min_euros(self
):
326 return (float)(self
.comp_autre_min
) * self
.get_taux_comparaison()
328 def get_comp_universite_max_euros(self
):
329 return (float)(self
.comp_universite_max
) * self
.get_taux_comparaison()
331 def get_comp_fonctionpub_max_euros(self
):
332 return (float)(self
.comp_fonctionpub_max
) * self
.get_taux_comparaison()
334 def get_comp_locale_max_euros(self
):
335 return (float)(self
.comp_locale_max
) * self
.get_taux_comparaison()
337 def get_comp_ong_max_euros(self
):
338 return (float)(self
.comp_ong_max
) * self
.get_taux_comparaison()
340 def get_comp_autre_max_euros(self
):
341 return (float)(self
.comp_autre_max
) * self
.get_taux_comparaison()
344 def __unicode__(self
):
346 Cette fonction est consommatrice SQL car elle cherche les dossiers
347 qui ont été liés à celui-ci.
349 complement_nom_poste
= self
.get_complement_nom()
350 if complement_nom_poste
is None:
351 complement_nom_poste
= ""
357 return u
'%s - %s (%s)' % data
360 # Tester l'enregistrement car les models.py sont importés au complet
361 if not reversion
.is_registered(Poste
):
362 reversion
.register(Poste
)
365 POSTE_FINANCEMENT_CHOICES
= (
366 ('A', 'A - Frais de personnel'),
367 ('B', 'B - Projet(s)-Titre(s)'),
371 class PosteFinancement(models
.Model
):
372 poste
= models
.ForeignKey('Poste', related_name
='financements')
373 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
374 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
375 help_text
="ex.: 33.33 % (décimale avec point)")
376 commentaire
= models
.TextField(
377 help_text
="Spécifiez la source de financement.")
382 def __unicode__(self
):
383 return u
"%s %.0f%% %s" % (self
.get_type_display(), self
.pourcentage
, self
.commentaire
)
386 class PostePiece(models
.Model
):
387 """Documents relatifs au Poste
388 Ex.: Description de poste
390 poste
= models
.ForeignKey("Poste")
391 nom
= models
.CharField(verbose_name
=u
"Nom", max_length
=255)
392 fichier
= models
.FileField(verbose_name
=u
"Fichier",
393 upload_to
='dae/poste',
394 storage
=UPLOAD_STORAGE
)
396 class PosteComparaison(models
.Model
):
397 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
398 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True, related_name
="+")
399 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+', verbose_name
=u
'Statut', null
=True, blank
=True, )
400 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+', verbose_name
=u
'Classement', null
=True, blank
=True, )
401 nom
= models
.CharField(verbose_name
=u
"Poste", max_length
=255, null
=True, blank
=True)
402 montant
= models
.IntegerField(null
=True)
403 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
405 objects
= PosteComparaisonManager()
407 def taux_devise(self
):
408 if self
.devise
.code
== 'EUR':
410 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
411 if len(liste_taux
) == 0:
412 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
414 return liste_taux
[0].taux
416 def montant_euros(self
):
417 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
422 # TODO : migration pour m -> M, f -> F
429 class Employe(models
.Model
):
432 id_rh
= models
.ForeignKey(rh
.Employe
, null
=True, related_name
='+',
433 verbose_name
=u
'Employé')
434 nom
= models
.CharField(max_length
=255)
435 prenom
= models
.CharField(max_length
=255, verbose_name
=u
'Prénom')
436 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
438 def __unicode__(self
):
439 return u
'%s %s' % (self
.prenom
, self
.nom
.upper())
444 STATUT_RESIDENCE_CHOICES
= (
446 ('expat', 'Expatrié'),
449 COMPTE_COMPTA_CHOICES
= (
455 class Dossier(DossierWorkflow
, models
.Model
):
458 employe
= models
.ForeignKey('Employe', related_name
='+', editable
=False)
459 poste
= models
.ForeignKey('Poste', related_name
='dossiers', editable
=False)
460 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+')
461 organisme_bstg
= models
.ForeignKey(rh
.OrganismeBstg
,
462 null
=True, blank
=True,
463 verbose_name
=u
"Organisme",
464 help_text
="Si détaché (DET) ou mis à disposition (MAD), \
465 préciser l'organisme.",
467 organisme_bstg_autre
= models
.CharField(max_length
=255,
468 verbose_name
=u
"Autre organisme",
469 help_text
="indiquer l'organisme ici s'il n'est pas dans la liste",
473 # Données antérieures de l'employé
474 statut_anterieur
= models
.ForeignKey(
475 rh
.Statut
, related_name
='+', null
=True, blank
=True,
476 verbose_name
=u
'Statut antérieur')
477 classement_anterieur
= models
.ForeignKey(
478 rh
.Classement
, related_name
='+', null
=True, blank
=True,
479 verbose_name
=u
'Classement précédent')
480 salaire_anterieur
= models
.DecimalField(
481 max_digits
=12, decimal_places
=2, null
=True, default
=None,
482 blank
=True, verbose_name
=u
'Salaire précédent')
483 devise_anterieur
= models
.ForeignKey(rh
.Devise
, related_name
='+',
484 null
=True, blank
=True)
485 type_contrat_anterieur
= models
.ForeignKey(rh
.TypeContrat
,
486 related_name
='+', null
=True, blank
=True,
487 verbose_name
=u
'Type contrat antérieur', )
489 # Données du titulaire précédent
490 employe_anterieur
= models
.ForeignKey(
491 rh
.Employe
, related_name
='+', null
=True, blank
=True,
492 verbose_name
=u
'Employé précédent')
493 statut_titulaire_anterieur
= models
.ForeignKey(
494 rh
.Statut
, related_name
='+', null
=True, blank
=True,
495 verbose_name
=u
'Statut titulaire précédent')
496 classement_titulaire_anterieur
= models
.ForeignKey(
497 rh
.Classement
, related_name
='+', null
=True, blank
=True,
498 verbose_name
=u
'Classement titulaire précédent')
499 salaire_titulaire_anterieur
= models
.DecimalField(
500 max_digits
=12, decimal_places
=2, default
=None, null
=True,
501 blank
=True, verbose_name
=u
'Salaire titulaire précédent')
502 devise_titulaire_anterieur
= models
.ForeignKey(rh
.Devise
, related_name
='+', null
=True, blank
=True)
505 remplacement
= models
.BooleanField()
506 statut_residence
= models
.CharField(max_length
=10, default
='local',
507 verbose_name
="Statut",
508 choices
=STATUT_RESIDENCE_CHOICES
)
511 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
512 null
=True, blank
=True,
513 verbose_name
=u
'Classement proposé')
514 salaire
= models
.DecimalField(max_digits
=12, decimal_places
=2,
515 verbose_name
=u
'Salaire de base',
516 null
=True, default
=None)
517 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
518 regime_travail
= models
.DecimalField(max_digits
=12,
520 default
=REGIME_TRAVAIL_DEFAULT
,
521 verbose_name
=u
"Régime de travail",
522 help_text
="% du temps complet")
523 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
525 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
526 verbose_name
=u
"Nb. heures par semaine")
529 type_contrat
= models
.ForeignKey(rh
.TypeContrat
, related_name
='+')
530 contrat_date_debut
= models
.DateField(help_text
="format: aaaa-mm-jj")
531 contrat_date_fin
= models
.DateField(null
=True, blank
=True,
532 help_text
="format: aaaa-mm-jj")
535 justif_nouveau_statut_label
= u
'Justifier le statut que ce type de poste nécessite (national, expatrié, màd ou détachement)'
536 justif_nouveau_statut
= models
.TextField(verbose_name
=justif_nouveau_statut_label
, null
=True, blank
=True)
537 justif_nouveau_tmp_remplacement_label
= u
"Si l'employé effectue un remplacement temporaire, préciser"
538 justif_nouveau_tmp_remplacement
= models
.TextField(verbose_name
=justif_nouveau_tmp_remplacement_label
, null
=True, blank
=True)
539 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 "
540 justif_nouveau_salaire
= models
.TextField(verbose_name
=justif_nouveau_salaire_label
, null
=True, blank
=True)
541 justif_nouveau_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
542 justif_nouveau_commentaire
= models
.TextField(verbose_name
=justif_nouveau_commentaire_label
, null
=True, blank
=True)
543 justif_rempl_type_contrat_label
= u
"Changement de type de contrat, ex : d'un CDD en CDI"
544 justif_rempl_type_contrat
= models
.TextField(verbose_name
=justif_rempl_type_contrat_label
, null
=True, blank
=True)
545 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"
546 justif_rempl_statut_employe
= models
.TextField(verbose_name
=justif_rempl_statut_employe_label
, null
=True, blank
=True)
547 justif_rempl_evaluation_label
= u
"L'évaluation de l'employé est-elle favorable? Préciser"
548 justif_rempl_evaluation
= models
.TextField(verbose_name
=justif_rempl_evaluation_label
, null
=True, blank
=True)
549 justif_rempl_salaire_label
= u
"Si le salaire de l'employé est modifié et/ou ne correspond pas à son classement, justifier"
550 justif_rempl_salaire
= models
.TextField(verbose_name
=justif_rempl_salaire_label
, null
=True, blank
=True)
551 justif_rempl_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
552 justif_rempl_commentaire
= models
.TextField(verbose_name
=justif_rempl_commentaire_label
, null
=True, blank
=True)
555 compte_compta
= models
.CharField(max_length
=10, default
='aucun',
556 verbose_name
=u
'Compte comptabilité',
557 choices
=COMPTE_COMPTA_CHOICES
)
558 compte_courriel
= models
.BooleanField()
561 date_creation
= models
.DateTimeField(auto_now_add
=True)
564 objects
= DossierManager()
566 def __unicode__(self
):
567 return u
'[%s] %s - %s' % (self
.poste
.implantation
, self
.poste
.nom
, self
.employe
)
569 def taux_devise(self
):
570 if self
.devise
.code
== 'EUR':
572 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.poste
.implantation
)
573 if len(liste_taux
) == 0:
574 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.poste
.implantation
))
576 return liste_taux
[0].taux
578 def get_salaire_anterieur_euros(self
):
579 if self
.devise_anterieur
.code
== 'EUR':
582 liste_taux
= self
.devise_anterieur
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.poste
.implantation
)
583 if len(liste_taux
) == 0:
584 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_anterieur
, self
.poste
.implantation
))
585 tx
= liste_taux
[0].taux
586 return (float)(tx
) * (float)(self
.salaire_anterieur
)
588 def get_salaire_titulaire_anterieur_euros(self
):
589 if self
.devise_titulaire_anterieur
.code
== 'EUR':
592 liste_taux
= self
.devise_titulaire_anterieur
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.poste
.implantation
)
593 if len(liste_taux
) == 0:
594 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise_titulaire_anterieur
, self
.poste
.implantation
))
595 tx
= liste_taux
[0].taux
596 return (float)(tx
) * (float)(self
.salaire_titulaire_anterieur
)
598 def get_salaire_euros(self
):
599 tx
= self
.taux_devise()
600 return (float)(tx
) * (float)(self
.salaire
)
602 def get_remunerations_brutes(self
):
606 4 Indemnité d'expatriation
607 5 Indemnité pour frais
608 6 Indemnité de logement
609 7 Indemnité de fonction
610 8 Indemnité de responsabilité
611 9 Indemnité de transport
612 10 Indemnité compensatrice
613 11 Indemnité de subsistance
614 12 Indemnité différentielle
615 13 Prime d'installation
618 16 Indemnité de départ
619 18 Prime de 13ième mois
622 ids
= [1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19]
623 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
625 def get_charges_salariales(self
):
627 20 Charges salariales ?
630 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
632 def get_total_charges_salariales(self
):
634 for r
in self
.get_charges_salariales():
635 total
+= r
.montant_euro()
638 def get_charges_patronales(self
):
640 17 Charges patronales
643 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
645 def get_total_charges_patronales(self
):
647 for r
in self
.get_charges_patronales():
648 total
+= r
.montant_euro()
651 def get_salaire_brut(self
):
653 somme des rémuérations brutes
656 for r
in self
.get_remunerations_brutes():
657 total
+= r
.montant_euro()
660 def get_salaire_net(self
):
662 salaire brut - charges salariales
665 for r
in self
.get_charges_salariales():
666 total_charges
+= r
.montant_euro()
667 return self
.get_salaire_brut() - total_charges
669 def get_couts_auf(self
):
671 salaire net + charges patronales
674 for r
in self
.get_charges_patronales():
675 total_charges
+= r
.montant_euro()
676 return self
.get_salaire_net() + total_charges
678 def get_remunerations_tierces(self
):
682 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in (2, )]
684 def get_total_remunerations_tierces(self
):
686 for r
in self
.get_remunerations_tierces():
687 total
+= r
.montant_euro()
691 return self
.etat
in (DOSSIER_ETAT_REGION_FINALISATION
,
692 DOSSIER_ETAT_DRH_FINALISATION
,
693 DOSSIER_ETAT_FINALISE
)
696 # Tester l'enregistrement car les models.py sont importés au complet
697 if not reversion
.is_registered(Dossier
):
698 reversion
.register(Dossier
)
700 class DossierPiece(models
.Model
):
701 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
702 Ex.: Lettre de motivation.
704 dossier
= models
.ForeignKey("Dossier")
705 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
706 fichier
= models
.FileField(verbose_name
="Fichier",
707 upload_to
='dae/dossier',
708 storage
=UPLOAD_STORAGE
)
711 class DossierComparaison(models
.Model
):
713 Photo d'une comparaison salariale au moment de l'embauche.
715 dossier
= models
.ForeignKey('Dossier', related_name
='comparaisons')
716 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+',
717 verbose_name
='Statut', null
=True, blank
=True, )
718 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
719 verbose_name
='Classement', null
=True, blank
=True, )
720 implantation
= models
.ForeignKey(ref
.Implantation
, related_name
='+',
721 null
=True, blank
=True)
722 poste
= models
.CharField(max_length
=255, null
=True, blank
=True)
723 personne
= models
.CharField(max_length
=255, null
=True, blank
=True)
724 montant
= models
.IntegerField(null
=True)
725 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
727 objects
= DossierComparaisonManager()
729 def taux_devise(self
):
730 if self
.devise
.code
== 'EUR':
732 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
733 if len(liste_taux
) == 0:
734 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
736 return liste_taux
[0].taux
738 def montant_euros(self
):
739 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
745 class Remuneration(models
.Model
):
747 dossier
= models
.ForeignKey('Dossier', db_column
='dossier')
748 type = models
.ForeignKey(rh
.TypeRemuneration
, db_column
='type',
750 montant
= models
.DecimalField(max_digits
=12, decimal_places
=2,
752 devise
= models
.ForeignKey(rh
.Devise
, to_field
='code',
753 db_column
='devise', related_name
='+')
754 precision
= models
.CharField(max_length
=255, null
=True, blank
=True)
757 date_creation
= models
.DateField(auto_now_add
=True)
758 user_creation
= models
.IntegerField(null
=True, blank
=True) # TODO : user
760 def montant_mois(self
):
761 return round(self
.montant
/ 12, 2)
763 def taux_devise(self
):
764 if self
.devise
.code
== 'EUR':
766 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.dossier
.poste
.implantation
)
767 if len(liste_taux
) == 0:
768 raise DeviseException(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.dossier
.poste
.implantation
))
770 return liste_taux
[0].taux
772 def montant_euro(self
):
773 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
775 def montant_euro_mois(self
):
776 return round(self
.montant_euro() / 12, 2)
781 class Contrat(models
.Model
):
782 dossier
= models
.ForeignKey(Dossier
, related_name
='contrats')
783 type = models
.ForeignKey(rh
.TypeContrat
, related_name
='+')
784 fichier
= models
.FileField(upload_to
='dae/contrats', storage
=UPLOAD_STORAGE
)