1 # -=- encoding: utf-8 -=-
5 from django
.core
.files
.storage
import FileSystemStorage
6 from django
.db
import models
9 import auf
.django
.references
.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 Metadata(models
.Model
):
33 Metadata.actif = flag remplaçant la suppression.
34 actif == False : objet réputé supprimé.
36 actif
= models
.BooleanField(default
=True)
37 date_creation
= models
.DateField(auto_now_add
=True)
38 user_creation
= models
.ForeignKey('auth.User',
39 db_column
='user_creation', related_name
='+',
40 null
=True, blank
=True)
41 date_modification
= models
.DateField(auto_now
=True)
42 user_modification
= models
.ForeignKey('auth.User',
43 db_column
='user_modification', related_name
='+',
44 null
=True, blank
=True)
45 date_desactivation
= models
.DateField(null
=True, blank
=True)
46 user_desactivation
= models
.ForeignKey('auth.User',
47 db_column
='user_desactivation', related_name
='+',
48 null
=True, blank
=True)
53 class Commentaire(Metadata
):
54 texte
= models
.TextField()
55 owner
= models
.ForeignKey('auth.User', db_column
='owner', related_name
='+')
59 ordering
= ['-date_creation']
61 def __unicode__(self
):
62 return u
'%s' % (self
.texte
)
67 POSTE_APPEL_CHOICES
= (
68 ('interne', 'Interne'),
69 ('externe', 'Externe'),
72 class Poste_(Metadata
):
73 """Un Poste est un emploi (job) à combler dans une implantation.
74 Un Poste peut être comblé par un Employe, auquel cas un Dossier est créé.
75 Si on veut recruter 2 jardiniers, 2 Postes distincts existent.
78 nom
= models
.CharField(max_length
=255,
79 verbose_name
="Titre du poste", )
80 nom_feminin
= models
.CharField(max_length
=255,
81 verbose_name
="Titre du poste (au féminin)",
83 implantation
= models
.ForeignKey(ref
.Implantation
,
84 db_column
='implantation', related_name
='+')
85 type_poste
= models
.ForeignKey('TypePoste', db_column
='type_poste',
88 service
= models
.ForeignKey('Service', db_column
='service',
90 verbose_name
="Direction/Service/Pôle support",
91 default
=1) # default = Rectorat
92 responsable
= models
.ForeignKey('Poste', db_column
='responsable',
94 verbose_name
="Poste du responsable",
95 default
=149) # default = Recteur
98 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
99 default
=REGIME_TRAVAIL_DEFAULT
,
100 verbose_name
="Temps de travail",
101 help_text
="% du temps complet")
102 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
104 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
105 verbose_name
="Nb. heures par semaine")
108 local
= models
.BooleanField(verbose_name
="Local", default
=True,
110 expatrie
= models
.BooleanField(verbose_name
="Expatrié", default
=False,
112 mise_a_disposition
= models
.BooleanField(
113 verbose_name
="Mise à disposition",
115 appel
= models
.CharField(max_length
=10,
116 verbose_name
="Appel à candidature",
117 choices
=POSTE_APPEL_CHOICES
,
121 classement_min
= models
.ForeignKey('Classement',
122 db_column
='classement_min', related_name
='+',
123 null
=True, blank
=True)
124 classement_max
= models
.ForeignKey('Classement',
125 db_column
='classement_max', related_name
='+',
126 null
=True, blank
=True)
127 valeur_point_min
= models
.ForeignKey('ValeurPoint',
128 db_column
='valeur_point_min', related_name
='+',
129 null
=True, blank
=True)
130 valeur_point_max
= models
.ForeignKey('ValeurPoint',
131 db_column
='valeur_point_max', related_name
='+',
132 null
=True, blank
=True)
133 devise_min
= models
.ForeignKey('Devise', db_column
='devise_min',
134 related_name
='+', default
=5)
135 devise_max
= models
.ForeignKey('Devise', db_column
='devise_max',
136 related_name
='+', default
=5)
137 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
139 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
141 indemn_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
143 indemn_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
145 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
147 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
150 # Comparatifs de rémunération
151 devise_comparaison
= models
.ForeignKey('Devise',
152 db_column
='devise_comparaison',
155 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
156 null
=True, blank
=True)
157 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
158 null
=True, blank
=True)
159 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
160 null
=True, blank
=True)
161 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
162 null
=True, blank
=True)
163 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
164 null
=True, blank
=True)
165 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
166 null
=True, blank
=True)
167 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
168 null
=True, blank
=True)
169 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
170 null
=True, blank
=True)
171 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
172 null
=True, blank
=True)
173 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
174 null
=True, blank
=True)
177 justification
= models
.TextField(null
=True, blank
=True)
180 date_validation
= models
.DateTimeField(null
=True, blank
=True) # de dae
181 date_debut
= models
.DateField(verbose_name
="Date de début",
182 help_text
=HELP_TEXT_DATE
,
183 null
=True, blank
=True)
184 date_fin
= models
.DateField(verbose_name
="Date de fin",
185 help_text
=HELP_TEXT_DATE
,
186 null
=True, blank
=True)
190 ordering
= ['implantation__nom', 'nom']
191 verbose_name
= "Poste"
192 verbose_name_plural
= "Postes"
194 def __unicode__(self
):
195 representation
= u
'%s - %s [%s]' % (self
.implantation
, self
.nom
,
198 representation
= representation
+ u
' (vacant)'
199 return representation
202 # TODO : si existe un dossier actif pour ce poste, return False
203 # self.dossier_set.all() fonctionne pas
208 __doc__
= Poste_
.__doc__
211 POSTE_FINANCEMENT_CHOICES
= (
212 ('A', 'A - Frais de personnel'),
213 ('B', 'B - Projet(s)-Titre(s)'),
218 class PosteFinancement_(models
.Model
):
219 """Pour un Poste, structure d'informations décrivant comment on prévoit
222 poste
= models
.ForeignKey('Poste', db_column
='poste',
223 related_name
='%(app_label)s_financements')
224 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
225 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
226 help_text
="ex.: 33.33 % (décimale avec point)")
227 commentaire
= models
.TextField(
228 help_text
="Spécifiez la source de financement.")
234 def __unicode__(self
):
235 return u
'%s : %s %' % (self
.type, self
.pourcentage
)
238 class PosteFinancement(PosteFinancement_
):
239 __doc__
= PosteFinancement_
.__doc__
242 class PostePiece(models
.Model
):
243 """Documents relatifs au Poste.
244 Ex.: Description de poste
246 poste
= models
.ForeignKey('Poste', db_column
='poste',
247 related_name
='pieces')
248 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
249 fichier
= models
.FileField(verbose_name
="Fichier",
250 upload_to
=poste_piece_dispatch
,
251 storage
=storage_prive
)
256 def __unicode__(self
):
257 return u
'%s' % (self
.nom
)
259 class PosteComparaison(models
.Model
):
261 De la même manière qu'un dossier, un poste peut-être comparé à un autre poste.
263 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
264 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True)
265 nom
= models
.CharField(verbose_name
="Poste", max_length
=255, null
=True, blank
=True)
266 montant
= models
.IntegerField(null
=True)
267 devise
= models
.ForeignKey("Devise", default
=5, related_name
='+', null
=True, blank
=True)
269 def taux_devise(self
):
270 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee')
271 if len(liste_taux
) == 0:
272 raise Exception(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.implantation
))
274 return liste_taux
[0].taux
276 def montant_euros(self
):
277 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
280 class PosteCommentaire(Commentaire
):
281 poste
= models
.ForeignKey('Poste', db_column
='poste', related_name
='+')
290 SITUATION_CHOICES
= (
291 ('C', 'Célibataire'),
296 class Employe(Metadata
):
297 """Personne occupant ou ayant occupé un Poste. Un Employe aura autant de
298 Dossiers qu'il occupe ou a occupé de Postes.
300 Cette classe aurait pu avantageusement s'appeler Personne car la notion
301 d'employé n'a pas de sens si aucun Dossier n'existe pour une personne.
304 nom
= models
.CharField(max_length
=255)
305 prenom
= models
.CharField(max_length
=255, verbose_name
="Prénom")
306 nom_affichage
= models
.CharField(max_length
=255,
307 verbose_name
="Nom d'affichage",
308 null
=True, blank
=True)
309 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
310 db_column
='nationalite',
311 related_name
='employes_nationalite',
312 verbose_name
="Nationalité")
313 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
314 verbose_name
="Date de naissance",
315 null
=True, blank
=True)
316 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
319 situation_famille
= models
.CharField(max_length
=1,
320 choices
=SITUATION_CHOICES
,
321 verbose_name
="Situation familiale",
322 null
=True, blank
=True)
323 date_entree
= models
.DateField(verbose_name
="Date d'entrée à l'AUF",
324 help_text
=HELP_TEXT_DATE
,
325 null
=True, blank
=True)
328 tel_domicile
= models
.CharField(max_length
=255,
329 verbose_name
="Tél. domicile",
330 null
=True, blank
=True)
331 tel_cellulaire
= models
.CharField(max_length
=255,
332 verbose_name
="Tél. cellulaire",
333 null
=True, blank
=True)
334 adresse
= models
.CharField(max_length
=255, null
=True, blank
=True)
335 ville
= models
.CharField(max_length
=255, null
=True, blank
=True)
336 province
= models
.CharField(max_length
=255, null
=True, blank
=True)
337 code_postal
= models
.CharField(max_length
=255, null
=True, blank
=True)
338 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code', db_column
='pays',
339 related_name
='employes',
340 null
=True, blank
=True)
343 ordering
= ['nom_affichage','nom','prenom']
344 verbose_name
= "Employé"
345 verbose_name_plural
= "Employés"
347 def __unicode__(self
):
348 return u
'%s' % (self
.get_nom())
351 nom_affichage
= self
.nom_affichage
352 if not nom_affichage
:
353 nom_affichage
= u
'%s %s' % (self
.nom
.upper(), self
.prenom
)
356 class EmployePiece(models
.Model
):
357 """Documents relatifs à un employé.
360 employe
= models
.ForeignKey('Employe', db_column
='employe',
362 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
363 fichier
= models
.FileField(verbose_name
="Fichier",
364 upload_to
=dossier_piece_dispatch
,
365 storage
=storage_prive
)
370 def __unicode__(self
):
371 return u
'%s' % (self
.nom
)
373 class EmployeCommentaire(Commentaire
):
374 employe
= models
.ForeignKey('Employe', db_column
='employe',
378 LIEN_PARENTE_CHOICES
= (
379 ('Conjoint', 'Conjoint'),
380 ('Conjointe', 'Conjointe'),
385 class AyantDroit(Metadata
):
386 """Personne en relation avec un Employe.
389 nom
= models
.CharField(max_length
=255)
390 prenom
= models
.CharField(max_length
=255,
391 verbose_name
="Prénom",)
392 nom_affichage
= models
.CharField(max_length
=255,
393 verbose_name
="Nom d'affichage",
394 null
=True, blank
=True)
395 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
396 db_column
='nationalite',
397 related_name
='ayantdroits_nationalite',
398 verbose_name
="Nationalité")
399 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
400 verbose_name
="Date de naissance",
401 null
=True, blank
=True)
402 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
405 employe
= models
.ForeignKey('Employe', db_column
='employe',
406 related_name
='ayantdroits',
407 verbose_name
="Employé")
408 lien_parente
= models
.CharField(max_length
=10,
409 choices
=LIEN_PARENTE_CHOICES
,
410 verbose_name
="Lien de parenté",
411 null
=True, blank
=True)
414 ordering
= ['nom_affichage']
415 verbose_name
= "Ayant droit"
416 verbose_name_plural
= "Ayants droit"
418 def __unicode__(self
):
419 return u
'%s' % (self
.get_nom())
422 nom_affichage
= self
.nom_affichage
423 if not nom_affichage
:
424 nom_affichage
= u
'%s %s' % (self
.nom
.upper(), self
.prenom
)
427 class AyantDroitCommentaire(Commentaire
):
428 ayant_droit
= models
.ForeignKey('AyantDroit', db_column
='ayant_droit',
434 STATUT_RESIDENCE_CHOICES
= (
436 ('expat', 'Expatrié'),
439 COMPTE_COMPTA_CHOICES
= (
446 class Dossier_(Metadata
):
447 """Le Dossier regroupe les informations relatives à l'occupation
448 d'un Poste par un Employe. Un seul Dossier existe par Poste occupé
451 Plusieurs Contrats peuvent être associés au Dossier.
452 Une structure de Remuneration est rattachée au Dossier. Un Poste pour
453 lequel aucun Dossier n'existe est un poste vacant.
456 employe
= models
.ForeignKey('Employe', db_column
='employe',
458 verbose_name
="Employé")
459 poste
= models
.ForeignKey('Poste', db_column
='poste',
460 related_name
='+', editable
=False)
461 statut
= models
.ForeignKey('Statut', related_name
='+', default
=3)
462 organisme_bstg
= models
.ForeignKey('OrganismeBstg',
463 db_column
='organisme_bstg',
465 verbose_name
="Organisme",
466 help_text
="Si détaché (DET) ou \
467 mis à disposition (MAD), \
468 préciser l'organisme.",
469 null
=True, blank
=True)
472 remplacement
= models
.BooleanField(default
=False)
473 statut_residence
= models
.CharField(max_length
=10, default
='local',
474 verbose_name
="Statut",
475 choices
=STATUT_RESIDENCE_CHOICES
)
478 classement
= models
.ForeignKey('Classement', db_column
='classement',
480 null
=True, blank
=True)
481 regime_travail
= models
.DecimalField(max_digits
=12,
483 default
=REGIME_TRAVAIL_DEFAULT
,
484 verbose_name
="Régime de travail",
485 help_text
="% du temps complet")
486 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
488 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
489 verbose_name
="Nb. heures par semaine")
491 # Occupation du Poste par cet Employe (anciennement "mandat")
492 date_debut
= models
.DateField(verbose_name
="Date de début d'occupation \
494 help_text
=HELP_TEXT_DATE
)
495 date_fin
= models
.DateField(verbose_name
="Date de fin d'occupation \
497 help_text
=HELP_TEXT_DATE
,
498 null
=True, blank
=True)
505 ordering
= ['employe__nom_affichage', 'employe__nom', 'poste__nom']
506 verbose_name
= "Dossier"
507 verbose_name_plural
= "Dossiers"
509 def __unicode__(self
):
510 poste
= self
.poste
.nom
511 if self
.employe
.genre
== 'F':
512 poste
= self
.poste
.nom_feminin
513 return u
'%s - %s' % (self
.employe
, poste
)
516 class Dossier(Dossier_
):
517 __doc__
= Dossier_
.__doc__
520 class DossierPiece(models
.Model
):
521 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
522 Ex.: Lettre de motivation.
524 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
526 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
527 fichier
= models
.FileField(verbose_name
="Fichier",
528 upload_to
=dossier_piece_dispatch
,
529 storage
=storage_prive
)
534 def __unicode__(self
):
535 return u
'%s' % (self
.nom
)
537 class DossierCommentaire(Commentaire
):
538 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
541 class DossierComparaison(models
.Model
):
543 Photo d'une comparaison salariale au moment de l'embauche.
545 dossier
= models
.ForeignKey('Dossier', related_name
='comparaisons')
546 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True)
547 poste
= models
.CharField(max_length
=255, null
=True, blank
=True)
548 personne
= models
.CharField(max_length
=255, null
=True, blank
=True)
549 montant
= models
.IntegerField(null
=True)
550 devise
= models
.ForeignKey('Devise', default
=5, related_name
='+', null
=True, blank
=True)
552 def taux_devise(self
):
553 liste_taux
= self
.devise
.tauxchange_set
.order_by('-annee')
554 if len(liste_taux
) == 0:
555 raise Exception(u
"La devise %s n'a pas de taux pour l'implantation %s" % (self
.devise
, self
.dossier
.poste
.implantation
))
557 return liste_taux
[0].taux
559 def montant_euros(self
):
560 return round(float(self
.montant
) * float(self
.taux_devise()), 2)
565 class RemunerationMixin(Metadata
):
567 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
568 related_name
='%(app_label)s_%(class)s_remunerations')
569 type = models
.ForeignKey('TypeRemuneration', db_column
='type',
571 verbose_name
="Type de rémunération")
572 type_revalorisation
= models
.ForeignKey('TypeRevalorisation',
573 db_column
='type_revalorisation',
575 verbose_name
="Type de revalorisation",
576 null
=True, blank
=True)
577 montant
= models
.FloatField(null
=True, blank
=True,
579 # Annuel (12 mois, 52 semaines, 364 jours?)
580 devise
= models
.ForeignKey('Devise', to_field
='id',
581 db_column
='devise', related_name
='+',
583 # commentaire = precision
584 commentaire
= models
.CharField(max_length
=255, null
=True, blank
=True)
585 # date_debut = anciennement date_effectif
586 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
587 verbose_name
="Date de début",
588 null
=True, blank
=True)
589 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
590 verbose_name
="Date de fin",
591 null
=True, blank
=True)
595 ordering
= ['type__nom', '-date_fin']
597 def __unicode__(self
):
598 return u
'%s %s (%s)' % (self
.montant
, self
.devise
.code
, self
.type.nom
)
600 class Remuneration_(RemunerationMixin
):
601 """Structure de rémunération (données budgétaires) en situation normale
602 pour un Dossier. Si un Evenement existe, utiliser la structure de
603 rémunération EvenementRemuneration de cet événement.
606 def montant_mois(self
):
607 return round(self
.montant
/ 12, 2)
609 def taux_devise(self
):
610 return self
.devise
.tauxchange_set
.order_by('-annee').all()[0].taux
612 def montant_euro(self
):
613 return round(float(self
.montant
) / float(self
.taux_devise()), 2)
615 def montant_euro_mois(self
):
616 return round(self
.montant_euro() / 12, 2)
618 def __unicode__(self
):
620 devise
= self
.devise
.code
623 return "%s %s" % (self
.montant
, devise
)
627 verbose_name
= "Rémunération"
628 verbose_name_plural
= "Rémunérations"
631 class Remuneration(Remuneration_
):
632 __doc__
= Remuneration_
.__doc__
637 class Contrat(Metadata
):
638 """Document juridique qui encadre la relation de travail d'un Employe
639 pour un Poste particulier. Pour un Dossier (qui documente cette
640 relation de travail) plusieurs contrats peuvent être associés.
642 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
644 type_contrat
= models
.ForeignKey('TypeContrat', db_column
='type_contrat',
646 verbose_name
="Type de contrat")
647 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
648 verbose_name
="Date de début")
649 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
650 verbose_name
="Date de fin",
651 null
=True, blank
=True)
654 ordering
= ['dossier__employe__nom_affichage']
655 verbose_name
= "Contrat"
656 verbose_name_plural
= "Contrats"
658 def __unicode__(self
):
659 return u
'%s - %s' % (self
.dossier
, self
.id)
661 # TODO? class ContratPiece(models.Model):
666 class Evenement_(Metadata
):
667 """Un Evenement sert à déclarer une situation temporaire (exceptionnelle)
668 d'un Dossier qui vient altérer des informations normales liées à un Dossier
669 (ex.: la Remuneration).
671 Ex.: congé de maternité, maladie...
673 Lors de ces situations exceptionnelles, l'Employe a un régime de travail
674 différent et une rémunération en conséquence. On souhaite toutefois
675 conserver le Dossier intact afin d'éviter une re-saisie des données lors
676 du retour à la normale.
678 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
680 nom
= models
.CharField(max_length
=255)
681 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
682 verbose_name
="Date de début")
683 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
684 verbose_name
="Date de fin",
685 null
=True, blank
=True)
690 verbose_name
= "Évènement"
691 verbose_name_plural
= "Évènements"
693 def __unicode__(self
):
694 return u
'%s' % (self
.nom
)
697 class Evenement(Evenement_
):
698 __doc__
= Evenement_
.__doc__
701 class EvenementRemuneration_(RemunerationMixin
):
702 """Structure de rémunération liée à un Evenement qui remplace
703 temporairement la Remuneration normale d'un Dossier, pour toute la durée
706 evenement
= models
.ForeignKey("Evenement", db_column
='evenement',
708 verbose_name
="Évènement")
709 # TODO : le champ dossier hérité de Remuneration doit être dérivé
710 # de l'Evenement associé
714 ordering
= ['evenement', 'type__nom', '-date_fin']
715 verbose_name
= "Évènement - rémunération"
716 verbose_name_plural
= "Évènements - rémunérations"
719 class EvenementRemuneration(EvenementRemuneration_
):
720 __doc__
= EvenementRemuneration_
.__doc__
725 class FamilleEmploi(Metadata
):
726 """Catégorie utilisée dans la gestion des Postes.
727 Catégorie supérieure à TypePoste.
729 nom
= models
.CharField(max_length
=255)
733 verbose_name
= "Famille d'emploi"
734 verbose_name_plural
= "Familles d'emploi"
736 def __unicode__(self
):
737 return u
'%s' % (self
.nom
)
739 class TypePoste(Metadata
):
740 """Catégorie de Poste.
742 nom
= models
.CharField(max_length
=255)
743 nom_feminin
= models
.CharField(max_length
=255,
744 verbose_name
="Nom féminin")
746 is_responsable
= models
.BooleanField(default
=False,
747 verbose_name
="Poste de responsabilité")
748 famille_emploi
= models
.ForeignKey('FamilleEmploi',
749 db_column
='famille_emploi',
751 verbose_name
="Famille d'emploi")
755 verbose_name
= "Type de poste"
756 verbose_name_plural
= "Types de poste"
758 def __unicode__(self
):
759 return u
'%s' % (self
.nom
)
762 TYPE_PAIEMENT_CHOICES
= (
763 ('Régulier', 'Régulier'),
764 ('Ponctuel', 'Ponctuel'),
767 NATURE_REMUNERATION_CHOICES
= (
768 ('Accessoire', 'Accessoire'),
769 ('Charges', 'Charges'),
770 ('Indemnité', 'Indemnité'),
771 ('RAS', 'Rémunération autre source'),
772 ('Traitement', 'Traitement'),
775 class TypeRemuneration(Metadata
):
776 """Catégorie de Remuneration.
778 nom
= models
.CharField(max_length
=255)
779 type_paiement
= models
.CharField(max_length
=30,
780 choices
=TYPE_PAIEMENT_CHOICES
,
781 verbose_name
="Type de paiement")
782 nature_remuneration
= models
.CharField(max_length
=30,
783 choices
=NATURE_REMUNERATION_CHOICES
,
784 verbose_name
="Nature de la rémunération")
788 verbose_name
= "Type de rémunération"
789 verbose_name_plural
= "Types de rémunération"
791 def __unicode__(self
):
792 return u
'%s' % (self
.nom
)
794 class TypeRevalorisation(Metadata
):
795 """Justification du changement de la Remuneration.
796 (Actuellement utilisé dans aucun traitement informatique.)
798 nom
= models
.CharField(max_length
=255)
802 verbose_name
= "Type de revalorisation"
803 verbose_name_plural
= "Types de revalorisation"
805 def __unicode__(self
):
806 return u
'%s' % (self
.nom
)
808 class Service(Metadata
):
809 """Unité administrative où les Postes sont rattachés.
811 nom
= models
.CharField(max_length
=255)
815 verbose_name
= "Service"
816 verbose_name_plural
= "Services"
818 def __unicode__(self
):
819 return u
'%s' % (self
.nom
)
822 TYPE_ORGANISME_CHOICES
= (
823 ('MAD', 'Mise à disposition'),
824 ('DET', 'Détachement'),
827 class OrganismeBstg(Metadata
):
828 """Organisation d'où provient un Employe mis à disposition (MAD) de
829 ou détaché (DET) à l'AUF à titre gratuit.
831 (BSTG = bien et service à titre gratuit.)
833 nom
= models
.CharField(max_length
=255)
834 type = models
.CharField(max_length
=10, choices
=TYPE_ORGANISME_CHOICES
)
835 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code',
837 related_name
='organismes_bstg',
838 null
=True, blank
=True)
841 ordering
= ['type', 'nom']
842 verbose_name
= "Organisme BSTG"
843 verbose_name_plural
= "Organismes BSTG"
845 def __unicode__(self
):
846 return u
'%s (%s)' % (self
.nom
, self
.get_type_display())
848 class Statut(Metadata
):
849 """Statut de l'Employe dans le cadre d'un Dossier particulier.
852 code
= models
.CharField(max_length
=25, unique
=True)
853 nom
= models
.CharField(max_length
=255)
857 verbose_name
= "Statut d'employé"
858 verbose_name_plural
= "Statuts d'employé"
860 def __unicode__(self
):
861 return u
'%s : %s' % (self
.code
, self
.nom
)
864 TYPE_CLASSEMENT_CHOICES
= (
866 ('T', 'T - Technicien'),
867 ('P', 'P - Professionel'),
869 ('D', 'D - Direction'),
870 ('SO', 'SO - Sans objet [expatriés]'),
871 ('HG', 'HG - Hors grille [direction]'),
875 class Classement_(Metadata
):
876 """Éléments de classement de la
877 "Grille générique de classement hiérarchique".
879 Utile pour connaître, pour un Dossier, le salaire de base théorique lié au
880 classement dans la grille. Le classement donne le coefficient utilisé dans:
882 salaire de base = coefficient * valeur du point de l'Implantation du Poste
885 type = models
.CharField(max_length
=10, choices
=TYPE_CLASSEMENT_CHOICES
)
886 echelon
= models
.IntegerField(verbose_name
="Échelon")
887 degre
= models
.IntegerField(verbose_name
="Degré")
888 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()
939 devise
= models
.ForeignKey('Devise', db_column
='devise',
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()
950 verbose_name
= "Valeur du point"
951 verbose_name_plural
= "Valeurs du point"
953 def __unicode__(self
):
954 return u
'%s %s (%s)' % (self
.valeur
, self
.devise
, self
.annee
)
957 class ValeurPoint(ValeurPoint_
):
958 __doc__
= ValeurPoint_
.__doc__
961 class Devise(Metadata
):
964 code
= models
.CharField(max_length
=10, unique
=True)
965 nom
= models
.CharField(max_length
=255)
969 verbose_name
= "Devise"
970 verbose_name_plural
= "Devises"
972 def __unicode__(self
):
973 return u
'%s - %s' % (self
.code
, self
.nom
)
975 class TypeContrat(Metadata
):
978 nom
= models
.CharField(max_length
=255)
979 nom_long
= models
.CharField(max_length
=255)
983 verbose_name
= "Type de contrat"
984 verbose_name_plural
= "Types de contrat"
986 def __unicode__(self
):
987 return u
'%s' % (self
.nom
)
992 class ResponsableImplantation(Metadata
):
993 """Le responsable d'une implantation.
994 Anciennement géré sur le Dossier du responsable.
996 employe
= models
.ForeignKey('Employe', db_column
='employe',
998 null
=True, blank
=True)
999 implantation
= models
.ForeignKey(ref
.Implantation
,
1000 db_column
='implantation', related_name
='+',
1003 def __unicode__(self
):
1004 return u
'%s : %s' % (self
.implantation
, self
.employe
)
1007 ordering
= ['implantation__nom']
1008 verbose_name
= "Responsable d'implantation"
1009 verbose_name_plural
= "Responsables d'implantation"