Fix for salaire de base bug
[auf_rh_dae.git] / project / dae / forms.py
index 8b14afb..373099f 100644 (file)
 # -*- encoding: utf-8 -*-
 
-from django.db.models import Q, Max
+import datetime
+from ordereddict import OrderedDict
+from dateutil.relativedelta import relativedelta
 from django import forms
-from django.forms.models import inlineformset_factory, modelformset_factory
+from django.core.urlresolvers import reverse
+from django.core.exceptions import MultipleObjectsReturned
+from django.forms.models import BaseInlineFormSet
+from django.forms.models import (
+    inlineformset_factory,
+    modelformset_factory,
+    _get_foreign_key,
+    )
+from django.db.models import Q, Max, Count
+from django.shortcuts import redirect
 from django.contrib.admin import widgets as admin_widgets
+
 from ajax_select.fields import AutoCompleteSelectField
-from auf.django.workflow.forms import WorkflowFormMixin
+
 from auf.django.references import models as ref
-from dae import models as dae
-from utils import get_employe_from_user, is_user_dans_services_centraux
-from rh import models as rh
-from workflow import grp_drh, POSTE_ETATS_BOUTONS, DOSSIER_ETAT_FINALISE, POSTE_ETAT_FINALISE
+from auf.django.workflow.forms import WorkflowFormMixin
+from auf.django.workflow.models import WorkflowCommentaire
+
+from project import groups
+from project.rh import models as rh
+from project.dae import models as dae
+from .widgets import ReadOnlyChoiceWidget, ReadOnlyWidget
+from project.dae.workflow import POSTE_ETATS_BOUTONS, POSTE_ETAT_FINALISE
+
+
+def filtered_archived_fields_form_factory(*fields):
+    """
+    Retourne un model form 
+    """
+    class FilterArchivedFields(object):
+        def __init__(self, *a, **kw):
+            super(FilterArchivedFields, self).__init__(*a, **kw)
+            for f in fields:
+                self.fields[f].queryset = (
+                    self.fields[f]._queryset.filter(archive=False)
+                    )
+    return FilterArchivedFields
+
+
+class BaseInlineFormSetWithInitial(BaseInlineFormSet):
+    """
+    Cette classe permet de fournir l'option initial aux inlineformsets.
+    Elle devient désuette en django 1.4.
+    """
+    def __init__(self, data=None, files=None, instance=None,
+                 save_as_new=False, prefix=None, queryset=None, **kwargs):
+
+        self.initial_extra = kwargs.pop('initial', None)
+
+        from django.db.models.fields.related import RelatedObject
+        if instance is None:
+            self.instance = self.fk.rel.to()
+        else:
+            self.instance = instance
+        self.save_as_new = save_as_new
+        # is there a better way to get the object descriptor?
+        self.rel_name = RelatedObject(self.fk.rel.to, self.model, self.fk).get_accessor_name()
+        if queryset is None:
+            queryset = self.model._default_manager
+        qs = queryset.filter(**{self.fk.name: self.instance})
+        super(BaseInlineFormSetWithInitial, self).__init__(data, files, prefix=prefix,
+                                                queryset=qs, **kwargs)
+
+    def _construct_form(self, i, **kwargs):
+        if self.is_bound and i < self.initial_form_count():
+            # Import goes here instead of module-level because importing
+            # django.db has side effects.
+            from django.db import connections
+            pk_key = "%s-%s" % (self.add_prefix(i), self.model._meta.pk.name)
+            pk = self.data[pk_key]
+            pk_field = self.model._meta.pk
+            pk = pk_field.get_db_prep_lookup('exact', pk,
+                connection=connections[self.get_queryset().db])
+            if isinstance(pk, list):
+                pk = pk[0]
+            kwargs['instance'] = self._existing_object(pk)
+        if i < self.initial_form_count() and not kwargs.get('instance'):
+            kwargs['instance'] = self.get_queryset()[i]
+        if i >= self.initial_form_count() and self.initial_extra:
+            # Set initial values for extra forms
+            try:
+                kwargs['initial'] = self.initial_extra[i-self.initial_form_count()]
+            except IndexError:
+                pass
+
+        defaults = {'auto_id': self.auto_id, 'prefix': self.add_prefix(i)}
+        if self.is_bound:
+            defaults['data'] = self.data
+            defaults['files'] = self.files
+        if self.initial:
+            try:
+                defaults['initial'] = self.initial[i]
+            except IndexError:
+                pass
+        # Allow extra forms to be empty.
+        if i >= self.initial_form_count():
+            defaults['empty_permitted'] = True
+        defaults.update(kwargs)
+        form = self.form(**defaults)
+        self.add_fields(form, i)
+        return form
+
 
 def _implantation_choices(obj, request):
     # TRAITEMENT NORMAL
