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