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 supprime
= models
.BooleanField(default
=False)
43 date_creation
= models
.DateField(null
=True, blank
=True)
44 user_creation
= models
.ForeignKey('auth.User',
45 db_column
='user_creation', related_name
='+',
46 null
=True, blank
=True)
47 date_modification
= models
.DateField(null
=True, blank
=True)
48 user_modification
= models
.ForeignKey('auth.User',
49 db_column
='user_modification', related_name
='+',
50 null
=True, blank
=True)
51 actif
= models
.BooleanField(default
=True)
52 date_activation
= models
.DateField(null
=True, blank
=True)
53 user_activation
= models
.ForeignKey('auth.User',
54 db_column
='user_activation', related_name
='+',
55 null
=True, blank
=True)
56 date_desactivation
= models
.DateField(null
=True, blank
=True)
57 user_desactivation
= models
.ForeignKey('auth.User',
58 db_column
='user_desactivation', related_name
='+',
59 null
=True, blank
=True)
71 class Commentaire(Metadata
):
72 texte
= models
.TextField()
73 owner
= models
.ForeignKey('auth.User', db_column
='owner', related_name
='+')
77 ordering
= ['-date_creation']
79 def __unicode__(self
):
80 return u
'%s' % (self
.texte
)
85 POSTE_APPEL_CHOICES
= (
86 ('interne', 'Interne'),
87 ('externe', 'Externe'),
91 class PosteManager(models
.Manager
):
92 def get_query_set(self
):
93 return super(PosteManager
, self
).get_query_set().select_related('implantation')
95 class Poste_(Metadata
):
96 """Un Poste est un emploi (job) à combler dans une implantation.
97 Un Poste peut être comblé par un Employe, auquel cas un Dossier est créé.
98 Si on veut recruter 2 jardiniers, 2 Postes distincts existent.
101 objects
= PosteManager()
104 nom
= models
.CharField(max_length
=255,
105 verbose_name
="Titre du poste", )
106 nom_feminin
= models
.CharField(max_length
=255,
107 verbose_name
="Titre du poste (au féminin)",
109 implantation
= models
.ForeignKey(ref
.Implantation
,
110 db_column
='implantation', related_name
='+')
111 type_poste
= models
.ForeignKey('TypePoste', db_column
='type_poste',
114 service
= models
.ForeignKey('Service', db_column
='service', null
=True,
116 verbose_name
="Direction/Service/Pôle support",
117 default
=1) # default = Rectorat
118 responsable
= models
.ForeignKey('Poste', db_column
='responsable',
119 related_name
='+', null
=True,
120 verbose_name
="Poste du responsable",
121 default
=149) # default = Recteur
124 regime_travail
= models
.DecimalField(max_digits
=12, decimal_places
=2,
125 default
=REGIME_TRAVAIL_DEFAULT
, null
=True,
126 verbose_name
="Temps de travail",
127 help_text
="% du temps complet")
128 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
129 decimal_places
=2, null
=True,
130 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
131 verbose_name
="Nb. heures par semaine")
134 local
= models
.NullBooleanField(verbose_name
="Local", default
=True,
135 null
=True, blank
=True)
136 expatrie
= models
.NullBooleanField(verbose_name
="Expatrié", default
=False,
137 null
=True, blank
=True)
138 mise_a_disposition
= models
.NullBooleanField(
139 verbose_name
="Mise à disposition",
140 null
=True, default
=False)
141 appel
= models
.CharField(max_length
=10, null
=True,
142 verbose_name
="Appel à candidature",
143 choices
=POSTE_APPEL_CHOICES
,
147 classement_min
= models
.ForeignKey('Classement',
148 db_column
='classement_min', related_name
='+',
149 null
=True, blank
=True)
150 classement_max
= models
.ForeignKey('Classement',
151 db_column
='classement_max', related_name
='+',
152 null
=True, blank
=True)
153 valeur_point_min
= models
.ForeignKey('ValeurPoint',
154 db_column
='valeur_point_min', related_name
='+',
155 null
=True, blank
=True)
156 valeur_point_max
= models
.ForeignKey('ValeurPoint',
157 db_column
='valeur_point_max', related_name
='+',
158 null
=True, blank
=True)
159 devise_min
= models
.ForeignKey('Devise', db_column
='devise_min', null
=True,
160 related_name
='+', default
=5)
161 devise_max
= models
.ForeignKey('Devise', db_column
='devise_max', null
=True,
162 related_name
='+', default
=5)
163 salaire_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
164 null
=True, default
=0)
165 salaire_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
166 null
=True, default
=0)
167 indemn_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
168 null
=True, default
=0)
169 indemn_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
170 null
=True, default
=0)
171 autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
172 null
=True, default
=0)
173 autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
174 null
=True, default
=0)
176 # Comparatifs de rémunération
177 devise_comparaison
= models
.ForeignKey('Devise', null
=True,
178 db_column
='devise_comparaison',
181 comp_locale_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
182 null
=True, blank
=True)
183 comp_locale_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
184 null
=True, blank
=True)
185 comp_universite_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
186 null
=True, blank
=True)
187 comp_universite_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
188 null
=True, blank
=True)
189 comp_fonctionpub_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
190 null
=True, blank
=True)
191 comp_fonctionpub_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
192 null
=True, blank
=True)
193 comp_ong_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
194 null
=True, blank
=True)
195 comp_ong_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
196 null
=True, blank
=True)
197 comp_autre_min
= models
.DecimalField(max_digits
=12, decimal_places
=2,
198 null
=True, blank
=True)
199 comp_autre_max
= models
.DecimalField(max_digits
=12, decimal_places
=2,
200 null
=True, blank
=True)
203 justification
= models
.TextField(null
=True, blank
=True)
206 date_validation
= models
.DateTimeField(null
=True, blank
=True) # de dae
207 date_debut
= models
.DateField(verbose_name
="Date de début", null
=True,
208 help_text
=HELP_TEXT_DATE
)
209 date_fin
= models
.DateField(verbose_name
="Date de fin",
210 help_text
=HELP_TEXT_DATE
,
211 null
=True, blank
=True)
215 ordering
= ['implantation__nom', 'nom']
216 verbose_name
= "Poste"
217 verbose_name_plural
= "Postes"
219 def __unicode__(self
):
220 representation
= u
'%s - %s [%s]' % (self
.implantation
, self
.nom
,
223 representation
= representation
+ u
' (vacant)'
224 return representation
227 # TODO : si existe un dossier actif pour ce poste, return False
228 # self.dossier_set.all() fonctionne pas
233 __doc__
= Poste_
.__doc__
237 __doc__
= Poste_
.__doc__
240 POSTE_FINANCEMENT_CHOICES
= (
241 ('A', 'A - Frais de personnel'),
242 ('B', 'B - Projet(s)-Titre(s)'),
247 class PosteFinancement_(models
.Model
):
248 """Pour un Poste, structure d'informations décrivant comment on prévoit
251 poste
= models
.ForeignKey('Poste', db_column
='poste',
252 related_name
='%(app_label)s_financements')
253 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
254 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
255 help_text
="ex.: 33.33 % (décimale avec point)")
256 commentaire
= models
.TextField(
257 help_text
="Spécifiez la source de financement.")
263 def __unicode__(self
):
264 return u
'%s : %s %' % (self
.type, self
.pourcentage
)
267 class PosteFinancement(PosteFinancement_
):
268 __doc__
= PosteFinancement_
.__doc__
271 class PostePiece(models
.Model
):
272 """Documents relatifs au Poste.
273 Ex.: Description de poste
275 poste
= models
.ForeignKey('Poste', db_column
='poste',
276 related_name
='pieces')
277 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
278 fichier
= models
.FileField(verbose_name
="Fichier",
279 upload_to
=poste_piece_dispatch
,
280 storage
=storage_prive
)
285 def __unicode__(self
):
286 return u
'%s' % (self
.nom
)
288 class PosteComparaison(models
.Model
):
290 De la même manière qu'un dossier, un poste peut-être comparé à un autre poste.
292 poste
= models
.ForeignKey('Poste', related_name
='comparaisons_internes')
293 implantation
= models
.ForeignKey(ref
.Implantation
, null
=True, blank
=True, related_name
="+")
294 nom
= models
.CharField(verbose_name
="Poste", max_length
=255, null
=True, blank
=True)
295 montant
= models
.IntegerField(null
=True)
296 devise
= models
.ForeignKey("Devise", default
=5, related_name
='+', null
=True, blank
=True)
297 montant_euros
= models
.IntegerField(null
=True)
300 class PosteCommentaire(Commentaire
):
301 poste
= models
.ForeignKey('Poste', db_column
='poste', related_name
='+')
310 SITUATION_CHOICES
= (
311 ('C', 'Célibataire'),
316 class Employe(Metadata
):
317 """Personne occupant ou ayant occupé un Poste. Un Employe aura autant de
318 Dossiers qu'il occupe ou a occupé de Postes.
320 Cette classe aurait pu avantageusement s'appeler Personne car la notion
321 d'employé n'a pas de sens si aucun Dossier n'existe pour une personne.
324 nom
= models
.CharField(max_length
=255)
325 prenom
= models
.CharField(max_length
=255, verbose_name
="Prénom")
326 nom_affichage
= models
.CharField(max_length
=255,
327 verbose_name
="Nom d'affichage",
328 null
=True, blank
=True)
329 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
330 db_column
='nationalite',
331 related_name
='employes_nationalite',
332 verbose_name
="Nationalité")
333 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
334 verbose_name
="Date de naissance",
335 null
=True, blank
=True)
336 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
339 situation_famille
= models
.CharField(max_length
=1,
340 choices
=SITUATION_CHOICES
,
341 verbose_name
="Situation familiale",
342 null
=True, blank
=True)
343 date_entree
= models
.DateField(verbose_name
="Date d'entrée à l'AUF",
344 help_text
=HELP_TEXT_DATE
,
345 null
=True, blank
=True)
348 tel_domicile
= models
.CharField(max_length
=255,
349 verbose_name
="Tél. domicile",
350 null
=True, blank
=True)
351 tel_cellulaire
= models
.CharField(max_length
=255,
352 verbose_name
="Tél. cellulaire",
353 null
=True, blank
=True)
354 adresse
= models
.CharField(max_length
=255, null
=True, blank
=True)
355 ville
= models
.CharField(max_length
=255, null
=True, blank
=True)
356 province
= models
.CharField(max_length
=255, null
=True, blank
=True)
357 code_postal
= models
.CharField(max_length
=255, null
=True, blank
=True)
358 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code', db_column
='pays',
359 related_name
='employes',
360 null
=True, blank
=True)
363 ordering
= ['nom_affichage','nom','prenom']
364 verbose_name
= "Employé"
365 verbose_name_plural
= "Employés"
367 def __unicode__(self
):
368 return u
'%s' % (self
.get_nom())
371 nom_affichage
= self
.nom_affichage
372 if not nom_affichage
:
373 nom_affichage
= u
'%s %s' % (self
.nom
.upper(), self
.prenom
)
376 class EmployePiece(models
.Model
):
377 """Documents relatifs à un employé.
380 employe
= models
.ForeignKey('Employe', db_column
='employe',
382 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
383 fichier
= models
.FileField(verbose_name
="Fichier",
384 upload_to
=dossier_piece_dispatch
,
385 storage
=storage_prive
)
390 def __unicode__(self
):
391 return u
'%s' % (self
.nom
)
393 class EmployeCommentaire(Commentaire
):
394 employe
= models
.ForeignKey('Employe', db_column
='employe',
398 LIEN_PARENTE_CHOICES
= (
399 ('Conjoint', 'Conjoint'),
400 ('Conjointe', 'Conjointe'),
405 class AyantDroit(Metadata
):
406 """Personne en relation avec un Employe.
409 nom
= models
.CharField(max_length
=255)
410 prenom
= models
.CharField(max_length
=255,
411 verbose_name
="Prénom",)
412 nom_affichage
= models
.CharField(max_length
=255,
413 verbose_name
="Nom d'affichage",
414 null
=True, blank
=True)
415 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
416 db_column
='nationalite',
417 related_name
='ayantdroits_nationalite',
418 verbose_name
="Nationalité")
419 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
420 verbose_name
="Date de naissance",
421 null
=True, blank
=True)
422 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
425 employe
= models
.ForeignKey('Employe', db_column
='employe',
426 related_name
='ayantdroits',
427 verbose_name
="Employé")
428 lien_parente
= models
.CharField(max_length
=10,
429 choices
=LIEN_PARENTE_CHOICES
,
430 verbose_name
="Lien de parenté",
431 null
=True, blank
=True)
434 ordering
= ['nom_affichage']
435 verbose_name
= "Ayant droit"
436 verbose_name_plural
= "Ayants droit"
438 def __unicode__(self
):
439 return u
'%s' % (self
.get_nom())
442 nom_affichage
= self
.nom_affichage
443 if not nom_affichage
:
444 nom_affichage
= u
'%s %s' % (self
.nom
.upper(), self
.prenom
)
447 class AyantDroitCommentaire(Commentaire
):
448 ayant_droit
= models
.ForeignKey('AyantDroit', db_column
='ayant_droit',
454 STATUT_RESIDENCE_CHOICES
= (
456 ('expat', 'Expatrié'),
459 COMPTE_COMPTA_CHOICES
= (
465 class Dossier_(Metadata
):
466 """Le Dossier regroupe les informations relatives à l'occupation
467 d'un Poste par un Employe. Un seul Dossier existe par Poste occupé
470 Plusieurs Contrats peuvent être associés au Dossier.
471 Une structure de Remuneration est rattachée au Dossier. Un Poste pour
472 lequel aucun Dossier n'existe est un poste vacant.
475 employe
= models
.ForeignKey('Employe', db_column
='employe',
477 verbose_name
="Employé")
478 poste
= models
.ForeignKey('Poste', db_column
='poste', related_name
='+')
479 statut
= models
.ForeignKey('Statut', related_name
='+', default
=3,
481 organisme_bstg
= models
.ForeignKey('OrganismeBstg',
482 db_column
='organisme_bstg',
484 verbose_name
="Organisme",
485 help_text
="Si détaché (DET) ou \
486 mis à disposition (MAD), \
487 préciser l'organisme.",
488 null
=True, blank
=True)
491 remplacement
= models
.BooleanField(default
=False)
492 statut_residence
= models
.CharField(max_length
=10, default
='local',
493 verbose_name
="Statut", null
=True,
494 choices
=STATUT_RESIDENCE_CHOICES
)
497 classement
= models
.ForeignKey('Classement', db_column
='classement',
499 null
=True, blank
=True)
500 regime_travail
= models
.DecimalField(max_digits
=12, null
=True,
502 default
=REGIME_TRAVAIL_DEFAULT
,
503 verbose_name
="Régime de travail",
504 help_text
="% du temps complet")
505 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
506 decimal_places
=2, null
=True,
507 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
508 verbose_name
="Nb. heures par semaine")
510 # Occupation du Poste par cet Employe (anciennement "mandat")
511 date_debut
= models
.DateField(verbose_name
="Date de début d'occupation \
513 help_text
=HELP_TEXT_DATE
)
514 date_fin
= models
.DateField(verbose_name
="Date de fin d'occupation \
516 help_text
=HELP_TEXT_DATE
,
517 null
=True, blank
=True)
524 ordering
= ['employe__nom_affichage', 'employe__nom', 'poste__nom']
525 verbose_name
= "Dossier"
526 verbose_name_plural
= "Dossiers"
528 def __unicode__(self
):
529 poste
= self
.poste
.nom
530 if self
.employe
.genre
== 'F':
531 poste
= self
.poste
.nom_feminin
532 return u
'%s - %s' % (self
.employe
, poste
)
535 class Dossier(Dossier_
):
536 __doc__
= Dossier_
.__doc__
540 class Dossier(Dossier_
):
541 __doc__
= Dossier_
.__doc__
544 class DossierPiece(models
.Model
):
545 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
546 Ex.: Lettre de motivation.
548 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
550 nom
= models
.CharField(verbose_name
="Nom", max_length
=255)
551 fichier
= models
.FileField(verbose_name
="Fichier",
552 upload_to
=dossier_piece_dispatch
,
553 storage
=storage_prive
)
558 def __unicode__(self
):
559 return u
'%s' % (self
.nom
)
561 class DossierCommentaire(Commentaire
):
562 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
568 class RemunerationMixin(Metadata
):
570 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
571 related_name
='%(app_label)s_%(class)s_remunerations')
572 type = models
.ForeignKey('TypeRemuneration', db_column
='type',
574 verbose_name
="Type de rémunération")
575 type_revalorisation
= models
.ForeignKey('TypeRevalorisation',
576 db_column
='type_revalorisation',
578 verbose_name
="Type de revalorisation",
579 null
=True, blank
=True)
580 montant
= models
.FloatField(null
=True, blank
=True,
582 # Annuel (12 mois, 52 semaines, 364 jours?)
583 devise
= models
.ForeignKey('Devise', to_field
='id',
584 db_column
='devise', related_name
='+',
586 # commentaire = precision
587 commentaire
= models
.CharField(max_length
=255, null
=True, blank
=True)
588 # date_debut = anciennement date_effectif
589 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
590 verbose_name
="Date de début",
591 null
=True, blank
=True)
592 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
593 verbose_name
="Date de fin",
594 null
=True, blank
=True)
598 ordering
= ['type__nom', '-date_fin']
600 def __unicode__(self
):
601 return u
'%s %s (%s)' % (self
.montant
, self
.devise
.code
, self
.type.nom
)
603 class Remuneration_(RemunerationMixin
):
604 """Structure de rémunération (données budgétaires) en situation normale
605 pour un Dossier. Si un Evenement existe, utiliser la structure de
606 rémunération EvenementRemuneration de cet événement.
609 def montant_mois(self
):
610 return round(self
.montant
/ 12, 2)
612 def taux_devise(self
):
613 return self
.devise
.tauxchange_set
.order_by('-annee').all()[0].taux
615 def montant_euro(self
):
616 return round(float(self
.montant
) / float(self
.taux_devise()), 2)
618 def montant_euro_mois(self
):
619 return round(self
.montant_euro() / 12, 2)
621 def __unicode__(self
):
623 devise
= self
.devise
.code
626 return "%s %s" % (self
.montant
, devise
)
630 verbose_name
= "Rémunération"
631 verbose_name_plural
= "Rémunérations"
634 class Remuneration(Remuneration_
):
635 __doc__
= Remuneration_
.__doc__
640 class Contrat(Metadata
):
641 """Document juridique qui encadre la relation de travail d'un Employe
642 pour un Poste particulier. Pour un Dossier (qui documente cette
643 relation de travail) plusieurs contrats peuvent être associés.
645 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
647 type_contrat
= models
.ForeignKey('TypeContrat', db_column
='type_contrat',
649 verbose_name
="Type de contrat")
650 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
651 verbose_name
="Date de début")
652 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
653 verbose_name
="Date de fin",
654 null
=True, blank
=True)
657 ordering
= ['dossier__employe__nom_affichage']
658 verbose_name
= "Contrat"
659 verbose_name_plural
= "Contrats"
661 def __unicode__(self
):
662 return u
'%s - %s' % (self
.dossier
, self
.id)
664 # TODO? class ContratPiece(models.Model):
669 class Evenement_(Metadata
):
670 """Un Evenement sert à déclarer une situation temporaire (exceptionnelle)
671 d'un Dossier qui vient altérer des informations normales liées à un Dossier
672 (ex.: la Remuneration).
674 Ex.: congé de maternité, maladie...
676 Lors de ces situations exceptionnelles, l'Employe a un régime de travail
677 différent et une rémunération en conséquence. On souhaite toutefois
678 conserver le Dossier intact afin d'éviter une re-saisie des données lors
679 du retour à la normale.
681 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
683 nom
= models
.CharField(max_length
=255)
684 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
685 verbose_name
="Date de début")
686 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
687 verbose_name
="Date de fin",
688 null
=True, blank
=True)
693 verbose_name
= "Évènement"
694 verbose_name_plural
= "Évènements"
696 def __unicode__(self
):
697 return u
'%s' % (self
.nom
)
700 class Evenement(Evenement_
):
701 __doc__
= Evenement_
.__doc__
704 class EvenementRemuneration_(RemunerationMixin
):
705 """Structure de rémunération liée à un Evenement qui remplace
706 temporairement la Remuneration normale d'un Dossier, pour toute la durée
709 evenement
= models
.ForeignKey("Evenement", db_column
='evenement',
711 verbose_name
="Évènement")
712 # TODO : le champ dossier hérité de Remuneration doit être dérivé
713 # de l'Evenement associé
717 ordering
= ['evenement', 'type__nom', '-date_fin']
718 verbose_name
= "Évènement - rémunération"
719 verbose_name_plural
= "Évènements - rémunérations"
722 class EvenementRemuneration(EvenementRemuneration_
):
723 __doc__
= EvenementRemuneration_
.__doc__
729 class EvenementRemuneration(EvenementRemuneration_
):
730 __doc__
= EvenementRemuneration_
.__doc__
735 class FamilleEmploi(Metadata
):
736 """Catégorie utilisée dans la gestion des Postes.
737 Catégorie supérieure à TypePoste.
739 nom
= models
.CharField(max_length
=255)
743 verbose_name
= "Famille d'emploi"
744 verbose_name_plural
= "Familles d'emploi"
746 def __unicode__(self
):
747 return u
'%s' % (self
.nom
)
749 class TypePoste(Metadata
):
750 """Catégorie de Poste.
752 nom
= models
.CharField(max_length
=255)
753 nom_feminin
= models
.CharField(max_length
=255,
754 verbose_name
="Nom féminin")
756 is_responsable
= models
.BooleanField(default
=False,
757 verbose_name
="Poste de responsabilité")
758 famille_emploi
= models
.ForeignKey('FamilleEmploi',
759 db_column
='famille_emploi',
761 verbose_name
="Famille d'emploi")
765 verbose_name
= "Type de poste"
766 verbose_name_plural
= "Types de poste"
768 def __unicode__(self
):
769 return u
'%s' % (self
.nom
)
772 TYPE_PAIEMENT_CHOICES
= (
773 ('Régulier', 'Régulier'),
774 ('Ponctuel', 'Ponctuel'),
777 NATURE_REMUNERATION_CHOICES
= (
778 ('Accessoire', 'Accessoire'),
779 ('Charges', 'Charges'),
780 ('Indemnité', 'Indemnité'),
781 ('RAS', 'Rémunération autre source'),
782 ('Traitement', 'Traitement'),
785 class TypeRemuneration(Metadata
):
786 """Catégorie de Remuneration.
788 nom
= models
.CharField(max_length
=255)
789 type_paiement
= models
.CharField(max_length
=30,
790 choices
=TYPE_PAIEMENT_CHOICES
,
791 verbose_name
="Type de paiement")
792 nature_remuneration
= models
.CharField(max_length
=30,
793 choices
=NATURE_REMUNERATION_CHOICES
,
794 verbose_name
="Nature de la rémunération")
798 verbose_name
= "Type de rémunération"
799 verbose_name_plural
= "Types de rémunération"
801 def __unicode__(self
):
802 return u
'%s' % (self
.nom
)
804 class TypeRevalorisation(Metadata
):
805 """Justification du changement de la Remuneration.
806 (Actuellement utilisé dans aucun traitement informatique.)
808 nom
= models
.CharField(max_length
=255)
812 verbose_name
= "Type de revalorisation"
813 verbose_name_plural
= "Types de revalorisation"
815 def __unicode__(self
):
816 return u
'%s' % (self
.nom
)
818 class Service(Metadata
):
819 """Unité administrative où les Postes sont rattachés.
821 nom
= models
.CharField(max_length
=255)
825 verbose_name
= "Service"
826 verbose_name_plural
= "Services"
828 def __unicode__(self
):
829 return u
'%s' % (self
.nom
)
832 TYPE_ORGANISME_CHOICES
= (
833 ('MAD', 'Mise à disposition'),
834 ('DET', 'Détachement'),
837 class OrganismeBstg(Metadata
):
838 """Organisation d'où provient un Employe mis à disposition (MAD) de
839 ou détaché (DET) à l'AUF à titre gratuit.
841 (BSTG = bien et service à titre gratuit.)
843 nom
= models
.CharField(max_length
=255)
844 type = models
.CharField(max_length
=10, choices
=TYPE_ORGANISME_CHOICES
)
845 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code',
847 related_name
='organismes_bstg',
848 null
=True, blank
=True)
851 ordering
= ['type', 'nom']
852 verbose_name
= "Organisme BSTG"
853 verbose_name_plural
= "Organismes BSTG"
855 def __unicode__(self
):
856 return u
'%s (%s)' % (self
.nom
, self
.get_type_display())
858 class Statut(Metadata
):
859 """Statut de l'Employe dans le cadre d'un Dossier particulier.
862 code
= models
.CharField(max_length
=25, unique
=True)
863 nom
= models
.CharField(max_length
=255)
867 verbose_name
= "Statut d'employé"
868 verbose_name_plural
= "Statuts d'employé"
870 def __unicode__(self
):
871 return u
'%s : %s' % (self
.code
, self
.nom
)
874 TYPE_CLASSEMENT_CHOICES
= (
876 ('T', 'T - Technicien'),
877 ('P', 'P - Professionel'),
879 ('D', 'D - Direction'),
880 ('SO', 'SO - Sans objet [expatriés]'),
881 ('HG', 'HG - Hors grille [direction]'),
885 class Classement_(Metadata
):
886 """Éléments de classement de la
887 "Grille générique de classement hiérarchique".
889 Utile pour connaître, pour un Dossier, le salaire de base théorique lié au
890 classement dans la grille. Le classement donne le coefficient utilisé dans:
892 salaire de base = coefficient * valeur du point de l'Implantation du Poste
895 type = models
.CharField(max_length
=10, choices
=TYPE_CLASSEMENT_CHOICES
)
896 echelon
= models
.IntegerField(verbose_name
="Échelon")
897 degre
= models
.IntegerField(verbose_name
="Degré")
898 coefficient
= models
.FloatField(default
=0, verbose_name
="Coéfficient",
901 # annee # au lieu de date_debut et date_fin
902 commentaire
= models
.TextField(null
=True, blank
=True)
906 ordering
= ['type','echelon','degre','coefficient']
907 verbose_name
= "Classement"
908 verbose_name_plural
= "Classements"
910 def __unicode__(self
):
911 return u
'%s.%s.%s (%s)' % (self
.type, self
.echelon
, self
.degre
,
914 class Classement(Classement_
):
915 __doc__
= Classement_
.__doc__
918 class TauxChange_(Metadata
):
919 """Taux de change de la devise vers l'euro (EUR)
920 pour chaque année budgétaire.
923 devise
= models
.ForeignKey('Devise', db_column
='devise',
925 annee
= models
.IntegerField(verbose_name
="Année")
926 taux
= models
.FloatField(verbose_name
="Taux vers l'euro")
930 ordering
= ['-annee', 'devise__code']
931 verbose_name
= "Taux de change"
932 verbose_name_plural
= "Taux de change"
934 def __unicode__(self
):
935 return u
'%s : %s € (%s)' % (self
.devise
, self
.taux
, self
.annee
)
938 class TauxChange(TauxChange_
):
939 __doc__
= TauxChange_
.__doc__
942 class ValeurPoint_(Metadata
):
943 """Utile pour connaître, pour un Dossier, le salaire de base théorique lié
944 au classement dans la grille. La ValeurPoint s'obtient par l'implantation
945 du Poste de ce Dossier : dossier.poste.implantation (pseudo code).
947 salaire de base = coefficient * valeur du point de l'Implantation du Poste
949 valeur
= models
.FloatField(null
=True)
950 devise
= models
.ForeignKey('Devise', db_column
='devise', null
=True,
951 related_name
='+', default
=5)
952 implantation
= models
.ForeignKey(ref
.Implantation
,
953 db_column
='implantation',
954 related_name
='%(app_label)s_valeur_point')
956 annee
= models
.IntegerField()
959 ordering
= ['annee', 'implantation__nom']
962 verbose_name
= "Valeur du point"
963 verbose_name_plural
= "Valeurs du point"
965 # TODO : cette fonction n'était pas présente dans la branche dev, utilité?
966 def get_tauxchange_courant(self
):
968 Recherche le taux courant associé à la valeur d'un point.
969 Tous les taux de l'année courante sont chargés, pour optimiser un
970 affichage en liste. (On pourrait probablement améliorer le manager pour
971 lui greffer le taux courant sous forme de JOIN)
973 for tauxchange
in self
.tauxchange
:
974 if tauxchange
.implantation_id
== self
.implantation_id
:
978 def __unicode__(self
):
979 return u
'%s %s (%s)' % (self
.valeur
, self
.devise
, self
.annee
)
982 class ValeurPoint(ValeurPoint_
):
983 __doc__
= ValeurPoint_
.__doc__
986 class Devise(Metadata
):
989 code
= models
.CharField(max_length
=10, unique
=True)
990 nom
= models
.CharField(max_length
=255)
994 verbose_name
= "Devise"
995 verbose_name_plural
= "Devises"
997 def __unicode__(self
):
998 return u
'%s - %s' % (self
.code
, self
.nom
)
1000 class TypeContrat(Metadata
):
1003 nom
= models
.CharField(max_length
=255)
1004 nom_long
= models
.CharField(max_length
=255)
1008 verbose_name
= "Type de contrat"
1009 verbose_name_plural
= "Types de contrat"
1011 def __unicode__(self
):
1012 return u
'%s' % (self
.nom
)
1017 class ResponsableImplantation(Metadata
):
1018 """Le responsable d'une implantation.
1019 Anciennement géré sur le Dossier du responsable.
1021 employe
= models
.ForeignKey('Employe', db_column
='employe',
1023 null
=True, blank
=True)
1024 implantation
= models
.ForeignKey(ref
.Implantation
,
1025 db_column
='implantation', related_name
='+',
1028 def __unicode__(self
):
1029 return u
'%s : %s' % (self
.implantation
, self
.employe
)
1032 ordering
= ['implantation__nom']
1033 verbose_name
= "Responsable d'implantation"
1034 verbose_name_plural
= "Responsables d'implantation"