1 # -=- encoding: utf-8 -=-
5 from django
.core
.files
.storage
import FileSystemStorage
6 from django
.db
import models
9 import datamaster_modeles
.models
as ref
13 HELP_TEXT_DATE
= "format: aaaa-mm-jj"
14 REGIME_TRAVAIL_DEFAULT
= 100.00
15 REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
= 35.00
19 storage_prive
= FileSystemStorage(settings
.PRIVE_MEDIA_ROOT
,
20 base_url
=settings
.PRIVE_MEDIA_URL
)
22 def poste_piece_dispatch(instance
, filename
):
23 path
= "poste/%s/%s" % (instance
.poste_id
, filename
)
26 def dossier_piece_dispatch(instance
, filename
):
27 path
= "dossier/%s/%s" % (instance
.dossier_id
, filename
)
31 class RHManager(models
.Manager
):
32 def get_query_set(self
):
33 return super(RHManager
, self
).get_query_set().filter(supprime
=False)
37 class Metadata(models
.Model
):
39 Metadata.actif = flag remplaçant la suppression.
40 supprime == True : objet réputé supprimé.
42 actif
= models
.BooleanField(default
=True)
43 supprime
= models
.BooleanField(default
=False)
44 date_creation
= models
.DateField(auto_now_add
=True)
45 user_creation
= models
.ForeignKey('auth.User',
46 db_column
='user_creation', related_name
='+',
47 null
=True, blank
=True)
48 date_modification
= models
.DateField(auto_now
=True)
49 user_modification
= models
.ForeignKey('auth.User',
50 db_column
='user_modification', related_name
='+',
51 null
=True, blank
=True)
52 date_desactivation
= models
.DateField(null
=True, blank
=True)
53 user_desactivation
= models
.ForeignKey('auth.User',
54 db_column
='user_desactivation', related_name
='+',
55 null
=True, blank
=True)
67 class Commentaire(Metadata
):
68 texte
= models
.TextField()
69 owner
= models
.ForeignKey('auth.User', db_column
='owner', related_name
='+')
73 ordering
= ['-date_creation']
75 def __unicode__(self
):
76 return u
'%s' % (self
.texte
)
81 POSTE_APPEL_CHOICES
= (
82 ('interne', 'Interne'),
83 ('externe', 'Externe'),
86 class Poste_(Metadata
):
87 """Un Poste est un emploi (job) à combler dans une implantation.
88 Un Poste peut être comblé par un Employe, auquel cas un Dossier est créé.
89 Si on veut recruter 2 jardiniers, 2 Postes distincts existent.
92 nom
= models
.CharField(max_length
=255,
93 verbose_name
="Titre du poste", )
94 nom_feminin
= models
.CharField(max_length
=255,
95 verbose_name
="Titre du poste (au féminin)",
97 implantation
= models
.ForeignKey(ref
.Implantation
,
98 db_column
='implantation', related_name
='+')
99 type_poste
= models
.ForeignKey('TypePoste', db_column
='type_poste',
102 service
= models
.ForeignKey('Service', db_column
='service', null
=True,
104 verbose_name
="Direction/Service/Pôle support",
105 default
=1) # default = Rectorat
106 responsable
= models
.ForeignKey('Poste', db_column
='responsable',
107 related_name
='+', null
=True,
108 verbose_name
="Poste du responsable",
109 default
=149) # default = Recteur
112 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
113 default
=REGIME_TRAVAIL_DEFAULT
, null
=True,
114 verbose_name
="Temps de travail",
115 help_text
="% du temps complet")
116 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
117 decimal_places
=2, null
=True,
118 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
119 verbose_name
="Nb. heures par semaine")
122 local
= models
.NullBooleanField(verbose_name
="Local", default
=True,
123 null
=True, blank
=True)
124 expatrie
= models
.NullBooleanField(verbose_name
="Expatrié", default
=False,
125 null
=True, blank
=True)
126 mise_a_disposition
= models
.NullBooleanField(
127 verbose_name
="Mise à disposition",
128 null
=True, default
=False)
129 appel
= models
.CharField(max_length
=10, null
=True,
130 verbose_name
="Appel à candidature",
131 choices
=POSTE_APPEL_CHOICES
,
135 classement_min
= models
.ForeignKey('Classement',
136 db_column
='classement_min', related_name
='+',
137 null
=True, blank
=True)
138 classement_max
= models
.ForeignKey('Classement',
139 db_column
='classement_max', related_name
='+',
140 null
=True, blank
=True)
141 valeur_point_min
= models
.ForeignKey('ValeurPoint',
142 db_column
='valeur_point_min', related_name
='+',
143 null
=True, blank
=True)
144 valeur_point_max
= models
.ForeignKey('ValeurPoint',
145 db_column
='valeur_point_max', related_name
='+',
146 null
=True, blank
=True)
147 devise_min
= models
.ForeignKey('Devise', db_column
='devise_min', null
=True,
148 related_name
='+', default
=5)
149 devise_max
= models
.ForeignKey('Devise', db_column
='devise_max', null
=True,
150 related_name
='+', default
=5)
151 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
152 null
=True, default
=0)
153 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
154 null
=True, default
=0)
155 indemn_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
156 null
=True, default
=0)
157 indemn_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
158 null
=True, default
=0)
159 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
160 null
=True, default
=0)
161 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
162 null
=True, default
=0)
164 # Comparatifs de rémunération
165 devise_comparaison
= models
.ForeignKey('Devise', null
=True,
166 db_column
='devise_comparaison',
169 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
170 null
=True, blank
=True)
171 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
172 null
=True, blank
=True)
173 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
174 null
=True, blank
=True)
175 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
176 null
=True, blank
=True)
177 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
178 null
=True, blank
=True)
179 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
180 null
=True, blank
=True)
181 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
182 null
=True, blank
=True)
183 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
184 null
=True, blank
=True)
185 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
186 null
=True, blank
=True)
187 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
188 null
=True, blank
=True)
191 justification
= models
.TextField(null
=True, blank
=True)
194 date_validation
= models
.DateTimeField(null
=True, blank
=True) # de dae
195 date_debut
= models
.DateField(verbose_name
="Date de début", null
=True,
196 help_text
=HELP_TEXT_DATE
)
197 date_fin
= models
.DateField(verbose_name
="Date de fin",
198 help_text
=HELP_TEXT_DATE
,
199 null
=True, blank
=True)
203 ordering
= ['implantation__nom', 'nom']
204 verbose_name
= "Poste"
205 verbose_name_plural
= "Postes"
207 def __unicode__(self
):
208 representation
= u
'%s - %s [%s]' % (self
.implantation
, self
.nom
,
211 representation
= representation
+ u
' (vacant)'
212 return representation
215 # TODO : si existe un dossier actif pour ce poste, return False
216 # self.dossier_set.all() fonctionne pas
221 __doc__
= Poste_
.__doc__
225 __doc__
= Poste_
.__doc__
228 POSTE_FINANCEMENT_CHOICES
= (
229 ('A', 'A - Frais de personnel'),
230 ('B', 'B - Projet(s)-Titre(s)'),
235 class PosteFinancement_(models
.Model
):
236 """Pour un Poste, structure d'informations décrivant comment on prévoit
239 poste
= models
.ForeignKey('Poste', db_column
='poste',
240 related_name
='%(app_label)s_financements')
241 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
242 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
243 help_text
="ex.: 33.33 % (décimale avec point)")
244 commentaire
= models
.TextField(
245 help_text
="Spécifiez la source de financement.")
251 def __unicode__(self
):
252 return u
'%s : %s %' % (self
.type, self
.pourcentage
)
255 class PosteFinancement(PosteFinancement_
):
256 __doc__
= PosteFinancement_
.__doc__
259 class PostePiece(models
.Model
):
260 """Documents relatifs au Poste.
261 Ex.: Description de poste
263 poste
= models
.ForeignKey('Poste', db_column
='poste',
264 related_name
='pieces')
265 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
266 fichier
= models
.FileField(verbose_name
="Fichier",
267 upload_to
=poste_piece_dispatch
,
268 storage
=storage_prive
)
273 def __unicode__(self
):
274 return u
'%s' % (self
.nom
)
276 class PosteComparaison(models
.Model
):
278 De la même manière qu'un dossier, un poste peut-être comparé à un autre poste.
280 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
281 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True, related_name
="+")
282 nom
= models
.CharField(verbose_name
="Poste", max_length
=255, null
=True, blank
=True)
283 montant
= models
.IntegerField(null
=True)
284 devise
= models
.ForeignKey("Devise", default
=5, related_name
='+', null
=True, blank
=True)
285 montant_euros
= models
.IntegerField(null
=True)
288 class PosteCommentaire(Commentaire
):
289 poste
= models
.ForeignKey('Poste', db_column
='poste', related_name
='+')
298 SITUATION_CHOICES
= (
299 ('C', 'Célibataire'),
304 class Employe(Metadata
):
305 """Personne occupant ou ayant occupé un Poste. Un Employe aura autant de
306 Dossiers qu'il occupe ou a occupé de Postes.
308 Cette classe aurait pu avantageusement s'appeler Personne car la notion
309 d'employé n'a pas de sens si aucun Dossier n'existe pour une personne.
312 nom
= models
.CharField(max_length
=255)
313 prenom
= models
.CharField(max_length
=255, verbose_name
="Prénom")
314 nom_affichage
= models
.CharField(max_length
=255,
315 verbose_name
="Nom d'affichage",
316 null
=True, blank
=True)
317 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
318 db_column
='nationalite',
319 related_name
='employes_nationalite',
320 verbose_name
="Nationalité")
321 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
322 verbose_name
="Date de naissance",
323 null
=True, blank
=True)
324 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
327 situation_famille
= models
.CharField(max_length
=1,
328 choices
=SITUATION_CHOICES
,
329 verbose_name
="Situation familiale",
330 null
=True, blank
=True)
331 date_entree
= models
.DateField(verbose_name
="Date d'entrée à l'AUF",
332 help_text
=HELP_TEXT_DATE
,
333 null
=True, blank
=True)
336 tel_domicile
= models
.CharField(max_length
=255,
337 verbose_name
="Tél. domicile",
338 null
=True, blank
=True)
339 tel_cellulaire
= models
.CharField(max_length
=255,
340 verbose_name
="Tél. cellulaire",
341 null
=True, blank
=True)
342 adresse
= models
.CharField(max_length
=255, null
=True, blank
=True)
343 ville
= models
.CharField(max_length
=255, null
=True, blank
=True)
344 province
= models
.CharField(max_length
=255, null
=True, blank
=True)
345 code_postal
= models
.CharField(max_length
=255, null
=True, blank
=True)
346 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code', db_column
='pays',
347 related_name
='employes',
348 null
=True, blank
=True)
351 ordering
= ['nom_affichage','nom','prenom']
352 verbose_name
= "Employé"
353 verbose_name_plural
= "Employés"
355 def __unicode__(self
):
356 return u
'%s' % (self
.get_nom())
359 nom_affichage
= self
.nom_affichage
360 if not nom_affichage
:
361 nom_affichage
= u
'%s %s' % (self
.nom
.upper(), self
.prenom
)
364 class EmployePiece(models
.Model
):
365 """Documents relatifs à un employé.
368 employe
= models
.ForeignKey('Employe', db_column
='employe',
370 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
371 fichier
= models
.FileField(verbose_name
="Fichier",
372 upload_to
=dossier_piece_dispatch
,
373 storage
=storage_prive
)
378 def __unicode__(self
):
379 return u
'%s' % (self
.nom
)
381 class EmployeCommentaire(Commentaire
):
382 employe
= models
.ForeignKey('Employe', db_column
='employe',
386 LIEN_PARENTE_CHOICES
= (
387 ('Conjoint', 'Conjoint'),
388 ('Conjointe', 'Conjointe'),
393 class AyantDroit(Metadata
):
394 """Personne en relation avec un Employe.
397 nom
= models
.CharField(max_length
=255)
398 prenom
= models
.CharField(max_length
=255,
399 verbose_name
="Prénom",)
400 nom_affichage
= models
.CharField(max_length
=255,
401 verbose_name
="Nom d'affichage",
402 null
=True, blank
=True)
403 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
404 db_column
='nationalite',
405 related_name
='ayantdroits_nationalite',
406 verbose_name
="Nationalité")
407 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
408 verbose_name
="Date de naissance",
409 null
=True, blank
=True)
410 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
413 employe
= models
.ForeignKey('Employe', db_column
='employe',
414 related_name
='ayantdroits',
415 verbose_name
="Employé")
416 lien_parente
= models
.CharField(max_length
=10,
417 choices
=LIEN_PARENTE_CHOICES
,
418 verbose_name
="Lien de parenté",
419 null
=True, blank
=True)
422 ordering
= ['nom_affichage']
423 verbose_name
= "Ayant droit"
424 verbose_name_plural
= "Ayants droit"
426 def __unicode__(self
):
427 return u
'%s' % (self
.get_nom())
430 nom_affichage
= self
.nom_affichage
431 if not nom_affichage
:
432 nom_affichage
= u
'%s %s' % (self
.nom
.upper(), self
.prenom
)
435 class AyantDroitCommentaire(Commentaire
):
436 ayant_droit
= models
.ForeignKey('AyantDroit', db_column
='ayant_droit',
442 STATUT_RESIDENCE_CHOICES
= (
444 ('expat', 'Expatrié'),
447 COMPTE_COMPTA_CHOICES
= (
453 class Dossier_(Metadata
):
454 """Le Dossier regroupe les informations relatives à l'occupation
455 d'un Poste par un Employe. Un seul Dossier existe par Poste occupé
458 Plusieurs Contrats peuvent être associés au Dossier.
459 Une structure de Remuneration est rattachée au Dossier. Un Poste pour
460 lequel aucun Dossier n'existe est un poste vacant.
463 employe
= models
.ForeignKey('Employe', db_column
='employe',
465 verbose_name
="Employé")
466 poste
= models
.ForeignKey('Poste', db_column
='poste',
467 related_name
='+', editable
=False)
468 statut
= models
.ForeignKey('Statut', related_name
='+', default
=3,
470 organisme_bstg
= models
.ForeignKey('OrganismeBstg',
471 db_column
='organisme_bstg',
473 verbose_name
="Organisme",
474 help_text
="Si détaché (DET) ou \
475 mis à disposition (MAD), \
476 préciser l'organisme.",
477 null
=True, blank
=True)
480 remplacement
= models
.BooleanField(default
=False)
481 statut_residence
= models
.CharField(max_length
=10, default
='local',
482 verbose_name
="Statut", null
=True,
483 choices
=STATUT_RESIDENCE_CHOICES
)
486 classement
= models
.ForeignKey('Classement', db_column
='classement',
488 null
=True, blank
=True)
489 regime_travail
= models
.DecimalField(max_digits
=12, null
=True,
491 default
=REGIME_TRAVAIL_DEFAULT
,
492 verbose_name
="Régime de travail",
493 help_text
="% du temps complet")
494 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
495 decimal_places
=2, null
=True,
496 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
497 verbose_name
="Nb. heures par semaine")
499 # Occupation du Poste par cet Employe (anciennement "mandat")
500 date_debut
= models
.DateField(verbose_name
="Date de début d'occupation \
502 help_text
=HELP_TEXT_DATE
)
503 date_fin
= models
.DateField(verbose_name
="Date de fin d'occupation \
505 help_text
=HELP_TEXT_DATE
,
506 null
=True, blank
=True)
513 ordering
= ['employe__nom_affichage', 'employe__nom', 'poste__nom']
514 verbose_name
= "Dossier"
515 verbose_name_plural
= "Dossiers"
517 def __unicode__(self
):
518 poste
= self
.poste
.nom
519 if self
.employe
.genre
== 'F':
520 poste
= self
.poste
.nom_feminin
521 return u
'%s - %s' % (self
.employe
, poste
)
524 class Dossier(Dossier_
):
525 __doc__
= Dossier_
.__doc__
529 class Dossier(Dossier_
):
530 __doc__
= Dossier_
.__doc__
533 class DossierPiece(models
.Model
):
534 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
535 Ex.: Lettre de motivation.
537 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
539 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
540 fichier
= models
.FileField(verbose_name
="Fichier",
541 upload_to
=dossier_piece_dispatch
,
542 storage
=storage_prive
)
547 def __unicode__(self
):
548 return u
'%s' % (self
.nom
)
550 class DossierCommentaire(Commentaire
):
551 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
557 class RemunerationMixin(Metadata
):
559 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
560 related_name
='%(app_label)s_%(class)s_remunerations')
561 type = models
.ForeignKey('TypeRemuneration', db_column
='type',
563 verbose_name
="Type de rémunération")
564 type_revalorisation
= models
.ForeignKey('TypeRevalorisation',
565 db_column
='type_revalorisation',
567 verbose_name
="Type de revalorisation",
568 null
=True, blank
=True)
569 montant
= models
.FloatField(null
=True, blank
=True,
571 # Annuel (12 mois, 52 semaines, 364 jours?)
572 devise
= models
.ForeignKey('Devise', to_field
='id',
573 db_column
='devise', related_name
='+',
575 # commentaire = precision
576 commentaire
= models
.CharField(max_length
=255, null
=True, blank
=True)
577 # date_debut = anciennement date_effectif
578 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
579 verbose_name
="Date de début",
580 null
=True, blank
=True)
581 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
582 verbose_name
="Date de fin",
583 null
=True, blank
=True)
587 ordering
= ['type__nom', '-date_fin']
589 def __unicode__(self
):
590 return u
'%s %s (%s)' % (self
.montant
, self
.devise
.code
, self
.type.nom
)
592 class Remuneration_(RemunerationMixin
):
593 """Structure de rémunération (données budgétaires) en situation normale
594 pour un Dossier. Si un Evenement existe, utiliser la structure de
595 rémunération EvenementRemuneration de cet événement.
598 def montant_mois(self
):
599 return round(self
.montant
/ 12, 2)
601 def taux_devise(self
):
602 return self
.devise
.tauxchange_set
.order_by('-annee').all()[0].taux
604 def montant_euro(self
):
605 return round(float(self
.montant
) / float(self
.taux_devise()), 2)
607 def montant_euro_mois(self
):
608 return round(self
.montant_euro() / 12, 2)
610 def __unicode__(self
):
612 devise
= self
.devise
.code
615 return "%s %s" % (self
.montant
, devise
)
619 verbose_name
= "Rémunération"
620 verbose_name_plural
= "Rémunérations"
623 class Remuneration(Remuneration_
):
624 __doc__
= Remuneration_
.__doc__
629 class Contrat(Metadata
):
630 """Document juridique qui encadre la relation de travail d'un Employe
631 pour un Poste particulier. Pour un Dossier (qui documente cette
632 relation de travail) plusieurs contrats peuvent être associés.
634 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
636 type_contrat
= models
.ForeignKey('TypeContrat', db_column
='type_contrat',
638 verbose_name
="Type de contrat")
639 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
640 verbose_name
="Date de début")
641 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
642 verbose_name
="Date de fin",
643 null
=True, blank
=True)
646 ordering
= ['dossier__employe__nom_affichage']
647 verbose_name
= "Contrat"
648 verbose_name_plural
= "Contrats"
650 def __unicode__(self
):
651 return u
'%s - %s' % (self
.dossier
, self
.id)
653 # TODO? class ContratPiece(models.Model):
658 class Evenement_(Metadata
):
659 """Un Evenement sert à déclarer une situation temporaire (exceptionnelle)
660 d'un Dossier qui vient altérer des informations normales liées à un Dossier
661 (ex.: la Remuneration).
663 Ex.: congé de maternité, maladie...
665 Lors de ces situations exceptionnelles, l'Employe a un régime de travail
666 différent et une rémunération en conséquence. On souhaite toutefois
667 conserver le Dossier intact afin d'éviter une re-saisie des données lors
668 du retour à la normale.
670 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
672 nom
= models
.CharField(max_length
=255)
673 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
674 verbose_name
="Date de début")
675 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
676 verbose_name
="Date de fin",
677 null
=True, blank
=True)
682 verbose_name
= "Évènement"
683 verbose_name_plural
= "Évènements"
685 def __unicode__(self
):
686 return u
'%s' % (self
.nom
)
689 class Evenement(Evenement_
):
690 __doc__
= Evenement_
.__doc__
693 class EvenementRemuneration_(RemunerationMixin
):
694 """Structure de rémunération liée à un Evenement qui remplace
695 temporairement la Remuneration normale d'un Dossier, pour toute la durée
698 evenement
= models
.ForeignKey("Evenement", db_column
='evenement',
700 verbose_name
="Évènement")
701 # TODO : le champ dossier hérité de Remuneration doit être dérivé
702 # de l'Evenement associé
706 ordering
= ['evenement', 'type__nom', '-date_fin']
707 verbose_name
= "Évènement - rémunération"
708 verbose_name_plural
= "Évènements - rémunérations"
711 class EvenementRemuneration(EvenementRemuneration_
):
712 __doc__
= EvenementRemuneration_
.__doc__
718 class EvenementRemuneration(EvenementRemuneration_
):
719 __doc__
= EvenementRemuneration_
.__doc__
724 class FamilleEmploi(Metadata
):
725 """Catégorie utilisée dans la gestion des Postes.
726 Catégorie supérieure à TypePoste.
728 nom
= models
.CharField(max_length
=255)
732 verbose_name
= "Famille d'emploi"
733 verbose_name_plural
= "Familles d'emploi"
735 def __unicode__(self
):
736 return u
'%s' % (self
.nom
)
738 class TypePoste(Metadata
):
739 """Catégorie de Poste.
741 nom
= models
.CharField(max_length
=255)
742 nom_feminin
= models
.CharField(max_length
=255,
743 verbose_name
="Nom féminin")
745 is_responsable
= models
.BooleanField(default
=False,
746 verbose_name
="Poste de responsabilité")
747 famille_emploi
= models
.ForeignKey('FamilleEmploi',
748 db_column
='famille_emploi',
750 verbose_name
="Famille d'emploi")
754 verbose_name
= "Type de poste"
755 verbose_name_plural
= "Types de poste"
757 def __unicode__(self
):
758 return u
'%s' % (self
.nom
)
761 TYPE_PAIEMENT_CHOICES
= (
762 ('Régulier', 'Régulier'),
763 ('Ponctuel', 'Ponctuel'),
766 NATURE_REMUNERATION_CHOICES
= (
767 ('Accessoire', 'Accessoire'),
768 ('Charges', 'Charges'),
769 ('Indemnité', 'Indemnité'),
770 ('RAS', 'Rémunération autre source'),
771 ('Traitement', 'Traitement'),
774 class TypeRemuneration(Metadata
):
775 """Catégorie de Remuneration.
777 nom
= models
.CharField(max_length
=255)
778 type_paiement
= models
.CharField(max_length
=30,
779 choices
=TYPE_PAIEMENT_CHOICES
,
780 verbose_name
="Type de paiement")
781 nature_remuneration
= models
.CharField(max_length
=30,
782 choices
=NATURE_REMUNERATION_CHOICES
,
783 verbose_name
="Nature de la rémunération")
787 verbose_name
= "Type de rémunération"
788 verbose_name_plural
= "Types de rémunération"
790 def __unicode__(self
):
791 return u
'%s' % (self
.nom
)
793 class TypeRevalorisation(Metadata
):
794 """Justification du changement de la Remuneration.
795 (Actuellement utilisé dans aucun traitement informatique.)
797 nom
= models
.CharField(max_length
=255)
801 verbose_name
= "Type de revalorisation"
802 verbose_name_plural
= "Types de revalorisation"
804 def __unicode__(self
):
805 return u
'%s' % (self
.nom
)
807 class Service(Metadata
):
808 """Unité administrative où les Postes sont rattachés.
810 nom
= models
.CharField(max_length
=255)
814 verbose_name
= "Service"
815 verbose_name_plural
= "Services"
817 def __unicode__(self
):
818 return u
'%s' % (self
.nom
)
821 TYPE_ORGANISME_CHOICES
= (
822 ('MAD', 'Mise à disposition'),
823 ('DET', 'Détachement'),
826 class OrganismeBstg(Metadata
):
827 """Organisation d'où provient un Employe mis à disposition (MAD) de
828 ou détaché (DET) à l'AUF à titre gratuit.
830 (BSTG = bien et service à titre gratuit.)
832 nom
= models
.CharField(max_length
=255)
833 type = models
.CharField(max_length
=10, choices
=TYPE_ORGANISME_CHOICES
)
834 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code',
836 related_name
='organismes_bstg',
837 null
=True, blank
=True)
840 ordering
= ['type', 'nom']
841 verbose_name
= "Organisme BSTG"
842 verbose_name_plural
= "Organismes BSTG"
844 def __unicode__(self
):
845 return u
'%s (%s)' % (self
.nom
, self
.get_type_display())
847 class Statut(Metadata
):
848 """Statut de l'Employe dans le cadre d'un Dossier particulier.
851 code
= models
.CharField(max_length
=25, unique
=True)
852 nom
= models
.CharField(max_length
=255)
856 verbose_name
= "Statut d'employé"
857 verbose_name_plural
= "Statuts d'employé"
859 def __unicode__(self
):
860 return u
'%s : %s' % (self
.code
, self
.nom
)
863 TYPE_CLASSEMENT_CHOICES
= (
865 ('T', 'T - Technicien'),
866 ('P', 'P - Professionel'),
868 ('D', 'D - Direction'),
869 ('SO', 'SO - Sans objet [expatriés]'),
870 ('HG', 'HG - Hors grille [direction]'),
874 class Classement_(Metadata
):
875 """Éléments de classement de la
876 "Grille générique de classement hiérarchique".
878 Utile pour connaître, pour un Dossier, le salaire de base théorique lié au
879 classement dans la grille. Le classement donne le coefficient utilisé dans:
881 salaire de base = coefficient * valeur du point de l'Implantation du Poste
884 type = models
.CharField(max_length
=10, choices
=TYPE_CLASSEMENT_CHOICES
)
885 echelon
= models
.IntegerField(verbose_name
="Échelon")
886 degre
= models
.IntegerField(verbose_name
="Degré")
887 coefficient
= models
.FloatField(default
=0, verbose_name
="Coéfficient",
890 # annee # au lieu de date_debut et date_fin
891 commentaire
= models
.TextField(null
=True, blank
=True)
895 ordering
= ['type','echelon','degre','coefficient']
896 verbose_name
= "Classement"
897 verbose_name_plural
= "Classements"
899 def __unicode__(self
):
900 return u
'%s.%s.%s (%s)' % (self
.type, self
.echelon
, self
.degre
,
903 class Classement(Classement_
):
904 __doc__
= Classement_
.__doc__
907 class TauxChange_(Metadata
):
908 """Taux de change de la devise vers l'euro (EUR)
909 pour chaque année budgétaire.
912 devise
= models
.ForeignKey('Devise', db_column
='devise',
914 annee
= models
.IntegerField(verbose_name
="Année")
915 taux
= models
.FloatField(verbose_name
="Taux vers l'euro")
919 ordering
= ['-annee', 'devise__code']
920 verbose_name
= "Taux de change"
921 verbose_name_plural
= "Taux de change"
923 def __unicode__(self
):
924 return u
'%s : %s € (%s)' % (self
.devise
, self
.taux
, self
.annee
)
927 class TauxChange(TauxChange_
):
928 __doc__
= TauxChange_
.__doc__
931 class ValeurPoint_(Metadata
):
932 """Utile pour connaître, pour un Dossier, le salaire de base théorique lié
933 au classement dans la grille. La ValeurPoint s'obtient par l'implantation
934 du Poste de ce Dossier : dossier.poste.implantation (pseudo code).
936 salaire de base = coefficient * valeur du point de l'Implantation du Poste
938 valeur
= models
.FloatField(null
=True)
939 devise
= models
.ForeignKey('Devise', db_column
='devise', null
=True,
940 related_name
='+', default
=5)
941 implantation
= models
.ForeignKey(ref
.Implantation
,
942 db_column
='implantation',
943 related_name
='%(app_label)s_valeur_point')
945 annee
= models
.IntegerField()
948 ordering
= ['annee', 'implantation__nom']
951 verbose_name
= "Valeur du point"
952 verbose_name_plural
= "Valeurs du point"
954 # TODO : cette fonction n'était pas présente dans la branche dev, utilité?
955 def get_tauxchange_courant(self
):
957 Recherche le taux courant associé à la valeur d'un point.
958 Tous les taux de l'année courante sont chargés, pour optimiser un
959 affichage en liste. (On pourrait probablement améliorer le manager pour
960 lui greffer le taux courant sous forme de JOIN)
962 for tauxchange
in self
.tauxchange
:
963 if tauxchange
.implantation_id
== self
.implantation_id
:
967 def __unicode__(self
):
968 return u
'%s %s (%s)' % (self
.valeur
, self
.devise
, self
.annee
)
971 class ValeurPoint(ValeurPoint_
):
972 __doc__
= ValeurPoint_
.__doc__
975 class Devise(Metadata
):
978 code
= models
.CharField(max_length
=10, unique
=True)
979 nom
= models
.CharField(max_length
=255)
983 verbose_name
= "Devise"
984 verbose_name_plural
= "Devises"
986 def __unicode__(self
):
987 return u
'%s - %s' % (self
.code
, self
.nom
)
989 class TypeContrat(Metadata
):
992 nom
= models
.CharField(max_length
=255)
993 nom_long
= models
.CharField(max_length
=255)
997 verbose_name
= "Type de contrat"
998 verbose_name_plural
= "Types de contrat"
1000 def __unicode__(self
):
1001 return u
'%s' % (self
.nom
)
1006 class ResponsableImplantation(Metadata
):
1007 """Le responsable d'une implantation.
1008 Anciennement géré sur le Dossier du responsable.
1010 employe
= models
.ForeignKey('Employe', db_column
='employe',
1012 null
=True, blank
=True)
1013 implantation
= models
.ForeignKey(ref
.Implantation
,
1014 db_column
='implantation', related_name
='+',
1017 def __unicode__(self
):
1018 return u
'%s : %s' % (self
.implantation
, self
.employe
)
1021 ordering
= ['implantation__nom']
1022 verbose_name
= "Responsable d'implantation"
1023 verbose_name_plural
= "Responsables d'implantation"