# Sammelbestellungen: gemeinsames Konzept für Club, Trainer und Trainingstagebuch

Stand: 2026-07-22

## Ziel

Eine Sammelbestellung bündelt Wünsche von Mitgliedern, Trainingsteilnehmern und
Vereinsverantwortlichen. Club- und Trainerrollen steuern Bestellung, Preise,
Rückfragen, Zahlung und Ausgabe; alle berechtigten Nutzer können Wünsche
eintragen und ihren eigenen Stand nachvollziehen.

## Rollen und Rechte

| Aktion | Club | Trainer | Mitglied / Trainingstagebuch-Nutzer |
| --- | --- | --- | --- |
| Sammelbestellung anlegen | Ja | Ja | Nein |
| Eigene Artikelwünsche eintragen | Ja | Ja | Ja |
| Eigene Wünsche ändern oder stornieren, solange offen | Ja | Ja | Ja |
| Preise, Bestellung, Ausgabe und Zahlungsstatus bearbeiten | Ja | Ja | Nein |
| Rückfrage zu einem Artikel stellen | Ja | Ja | Nein |
| Auf Rückfrage antworten | Ja | Ja | Ja, nur zum eigenen Artikel |
| Preis bestätigen | Ja | Ja | Ja, nur zum eigenen Artikel |
| Gesamtrechnung und Bestellstatus bearbeiten | Ja | Ja | Nein |

Der Ersteller einer Sammelbestellung erhält zusätzlich dieselben Steuerrechte
wie Club/Trainer für genau diese Bestellung, auch wenn seine allgemeine Rolle
später geändert wird.

## Datenmodell

### Sammelbestellung

- ID, `club_id`, Titel, Beschreibung, Lieferant, Bestellfrist
- Ersteller (`created_by_user_id`), optional verantwortlicher Trainer
- Bestellstatus: `open`, `ordered`, `arrived`
- Zahlungsstatus: `unpaid`, `partially_paid`, `paid`
- Gesamtrechnungsbetrag in Cent, Währung, Rechnungsreferenz
- Zeitstempel für Bestellung, Eingang und Abschluss

### Artikelwunsch

- ID, Sammelbestellung, anfragender Nutzer und optional zugeordnetes Mitglied
- Artikelname, Variante/Größe, Menge, Freitextwunsch
- Einzelpreis in Cent, Währung
- Artikelstatus: `entered`, `question`, `ordered`, `cancelled`, `arrived`, `issued`
- Zahlungsstatus: `unpaid`, `paid`
- Preisbestätigung durch den Anfragenden (`price_confirmed_at`)
- Rückfrage: Text, gestellt von, gestellt am, Antwort, beantwortet am
- Ausgabe: ausgegeben von, ausgegeben am

## Verbindliche Statuslogik

### Einzelartikel

1. `entered`: Wunsch wurde eingetragen.
2. `question`: Verantwortliche stellen eine Rückfrage; der Nutzer kann antworten.
3. `ordered`: Artikel ist beim Lieferanten bestellt.
4. `cancelled`: Artikel wird nicht weitergeführt.
5. `arrived`: Artikel ist eingetroffen.
6. `issued`: Artikel wurde an den Nutzer ausgegeben.

Der Preis darf von Club/Trainer jederzeit bis zur Ausgabe gepflegt werden. Ist
ein Einzelpreis vorhanden oder geändert, kann der Anfragende ihn bestätigen.
Die Preisbestätigung ist für die Bestellung optional konfigurierbar, sollte aber
vor `ordered` sichtbar als offen markiert sein.

Ein Artikel gilt nur dann als **abgeschlossen**, wenn sein Artikelstatus
`issued` und sein Zahlungsstatus `paid` ist. Stornierte Artikel gelten als
abgeschlossen, jedoch separat als storniert.

### Gesamte Sammelbestellung

- `open`: Wünsche werden gesammelt und geklärt.
- `ordered`: Bestellung wurde ausgelöst.
- `arrived`: Lieferung ist eingetroffen.

