1 # -*- encoding: utf-8 -*-
4 from ordereddict
import OrderedDict
5 from dateutil
.relativedelta
import relativedelta
6 from django
import forms
7 from django
.core
.urlresolvers
import reverse
8 from django
.core
.exceptions
import MultipleObjectsReturned
9 from django
.forms
.models
import BaseInlineFormSet
10 from django
.forms
.models
import (
11 inlineformset_factory
,
15 from django
.db
.models
import Q
, Max
, Count
16 from django
.shortcuts
import redirect
17 from django
.contrib
.admin
import widgets
as admin_widgets
19 from ajax_select
.fields
import AutoCompleteSelectField
21 from auf
.django
.references
import models
as ref
22 from auf
.django
.workflow
.forms
import WorkflowFormMixin
23 from auf
.django
.workflow
.models
import WorkflowCommentaire
25 from project
import groups
26 from project
.rh
import models
as rh
27 from project
.dae
import models
as dae
28 from .widgets
import ReadOnlyChoiceWidget
, ReadOnlyWidget
29 from project
.dae
.workflow
import POSTE_ETATS_BOUTONS
, POSTE_ETAT_FINALISE
32 def filtered_archived_fields_form_factory(*fields
):
34 Retourne un model form
36 class FilterArchivedFields(object):
37 def __init__(self
, *a
, **kw
):
38 super(FilterArchivedFields
, self
).__init__(*a
, **kw
)
40 self
.fields
[f
].queryset
= (
41 self
.fields
[f
]._queryset
.filter(archive
=False)
43 return FilterArchivedFields
46 class BaseInlineFormSetWithInitial(BaseInlineFormSet
):
48 Cette classe permet de fournir l'option initial aux inlineformsets.
49 Elle devient désuette en django 1.4.
51 def __init__(self
, data
=None, files
=None, instance
=None,
52 save_as_new
=False, prefix
=None, queryset
=None, **kwargs
):
54 self
.initial_extra
= kwargs
.pop('initial', None)
56 from django
.db
.models
.fields
.related
import RelatedObject
58 self
.instance
= self
.fk
.rel
.to()
60 self
.instance
= instance
61 self
.save_as_new
= save_as_new
62 # is there a better way to get the object descriptor?
63 self
.rel_name
= RelatedObject(self
.fk
.rel
.to
, self
.model
, self
.fk
).get_accessor_name()
65 queryset
= self
.model
._default_manager
66 qs
= queryset
.filter(**{self
.fk
.name
: self
.instance
})
67 super(BaseInlineFormSetWithInitial
, self
).__init__(data
, files
, prefix
=prefix
,
68 queryset
=qs
, **kwargs
)
70 def _construct_form(self
, i
, **kwargs
):
71 if self
.is_bound
and i
< self
.initial_form_count():
72 # Import goes here instead of module-level because importing
73 # django.db has side effects.
74 from django
.db
import connections
75 pk_key
= "%s-%s" % (self
.add_prefix(i
), self
.model
._meta
.pk
.name
)
76 pk
= self
.data
[pk_key
]
77 pk_field
= self
.model
._meta
.pk
78 pk
= pk_field
.get_db_prep_lookup('exact', pk
,
79 connection
=connections
[self
.get_queryset().db
])
80 if isinstance(pk
, list):
82 kwargs
['instance'] = self
._existing_object(pk
)
83 if i
< self
.initial_form_count() and not kwargs
.get('instance'):
84 kwargs
['instance'] = self
.get_queryset()[i
]
85 if i
>= self
.initial_form_count() and self
.initial_extra
:
86 # Set initial values for extra forms
88 kwargs
['initial'] = self
.initial_extra
[i
-self
.initial_form_count()]
92 defaults
= {'auto_id': self
.auto_id
, 'prefix': self
.add_prefix(i
)}
94 defaults
['data'] = self
.data
95 defaults
['files'] = self
.files
98 defaults
['initial'] = self
.initial
[i
]
101 # Allow extra forms to be empty.
102 if i
>= self
.initial_form_count():
103 defaults
['empty_permitted'] = True
104 defaults
.update(kwargs
)
105 form
= self
.form(**defaults
)
106 self
.add_fields(form
, i
)
110 def _implantation_choices(obj
, request
):
112 employe
= groups
.get_employe_from_user(request
.user
)
113 q
= Q(**{'zone_administrative__in': groups
.get_zones_from_user(request
.user
)})
116 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
117 if groups
.DRH_NIVEAU_1
in user_groupes
or \
118 groups
.DRH_NIVEAU_2
in user_groupes
:
120 return [('', '----------')] + \
121 [(i
.id, unicode(i
), )for i
in ref
.Implantation
.objects
.filter(q
)]
124 def _employe_choices(obj
, request
):
126 employe
= groups
.get_employe_from_user(request
.user
)
127 q_dae_region_service
= Q(
128 poste__implantation__zone_administrative__in
=(
129 groups
.get_zones_from_user(request
.user
)
132 q_rh_region_service
= Q(
133 poste__implantation__zone_administrative__in
=(
134 groups
.get_zones_from_user(request
.user
)
138 user_groupes
= [g
.name
for g
in request
.user
.groups
.all()]
139 if groups
.DRH_NIVEAU_1
in user_groupes
or \
140 groups
.DRH_NIVEAU_2
in user_groupes
:
141 q_dae_region_service
= Q()
142 q_rh_region_service
= Q()
144 # On filtre les employes avec les droits régionaux et on s'assure que
145 # c'est bien le dernier dossier en date pour sortir l'employe. On retient
146 # un employé qui travaille présentement dans la même région que le user
148 dossiers_regionaux_ids
= [
149 d
.id for d
in dae
.Dossier
.objects
.filter(q_dae_region_service
)
153 for d
in dae
.Dossier
.objects
155 .annotate(dernier_dossier
=Max('id'))
156 if d
['dernier_dossier'] in dossiers_regionaux_ids
158 dae_employe
= dae
.Employe
.objects
.filter(id__in
=employes_ids
)
159 dae_
= dae_employe
.filter(id_rh__isnull
=True)
160 copies
= dae_employe
.filter(Q(id_rh__isnull
=False))
161 id_copies
= [p
.id_rh_id
for p
in copies
.all()]
163 dossiers_regionaux_ids
= [
164 d
.id for d
in rh
.Dossier
.objects
.filter(q_rh_region_service
)
168 for d
in rh
.Dossier
.objects
170 .annotate(dernier_dossier
=Max('id'))
171 if d
['dernier_dossier'] in dossiers_regionaux_ids
173 rhv1
= rh
.Employe
.objects \
174 .filter(id__in
=employes_ids
) \
175 .exclude(id__in
=id_copies
)
177 # On ajoute les nouveaux Employés DAE qui ont été crées, mais qui n'ont
178 # pas de Dossier associés
179 employes_avec_dae
= [d
.employe_id
for d
in dae
.Dossier
.objects
.all()]
180 employes_orphelins
= dae
.Employe
.objects
.exclude(id__in
=employes_avec_dae
)
182 def option_label(employe
, extra
=""):
184 extra
= " [%s]" % extra
185 return "%s %s %s" % (employe
.nom
.upper(), employe
.prenom
.title(), extra
)
187 lbl_rh
= sorted([('rh-%s' % p
.id, option_label(p
, "existant dans rh")) for p
in rhv1
],
189 lbl_dae
= sorted([('dae-%s' % p
.id, option_label(p
)) for p
in dae_ | copies | employes_orphelins
],
191 return [('', 'Nouvel employé')] + lbl_rh
+ lbl_dae
194 def label_poste_display(poste
):
195 """Formate un visuel pour un poste dans une liste déroulante"""
198 annee
= poste
.date_debut
.year
201 label
= u
"%s (%s) %s [%s]" % (
203 poste
.implantation
.nom_court
,
205 #poste.type_poste.categorie_emploi.nom,
211 PostePieceFormSet
= inlineformset_factory(dae
.Poste
, dae
.PostePiece
,)
212 DossierPieceForm
= inlineformset_factory(dae
.Dossier
, dae
.DossierPiece
)
214 # Ce formset est utilisé dans le cas de la création de poste prépopulé avec les
216 FinancementFormSetInitial
= inlineformset_factory(
218 dae
.PosteFinancement
,
219 formset
=BaseInlineFormSetWithInitial
,
222 FinancementFormSet
= inlineformset_factory(
224 dae
.PosteFinancement
,
229 class DossierComparaisonForm(
230 filtered_archived_fields_form_factory(
235 recherche
= AutoCompleteSelectField('dossiers', required
=False)
236 poste
= forms
.CharField(
237 max_length
=255, widget
=forms
.TextInput(attrs
={'size': '60'})
239 cmp_dossier
= forms
.IntegerField(
240 widget
=forms
.widgets
.HiddenInput
,
245 model
= dae
.DossierComparaison
246 exclude
= ('dossier',)
248 DossierComparaisonFormSet
= modelformset_factory(
249 dae
.DossierComparaison
, extra
=3, max_num
=3, form
=DossierComparaisonForm
253 class PosteComparaisonForm(
254 filtered_archived_fields_form_factory('classement'),
257 recherche
= AutoCompleteSelectField('dae_postes', required
=False)
259 cmp_poste
= forms
.IntegerField(
260 widget
=forms
.widgets
.HiddenInput
,
265 model
= dae
.PosteComparaison
268 # Ce formset est utilisé dans le cas de la création de poste prépopulé avec les
270 PosteComparaisonFormSetInitial
= inlineformset_factory(
272 dae
.PosteComparaison
,
275 form
=PosteComparaisonForm
,
276 formset
=BaseInlineFormSetWithInitial
,
278 PosteComparaisonFormSet
= inlineformset_factory(
280 dae
.PosteComparaison
,
283 form
=PosteComparaisonForm
,
287 class FlexibleRemunForm(
288 filtered_archived_fields_form_factory(
292 # Utilisé dans templats.
293 montant_mensuel
= forms
.DecimalField(required
=False)
294 montant
= forms
.DecimalField(required
=True, label
='Montant annuel')
297 model
= dae
.Remuneration
299 def __init__(self
, *a
, **kw
):
300 super(FlexibleRemunForm
, self
).__init__(*a
, **kw
)
301 # self.fields['type'].widget = ReadOnlyChoiceWidget(choices=self.fields['type'].choices)
303 def clean_devise(self
):
304 devise
= self
.cleaned_data
['devise']
305 if devise
.code
== 'EUR':
307 implantation
= ref
.Implantation
.objects
.get(
308 id=self
.data
['implantation']
310 liste_taux
= devise
.tauxchange_set
.order_by('-annee')
311 if len(liste_taux
) == 0:
312 raise forms
.ValidationError(
313 u
"La devise %s n'a pas de taux pour l'implantation %s" %
314 (devise
, implantation
)
319 def has_changed(self
):
321 Modification de has_changed pour qu'il ignore les montant a 0
325 changed_data
= self
.changed_data
327 # Type is set in hidden fields, it shouldn't be changed by the
328 # user; ignore when checking if data has changed.
329 if 'type' in changed_data
:
330 changed_data
.pop(changed_data
.index('type'))
332 # Montant is set to 0 in javascript, ifnore 'montant' data if
335 # Generer le key tel qu'identifié dans self.data:
336 montant_key
= '-'.join((self
.prefix
, 'montant'))
338 if ('montant' in changed_data
and
339 self
.data
.get(montant_key
, '0') == '0'):
340 changed_data
.pop(changed_data
.index('montant'))
342 return bool(changed_data
)
345 class ReadOnlyRemunForm(FlexibleRemunForm
):
346 # Utilisé dans templats.
348 def __init__(self
, *a
, **kw
):
349 super (ReadOnlyRemunForm
, self
).__init__(*a
, **kw
)
350 for field
in self
.fields
:
351 field
= self
.fields
[field
]
352 if not isinstance(field
.widget
, (
353 forms
.widgets
.HiddenInput
,
354 forms
.widgets
.Select
)):
355 field
.widget
= ReadOnlyWidget()
356 elif isinstance(field
.widget
, forms
.widgets
.Select
):
357 field
.widget
= ReadOnlyChoiceWidget(choices
=field
.choices
)
360 class GroupedInlineFormset(BaseInlineFormSet
):
365 choice_overrides
=[]):
368 # Create pre-defined groups.
369 self
.groups
= OrderedDict()
371 self
.groups
[group
[0]] = {
377 # Assign each form to a group.
378 for form
in self
.forms
:
379 if bool(form
.initial
):
380 grp
= group_accessor(form
)
381 if grp
[0] not in self
.groups
:
382 self
.groups
[grp
[0]] = {
387 self
.groups
[grp
[0]]['forms'].append(form
)
389 # Add extra forms (n extra for each grop).
391 for i
in xrange(len(self
.groups
) * self
.extra
):
393 self
._construct_form(self
.initial_form_count() + i
))
395 for g
in self
.groups
:
396 for i
in xrange(self
.extra
):
397 tmp_form
= tmp_extras
.pop()
398 self
.groups
[g
]['forms'].append(tmp_form
)
399 self
.forms
.append(tmp_form
)
402 # Override form choices with the data provided in
404 for key
in choice_overrides
:
405 for form
in self
.groups
.get(key
, {'forms': []})['forms']:
406 for field_key
in choice_overrides
[key
]:
407 form
.fields
[field_key
].choices
= choice_overrides
[
411 # Create an iterable for easier access in template.
412 self
.group_list
= self
.groups
.values()
414 # def set_groups(self, group_accessor, groups, group_order=[]):
416 # group_accessor: A function that will get the key and name from
418 # group_order: list the group keys here in a list and
419 # GroupedInlineFormset.groups will be ordered (ordereddict) by
420 # the key sequence provided here. Any missing key from the
424 # # Build group list.
425 # self.groups = OrderedDict()
427 # # self.groups_and_forms = []
428 # for form in self.forms:
429 # group_key, group_name = group_accessor(form)
430 # if not temp_groups.has_key(group_key):
431 # temp_groups[group_key] = {
432 # 'name': group_name,
436 # temp_groups[group_key]['forms'].append(form)
438 # for order_key in group_order:
439 # if temp_groups.has_key(order_key):
440 # self.groups[order_key] = temp_groups.pop(order_key)
442 # for key in temp_groups:
443 # self.groups[key] = temp_groups[key]
447 # self.group_list = self.groups.values()
450 def remun_formset_factory(parent_model
,
452 form
=forms
.ModelForm
,
453 formset
=GroupedInlineFormset
,
462 formfield_callback
=None,
464 choice_overrides
=[]):
465 trs
= rh
.TypeRemuneration
.objects
.all()
466 # extra = max_num = trs.count()
467 fk
= _get_foreign_key(parent_model
, model
, fk_name
=fk_name
)
468 # enforce a max_num=1 when the foreign key to the parent model is unique.
473 'formfield_callback': formfield_callback
,
476 'can_delete': can_delete
,
477 'can_order': can_order
,
482 FormSet
= modelformset_factory(model
, **kwargs
)
484 FormSet
.read_only
= read_only
487 rtype
= form
.initial
['type']
488 if not isinstance(rtype
, rh
.TypeRemuneration
):
489 rtype
= rh
.TypeRemuneration
.objects
.get(id=rtype
)
490 return (rtype
.nature_remuneration
,
491 rtype
.nature_remuneration
496 # Monkey patch FormSet.
497 def __init__(inst
, *a
, **kw
):
498 super(inst
.__class__
, inst
).__init__(*a
, **kw
)
499 inst
.set_groups(groups
, grouper
, choice_overrides
)
501 FormSet
.__init__
= __init__
506 def remun_formset_factory_factory(
508 parent_model
=dae
.Dossier
,
509 model
=dae
.Remuneration
,
510 exclude_archived
=False):
512 Don't we love factory factories?
515 null_choice
= ('', '-' * 10)
516 extras
= 2 if not read_only
else 0
517 can_delete
= False if read_only
else True
518 form_class
= ReadOnlyRemunForm
if read_only
else FlexibleRemunForm
520 choice_override_extra_q
= {}
523 choice_override_extra_q
.update({
527 return remun_formset_factory(
532 can_delete
=can_delete
,
534 groups
= rh
.NATURE_REMUNERATION_CHOICES
,
537 'type': [null_choice
] + list(
538 rh
.TypeRemuneration
.objects
.filter(
539 nature_remuneration
=u
'Traitement',
540 **choice_override_extra_q
).values_list(
545 'type': [null_choice
] + list(
546 rh
.TypeRemuneration
.objects
.filter(
547 nature_remuneration
=u
'Indemnité',
548 **choice_override_extra_q
).values_list(
553 'type': [null_choice
] + list(
554 rh
.TypeRemuneration
.objects
.filter(
555 nature_remuneration
=u
'Charges',
556 **choice_override_extra_q
).values_list(
561 'type': [null_choice
] + list(
562 rh
.TypeRemuneration
.objects
.filter(
563 nature_remuneration
=u
'Accessoire',
564 **choice_override_extra_q
).values_list(
569 'type': [null_choice
] + list(
570 rh
.TypeRemuneration
.objects
.filter(
571 nature_remuneration
=u
'RAS',
572 **choice_override_extra_q
).values_list(
579 RemunForm
= remun_formset_factory_factory(
581 parent_model
=dae
.Dossier
,
582 model
=dae
.Remuneration
,
583 exclude_archived
=True,
586 ReadOnlyRemunFormSet
= remun_formset_factory_factory(
588 parent_model
=dae
.Dossier
,
589 model
=dae
.Remuneration
,
592 PosteCompReadOnlyRemunFormSet
= remun_formset_factory_factory(
594 parent_model
=dae
.PosteComparaison
,
595 model
=dae
.PosteComparaisonRemuneration
,
598 DossierCompReadOnlyRemunFormSet
= remun_formset_factory_factory(
600 parent_model
=dae
.DossierComparaison
,
601 model
=dae
.DossierComparaisonRemuneration
,
605 class PosteForm(filtered_archived_fields_form_factory(
609 """ Formulaire des postes. """
611 # On ne propose que les services actifs
612 service
= forms
.ModelChoiceField(
613 queryset
=rh
.Service
.objects
.all(), required
=True
616 responsable
= AutoCompleteSelectField('responsables', required
=True)
617 #responsable = forms.ModelChoiceField(
618 # queryset=rh.Poste.objects.select_related(depth=1))
620 # La liste des choix est laissée vide. Voir __init__ pour la raison.
621 poste
= forms
.ChoiceField(label
="Nouveau poste ou évolution du poste",
622 choices
=(), required
=False)
624 valeur_point_min
= forms
.ModelChoiceField(
625 queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False
627 valeur_point_max
= forms
.ModelChoiceField(
628 queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False
633 fields
= ('type_intervention',
634 'poste', 'implantation', 'type_poste', 'service', 'nom',
635 'responsable', 'local', 'expatrie', 'mise_a_disposition',
636 'appel', 'date_debut', 'date_fin',
637 'regime_travail', 'regime_travail_nb_heure_semaine',
638 'classement_min', 'classement_max',
639 'valeur_point_min', 'valeur_point_max',
640 'devise_min', 'devise_max',
641 'salaire_min', 'salaire_max',
642 'indemn_expat_min', 'indemn_expat_max',
643 'indemn_fct_min', 'indemn_fct_max',
644 'charges_patronales_min', 'charges_patronales_max',
645 'autre_min', 'autre_max', 'devise_comparaison',
646 'comp_locale_min', 'comp_locale_max',
647 'comp_universite_min', 'comp_universite_max',
648 'comp_fonctionpub_min', 'comp_fonctionpub_max',
649 'comp_ong_min', 'comp_ong_max',
650 'comp_autre_min', 'comp_autre_max',
653 widgets
= dict(type_intervention
=forms
.RadioSelect(),
654 appel
=forms
.RadioSelect(),
655 nom
=forms
.TextInput(attrs
={'size': 60},),
656 date_debut
=admin_widgets
.AdminDateWidget(),
657 date_fin
=admin_widgets
.AdminDateWidget(),
658 justification
=forms
.Textarea(attrs
={'cols': 80},),
659 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
660 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
663 def __init__(self
, *args
, **kwargs
):
664 """ Mise à jour dynamique du contenu du menu des postes.
666 Si on ne met le menu à jour de cette façon, à chaque instantiation du
667 formulaire, son contenu est mis en cache par le système et il ne
668 reflète pas les changements apportés par les ajouts, modifications,
671 Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField
672 car le "id" de chaque choix est spécial (voir _poste_choices).
675 request
= kwargs
.pop('request')
676 super(PosteForm
, self
).__init__(*args
, **kwargs
)
677 self
.fields
['poste'].choices
= self
._poste_choices(request
)
679 self
.fields
['implantation'].choices
= \
680 _implantation_choices(self
, request
)
682 # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1
683 if self
.instance
and self
.instance
.id is None:
684 dossiers
= self
.instance
.get_dossiers()
685 if len(dossiers
) > 0:
686 self
.initial
['service'] = dossiers
[0].poste
.service
688 def _poste_choices(self
, request
):
689 """ Menu déroulant pour les postes.
690 Constitué des postes de RH
692 postes_rh
= rh
.Poste
.objects
.ma_region_ou_service(request
.user
).all()
693 postes_rh
= postes_rh
.select_related(depth
=1)
695 return [('', 'Nouveau poste')] + \
696 sorted([('rh-%s' % p
.id, label_poste_display(p
)) for p
in
702 Validation conditionnelles de certains champs.
704 cleaned_data
= self
.cleaned_data
706 if cleaned_data
.get("local") is False \
707 and cleaned_data
.get("expatrie") is False:
708 msg
= "Le poste doit au moins être ouvert localement " \
710 self
._errors
["local"] = self
.error_class([msg
])
711 self
._errors
["expatrie"] = ''
712 raise forms
.ValidationError(msg
)
717 class ChoosePosteForm(forms
.Form
):
721 # La liste des choix est laissée vide. Voir PosteForm.__init__.
722 postes_dae
= forms
.ChoiceField(choices
=(), required
=False)
723 postes_rh
= forms
.ChoiceField(choices
=(), required
=False)
725 def __init__(self
, request
=None, *args
, **kwargs
):
726 super(ChoosePosteForm
, self
).__init__(*args
, **kwargs
)
727 self
.fields
['postes_dae'].choices
= self
._poste_dae_choices(request
)
728 self
.fields
['postes_rh'].choices
= self
._poste_rh_choices(request
)
730 def _poste_dae_choices(self
, request
):
731 """ Menu déroulant pour les postes."""
732 postes_dae
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
) \
733 .exclude(etat__in
=(POSTE_ETAT_FINALISE
, )) \
734 .annotate(num_dae
=Count('dae_dossiers')) \
736 .order_by('implantation', '-date_debut', )
738 return [('', '----------')] + \
739 [('dae-%s' % p
.id, label_poste_display(p
)) for p
in postes_dae
]
741 def _poste_rh_choices(self
, request
):
742 """ Menu déroulant pour les postes."""
743 postes_dae
= dae
.Poste
.objects
.exclude(etat__in
=(POSTE_ETAT_FINALISE
, ))
744 today
= datetime
.date
.today()
745 id_poste_dae_commences
= [p
.id_rh_id
for p
in postes_dae
if p
.id_rh
is not None]
746 postes_rh
= rh
.Poste
.objects
.ma_region_ou_service(request
.user
) \
747 .exclude(id__in
=id_poste_dae_commences
) \
748 .filter(Q(date_debut__lte
=today
) &
749 (Q(date_fin__gte
=today
) |
750 Q(date_fin__isnull
=True))
752 .order_by('implantation', '-date_debut', )
754 return [('', '----------')] + \
755 [('rh-%s' % p
.id, label_poste_display(p
)) for p
in postes_rh
]
758 cleaned_data
= super(ChoosePosteForm
, self
).clean()
759 postes_dae
= cleaned_data
.get("postes_dae")
760 postes_rh
= cleaned_data
.get("postes_rh")
761 if (postes_dae
is u
"" and postes_rh
is u
"") or \
762 (postes_dae
is not u
"" and postes_rh
is not u
""):
763 raise forms
.ValidationError("Choisissez un poste DAE ou un poste RH")
767 poste_dae_key
= self
.cleaned_data
.get("postes_dae")
768 if poste_dae_key
is not u
"":
769 return redirect(reverse('embauche', args
=(poste_dae_key
,)))
770 poste_rh_key
= self
.cleaned_data
.get("postes_rh")
771 if poste_rh_key
is not u
"":
772 return redirect("%s?creer_dossier_dae='M'" % reverse('poste', args
=(poste_rh_key
,)))
774 class EmployeForm(forms
.ModelForm
):
775 """ Formulaire des employés. """
778 fields
= ('employe', 'nom', 'prenom', 'genre')
780 # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison.
781 employe
= forms
.ChoiceField(choices
=(), required
=False)
783 def __init__(self
, *args
, **kwargs
):
784 """ Mise à jour dynamique du contenu du menu des employés. """
785 request
= kwargs
.pop('request', None)
786 super(EmployeForm
, self
).__init__(*args
, **kwargs
)
787 self
.fields
['employe'].choices
= _employe_choices(self
, request
)
791 filtered_archived_fields_form_factory(
793 'classement_anterieur',
794 'classement_titulaire_anterieur',
797 """ Formulaire des dossiers. """
799 exclude
= ('etat', 'employe', 'poste', 'date_debut',)
801 widgets
= dict(statut_residence
=forms
.RadioSelect(),
802 contrat_date_debut
=admin_widgets
.AdminDateWidget(),
803 contrat_date_fin
=admin_widgets
.AdminDateWidget(),
809 class PosteWorkflowForm(WorkflowFormMixin
):
810 bouton_libelles
= POSTE_ETATS_BOUTONS
816 def __init__(self
, *args
, **kwargs
):
817 super(PosteWorkflowForm
, self
).__init__(*args
, **kwargs
)
818 self
.fields
['etat'].help_text
= WF_HELP_TEXT
821 class DossierWorkflowForm(WorkflowFormMixin
):
822 bouton_libelles
= POSTE_ETATS_BOUTONS
# meme workflow que poste...
828 def __init__(self
, *args
, **kwargs
):
829 super(DossierWorkflowForm
, self
).__init__(*args
, **kwargs
)
830 self
.fields
['etat'].help_text
= WF_HELP_TEXT
831 self
._etat_initial
= self
.instance
.etat
834 super(DossierWorkflowForm
, self
).save()
835 poste
= self
.instance
.poste
837 if poste
.etat
== self
._etat_initial
:
838 poste
.etat
= self
.instance
.etat
841 # créer le commentaire automatique pour le poste associé
842 commentaire
= WorkflowCommentaire()
843 commentaire
.content_object
= poste
844 texte
= u
"Validation automatique à travers le dossier [%s] de %s\n%s" %(
847 self
.data
.get('commentaire', ''),
849 commentaire
.texte
= texte
850 commentaire
.etat_initial
= self
.instance
._etat_courant
851 commentaire
.etat_final
= self
.instance
.etat
852 commentaire
.owner
= self
.request
.user
856 class ContratForm(forms
.ModelForm
):
859 fields
= ('type_contrat', 'fichier', )
863 class DAENumeriseeForm(forms
.ModelForm
):
867 fields
= ('dae_numerisee',)
870 class DAEFinaliseesSearchForm(forms
.Form
):
872 label
='Recherche', required
=False,
873 widget
=forms
.TextInput(attrs
={'size': 40})
875 importees
= forms
.ChoiceField(
876 label
='Importation', required
=False, choices
=(
878 ('oui', 'DAE importées seulement'),
879 ('non', 'DAE non-importées seulement'),