Fix for salaire de base bug
[auf_rh_dae.git] / project / dae / forms.py
index 01aee78..373099f 100644 (file)
@@ -2,6 +2,7 @@
 
 import datetime
 from ordereddict import OrderedDict
+from dateutil.relativedelta import relativedelta
 from django import forms
 from django.core.urlresolvers import reverse
 from django.core.exceptions import MultipleObjectsReturned
@@ -28,6 +29,20 @@ 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.
@@ -95,7 +110,7 @@ class BaseInlineFormSetWithInitial(BaseInlineFormSet):
 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()]
@@ -110,13 +125,13 @@ def _employe_choices(obj, request):
     # 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(
-        poste__implantation__zone_administrative=(
-            employe.implantation.zone_administrative
+        poste__implantation__zone_administrative__in=(
+            groups.get_zones_from_user(request.user)
         )
     )
     # TRAITEMENT DRH
@@ -211,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'})
     )
+    cmp_dossier = forms.IntegerField(
+        widget=forms.widgets.HiddenInput,
+        required=False
+        )
 
     class Meta:
         model = dae.DossierComparaison
@@ -227,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)
 
+    cmp_poste = forms.IntegerField(
+        widget=forms.widgets.HiddenInput,
+        required=False,
+        )
+
     class Meta:
         model = dae.PosteComparaison
         exclude = ('poste',)
@@ -254,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')
 
@@ -309,8 +343,10 @@ class FlexibleRemunForm(forms.ModelForm):
 
 
 class ReadOnlyRemunForm(FlexibleRemunForm):
+    # Utilisé dans templats.
+
     def __init__(self, *a, **kw):
-        super(FlexibleRemunForm, self).__init__(*a, **kw)
+        super (ReadOnlyRemunForm, self).__init__(*a, **kw)
         for field in self.fields:
             field = self.fields[field]
             if not isinstance(field.widget, (
@@ -339,6 +375,7 @@ class GroupedInlineFormset(BaseInlineFormSet):
                 }
 
         # Assign each form to a group.
+        ungrouped_forms = []
         for form in self.forms:
             if bool(form.initial):
                 grp = group_accessor(form)
@@ -349,16 +386,26 @@ class GroupedInlineFormset(BaseInlineFormSet):
                         'forms': [],
                         }
                 self.groups[grp[0]]['forms'].append(form)
+            else:
+                ungrouped_forms.append(form)
+            
     
-        # Add extra forms (n extra for each grop).
-        tmp_extras = []
-        for i in xrange(len(self.groups) * self.extra):
-            tmp_extras.insert(0, self._construct_form(i))
-
+        # 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(self.extra):
-                self.groups[g]['forms'].append(tmp_extras.pop())
-            
+            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
@@ -372,41 +419,6 @@ class GroupedInlineFormset(BaseInlineFormSet):
         # Create an iterable for easier access in template.
         self.group_list = self.groups.values()
 