-    employe = get_employe_from_user(request.user)
-    # SERVICE
-    if is_user_dans_services_centraux(request.user):
-        q = Q(**{ 'id' : employe.implantation_id })
-    # REGION
-    else:
-        q = Q(**{ 'region' : employe.implantation.region })
+    employe = groups.get_employe_from_user(request.user)
+    q = Q(**{'zone_administrative__in': groups.get_zones_from_user(request.user)})
 
     # TRAITEMENT DRH
-    if grp_drh in request.user.groups.all():
+    user_groupes = [g.name for g in request.user.groups.all()]
+    if groups.DRH_NIVEAU_1 in user_groupes or \
+       groups.DRH_NIVEAU_2 in user_groupes:
         q = Q()
-    return [('', '----------')] + [(i.id, unicode(i), )for i in ref.Implantation.objects.filter(q)]
+    return [('', '----------')] + \
+            [(i.id, unicode(i), )for i in ref.Implantation.objects.filter(q)]
+
 
 def _employe_choices(obj, request):
     # TRAITEMENT NORMAL
-    employe = get_employe_from_user(request.user)
-    # SERVICE
-    if is_user_dans_services_centraux(request.user):
-        q_dae_region_service = Q(poste__implantation=employe.implantation)
-        q_rh_region_service = Q(poste__implantation=employe.implantation)
-    # REGION
-    else:
-        q_dae_region_service = Q(poste__implantation__region=employe.implantation.region)
-        q_rh_region_service = Q(poste__implantation__region=employe.implantation.region)
+    employe = groups.get_employe_from_user(request.user)
+    q_dae_region_service = Q(
+        poste__implantation__zone_administrative__in=(
+            groups.get_zones_from_user(request.user)
+        )
+    )
+    q_rh_region_service = Q(
+        poste__implantation__zone_administrative__in=(
+            groups.get_zones_from_user(request.user)
+        )
+    )
     # TRAITEMENT DRH
-    if grp_drh in request.user.groups.all():
+    user_groupes = [g.name for g in request.user.groups.all()]
+    if groups.DRH_NIVEAU_1 in user_groupes or \
+       groups.DRH_NIVEAU_2 in user_groupes:
         q_dae_region_service = Q()
         q_rh_region_service = Q()
 
-    # On filtre les employes avec les droits régionaux et on s'assure que c'est bien le dernier dossier en date pour sortir l'employe
-    # On retient un employé qui travaille présentement dans la même région que le user connecté.
-    dossiers_regionaux_ids = [d.id for d in dae.Dossier.objects.filter(q_dae_region_service)]
-    employes_ids = [d['employe'] for d in dae.Dossier.objects.values('employe').annotate(dernier_dossier=Max('id')) if d['dernier_dossier'] in dossiers_regionaux_ids]
+    # On filtre les employes avec les droits régionaux et on s'assure que
+    # c'est bien le dernier dossier en date pour sortir l'employe. On retient
+    # un employé qui travaille présentement dans la même région que le user
+    # connecté.
+    dossiers_regionaux_ids = [
+        d.id for d in dae.Dossier.objects.filter(q_dae_region_service)
+    ]
+    employes_ids = [
+        d['employe']
+        for d in dae.Dossier.objects
+        .values('employe')
+        .annotate(dernier_dossier=Max('id'))
+        if d['dernier_dossier'] in dossiers_regionaux_ids
+    ]
     dae_employe = dae.Employe.objects.filter(id__in=employes_ids)
     dae_ = dae_employe.filter(id_rh__isnull=True)
     copies = dae_employe.filter(Q(id_rh__isnull=False))
     id_copies = [p.id_rh_id for p in copies.all()]
 
-    dossiers_regionaux_ids = [d.id for d in rh.Dossier.objects.filter(q_rh_region_service)]
-    employes_ids = [d['employe'] for d in rh.Dossier.objects.values('employe').annotate(dernier_dossier=Max('id')) if d['dernier_dossier'] in dossiers_regionaux_ids]
-    rhv1 = rh.Employe.objects.filter(id__in=employes_ids).exclude(id__in=id_copies)
-
-    # On ajoute les nouveaux Employés DAE qui ont été crées, mais qui n'ont pas de Dossier associés
+    dossiers_regionaux_ids = [
+        d.id for d in rh.Dossier.objects.filter(q_rh_region_service)
+    ]
+    employes_ids = [
+        d['employe']
+        for d in rh.Dossier.objects
+        .values('employe')
+        .annotate(dernier_dossier=Max('id'))
+        if d['dernier_dossier'] in dossiers_regionaux_ids
+    ]
+    rhv1 = rh.Employe.objects \
+            .filter(id__in=employes_ids) \
+            .exclude(id__in=id_copies)
+
+    # On ajoute les nouveaux Employés DAE qui ont été crées, mais qui n'ont
+    # pas de Dossier associés
     employes_avec_dae = [d.employe_id for d in dae.Dossier.objects.all()]
     employes_orphelins = dae.Employe.objects.exclude(id__in=employes_avec_dae)
 
