Fix for salaire de base bug
[auf_rh_dae.git] / project / dae / forms.py
index 916f3ac..373099f 100644 (file)
@@ -2,8 +2,10 @@
 
 import datetime
 from ordereddict import OrderedDict
 
 import datetime
 from ordereddict import OrderedDict
+from dateutil.relativedelta import relativedelta
 from django import forms
 from django.core.urlresolvers import reverse
 from django import forms
 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,
 from django.forms.models import BaseInlineFormSet
 from django.forms.models import (
     inlineformset_factory,
@@ -23,10 +25,24 @@ 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 project import groups
 from project.rh import models as rh
 from project.dae import models as dae
-from .widgets import ReadOnlyChoiceWidget
+from .widgets import ReadOnlyChoiceWidget, ReadOnlyWidget
 from project.dae.workflow import POSTE_ETATS_BOUTONS, POSTE_ETAT_FINALISE
 
 
 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.
 class BaseInlineFormSetWithInitial(BaseInlineFormSet):
     """
     Cette classe permet de fournir l'option initial aux inlineformsets.
@@ -94,7 +110,7 @@ class BaseInlineFormSetWithInitial(BaseInlineFormSet):
 def _implantation_choices(obj, request):
     # TRAITEMENT NORMAL
     employe = groups.get_employe_from_user(request.user)
 def _implantation_choices(obj, request):
     # TRAITEMENT NORMAL
     employe = groups.get_employe_from_user(request.user)
-    q = Q(**{'zone_administrative': employe.implantation.zone_administrative})
+    q = Q(**{'zone_administrative__in': groups.get_zones_from_user(request.user)})
 
     # TRAITEMENT DRH
     user_groupes = [g.name for g in request.user.groups.all()]
 
     # TRAITEMENT DRH
     user_groupes = [g.name for g in request.user.groups.all()]
@@ -109,13 +125,13 @@ def _employe_choices(obj, request):
     # TRAITEMENT NORMAL
     employe = groups.get_employe_from_user(request.user)
     q_dae_region_service = Q(
     # TRAITEMENT NORMAL
     employe = groups.get_employe_from_user(request.user)
     q_dae_region_service = Q(
-        poste__implantation__zone_administrative=(
-            employe.implantation.zone_administrative
+        poste__implantation__zone_administrative__in=(
+            groups.get_zones_from_user(request.user)
         )
     )
     q_rh_region_service = Q(
         )
     )
     q_rh_region_service = Q(
-        poste__implantation__zone_administrative=(
-            employe.implantation.zone_administrative
+        poste__implantation__zone_administrative__in=(
+            groups.get_zones_from_user(request.user)
         )
     )
     # TRAITEMENT DRH
         )
     )
     # TRAITEMENT DRH
@@ -210,12 +226,20 @@ FinancementFormSet = inlineformset_factory(
 )
 
 
 )
 
 
-class DossierComparaisonForm(forms.ModelForm):
+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'})
     )
 
     recherche = AutoCompleteSelectField('dossiers', required=False)
     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
 
     class Meta:
         model = dae.DossierComparaison
@@ -226,10 +250,17 @@ DossierComparaisonFormSet = modelformset_factory(
 )
 
 
 )
 
 
-class PosteComparaisonForm(forms.ModelForm):
+class PosteComparaisonForm(
+    filtered_archived_fields_form_factory('classement'),
+    forms.ModelForm):
 
     recherche = AutoCompleteSelectField('dae_postes', required=False)
 
 
     recherche = AutoCompleteSelectField('dae_postes', required=False)
 
+    cmp_poste = forms.IntegerField(
+        widget=forms.widgets.HiddenInput,
+        required=False,
+        )
+
     class Meta:
         model = dae.PosteComparaison
         exclude = ('poste',)
     class Meta:
         model = dae.PosteComparaison
         exclude = ('poste',)
@@ -253,8 +284,12 @@ PosteComparaisonFormSet = inlineformset_factory(
 )
 
 
 )
 
 
-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')
 
     montant_mensuel = forms.DecimalField(required=False)
     montant = forms.DecimalField(required=True, label='Montant annuel')
 
@@ -263,7 +298,7 @@ class FlexibleRemunForm(forms.ModelForm):
 
     def __init__(self, *a, **kw):
         super(FlexibleRemunForm, self).__init__(*a, **kw)
 
     def __init__(self, *a, **kw):
         super(FlexibleRemunForm, self).__init__(*a, **kw)
-        self.fields['type'].widget = ReadOnlyChoiceWidget(choices=self.fields['type'].choices)
+        # self.fields['type'].widget = ReadOnlyChoiceWidget(choices=self.fields['type'].choices)
 
     def clean_devise(self):
         devise = self.cleaned_data['devise']
 
     def clean_devise(self):
         devise = self.cleaned_data['devise']
@@ -307,41 +342,81 @@ class FlexibleRemunForm(forms.ModelForm):
         return bool(changed_data)
 
 
         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):
 
 class GroupedInlineFormset(BaseInlineFormSet):
 
-    def set_groups(self, group_accessor, group_order=[]):
-        """
-        group_accessor: A function that will get the key and name from
-        each form.
-        group_order: list the group keys here in a list and
-        GroupedInlineFormset.groups will be ordered (ordereddict) by
-        the key sequence provided here. Any missing key from the
-        sequence will 
-        """
+    def set_groups(self,
+                   groups,
+                   group_accessor,
+                   choice_overrides=[]):
 
 
-        # Build group list.
+
+        # Create pre-defined groups.
         self.groups = OrderedDict()
         self.groups = OrderedDict()
-        temp_groups = {}
-        # self.groups_and_forms = []
+        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:
         for form in self.forms:
-            group_key, group_name = group_accessor(form)
-            if not temp_groups.has_key(group_key):
-                temp_groups[group_key] = {
-                    'name': group_name,
-                    'key': group_key,
-                    'forms': [],
-                    }
-            temp_groups[group_key]['forms'].append(form)
-
-        for order_key in group_order:
-            if temp_groups.has_key(order_key):
-                self.groups[order_key] = temp_groups.pop(order_key)
-
-        for key in temp_groups:
-            self.groups[key] = temp_groups[key]
-
-        del temp_groups
+            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()
 
 
         self.group_list = self.groups.values()
 
 
@@ -354,11 +429,14 @@ def remun_formset_factory(parent_model,
                           exclude=None,
                           can_order=False,
                           can_delete=True,
                           exclude=None,
                           can_order=False,
                           can_delete=True,
+                          read_only=False,
+                          extra=2,
                           max_num=None,
                           formfield_callback=None,
                           max_num=None,
                           formfield_callback=None,
-                          group_order=None):
+                          groups=None,
+                          choice_overrides=[]):
     trs = rh.TypeRemuneration.objects.all()
     trs = rh.TypeRemuneration.objects.all()
-    extra = max_num = trs.count()
+    # 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:
     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:
@@ -376,44 +454,132 @@ def remun_formset_factory(parent_model,
     }
     FormSet = modelformset_factory(model, **kwargs)
     FormSet.fk = fk
     }
     FormSet = modelformset_factory(model, **kwargs)
     FormSet.fk = fk
+    FormSet.read_only = read_only
 
     def grouper(form):
 
     def grouper(form):
-        if 'type' in form.initial and form.initial['type']:
-            return (form.initial['type'].nature_remuneration,
-                    form.initial['type'].nature_remuneration,
-                    )
+        rtype = form.initial['type']
+        if not isinstance(rtype, rh.TypeRemuneration):
+            rtype = rh.TypeRemuneration.objects.get(id=rtype)
+        return (rtype.nature_remuneration,
+                rtype.nature_remuneration
+                )
 
 
-    def __init__(inst, *a, **kw):
-        super(FormSet, inst).__init__(*a, **kw)
 
 
-        # Set initial data.
-        for form, tr in zip(inst.forms, trs):
-            form.initial = {
-                'type': tr,
-                }
 
 
-        # Set form grouping.
-        inst.set_groups(grouper, group_order)
+    # 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
 
 
 
     FormSet.__init__ = __init__
 
     return FormSet
 
 
-RemunForm = remun_formset_factory(
-    dae.Dossier,
-    dae.Remuneration,
-    form=FlexibleRemunForm,
-    group_order = [
-        u'Traitement',
-        u'Indemnité',
-        u'Charges',
-        u'Accessoire',
-        ]
+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,
+)
+
+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(forms.ModelForm):
+
+class PosteForm(filtered_archived_fields_form_factory(
+        'classement_min',
+        'classement_max',),
+                forms.ModelForm):
     """ Formulaire des postes. """
 
     # On ne propose que les services actifs
     """ Formulaire des postes. """
 
     # On ne propose que les services actifs
@@ -595,7 +761,13 @@ class EmployeForm(forms.ModelForm):
         self.fields['employe'].choices = _employe_choices(self, request)
 
 
         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',)
     """ Formulaire des dossiers. """
     class Meta:
         exclude = ('etat', 'employe', 'poste', 'date_debut',)
@@ -636,23 +808,23 @@ class DossierWorkflowForm(WorkflowFormMixin):
         super(DossierWorkflowForm, self).save()
         poste = self.instance.poste
 
         super(DossierWorkflowForm, self).save()
         poste = self.instance.poste
 
-        # 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" %(
+        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', ''),
                 )
                 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()
-
-        # force l'état du poste
-        poste.etat = self.instance.etat
-        poste.save()
+            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 ContratForm(forms.ModelForm):