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
= u
"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
=u
"Titre du poste", )
80 nom_feminin
= models
.CharField(max_length
=255,
81 verbose_name
=u
"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
=u
"Direction/Service/Pôle support",
91 default
=1) # default = Rectorat
92 responsable
= models
.ForeignKey('Poste', db_column
='responsable',
94 verbose_name
=u
"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
=u
"Temps de travail",
101 help_text
=u
"% 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
=u
"Nb. heures par semaine")
108 local
= models
.BooleanField(verbose_name
=u
"Local", default
=True,
110 expatrie
= models
.BooleanField(verbose_name
=u
"Expatrié", default
=False,
112 mise_a_disposition
= models
.BooleanField(
113 verbose_name
=u
"Mise à disposition",
115 appel
= models
.CharField(max_length
=10,
116 verbose_name
=u
"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
=u
"Date de début",
182 help_text
=HELP_TEXT_DATE
)
183 date_fin
= models
.DateField(verbose_name
=u
"Date de fin",
184 help_text
=HELP_TEXT_DATE
,
185 null
=True, blank
=True)
188 ordering
= ['implantation__nom', 'nom']
190 def __unicode__(self
):
191 # TODO : gérer si poste est vacant ou non dans affichage
192 # TODO : gérer le nom_feminin (autre méthode appelée par __unicode__ ?)
193 return u
'%s - %s [%s]' % (self
.implantation
, self
.nom
, self
.id)
196 POSTE_FINANCEMENT_CHOICES
= (
197 ('A', 'A - Frais de personnel'),
198 ('B', 'B - Projet(s)-Titre(s)'),
202 class PosteFinancement(models
.Model
):
203 """Pour un Poste, structure d'informations décrivant comment on prévoit
206 poste
= models
.ForeignKey('Poste', db_column
='poste',
207 related_name
='financements')
208 type = models
.CharField(max_length
=1, choices
=POSTE_FINANCEMENT_CHOICES
)
209 pourcentage
= models
.DecimalField(max_digits
=12, decimal_places
=2,
210 help_text
=u
"ex.: 33.33 % (décimale avec point)")
211 commentaire
= models
.TextField(
212 help_text
=u
"Spécifiez la source de financement.")
217 def __unicode__(self
):
218 return u
'%s : %s %' % (self
.type, self
.pourcentage
)
220 class PostePiece(models
.Model
):
221 """Documents relatifs au Poste.
222 Ex.: Description de poste
224 poste
= models
.ForeignKey("Poste", db_column
='poste',
225 related_name
='pieces')
226 nom
= models
.CharField(verbose_name
=u
"Nom", max_length
=255)
227 fichier
= models
.FileField(verbose_name
=u
"Fichier",
228 upload_to
=poste_piece_dispatch
,
229 storage
=storage_prive
)
234 def __unicode__(self
):
235 return u
'%s' % (self
.nom
)
237 class PosteCommentaire(Commentaire
):
238 poste
= models
.ForeignKey("Poste", db_column
='poste', related_name
='+')
247 SITUATION_CHOICES
= (
248 ('C', 'Célibataire'),
253 class Employe(Metadata
):
254 """Personne occupant ou ayant occupé un Poste. Un Employe aura autant de
255 Dossiers qu'il occupe ou a occupé de Postes.
257 Cette classe aurait pu avantageusement s'appeler Personne car la notion
258 d'employé n'a pas de sens si aucun Dossier n'existe pour une personne.
261 nom
= models
.CharField(max_length
=255)
262 prenom
= models
.CharField(max_length
=255, verbose_name
=u
"Prénom")
263 # TODO : nom_affichage doit être obligatoire, pas nom et prenom
264 nom_affichage
= models
.CharField(max_length
=255,
265 verbose_name
=u
"Nom d'affichage",
266 null
=True, blank
=True)
267 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
268 db_column
='nationalite',
269 related_name
='employes_nationalite')
270 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
271 null
=True, blank
=True)
272 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
275 situation_famille
= models
.CharField(max_length
=1,
276 choices
=SITUATION_CHOICES
,
277 null
=True, blank
=True)
278 date_entree
= models
.DateField(verbose_name
=u
"Date d'entrée à l'AUF",
279 help_text
=HELP_TEXT_DATE
,
280 null
=True, blank
=True)
283 tel_domicile
= models
.CharField(max_length
=255, null
=True, blank
=True)
284 tel_cellulaire
= models
.CharField(max_length
=255, null
=True, blank
=True)
285 adresse
= models
.CharField(max_length
=255, null
=True, blank
=True)
286 ville
= models
.CharField(max_length
=255, null
=True, blank
=True)
287 province
= models
.CharField(max_length
=255, null
=True, blank
=True)
288 code_postal
= models
.CharField(max_length
=255, null
=True, blank
=True)
289 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code', db_column
='pays',
290 related_name
='employes',
291 null
=True, blank
=True)
294 ordering
= ['nom_affichage']
296 def __unicode__(self
):
297 # TODO : gérer nom d'affichage
298 return u
'%s' % (self
.nom_affichage
)
300 class EmployePiece(models
.Model
):
301 """Documents relatifs à un employé.
304 employe
= models
.ForeignKey("Employe", db_column
='employe',
306 nom
= models
.CharField(verbose_name
=u
"Nom", max_length
=255)
307 fichier
= models
.FileField(verbose_name
=u
"Fichier",
308 upload_to
=dossier_piece_dispatch
,
309 storage
=storage_prive
)
314 def __unicode__(self
):
315 return u
'%s' % (self
.nom
)
317 class EmployeCommentaire(Commentaire
):
318 employe
= models
.ForeignKey("Employe", db_column
='employe',
322 LIEN_PARENTE_CHOICES
= (
323 ('Conjoint', 'Conjoint'),
324 ('Conjointe', 'Conjointe'),
329 class AyantDroit(Metadata
):
330 """Personne en relation avec un Employe.
333 nom
= models
.CharField(max_length
=255)
334 prenom
= models
.CharField(max_length
=255)
335 # TODO : nom_affichage doit être obligatoire, pas nom et prenom
336 nom_affichage
= models
.CharField(max_length
=255,
337 verbose_name
=u
"Nom d'affichage",
338 null
=True, blank
=True)
339 nationalite
= models
.ForeignKey(ref
.Pays
, to_field
='code',
340 db_column
='nationalite',
341 related_name
='ayantdroits_nationalite')
342 date_naissance
= models
.DateField(help_text
=HELP_TEXT_DATE
,
343 null
=True, blank
=True)
344 genre
= models
.CharField(max_length
=1, choices
=GENRE_CHOICES
)
347 employe
= models
.ForeignKey('Employe', db_column
='employe',
348 related_name
='ayantdroits')
349 lien_parente
= models
.CharField(max_length
=10,
350 choices
=LIEN_PARENTE_CHOICES
,
351 null
=True, blank
=True)
354 ordering
= ['nom_affichage']
355 def __unicode__(self
):
356 # TODO : gérer nom d'affichage
357 return u
'%s %s' % (self
.prenom
, self
.nom
.upper())
359 class AyantDroitCommentaire(Commentaire
):
360 ayant_droit
= models
.ForeignKey("AyantDroit", db_column
='ayant_droit',
366 STATUT_RESIDENCE_CHOICES
= (
368 ('expat', 'Expatrié'),
371 COMPTE_COMPTA_CHOICES
= (
377 class Dossier(Metadata
):
378 """Le Dossier regroupe les informations relatives à l'occupation
379 d'un Poste par un Employe. Un seul Dossier existe par Poste occupé
382 Plusieurs Contrats peuvent être associés au Dossier.
383 Une structure de Remuneration est rattachée au Dossier. Un Poste pour
384 lequel aucun Dossier n'existe est un poste vacant.
387 employe
= models
.ForeignKey('Employe', db_column
='employe',
389 poste
= models
.ForeignKey('Poste', db_column
='poste',
390 related_name
='+', editable
=False)
391 statut
= models
.ForeignKey('Statut', related_name
='+', default
=3)
392 organisme_bstg
= models
.ForeignKey('OrganismeBstg',
393 db_column
='organisme_bstg',
395 verbose_name
=u
"Organisme",
396 help_text
=u
"Si détaché (DET) ou \
397 mis à disposition (MAD), \
398 préciser l'organisme.",
399 null
=True, blank
=True)
402 remplacement
= models
.BooleanField(default
=False)
403 statut_residence
= models
.CharField(max_length
=10, default
='local',
404 verbose_name
=u
"Statut",
405 choices
=STATUT_RESIDENCE_CHOICES
)
408 classement
= models
.ForeignKey('Classement', db_column
='classement',
410 null
=True, blank
=True)
411 regime_travail
= models
.DecimalField(max_digits
=12,
413 default
=REGIME_TRAVAIL_DEFAULT
,
414 verbose_name
=u
"Régime de travail",
415 help_text
=u
"% du temps complet")
416 regime_travail_nb_heure_semaine
= models
.DecimalField(max_digits
=12,
418 default
=REGIME_TRAVAIL_NB_HEURE_SEMAINE_DEFAULT
,
419 verbose_name
=u
"Nb. heures par semaine")
421 # Occupation du Poste par cet Employe (anciennement "mandat")
422 date_debut
= models
.DateField(verbose_name
=u
"Date de début d'occupation \
424 help_text
=HELP_TEXT_DATE
)
425 date_fin
= models
.DateField(verbose_name
=u
"Date de fin d'occupation \
427 help_text
=HELP_TEXT_DATE
,
428 null
=True, blank
=True)
434 ordering
= ['poste__nom', 'employe__nom_affichage']
436 def __unicode__(self
):
437 return u
'%s - %s' % (self
.poste
.nom
, self
.employe
)
439 class DossierPiece(models
.Model
):
440 """Documents relatifs au Dossier (à l'occupation de ce poste par employé).
441 Ex.: Lettre de motivation.
443 dossier
= models
.ForeignKey("Dossier", db_column
='dossier',
445 nom
= models
.CharField(verbose_name
=u
"Nom", max_length
=255)
446 fichier
= models
.FileField(verbose_name
=u
"Fichier",
447 upload_to
=dossier_piece_dispatch
,
448 storage
=storage_prive
)
453 def __unicode__(self
):
454 return u
'%s' % (self
.nom
)
456 class DossierCommentaire(Commentaire
):
457 dossier
= models
.ForeignKey("Dossier", db_column
='dossier',
463 class RemunerationMixin(Metadata
):
465 dossier
= models
.ForeignKey('Dossier', db_column
='dossier')
466 type = models
.ForeignKey('TypeRemuneration', db_column
='type',
468 type_revalorisation
= models
.ForeignKey('TypeRevalorisation',
469 db_column
='type_revalorisation',
471 null
=True, blank
=True)
472 montant
= models
.FloatField(null
=True, blank
=True,
474 # Annuel (12 mois, 52 semaines, 364 jours?)
475 devise
= models
.ForeignKey('Devise', to_field
='id',
476 db_column
='devise', related_name
='+',
478 # commentaire = precision
479 commentaire
= models
.CharField(max_length
=255, null
=True, blank
=True)
480 # date_debut = anciennement date_effectif
481 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
,
482 null
=True, blank
=True)
483 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
484 null
=True, blank
=True)
488 ordering
= ['type__nom', '-date_fin']
490 def __unicode__(self
):
491 return u
'%s %s (%s)' % (self
.montant
, self
.devise
.code
, self
.type.nom
)
493 class Remuneration(RemunerationMixin
):
494 """Structure de rémunération (données budgétaires) en situation normale
495 pour un Dossier. Si un Evenement existe, utiliser la structure de
496 rémunération EvenementRemuneration de cet événement.
499 def montant_mois(self
):
500 return round(self
.montant
/ 12, 2)
502 def taux_devise(self
):
503 return self
.devise
.tauxchange_set
.order_by('-annee').all()[0].taux
505 def montant_euro(self
):
506 return round(float(self
.montant
) / float(self
.taux_devise()), 2)
508 def montant_euro_mois(self
):
509 return round(self
.montant_euro() / 12, 2)
511 def __unicode__(self
):
513 devise
= self
.devise
.code
516 return "%s %s" % (self
.montant
, devise
)
521 class Contrat(Metadata
):
522 """Document juridique qui encadre la relation de travail d'un Employe
523 pour un Poste particulier. Pour un Dossier (qui documente cette
524 relation de travail) plusieurs contrats peuvent être associés.
526 dossier
= models
.ForeignKey('Dossier', db_column
='dossier',
528 type_contrat
= models
.ForeignKey('TypeContrat', db_column
='type_contrat',
530 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
)
531 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
532 null
=True, blank
=True)
535 ordering
= ['dossier__employe__nom_affichage']
537 def __unicode__(self
):
538 return u
'%s - %s' % (self
.dossier
.employe
.nom_affichage
, self
.id)
540 # TODO? class ContratPiece(models.Model):
545 class Evenement(Metadata
):
546 """Un Evenement sert à déclarer une situation temporaire (exceptionnelle)
547 d'un Dossier qui vient altérer des informations normales liées à un Dossier
548 (ex.: la Remuneration).
550 Ex.: congé de maternité, maladie...
552 Lors de ces situations exceptionnelles, l'Employe a un régime de travail
553 différent et une rémunération en conséquence. On souhaite toutefois
554 conserver le Dossier intact afin d'éviter une re-saisie des données lors
555 du retour à la normale.
557 dossier
= models
.ForeignKey("Dossier", db_column
='dossier',
559 nom
= models
.CharField(max_length
=255)
560 date_debut
= models
.DateField(help_text
=HELP_TEXT_DATE
)
561 date_fin
= models
.DateField(help_text
=HELP_TEXT_DATE
,
562 null
=True, blank
=True)
566 def __unicode__(self
):
567 return u
'%s' % (self
.nom
)
569 class EvenementRemuneration(RemunerationMixin
):
570 """Structure de rémunération liée à un Evenement qui remplace
571 temporairement la Remuneration normale d'un Dossier, pour toute la durée
574 evenement
= models
.ForeignKey("Evenement", db_column
='evenement',
580 class FamilleEmploi(Metadata
):
581 """Catégorie utilisée dans la gestion des Postes.
582 Catégorie supérieure à TypePoste.
584 nom
= models
.CharField(max_length
=255)
586 def __unicode__(self
):
587 return u
'%s' % (self
.nom
)
589 class TypePoste(Metadata
):
590 """Catégorie de Poste.
592 nom
= models
.CharField(max_length
=255)
593 nom_feminin
= models
.CharField(max_length
=255)
595 is_responsable
= models
.BooleanField(default
=False)
596 famille_emploi
= models
.ForeignKey('FamilleEmploi',
597 db_column
='famille_emploi',
603 def __unicode__(self
):
604 # TODO : gérer nom féminin
605 return u
'%s' % (self
.nom
)
608 TYPE_PAIEMENT_CHOICES
= (
609 ('Régulier', 'Régulier'),
610 ('Ponctuel', 'Ponctuel'),
613 NATURE_REMUNERATION_CHOICES
= (
614 ('Accessoire', 'Accessoire'),
615 ('Charges', 'Charges'),
616 ('Indemnité', 'Indemnité'),
617 ('RAS', 'Rémunération autre source'),
618 ('Traitement', 'Traitement'),
621 class TypeRemuneration(Metadata
):
622 """Catégorie de Remuneration.
624 nom
= models
.CharField(max_length
=255)
625 type_paiement
= models
.CharField(max_length
=30,
626 choices
=TYPE_PAIEMENT_CHOICES
)
627 nature_remuneration
= models
.CharField(max_length
=30,
628 choices
=NATURE_REMUNERATION_CHOICES
)
630 def __unicode__(self
):
631 return u
'%s' % (self
.nom
)
633 class TypeRevalorisation(Metadata
):
634 """Justification du changement de la Remuneration.
635 (Actuellement utilisé dans aucun traitement informatique.)
637 nom
= models
.CharField(max_length
=255)
639 def __unicode__(self
):
640 return u
'%s' % (self
.nom
)
642 class Service(Metadata
):
643 """Unité administrative où les Postes sont rattachés.
645 nom
= models
.CharField(max_length
=255)
650 def __unicode__(self
):
651 return u
'%s' % (self
.nom
)
654 TYPE_ORGANISME_CHOICES
= (
655 ('MAD', 'Mise à disposition'),
656 ('DET', 'Détachement'),
659 class OrganismeBstg(Metadata
):
660 """Organisation d'où provient un Employe mis à disposition (MAD) de
661 ou détaché (DET) à l'AUF à titre gratuit.
663 (BSTG = bien et service à titre gratuit.)
665 nom
= models
.CharField(max_length
=255)
666 type = models
.CharField(max_length
=10, choices
=TYPE_ORGANISME_CHOICES
)
667 pays
= models
.ForeignKey(ref
.Pays
, to_field
='code',
669 related_name
='organismes_bstg',
670 null
=True, blank
=True)
673 ordering
= ['type', 'nom']
675 def __unicode__(self
):
676 return u
'%s (%s)' % (self
.nom
, self
.type)
678 class Statut(Metadata
):
679 """Statut de l'Employe dans le cadre d'un Dossier particulier.
682 code
= models
.CharField(max_length
=25, unique
=True)
683 nom
= models
.CharField(max_length
=255)
688 def __unicode__(self
):
689 return u
'%s : %s' % (self
.code
, self
.nom
)
692 TYPE_CLASSEMENT_CHOICES
= (
694 ('T', 'T - Technicien'),
695 ('P', 'P - Professionel'),
697 ('D', 'D - Direction'),
698 ('SO', 'SO - Sans objet [expatriés]'),
699 ('HG', 'HG - Hors grille [direction]'),
702 class Classement(Metadata
):
703 """Éléments de classement de la
704 "Grille générique de classement hiérarchique".
706 Utile pour connaître, pour un Dossier, le salaire de base théorique lié au
707 classement dans la grille. Le classement donne le coefficient utilisé dans:
709 salaire de base = coefficient * valeur du point de l'Implantation du Poste
712 type = models
.CharField(max_length
=10, choices
=TYPE_CLASSEMENT_CHOICES
)
713 echelon
= models
.IntegerField()
714 degre
= models
.IntegerField()
715 coefficient
= models
.FloatField(default
=0)
717 # annee # au lieu de date_debut et date_fin
718 commentaire
= models
.TextField(null
=True, blank
=True)
721 ordering
= ['type','echelon','degre','coefficient']
723 def __unicode__(self
):
724 return u
'%s.%s.%s (%s)' % (self
.type, self
.echelon
, self
.degre
,
727 class TauxChange(Metadata
):
728 """Taux de change de la devise vers l'euro (EUR)
729 pour chaque année budgétaire.
732 devise
= models
.ForeignKey('Devise', to_field
='code', db_column
='devise',
734 annee
= models
.IntegerField()
735 taux
= models
.FloatField()
738 ordering
= ['annee', 'devise__code']
740 def __unicode__(self
):
741 return u
'%s : %s €' % (self
.devise
.code
, self
.taux
)
743 class ValeurPoint(Metadata
):
744 """Utile pour connaître, pour un Dossier, le salaire de base théorique lié
745 au classement dans la grille. La ValeurPoint s'obtient par l'implantation
746 du POste de ce Dossier : dossier.poste.implantation (pseudo code).
748 salaire de base = coefficient * valeur du point de l'Implantation du Poste
750 valeur
= models
.FloatField()
751 devise
= models
.ForeignKey('Devise', db_column
='devise',
752 related_name
='+', default
=5)
753 implantation
= models
.ForeignKey(ref
.Implantation
,
754 db_column
='implantation',
755 related_name
='valeur_point')
757 annee
= models
.IntegerField()
759 # Stockage de tous les taux de change
760 # pour optimiser la recherche de la devise associée
761 annee_courante
= datetime
.datetime
.now().year
762 tauxchange
= TauxChange
.objects
.select_related('devise') \
763 .filter(annee
=annee_courante
)
766 ordering
= ['annee', 'implantation__nom']
768 def __unicode__(self
):
769 tx
= self
.get_tauxchange_courant()
771 devise_code
= tx
.devise
.code
774 return u
'%s %s (%s-%s)' % (self
.valeur
, devise_code
,
775 self
.implantation_id
, self
.annee
)
778 ordering
= ['valeur']
780 class Devise(Metadata
):
783 code
= models
.CharField(max_length
=10, unique
=True)
784 nom
= models
.CharField(max_length
=255)
789 def __unicode__(self
):
790 return u
'%s - %s' % (self
.code
, self
.nom
)
792 class TypeContrat(Metadata
):
795 nom
= models
.CharField(max_length
=255)
796 nom_long
= models
.CharField(max_length
=255)
798 def __unicode__(self
):
799 return u
'%s' % (self
.nom
)
804 class ResponsableImplantation(Metadata
):
805 """Le responsable d'une implantation.
806 Anciennement géré sur le Dossier du responsable.
808 employe
= models
.ForeignKey('Employe', db_column
='employe',
810 null
=True, blank
=True)
811 implantation
= models
.ForeignKey(ref
.Implantation
,
812 db_column
='implantation', related_name
='+',
815 def __unicode__(self
):
816 return u
'%s : %s' % (self
.implantation
, self
.employe
)
819 ordering
= ['implantation__nom']