+    def option_label(employe, extra=""):
+        if extra:
+            extra = " [%s]" % extra
+        return "%s %s %s" % (employe.nom.upper(), employe.prenom.title(), extra)
 
-    def option_label(employe):
-        return "%s %s" % (employe.nom.upper(), employe.prenom.title())
+    lbl_rh = sorted([('rh-%s' % p.id, option_label(p, "existant dans rh")) for p in rhv1],
+            key=lambda t: t[1])
+    lbl_dae = sorted([('dae-%s' % p.id, option_label(p)) for p in dae_ | copies | employes_orphelins],
+            key=lambda t: t[1])
+    return [('', 'Nouvel employé')] + lbl_rh + lbl_dae
 
-    return [('', 'Nouvel employé')] + \
-           sorted([('dae-%s' % p.id, option_label(p)) for p in dae_ | copies | employes_orphelins] +
-                  [('rh-%s' % p.id, option_label(p)) for p in rhv1],
-                  key=lambda t: t[1])
 
 def label_poste_display(poste):
     """Formate un visuel pour un poste dans une liste déroulante"""
-    label = u"%s - %s [%s]" %(poste.type_poste, poste.type_poste.famille_emploi.nom, poste.id)
+    annee = ""
+    if poste.date_debut:
+        annee = poste.date_debut.year
+
+    nom = poste.nom
+    label = u"%s (%s) %s [%s]" % (
+        annee,
+        poste.implantation.nom_court,
+        nom,
+        #poste.type_poste.categorie_emploi.nom,
+        poste.id,
+        )
     return label
 
-PostePieceForm = inlineformset_factory(dae.Poste, dae.PostePiece)
+
+PostePieceFormSet = inlineformset_factory(dae.Poste, dae.PostePiece,)
 DossierPieceForm = inlineformset_factory(dae.Dossier, dae.DossierPiece)
-FinancementForm = inlineformset_factory(dae.Poste, dae.PosteFinancement, extra=2)
 
-class DossierComparaisonForm(forms.ModelForm):
+# Ce formset est utilisé dans le cas de la création de poste prépopulé avec les
+# données de RH
+FinancementFormSetInitial = inlineformset_factory(
+    dae.Poste,
+    dae.PosteFinancement,
+    formset=BaseInlineFormSetWithInitial,
+    extra=2
+)
+FinancementFormSet = inlineformset_factory(
+    dae.Poste,
+    dae.PosteFinancement,
+    extra=2
+)
+
+
+class DossierComparaisonForm(
+    filtered_archived_fields_form_factory(
+        'classement',
+        ),
+    forms.ModelForm):
 
     recherche = AutoCompleteSelectField('dossiers', required=False)
-    poste = forms.CharField(max_length=255, widget=forms.TextInput(attrs={'size':'60'}))
+    poste = forms.CharField(
+        max_length=255, widget=forms.TextInput(attrs={'size': '60'})
+    )
+    cmp_dossier = forms.IntegerField(
+        widget=forms.widgets.HiddenInput,
+        required=False
+        )
 
     class Meta:
         model = dae.DossierComparaison
@@ -91,48 +249,345 @@ DossierComparaisonFormSet = modelformset_factory(
     dae.DossierComparaison, extra=3, max_num=3, form=DossierComparaisonForm
 )
 
-class PosteComparaisonForm(forms.ModelForm):
 
-    recherche = AutoCompleteSelectField('postes', required=False)
+class PosteComparaisonForm(
+    filtered_archived_fields_form_factory('classement'),
+    forms.ModelForm):
+
+    recherche = AutoCompleteSelectField('dae_postes', required=False)
+
+    cmp_poste = forms.IntegerField(
+        widget=forms.widgets.HiddenInput,
+        required=False,
+        )
 
     class Meta:
         model = dae.PosteComparaison
         exclude = ('poste',)
 
