X-Git-Url: http://git.auf.org/?p=auf_rh_dae.git;a=blobdiff_plain;f=project%2Fdae%2Fforms.py;h=373099fa80f012ecc4a8be598e7c45741881f94e;hp=916f3ac9ff8aa6ad8fce387df965d32973eaf5c2;hb=892a50fd99f2506664f1699024d673fd39765c65;hpb=6bec56513db2ce6bbd7499a18ad3239dd965ba73 diff --git a/project/dae/forms.py b/project/dae/forms.py index 916f3ac..373099f 100644 --- a/project/dae/forms.py +++ b/project/dae/forms.py @@ -2,8 +2,10 @@ 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 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 .widgets import ReadOnlyChoiceWidget +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. @@ -94,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()] @@ -109,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 @@ -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'}) ) + cmp_dossier = forms.IntegerField( + widget=forms.widgets.HiddenInput, + required=False + ) 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) + cmp_poste = forms.IntegerField( + widget=forms.widgets.HiddenInput, + required=False, + ) + 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') @@ -263,7 +298,7 @@ class FlexibleRemunForm(forms.ModelForm): 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'] @@ -307,41 +342,81 @@ class FlexibleRemunForm(forms.ModelForm): 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, 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() - 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: - 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() @@ -354,11 +429,14 @@ 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, - group_order=None): + groups=None, + choice_overrides=[]): 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: @@ -376,44 +454,132 @@ def remun_formset_factory(parent_model, } FormSet = modelformset_factory(model, **kwargs) FormSet.fk = fk + FormSet.read_only = read_only 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 -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 @@ -595,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',) @@ -636,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):