+ 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,