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 Metadata(models
.Model
):
33 Metadata.actif = flag remplaçant la suppression.
34 supprime == True : objet réputé supprimé.
36 actif
= models
.BooleanField(default
=True)
37 supprime
= models
.BooleanField(default
=False)
38 date_creation
= models
.DateField(auto_now_add
=True)
39 user_creation
= models
.ForeignKey('auth.User',
40 db_column
='user_creation', related_name
='+',
41 null
=True, blank
=True)
42 date_modification
= models
.DateField(auto_now
=True)
43 user_modification
= models
.ForeignKey('auth.User',
44 db_column
='user_modification', related_name
='+',
45 null
=True, blank
=True)
46 date_desactivation
= models
.DateField(null
=True, blank
=True)
47 user_desactivation
= models
.ForeignKey('auth.User',
48 db_column
='user_desactivation', related_name
='+',
49 null
=True, blank
=True)
54 class Commentaire(Metadata
):
55 texte
= models
.TextField()
56 owner
= models
.ForeignKey('auth.User', db_column
='owner', related_name
='+')
60 ordering
= ['-date_creation']
62 def __unicode__(self
):
63 return u
'%s' % (self
.texte
)
68 POSTE_APPEL_CHOICES
= (
69 ('interne', 'Interne'),
70 ('externe', 'Externe'),
73 class Poste_(Metadata
):
74 """Un Poste est un emploi (job) à combler dans une implantation.
75 Un Poste peut être comblé par un Employe, auquel cas un Dossier est créé.
76 Si on veut recruter 2 jardiniers, 2 Postes distincts existent.
79 nom
= models
.CharField(max_length
=255,
80 verbose_name
="Titre du poste", )
81 nom_feminin
= models
.CharField(max_length
=255,
82 verbose_name
="Titre du poste (au féminin)",
84 implantation
= models
.ForeignKey(ref
.Implantation
,
85 db_column
='implantation', related_name
='+')
86 type_poste
= models
.ForeignKey('TypePoste', db_column
='type_poste',
89 service
= models
.ForeignKey('Service', db_column
='service', null
=True,
91 verbose_name
="Direction/Service/Pôle support",
92 default
=1) # default = Rectorat
93 responsable
= models
.ForeignKey('Poste', db_column
='responsable',
94 related_name
='+', null
=True,
95 verbose_name
="Poste du responsable",
96 default
=149) # default = Recteur
99 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
100 default
=REGIME_TRAVAIL_DEFAULT
, null
=True,
101 verbose_name
="Temps de travail",
102 help_text
="% du temps complet")
103 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
104 decimal_places
=2, null
=True,
105 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
106 verbose_name
="Nb. heures par semaine")
109 local
= models
.NullBooleanField(verbose_name
="Local", default
=True,
110 null
=True, blank
=True)
111 expatrie
= models
.NullBooleanField(verbose_name
="Expatrié", default
=False,
112 null
=True, blank
=True)
113 mise_a_disposition
= models
.NullBooleanField(
114 verbose_name
="Mise à disposition",
115 null
=True, default
=False)
116 appel
= models
.CharField(max_length
=10, null
=True,
117 verbose_name
="Appel à candidature",
118 choices
=POSTE_APPEL_CHOICES
,
122 classement_min
= models
.ForeignKey('Classement',
123 db_column
='classement_min', related_name
='+',
124 null
=True, blank
=True)
125 classement_max
= models
.ForeignKey('Classement',
126 db_column
='classement_max', related_name
='+',
127 null
=True, blank
=True)
128 valeur_point_min
= models
.ForeignKey('ValeurPoint',
129 db_column
='valeur_point_min', related_name
='+',
130 null
=True, blank
=True)
131 valeur_point_max
= models
.ForeignKey('ValeurPoint',
132 db_column
='valeur_point_max', related_name
='+',
133 null
=True, blank
=True)
134 devise_min
= models
.ForeignKey('Devise', db_column
='devise_min', null
=True,
135 related_name
='+', default
=5)
136 devise_max
= models
.ForeignKey('Devise', db_column
='devise_max', null
=True,
137 related_name
='+', default
=5)
138 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
139 null
=True, default
=0)
140 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
141 null
=True, default
=0)
142 indemn_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
143 null
=True, default
=0)
144 indemn_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
145 null
=True, default
=0)
146 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
147 null
=True, default
=0)
148 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
149 null
=True, default
=0)
151 # Comparatifs de rémunération
152 devise_comparaison
= models
.ForeignKey('Devise', null
=True,
153 db_column
='devise_comparaison',
156 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
157 null
=True, blank
=True)
158 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
159 null
=True, blank
=True)
160 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
161 null
=True, blank
=True)
162 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
163 null
=True, blank
=True)
164 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
165 null
=True, blank
=True)
166 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
167 null
=True, blank
=True)
168 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
169 null
=True, blank
=True)
170 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
171 null
=True, blank
=True)
172 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
173 null
=True, blank
=True)
174 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
175 null
=True, blank
=True)
178 justification
= models
.TextField(null
=True, blank
=True)
181 date_validation
= models
.DateTimeField(null
=True, blank
=True) # de dae
182 date_debut
= models
.DateField(verbose_name
="Date de début", null
=True,
183 help_text
=HELP_TEXT_DATE
)
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__
212 __doc__
= Poste_
.__doc__
215 POSTE_FINANCEMENT_CHOICES
= (
216 ('A', 'A - Frais de personnel'),
217 ('B', 'B - Projet(s)-Titre(s)'),
222 class PosteFinancement_(models
.Model
):
223 """Pour un Poste, structure d'informations décrivant comment on prévoit
226 poste
= models
.ForeignKey('Poste', db_column
='poste',
227 related_name
='%(app_label)s_financements')
228 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
229 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
230 help_text
="ex.: 33.33 % (décimale avec point)")
231 commentaire
= models
.TextField(
232 help_text
="Spécifiez la source de financement.")
238 def __unicode__(self
):
239 return u
'%s : %s %' % (self
.type, self
.pourcentage
)
242 class PosteFinancement(PosteFinancement_
):
243 __doc__
= PosteFinancement_
.__doc__
246 class PostePiece(models
.Model
):
247 """Documents relatifs au Poste.
248 Ex.: Description de poste
250 poste
= models
.ForeignKey('Poste', db_column
='poste',
251 related_name
='pieces')
252 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
253 fichier
= models
.FileField(verbose_name
="Fichier",
254 upload_to
=poste_piece_dispatch
,
255 storage
=storage_prive
)
260 def __unicode__(self
):
261 return u
'%s' % (self
.nom
)
263 class PosteComparaison(models
.Model
):
265 De la même manière qu'un dossier, un poste peut-être comparé à un autre poste.
267 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
268 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True, related_name
="+")
269 nom
= models
.CharField(verbose_name
="Poste", max_length
=255, null
=True, blank
=True)
270 montant
= models
.IntegerField(null
=True)
271 devise
= models
.ForeignKey("Devise", default
=5, related_name
='+', null
=True, blank
=True)
272 montant_euros
= models
.IntegerField(null
=True)
275 class PosteCommentaire(Commentaire
):
276 poste
= models
.ForeignKey('Poste', db_column
='poste', related_name
='+')
285 SITUATION_CHOICES
= (
286 ('C', 'Célibataire'),
291 class Employe(Metadata
):
292 """Personne occupant ou ayant occupé un Poste. Un Employe aura autant de
293 Dossiers qu'il occupe ou a occupé de Postes.
295 Cette classe aurait pu avantageusement s'appeler Personne car la notion
296 d'employé n'a pas de sens si aucun Dossier n'existe pour une personne.
299 nom
= models
.CharField(max_length
=255)
300 prenom
= models
.CharField(max_length
=255, verbose_name
="Prénom")
301 nom_affichage
= models
.CharField(max_length
=255,
302 verbose_name
="Nom d'affichage",
303 null
=True, blank
=True)
304 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
305 db_column
='nationalite',
306 related_name
='employes_nationalite',
307 verbose_name
="Nationalité")
308 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
309 verbose_name
="Date de naissance",
310 null
=True, blank
=True)
311 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
314 situation_famille
= models
.CharField(max_length
=1,
315 choices
=SITUATION_CHOICES
,
316 verbose_name
="Situation familiale",
317 null
=True, blank
=True)
318 date_entree
= models
.DateField(verbose_name
="Date d'entrée à l'AUF",
319 help_text
=HELP_TEXT_DATE
,
320 null
=True, blank
=True)
323 tel_domicile
= models
.CharField(max_length
=255,
324 verbose_name
="Tél. domicile",
325 null
=True, blank
=True)
326 tel_cellulaire
= models
.CharField(max_length
=255,
327 verbose_name
="Tél. cellulaire",
328 null
=True, blank
=True)
329 adresse
= models
.CharField(max_length
=255, null
=True, blank
=True)
330 ville
= models
.CharField(max_length
=255, null
=True, blank
=True)
331 province
= models
.CharField(max_length
=255, null
=True, blank
=True)
332 code_postal
= models
.CharField(max_length
=255, null
=True, blank
=True)
333 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code', db_column
='pays',
334 related_name
='employes',
335 null
=True, blank
=True)
338 ordering
= ['nom_affichage','nom','prenom']
339 verbose_name
= "Employé"
340 verbose_name_plural
= "Employés"
342 def __unicode__(self
):
343 return u
'%s' % (self
.get_nom())
346 nom_affichage
= self
.nom_affichage
347 if not nom_affichage
:
348 nom_affichage
= u
'%s %s' % (self
.nom
.upper(), self
.prenom
)
351 class EmployePiece(models
.Model
):
352 """Documents relatifs à un employé.
355 employe
= models
.ForeignKey('Employe', db_column
='employe',
357 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
358 fichier
= models
.FileField(verbose_name
="Fichier",
359 upload_to
=dossier_piece_dispatch
,
360 storage
=storage_prive
)
365 def __unicode__(self
):
366 return u
'%s' % (self
.nom
)
368 class EmployeCommentaire(Commentaire
):
369 employe
= models
.ForeignKey('Employe', db_column
='employe',
373 LIEN_PARENTE_CHOICES
= (
374 ('Conjoint', 'Conjoint'),
375 ('Conjointe', 'Conjointe'),
380 class AyantDroit(Metadata
):
381 """Personne en relation avec un Employe.
384 nom
= models
.CharField(max_length
=255)
385 prenom
= models
.CharField(max_length
=255,
386 verbose_name
="Prénom",)
387 nom_affichage
= models
.CharField(max_length
=255,
388 verbose_name
="Nom d'affichage",
389 null
=True, blank
=True)
390 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
391 db_column
='nationalite',
392 related_name
='ayantdroits_nationalite',
393 verbose_name
="Nationalité")
394 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
395 verbose_name
="Date de naissance",
396 null
=True, blank
=True)
397 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
400 employe
= models
.ForeignKey('Employe', db_column
='employe',
401 related_name
='ayantdroits',
402 verbose_name
="Employé")
403 lien_parente
= models
.CharField(max_length
=10,
404 choices
=LIEN_PARENTE_CHOICES
,
405 verbose_name
="Lien de parenté",
406 null
=True, blank
=True)
409 ordering
= ['nom_affichage']
410 verbose_name
= "Ayant droit"
411 verbose_name_plural
= "Ayants droit"
413 def __unicode__(self
):
414 return u
'%s' % (self
.get_nom())
417 nom_affichage
= self
.nom_affichage
418 if not nom_affichage
:
419 nom_affichage
= u
'%s %s' % (self
.nom
.upper(), self
.prenom
)
422 class AyantDroitCommentaire(Commentaire
):
423 ayant_droit
= models
.ForeignKey('AyantDroit', db_column
='ayant_droit',
429 STATUT_RESIDENCE_CHOICES
= (
431 ('expat', 'Expatrié'),
434 COMPTE_COMPTA_CHOICES
= (
440 class Dossier_(Metadata
):
441 """Le Dossier regroupe les informations relatives à l'occupation
442 d'un Poste par un Employe. Un seul Dossier existe par Poste occupé
445 Plusieurs Contrats peuvent être associés au Dossier.
446 Une structure de Remuneration est rattachée au Dossier. Un Poste pour
447 lequel aucun Dossier n'existe est un poste vacant.
450 employe
= models
.ForeignKey('Employe', db_column
='employe',
452 verbose_name
="Employé")
453 poste
= models
.ForeignKey('Poste', db_column
='poste',
454 related_name
='+', editable
=False)
455 statut
= models
.ForeignKey('Statut', related_name
='+', default
=3,
457 organisme_bstg
= models
.ForeignKey('OrganismeBstg',
458 db_column
='organisme_bstg',
460 verbose_name
="Organisme",
461 help_text
="Si détaché (DET) ou \
462 mis à disposition (MAD), \
463 préciser l'organisme.",
464 null
=True, blank
=True)
467 remplacement
= models
.BooleanField(default
=False)
468 statut_residence
= models
.CharField(max_length
=10, default
='local',
469 verbose_name
="Statut", null
=True,
470 choices
=STATUT_RESIDENCE_CHOICES
)
473 classement
= models
.ForeignKey('Classement', db_column
='classement',
475 null
=True, blank
=True)
476 regime_travail
= models
.DecimalField(max_digits
=12, null
=True,
478 default
=REGIME_TRAVAIL_DEFAULT
,
479 verbose_name
="Régime de travail",
480 help_text
="% du temps complet")
481 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
482 decimal_places
=2, null
=True,
483 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
484 verbose_name
="Nb. heures par semaine")
486 # Occupation du Poste par cet Employe (anciennement "mandat")
487 date_debut
= models
.DateField(verbose_name
="Date de début d'occupation \
489 help_text
=HELP_TEXT_DATE
)
490 date_fin
= models
.DateField(verbose_name
="Date de fin d'occupation \
492 help_text
=HELP_TEXT_DATE
,
493 null
=True, blank
=True)
500 ordering
= ['employe__nom_affichage', 'employe__nom', 'poste__nom']
501 verbose_name
= "Dossier"
502 verbose_name_plural
= "Dossiers"
504 def __unicode__(self
):
505 poste
= self
.poste
.nom
506 if self
.employe
.genre
== 'F':
507 poste
= self
.poste
.nom_feminin
508 return u
'%s - %s' % (self
.employe
, poste
)
511 class Dossier(Dossier_
):
512 __doc__
= Dossier_
.__doc__
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',
544 class RemunerationMixin(Metadata
):
546 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
547 related_name
='%(app_label)s_%(class)s_remunerations')
548 type = models
.ForeignKey('TypeRemuneration', db_column
='type',
550 verbose_name
="Type de rémunération")
551 type_revalorisation
= models
.ForeignKey('TypeRevalorisation',
552 db_column
='type_revalorisation',
554 verbose_name
="Type de revalorisation",
555 null
=True, blank
=True)
556 montant
= models
.FloatField(null
=True, blank
=True,
558 # Annuel (12 mois, 52 semaines, 364 jours?)
559 devise
= models
.ForeignKey('Devise', to_field
='id',
560 db_column
='devise', related_name
='+',
562 # commentaire = precision
563 commentaire
= models
.CharField(max_length
=255, null
=True, blank
=True)
564 # date_debut = anciennement date_effectif
565 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
566 verbose_name
="Date de début",
567 null
=True, blank
=True)
568 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
569 verbose_name
="Date de fin",
570 null
=True, blank
=True)
574 ordering
= ['type__nom', '-date_fin']
576 def __unicode__(self
):
577 return u
'%s %s (%s)' % (self
.montant
, self
.devise
.code
, self
.type.nom
)
579 class Remuneration_(RemunerationMixin
):
580 """Structure de rémunération (données budgétaires) en situation normale
581 pour un Dossier. Si un Evenement existe, utiliser la structure de
582 rémunération EvenementRemuneration de cet événement.
585 def montant_mois(self
):
586 return round(self
.montant
/ 12, 2)
588 def taux_devise(self
):
589 return self
.devise
.tauxchange_set
.order_by('-annee').all()[0].taux
591 def montant_euro(self
):
592 return round(float(self
.montant
) / float(self
.taux_devise()), 2)
594 def montant_euro_mois(self
):
595 return round(self
.montant_euro() / 12, 2)
597 def __unicode__(self
):
599 devise
= self
.devise
.code
602 return "%s %s" % (self
.montant
, devise
)
606 verbose_name
= "Rémunération"
607 verbose_name_plural
= "Rémunérations"
610 class Remuneration(Remuneration_
):
611 __doc__
= Remuneration_
.__doc__
616 class Contrat(Metadata
):
617 """Document juridique qui encadre la relation de travail d'un Employe
618 pour un Poste particulier. Pour un Dossier (qui documente cette
619 relation de travail) plusieurs contrats peuvent être associés.
621 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
623 type_contrat
= models
.ForeignKey('TypeContrat', db_column
='type_contrat',
625 verbose_name
="Type de contrat")
626 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
627 verbose_name
="Date de début")
628 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
629 verbose_name
="Date de fin",
630 null
=True, blank
=True)
633 ordering
= ['dossier__employe__nom_affichage']
634 verbose_name
= "Contrat"
635 verbose_name_plural
= "Contrats"
637 def __unicode__(self
):
638 return u
'%s - %s' % (self
.dossier
, self
.id)
640 # TODO? class ContratPiece(models.Model):
645 class Evenement_(Metadata
):
646 """Un Evenement sert à déclarer une situation temporaire (exceptionnelle)
647 d'un Dossier qui vient altérer des informations normales liées à un Dossier
648 (ex.: la Remuneration).
650 Ex.: congé de maternité, maladie...
652 Lors de ces situations exceptionnelles, l'Employe a un régime de travail
653 différent et une rémunération en conséquence. On souhaite toutefois
654 conserver le Dossier intact afin d'éviter une re-saisie des données lors
655 du retour à la normale.
657 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
659 nom
= models
.CharField(max_length
=255)
660 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
661 verbose_name
="Date de début")
662 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
663 verbose_name
="Date de fin",
664 null
=True, blank
=True)
669 verbose_name
= "Évènement"
670 verbose_name_plural
= "Évènements"
672 def __unicode__(self
):
673 return u
'%s' % (self
.nom
)
676 class Evenement(Evenement_
):
677 __doc__
= Evenement_
.__doc__
680 class EvenementRemuneration_(RemunerationMixin
):
681 """Structure de rémunération liée à un Evenement qui remplace
682 temporairement la Remuneration normale d'un Dossier, pour toute la durée
685 evenement
= models
.ForeignKey("Evenement", db_column
='evenement',
687 verbose_name
="Évènement")
688 # TODO : le champ dossier hérité de Remuneration doit être dérivé
689 # de l'Evenement associé
693 ordering
= ['evenement', 'type__nom', '-date_fin']
694 verbose_name
= "Évènement - rémunération"
695 verbose_name_plural
= "Évènements - rémunérations"
698 class EvenementRemuneration(EvenementRemuneration_
):
699 __doc__
= EvenementRemuneration_
.__doc__
705 class EvenementRemuneration(EvenementRemuneration_
):
706 __doc__
= EvenementRemuneration_
.__doc__
711 class FamilleEmploi(Metadata
):
712 """Catégorie utilisée dans la gestion des Postes.
713 Catégorie supérieure à TypePoste.
715 nom
= models
.CharField(max_length
=255)
719 verbose_name
= "Famille d'emploi"
720 verbose_name_plural
= "Familles d'emploi"
722 def __unicode__(self
):
723 return u
'%s' % (self
.nom
)
725 class TypePoste(Metadata
):
726 """Catégorie de Poste.
728 nom
= models
.CharField(max_length
=255)
729 nom_feminin
= models
.CharField(max_length
=255,
730 verbose_name
="Nom féminin")
732 is_responsable
= models
.BooleanField(default
=False,
733 verbose_name
="Poste de responsabilité")
734 famille_emploi
= models
.ForeignKey('FamilleEmploi',
735 db_column
='famille_emploi',
737 verbose_name
="Famille d'emploi")
741 verbose_name
= "Type de poste"
742 verbose_name_plural
= "Types de poste"
744 def __unicode__(self
):
745 return u
'%s' % (self
.nom
)
748 TYPE_PAIEMENT_CHOICES
= (
749 ('Régulier', 'Régulier'),
750 ('Ponctuel', 'Ponctuel'),
753 NATURE_REMUNERATION_CHOICES
= (
754 ('Accessoire', 'Accessoire'),
755 ('Charges', 'Charges'),
756 ('Indemnité', 'Indemnité'),
757 ('RAS', 'Rémunération autre source'),
758 ('Traitement', 'Traitement'),
761 class TypeRemuneration(Metadata
):
762 """Catégorie de Remuneration.
764 nom
= models
.CharField(max_length
=255)
765 type_paiement
= models
.CharField(max_length
=30,
766 choices
=TYPE_PAIEMENT_CHOICES
,
767 verbose_name
="Type de paiement")
768 nature_remuneration
= models
.CharField(max_length
=30,
769 choices
=NATURE_REMUNERATION_CHOICES
,
770 verbose_name
="Nature de la rémunération")
774 verbose_name
= "Type de rémunération"
775 verbose_name_plural
= "Types de rémunération"
777 def __unicode__(self
):
778 return u
'%s' % (self
.nom
)
780 class TypeRevalorisation(Metadata
):
781 """Justification du changement de la Remuneration.
782 (Actuellement utilisé dans aucun traitement informatique.)
784 nom
= models
.CharField(max_length
=255)
788 verbose_name
= "Type de revalorisation"
789 verbose_name_plural
= "Types de revalorisation"
791 def __unicode__(self
):
792 return u
'%s' % (self
.nom
)
794 class Service(Metadata
):
795 """Unité administrative où les Postes sont rattachés.
797 nom
= models
.CharField(max_length
=255)
801 verbose_name
= "Service"
802 verbose_name_plural
= "Services"
804 def __unicode__(self
):
805 return u
'%s' % (self
.nom
)
808 TYPE_ORGANISME_CHOICES
= (
809 ('MAD', 'Mise à disposition'),
810 ('DET', 'Détachement'),
813 class OrganismeBstg(Metadata
):
814 """Organisation d'où provient un Employe mis à disposition (MAD) de
815 ou détaché (DET) à l'AUF à titre gratuit.
817 (BSTG = bien et service à titre gratuit.)
819 nom
= models
.CharField(max_length
=255)
820 type = models
.CharField(max_length
=10, choices
=TYPE_ORGANISME_CHOICES
)
821 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code',
823 related_name
='organismes_bstg',
824 null
=True, blank
=True)
827 ordering
= ['type', 'nom']
828 verbose_name
= "Organisme BSTG"
829 verbose_name_plural
= "Organismes BSTG"
831 def __unicode__(self
):
832 return u
'%s (%s)' % (self
.nom
, self
.get_type_display())
834 class Statut(Metadata
):
835 """Statut de l'Employe dans le cadre d'un Dossier particulier.
838 code
= models
.CharField(max_length
=25, unique
=True)
839 nom
= models
.CharField(max_length
=255)
843 verbose_name
= "Statut d'employé"
844 verbose_name_plural
= "Statuts d'employé"
846 def __unicode__(self
):
847 return u
'%s : %s' % (self
.code
, self
.nom
)
850 TYPE_CLASSEMENT_CHOICES
= (
852 ('T', 'T - Technicien'),
853 ('P', 'P - Professionel'),
855 ('D', 'D - Direction'),
856 ('SO', 'SO - Sans objet [expatriés]'),
857 ('HG', 'HG - Hors grille [direction]'),
861 class Classement_(Metadata
):
862 """Éléments de classement de la
863 "Grille générique de classement hiérarchique".
865 Utile pour connaître, pour un Dossier, le salaire de base théorique lié au
866 classement dans la grille. Le classement donne le coefficient utilisé dans:
868 salaire de base = coefficient * valeur du point de l'Implantation du Poste
871 type = models
.CharField(max_length
=10, choices
=TYPE_CLASSEMENT_CHOICES
)
872 echelon
= models
.IntegerField(verbose_name
="Échelon")
873 degre
= models
.IntegerField(verbose_name
="Degré")
874 coefficient
= models
.FloatField(default
=0, verbose_name
="Coéfficient",
877 # annee # au lieu de date_debut et date_fin
878 commentaire
= models
.TextField(null
=True, blank
=True)
882 ordering
= ['type','echelon','degre','coefficient']
883 verbose_name
= "Classement"
884 verbose_name_plural
= "Classements"
886 def __unicode__(self
):
887 return u
'%s.%s.%s (%s)' % (self
.type, self
.echelon
, self
.degre
,
890 class Classement(Classement_
):
891 __doc__
= Classement_
.__doc__
894 class TauxChange_(Metadata
):
895 """Taux de change de la devise vers l'euro (EUR)
896 pour chaque année budgétaire.
899 devise
= models
.ForeignKey('Devise', db_column
='devise',
901 annee
= models
.IntegerField(verbose_name
="Année")
902 taux
= models
.FloatField(verbose_name
="Taux vers l'euro")
906 ordering
= ['-annee', 'devise__code']
907 verbose_name
= "Taux de change"
908 verbose_name_plural
= "Taux de change"
910 def __unicode__(self
):
911 return u
'%s : %s € (%s)' % (self
.devise
, self
.taux
, self
.annee
)
914 class TauxChange(TauxChange_
):
915 __doc__
= TauxChange_
.__doc__
918 class ValeurPoint_(Metadata
):
919 """Utile pour connaître, pour un Dossier, le salaire de base théorique lié
920 au classement dans la grille. La ValeurPoint s'obtient par l'implantation
921 du Poste de ce Dossier : dossier.poste.implantation (pseudo code).
923 salaire de base = coefficient * valeur du point de l'Implantation du Poste
925 valeur
= models
.FloatField(null
=True)
926 devise
= models
.ForeignKey('Devise', db_column
='devise', null
=True,
927 related_name
='+', default
=5)
928 implantation
= models
.ForeignKey(ref
.Implantation
,
929 db_column
='implantation',
930 related_name
='%(app_label)s_valeur_point')
932 annee
= models
.IntegerField()
935 ordering
= ['annee', 'implantation__nom']
938 verbose_name
= "Valeur du point"
939 verbose_name_plural
= "Valeurs du point"
941 # TODO : cette fonction n'était pas présente dans la branche dev, utilité?
942 def get_tauxchange_courant(self
):
944 Recherche le taux courant associé à la valeur d'un point.
945 Tous les taux de l'année courante sont chargés, pour optimiser un
946 affichage en liste. (On pourrait probablement améliorer le manager pour
947 lui greffer le taux courant sous forme de JOIN)
949 for tauxchange
in self
.tauxchange
:
950 if tauxchange
.implantation_id
== self
.implantation_id
:
954 def __unicode__(self
):
955 return u
'%s %s (%s)' % (self
.valeur
, self
.devise
, self
.annee
)
958 class ValeurPoint(ValeurPoint_
):
959 __doc__
= ValeurPoint_
.__doc__
962 class Devise(Metadata
):
965 code
= models
.CharField(max_length
=10, unique
=True)
966 nom
= models
.CharField(max_length
=255)
970 verbose_name
= "Devise"
971 verbose_name_plural
= "Devises"
973 def __unicode__(self
):
974 return u
'%s - %s' % (self
.code
, self
.nom
)
976 class TypeContrat(Metadata
):
979 nom
= models
.CharField(max_length
=255)
980 nom_long
= models
.CharField(max_length
=255)
984 verbose_name
= "Type de contrat"
985 verbose_name_plural
= "Types de contrat"
987 def __unicode__(self
):
988 return u
'%s' % (self
.nom
)
993 class ResponsableImplantation(Metadata
):
994 """Le responsable d'une implantation.
995 Anciennement géré sur le Dossier du responsable.
997 employe
= models
.ForeignKey('Employe', db_column
='employe',
999 null
=True, blank
=True)
1000 implantation
= models
.ForeignKey(ref
.Implantation
,
1001 db_column
='implantation', related_name
='+',
1004 def __unicode__(self
):
1005 return u
'%s : %s' % (self
.implantation
, self
.employe
)
1008 ordering
= ['implantation__nom']
1009 verbose_name
= "Responsable d'implantation"
1010 verbose_name_plural
= "Responsables d'implantation"