Phase 9F: Tarif-Seite mit Stripe-Checkout und Billing Portal

- Buchungs-Seite zeigt das echte 4-Tier-Raster aus plans (Monat/Jahr-
  Toggle, Jahrespreis als "2 Monate gratis") mit Checkout-Buttons,
  Einzel-PM als separaten No-Abo-Block und Enterprise-Hinweis;
  Credit-Konzept-Mock entfernt (Credits folgen mit 9I bzw. Phase 2)
- Aktueller-Tarif-Panel real: Abo (Preis, Kontingent, Kündigungsstatus),
  Bestandstarif (unbegrenzt, nächste MAN-Rechnung), offene Einzelkäufe;
  Kontingent-Kachel zeigt "Unbegrenzt" bei Bestandsschutz
- "Abo verwalten" über das Stripe Billing Portal
  (me.checkout.billing-portal; Zahlungsmethode, Rechnungen, Kündigung)
- Aktive Buchungen + Verlauf aus echten Daten (Abo, Legacy-Vereinbarung,
  offene/eingelöste Einzelkäufe mit PM-Verknüpfung)
- Tests: BookingsPageTest (9 Tests), PanelConsolidationTest angepasst;
  Suite 519 passed / 4 skipped
- Doku: PHASE-9-Plan 9F , Billing-Doku (Routen, Stripe Tax aktiviert),
  STATUS-ABGLEICH, Checkliste, PROGRESS

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-06-12 12:39:39 +00:00
parent c8dc99c3c8
commit 23ac8bc7f1
11 changed files with 581 additions and 316 deletions

View file

@ -1,5 +1,6 @@
<?php
use App\Models\Plan;
use App\Models\User;
use Database\Seeders\RolesAndPermissionsSeeder;
use Tests\TestCase;
@ -58,21 +59,27 @@ test('customer can access me dashboard but not admin dashboard', function () {
$this->get(route('dashboard'))->assertForbidden();
});
test('customer bookings page shows credit packages and add ons from pricing concept', function () {
test('customer bookings page shows the tariff grid and single pm block', function () {
// Seit Phase 9F zeigt die Seite das echte Tarif-Raster mit
// Stripe-Checkout statt des Credit-Konzept-Mocks (Credits → Phase 9I/2).
/** @var TestCase $this */
$customer = User::factory()->create(['is_active' => true]);
$customer->assignRole('customer');
Plan::factory()->create([
'name' => 'Starter',
'monthly_price_cents' => 2900,
'press_release_quota' => 3,
]);
$this->actingAs($customer)
->get(route('me.bookings.index'))
->assertSuccessful()
->assertSee('Credit-Pakete')
->assertSee('Standard')
->assertSee('50')
->assertSee('45 €')
->assertSee('Pressetext-Optimierung')
->assertSee('Top-Slot Startseite')
->assertSee('Score 80+')
->assertSee('Den passenden Tarif wählen')
->assertSee('Starter')
->assertSee('29 €')
->assertSee('2 Monate gratis')
->assertSee('Einzel-Pressemitteilung — ohne Abo')
->assertSee('Noch keine aktiven Buchungen');
});