feat(WP-0012): Querschnitt — Freigaben, Felder, Feedback, Suche, Tests

Implements all 8 tasks of the final cross-cutting workplan:

- T01: Generisches Freigabe-Modal (freigabe_modal, freigabe_erteilen views + templates)
- T02: Freigaben-Übersicht pro Ausschreibung (freigaben_uebersicht view + template)
- T03: EntityFieldConfig Admin-Interface (/felder/<entity_type>/ with HTMX toggle)
- T04: CustomAttribute-Panel (full CRUD with sort, lazy HTMX load)
- T05: Feedback-Backlog mit Statusverwaltung + feedback_success.html template
- T06: End-to-End-Tests in vergabe_teilnahme/tests/test_e2e.py (8 tests)
- T07: Globale Suche erweitert (Dokumente, Nachweise, Referenzen, Marktbegleiter)
- T08: Alle Migrationen sauber, 68/68 Tests grün, Ruff-Fehler in neuem Code behoben

Bugfix: URL-Namespace-Fehler in Abgabe-Templates (ausschreibungen:nachbetrachtung:abgabe → ausschreibungen:abgabe)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-05-11 17:54:38 +02:00
parent c5ccbd665d
commit 5a231223c0
23 changed files with 828 additions and 37 deletions

View file

@ -178,6 +178,36 @@ def ausschreibung_entscheidung(request, pk):
return render(request, 'ausschreibungen/entscheidung.html', ctx)
def freigaben_uebersicht(request, pk):
from django.contrib.contenttypes.models import ContentType
from vergabe_teilnahme.apps.core.models import Freigabe
a = get_object_or_404(Ausschreibung, pk=pk)
ct = ContentType.objects.get_for_model(a)
freigaben = Freigabe.objects.filter(
content_type=ct, object_id=pk
).select_related('freigebende_person').order_by('-timestamp')
erteilte_typen = set(freigaben.filter(status='erteilt').values_list('freigabe_typ', flat=True))
erforderliche_typen = {'teilnahme', 'preis', 'abgabe'}
fehlende_typen = erforderliche_typen - erteilte_typen
ctx = {
'ausschreibung': a,
'freigaben': freigaben,
'fehlende_typen': fehlende_typen,
'ct_id': ct.pk,
'freigabe_typ_choices': Freigabe.TYP_CHOICES,
'breadcrumbs': [
{'label': 'Ausschreibungen', 'url': '/ausschreibungen/'},
{'label': a.titel, 'url': f'/ausschreibungen/{pk}/'},
{'label': 'Freigaben', 'url': None},
],
}
return render(request, 'ausschreibungen/freigaben.html', ctx)
def ausschreibung_archivieren(request, pk):
a = get_object_or_404(Ausschreibung, pk=pk)
if request.method == 'POST':