-PosteComparaisonFormSet = modelformset_factory(
-    dae.PosteComparaison, extra=3, max_num=3, form=PosteComparaisonForm
+# Ce formset est utilisé dans le cas de la création de poste prépopulé avec les
+# données de RH
+PosteComparaisonFormSetInitial = inlineformset_factory(
+    dae.Poste,
+    dae.PosteComparaison,
+    extra=3,
+    max_num=3,
+    form=PosteComparaisonForm,
+    formset=BaseInlineFormSetWithInitial,
+)
+PosteComparaisonFormSet = inlineformset_factory(
+    dae.Poste,
+    dae.PosteComparaison,
+    extra=3,
+    max_num=3,
+    form=PosteComparaisonForm,
 )
 
-class FlexibleRemunForm(forms.ModelForm):
 
+class FlexibleRemunForm(
+    filtered_archived_fields_form_factory(
+        'type',
+        ),
+    forms.ModelForm):
+    # Utilisé dans templats.
     montant_mensuel = forms.DecimalField(required=False)
     montant = forms.DecimalField(required=True, label='Montant annuel')
 
     class Meta:
         model = dae.Remuneration
 
+    def __init__(self, *a, **kw):
+        super(FlexibleRemunForm, self).__init__(*a, **kw)
+        # self.fields['type'].widget = ReadOnlyChoiceWidget(choices=self.fields['type'].choices)
+
     def clean_devise(self):
         devise = self.cleaned_data['devise']
         if devise.code == 'EUR':
             return devise
-        implantation = ref.Implantation.objects.get(id=self.data['implantation'])
+        implantation = ref.Implantation.objects.get(
+            id=self.data['implantation']
+        )
         liste_taux = devise.tauxchange_set.order_by('-annee')
         if len(liste_taux) == 0:
-            raise forms.ValidationError(u"La devise %s n'a pas de taux pour l'implantation %s" % (devise, implantation))
+            raise forms.ValidationError(
+                u"La devise %s n'a pas de taux pour l'implantation %s" %
+                (devise, implantation)
+            )
         else:
             return devise
 
-RemunForm = inlineformset_factory(
-    dae.Dossier, dae.Remuneration, extra=5, form=FlexibleRemunForm
+    def has_changed(self):
+        """
+        Modification de has_changed pour qu'il ignore les montant a 0
+        et les 'types'.
+        """
+
+        changed_data = self.changed_data
+
+        # Type is set in hidden fields, it shouldn't be changed by the
+        # user; ignore when checking if data has changed.
+        if 'type' in changed_data:
+            changed_data.pop(changed_data.index('type'))
+
+        # Montant is set to 0 in javascript, ifnore 'montant' data if
+        # its value is 0.
+
+        # Generer le key tel qu'identifié dans self.data:
+        montant_key = '-'.join((self.prefix, 'montant'))
+
+        if ('montant' in changed_data and
+            self.data.get(montant_key, '0') == '0'):
+            changed_data.pop(changed_data.index('montant'))
+        
+        return bool(changed_data)
+
+
+class ReadOnlyRemunForm(FlexibleRemunForm):
+    # Utilisé dans templats.
+
+    def __init__(self, *a, **kw):
+        super (ReadOnlyRemunForm, self).__init__(*a, **kw)
+        for field in self.fields:
+            field = self.fields[field]
+            if not isinstance(field.widget, (
+                    forms.widgets.HiddenInput,
+                    forms.widgets.Select)):
+                field.widget = ReadOnlyWidget()
+            elif isinstance(field.widget, forms.widgets.Select):
+                field.widget = ReadOnlyChoiceWidget(choices=field.choices)
+
+
+class GroupedInlineFormset(BaseInlineFormSet):
+
+    def set_groups(self,
+                   groups,
+                   group_accessor,
+                   choice_overrides=[]):
+
+
+        # Create pre-defined groups.
+        self.groups = OrderedDict()
+        for group in groups:
+            self.groups[group[0]] = {
+                'name': group[1],
+                'key': group[0],
+                'forms': [],
+                }
+
+        # Assign each form to a group.
+        ungrouped_forms = []
+        for form in self.forms:
+            if bool(form.initial):
+                grp = group_accessor(form)
+                if grp[0] not in self.groups:
+                    self.groups[grp[0]] = {
+                        'name': grp[1],
+                        'key': grp[0],
+                        'forms': [],
+                        }
+                self.groups[grp[0]]['forms'].append(form)
+            else:
+                ungrouped_forms.append(form)
+            
+    
+        # Distribuer les extras de django dans les groupes, et ajouter
+        # des extras pour les groupes en nécessitant.
+        f_count = len(self.forms)
+        for g in self.groups:
+            for i in xrange(f_count, f_count + self.extra):
+                if len(ungrouped_forms) == 0:
+                    f_count += 1
+
+                if len(ungrouped_forms) > 0:
+                    new_form = ungrouped_forms.pop()
+                else:
+                    new_form = self._construct_form(i)
+                    self.forms.append(new_form)
+
+                self.groups[g]['forms'].append(new_form)
+                
+
+        # Override form choices with the data provided in
+        # choice_overrides
+        for key in choice_overrides:
+            for form in self.groups.get(key, {'forms': []})['forms']:
+                for field_key in choice_overrides[key]:
+                    form.fields[field_key].choices = choice_overrides[
+                        key][field_key]
+                
+
+        # Create an iterable for easier access in template.
+        self.group_list = self.groups.values()
+
+
+def remun_formset_factory(parent_model,
+                          model,
+                          form=forms.ModelForm,
+                          formset=GroupedInlineFormset,
+                          fk_name=None,
+                          fields=None,
+                          exclude=None,
+                          can_order=False,
+                          can_delete=True,
+                          read_only=False,
+                          extra=2,
+                          max_num=None,
+                          formfield_callback=None,
+                          groups=None,
+                          choice_overrides=[]):
+    trs = rh.TypeRemuneration.objects.all()
+    # extra = max_num = trs.count()
+    fk = _get_foreign_key(parent_model, model, fk_name=fk_name)
+    # enforce a max_num=1 when the foreign key to the parent model is unique.
+    if fk.unique:
+        max_num = 1
+    kwargs = {
+        'form': form,
+        'formfield_callback': formfield_callback,
+        'formset': formset,
+        'extra': extra,
+        'can_delete': can_delete,
+        'can_order': can_order,
+        'fields': fields,
+        'exclude': exclude,
+        'max_num': max_num,
+    }
+    FormSet = modelformset_factory(model, **kwargs)
+    FormSet.fk = fk
+    FormSet.read_only = read_only
+
+    def grouper(form):
+        rtype = form.initial['type']
+        if not isinstance(rtype, rh.TypeRemuneration):
+            rtype = rh.TypeRemuneration.objects.get(id=rtype)
+        return (rtype.nature_remuneration,
+                rtype.nature_remuneration
+                )
+
+
+
+    # Monkey patch FormSet.
+    def __init__(inst, *a, **kw):
+        super(inst.__class__, inst).__init__(*a, **kw)
+        inst.set_groups(groups, grouper, choice_overrides)
+
+    FormSet.__init__ = __init__
+
+    return FormSet
+
+
+def remun_formset_factory_factory(
+    read_only=False,
+    parent_model=dae.Dossier,
+    model=dae.Remuneration,
+    exclude_archived=False):
+    """
+    Don't we love factory factories?
+    """
+    
+    null_choice = ('', '-' * 10)
+    extras = 2 if not read_only else 0
+    can_delete = False if read_only else True
+    form_class = ReadOnlyRemunForm if read_only else FlexibleRemunForm
+
+    choice_override_extra_q = {}
+
+    if exclude_archived:
+        choice_override_extra_q.update({
+            'archive': False
+            })
+    
+    return remun_formset_factory(
+        parent_model,
+        model,
+        form=form_class,
+        extra=extras,
+        can_delete=can_delete,
+        read_only=read_only,
+        groups = rh.NATURE_REMUNERATION_CHOICES,
+        choice_overrides = {
+            u'Traitement': {
+                'type': [null_choice] + list(
+                    rh.TypeRemuneration.objects.filter(
+                        nature_remuneration=u'Traitement',
+                        **choice_override_extra_q).values_list(
+                        'id', 'nom')
+                    )
+                },
+            u'Indemnité': {
+                'type': [null_choice] + list(
+                    rh.TypeRemuneration.objects.filter(
+                        nature_remuneration=u'Indemnité',
+                        **choice_override_extra_q).values_list(
+                        'id', 'nom')
+                    )
+                },
+            u'Charges': {
+                'type': [null_choice] + list(
+                    rh.TypeRemuneration.objects.filter(
+                        nature_remuneration=u'Charges',
+                        **choice_override_extra_q).values_list(
+                        'id', 'nom')
+                    )
+                },
+            u'Accessoire': {
+                'type': [null_choice] + list(
+                    rh.TypeRemuneration.objects.filter(
+                        nature_remuneration=u'Accessoire',
+                        **choice_override_extra_q).values_list(
+                        'id', 'nom')
+                    )
+                },
+            u'RAS': {
+                'type': [null_choice] + list(
+                    rh.TypeRemuneration.objects.filter(
+                        nature_remuneration=u'RAS',
+                        **choice_override_extra_q).values_list(
+                        'id', 'nom')
+                    )
+                },
+            },
+        )
+
+
+RemunForm = remun_formset_factory_factory(
+    read_only=False,
+    parent_model=dae.Dossier,
+    model=dae.Remuneration,
+    exclude_archived=True,
 )
 
-class PosteForm(forms.ModelForm):
+ReadOnlyRemunFormSet = remun_formset_factory_factory(
+    read_only=True,
+    parent_model=dae.Dossier,
+    model=dae.Remuneration,
+    )
+
+PosteCompReadOnlyRemunFormSet = remun_formset_factory_factory(
+    read_only=True,
+    parent_model=dae.PosteComparaison,
+    model=dae.PosteComparaisonRemuneration,
+    )
+
+DossierCompReadOnlyRemunFormSet = remun_formset_factory_factory(
+    read_only=True,
+    parent_model=dae.DossierComparaison,
+    model=dae.DossierComparaisonRemuneration,
+    )
+
+
+class PosteForm(filtered_archived_fields_form_factory(
+        'classement_min',
+        'classement_max',),
+                forms.ModelForm):
     """ Formulaire des postes. """
 
     # On ne propose que les services actifs
-    service = forms.ModelChoiceField(queryset=rh.Service.objects.filter(actif=True), required=True)
+    service = forms.ModelChoiceField(
+        queryset=rh.Service.objects.all(), required=True
+    )
 
-    responsable=AutoCompleteSelectField('responsables', required=True)
+    responsable = AutoCompleteSelectField('responsables', required=True)
     #responsable = forms.ModelChoiceField(
     #        queryset=rh.Poste.objects.select_related(depth=1))
 
@@ -140,13 +595,15 @@ class PosteForm(forms.ModelForm):
     poste = forms.ChoiceField(label="Nouveau poste ou évolution du poste",
                               choices=(), required=False)
 
-    valeur_point_min  = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
-    valeur_point_max = forms.ModelChoiceField(queryset=rh.ValeurPoint.actuelles.all(), required=False)
-
+    valeur_point_min = forms.ModelChoiceField(
+        queryset=rh.ValeurPoint.actuelles.all(), required=False
+    )
+    valeur_point_max = forms.ModelChoiceField(
+        queryset=rh.ValeurPoint.actuelles.all(), required=False
+    )
 
     class Meta:
         model = dae.Poste
-        exclude = ('actif', )
         fields = ('type_intervention',
                   'poste', 'implantation', 'type_poste', 'service', 'nom',
                   'responsable', 'local', 'expatrie', 'mise_a_disposition',
@@ -192,43 +649,38 @@ class PosteForm(forms.ModelForm):
         request = kwargs.pop('request')
         super(PosteForm, self).__init__(*args, **kwargs)
         self.fields['poste'].choices = self._poste_choices(request)
-        self.fields['implantation'].choices = _implantation_choices(self, request)
+        
+        self.fields['implantation'].choices = \
+                _implantation_choices(self, request)
 
         # Quand le dae.Poste n'existe pas, on recherche dans les dossiers rhv1
         if self.instance and self.instance.id is None:
             dossiers = self.instance.get_dossiers()
             if len(dossiers) > 0:
                 self.initial['service'] = dossiers[0].poste.service
-                self.initial['nom'] = "%s %s" % (self.initial['nom'], self.instance.get_complement_nom())
-
 
     def _poste_choices(self, request):
         """ Menu déroulant pour les postes.
-
-        Constitué des postes de dae et des postes de rh_v1 qui n'ont pas
-        d'équivalent dans dae.
-
+        Constitué des postes de RH
         """
-        dae_ = dae.Poste.objects.ma_region_ou_service(request.user).filter(actif=True, id_rh__isnull=True)
-        copies = dae.Poste.objects.ma_region_ou_service(request.user).exclude(id_rh__isnull=True)
-        id_copies = [p.id_rh_id for p in copies.all()]
-        rhv1 = rh.Poste.objects.ma_region_ou_service(request.user).filter(actif=True).exclude(id__in=id_copies)
-        # Optimisation de la requête
-        rhv1 = rhv1.select_related(depth=1)
+        postes_rh = rh.Poste.objects.ma_region_ou_service(request.user).all()
+        postes_rh = postes_rh.select_related(depth=1)
 
         return [('', 'Nouveau poste')] + \
-               sorted([('dae-%s' % p.id, label_poste_display(p)) for p in dae_ | copies] +
-                      [('rh-%s' % p.id, label_poste_display(p)) for p in rhv1],
+               sorted([('rh-%s' % p.id, label_poste_display(p)) for p in
+                   postes_rh],
                       key=lambda t: t[1])
 
     def clean(self):
         """
         Validation conditionnelles de certains champs.
         """
-        cleaned_data  = self.cleaned_data
+        cleaned_data = self.cleaned_data
 
-        if cleaned_data.get("local") is False and cleaned_data.get("expatrie") is False:
-            msg = "Le poste doit au moins être ouvert localement ou aux expatriés"
+        if cleaned_data.get("local") is False \
+           and cleaned_data.get("expatrie") is False:
+            msg = "Le poste doit au moins être ouvert localement " \
+                    "ou aux expatriés"
             self._errors["local"] = self.error_class([msg])
             self._errors["expatrie"] = ''
             raise forms.ValidationError(msg)
@@ -236,39 +688,62 @@ class PosteForm(forms.ModelForm):
         return cleaned_data
 
 
-
-    def save(self, *args, **kwargs):
-        kwargs2 = kwargs.copy()
-        kwargs2['commit'] = False
-        poste = super(PosteForm, self).save(*args, **kwargs2)
-        # id_rh
-        if 'commit' not in kwargs or kwargs['commit']:
-            poste.save()
-        return poste
-
-
-class ChoosePosteForm(forms.ModelForm):
+class ChoosePosteForm(forms.Form):
     class Meta:
-        model = dae.Poste
         fields = ('poste',)
 
     # La liste des choix est laissée vide. Voir PosteForm.__init__.
-    poste = forms.ChoiceField(choices=(), required=False)
+    postes_dae = forms.ChoiceField(choices=(), required=False)
+    postes_rh = forms.ChoiceField(choices=(), required=False)
 
     def __init__(self, request=None, *args, **kwargs):
         super(ChoosePosteForm, self).__init__(*args, **kwargs)
-        self.fields['poste'].choices = self._poste_choices(request)
+        self.fields['postes_dae'].choices = self._poste_dae_choices(request)
+        self.fields['postes_rh'].choices = self._poste_rh_choices(request)
 
-    def _poste_choices(self, request):
-        """ Menu déroulant pour les postes. """
-        dae_ = dae.Poste.objects.ma_region_ou_service(request.user).filter(id_rh__isnull=True)
-        copies = dae.Poste.objects.ma_region_ou_service(request.user).exclude(id_rh__isnull=True)
-        id_copies = [p.id_rh_id for p in copies.all()]
+    def _poste_dae_choices(self, request):
+        """ Menu déroulant pour les postes."""
+        postes_dae = dae.Poste.objects.ma_region_ou_service(request.user) \
+                .exclude(etat__in=(POSTE_ETAT_FINALISE, )) \
+                .annotate(num_dae=Count('dae_dossiers')) \
+                .filter(num_dae=0) \
+                .order_by('implantation', '-date_debut', )
 
         return [('', '----------')] + \
-               sorted([('dae-%s' % p.id, unicode(p)) for p in dae_ | copies],
-                      key=lambda t: t[1])
+               [('dae-%s' % p.id, label_poste_display(p)) for p in postes_dae]
+
+    def _poste_rh_choices(self, request):
+        """ Menu déroulant pour les postes."""
+        postes_dae = dae.Poste.objects.exclude(etat__in=(POSTE_ETAT_FINALISE, ))
+        today = datetime.date.today()
+        id_poste_dae_commences = [p.id_rh_id for p in postes_dae if p.id_rh is not None]
+        postes_rh = rh.Poste.objects.ma_region_ou_service(request.user) \
+                .exclude(id__in=id_poste_dae_commences) \
+                .filter(Q(date_debut__lte=today) &
+                        (Q(date_fin__gte=today) |
+                         Q(date_fin__isnull=True))
+                        ) \
+                .order_by('implantation', '-date_debut', )
+
+        return [('', '----------')] + \
+               [('rh-%s' % p.id, label_poste_display(p)) for p in postes_rh]
 
+    def clean(self):
+        cleaned_data = super(ChoosePosteForm, self).clean()
+        postes_dae = cleaned_data.get("postes_dae")
+        postes_rh = cleaned_data.get("postes_rh")
+        if (postes_dae is u"" and postes_rh is u"") or \
+           (postes_dae is not u"" and postes_rh is not u""):
+                raise forms.ValidationError("Choisissez un poste DAE ou un poste RH")
+        return cleaned_data
+
+    def redirect(self):
+        poste_dae_key = self.cleaned_data.get("postes_dae")
+        if poste_dae_key is not u"":
+            return redirect(reverse('embauche', args=(poste_dae_key,)))
+        poste_rh_key = self.cleaned_data.get("postes_rh")
+        if poste_rh_key is not u"":
+            return redirect("%s?creer_dossier_dae='M'" % reverse('poste', args=(poste_rh_key,)))
 
 class EmployeForm(forms.ModelForm):
     """ Formulaire des employés. """
@@ -286,10 +761,16 @@ class EmployeForm(forms.ModelForm):
         self.fields['employe'].choices = _employe_choices(self, request)
 
 
-class DossierForm(forms.ModelForm):
+class DossierForm(
+    filtered_archived_fields_form_factory(
+        'classement',
+        'classement_anterieur',
+        'classement_titulaire_anterieur',
+        ),
+    forms.ModelForm):
     """ Formulaire des dossiers. """
     class Meta:
-        exclude= ('etat', 'employe', 'poste', 'date_debut', )
+        exclude = ('etat', 'employe', 'poste', 'date_debut',)
         model = dae.Dossier
         widgets = dict(statut_residence=forms.RadioSelect(),
                        contrat_date_debut=admin_widgets.AdminDateWidget(),
@@ -298,8 +779,10 @@ class DossierForm(forms.ModelForm):
 
 WF_HELP_TEXT = ""
 
+
 class PosteWorkflowForm(WorkflowFormMixin):
     bouton_libelles = POSTE_ETATS_BOUTONS
+
     class Meta:
         fields = ('etat', )
         model = dae.Poste
@@ -310,7 +793,8 @@ class PosteWorkflowForm(WorkflowFormMixin):
 
 
 class DossierWorkflowForm(WorkflowFormMixin):
-    bouton_libelles = POSTE_ETATS_BOUTONS # meme workflow que poste...
+    bouton_libelles = POSTE_ETATS_BOUTONS  # meme workflow que poste...
+
     class Meta:
         fields = ('etat', )
         model = dae.Dossier
@@ -323,42 +807,49 @@ class DossierWorkflowForm(WorkflowFormMixin):
     def save(self):
         super(DossierWorkflowForm, self).save()
         poste = self.instance.poste
+
         if poste.etat == self._etat_initial:
             poste.etat = self.instance.etat
             poste.save()
 
+            # créer le commentaire automatique pour le poste associé
+            commentaire = WorkflowCommentaire()
+            commentaire.content_object = poste
+            texte = u"Validation automatique à travers le dossier [%s] de %s\n%s" %(
+                self.instance.id,
+                self.instance,
+                self.data.get('commentaire', ''),
+                )
+            commentaire.texte = texte
+            commentaire.etat_initial = self.instance._etat_courant
+            commentaire.etat_final = self.instance.etat
+            commentaire.owner = self.request.user
+            commentaire.save()
+
+
 class ContratForm(forms.ModelForm):
 
     class Meta:
-        fields = ('type_contrat', )
+        fields = ('type_contrat', 'fichier', )
         model = dae.Contrat
 
+
 class DAENumeriseeForm(forms.ModelForm):
 
     class Meta:
         model = dae.Dossier
         fields = ('dae_numerisee',)
 
-class DAEImportableForm(forms.Form):
-    qs_poste = dae.Poste.objects.filter(etat=POSTE_ETAT_FINALISE)
-    qs_dossier = dae.Dossier.objects.filter(etat=DOSSIER_ETAT_FINALISE)
-    poste = forms.ModelChoiceField(queryset=qs_poste, label="Poste finalisé", required=False)
-    dossier = forms.ModelChoiceField(queryset=qs_dossier, label="DAE finalisée", required=False)
-
-    def clean_poste(self):
-        poste = self.cleaned_data['poste']
-        if poste is not None and poste.est_importe():
-            raise forms.ValidationError("Ce poste a déjà été importé")
-        return poste
-
-    def clean_dossier(self):
-        dossier = self.cleaned_data['dossier']
-        if dossier is not None and not dossier.poste.est_importe():
-            raise forms.ValidationError("Le poste de ce dossier doit être importé avant de pouvoir importer le dossier.")
-        return dossier
-
-    def importer_poste(self):
-        poste = self.cleaned_data['poste']
-        if poste is not None and not poste.est_importe():
-            poste.importer()
-        
+
+class DAEFinaliseesSearchForm(forms.Form):
+    q = forms.CharField(
+        label='Recherche', required=False,
+        widget=forms.TextInput(attrs={'size': 40})
+    )
+    importees = forms.ChoiceField(
+        label='Importation', required=False, choices=(
+            ('', ''),
+            ('oui', 'DAE importées seulement'),
+            ('non', 'DAE non-importées seulement'),
+        )
+    )