--- id: WP-0009 title: Abgabe und Nachbetrachtung status: done phase: 9-of-12 created: "2026-05-08" depends_on: WP-0008 --- # WP-0009 — Abgabe (Phase 6/7) und Nachbetrachtung (Phase 8) Abgabe-Checkliste, Vollständigkeitsprüfung, Abgabe-Dokumentation mit Nachweis, Ergebnis erfassen, Kickoff-Aufgabe erstellen, Verlustanalyse, Lessons Learned. Referenz: UC-AB-01 bis UC-AB-03, UC-NB-01 bis UC-NB-03. --- ```task id: WP-0009-T01 title: Abgabe-Checkliste mit Vollständigkeitsstatus (UC-AB-01) status: done `nachbetrachtung/abgabe_views.py` — abgabe_checkliste: Vollständigkeitsprüfung-Service `abgabe_vollstaendigkeit(ausschreibung)`: ```python def abgabe_vollstaendigkeit(ausschreibung): from vergabe_teilnahme.apps.dokumente.models import Dokument from vergabe_teilnahme.apps.core.models import Freigabe from django.contrib.contenttypes.models import ContentType ct = ContentType.objects.get_for_model(ausschreibung) freigaben = Freigabe.objects.filter(content_type=ct, object_id=ausschreibung.pk) def hat_freigabe(typ): return freigaben.filter(freigabe_typ=typ, status='erteilt').exists() return { 'dokumente_gesamt': Dokument.objects.filter(ausschreibung=ausschreibung).count(), 'dokumente_freigegeben': Dokument.objects.filter( ausschreibung=ausschreibung, status__in=['freigegeben', 'final_abgegeben']).count(), 'teilnahme_freigabe': hat_freigabe('teilnahme'), 'preis_freigabe': hat_freigabe('preis'), 'recht_freigabe': hat_freigabe('recht'), 'abgabe_freigabe': hat_freigabe('abgabe'), 'entscheidung_getroffen': ausschreibung.teilnahmeentscheidung == 'teilnahme', } ``` Template `nachbetrachtung/abgabe.html`: - Fortschrittsbalken oben (Anzahl erfüllter Checkpunkte / Gesamt) - Checkliste mit Grün-/Rot-Badges für jeden Punkt - Dokumente-Sektion: Liste aller Dokumente mit Status - Freigaben-Sektion: Welche Freigaben vorliegen / fehlen - Frist-Banner: "Abgabe bis: " prominent oben ``` ```task id: WP-0009-T02 title: Abgabe dokumentieren mit Nachweis-Upload (UC-AB-02) status: done `nachbetrachtung/abgabe_views.py` — abgabe_dokumentieren: `AbgabeForm(Form)`: - `abgabe_zeitpunkt` DateTimeInput(type='datetime-local') - `abgabe_plattform` CharField - `verantwortlicher` ModelChoiceField(Mitarbeiter) - `abgabenachweis` FileField (Eingangsbestätigung, Screenshot etc.) - `kommentar` Textarea ```python def abgabe_dokumentieren(request, ausschreibung_id): ausschreibung = get_object_or_404(Ausschreibung, pk=ausschreibung_id) if request.method == 'POST': form = AbgabeForm(request.POST, request.FILES) if form.is_valid(): # Abgabenachweis als Dokument speichern if form.cleaned_data.get('abgabenachweis'): Dokument.objects.create( ausschreibung=ausschreibung, datei=form.cleaned_data['abgabenachweis'], kategorie='abgabenachweis', status='final_abgegeben', finale_abgabeversion=True, ) # Ausschreibungsstatus auf Abgegeben setzen ausschreibung.status = 9 ausschreibung.save(update_fields=['status', 'geaendert_am']) # Alle Dokumente mit finale_abgabeversion=True: gesperrt (kein weiterer Upload) return redirect('ausschreibungen:detail', pk=ausschreibung_id) else: form = AbgabeForm() return render(request, 'nachbetrachtung/abgabe_formular.html', {'form': form, 'ausschreibung': ausschreibung}) ``` ``` ```task id: WP-0009-T03 title: Nachbetrachtung-View — Ergebnis und Kickoff (UC-NB-01) status: done `nachbetrachtung/views.py` — nachbetrachtung_detail: Erstellt oder lädt die OneToOne `Nachbetrachtung` für die Ausschreibung. `NachbetrachtungForm(ModelForm)`: Felder: ergebnis (Radio), zuschlagsdatum, projektverantwortlicher (Select Mitarbeiter). Bei Ergebnis 'gewonnen' (POST): 1. Setze Ausschreibungsstatus auf 10 2. Erstelle automatisch Aufgabe: ```python Aufgabe.objects.get_or_create( ausschreibung=ausschreibung, titel="Kickoff vorbereiten", defaults={ 'typ': 'fachlich', 'prioritaet': 1, 'verantwortlicher': form.cleaned_data.get('projektverantwortlicher'), 'beschreibung': f"Kickoff für {ausschreibung.titel}. Angebotsumfang und Annahmen übergeben.", } ) ``` 3. Flash-Meldung: "Kickoff-Aufgabe erstellt für " Template `nachbetrachtung/detail.html`: - Ergebnis-Formular oben - Bei Ergebnis 'gewonnen': Übergabe-Abschnitt (Projektverantwortlicher, Kickoff-Aufgabe-Link) - Bei Ergebnis 'verloren': Verlustanalyse-Abschnitt (aus UC-NB-02) ``` ```task id: WP-0009-T04 title: Verlustanalyse und Lessons Learned (UC-NB-02, UC-NB-03) status: done **Verlustgründe** — dynamisches JSONField-Formular: Alpine.js-gesteuertes Array: ```html
``` Ausschlaggebende Merkmale, Lessons Learned, Empfehlungen: einfache Textareas. Checkbox "Wiederverwendbare Erkenntnisse markieren". Bei Speichern: Aktualisiere `Nachbetrachtung`-Objekt, Redirect zur Nachbetrachtungsseite. ``` ```task id: WP-0009-T05 title: URL-Verkabelung Abgabe/Nachbetrachtung und Tests status: done `nachbetrachtung/abgabe_urls.py`: ```python urlpatterns = [ path('', abgabe_views.abgabe_checkliste, name='checkliste'), path('dokumentieren/', abgabe_views.abgabe_dokumentieren, name='dokumentieren'), path('problem/', abgabe_views.abgabe_problem, name='problem'), ] ``` `nachbetrachtung/urls.py`: ```python app_name = 'nachbetrachtung' urlpatterns = [ path('', views.nachbetrachtung_detail, name='detail'), ] ``` `abgabe_problem (POST)`: Setzt `ausschreibung.status` auf internen Marker "Problem bei Abgabe" (eigenes Status-Choice ergänzen wenn nötig, oder Kommentarfeld). Tests: - Test: abgabe_vollstaendigkeit ohne Freigaben → alle False - Test: Freigabe erteilen → entsprechendes Feld True - Test: Ergebnis 'gewonnen' → Kickoff-Aufgabe wird erstellt, Status 10 - Test: Ergebnis 'verloren' → Status 11 - Test: Verlustgründe JSONField gespeichert mit korrekter Struktur ```