dae migration default statut_residence
[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
NC
140
141 # Méta
5d680e84
NC
142 date_creation = models.DateTimeField(auto_now_add=True)
143 date_modification = models.DateTimeField(auto_now=True)
98d51b59 144 date_debut = models.DateField(verbose_name="Date de début",
9fb2ccd9 145 help_text="format: aaaa-mm-jj")
146 date_fin = models.DateField(null=True, blank=True,
147 verbose_name="Date de fin",
148 help_text="format: aaaa-mm-jj")
bd28238f
NC
149 actif = models.BooleanField(default=True)
150
1c7d67ce
OL
151 # Managers
152 objects = PosteManager()
153
03858ba5
OL
154 def _get_key(self):
155 """
156 Les vues sont montées selon une clef spéciale pour identifier la provenance du poste.
157 Cette méthode fournit un moyen de reconstruire cette clef afin de générer les URLs.
158 """
159 return "dae-%s" % self.id
160 key = property(_get_key)
161
f3333b0e
OL
162 def get_dossiers(self):
163 """
164 Liste tous les anciens dossiers liés à ce poste.
165 (Le nom de la relation sur le rh.Poste est mal choisi poste1 au lieu de dossier1)
166 Note1 : seulement le dosssier principal fait l'objet de la recherche.
167 Note2 : les dossiers sont retournés du plus récent au plus vieux. (Ce test est fait
168 en fonction du id, car les dates de création sont absentes de rh v1).
169 """
170 if self.id_rh is None:
171 return []
172 postes = [p for p in self.id_rh.poste1.all()]
173 return sorted(postes, key=lambda poste: poste.id, reverse=True)
174
175 def get_complement_nom(self):
176 """
177 Inspecte les modèles rh v1 pour trouver dans le dernier dossier un complément de titre de poste.
178 """
179 dossiers = self.get_dossiers()
180 if len(dossiers) > 0:
181 nom = dossiers[0].complement1
182 else:
183 nom = ""
a9c281dd 184 return nom
f3333b0e
OL
185
186 def get_employe(self):
187 """
188 Inspecte les modèles rh v1 pour trouver l'employé du dernier dossier.
189 """
190 dossiers = self.get_dossiers()
191 if len(dossiers) > 0:
192 return dossiers[0].employe
193 else:
194 return None
195
5d680e84 196 def __unicode__(self):
f3333b0e
OL
197 """
198 Cette fonction est consommatrice SQL car elle cherche les dossiers qui ont été liés à celui-ci.
199 """
200 complement_nom_poste = self.get_complement_nom()
c7a4aa2b
OL
201 if complement_nom_poste is None:
202 complement_nom_poste = ""
f3333b0e 203 employe = self.get_employe()
c7a4aa2b
OL
204 if employe is None:
205 employe = "VACANT"
f3333b0e
OL
206 data = (
207 self.implantation,
208 self.type_poste.nom,
209 self.nom,
210 self.id,
211 complement_nom_poste,
212 employe,
213 )
214 return u'%s - %s (%s) [dae-%s %s %s]' % data
5d680e84 215
bd28238f 216
a9c281dd
OL
217# Tester l'enregistrement car les models.py sont importés au complet
218if not reversion.is_registered(Poste):
219 reversion.register(Poste)
220
bd28238f 221
5d680e84
NC
222POSTE_FINANCEMENT_CHOICES = (
223 ('A', 'A - Frais de personnel'),
224 ('B', 'B - Projet(s)-Titre(s)'),
225 ('C', 'C - Autre')
226)
bd28238f
NC
227
228
5d680e84 229class PosteFinancement(models.Model):
43d04712 230 montant = models.DecimalField(max_digits=12, decimal_places=2,
231 help_text="ex.: 12000.00 € (décimale avec point, devise = EUR)")
5d680e84
NC
232 poste = models.ForeignKey('Poste', related_name='financements')
233 type = models.CharField(max_length=1, choices=POSTE_FINANCEMENT_CHOICES)
43d04712 234 pourcentage = models.DecimalField(max_digits=12, decimal_places=2,
235 help_text="ex.: 33.33 % (décimale avec point)")
236 commentaire = models.TextField(
237 help_text="Spécifiez la source de financement.")
bd28238f 238
43d04712 239 class Meta:
240 ordering = ['type']
bd28238f
NC
241
242GENRE_CHOICES = (
139686f2
NC
243 ('m', 'Homme'),
244 ('f', 'Femme'),
bd28238f
NC
245)
246
247
248class Employe(models.Model):
bd28238f
NC
249
250 # Modèle existant
da3ca955 251 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+',
252 verbose_name='Employé')
bd28238f 253 nom = models.CharField(max_length=255)
da3ca955 254 prenom = models.CharField(max_length=255, verbose_name='Prénom')
494ff2be
NC
255 genre = models.CharField(max_length=1, choices=GENRE_CHOICES,
256 null=True, blank=True)
bd28238f 257
139686f2
NC
258 def __unicode__(self):
259 return u'%s %s' % (self.prenom, self.nom)
260
bd28238f
NC
261
262COMPTE_COMPTA_CHOICES = (
494ff2be
NC
263 ('coda', 'CODA'),
264 ('scs', 'SCS'),
265 ('aucun', 'Aucun'),
bd28238f
NC
266)
267
d766bf2c
OL
268class DossierPiece(models.Model):
269 dossier = models.ForeignKey("Dossier")
270 nom = models.CharField(verbose_name="Nom", max_length=255)
271 fichier = models.FileField(verbose_name="Fichier", upload_to=dossier_piece_dispatch, storage=storage_prive)
bd28238f
NC
272
273class Dossier(models.Model):
bd28238f
NC
274
275 # Modèle existant
139686f2
NC
276 employe = models.ForeignKey('Employe', related_name='+', editable=False)
277 poste = models.ForeignKey('Poste', related_name='+', editable=False)
5d680e84
NC
278 statut = models.ForeignKey(rh.Statut, related_name='+')
279 organisme_bstg = models.ForeignKey(rh.OrganismeBstg, related_name='+')
bd28238f 280
139686f2
NC
281 # Données antérieures de l'employé
282 statut_anterieur = models.ForeignKey(
283 rh.Statut, related_name='+', null=True, blank=True,
da3ca955 284 verbose_name='Statut antérieur')
285 #type contrat
139686f2
NC
286 classement_anterieur = models.ForeignKey(
287 rh.Classement, related_name='+', null=True, blank=True,
288 verbose_name='Classement précédent')
289 salaire_anterieur = models.DecimalField(
290 max_digits=12, decimal_places=2, null=True, default=None,
291 blank=True, verbose_name='Salaire précédent')
292
293 # Données du titulaire précédent
294 employe_anterieur = models.ForeignKey(
295 rh.Employe, related_name='+', null=True, blank=True,
296 verbose_name='Employé précédent')
297 statut_titulaire_anterieur = models.ForeignKey(
298 rh.Statut, related_name='+', null=True, blank=True,
299 verbose_name='Statut titulaire précédent')
300 classement_titulaire_anterieur = models.ForeignKey(
301 rh.Classement, related_name='+', null=True, blank=True,
302 verbose_name='Classement titulaire précédent')
303 salaire_titulaire_anterieur = models.DecimalField(
304 max_digits=12, decimal_places=2, default=None, null=True,
305 blank=True, verbose_name='Salaire titulaire précédent')
494ff2be 306
bd28238f
NC
307 # Recrutement
308 remplacement = models.BooleanField()
4d25e2ba 309 statut_residence = models.CharField(max_length=10, default='local',
310 verbose_name="Statut",
bd28238f
NC
311 choices=STATUT_RESIDENCE_CHOICES)
312
313 # Rémunération
494ff2be
NC
314 classement = models.ForeignKey(rh.Classement, related_name='+',
315 verbose_name='Classement proposé')
316 salaire = models.DecimalField(max_digits=12, decimal_places=2,
bd28238f 317 verbose_name='Salaire de base',
494ff2be 318 null=True, default=None)
5d680e84 319 devise = models.ForeignKey(rh.Devise, related_name='+')
7ad7408e 320 regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
4d25e2ba 321 verbose_name="Régime de travail",
322 help_text="% du temps complet")
139686f2 323 regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
4d25e2ba 324 decimal_places=2, verbose_name="Nb. heures par semaine")
bd28238f
NC
325
326 # Contrat
5d680e84 327 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
4d25e2ba 328 contrat_date_debut = models.DateField(help_text="format: aaaa-mm-jj")
329 contrat_date_fin = models.DateField(help_text="format: aaaa-mm-jj")
bd28238f
NC
330
331 # Comptes
332 compte_compta = models.CharField(max_length=10,
333 choices=COMPTE_COMPTA_CHOICES)
334 compte_courriel = models.BooleanField()
335
336
337class Remuneration(models.Model):
5d680e84 338 # Identification
bd28238f 339 dossier = models.ForeignKey('Dossier', db_column='dossier')
cb1d62b5
NC
340 type = models.ForeignKey(rh.TypeRemuneration, db_column='type',
341 related_name='+')
5d680e84
NC
342 # TODO: what's that?
343 # type_revalorisation = models.ForeignKey('TypeRevalorisation',
344 # db_column='type_revalorisation')
cb1d62b5
NC
345 montant = models.DecimalField(max_digits=12, decimal_places=2,
346 null=True) # Annuel
494ff2be 347 devise = models.ForeignKey(rh.Devise, to_field='code',
5d680e84 348 db_column='devise', related_name='+')
cb1d62b5
NC
349 precision = models.CharField(max_length=255, null=True, blank=True)
350 # date_effective = models.DateField(null=True, blank=True)
351 # pourcentage = models.IntegerField(null=True, blank=True)
bd28238f 352
5d680e84 353 # Méta
bd28238f 354 date_creation = models.DateField(auto_now_add=True)
494ff2be 355 user_creation = models.IntegerField(null=True, blank=True)
cb1d62b5
NC
356 # desactivation = models.BooleanField(default=False, blank=True)
357 # date_desactivation = models.DateField(null=True, blank=True)
358 # user_desactivation = models.IntegerField(null=True, blank=True)
359 # annulation = models.BooleanField(default=False, blank=True)
360 # date_annulation = models.DateField(null=True, blank=True)
361 # user_annulation = models.IntegerField(null=True, blank=True)
bd28238f 362
ee91bc95
NC
363 def montant_mois(self):
364 return round(self.montant / 12, 2)
365
366 def taux_devise(self):
367 return self.devise.tauxchange_set.order_by('-annee').all()[0].taux
368
369 def montant_euro(self):
370 return round(float(self.montant) / float(self.taux_devise()), 2)
371
372 def montant_euro_mois(self):
373 return round(self.montant_euro() / 12, 2)
bd28238f
NC
374
375
376class JustificationPoste(models.Model):
377 pass
378
379
380class JustificationEmploye(models.Model):
381 pass
382
383
384class DocumentPoste(models.Model):
385 pass
386
387
388class DocumentEmploye(models.Model):
389 pass
390
391
392class Validation(models.Model):
393 # user
394 date = models.DateField()
395
396 # avis = ? (CHOICES?)
397
398
399class ValidationPoste(models.Model):
400 poste = models.ForeignKey('Poste')
401
402
403class ValidationEmploye(models.Model):
404 employe = models.ForeignKey('Employe')