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 statut_residence
= models
.CharField(max_length
=10, default
='local',
88 verbose_name
="Statut",
89 choices
=STATUT_RESIDENCE_CHOICES
)
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 validation_bureau_regional
= models
.BooleanField(verbose_name
="Validation bureau régional")
144 validation_bureau_regional_date
= models
.DateField(blank
=True, null
=True)
145 validation_drh
= models
.BooleanField(verbose_name
="Validation DRH")
146 validation_drh_date
= models
.DateField(blank
=True, null
=True)
147 validation_secretaire_general
= models
.BooleanField(verbose_name
="Validation secrétaire général")
148 validation_secretaire_general_date
= models
.DateField(blank
=True, null
=True)
149 validation_recteur
= models
.BooleanField(verbose_name
="Validation recteur")
150 validation_recteur_date
= models
.DateField(blank
=True, null
=True)
153 date_creation
= models
.DateTimeField(auto_now_add
=True)
154 date_modification
= models
.DateTimeField(auto_now
=True)
155 date_debut
= models
.DateField(verbose_name
="Date de début",
156 help_text
="format: aaaa-mm-jj")
157 date_fin
= models
.DateField(null
=True, blank
=True,
158 verbose_name
="Date de fin",
159 help_text
="format: aaaa-mm-jj")
160 actif
= models
.BooleanField(default
=True)
163 objects
= PosteManager()
167 Les vues sont montées selon une clef spéciale pour identifier la provenance du poste.
168 Cette méthode fournit un moyen de reconstruire cette clef afin de générer les URLs.
170 return "dae-%s" % self
.id
171 key
= property(_get_key
)
173 def get_dossiers(self
):
175 Liste tous les anciens dossiers liés à ce poste.
176 (Le nom de la relation sur le rh.Poste est mal choisi poste1 au lieu de dossier1)
177 Note1 : seulement le dosssier principal fait l'objet de la recherche.
178 Note2 : les dossiers sont retournés du plus récent au plus vieux. (Ce test est fait
179 en fonction du id, car les dates de création sont absentes de rh v1).
181 if self
.id_rh
is None:
183 postes
= [p
for p
in self
.id_rh
.poste1
.all()]
184 return sorted(postes
, key
=lambda poste
: poste
.id, reverse
=True)
186 def get_complement_nom(self
):
188 Inspecte les modèles rh v1 pour trouver dans le dernier dossier un complément de titre de poste.
190 dossiers
= self
.get_dossiers()
191 if len(dossiers
) > 0:
192 nom
= dossiers
[0].complement1
197 def get_employe(self
):
199 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
201 dossiers
= self
.get_dossiers()
202 if len(dossiers
) > 0:
203 return dossiers
[0].employe
207 def __unicode__(self
):
209 Cette fonction est consommatrice SQL car elle cherche les dossiers qui ont été liés à celui-ci.
211 complement_nom_poste
= self
.get_complement_nom()
212 if complement_nom_poste
is None:
213 complement_nom_poste
= ""
214 employe
= self
.get_employe()
222 complement_nom_poste
,
225 return u
'%s - %s (%s) [dae-%s %s %s]' % data
228 # Tester l'enregistrement car les models.py sont importés au complet
229 if not reversion
.is_registered(Poste
):
230 reversion
.register(Poste
)
233 POSTE_FINANCEMENT_CHOICES
= (
234 ('A', 'A - Frais de personnel'),
235 ('B', 'B - Projet(s)-Titre(s)'),
240 class PosteFinancement(models
.Model
):
241 montant
= models
.DecimalField(max_digits
=12, decimal_places
=2,
242 help_text
="ex.: 12000.00 € (décimale avec point, devise = EUR)")
243 poste
= models
.ForeignKey('Poste', related_name
='financements')
244 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
245 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
246 help_text
="ex.: 33.33 % (décimale avec point)")
247 commentaire
= models
.TextField(
248 help_text
="Spécifiez la source de financement.")
259 class Employe(models
.Model
):
262 id_rh
= models
.ForeignKey(rh
.Employe
, null
=True, related_name
='+',
263 verbose_name
='Employé')
264 nom
= models
.CharField(max_length
=255)
265 prenom
= models
.CharField(max_length
=255, verbose_name
='Prénom')
266 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
,
267 null
=True, blank
=True)
269 def __unicode__(self
):
270 return u
'%s %s' % (self
.prenom
, self
.nom
)
273 COMPTE_COMPTA_CHOICES
= (
279 class DossierPiece(models
.Model
):
280 dossier
= models
.ForeignKey("Dossier")
281 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
282 fichier
= models
.FileField(verbose_name
="Fichier", upload_to
=dossier_piece_dispatch
, storage
=storage_prive
)
284 class Dossier(models
.Model
):
287 employe
= models
.ForeignKey('Employe', related_name
='+', editable
=False)
288 poste
= models
.ForeignKey('Poste', related_name
='+', editable
=False)
289 statut
= models
.ForeignKey(rh
.Statut
, related_name
='+')
290 organisme_bstg
= models
.ForeignKey(rh
.OrganismeBstg
,
291 null
=True, blank
=True,
292 verbose_name
="Organisme",
293 help_text
="Si détaché (DET) ou mis à disposition (MAD), \
294 préciser l'organisme.",
297 # Données antérieures de l'employé
298 statut_anterieur
= models
.ForeignKey(
299 rh
.Statut
, related_name
='+', null
=True, blank
=True,
300 verbose_name
='Statut antérieur')
302 classement_anterieur
= models
.ForeignKey(
303 rh
.Classement
, related_name
='+', null
=True, blank
=True,
304 verbose_name
='Classement précédent')
305 salaire_anterieur
= models
.DecimalField(
306 max_digits
=12, decimal_places
=2, null
=True, default
=None,
307 blank
=True, verbose_name
='Salaire précédent')
309 # Données du titulaire précédent
310 employe_anterieur
= models
.ForeignKey(
311 rh
.Employe
, related_name
='+', null
=True, blank
=True,
312 verbose_name
='Employé précédent')
313 statut_titulaire_anterieur
= models
.ForeignKey(
314 rh
.Statut
, related_name
='+', null
=True, blank
=True,
315 verbose_name
='Statut titulaire précédent')
316 classement_titulaire_anterieur
= models
.ForeignKey(
317 rh
.Classement
, related_name
='+', null
=True, blank
=True,
318 verbose_name
='Classement titulaire précédent')
319 salaire_titulaire_anterieur
= models
.DecimalField(
320 max_digits
=12, decimal_places
=2, default
=None, null
=True,
321 blank
=True, verbose_name
='Salaire titulaire précédent')
324 remplacement
= models
.BooleanField()
325 statut_residence
= models
.CharField(max_length
=10, default
='local',
326 verbose_name
="Statut",
327 choices
=STATUT_RESIDENCE_CHOICES
)
330 classement
= models
.ForeignKey(rh
.Classement
, related_name
='+',
331 verbose_name
='Classement proposé')
332 salaire
= models
.DecimalField(max_digits
=12, decimal_places
=2,
333 verbose_name
='Salaire de base',
334 null
=True, default
=None)
335 devise
= models
.ForeignKey(rh
.Devise
, default
=5, related_name
='+')
336 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
337 verbose_name
="Régime de travail",
338 help_text
="% du temps complet")
339 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
340 decimal_places
=2, verbose_name
="Nb. heures par semaine")
343 type_contrat
= models
.ForeignKey(rh
.TypeContrat
, related_name
='+')
344 contrat_date_debut
= models
.DateField(help_text
="format: aaaa-mm-jj")
345 contrat_date_fin
= models
.DateField(null
=True, blank
=True,
346 help_text
="format: aaaa-mm-jj")
349 compte_compta
= models
.CharField(max_length
=10, default
='aucun',
350 verbose_name
=u
'Compte comptabilité',
351 choices
=COMPTE_COMPTA_CHOICES
)
352 compte_courriel
= models
.BooleanField()
355 date_creation
= models
.DateTimeField(auto_now_add
=True)
357 def __unicode__(self
):
358 return u
'%s - %s' % (self
.poste
.nom
, self
.employe
)
360 # Tester l'enregistrement car les models.py sont importés au complet
361 if not reversion
.is_registered(Dossier
):
362 reversion
.register(Dossier
)
364 class Remuneration(models
.Model
):
366 dossier
= models
.ForeignKey('Dossier', db_column
='dossier')
367 type = models
.ForeignKey(rh
.TypeRemuneration
, db_column
='type',
370 # type_revalorisation = models.ForeignKey('TypeRevalorisation',
371 # db_column='type_revalorisation')
372 montant
= models
.DecimalField(max_digits
=12, decimal_places
=2,
374 devise
= models
.ForeignKey(rh
.Devise
, to_field
='code',
375 db_column
='devise', related_name
='+')
376 precision
= models
.CharField(max_length
=255, null
=True, blank
=True)
377 # date_effective = models.DateField(null=True, blank=True)
378 # pourcentage = models.IntegerField(null=True, blank=True)
381 date_creation
= models
.DateField(auto_now_add
=True)
382 user_creation
= models
.IntegerField(null
=True, blank
=True)
383 # desactivation = models.BooleanField(default=False, blank=True)
384 # date_desactivation = models.DateField(null=True, blank=True)
385 # user_desactivation = models.IntegerField(null=True, blank=True)
386 # annulation = models.BooleanField(default=False, blank=True)
387 # date_annulation = models.DateField(null=True, blank=True)
388 # user_annulation = models.IntegerField(null=True, blank=True)
390 def montant_mois(self
):
391 return round(self
.montant
/ 12, 2)
393 def taux_devise(self
):
394 return self
.devise
.tauxchange_set
.order_by('-annee').all()[0].taux
396 def montant_euro(self
):
397 return round(float(self
.montant
) / float(self
.taux_devise()), 2)
399 def montant_euro_mois(self
):
400 return round(self
.montant_euro() / 12, 2)
403 class JustificationPoste(models
.Model
):
407 class JustificationEmploye(models
.Model
):
411 class DocumentPoste(models
.Model
):
415 class DocumentEmploye(models
.Model
):
419 class Validation(models
.Model
):
421 date
= models
.DateField()
423 # avis = ? (CHOICES?)
426 class ValidationPoste(models
.Model
):
427 poste
= models
.ForeignKey('Poste')
430 class ValidationEmploye(models
.Model
):
431 employe
= models
.ForeignKey('Employe')