From 69128196ef45d1e6194a12f868f9cb2c2b7ae544 Mon Sep 17 00:00:00 2001 From: Stiftung Development Date: Fri, 19 Sep 2025 23:52:26 +0200 Subject: [PATCH] Enhance Destinataer functionality: inline editing and improved list view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add inline edit mode to destinataer detail view with AJAX save/cancel - Fix form validation by aligning select choices with model definitions - Update Destinataer model to make familienzweig and berufsgruppe optional - Fix StiftungsKonto integration in forms and views - Redesign destinataer list view with new column layout: * Vorname, Nachname, E-Mail, Vierteljährlicher Betrag * Letzter Studiennachweis, Unterstützung bestätigt, Aktionen - Improve form styling and user experience - Add proper field validation and error handling - Enhance UI with better badges, icons, and formatting --- app/stiftung/forms.py | 22 +++++++- ...alter_destinataer_berufsgruppe_and_more.py | 23 ++++++++ app/stiftung/models.py | 5 +- app/stiftung/views.py | 6 ++- .../stiftung/destinataer_detail.html | 24 ++++++--- app/templates/stiftung/destinataer_list.html | 54 +++++++++---------- 6 files changed, 91 insertions(+), 43 deletions(-) create mode 100644 app/stiftung/migrations/0029_alter_destinataer_berufsgruppe_and_more.py diff --git a/app/stiftung/forms.py b/app/stiftung/forms.py index 9bede74..7e0cc19 100644 --- a/app/stiftung/forms.py +++ b/app/stiftung/forms.py @@ -369,14 +369,13 @@ class DestinataerForm(forms.ModelForm): "haushaltsgroesse": forms.NumberInput( attrs={"class": "form-control", "min": 1} ), - # renamed in UI: use vierteljaehrlicher_betrag field "vermoegen": forms.NumberInput( attrs={"class": "form-control", "step": "0.01"} ), "unterstuetzung_bestaetigt": forms.CheckboxInput( attrs={"class": "form-check-input"} ), - "standard_konto": forms.Select(attrs={"class": "form-select"}), + "standard_konto": forms.Select(attrs={"class": "form-select"}, choices=[(None, "---")] + [(c.pk, str(c)) for c in getattr(Destinataer, 'konten_queryset', lambda: [])()]), "vierteljaehrlicher_betrag": forms.NumberInput( attrs={"class": "form-control", "step": "0.01"} ), @@ -386,8 +385,27 @@ class DestinataerForm(forms.ModelForm): "letzter_studiennachweis": forms.DateInput( attrs={"class": "form-control", "type": "date"} ), + "familienzweig": forms.Select(attrs={"class": "form-select"}), + "berufsgruppe": forms.Select(attrs={"class": "form-select"}), } + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + for field_name, field in self.fields.items(): + if field_name not in ["vorname", "nachname"]: + field.required = False + # Set choices for familienzweig and berufsgruppe to match model + self.fields["familienzweig"].choices = [("", "Bitte wählen...")] + list(Destinataer.FAMILIENZWIG_CHOICES) + self.fields["berufsgruppe"].choices = [("", "Bitte wählen...")] + list(Destinataer.BERUFSGRUPPE_CHOICES) + # Set choices for standard_konto to allow blank + self.fields["standard_konto"].empty_label = "---" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + for field_name, field in self.fields.items(): + if field_name not in ["vorname", "nachname"]: + field.required = False + class LandForm(forms.ModelForm): """Form für das Erstellen und Bearbeiten von Ländern""" diff --git a/app/stiftung/migrations/0029_alter_destinataer_berufsgruppe_and_more.py b/app/stiftung/migrations/0029_alter_destinataer_berufsgruppe_and_more.py new file mode 100644 index 0000000..5630b1c --- /dev/null +++ b/app/stiftung/migrations/0029_alter_destinataer_berufsgruppe_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 5.0.6 on 2025-09-19 21:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('stiftung', '0028_alter_helpbox_page_key'), + ] + + operations = [ + migrations.AlterField( + model_name='destinataer', + name='berufsgruppe', + field=models.CharField(blank=True, choices=[('student', 'Student/Studentin'), ('wissenschaftler', 'Wissenschaftler/in'), ('künstler', 'Künstler/in'), ('sozialarbeiter', 'Sozialarbeiter/in'), ('umweltschützer', 'Umweltschützer/in'), ('andere', 'Andere')], max_length=20, null=True, verbose_name='Berufsgruppe'), + ), + migrations.AlterField( + model_name='destinataer', + name='familienzweig', + field=models.CharField(blank=True, choices=[('hauptzweig', 'Hauptzweig'), ('nebenzweig', 'Nebenzweig'), ('verwandt', 'Verwandt'), ('anderer', 'Anderer')], max_length=100, null=True), + ), + ] diff --git a/app/stiftung/models.py b/app/stiftung/models.py index 6e4e42e..1c6433b 100644 --- a/app/stiftung/models.py +++ b/app/stiftung/models.py @@ -199,7 +199,7 @@ class Destinataer(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) familienzweig = models.CharField( - max_length=100, choices=FAMILIENZWIG_CHOICES, default="hauptzweig" + max_length=100, choices=FAMILIENZWIG_CHOICES, blank=True, null=True ) vorname = models.CharField(max_length=100, verbose_name="Vorname") nachname = models.CharField(max_length=100, verbose_name="Nachname") @@ -221,7 +221,8 @@ class Destinataer(models.Model): berufsgruppe = models.CharField( max_length=20, choices=BERUFSGRUPPE_CHOICES, - default="andere", + blank=True, + null=True, verbose_name="Berufsgruppe", ) ausbildungsstand = models.CharField( diff --git a/app/stiftung/views.py b/app/stiftung/views.py index 0658362..0936959 100644 --- a/app/stiftung/views.py +++ b/app/stiftung/views.py @@ -24,7 +24,7 @@ from rest_framework.response import Response from .models import (AppConfiguration, CSVImport, Destinataer, DestinataerUnterstuetzung, DokumentLink, Foerderung, Land, LandAbrechnung, LandVerpachtung, Paechter, Person, - UnterstuetzungWiederkehrend) + StiftungsKonto, UnterstuetzungWiederkehrend) def get_pdf_generator(): @@ -1167,12 +1167,16 @@ def destinataer_detail(request, pk): destinataer=destinataer ).order_by("-erstellt_am") + # Alle verfügbaren StiftungsKonten für das Select-Feld laden + stiftungskonten = StiftungsKonto.objects.all().order_by("kontoname") + context = { "destinataer": destinataer, "verknuepfte_dokumente": verknuepfte_dokumente, "foerderungen": foerderungen, "unterstuetzungen": unterstuetzungen, "notizen_eintraege": notizen_eintraege, + "stiftungskonten": stiftungskonten, } return render(request, "stiftung/destinataer_detail.html", context) diff --git a/app/templates/stiftung/destinataer_detail.html b/app/templates/stiftung/destinataer_detail.html index fe462bc..7afe50f 100644 --- a/app/templates/stiftung/destinataer_detail.html +++ b/app/templates/stiftung/destinataer_detail.html @@ -87,9 +87,10 @@

