pieces jointes
[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
5d680e84 253 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+')
bd28238f
NC
254 nom = models.CharField(max_length=255)
255 prenom = models.CharField(max_length=255)
494ff2be
NC
256 genre = models.CharField(max_length=1, choices=GENRE_CHOICES,
257 null=True, blank=True)
bd28238f 258
139686f2
NC
259 def __unicode__(self):
260 return u'%s %s' % (self.prenom, self.nom)
261
bd28238f
NC
262
263COMPTE_COMPTA_CHOICES = (
494ff2be
NC
264 ('coda', 'CODA'),
265 ('scs', 'SCS'),
266 ('aucun', 'Aucun'),
bd28238f
NC
267)
268
269
270class Dossier(models.Model):
bd28238f
NC
271
272 # Modèle existant
139686f2
NC
273 employe = models.ForeignKey('Employe', related_name='+', editable=False)
274 poste = models.ForeignKey('Poste', related_name='+', editable=False)
5d680e84
NC
275 statut = models.ForeignKey(rh.Statut, related_name='+')
276 organisme_bstg = models.ForeignKey(rh.OrganismeBstg, related_name='+')
bd28238f 277
139686f2
NC
278 # Données antérieures de l'employé
279 statut_anterieur = models.ForeignKey(
280 rh.Statut, related_name='+', null=True, blank=True,
281 verbose_name='Statut précédent')
282 classement_anterieur = models.ForeignKey(
283 rh.Classement, related_name='+', null=True, blank=True,
284 verbose_name='Classement précédent')
285 salaire_anterieur = models.DecimalField(
286 max_digits=12, decimal_places=2, null=True, default=None,
287 blank=True, verbose_name='Salaire précédent')
288
289 # Données du titulaire précédent
290 employe_anterieur = models.ForeignKey(
291 rh.Employe, related_name='+', null=True, blank=True,
292 verbose_name='Employé précédent')
293 statut_titulaire_anterieur = models.ForeignKey(
294 rh.Statut, related_name='+', null=True, blank=True,
295 verbose_name='Statut titulaire précédent')
296 classement_titulaire_anterieur = models.ForeignKey(
297 rh.Classement, related_name='+', null=True, blank=True,
298 verbose_name='Classement titulaire précédent')
299 salaire_titulaire_anterieur = models.DecimalField(
300 max_digits=12, decimal_places=2, default=None, null=True,
301 blank=True, verbose_name='Salaire titulaire précédent')
494ff2be 302
bd28238f
NC
303 # Recrutement
304 remplacement = models.BooleanField()
bd28238f
NC
305 statut_residence = models.CharField(max_length=10,
306 choices=STATUT_RESIDENCE_CHOICES)
307
308 # Rémunération
494ff2be
NC
309 classement = models.ForeignKey(rh.Classement, related_name='+',
310 verbose_name='Classement proposé')
311 salaire = models.DecimalField(max_digits=12, decimal_places=2,
bd28238f 312 verbose_name='Salaire de base',
494ff2be 313 null=True, default=None)
5d680e84 314 devise = models.ForeignKey(rh.Devise, related_name='+')
7ad7408e
NC
315 regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
316 verbose_name="Régime de travail")
139686f2 317 regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
7ad7408e 318 decimal_places=2, verbose_name="Nbr heures par semaine")
bd28238f
NC
319
320 # Contrat
5d680e84 321 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
bd28238f
NC
322 contrat_date_debut = models.DateField()
323 contrat_date_fin = models.DateField()
bd28238f
NC
324
325 # Comptes
326 compte_compta = models.CharField(max_length=10,
327 choices=COMPTE_COMPTA_CHOICES)
328 compte_courriel = models.BooleanField()
329
330
331class Remuneration(models.Model):
5d680e84 332 # Identification
bd28238f
NC
333 id = models.IntegerField(primary_key=True)
334 dossier = models.ForeignKey('Dossier', db_column='dossier')
335 type = models.ForeignKey('TypeRemuneration', db_column='type')
5d680e84
NC
336 # TODO: what's that?
337 # type_revalorisation = models.ForeignKey('TypeRevalorisation',
338 # db_column='type_revalorisation')
98d51b59 339 montant = models.DecimalField(max_digits=12, decimal_places=2) # Annuel
494ff2be 340 devise = models.ForeignKey(rh.Devise, to_field='code',
5d680e84 341 db_column='devise', related_name='+')
494ff2be
NC
342 date_effective = models.DateField(null=True, blank=True)
343 pourcentage = models.IntegerField(null=True, blank=True)
bd28238f 344
5d680e84 345 # Méta
bd28238f 346 date_creation = models.DateField(auto_now_add=True)
494ff2be 347 user_creation = models.IntegerField(null=True, blank=True)
139686f2 348 desactivation = models.BooleanField(default=False, blank=True)
494ff2be
NC
349 date_desactivation = models.DateField(null=True, blank=True)
350 user_desactivation = models.IntegerField(null=True, blank=True)
139686f2
NC
351 annulation = models.BooleanField(default=False, blank=True)
352 date_annulation = models.DateField(null=True, blank=True)
353 user_annulation = models.IntegerField(null=True, blank=True)
bd28238f
NC
354
355
356class JustificationPoste(models.Model):
357 pass
358
359
360class JustificationEmploye(models.Model):
361 pass
362
363
364class DocumentPoste(models.Model):
365 pass
366
367
368class DocumentEmploye(models.Model):
369 pass
370
371
372class Validation(models.Model):
373 # user
374 date = models.DateField()
375
376 # avis = ? (CHOICES?)
377
378
379class ValidationPoste(models.Model):
380 poste = models.ForeignKey('Poste')
381
382
383class ValidationEmploye(models.Model):
384 employe = models.ForeignKey('Employe')
385
386
387class TypeRemuneration(models.Model):
388 ordre = models.IntegerField()
389 groupe = models.ForeignKey('GroupeTypeRemuneration')
390
391
392class GroupeTypeRemuneration(models.Model):
393 nom = models.CharField(max_length=255)
394 ordre = models.IntegerField()