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