150 lines
5.4 KiB
Markdown
150 lines
5.4 KiB
Markdown
---
|
|
id: WP-0006
|
|
title: Aufgaben und Bieterfragen
|
|
status: done
|
|
phase: 6-of-12
|
|
created: "2026-05-08"
|
|
depends_on: WP-0005
|
|
---
|
|
|
|
# WP-0006 — Aufgaben und Bieterfragen
|
|
|
|
Implementiert alle Views für Aufgaben (UC-AU-01 bis UC-AU-04) und Bieterfragen
|
|
(UC-BF-01 bis UC-BF-03) inklusive globaler Aufgabenliste und Fristwarnung.
|
|
|
|
---
|
|
|
|
```task
|
|
id: WP-0006-T01
|
|
title: Aufgabenliste pro Ausschreibung und globale Liste (UC-OV-03, UC-AU-01)
|
|
status: done
|
|
|
|
`aufgaben/views.py` — aufgaben_liste:
|
|
|
|
**Pro Ausschreibung** (`/ausschreibungen/<id>/aufgaben/`):
|
|
Zeigt alle Aufgaben dieser Ausschreibung, filterbar nach Status, Typ, Verantwortlicher.
|
|
Template `aufgaben/liste.html` — Tabelle mit: Titel, Typ-Badge, Priorität, Frist (rot wenn überfällig),
|
|
Verantwortlicher, Status-Badge, Inline-Status-Dropdown.
|
|
|
|
**Globale Liste** (`/aufgaben/`):
|
|
Gleiche View mit `ausschreibung_id=None`. Zusätzlicher Filter: "Nur meine Aufgaben"
|
|
(request.user als Verantwortlicher).
|
|
Zeigt zusätzliche Spalte "Ausschreibung" mit Link.
|
|
|
|
`Aufgabe.objects.filter(frist__lt=today, status__in=AKTIVE_STATUS)`:
|
|
Vor dem Rendering: Update alle überfälligen Aufgaben via `update()` auf status='ueberfaellig'.
|
|
(Kein Celery nötig — wird beim Seitenaufruf der Liste getriggert.)
|
|
|
|
URL in `aufgaben/urls.py`:
|
|
```python
|
|
path('', views.aufgaben_liste, name='liste'),
|
|
```
|
|
Globale URL in Haupt-urls.py: `path('aufgaben/', include('vergabe_teilnahme.apps.aufgaben.urls'))`
|
|
```
|
|
|
|
```task
|
|
id: WP-0006-T02
|
|
title: Aufgabe anlegen und zuweisen (UC-AU-01)
|
|
status: done
|
|
|
|
`AufgabeForm(ModelForm)`:
|
|
- `typ` als Select, `prioritaet` als Radio (Hoch/Mittel/Niedrig)
|
|
- `frist` als DateInput type="date"
|
|
- `los`, `anforderung`, `bieterfrage` als optionale Selects (gefiltert auf aktuelle Ausschreibung)
|
|
|
|
`aufgabe_neu (POST)`: Bei HTMX-Request gibt es die neue Tabellenzeile zurück
|
|
(kein Full-Page-Reload). Sonst Redirect zu Aufgabenliste.
|
|
|
|
`aufgabe_bearbeiten`: Gleiche Form mit `instance`.
|
|
`aufgabe_loeschen (POST)`: Setzt status='verworfen' statt hartem Delete.
|
|
`aufgabe_detail`: Zeigt alle Felder, verknüpfte Anforderung/Bieterfrage, Ergebnisfeld.
|
|
```
|
|
|
|
```task
|
|
id: WP-0006-T03
|
|
title: Aufgabenstatus inline ändern und Ergebnis dokumentieren (UC-AU-03)
|
|
status: done
|
|
|
|
**Status-Widget** (analog zum Ausschreibungs-Status-Widget):
|
|
Jede Zeile in der Aufgabenliste enthält ein Status-Dropdown:
|
|
```html
|
|
<select name="status"
|
|
hx-post="{% url 'aufgaben:status' ausschreibung.pk aufgabe.pk %}"
|
|
hx-target="closest tr"
|
|
hx-swap="outerHTML"
|
|
class="form-input text-xs">
|
|
{% for val, label in Aufgabe.STATUS_CHOICES %}
|
|
<option value="{{ val }}" {% if val == aufgabe.status %}selected{% endif %}>{{ label }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
```
|
|
|
|
Bei Status-Wechsel auf 'erledigt': HTMX-Response zeigt zusätzlich ein Ergebnis-Eingabefeld inline.
|
|
Nutzer kann Ergebnis eintragen und separat abspeichern.
|
|
|
|
`aufgabe_status (POST)`: Aktualisiert Status, gibt einzelne Tabellenzeile zurück.
|
|
`aufgabe_ergebnis (POST)`: Speichert Ergebnistext.
|
|
```
|
|
|
|
```task
|
|
id: WP-0006-T04
|
|
title: Bieterfragen-Liste und Bieterfrage anlegen (UC-BF-01, UC-BF-02)
|
|
status: done
|
|
|
|
`aufgaben/views.py` — bieterfragen_liste und bieterfrage_neu:
|
|
|
|
Template `aufgaben/bieterfragen_liste.html`:
|
|
- Fristwarnung oben: "Bieterfragen bis: <Datum> — noch X Tage" (roter/gelber Banner)
|
|
- Filter: Status, Priorität, Verantwortlicher
|
|
- Tabelle: Frage (gekürzt), Status-Badge, Priorität, Einreichungsdatum, Verantwortlicher
|
|
|
|
`BieterfragenForm(ModelForm)`:
|
|
`frage` als Textarea, `hintergrund` als Textarea,
|
|
`anforderung` + `dokument` als optionale Selects.
|
|
|
|
bieterfrage_neu: Kann aus Anforderung vorausgefüllt werden (GET-Parameter `anforderung_id`).
|
|
bieterfrage_detail: Zeigt Frage, Hintergrund, verknüpfte Anforderung, Status-Timeline.
|
|
|
|
URLs in `aufgaben/bieterfragen_urls.py`:
|
|
```python
|
|
path('', views.bieterfragen_liste, name='liste'),
|
|
path('neu/', views.bieterfrage_neu, name='neu'),
|
|
path('<int:pk>/', views.bieterfrage_detail, name='detail'),
|
|
path('<int:pk>/status/', views.bieterfrage_status, name='status'),
|
|
path('<int:pk>/antwort/', views.bieterfrage_antwort, name='antwort'),
|
|
```
|
|
```
|
|
|
|
```task
|
|
id: WP-0006-T05
|
|
title: Bieterfragen-Workflow und Antwort einarbeiten (UC-BF-03)
|
|
status: done
|
|
|
|
`bieterfrage_status (POST)`: Ermöglicht Status-Wechsel über definierte Übergänge:
|
|
entwurf → abgestimmt → eingereicht → beantwortet → eingearbeitet.
|
|
Beim Wechsel auf 'eingereicht': Setzt einreichungsdatum=heute (wenn noch nicht gesetzt).
|
|
|
|
`bieterfrage_antwort (POST)`:
|
|
Speichert `antwort`, `auswirkung_angebot`.
|
|
Falls eine Anforderung verknüpft ist: Zeigt Button "Anforderungsstatus aktualisieren" →
|
|
Weiterleitung zur Anforderungsdetailseite mit vorausgefülltem Erfüllungsstatus.
|
|
|
|
Auf der Bieterfragen-Detailseite:
|
|
- Status-Timeline als vertikale Stepper-Darstellung (CSS-only mit Tailwind)
|
|
- Antwortformular (erscheint nur bei Status 'eingereicht'/'beantwortet')
|
|
- "Einarbeiten"-Checkbox setzt Status direkt auf 'eingearbeitet' und `eingearbeitet=True`
|
|
```
|
|
|
|
```task
|
|
id: WP-0006-T06
|
|
title: Aufgaben- und Bieterfragen-Tests
|
|
status: done
|
|
|
|
`aufgaben/tests/test_views.py`:
|
|
- Test: Aufgabenliste gibt 200 zurück
|
|
- Test: Neue Aufgabe anlegen → erscheint in Liste
|
|
- Test: Status-Wechsel via HTMX → Zeile enthält neuen Status-Badge
|
|
- Test: Überfällige Aufgabe → status wird auf 'ueberfaellig' gesetzt bei Listenabruf
|
|
- Test: Bieterfrage aus Anforderung vorausgefüllt (GET mit anforderung_id)
|
|
- Test: Antwort speichern → antwort-Feld befüllt, Status auf 'beantwortet'
|
|
```
|