-    # def set_groups(self, group_accessor, groups, 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 
-    #     """
-
-    #     # Build group list.
-    #     self.groups = OrderedDict()
-    #     temp_groups = {}
-    #     # self.groups_and_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
-            
-    #     self.group_list = self.groups.values()
-
 
 def remun_formset_factory(parent_model,
                           model,
@@ -417,6 +429,7 @@ def remun_formset_factory(parent_model,
                           exclude=None,
                           can_order=False,
                           can_delete=True,
+                          read_only=False,
                           extra=2,
                           max_num=None,
                           formfield_callback=None,
@@ -441,6 +454,7 @@ def remun_formset_factory(parent_model,
     }
     FormSet = modelformset_factory(model, **kwargs)
     FormSet.fk = fk
+    FormSet.read_only = read_only
 
     def grouper(form):
         rtype = form.initial['type']
@@ -450,107 +464,122 @@ def remun_formset_factory(parent_model,
                 rtype.nature_remuneration
                 )
 
-    def __init__(inst, *a, **kw):
-        super(FormSet, inst).__init__(*a, **kw)
 
-        # Warning, this constructor can be improved and made more
-        # efficient.. it's a bit of a hack that will help creating a
-        # "grouped" formset that works inside Django. Although the
-        # code makes several iterations, I've timed it at 1ms to
-        # for it's execution.
 
-        # # Set initial data.
-        # d_inst = kw.get('instance', None)
+    # Monkey patch FormSet.
+    def __init__(inst, *a, **kw):
+        super(inst.__class__, inst).__init__(*a, **kw)
+        inst.set_groups(groups, grouper, choice_overrides)
 
-        # Set initial for all form type.
-        # for form, tr in zip(inst.forms, trs):
-        #     form.initial['type'] = tr
+    FormSet.__init__ = __init__
 
-        # # Set form grouping.
-        inst.set_groups(groups, grouper, choice_overrides)
+    return FormSet
 
-        # # Create groups list of choices for type field.
-        # inst.group_type_choices = {}
-        # for group_key in inst.groups:
-        #     inst.group_type_choices[group_key] = []
 
-        # # Add choices based on form.initial which have been set above.
-        # for form in inst.forms:
-        #     inst.group_type_choices[
-        #         form.initial['type'].nature_remuneration].append(
-        #         (form.initial['type'].id, form.initial['type'].nom)
-        #         )
+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
 
-        # # Finally... change the choices of each form in the formset:
-        # for form in inst.forms:
-        #     form.fields['type'].choices = inst.group_type_choices[
-        #         form.initial['type'].nature_remuneration]
+    choice_override_extra_q = {}
 
-        
-    FormSet.__init__ = __init__
+    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')
+                    )
+                },
+            },
+        )
 
-    return FormSet
 
+RemunForm = remun_formset_factory_factory(
+    read_only=False,
+    parent_model=dae.Dossier,
+    model=dae.Remuneration,
+    exclude_archived=True,
+)
 
-ReadOnlyRemunForm = remun_formset_factory(
-    dae.Dossier,
-    dae.Remuneration,
-    form=ReadOnlyRemunForm,
-    groups = [
-        (u'Traitement', u'Traitement',),
-        (u'Indemnité', u'Indemnité',),
-        (u'Charges', u'Charges',),
-        (u'Accessoire', u'Accessoire',),
-        ]
+ReadOnlyRemunFormSet = remun_formset_factory_factory(
+    read_only=True,
+    parent_model=dae.Dossier,
+    model=dae.Remuneration,
     )
 
-null_choice = ('', '-' * 10)
-RemunForm = remun_formset_factory(
-    dae.Dossier,
-    dae.Remuneration,
-    form=FlexibleRemunForm,
-    groups = [
-        (u'Traitement', u'Traitement',),
-        (u'Indemnité', u'Indemnité',),
-        (u'Charges', u'Charges',),
-        (u'Accessoire', u'Accessoire',),
-        ],
-    choice_overrides = {
-        u'Traitement': {
-            'type': [null_choice] + list(
-                rh.TypeRemuneration.objects.filter(
-                nature_remuneration=u'Traitement').values_list(
-                'id', 'nom')
-                )
-            },
-        u'Indemnité': {
-            'type': [null_choice] + list(
-                rh.TypeRemuneration.objects.filter(
-                nature_remuneration=u'Indemnité').values_list(
-                'id', 'nom')
-                )
-            },
-        u'Charges': {
-            'type': [null_choice] + list(
-                rh.TypeRemuneration.objects.filter(
-                nature_remuneration=u'Charges').values_list(
-                'id', 'nom')
-                )
-            },
-        u'Accessoire': {
-            'type': [null_choice] + list(
-                rh.TypeRemuneration.objects.filter(
-                nature_remuneration=u'Accessoire').values_list(
-                'id', 'nom')
-                )
-            },
-        }
+PosteCompReadOnlyRemunFormSet = remun_formset_factory_factory(
+    read_only=True,
+    parent_model=dae.PosteComparaison,
+    model=dae.PosteComparaisonRemuneration,
     )
 
-RemunForm = ReadOnlyRemunForm
+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
@@ -732,7 +761,13 @@ 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',)
@@ -773,23 +808,23 @@ class DossierWorkflowForm(WorkflowFormMixin):
         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', ''),
                 )
-        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):