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"),
48 class Poste(PosteWorkflow
, models
.Model
):
50 type_intervention
= models
.CharField(max_length
=1, choices
=POSTE_ACTION
, default
='N')
53 id_rh
= models
.ForeignKey(rh
.Poste
, null
=True, related_name
='+',
55 verbose_name
="Mise à jour du poste")
56 nom
= models
.CharField(verbose_name
="Titre du poste", max_length
=255)
57 implantation
= models
.ForeignKey(ref
.Implantation
)
58 type_poste
= models
.ForeignKey(rh
.TypePoste
, null
=True, related_name
='+')
59 service
= models
.ForeignKey(rh
.Service
, related_name
='+',
60 verbose_name
=u
"Direction/Service/Pôle support")
61 responsable
= models
.ForeignKey(rh
.Poste
, related_name
='+',
62 verbose_name
="Poste du responsable")
65 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
66 default
=REGIME_TRAVAIL_DEFAULT
,
67 verbose_name
="Temps de travail",
68 help_text
="% du temps complet")
69 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
71 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
72 verbose_name
="Nb. heures par semaine")
75 local
= models
.BooleanField(verbose_name
="Local", default
=True, blank
=True)
76 expatrie
= models
.BooleanField(verbose_name
="Expatrié", default
=False,
78 mise_a_disposition
= models
.BooleanField(verbose_name
="Mise à disposition")
79 appel
= models
.CharField(max_length
=10, default
='interne',
80 verbose_name
="Appel à candidature",
81 choices
=POSTE_APPEL_CHOICES
)
84 classement_min
= models
.ForeignKey(rh
.Classement
, related_name
='+',
85 blank
=True, null
=True)
86 classement_max
= models
.ForeignKey(rh
.Classement
, related_name
='+',
87 blank
=True, null
=True)
88 valeur_point_min
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+',
89 blank
=True, null
=True)
90 valeur_point_max
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+',
91 blank
=True, null
=True)
92 devise_min
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
93 devise_max
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
94 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
96 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
97 indemn_expat_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
98 indemn_expat_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
99 indemn_fct_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
100 indemn_fct_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
101 charges_patronales_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
102 charges_patronales_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
103 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
104 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2, default
=0)
106 # Comparatifs de rémunération
107 devise_comparaison
= models
.ForeignKey(rh
.Devise
, related_name
='+',
109 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
110 null
=True, blank
=True)
111 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
112 null
=True, blank
=True)
113 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
114 null
=True, blank
=True)
115 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
116 null
=True, blank
=True)
117 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
118 null
=True, blank
=True)
119 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
120 null
=True, blank
=True)
121 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
122 null
=True, blank
=True)
123 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
124 null
=True, blank
=True)
125 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
126 null
=True, blank
=True)
127 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
128 null
=True, blank
=True)
131 justification
= models
.TextField()
134 date_creation
= models
.DateTimeField(auto_now_add
=True)
135 date_modification
= models
.DateTimeField(auto_now
=True)
136 date_debut
= models
.DateField(verbose_name
="Date de début",
137 help_text
=HELP_TEXT_DATE
)
138 date_fin
= models
.DateField(null
=True, blank
=True,
139 verbose_name
="Date de fin",
140 help_text
=HELP_TEXT_DATE
)
141 actif
= models
.BooleanField(default
=True)
144 objects
= PosteManager()
148 Les vues sont montées selon une clef spéciale
149 pour identifier la provenance du poste.
150 Cette méthode fournit un moyen de reconstruire cette clef
151 afin de générer les URLs.
153 return "dae-%s" % self
.id
154 key
= property(_get_key
)
156 def get_dossiers(self
):
158 Liste tous les anciens dossiers liés à ce poste.
159 (Le nom de la relation sur le rh.Poste est mal choisi
160 poste1 au lieu de dossier1)
161 Note1 : seulement le dosssier principal fait l'objet de la recherche.
162 Note2 : les dossiers sont retournés du plus récent au plus vieux.
163 (Ce test est fait en fonction du id,
164 car les dates de création sont absentes de rh v1).
166 if self
.id_rh
is None:
168 postes
= [p
for p
in self
.id_rh
.poste1
.all()]
169 return sorted(postes
, key
=lambda poste
: poste
.id, reverse
=True)
171 def get_complement_nom(self
):
173 Inspecte les modèles rh v1 pour trouver dans le dernier dossier
174 un complément de titre de poste.
176 dossiers
= self
.get_dossiers()
177 if len(dossiers
) > 0:
178 nom
= dossiers
[0].complement1
183 def get_employe(self
):
185 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
187 dossiers
= self
.get_dossiers()
188 if len(dossiers
) > 0:
189 return dossiers
[0].employe
193 def get_default_devise(self
):
194 """Récupère la devise par défaut en fonction de l'implantation
198 implantation_devise
= rh
.TauxChange
.objects \
199 .filter(implantation
=self
.implantation
)[0].devise
201 implantation_devise
= 5 # EUR
202 return implantation_devise
204 #####################
205 # Classement de poste
206 #####################
208 def get_couts_minimum(self
):
209 return (float)(self
.salaire_min
+ self
.indemn_expat_min
+ + self
.indemn_fct_min
+ self
.charges_patronales_min
+ self
.autre_min
)
211 def get_taux_minimum(self
):
212 taux_changes
= rh
.TauxChange
.objects
.filter(devise
=self
.devise_min
).order_by('annee')
213 for t
in taux_changes
:
214 if t
.implantation
== self
.implantation
:
216 if len(taux_changes
) > 0:
217 return taux_changes
[0].taux
219 raise Exception('Taux indisponible pour la devise %s (%s)' % (self
.devise_min
, self
.implantation
))
221 def get_couts_minimum_euros(self
):
222 return self
.get_couts_minimum() * self
.get_taux_minimum()
224 def get_couts_maximum(self
):
225 return (float)(self
.salaire_max
+ self
.indemn_expat_max
+ + self
.indemn_fct_max
+ self
.charges_patronales_max
+ self
.autre_max
)
227 def get_taux_maximum(self
):
228 taux_changes
= rh
.TauxChange
.objects
.filter(devise
=self
.devise_max
).order_by('annee')
229 for t
in taux_changes
:
230 if t
.implantation
== self
.implantation
:
232 if len(taux_changes
) > 0:
233 return taux_changes
[0].taux
235 raise Exception('Taux indisponible pour la devise %s (%s)' % (self
.devise_max
, self
.implantation
))
237 def get_couts_maximum_euros(self
):
238 return self
.get_couts_maximum() * self
.get_taux_maximum()
241 def show_taux_minimum(self
):
243 return self
.get_taux_minimum()
247 def show_couts_minimum_euros(self
):
249 return self
.get_couts_minimum_euros()
253 def show_taux_maximum(self
):
255 return self
.get_taux_maximum()
259 def show_couts_maximum_euros(self
):
261 return self
.get_couts_maximum_euros()
266 ######################
267 # Comparaison de poste
268 ######################
270 def est_comparable(self
):
272 Si on a au moins une valeur de saisie dans les comparaisons, alors le poste
275 if self
.comp_universite_min
is None and \
276 self
.comp_fonctionpub_min
is None and \
277 self
.comp_locale_min
is None and \
278 self
.comp_ong_min
is None and \
279 self
.comp_autre_min
is None and \
280 self
.comp_universite_max
is None and \
281 self
.comp_fonctionpub_max
is None and \
282 self
.comp_locale_max
is None and \
283 self
.comp_ong_max
is None and \
284 self
.comp_autre_max
is None:
290 def get_taux_comparaison(self
):
292 return rh
.TauxChange
.objects
.filter(implantation
=self
.implantation
, devise
=self
.devise_comparaison
)[0].taux
296 def get_comp_universite_min_euros(self
):
297 return (float)(self
.comp_universite_min
) * self
.get_taux_comparaison()
299 def get_comp_fonctionpub_min_euros(self
):
300 return (float)(self
.comp_fonctionpub_min
) * self
.get_taux_comparaison()
302 def get_comp_locale_min_euros(self
):
303 return (float)(self
.comp_locale_min
) * self
.get_taux_comparaison()
305 def get_comp_ong_min_euros(self
):
306 return (float)(self
.comp_ong_min
) * self
.get_taux_comparaison()
308 def get_comp_autre_min_euros(self
):
309 return (float)(self
.comp_autre_min
) * self
.get_taux_comparaison()
311 def get_comp_universite_max_euros(self
):
312 return (float)(self
.comp_universite_max
) * self
.get_taux_comparaison()
314 def get_comp_fonctionpub_max_euros(self
):
315 return (float)(self
.comp_fonctionpub_max
) * self
.get_taux_comparaison()
317 def get_comp_locale_max_euros(self
):
318 return (float)(self
.comp_locale_max
) * self
.get_taux_comparaison()
320 def get_comp_ong_max_euros(self
):
321 return (float)(self
.comp_ong_max
) * self
.get_taux_comparaison()
323 def get_comp_autre_max_euros(self
):
324 return (float)(self
.comp_autre_max
) * self
.get_taux_comparaison()
327 def __unicode__(self
):
329 Cette fonction est consommatrice SQL car elle cherche les dossiers
330 qui ont été liés à celui-ci.
332 complement_nom_poste
= self
.get_complement_nom()
333 if complement_nom_poste
is None:
334 complement_nom_poste
= ""
340 return u
'%s - %s (%s)' % data
343 # Tester l'enregistrement car les models.py sont importés au complet
344 if not reversion
.is_registered(Poste
):
345 reversion
.register(Poste
)
348 POSTE_FINANCEMENT_CHOICES
= (
349 ('A', 'A - Frais de personnel'),
350 ('B', 'B - Projet(s)-Titre(s)'),
354 class PosteFinancement(models
.Model
):
355 poste
= models
.ForeignKey('Poste', related_name
='financements')
356 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
357 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
358 help_text
="ex.: 33.33 % (décimale avec point)")
359 commentaire
= models
.TextField(
360 help_text
="Spécifiez la source de financement.")
365 def __unicode__(self
):
366 return u
"%s %s %s" % (self
.get_type_display(), self
.pourcentage
, self
.commentaire
)
369 class PostePiece(models
.Model
):
370 """Documents relatifs au Poste
371 Ex.: Description de poste
373 poste
= models
.ForeignKey("Poste")
374 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
375 fichier
= models
.FileField(verbose_name
="Fichier",
376 upload_to
=poste_piece_dispatch
,
377 storage
=storage_prive
)
379 class PosteComparaison(models
.Model
):
380 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
381 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True, related_name
="+")
382 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+', verbose_name
='Statut', null
=True, blank
=True, )
383 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+', verbose_name
='Classement', null
=True, blank
=True, )
384 nom
= models
.CharField(verbose_name
="Poste", max_length
=255, null
=True, blank
=True)
385 montant
= models
.IntegerField(null
=True)
386 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
388 def taux_devise(self
):
389 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.implantation
)
390 if len(liste_taux
) == 0:
391 raise Exception(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
393 return liste_taux
[0].taux
395 def montant_euros(self
):
396 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
401 # TODO : migration pour m -> M, f -> F
408 class Employe(models
.Model
):
411 id_rh
= models
.ForeignKey(rh
.Employe
, null
=True, related_name
='+',
412 verbose_name
='Employé')
413 nom
= models
.CharField(max_length
=255)
414 prenom
= models
.CharField(max_length
=255, verbose_name
='Prénom')
415 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
417 def __unicode__(self
):
418 return u
'%s %s' % (self
.prenom
, self
.nom
.upper())
423 STATUT_RESIDENCE_CHOICES
= (
425 ('expat', 'Expatrié'),
428 COMPTE_COMPTA_CHOICES
= (
434 class Dossier(DossierWorkflow
, models
.Model
):
437 employe
= models
.ForeignKey('Employe', related_name
='+', editable
=False)
438 poste
= models
.ForeignKey('Poste', related_name
='dossiers', editable
=False)
439 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+')
440 organisme_bstg
= models
.ForeignKey(rh
.OrganismeBstg
,
441 null
=True, blank
=True,
442 verbose_name
="Organisme",
443 help_text
="Si détaché (DET) ou mis à disposition (MAD), \
444 préciser l'organisme.",
446 organisme_bstg_autre
= models
.CharField(max_length
=255,
447 verbose_name
="Autre organisme",
448 help_text
="indiquer l'organisme ici s'il n'est pas dans la liste",
452 # Données antérieures de l'employé
453 statut_anterieur
= models
.ForeignKey(
454 rh
.Statut
, related_name
='+', null
=True, blank
=True,
455 verbose_name
='Statut antérieur')
456 classement_anterieur
= models
.ForeignKey(
457 rh
.Classement
, related_name
='+', null
=True, blank
=True,
458 verbose_name
='Classement précédent')
459 salaire_anterieur
= models
.DecimalField(
460 max_digits
=12, decimal_places
=2, null
=True, default
=None,
461 blank
=True, verbose_name
='Salaire précédent')
463 # Données du titulaire précédent
464 employe_anterieur
= models
.ForeignKey(
465 rh
.Employe
, related_name
='+', null
=True, blank
=True,
466 verbose_name
='Employé précédent')
467 statut_titulaire_anterieur
= models
.ForeignKey(
468 rh
.Statut
, related_name
='+', null
=True, blank
=True,
469 verbose_name
='Statut titulaire précédent')
470 classement_titulaire_anterieur
= models
.ForeignKey(
471 rh
.Classement
, related_name
='+', null
=True, blank
=True,
472 verbose_name
='Classement titulaire précédent')
473 salaire_titulaire_anterieur
= models
.DecimalField(
474 max_digits
=12, decimal_places
=2, default
=None, null
=True,
475 blank
=True, verbose_name
='Salaire titulaire précédent')
478 remplacement
= models
.BooleanField()
479 statut_residence
= models
.CharField(max_length
=10, default
='local',
480 verbose_name
="Statut",
481 choices
=STATUT_RESIDENCE_CHOICES
)
484 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
485 null
=True, blank
=True,
486 verbose_name
='Classement proposé')
487 salaire
= models
.DecimalField(max_digits
=12, decimal_places
=2,
488 verbose_name
='Salaire de base',
489 null
=True, default
=None)
490 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
491 regime_travail
= models
.DecimalField(max_digits
=12,
493 default
=REGIME_TRAVAIL_DEFAULT
,
494 verbose_name
="Régime de travail",
495 help_text
="% du temps complet")
496 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
498 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
499 verbose_name
="Nb. heures par semaine")
502 type_contrat
= models
.ForeignKey(rh
.TypeContrat
, related_name
='+')
503 contrat_date_debut
= models
.DateField(help_text
="format: aaaa-mm-jj")
504 contrat_date_fin
= models
.DateField(null
=True, blank
=True,
505 help_text
="format: aaaa-mm-jj")
508 justif_nouveau_statut_label
= u
'Justifier le statut que ce type de poste nécessite (national, expatrié, màd ou détachement)'
509 justif_nouveau_statut
= models
.TextField(verbose_name
=justif_nouveau_statut_label
, null
=True, blank
=True)
510 justif_nouveau_tmp_remplacement_label
= u
"Si l'employé effectue un remplacement temporaire, préciser"
511 justif_nouveau_tmp_remplacement
= models
.TextField(verbose_name
=justif_nouveau_tmp_remplacement_label
, null
=True, blank
=True)
512 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 "
513 justif_nouveau_salaire
= models
.TextField(verbose_name
=justif_nouveau_salaire_label
, null
=True, blank
=True)
514 justif_nouveau_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
515 justif_nouveau_commentaire
= models
.TextField(verbose_name
=justif_nouveau_commentaire_label
, null
=True, blank
=True)
516 justif_rempl_type_contrat_label
= u
"Changement de type de contrat, ex : d'un CDD en CDI"
517 justif_rempl_type_contrat
= models
.TextField(verbose_name
=justif_rempl_type_contrat_label
, null
=True, blank
=True)
518 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"
519 justif_rempl_statut_employe
= models
.TextField(verbose_name
=justif_rempl_statut_employe_label
, null
=True, blank
=True)
520 justif_rempl_evaluation_label
= u
"L'évaluation de l'employé est-elle favorable? Préciser"
521 justif_rempl_evaluation
= models
.TextField(verbose_name
=justif_rempl_evaluation_label
, null
=True, blank
=True)
522 justif_rempl_salaire_label
= u
"Si le salaire de l'employé est modifié et/ou ne correspond pas à son classement, justifier"
523 justif_rempl_salaire
= models
.TextField(verbose_name
=justif_rempl_salaire_label
, null
=True, blank
=True)
524 justif_rempl_commentaire_label
= u
"COMMENTAIRES ADDITIONNELS"
525 justif_rempl_commentaire
= models
.TextField(verbose_name
=justif_rempl_commentaire_label
, null
=True, blank
=True)
528 compte_compta
= models
.CharField(max_length
=10, default
='aucun',
529 verbose_name
=u
'Compte comptabilité',
530 choices
=COMPTE_COMPTA_CHOICES
)
531 compte_courriel
= models
.BooleanField()
534 date_creation
= models
.DateTimeField(auto_now_add
=True)
537 objects
= DossierManager()
539 def __unicode__(self
):
540 return u
'[%s] %s - %s' % (self
.poste
.implantation
, self
.poste
.nom
, self
.employe
)
542 def get_salaire_euros(self
):
544 tx
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.poste
.implantation
)[0].taux
547 return (float)(tx
) * (float)(self
.salaire
)
549 def get_remunerations_brutes(self
):
553 4 Indemnité d'expatriation
554 5 Indemnité pour frais
555 6 Indemnité de logement
556 7 Indemnité de fonction
557 8 Indemnité de responsabilité
558 9 Indemnité de transport
559 10 Indemnité compensatrice
560 11 Indemnité de subsistance
561 12 Indemnité différentielle
562 13 Prime d'installation
565 16 Indemnité de départ
566 18 Prime de 13ième mois
569 ids
= [1,3,4,5,6,7,8,9,10,11,12,13,14,15,16,18,19]
570 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
572 def get_charges_salariales(self
):
574 20 Charges salariales ?
577 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
579 def get_total_charges_salariales(self
):
581 for r
in self
.get_charges_salariales():
582 total
+= r
.montant_euro()
585 def get_charges_patronales(self
):
587 17 Charges patronales
590 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in ids
]
592 def get_total_charges_patronales(self
):
594 for r
in self
.get_charges_patronales():
595 total
+= r
.montant_euro()
598 def get_salaire_brut(self
):
600 somme des rémuérations brutes
603 for r
in self
.get_remunerations_brutes():
604 total
+= r
.montant_euro()
607 def get_salaire_net(self
):
609 salaire brut - charges salariales
612 for r
in self
.get_charges_salariales():
613 total_charges
+= r
.montant_euro()
614 return self
.get_salaire_brut() - total_charges
616 def get_couts_auf(self
):
618 salaire net + charges patronales
621 for r
in self
.get_charges_patronales():
622 total_charges
+= r
.montant_euro()
623 return self
.get_salaire_net() + total_charges
625 def get_remunerations_tierces(self
):
629 return [r
for r
in self
.remuneration_set
.all() if r
.type_id
in (2, )]
631 def get_total_remunerations_tierces(self
):
633 for r
in self
.get_remunerations_tierces():
634 total
+= r
.montant_euro()
638 # Tester l'enregistrement car les models.py sont importés au complet
639 if not reversion
.is_registered(Dossier
):
640 reversion
.register(Dossier
)
642 class DossierPiece(models
.Model
):
643 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
644 Ex.: Lettre de motivation.
646 dossier
= models
.ForeignKey("Dossier")
647 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
648 fichier
= models
.FileField(verbose_name
="Fichier",
649 upload_to
=dossier_piece_dispatch
,
650 storage
=storage_prive
)
653 class DossierComparaison(models
.Model
):
655 Photo d'une comparaison salariale au moment de l'embauche.
657 dossier
= models
.ForeignKey('Dossier', related_name
='comparaisons')
658 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+', verbose_name
='Statut', null
=True, blank
=True, )
659 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+', verbose_name
='Classement', null
=True, blank
=True, )
660 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True)
661 poste
= models
.CharField(max_length
=255, null
=True, blank
=True)
662 personne
= models
.CharField(max_length
=255, null
=True, blank
=True)
663 montant
= models
.IntegerField(null
=True)
664 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+', null
=True, blank
=True)
666 def taux_devise(self
):
667 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.dossier
.poste
.implantation
)
668 if len(liste_taux
) == 0:
669 raise Exception(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.dossier
.poste
.implantation
))
671 return liste_taux
[0].taux
673 def montant_euros(self
):
674 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
680 class Remuneration(models
.Model
):
682 dossier
= models
.ForeignKey('Dossier', db_column
='dossier')
683 type = models
.ForeignKey(rh
.TypeRemuneration
, db_column
='type',
685 montant
= models
.DecimalField(max_digits
=12, decimal_places
=2,
687 devise
= models
.ForeignKey(rh
.Devise
, to_field
='code',
688 db_column
='devise', related_name
='+')
689 precision
= models
.CharField(max_length
=255, null
=True, blank
=True)
692 date_creation
= models
.DateField(auto_now_add
=True)
693 user_creation
= models
.IntegerField(null
=True, blank
=True) # TODO : user
695 def montant_mois(self
):
696 return round(self
.montant
/ 12, 2)
698 def taux_devise(self
):
699 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee').filter(implantation
=self
.dossier
.poste
.implantation
)
700 if len(liste_taux
) == 0:
701 raise Exception(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.dossier
.poste
.implantation
))
703 return liste_taux
[0].taux
705 def montant_euro(self
):
706 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
708 def montant_euro_mois(self
):
709 return round(self
.montant_euro() / 12, 2)