Der Zahlungsstatus bleibt unabhängig: `unpaid`, `partially_paid`, `paid`.
Der Gesamtbetrag der Rechnung wird manuell gepflegt und steht neben der Summe
aller Einzelpreise, damit Abweichungen sichtbar sind. Eine Bestellung ist erst
abgeschlossen, wenn sie `arrived` ist und alle nicht stornierten Artikel
ausgegeben und bezahlt sind.

## Ansichten

### Für alle Nutzer

- Liste offener und eigener Sammelbestellungen.
- Wunschformular mit Artikel, Variante, Menge und Hinweis.
- Eigene Artikel mit Preis, Preisbestätigung, Rückfrage und Status-Timeline.
- Keine Sicht auf Wünsche, Preise oder Zahlungen anderer Nutzer.

### Club- und Traineransicht

- Neue Sammelbestellung anlegen und Verantwortliche festlegen.
- Artikeltabelle mit Filtern: Status, Rückfrage offen, Preis unbestätigt,
  unbezahlt, eingetroffen, auszugeben.
- Preis, Artikelstatus, Rückfrage und Zahlungsstatus inline pflegen.
- Gesamtstatus, Gesamtrechnung und Gesamtzahlungsstatus pflegen.
- Übersichten für fehlende Preisbestätigungen, offene Rückfragen und noch
  auszugebende Artikel.

### Trainingstagebuch

- Kontextlink aus einer Trainingseinheit auf aktive Sammelbestellungen.
- Teilnehmer können dort ihren Wunsch eintragen oder den eigenen Status prüfen.
- Keine Finanz- oder Verwaltungsaktionen für normale Teilnehmer.

## Umsetzungstodos

### Phase 1: Grundlage und Rechte

- [ ] Datenmodell, Migrationen und Indizes für Bestellung und Artikelwunsch anlegen.
- [ ] Berechtigung `collective_orders` mit read/write und Ersteller-Ausnahme definieren.
- [ ] Sichere Zuordnung User ↔ Mitglied für eigene Wünsche verbindlich klären.
- [ ] REST-Endpunkte für Liste, Detail, Bestellung und eigene Artikelwünsche erstellen.
- [ ] Statusübergänge serverseitig validieren.

### Phase 2: Club- und Trainer-Arbeitsbereich

- [ ] Bestellliste und Detailansicht implementieren.
- [ ] Bestellung anlegen, Gesamtbetrag und Gesamtstatus pflegen.
- [ ] Artikelstatus, Einzelpreis und Zahlungsstatus pflegen.
- [ ] Rückfrage-/Antwort-Workflow und Preisbestätigung umsetzen.
- [ ] Abschlusslogik und Arbeitsfilter umsetzen.

### Phase 3: Mitglieder- und Trainingstagebuch-Sicht

- [ ] Eigene Wünsche eintragen, ändern und stornieren.
- [ ] Eigene Rückfragen beantworten und Preise bestätigen.
- [ ] Persönliche Statusanzeige und verständliche leere Zustände bauen.
- [ ] Kontextlink aus Trainingstagebuch ergänzen.

### Phase 4: Abgleich und Qualität

- [ ] Abweichung zwischen Gesamtrechnung und Summe der Artikelpreise sichtbar machen.
- [ ] Export für Lieferant, Ausgabe und offene Zahlungen ergänzen.
- [ ] Rechte-, Status- und Mobil-Smoketests mit Club, Trainer und Mitglied durchführen.
- [ ] Historie und Archivverknüpfung für abgeschlossene Bestellungen ergänzen.

## Abnahmekriterien

- [ ] Mitglieder können ausschließlich eigene Wünsche und Rückfragen sehen.
- [ ] Club/Trainer können jeden Artikel vollständig steuern.
- [ ] Kein Artikel wird als abgeschlossen markiert, bevor er ausgegeben und bezahlt ist.
- [ ] Gesamtbetrag und Artikelpreissumme sind transparent vergleichbar.
- [ ] Offene Rückfragen, unbestätigte Preise, fehlende Zahlungen und Ausgaben sind mit einem Filter erreichbar.
