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(forms
.ModelForm
):
288 # Utilisé dans templats.
289 montant_mensuel
= forms
.DecimalField(required
=False)
290 montant
= forms
.DecimalField(required
=True, label
='Montant annuel')
293 model
= dae
.Remuneration
295 def __init__(self
, *a
, **kw
):
296 super(FlexibleRemunForm
, self
).__init__(*a
, **kw
)
297 # self.fields['type'].widget = ReadOnlyChoiceWidget(choices=self.fields['type'].choices)
299 def clean_devise(self
):
300 devise
= self
.cleaned_data
['devise']
301 if devise
.code
== 'EUR':
303 implantation
= ref
.Implantation
.objects
.get(
304 id=self
.data
['implantation']
306 liste_taux
= devise
.tauxchange_set
.order_by('-annee')
307 if len(liste_taux
) == 0:
308 raise forms
.ValidationError(
309 u
"La devise %s n'a pas de taux pour l'implantation %s" %
310 (devise
, implantation
)
315 def has_changed(self
):
317 Modification de has_changed pour qu'il ignore les montant a 0
321 changed_data
= self
.changed_data
323 # Type is set in hidden fields, it shouldn't be changed by the
324 # user; ignore when checking if data has changed.
325 if 'type' in changed_data
:
326 changed_data
.pop(changed_data
.index('type'))
328 # Montant is set to 0 in javascript, ifnore 'montant' data if
331 # Generer le key tel qu'identifié dans self.data:
332 montant_key
= '-'.join((self
.prefix
, 'montant'))
334 if ('montant' in changed_data
and
335 self
.data
.get(montant_key
, '0') == '0'):
336 changed_data
.pop(changed_data
.index('montant'))
338 return bool(changed_data
)
341 class ReadOnlyRemunForm(FlexibleRemunForm
):
342 # Utilisé dans templats.
344 def __init__(self
, *a
, **kw
):
345 super (ReadOnlyRemunForm
, self
).__init__(*a
, **kw
)
346 for field
in self
.fields
:
347 field
= self
.fields
[field
]
348 if not isinstance(field
.widget
, (
349 forms
.widgets
.HiddenInput
,
350 forms
.widgets
.Select
)):
351 field
.widget
= ReadOnlyWidget()
352 elif isinstance(field
.widget
, forms
.widgets
.Select
):
353 field
.widget
= ReadOnlyChoiceWidget(choices
=field
.choices
)
356 class GroupedInlineFormset(BaseInlineFormSet
):
361 choice_overrides
=[]):
364 # Create pre-defined groups.
365 self
.groups
= OrderedDict()
367 self
.groups
[group
[0]] = {
373 # Assign each form to a group.
374 for form
in self
.forms
:
375 if bool(form
.initial
):
376 grp
= group_accessor(form
)
377 if grp
[0] not in self
.groups
:
378 self
.groups
[grp
[0]] = {
383 self
.groups
[grp
[0]]['forms'].append(form
)
385 # Add extra forms (n extra for each grop).
387 for i
in xrange(len(self
.groups
) * self
.extra
):
389 self
._construct_form(self
.initial_form_count() + i
))
391 for g
in self
.groups
:
392 for i
in xrange(self
.extra
):
393 tmp_form
= tmp_extras
.pop()
394 self
.groups
[g
]['forms'].append(tmp_form
)
395 self
.forms
.append(tmp_form
)
398 # Override form choices with the data provided in
400 for key
in choice_overrides
:
401 for form
in self
.groups
.get(key
, {'forms': []})['forms']:
402 for field_key
in choice_overrides
[key
]:
403 form
.fields
[field_key
].choices
= choice_overrides
[
407 # Create an iterable for easier access in template.
408 self
.group_list
= self
.groups
.values()
410 # def set_groups(self, group_accessor, groups, group_order=[]):
412 # group_accessor: A function that will get the key and name from
414 # group_order: list the group keys here in a list and
415 # GroupedInlineFormset.groups will be ordered (ordereddict) by
416 # the key sequence provided here. Any missing key from the
420 # # Build group list.
421 # self.groups = OrderedDict()
423 # # self.groups_and_forms = []
424 # for form in self.forms:
425 # group_key, group_name = group_accessor(form)
426 # if not temp_groups.has_key(group_key):
427 # temp_groups[group_key] = {
428 # 'name': group_name,
432 # temp_groups[group_key]['forms'].append(form)
434 # for order_key in group_order:
435 # if temp_groups.has_key(order_key):
436 # self.groups[order_key] = temp_groups.pop(order_key)
438 # for key in temp_groups:
439 # self.groups[key] = temp_groups[key]
443 # self.group_list = self.groups.values()
446 def remun_formset_factory(parent_model
,
448 form
=forms
.ModelForm
,
449 formset
=GroupedInlineFormset
,
458 formfield_callback
=None,
460 choice_overrides
=[]):
461 trs
= rh
.TypeRemuneration
.objects
.all()
462 # extra = max_num = trs.count()
463 fk
= _get_foreign_key(parent_model
, model
, fk_name
=fk_name
)
464 # enforce a max_num=1 when the foreign key to the parent model is unique.
469 'formfield_callback': formfield_callback
,
472 'can_delete': can_delete
,
473 'can_order': can_order
,
478 FormSet
= modelformset_factory(model
, **kwargs
)
480 FormSet
.read_only
= read_only
483 rtype
= form
.initial
['type']
484 if not isinstance(rtype
, rh
.TypeRemuneration
):
485 rtype
= rh
.TypeRemuneration
.objects
.get(id=rtype
)
486 return (rtype
.nature_remuneration
,
487 rtype
.nature_remuneration
492 # Monkey patch FormSet.
493 def __init__(inst
, *a
, **kw
):
494 super(inst
.__class__
, inst
).__init__(*a
, **kw
)
495 inst
.set_groups(groups
, grouper
, choice_overrides
)
497 FormSet
.__init__
= __init__
502 def remun_formset_factory_factory(
504 parent_model
=dae
.Dossier
,
505 model
=dae
.Remuneration
,
506 exclude_archived
=False):
508 Don't we love factory factories?
511 null_choice
= ('', '-' * 10)
512 extras
= 2 if not read_only
else 0
513 can_delete
= False if read_only
else True
514 form_class
= ReadOnlyRemunForm
if read_only
else FlexibleRemunForm
516 choice_override_extra_q
= {}
519 choice_override_extra_q
.update({
523 return remun_formset_factory(
528 can_delete
=can_delete
,
530 groups
= rh
.NATURE_REMUNERATION_CHOICES
,
533 'type': [null_choice
] + list(
534 rh
.TypeRemuneration
.objects
.filter(
535 nature_remuneration
=u
'Traitement',
536 **choice_override_extra_q
).values_list(
541 'type': [null_choice
] + list(
542 rh
.TypeRemuneration
.objects
.filter(
543 nature_remuneration
=u
'Indemnité',
544 **choice_override_extra_q
).values_list(
549 'type': [null_choice
] + list(
550 rh
.TypeRemuneration
.objects
.filter(
551 nature_remuneration
=u
'Charges',
552 **choice_override_extra_q
).values_list(
557 'type': [null_choice
] + list(
558 rh
.TypeRemuneration
.objects
.filter(
559 nature_remuneration
=u
'Accessoire',
560 **choice_override_extra_q
).values_list(
565 'type': [null_choice
] + list(
566 rh
.TypeRemuneration
.objects
.filter(
567 nature_remuneration
=u
'RAS',
568 **choice_override_extra_q
).values_list(
575 RemunForm
= remun_formset_factory_factory(
577 parent_model
=dae
.Dossier
,
578 model
=dae
.Remuneration
,
579 exclude_archived
=True,
582 ReadOnlyRemunFormSet
= remun_formset_factory_factory(
584 parent_model
=dae
.Dossier
,
585 model
=dae
.Remuneration
,
588 PosteCompReadOnlyRemunFormSet
= remun_formset_factory_factory(
590 parent_model
=dae
.PosteComparaison
,
591 model
=dae
.PosteComparaisonRemuneration
,
594 DossierCompReadOnlyRemunFormSet
= remun_formset_factory_factory(
596 parent_model
=dae
.DossierComparaison
,
597 model
=dae
.DossierComparaisonRemuneration
,
601 class PosteForm(filtered_archived_fields_form_factory(
605 """ Formulaire des postes. """
607 # On ne propose que les services actifs
608 service
= forms
.ModelChoiceField(
609 queryset
=rh
.Service
.objects
.all(), required
=True
612 responsable
= AutoCompleteSelectField('responsables', required
=True)
613 #responsable = forms.ModelChoiceField(
614 # queryset=rh.Poste.objects.select_related(depth=1))
616 # La liste des choix est laissée vide. Voir __init__ pour la raison.
617 poste
= forms
.ChoiceField(label
="Nouveau poste ou évolution du poste",
618 choices
=(), required
=False)
620 valeur_point_min
= forms
.ModelChoiceField(
621 queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False
623 valeur_point_max
= forms
.ModelChoiceField(
624 queryset
=rh
.ValeurPoint
.actuelles
.all(), required
=False
629 fields
= ('type_intervention',
630 'poste', 'implantation', 'type_poste', 'service', 'nom',
631 'responsable', 'local', 'expatrie', 'mise_a_disposition',
632 'appel', 'date_debut', 'date_fin',
633 'regime_travail', 'regime_travail_nb_heure_semaine',
634 'classement_min', 'classement_max',
635 'valeur_point_min', 'valeur_point_max',
636 'devise_min', 'devise_max',
637 'salaire_min', 'salaire_max',
638 'indemn_expat_min', 'indemn_expat_max',
639 'indemn_fct_min', 'indemn_fct_max',
640 'charges_patronales_min', 'charges_patronales_max',
641 'autre_min', 'autre_max', 'devise_comparaison',
642 'comp_locale_min', 'comp_locale_max',
643 'comp_universite_min', 'comp_universite_max',
644 'comp_fonctionpub_min', 'comp_fonctionpub_max',
645 'comp_ong_min', 'comp_ong_max',
646 'comp_autre_min', 'comp_autre_max',
649 widgets
= dict(type_intervention
=forms
.RadioSelect(),
650 appel
=forms
.RadioSelect(),
651 nom
=forms
.TextInput(attrs
={'size': 60},),
652 date_debut
=admin_widgets
.AdminDateWidget(),
653 date_fin
=admin_widgets
.AdminDateWidget(),
654 justification
=forms
.Textarea(attrs
={'cols': 80},),
655 #devise_min=forms.Select(attrs={'disabled':'disabled'}),
656 #devise_max=forms.Select(attrs={'disabled':'disabled'}),
659 def __init__(self
, *args
, **kwargs
):
660 """ Mise à jour dynamique du contenu du menu des postes.
662 Si on ne met le menu à jour de cette façon, à chaque instantiation du
663 formulaire, son contenu est mis en cache par le système et il ne
664 reflète pas les changements apportés par les ajouts, modifications,
667 Aussi, dans ce cas-ci, on ne peut pas utiliser un ModelChoiceField
668 car le "id" de chaque choix est spécial (voir _poste_choices).
671 request
= kwargs
.pop('request')
672 super(PosteForm
, self
).__init__(*args
, **kwargs
)
673 self
.fields
['poste'].choices
= self
._poste_choices(request
)
675 self
.fields
['implantation'].choices
= \
676 _implantation_choices(self
, request
)
678 # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1
679 if self
.instance
and self
.instance
.id is None:
680 dossiers
= self
.instance
.get_dossiers()
681 if len(dossiers
) > 0:
682 self
.initial
['service'] = dossiers
[0].poste
.service
684 def _poste_choices(self
, request
):
685 """ Menu déroulant pour les postes.
686 Constitué des postes de RH
688 postes_rh
= rh
.Poste
.objects
.ma_region_ou_service(request
.user
).all()
689 postes_rh
= postes_rh
.select_related(depth
=1)
691 return [('', 'Nouveau poste')] + \
692 sorted([('rh-%s' % p
.id, label_poste_display(p
)) for p
in
698 Validation conditionnelles de certains champs.
700 cleaned_data
= self
.cleaned_data
702 if cleaned_data
.get("local") is False \
703 and cleaned_data
.get("expatrie") is False:
704 msg
= "Le poste doit au moins être ouvert localement " \
706 self
._errors
["local"] = self
.error_class([msg
])
707 self
._errors
["expatrie"] = ''
708 raise forms
.ValidationError(msg
)
713 class ChoosePosteForm(forms
.Form
):
717 # La liste des choix est laissée vide. Voir PosteForm.__init__.
718 postes_dae
= forms
.ChoiceField(choices
=(), required
=False)
719 postes_rh
= forms
.ChoiceField(choices
=(), required
=False)
721 def __init__(self
, request
=None, *args
, **kwargs
):
722 super(ChoosePosteForm
, self
).__init__(*args
, **kwargs
)
723 self
.fields
['postes_dae'].choices
= self
._poste_dae_choices(request
)
724 self
.fields
['postes_rh'].choices
= self
._poste_rh_choices(request
)
726 def _poste_dae_choices(self
, request
):
727 """ Menu déroulant pour les postes."""
728 postes_dae
= dae
.Poste
.objects
.ma_region_ou_service(request
.user
) \
729 .exclude(etat__in
=(POSTE_ETAT_FINALISE
, )) \
730 .annotate(num_dae
=Count('dae_dossiers')) \
732 .order_by('implantation', '-date_debut', )
734 return [('', '----------')] + \
735 [('dae-%s' % p
.id, label_poste_display(p
)) for p
in postes_dae
]
737 def _poste_rh_choices(self
, request
):
738 """ Menu déroulant pour les postes."""
739 postes_dae
= dae
.Poste
.objects
.exclude(etat__in
=(POSTE_ETAT_FINALISE
, ))
740 today
= datetime
.date
.today()
741 id_poste_dae_commences
= [p
.id_rh_id
for p
in postes_dae
if p
.id_rh
is not None]
742 postes_rh
= rh
.Poste
.objects
.ma_region_ou_service(request
.user
) \
743 .exclude(id__in
=id_poste_dae_commences
) \
744 .filter(Q(date_debut__lte
=today
) &
745 (Q(date_fin__gte
=today
) |
746 Q(date_fin__isnull
=True))
748 .order_by('implantation', '-date_debut', )
750 return [('', '----------')] + \
751 [('rh-%s' % p
.id, label_poste_display(p
)) for p
in postes_rh
]
754 cleaned_data
= super(ChoosePosteForm
, self
).clean()
755 postes_dae
= cleaned_data
.get("postes_dae")
756 postes_rh
= cleaned_data
.get("postes_rh")
757 if (postes_dae
is u
"" and postes_rh
is u
"") or \
758 (postes_dae
is not u
"" and postes_rh
is not u
""):
759 raise forms
.ValidationError("Choisissez un poste DAE ou un poste RH")
763 poste_dae_key
= self
.cleaned_data
.get("postes_dae")
764 if poste_dae_key
is not u
"":
765 return redirect(reverse('embauche', args
=(poste_dae_key
,)))
766 poste_rh_key
= self
.cleaned_data
.get("postes_rh")
767 if poste_rh_key
is not u
"":
768 return redirect("%s?creer_dossier_dae='M'" % reverse('poste', args
=(poste_rh_key
,)))
770 class EmployeForm(forms
.ModelForm
):
771 """ Formulaire des employés. """
774 fields
= ('employe', 'nom', 'prenom', 'genre')
776 # La liste des choix est laissée vide. Voir Poste.__init__ pour la raison.
777 employe
= forms
.ChoiceField(choices
=(), required
=False)
779 def __init__(self
, *args
, **kwargs
):
780 """ Mise à jour dynamique du contenu du menu des employés. """
781 request
= kwargs
.pop('request', None)
782 super(EmployeForm
, self
).__init__(*args
, **kwargs
)
783 self
.fields
['employe'].choices
= _employe_choices(self
, request
)
787 filtered_archived_fields_form_factory(
789 'classement_anterieur',
790 'classement_titulaire_anterieur',
793 """ Formulaire des dossiers. """
795 exclude
= ('etat', 'employe', 'poste', 'date_debut',)
797 widgets
= dict(statut_residence
=forms
.RadioSelect(),
798 contrat_date_debut
=admin_widgets
.AdminDateWidget(),
799 contrat_date_fin
=admin_widgets
.AdminDateWidget(),
805 class PosteWorkflowForm(WorkflowFormMixin
):
806 bouton_libelles
= POSTE_ETATS_BOUTONS
812 def __init__(self
, *args
, **kwargs
):
813 super(PosteWorkflowForm
, self
).__init__(*args
, **kwargs
)
814 self
.fields
['etat'].help_text
= WF_HELP_TEXT
817 class DossierWorkflowForm(WorkflowFormMixin
):
818 bouton_libelles
= POSTE_ETATS_BOUTONS
# meme workflow que poste...
824 def __init__(self
, *args
, **kwargs
):
825 super(DossierWorkflowForm
, self
).__init__(*args
, **kwargs
)
826 self
.fields
['etat'].help_text
= WF_HELP_TEXT
827 self
._etat_initial
= self
.instance
.etat
830 super(DossierWorkflowForm
, self
).save()
831 poste
= self
.instance
.poste
833 # créer le commentaire automatique pour le poste associé
834 commentaire
= WorkflowCommentaire()
835 commentaire
.content_object
= poste
836 texte
= u
"Validation automatique à travers le dossier [%s] de %s\n%s" %(
839 self
.data
.get('commentaire', ''),
841 commentaire
.texte
= texte
842 commentaire
.etat_initial
= self
.instance
._etat_courant
843 commentaire
.etat_final
= self
.instance
.etat
844 commentaire
.owner
= self
.request
.user
847 # force l'état du poste
848 poste
.etat
= self
.instance
.etat
852 class ContratForm(forms
.ModelForm
):
855 fields
= ('type_contrat', 'fichier', )
859 class DAENumeriseeForm(forms
.ModelForm
):
863 fields
= ('dae_numerisee',)
866 class DAEFinaliseesSearchForm(forms
.Form
):
868 label
='Recherche', required
=False,
869 widget
=forms
.TextInput(attrs
={'size': 40})
871 importees
= forms
.ChoiceField(
872 label
='Importation', required
=False, choices
=(
874 ('oui', 'DAE importées seulement'),
875 ('non', 'DAE non-importées seulement'),