@@ -120,10 +121,12 @@

@@ -369,7 +372,12 @@ Nicht angegeben {% endif %} - +

diff --git a/app/templates/stiftung/destinataer_list.html b/app/templates/stiftung/destinataer_list.html index ffad155..d496094 100644 --- a/app/templates/stiftung/destinataer_list.html +++ b/app/templates/stiftung/destinataer_list.html @@ -88,25 +88,22 @@ - Name + Vorname - Familienzweig - - - Berufsgruppe - - - Institution + Nachname E-Mail - Förderungen + Vierteljährlicher Betrag - Status + Letzter Studiennachweis + + + Unterstützung bestätigt Aktionen @@ -115,24 +112,14 @@ {% for destinataer in page_obj %} - {{ destinataer.nachname }}, {{ destinataer.vorname }} + {{ destinataer.vorname|default:"-" }} + + + {{ destinataer.nachname }} {% if destinataer.geburtsdatum %}
{{ destinataer.geburtsdatum|date:"d.m.Y" }} {% endif %} - - {{ destinataer.get_familienzweig_display }} - - - {{ destinataer.get_berufsgruppe_display }} - - - {% if destinataer.institution %} - {{ destinataer.institution }} - {% else %} - - - {% endif %} - {% if destinataer.email %} {{ destinataer.email }} @@ -141,17 +128,24 @@ {% endif %} - {% if destinataer.total_foerderungen %} - €{{ destinataer.total_foerderungen|floatformat:2 }} + {% if destinataer.vierteljaehrlicher_betrag %} + €{{ destinataer.vierteljaehrlicher_betrag|floatformat:2 }} {% else %} - €0.00 + - {% endif %} - {% if destinataer.aktiv %} - Aktiv + {% if destinataer.letzter_studiennachweis %} + {{ destinataer.letzter_studiennachweis|date:"d.m.Y" }} {% else %} - Inaktiv + - + {% endif %} + + + {% if destinataer.unterstuetzung_bestaetigt %} + Bestätigt + {% else %} + Ausstehend {% endif %}