1 # -=- encoding: utf-8 -=-
4 from django
.core
.files
.storage
import FileSystemStorage
5 from django
.db
import models
7 from workflow
import PosteWorkflow
8 import datamaster_modeles
.models
as ref
9 from rh_v1
import models
as rh
12 STATUT_RESIDENCE_CHOICES
= (
14 ('expat', 'Expatrié'),
17 POSTE_APPEL_CHOICES
= (
18 ('interne', 'Interne'),
19 ('externe', 'Externe'),
22 POSTE_STATUT_CHOICES
= (
23 ('MAD', 'Mise à disposition'),
24 ('DET', 'Détachement'),
28 storage_prive
= FileSystemStorage(settings
.PRIVE_MEDIA_ROOT
, base_url
=settings
.PRIVE_MEDIA_URL
)
30 def poste_piece_dispatch(instance
, filename
):
31 path
= "poste/%s/%s" % (instance
.poste_id
, filename
)
34 def dossier_piece_dispatch(instance
, filename
):
35 path
= "dossier/%s/%s" % (instance
.dossier_id
, filename
)
39 class PostePiece(models
.Model
):
40 poste
= models
.ForeignKey("Poste")
41 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
42 fichier
= models
.FileField(verbose_name
="Fichier", upload_to
=poste_piece_dispatch
, storage
=storage_prive
)
44 class PosteManager(models
.Manager
):
46 Chargement de tous les objets FK existants sur chaque QuerySet.
48 def get_query_set(self
):
60 return super(PosteManager
, self
).get_query_set() \
61 .select_related(*fkeys
).all()
64 class Poste(PosteWorkflow
, models
.Model
):
66 id_rh
= models
.ForeignKey(rh
.Poste
, null
=True, related_name
='+',
68 verbose_name
="Mise à jour du poste")
69 nom
= models
.CharField(verbose_name
="Titre du poste", max_length
=255)
70 implantation
= models
.ForeignKey(ref
.Implantation
)
71 type_poste
= models
.ForeignKey(rh
.TypePoste
, null
=True, related_name
='+')
72 service
= models
.ForeignKey(rh
.Service
, related_name
='+',
73 verbose_name
=u
"Direction/Service/Pôle support")
74 responsable
= models
.ForeignKey(rh
.Poste
, related_name
='+',
75 verbose_name
="Poste du responsable")
77 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
79 verbose_name
="Temps de travail",
80 help_text
="% du temps complet")
81 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
84 verbose_name
="Nb. heures par semaine")
87 local
= models
.BooleanField(verbose_name
="Local", default
=True, blank
=True)
88 expatrie
= models
.BooleanField(verbose_name
="Expatrié", default
=False, blank
=True)
91 mise_a_disposition
= models
.BooleanField(verbose_name
="Mise à disposition")
92 appel
= models
.CharField(max_length
=10, default
='interne',
93 verbose_name
="Appel à candidature",
94 choices
=POSTE_APPEL_CHOICES
)
97 classement_min
= models
.ForeignKey(rh
.Classement
, related_name
='+')
98 classement_max
= models
.ForeignKey(rh
.Classement
, related_name
='+')
99 coefficient_min
= models
.FloatField(null
=True) # pour classement "hors grille"
100 coefficient_max
= models
.FloatField(null
=True) # pour classement "hors grille"
101 valeur_point_min
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+', blank
=True, null
=True)
102 valeur_point_max
= models
.ForeignKey(rh
.ValeurPoint
, related_name
='+', blank
=True, null
=True)
103 devise_min
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
104 devise_max
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
105 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
107 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
109 indemn_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
111 indemn_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
113 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
115 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
118 # Comparatifs de rémunération
119 devise_comparaison
= models
.ForeignKey(rh
.Devise
, related_name
='+',
121 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
122 null
=True, blank
=True)
123 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
124 null
=True, blank
=True)
125 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
126 null
=True, blank
=True)
127 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
128 null
=True, blank
=True)
129 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
130 null
=True, blank
=True)
131 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
132 null
=True, blank
=True)
133 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
134 null
=True, blank
=True)
135 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
136 null
=True, blank
=True)
137 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
138 null
=True, blank
=True)
139 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
140 null
=True, blank
=True)
143 justification
= models
.TextField()
146 validation_bureau_regional
= models
.BooleanField(verbose_name
="Validation bureau régional")
147 validation_bureau_regional_date
= models
.DateField(blank
=True, null
=True)
148 validation_drh
= models
.BooleanField(verbose_name
="Validation DRH")
149 validation_drh_date
= models
.DateField(blank
=True, null
=True)
150 validation_secretaire_general
= models
.BooleanField(verbose_name
="Validation secrétaire général")
151 validation_secretaire_general_date
= models
.DateField(blank
=True, null
=True)
152 validation_recteur
= models
.BooleanField(verbose_name
="Validation recteur")
153 validation_recteur_date
= models
.DateField(blank
=True, null
=True)
156 date_creation
= models
.DateTimeField(auto_now_add
=True)
157 date_modification
= models
.DateTimeField(auto_now
=True)
158 date_debut
= models
.DateField(verbose_name
="Date de début",
159 help_text
="format: aaaa-mm-jj")
160 date_fin
= models
.DateField(null
=True, blank
=True,
161 verbose_name
="Date de fin",
162 help_text
="format: aaaa-mm-jj")
163 actif
= models
.BooleanField(default
=True)
166 objects
= PosteManager()
170 Les vues sont montées selon une clef spéciale pour identifier la provenance du poste.
171 Cette méthode fournit un moyen de reconstruire cette clef afin de générer les URLs.
173 return "dae-%s" % self
.id
174 key
= property(_get_key
)
176 def get_dossiers(self
):
178 Liste tous les anciens dossiers liés à ce poste.
179 (Le nom de la relation sur le rh.Poste est mal choisi poste1 au lieu de dossier1)
180 Note1 : seulement le dosssier principal fait l'objet de la recherche.
181 Note2 : les dossiers sont retournés du plus récent au plus vieux. (Ce test est fait
182 en fonction du id, car les dates de création sont absentes de rh v1).
184 if self
.id_rh
is None:
186 postes
= [p
for p
in self
.id_rh
.poste1
.all()]
187 return sorted(postes
, key
=lambda poste
: poste
.id, reverse
=True)
189 def get_complement_nom(self
):
191 Inspecte les modèles rh v1 pour trouver dans le dernier dossier un complément de titre de poste.
193 dossiers
= self
.get_dossiers()
194 if len(dossiers
) > 0:
195 nom
= dossiers
[0].complement1
200 def get_employe(self
):
202 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
204 dossiers
= self
.get_dossiers()
205 if len(dossiers
) > 0:
206 return dossiers
[0].employe
210 def get_default_devise(self
):
211 """Récupère la devise par défaut en fonction de l'implantation (EUR autrement)"""
213 implantation_devise
= rh
.TauxChange
.objects
.filter(implantation
=self
.implantation
)[0].devise
215 implantation_devise
= 5 # EUR
216 return implantation_devise
218 def __unicode__(self
):
220 Cette fonction est consommatrice SQL car elle cherche les dossiers qui ont été liés à celui-ci.
222 complement_nom_poste
= self
.get_complement_nom()
223 if complement_nom_poste
is None:
224 complement_nom_poste
= ""
225 employe
= self
.get_employe()
233 complement_nom_poste
,
236 return u
'%s - %s (%s) [dae-%s %s %s]' % data
239 # Tester l'enregistrement car les models.py sont importés au complet
240 if not reversion
.is_registered(Poste
):
241 reversion
.register(Poste
)
244 POSTE_FINANCEMENT_CHOICES
= (
245 ('A', 'A - Frais de personnel'),
246 ('B', 'B - Projet(s)-Titre(s)'),
251 class PosteFinancement(models
.Model
):
252 poste
= models
.ForeignKey('Poste', related_name
='financements')
253 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
254 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
255 help_text
="ex.: 33.33 % (décimale avec point)")
256 commentaire
= models
.TextField(
257 help_text
="Spécifiez la source de financement.")
268 class Employe(models
.Model
):
271 id_rh
= models
.ForeignKey(rh
.Employe
, null
=True, related_name
='+',
272 verbose_name
='Employé')
273 nom
= models
.CharField(max_length
=255)
274 prenom
= models
.CharField(max_length
=255, verbose_name
='Prénom')
275 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
,
276 null
=True, blank
=True)
278 def __unicode__(self
):
279 return u
'%s %s' % (self
.prenom
, self
.nom
)
282 COMPTE_COMPTA_CHOICES
= (
288 class DossierPiece(models
.Model
):
289 dossier
= models
.ForeignKey("Dossier")
290 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
291 fichier
= models
.FileField(verbose_name
="Fichier", upload_to
=dossier_piece_dispatch
, storage
=storage_prive
)
293 class Dossier(models
.Model
):
296 employe
= models
.ForeignKey('Employe', related_name
='+', editable
=False)
297 poste
= models
.ForeignKey('Poste', related_name
='+', editable
=False)
298 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+')
299 organisme_bstg
= models
.ForeignKey(rh
.OrganismeBstg
,
300 null
=True, blank
=True,
301 verbose_name
="Organisme",
302 help_text
="Si détaché (DET) ou mis à disposition (MAD), \
303 préciser l'organisme.",
305 organisme_bstg_autre
= models
.CharField(max_length
=255,
306 verbose_name
="Autre organisme",
307 help_text
="indiquer l'organisme ici s'il n'est pas dans la liste",
311 # Données antérieures de l'employé
312 statut_anterieur
= models
.ForeignKey(
313 rh
.Statut
, related_name
='+', null
=True, blank
=True,
314 verbose_name
='Statut antérieur')
315 classement_anterieur
= models
.ForeignKey(
316 rh
.Classement
, related_name
='+', null
=True, blank
=True,
317 verbose_name
='Classement précédent')
318 salaire_anterieur
= models
.DecimalField(
319 max_digits
=12, decimal_places
=2, null
=True, default
=None,
320 blank
=True, verbose_name
='Salaire précédent')
322 # Données du titulaire précédent
323 employe_anterieur
= models
.ForeignKey(
324 rh
.Employe
, related_name
='+', null
=True, blank
=True,
325 verbose_name
='Employé précédent')
326 statut_titulaire_anterieur
= models
.ForeignKey(
327 rh
.Statut
, related_name
='+', null
=True, blank
=True,
328 verbose_name
='Statut titulaire précédent')
329 classement_titulaire_anterieur
= models
.ForeignKey(
330 rh
.Classement
, related_name
='+', null
=True, blank
=True,
331 verbose_name
='Classement titulaire précédent')
332 salaire_titulaire_anterieur
= models
.DecimalField(
333 max_digits
=12, decimal_places
=2, default
=None, null
=True,
334 blank
=True, verbose_name
='Salaire titulaire précédent')
337 remplacement
= models
.BooleanField()
338 statut_residence
= models
.CharField(max_length
=10, default
='local',
339 verbose_name
="Statut",
340 choices
=STATUT_RESIDENCE_CHOICES
)
343 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
344 verbose_name
='Classement proposé')
345 salaire
= models
.DecimalField(max_digits
=12, decimal_places
=2,
346 verbose_name
='Salaire de base',
347 null
=True, default
=None)
348 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
349 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
350 verbose_name
="Régime de travail",
351 help_text
="% du temps complet")
352 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
353 decimal_places
=2, verbose_name
="Nb. heures par semaine")
356 type_contrat
= models
.ForeignKey(rh
.TypeContrat
, related_name
='+')
357 contrat_date_debut
= models
.DateField(help_text
="format: aaaa-mm-jj")
358 contrat_date_fin
= models
.DateField(null
=True, blank
=True,
359 help_text
="format: aaaa-mm-jj")
362 compte_compta
= models
.CharField(max_length
=10, default
='aucun',
363 verbose_name
=u
'Compte comptabilité',
364 choices
=COMPTE_COMPTA_CHOICES
)
365 compte_courriel
= models
.BooleanField()
368 date_creation
= models
.DateTimeField(auto_now_add
=True)
370 def __unicode__(self
):
371 return u
'%s - %s' % (self
.poste
.nom
, self
.employe
)
373 # Tester l'enregistrement car les models.py sont importés au complet
374 if not reversion
.is_registered(Dossier
):
375 reversion
.register(Dossier
)
377 class Remuneration(models
.Model
):
379 dossier
= models
.ForeignKey('Dossier', db_column
='dossier')
380 type = models
.ForeignKey(rh
.TypeRemuneration
, db_column
='type',
383 # type_revalorisation = models.ForeignKey('TypeRevalorisation',
384 # db_column='type_revalorisation')
385 montant
= models
.DecimalField(max_digits
=12, decimal_places
=2,
387 devise
= models
.ForeignKey(rh
.Devise
, to_field
='code',
388 db_column
='devise', related_name
='+')
389 precision
= models
.CharField(max_length
=255, null
=True, blank
=True)
390 # date_effective = models.DateField(null=True, blank=True)
391 # pourcentage = models.IntegerField(null=True, blank=True)
394 date_creation
= models
.DateField(auto_now_add
=True)
395 user_creation
= models
.IntegerField(null
=True, blank
=True)
396 # desactivation = models.BooleanField(default=False, blank=True)
397 # date_desactivation = models.DateField(null=True, blank=True)
398 # user_desactivation = models.IntegerField(null=True, blank=True)
399 # annulation = models.BooleanField(default=False, blank=True)
400 # date_annulation = models.DateField(null=True, blank=True)
401 # user_annulation = models.IntegerField(null=True, blank=True)
403 def montant_mois(self
):
404 return round(self
.montant
/ 12, 2)
406 def taux_devise(self
):
407 return self
.devise
.tauxchange_set
.order_by('-annee').all()[0].taux
409 def montant_euro(self
):
410 return round(float(self
.montant
) / float(self
.taux_devise()), 2)
412 def montant_euro_mois(self
):
413 return round(self
.montant_euro() / 12, 2)
416 TYPE_JUSTIFICATIONS
= (
417 ('N', 'Nouvel employé'),
418 ('R', 'Renouvellement employé'),
421 class JustificationQuestion(models
.Model
):
422 question
= models
.CharField(max_length
=255)
423 type = models
.CharField(max_length
=255, choices
=TYPE_JUSTIFICATIONS
)
425 def __unicode__(self
,):
428 class JustificationNouvelEmploye(models
.Model
):
429 dossier
= models
.ForeignKey("Dossier")
430 question
= models
.ForeignKey("JustificationQuestion")
431 reponse
= models
.TextField()
433 class JustificationAutreEmploye(models
.Model
):
434 dossier
= models
.ForeignKey("Dossier")
435 question
= models
.ForeignKey("JustificationQuestion")
436 reponse
= models
.TextField()
439 class Validation(models
.Model
):
441 date
= models
.DateField()
443 # avis = ? (CHOICES?)
446 class ValidationPoste(models
.Model
):
447 poste
= models
.ForeignKey('Poste')
450 class ValidationEmploye(models
.Model
):
451 employe
= models
.ForeignKey('Employe')