fix pj pour nx poste
[auf_rh_dae.git] / project / dae / models.py
CommitLineData
bd28238f 1# -=- encoding: utf-8 -=-
3f3cf5f3 2
36341125
OL
3import os
4from django.core.files.storage import FileSystemStorage
a9c281dd
OL
5from django.db import models
6import reversion
bd28238f 7import datamaster_modeles.models as ref
a9c281dd 8from rh_v1 import models as rh
36341125 9import settings
bd28238f
NC
10
11STATUT_RESIDENCE_CHOICES = (
5d680e84
NC
12 ('local', 'Local'),
13 ('expat', 'Expatrié'),
bd28238f
NC
14)
15
16POSTE_APPEL_CHOICES = (
5d680e84
NC
17 ('interne', 'Interne'),
18 ('externe', 'Externe'),
bd28238f
NC
19)
20
21POSTE_STATUT_CHOICES = (
22 ('MAD', 'Mise à disposition'),
23 ('DET', 'Détachement'),
24)
25
d766bf2c 26# Upload de fichiers
36341125
OL
27storage_prive = FileSystemStorage(settings.PRIVE_MEDIA_ROOT, base_url=settings.PRIVE_MEDIA_URL)
28
29def poste_piece_dispatch(instance, filename):
30 path = "poste/%s/%s" % (instance.poste.id, filename)
31 return path
32
d766bf2c
OL
33def dossier_piece_dispatch(instance, filename):
34 path = "dossier/%s/%s" % (instance.dossier.id, filename)
35 return path
36
36341125
OL
37
38class PostePiece(models.Model):
39 poste = models.ForeignKey("Poste")
40 nom = models.CharField(verbose_name="Nom", max_length=255)
41 fichier = models.FileField(verbose_name="Fichier", upload_to=poste_piece_dispatch, storage=storage_prive)
42
1c7d67ce
OL
43class PosteManager(models.Manager):
44 """
45 Chargement de tous les objets FK existants sur chaque QuerySet.
46 """
47 def get_query_set(self):
48 fkeys = (
49 'id_rh',
50 'responsable',
51 'implantation',
52 'type_poste',
53 'service',
54 'classement_min',
55 'classement_max',
56 'valeur_point_min',
57 'valeur_point_max',
58 )
98d51b59
NC
59 return super(PosteManager, self).get_query_set() \
60 .select_related(*fkeys).all()
1c7d67ce
OL
61
62
bd28238f 63class Poste(models.Model):
bd28238f 64 # Modèle existant
5d680e84 65 id_rh = models.ForeignKey(rh.Poste, null=True, related_name='+',
98d51b59
NC
66 editable=False,
67 verbose_name="Mise à jour du poste")
ce110fb9 68 nom = models.CharField(verbose_name="Titre du poste", max_length=255)
5d680e84
NC
69 implantation = models.ForeignKey(ref.Implantation)
70 type_poste = models.ForeignKey(rh.TypePoste, null=True, related_name='+')
98d51b59
NC
71 service = models.ForeignKey(rh.Service, related_name='+',
72 verbose_name=u"Direction/Service/Pôle support")
73 responsable = models.ForeignKey(rh.Poste, related_name='+',
5efcd48e 74 verbose_name="Poste du responsable")
9a85768a 75
5d680e84 76 regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
5efcd48e 77 default=100,
78 verbose_name="Temps de travail",
79 help_text="% du temps complet")
5d680e84 80 regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
5efcd48e 81 decimal_places=2,
82 default=40,
83 verbose_name="Nb. heures par semaine")
bd28238f
NC
84
85 # Recrutement
4d25e2ba 86 statut_residence = models.CharField(max_length=10, default='local',
5efcd48e 87 verbose_name="Statut",
bd28238f 88 choices=STATUT_RESIDENCE_CHOICES)
5d680e84 89 # TODO null?
a3508c67 90 mise_a_disposition = models.BooleanField(verbose_name="Mise à disposition")
98d51b59
NC
91 appel = models.CharField(max_length=10, default='interne',
92 verbose_name="Appel à candidature",
5d680e84 93 choices=POSTE_APPEL_CHOICES)
bd28238f
NC
94
95 # Rémunération
5d680e84
NC
96 classement_min = models.ForeignKey(rh.Classement, related_name='+')
97 classement_max = models.ForeignKey(rh.Classement, related_name='+')
96d32304 98 coefficient_min = models.FloatField(null=True) # pour classement "hors grille"
99 coefficient_max = models.FloatField(null=True) # pour classement "hors grille"
4dd75e7b
OL
100 valeur_point_min = models.ForeignKey(rh.ValeurPoint, related_name='+', blank=True, null=True)
101 valeur_point_max = models.ForeignKey(rh.ValeurPoint, related_name='+', blank=True, null=True)
3d627bfd 102 devise_min = models.ForeignKey(rh.Devise, default=5, related_name='+')
103 devise_max = models.ForeignKey(rh.Devise, default=5, related_name='+')
5d680e84
NC
104 salaire_min = models.DecimalField(max_digits=12, decimal_places=2,
105 default=0)
106 salaire_max = models.DecimalField(max_digits=12, decimal_places=2,
107 default=0)
108 indemn_min = models.DecimalField(max_digits=12, decimal_places=2,
109 default=0)
110 indemn_max = models.DecimalField(max_digits=12, decimal_places=2,
111 default=0)
112 autre_min = models.DecimalField(max_digits=12, decimal_places=2,
113 default=0)
114 autre_max = models.DecimalField(max_digits=12, decimal_places=2,
115 default=0)
116
117 # Comparatifs de rémunération
118 devise_comparaison = models.ForeignKey(rh.Devise, related_name='+',
a3508c67 119 default=5)
5d680e84
NC
120 comp_locale_min = models.DecimalField(max_digits=12, decimal_places=2,
121 null=True, blank=True)
122 comp_locale_max = models.DecimalField(max_digits=12, decimal_places=2,
123 null=True, blank=True)
124 comp_universite_min = models.DecimalField(max_digits=12, decimal_places=2,
125 null=True, blank=True)
126 comp_universite_max = models.DecimalField(max_digits=12, decimal_places=2,
127 null=True, blank=True)
128 comp_fonctionpub_min = models.DecimalField(max_digits=12, decimal_places=2,
129 null=True, blank=True)
130 comp_fonctionpub_max = models.DecimalField(max_digits=12, decimal_places=2,
131 null=True, blank=True)
132 comp_ong_min = models.DecimalField(max_digits=12, decimal_places=2,
133 null=True, blank=True)
134 comp_ong_max = models.DecimalField(max_digits=12, decimal_places=2,
135 null=True, blank=True)
136 comp_autre_min = models.DecimalField(max_digits=12, decimal_places=2,
137 null=True, blank=True)
138 comp_autre_max = models.DecimalField(max_digits=12, decimal_places=2,
139 null=True, blank=True)
bd28238f 140
a05cc82d
OL
141 # Validations
142 validation_bureau_regional = models.BooleanField(verbose_name="Validation bureau régional")
143 validation_bureau_regional_date = models.DateField(blank=True, null=True)
144 validation_drh = models.BooleanField(verbose_name="Validation DRH")
145 validation_drh_date = models.DateField(blank=True, null=True)
146 validation_secretaire_general = models.BooleanField(verbose_name="Validation secrétaire général")
147 validation_secretaire_general_date = models.DateField(blank=True, null=True)
148 validation_recteur = models.BooleanField(verbose_name="Validation recteur")
149 validation_recteur_date = models.DateField(blank=True, null=True)
150
bd28238f 151 # Méta
5d680e84
NC
152 date_creation = models.DateTimeField(auto_now_add=True)
153 date_modification = models.DateTimeField(auto_now=True)
98d51b59 154 date_debut = models.DateField(verbose_name="Date de début",
9fb2ccd9 155 help_text="format: aaaa-mm-jj")
156 date_fin = models.DateField(null=True, blank=True,
157 verbose_name="Date de fin",
158 help_text="format: aaaa-mm-jj")
bd28238f
NC
159 actif = models.BooleanField(default=True)
160
1c7d67ce
OL
161 # Managers
162 objects = PosteManager()
163
03858ba5
OL
164 def _get_key(self):
165 """
166 Les vues sont montées selon une clef spéciale pour identifier la provenance du poste.
167 Cette méthode fournit un moyen de reconstruire cette clef afin de générer les URLs.
168 """
169 return "dae-%s" % self.id
170 key = property(_get_key)
171
f3333b0e
OL
172 def get_dossiers(self):
173 """
174 Liste tous les anciens dossiers liés à ce poste.
175 (Le nom de la relation sur le rh.Poste est mal choisi poste1 au lieu de dossier1)
176 Note1 : seulement le dosssier principal fait l'objet de la recherche.
177 Note2 : les dossiers sont retournés du plus récent au plus vieux. (Ce test est fait
178 en fonction du id, car les dates de création sont absentes de rh v1).
179 """
180 if self.id_rh is None:
181 return []
182 postes = [p for p in self.id_rh.poste1.all()]
183 return sorted(postes, key=lambda poste: poste.id, reverse=True)
184
185 def get_complement_nom(self):
186 """
187 Inspecte les modèles rh v1 pour trouver dans le dernier dossier un complément de titre de poste.
188 """
189 dossiers = self.get_dossiers()
190 if len(dossiers) > 0:
191 nom = dossiers[0].complement1
192 else:
193 nom = ""
a9c281dd 194 return nom
f3333b0e
OL
195
196 def get_employe(self):
197 """
198 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
199 """
200 dossiers = self.get_dossiers()
201 if len(dossiers) > 0:
202 return dossiers[0].employe
203 else:
204 return None
205
5d680e84 206 def __unicode__(self):
f3333b0e
OL
207 """
208 Cette fonction est consommatrice SQL car elle cherche les dossiers qui ont été liés à celui-ci.
209 """
210 complement_nom_poste = self.get_complement_nom()
c7a4aa2b
OL
211 if complement_nom_poste is None:
212 complement_nom_poste = ""
f3333b0e 213 employe = self.get_employe()
c7a4aa2b
OL
214 if employe is None:
215 employe = "VACANT"
f3333b0e
OL
216 data = (
217 self.implantation,
218 self.type_poste.nom,
219 self.nom,
220 self.id,
221 complement_nom_poste,
222 employe,
223 )
224 return u'%s - %s (%s) [dae-%s %s %s]' % data
5d680e84 225
bd28238f 226
a9c281dd
OL
227# Tester l'enregistrement car les models.py sont importés au complet
228if not reversion.is_registered(Poste):
229 reversion.register(Poste)
230
bd28238f 231
5d680e84
NC
232POSTE_FINANCEMENT_CHOICES = (
233 ('A', 'A - Frais de personnel'),
234 ('B', 'B - Projet(s)-Titre(s)'),
235 ('C', 'C - Autre')
236)
bd28238f
NC
237
238
5d680e84 239class PosteFinancement(models.Model):
43d04712 240 montant = models.DecimalField(max_digits=12, decimal_places=2,
241 help_text="ex.: 12000.00 € (décimale avec point, devise = EUR)")
5d680e84
NC
242 poste = models.ForeignKey('Poste', related_name='financements')
243 type = models.CharField(max_length=1, choices=POSTE_FINANCEMENT_CHOICES)
43d04712 244 pourcentage = models.DecimalField(max_digits=12, decimal_places=2,
245 help_text="ex.: 33.33 % (décimale avec point)")
246 commentaire = models.TextField(
247 help_text="Spécifiez la source de financement.")
bd28238f 248
43d04712 249 class Meta:
250 ordering = ['type']
bd28238f
NC
251
252GENRE_CHOICES = (
139686f2
NC
253 ('m', 'Homme'),
254 ('f', 'Femme'),
bd28238f
NC
255)
256
257
258class Employe(models.Model):
bd28238f
NC
259
260 # Modèle existant
da3ca955 261 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+',
262 verbose_name='Employé')
bd28238f 263 nom = models.CharField(max_length=255)
da3ca955 264 prenom = models.CharField(max_length=255, verbose_name='Prénom')
494ff2be
NC
265 genre = models.CharField(max_length=1, choices=GENRE_CHOICES,
266 null=True, blank=True)
bd28238f 267
139686f2
NC
268 def __unicode__(self):
269 return u'%s %s' % (self.prenom, self.nom)
270
bd28238f
NC
271
272COMPTE_COMPTA_CHOICES = (
494ff2be
NC
273 ('coda', 'CODA'),
274 ('scs', 'SCS'),
275 ('aucun', 'Aucun'),
bd28238f
NC
276)
277
d766bf2c
OL
278class DossierPiece(models.Model):
279 dossier = models.ForeignKey("Dossier")
280 nom = models.CharField(verbose_name="Nom", max_length=255)
281 fichier = models.FileField(verbose_name="Fichier", upload_to=dossier_piece_dispatch, storage=storage_prive)
bd28238f
NC
282
283class Dossier(models.Model):
bd28238f
NC
284
285 # Modèle existant
139686f2
NC
286 employe = models.ForeignKey('Employe', related_name='+', editable=False)
287 poste = models.ForeignKey('Poste', related_name='+', editable=False)
5d680e84 288 statut = models.ForeignKey(rh.Statut, related_name='+')
dfc2c344 289 organisme_bstg = models.ForeignKey(rh.OrganismeBstg,
290 verbose_name="Organisme",
291 help_text="Si détaché (DET) ou mis à disposition (MAD), \
292 préciser l'organisme.",
293 related_name='+')
bd28238f 294
139686f2
NC
295 # Données antérieures de l'employé
296 statut_anterieur = models.ForeignKey(
297 rh.Statut, related_name='+', null=True, blank=True,
da3ca955 298 verbose_name='Statut antérieur')
299 #type contrat
139686f2
NC
300 classement_anterieur = models.ForeignKey(
301 rh.Classement, related_name='+', null=True, blank=True,
302 verbose_name='Classement précédent')
303 salaire_anterieur = models.DecimalField(
304 max_digits=12, decimal_places=2, null=True, default=None,
305 blank=True, verbose_name='Salaire précédent')
306
307 # Données du titulaire précédent
308 employe_anterieur = models.ForeignKey(
309 rh.Employe, related_name='+', null=True, blank=True,
310 verbose_name='Employé précédent')
311 statut_titulaire_anterieur = models.ForeignKey(
312 rh.Statut, related_name='+', null=True, blank=True,
313 verbose_name='Statut titulaire précédent')
314 classement_titulaire_anterieur = models.ForeignKey(
315 rh.Classement, related_name='+', null=True, blank=True,
316 verbose_name='Classement titulaire précédent')
317 salaire_titulaire_anterieur = models.DecimalField(
318 max_digits=12, decimal_places=2, default=None, null=True,
319 blank=True, verbose_name='Salaire titulaire précédent')
494ff2be 320
bd28238f
NC
321 # Recrutement
322 remplacement = models.BooleanField()
4d25e2ba 323 statut_residence = models.CharField(max_length=10, default='local',
324 verbose_name="Statut",
bd28238f
NC
325 choices=STATUT_RESIDENCE_CHOICES)
326
327 # Rémunération
494ff2be
NC
328 classement = models.ForeignKey(rh.Classement, related_name='+',
329 verbose_name='Classement proposé')
330 salaire = models.DecimalField(max_digits=12, decimal_places=2,
bd28238f 331 verbose_name='Salaire de base',
494ff2be 332 null=True, default=None)
e8e75458 333 devise = models.ForeignKey(rh.Devise, default=5, related_name='+')
7ad7408e 334 regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
4d25e2ba 335 verbose_name="Régime de travail",
336 help_text="% du temps complet")
139686f2 337 regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
4d25e2ba 338 decimal_places=2, verbose_name="Nb. heures par semaine")
bd28238f
NC
339
340 # Contrat
5d680e84 341 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
4d25e2ba 342 contrat_date_debut = models.DateField(help_text="format: aaaa-mm-jj")
343 contrat_date_fin = models.DateField(help_text="format: aaaa-mm-jj")
bd28238f
NC
344
345 # Comptes
dfc2c344 346 compte_compta = models.CharField(max_length=10, default='aucun',
347 verbose_name=u'Compte comptabilité',
348 choices=COMPTE_COMPTA_CHOICES)
bd28238f 349 compte_courriel = models.BooleanField()
0140cbd2 350
351 # Méta
352 date_creation = models.DateTimeField(auto_now_add=True)
bd28238f 353
0140cbd2 354# Tester l'enregistrement car les models.py sont importés au complet
355if not reversion.is_registered(Dossier):
356 reversion.register(Dossier)
bd28238f
NC
357
358class Remuneration(models.Model):
5d680e84 359 # Identification
bd28238f 360 dossier = models.ForeignKey('Dossier', db_column='dossier')
cb1d62b5
NC
361 type = models.ForeignKey(rh.TypeRemuneration, db_column='type',
362 related_name='+')
5d680e84
NC
363 # TODO: what's that?
364 # type_revalorisation = models.ForeignKey('TypeRevalorisation',
365 # db_column='type_revalorisation')
cb1d62b5
NC
366 montant = models.DecimalField(max_digits=12, decimal_places=2,
367 null=True) # Annuel
494ff2be 368 devise = models.ForeignKey(rh.Devise, to_field='code',
5d680e84 369 db_column='devise', related_name='+')
cb1d62b5
NC
370 precision = models.CharField(max_length=255, null=True, blank=True)
371 # date_effective = models.DateField(null=True, blank=True)
372 # pourcentage = models.IntegerField(null=True, blank=True)
bd28238f 373
5d680e84 374 # Méta
bd28238f 375 date_creation = models.DateField(auto_now_add=True)
494ff2be 376 user_creation = models.IntegerField(null=True, blank=True)
cb1d62b5
NC
377 # desactivation = models.BooleanField(default=False, blank=True)
378 # date_desactivation = models.DateField(null=True, blank=True)
379 # user_desactivation = models.IntegerField(null=True, blank=True)
380 # annulation = models.BooleanField(default=False, blank=True)
381 # date_annulation = models.DateField(null=True, blank=True)
382 # user_annulation = models.IntegerField(null=True, blank=True)
bd28238f 383
ee91bc95
NC
384 def montant_mois(self):
385 return round(self.montant / 12, 2)
386
387 def taux_devise(self):
388 return self.devise.tauxchange_set.order_by('-annee').all()[0].taux
389
390 def montant_euro(self):
391 return round(float(self.montant) / float(self.taux_devise()), 2)
392
393 def montant_euro_mois(self):
394 return round(self.montant_euro() / 12, 2)
bd28238f
NC
395
396
397class JustificationPoste(models.Model):
398 pass
399
400
401class JustificationEmploye(models.Model):
402 pass
403
404
405class DocumentPoste(models.Model):
406 pass
407
408
409class DocumentEmploye(models.Model):
410 pass
411
412
413class Validation(models.Model):
414 # user
415 date = models.DateField()
416
417 # avis = ? (CHOICES?)
418
419
420class ValidationPoste(models.Model):
421 poste = models.ForeignKey('Poste')
422
423
424class ValidationEmploye(models.Model):
425 employe = models.ForeignKey('Employe')