Buchungsseite: Buchungs- und Verlaengerungsdatum des Abos aus Stripe

Cashier spiegelt die Periode nicht lokal; neuer SubscriptionPeriodResolver
holt start_date + current_period_end (Item-Ebene) gecacht, Fallback null.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kevin Adametz 2026-07-09 15:34:28 +00:00
parent a254bbd6a3
commit ac870a4076
3 changed files with 140 additions and 0 deletions

View file

@ -12,14 +12,25 @@ use App\Models\User;
use App\Models\UserPaymentOption;
use App\Services\Billing\CreditWalletService;
use App\Services\Billing\StripeCheckoutService;
use App\Services\Billing\SubscriptionPeriodResolver;
use Database\Seeders\LegalDocumentSeeder;
use Database\Seeders\RolesAndPermissionsSeeder;
use Illuminate\Support\Carbon;
use Livewire\Volt\Volt as LivewireVolt;
use Tests\TestCase;
beforeEach(function (): void {
/** @var TestCase $this */
$this->seed(RolesAndPermissionsSeeder::class);
// Standard: kein echter Stripe-Abruf fürs Buchungs-/Verlängerungsdatum.
// Die Datums-Tests binden bei Bedarf einen eigenen Stub.
$this->instance(
SubscriptionPeriodResolver::class,
Mockery::mock(SubscriptionPeriodResolver::class, function ($mock) {
$mock->shouldReceive('resolve')->andReturnNull();
})
);
});
function bookingsTestCustomer(): User
@ -448,3 +459,63 @@ test('a scheduled plan change is shown on the current plan card', function () {
->assertSee('Tarifwechsel zu Kleiner Tarif am')
->assertSee(now()->addDays(9)->format('d.m.Y'));
});
test('the current plan card shows booking and renewal dates from stripe', function () {
/** @var TestCase $this */
$user = bookingsTestCustomer();
BillingAddress::factory()->create(['user_id' => $user->id]);
$plan = Plan::factory()->create([
'name' => 'Pro',
'slug' => 'pro',
'monthly_price_cents' => 9900,
'stripe_price_id_monthly' => 'price_test_pro_m',
]);
subscribeUserToPlan($user, $plan);
// Stripe-Periode deterministisch stubben — kein echter API-Abruf im Test.
$this->instance(
SubscriptionPeriodResolver::class,
Mockery::mock(SubscriptionPeriodResolver::class, function ($mock) {
$mock->shouldReceive('resolve')->andReturn([
'booked_at' => Carbon::parse('2026-07-09'),
'renews_at' => Carbon::parse('2026-08-09'),
]);
})
);
$this->actingAs($user);
LivewireVolt::test('customer.bookings')
->assertSee('Aktueller Tarif')
->assertSee('Gebucht am 09.07.2026')
->assertSee('Verlängerung am 09.08.2026');
});
test('the current plan card omits the dates when the stripe period is unavailable', function () {
/** @var TestCase $this */
$user = bookingsTestCustomer();
BillingAddress::factory()->create(['user_id' => $user->id]);
$plan = Plan::factory()->create([
'name' => 'Pro',
'slug' => 'pro',
'stripe_price_id_monthly' => 'price_test_pro_m2',
]);
subscribeUserToPlan($user, $plan);
// Stripe nicht erreichbar → Resolver liefert null; Seite rendert trotzdem.
$this->instance(
SubscriptionPeriodResolver::class,
Mockery::mock(SubscriptionPeriodResolver::class, function ($mock) {
$mock->shouldReceive('resolve')->andReturnNull();
})
);
$this->actingAs($user);
LivewireVolt::test('customer.bookings')
->assertSee('Aktueller Tarif')
->assertDontSee('Gebucht am')
->assertDontSee('Verlängerung am');
});