amélioration du formulaire de coût d'embauche
[auf_rh_dae.git] / project / dae / models.py
1 # -=- encoding: utf-8 -=-
2
3 import os
4 from django.core.files.storage import FileSystemStorage
5 from django.db import models
6 import reversion
7 import datamaster_modeles.models as ref
8 from rh_v1 import models as rh
9 import settings
10
11 STATUT_RESIDENCE_CHOICES = (
12 ('local', 'Local'),
13 ('expat', 'Expatrié'),
14 )
15
16 POSTE_APPEL_CHOICES = (
17 ('interne', 'Interne'),
18 ('externe', 'Externe'),
19 )
20
21 POSTE_STATUT_CHOICES = (
22 ('MAD', 'Mise à disposition'),
23 ('DET', 'Détachement'),
24 )
25
26
27 storage_prive = FileSystemStorage(settings.PRIVE_MEDIA_ROOT, base_url=settings.PRIVE_MEDIA_URL)
28
29 def poste_piece_dispatch(instance, filename):
30 path = "poste/%s/%s" % (instance.poste.id, filename)
31 return path
32
33
34 class 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
39 class 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 )
55 return super(PosteManager, self).get_query_set() \
56 .select_related(*fkeys).all()
57
58
59 class Poste(models.Model):
60 # Modèle existant
61 id_rh = models.ForeignKey(rh.Poste, null=True, related_name='+',
62 editable=False,
63 verbose_name="Mise à jour du poste")
64 nom = models.CharField(verbose_name="Titre du poste", max_length=255)
65 implantation = models.ForeignKey(ref.Implantation)
66 type_poste = models.ForeignKey(rh.TypePoste, null=True, related_name='+')
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='+',
70 verbose_name="Poste du responsable")
71
72 regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
73 default=100,
74 verbose_name="Temps de travail",
75 help_text="% du temps complet")
76 regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
77 decimal_places=2,
78 default=40,
79 verbose_name="Nb. heures par semaine")
80
81 # Recrutement
82 statut_residence = models.CharField(max_length=10, default='MAD',
83 verbose_name="Statut",
84 choices=STATUT_RESIDENCE_CHOICES)
85 # TODO null?
86 mise_a_disposition = models.BooleanField(verbose_name="Mise à disposition")
87 appel = models.CharField(max_length=10, default='interne',
88 verbose_name="Appel à candidature",
89 choices=POSTE_APPEL_CHOICES)
90
91 # Rémunération
92 classement_min = models.ForeignKey(rh.Classement, related_name='+')
93 classement_max = models.ForeignKey(rh.Classement, related_name='+')
94 coefficient_min = models.FloatField(null=True) # pour classement "hors grille"
95 coefficient_max = models.FloatField(null=True) # pour classement "hors grille"
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)
98 devise_min = models.ForeignKey(rh.Devise, default=5, related_name='+')
99 devise_max = models.ForeignKey(rh.Devise, default=5, related_name='+')
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='+',
115 default=5)
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)
136
137 # Méta
138 date_creation = models.DateTimeField(auto_now_add=True)
139 date_modification = models.DateTimeField(auto_now=True)
140 date_debut = models.DateField(verbose_name="Date de début",
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")
145 actif = models.BooleanField(default=True)
146
147 # Managers
148 objects = PosteManager()
149
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 = ""
172 return nom
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
184 def __unicode__(self):
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()
189 if complement_nom_poste is None:
190 complement_nom_poste = ""
191 employe = self.get_employe()
192 if employe is None:
193 employe = "VACANT"
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
203
204
205 # Tester l'enregistrement car les models.py sont importés au complet
206 if not reversion.is_registered(Poste):
207 reversion.register(Poste)
208
209
210 POSTE_FINANCEMENT_CHOICES = (
211 ('A', 'A - Frais de personnel'),
212 ('B', 'B - Projet(s)-Titre(s)'),
213 ('C', 'C - Autre')
214 )
215
216
217 class PosteFinancement(models.Model):
218 montant = models.DecimalField(max_digits=12, decimal_places=2,
219 help_text="ex.: 12000.00 € (décimale avec point, devise = EUR)")
220 poste = models.ForeignKey('Poste', related_name='financements')
221 type = models.CharField(max_length=1, choices=POSTE_FINANCEMENT_CHOICES)
222 pourcentage = models.DecimalField(max_digits=12, decimal_places=2,
223 help_text="ex.: 33.33 % (décimale avec point)")
224 commentaire = models.TextField(
225 help_text="Spécifiez la source de financement.")
226
227 class Meta:
228 ordering = ['type']
229
230 GENRE_CHOICES = (
231 ('m', 'Homme'),
232 ('f', 'Femme'),
233 )
234
235
236 class Employe(models.Model):
237
238 # Modèle existant
239 id_rh = models.ForeignKey(rh.Employe, null=True, related_name='+',
240 verbose_name='Employé')
241 nom = models.CharField(max_length=255)
242 prenom = models.CharField(max_length=255, verbose_name='Prénom')
243 genre = models.CharField(max_length=1, choices=GENRE_CHOICES,
244 null=True, blank=True)
245
246 def __unicode__(self):
247 return u'%s %s' % (self.prenom, self.nom)
248
249
250 COMPTE_COMPTA_CHOICES = (
251 ('coda', 'CODA'),
252 ('scs', 'SCS'),
253 ('aucun', 'Aucun'),
254 )
255
256
257 class Dossier(models.Model):
258
259 # Modèle existant
260 employe = models.ForeignKey('Employe', related_name='+', editable=False)
261 poste = models.ForeignKey('Poste', related_name='+', editable=False)
262 statut = models.ForeignKey(rh.Statut, related_name='+')
263 organisme_bstg = models.ForeignKey(rh.OrganismeBstg, related_name='+')
264
265 # Données antérieures de l'employé
266 statut_anterieur = models.ForeignKey(
267 rh.Statut, related_name='+', null=True, blank=True,
268 verbose_name='Statut antérieur')
269 #type contrat
270 classement_anterieur = models.ForeignKey(
271 rh.Classement, related_name='+', null=True, blank=True,
272 verbose_name='Classement précédent')
273 salaire_anterieur = models.DecimalField(
274 max_digits=12, decimal_places=2, null=True, default=None,
275 blank=True, verbose_name='Salaire précédent')
276
277 # Données du titulaire précédent
278 employe_anterieur = models.ForeignKey(
279 rh.Employe, related_name='+', null=True, blank=True,
280 verbose_name='Employé précédent')
281 statut_titulaire_anterieur = models.ForeignKey(
282 rh.Statut, related_name='+', null=True, blank=True,
283 verbose_name='Statut titulaire précédent')
284 classement_titulaire_anterieur = models.ForeignKey(
285 rh.Classement, related_name='+', null=True, blank=True,
286 verbose_name='Classement titulaire précédent')
287 salaire_titulaire_anterieur = models.DecimalField(
288 max_digits=12, decimal_places=2, default=None, null=True,
289 blank=True, verbose_name='Salaire titulaire précédent')
290
291 # Recrutement
292 remplacement = models.BooleanField()
293 statut_residence = models.CharField(max_length=10,
294 choices=STATUT_RESIDENCE_CHOICES)
295
296 # Rémunération
297 classement = models.ForeignKey(rh.Classement, related_name='+',
298 verbose_name='Classement proposé')
299 salaire = models.DecimalField(max_digits=12, decimal_places=2,
300 verbose_name='Salaire de base',
301 null=True, default=None)
302 devise = models.ForeignKey(rh.Devise, related_name='+')
303 regime_travail = models.DecimalField(max_digits=12, decimal_places=2,
304 verbose_name="Régime de travail")
305 regime_travail_nb_heure_semaine = models.DecimalField(max_digits=12,
306 decimal_places=2, verbose_name="Nbr heures par semaine")
307
308 # Contrat
309 type_contrat = models.ForeignKey(rh.TypeContrat, related_name='+')
310 contrat_date_debut = models.DateField()
311 contrat_date_fin = models.DateField()
312
313 # Comptes
314 compte_compta = models.CharField(max_length=10,
315 choices=COMPTE_COMPTA_CHOICES)
316 compte_courriel = models.BooleanField()
317
318
319 class Remuneration(models.Model):
320 # Identification
321 dossier = models.ForeignKey('Dossier', db_column='dossier')
322 type = models.ForeignKey(rh.TypeRemuneration, db_column='type',
323 related_name='+')
324 # TODO: what's that?
325 # type_revalorisation = models.ForeignKey('TypeRevalorisation',
326 # db_column='type_revalorisation')
327 montant = models.DecimalField(max_digits=12, decimal_places=2,
328 null=True) # Annuel
329 devise = models.ForeignKey(rh.Devise, to_field='code',
330 db_column='devise', related_name='+')
331 precision = models.CharField(max_length=255, null=True, blank=True)
332 # date_effective = models.DateField(null=True, blank=True)
333 # pourcentage = models.IntegerField(null=True, blank=True)
334
335 # Méta
336 date_creation = models.DateField(auto_now_add=True)
337 user_creation = models.IntegerField(null=True, blank=True)
338 # desactivation = models.BooleanField(default=False, blank=True)
339 # date_desactivation = models.DateField(null=True, blank=True)
340 # user_desactivation = models.IntegerField(null=True, blank=True)
341 # annulation = models.BooleanField(default=False, blank=True)
342 # date_annulation = models.DateField(null=True, blank=True)
343 # user_annulation = models.IntegerField(null=True, blank=True)
344
345 def montant_mois(self):
346 return round(self.montant / 12, 2)
347
348 def taux_devise(self):
349 return self.devise.tauxchange_set.order_by('-annee').all()[0].taux
350
351 def montant_euro(self):
352 return round(float(self.montant) / float(self.taux_devise()), 2)
353
354 def montant_euro_mois(self):
355 return round(self.montant_euro() / 12, 2)
356
357
358 class JustificationPoste(models.Model):
359 pass
360
361
362 class JustificationEmploye(models.Model):
363 pass
364
365
366 class DocumentPoste(models.Model):
367 pass
368
369
370 class DocumentEmploye(models.Model):
371 pass
372
373
374 class Validation(models.Model):
375 # user
376 date = models.DateField()
377
378 # avis = ? (CHOICES?)
379
380
381 class ValidationPoste(models.Model):
382 poste = models.ForeignKey('Poste')
383
384
385 class ValidationEmploye(models.Model):
386 employe = models.ForeignKey('Employe')