'/'.$name.'/'.implode('/', $parameters) ); }); afterEach(function () { Carbon::setTestNow(); }); function auaMakeUser(): User { return User::forceCreate([ 'email' => 'aua-'.uniqid('', true).'@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'm_level' => 1, 'payment_account' => now()->addYear(), ]); } function auaMakeAbo(User $user, int $paidDeliveries = 6, string $nextDate = '2026-08-05', ?string $lastPauseDate = null): UserAbo { $abo = UserAbo::create([ 'user_id' => $user->id, 'member_id' => $user->id, 'shopping_user_id' => 0, 'email' => 'aua-abo-'.uniqid('', true).'@example.com', 'is_for' => 'me', 'payone_userid' => 0, 'clearingtype' => 'cc', 'amount' => 5000, 'active' => true, 'status' => 2, 'abo_interval' => 5, 'start_date' => '2026-01-05', 'last_date' => '2026-07-05', 'next_date' => $nextDate, 'last_pause_date' => $lastPauseDate, ]); for ($i = 0; $i < $paidDeliveries; $i++) { UserAboOrder::create([ 'user_abo_id' => $abo->id, 'shopping_order_id' => 0, 'status' => 2, 'paid' => true, ]); } return $abo->fresh(); } /** * Simuliert den POST des Abo-Einstellungs-Modals an AboController@update. * * @param array $payload */ function auaCallUpdate(string $routeView, int $routeId, array $payload): mixed { app('request')->merge($payload); return (new AboController(app(AboRepository::class)))->update($routeView, $routeId); } it('blockiert das Kündigen eines fremden Abos über eine manipulierte Body-id', function (): void { $attacker = auaMakeUser(); $victim = auaMakeUser(); $attackerAbo = auaMakeAbo($attacker); $victimAbo = auaMakeAbo($victim); $this->actingAs($attacker); expect(fn () => auaCallUpdate('me', $attackerAbo->id, [ 'action' => 'abo_update_settings', 'id' => $victimAbo->id, 'view' => 'admin', 'abo_interval' => 5, 'abo_next_month' => now()->addMonth()->format('Y-m'), 'abo_cancel' => 'true', ]))->toThrow(HttpException::class); expect((int) $victimAbo->fresh()->status)->toBe(2) ->and($victimAbo->fresh()->active)->toBeTruthy(); }); it('ignoriert ein gespooftes view=admin im Body: Mindestlaufzeit gilt weiterhin', function (): void { $user = auaMakeUser(); $abo = auaMakeAbo($user, paidDeliveries: 2); $this->actingAs($user); auaCallUpdate('me', $abo->id, [ 'action' => 'abo_update_settings', 'id' => $abo->id, 'view' => 'admin', 'abo_interval' => 5, 'abo_next_month' => now()->addMonth()->format('Y-m'), 'abo_cancel' => 'true', ]); expect((int) $abo->fresh()->status)->toBe(2) ->and($abo->fresh()->active)->toBeTruthy(); }); it('ignoriert ein gespooftes view=admin im Body: Pause-Intervall gilt weiterhin', function (): void { $user = auaMakeUser(); $abo = auaMakeAbo($user, lastPauseDate: '2026-06-01'); $this->actingAs($user); auaCallUpdate('me', $abo->id, [ 'action' => 'abo_update_settings', 'id' => $abo->id, 'view' => 'admin', 'abo_interval' => 5, 'abo_next_month' => now()->addMonth()->format('Y-m'), 'abo_pause' => 'true', ]); expect($abo->fresh()->getRawOriginal('next_date'))->toStartWith('2026-08-05'); }); it('kündigt das eigene Abo nach erfüllter Mindestlaufzeit weiterhin regulär', function (): void { $user = auaMakeUser(); $abo = auaMakeAbo($user); $this->actingAs($user); auaCallUpdate('me', $abo->id, [ 'action' => 'abo_update_settings', 'id' => $abo->id, 'view' => 'me', 'abo_interval' => 5, 'abo_cancel' => 'true', 'abo_cancel_confirm' => '1', ]); expect((int) $abo->fresh()->status)->toBe(4) ->and($abo->fresh()->active)->toBeFalsy(); }); it('blockiert die Kündigung serverseitig vor erreichter Mindestlaufzeit', function (): void { $user = auaMakeUser(); $abo = auaMakeAbo($user, paidDeliveries: 2); $this->actingAs($user); $repository = new AboRepository; $repository->setModel($abo); $repository->update([ 'action' => 'abo_update_settings', 'id' => $abo->id, 'view' => 'me', 'abo_interval' => 5, 'abo_cancel' => 'true', ]); expect((int) $abo->fresh()->status)->toBe(2) ->and($abo->fresh()->active)->toBeTruthy(); }); it('zeigt im Portal nach der Kündigung wieder die Abo-Neuanlage an', function (): void { $shoppingUser = ShoppingUser::create([ 'auth_user_id' => 1, 'billing_firstname' => 'Karla', 'billing_lastname' => 'Kundin', 'billing_address' => 'Kundenweg 2', 'billing_zipcode' => '11111', 'billing_city' => 'Kundenstadt', 'billing_country_id' => 1, 'shipping_country_id' => 1, 'billing_email' => 'aua-kundin@example.com', 'same_as_billing' => true, 'mode' => 'test', 'wp_order_number' => 0, ]); UserAbo::create([ 'user_id' => 1, 'member_id' => 1, 'shopping_user_id' => $shoppingUser->id, 'email' => 'aua-kundin@example.com', 'is_for' => 'ot', 'payone_userid' => 0, 'clearingtype' => 'cc', 'amount' => 5000, 'active' => false, 'status' => 4, 'abo_interval' => 5, 'cancel_date' => now(), ]); $customer = Customer::create([ 'name' => 'Karla Kundin', 'email' => 'aua-kundin@example.com', 'shopping_user_id' => $shoppingUser->id, ]); $this->actingAs($customer, 'customers'); $response = (new PortalAboController)->myAbo(); expect($response->name())->toBe('portal.abo.my_abo_create'); });