Abo: Bestellung extern als erledigt markieren (ohne Rechnung/Inkasso)

Neue Admin-Funktion fuer angehaltene Abo-Bestellungen, die der Kunde
ausserhalb des Systems geliefert und verrechnet hat.

Aktion (AboExternalCompletionService):
- Punkte gutschreiben wie bei eingegangener Zahlung (SalesPointsVolume,
  idempotent gegen Doppelbuchung)
- UserAboOrder auf neuen gruenen Status 8 "extern erledigt"; paid bleibt false
- Bestellung: shipped=2 (Lieferung bestaetigt), keine Rechnung/kein Lieferschein
- Blockade aufheben: Abo zurueck auf status=2 (okay), aktiv, next_date neu,
  damit der naechste Termin regulaer laeuft
- wie bei regulaerer Ausfuehrung: IncentiveTracker + AboOneTimeService-Purge

Einstiegspunkte: Button + Bestaetigungs-Modal auf der Kunden-Bestelldetailseite
(SalesController) und auf der Abo-Detailseite (Admin\AboController@externDone,
Route admin_abos_extern_done). Status 8 (gruen) in UserAbo/UserAboOrder, Labels
de/en.

Tests: tests/Feature/AboExternalCompletionTest (Happy Path, Idempotenz,
bezahlt-/Nicht-Abo-Guards, Abo-Detail-Einstieg) - 5 gruen.

Zusaetzlich: docs/2026-06-11-test-suite-vorbestehende-fehler.md - Diagnose der
93 vorbestehenden (von master geerbten) Test-Suite-Fehler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Kevin 2026-06-11 15:40:16 +00:00
parent ccc6f85809
commit 4709dfde55
13 changed files with 609 additions and 59 deletions

View file

@ -0,0 +1,80 @@
# Vorbestehende Test-Suite-Fehler (Diagnose)
**Datum:** 2026-06-11
**Branch bei Aufnahme:** `payment/phase-r-payone-refactoring`
**Status:** Nur dokumentiert — keine Codeänderung vorgenommen.
## Ausgangslage
`php artisan test --compact` meldet aktuell **93 failed, 1 skipped, 448 passed**.
Diese Fehler sind **nicht** durch die Abo-„Extern erledigt"-Funktion oder durch
diesen Branch verursacht.
### Beweis, dass die Fehler von `master` geerbt sind
- Der einzige test-relevante Commit dieses Branches (`8593dbe`, Payment Phase R)
ändert an `phpunit.xml` nur **eine** Zeile: `PAYONE_KEY_HASH` (DB-Config
unberührt).
- `DB_DATABASE=":memory:"` mit `force="true"` steht bereits auf `master`.
- Legacy-Factory `database/factories/UserFactory.php` (`$factory->define`) und alle
betroffenen Testdateien existieren unverändert bereits auf `master`.
- Gegenprobe per `git stash`: dasselbe Test-Subset scheitert mit und ohne die
Änderungen dieses Branches identisch.
## Vier unabhängige Ursachen
### 1. Legacy-Factories + fehlendes `HasFactory` (~20 Tests)
- **Symptom:** `Call to undefined method App\User::factory()`
- **Ursache:** `App\User` nutzt das `HasFactory`-Trait nicht; `UserFactory.php` ist
im alten `$factory->define()`-Stil (Laravel ≤6) statt klassenbasiert
(`extends Factory`). Die Tests rufen die neue API `User::factory()`.
- **Betroffen:** `Unit/BusinessPlan/BusinessUserItemOptimizedTest`,
`Unit/BusinessPlan/BusinessUserRepositoryTest`, Teile von
`Unit/Incentive/IncentiveTrackerTest`.
- **Fix (sicher, hoher Hebel):** `App\User` → `use HasFactory` + `newFactory()`
(nötig, weil das Model unter `App\` statt `App\Models\` liegt);
`UserFactory` auf `class UserFactory extends Factory { protected $model = \App\User::class; … }`
umstellen.
### 2. `DatabaseTransactions` auf `:memory:`-SQLite (~32 Tests)
- **Symptom:** `SQLSTATE … no such table: settings` (o. ä.)
- **Ursache:** Das Trait `DatabaseTransactions` führt **keine** Migrationen aus,
sondern setzt ein bereits migriertes Schema voraus. Bei `:memory:` startet jede
Connection leer → Tabellen fehlen. (`RefreshDatabase`-Tests migrieren und laufen
daher grün.)
- **Betroffen:** `Unit/Services/InvoiceServiceTest`,
`Feature/Payment/ConcurrentPaymentTest`, `Feature/Payment/PayoneRaceConditionTest`.
- **Fix (Entscheidung nötig):** entweder Trait auf `RefreshDatabase` umstellen,
**oder** Test-DB-Strategie ändern (persistente, vorab migrierte SQLite-Datei
statt `:memory:`). Architekturentscheidung — Race-Condition-/Concurrency-Tests
können bewusst eine persistente DB erwarten.
### 3. Domain-aware Routen in Unit-Tests nicht geladen (~10 Tests)
- **Symptom:** `Route [modal_load] not defined.`
- **Ursache:** Die Anwendung lädt Routen host-abhängig (siehe CLAUDE.md,
Multi-Tenant Routing). In Unit-Tests ohne Host sind die `routes/domains/*`-Routen
nicht registriert; `TreeHtmlRenderer` erzeugt aber HTML mit `route('modal_load')`.
- **Betroffen:** `Unit/BusinessPlan/TreeHtmlRendererTest`.
- **Fix (mittel):** Routen im Test-Setup laden bzw. den Renderer von der
Route-Generierung entkoppeln (URL injizieren).
### 4. Tests veraltet ggü. refaktoriertem Konstruktor (~19 Tests)
- **Symptom:**
`TreeCalcBotOptimized::__construct(): Argument #4 ($forceLiveCalculation) must be of type bool, …BusinessUserRepository given`
- **Ursache:** Die Konstruktor-Signatur von
`App\Services\BusinessPlan\TreeCalcBotOptimized` wurde geändert; der Test
(`TreeCalcBotOptimizedTest`) übergibt die Argumente noch in alter Reihenfolge.
- **Betroffen:** `Unit/BusinessPlan/TreeCalcBotOptimizedTest`.
- **Fix (mittel, reine Teständerung):** Konstruktor-Aufrufe im Test an die aktuelle
Signatur anpassen.
### Rest
Einzelne Folgefehler/Sonderfälle: `Feature/ExampleTest`,
`Feature/FrenchLocalizationTest`, `Feature/AboOneTimeWindowTest`,
`Feature/Incentive/IncentiveTeaserPageTest`.
## Empfehlung
Eigenständige Aufräum-Aufgabe in separatem Branch, **nicht** in den Payment-Branch
mischen. Sinnvolle Reihenfolge nach Risiko/Nutzen: **1 → 4 → 3 → 2**
(Ursache 2 zuletzt, da Architekturentscheidung zur Test-DB nötig).