'DE', 'phone' => '49', 'en' => 'Germany', 'de' => 'Deutschland', 'es' => 'Alemania', 'fr' => 'Allemagne', 'it' => 'Germania', 'ru' => 'Германия', ]); $shipping = Shipping::create(['name' => 'Standard', 'active' => true]); ShippingCountry::create(['shipping_id' => $shipping->id, 'country_id' => $country->id]); $account = UserAccount::create([ 'salutation' => 'Herr', 'first_name' => 'Max', 'last_name' => 'Muster', 'address' => 'Musterstr. 1', 'zipcode' => '12345', 'city' => 'Musterstadt', 'country_id' => $country->id, 'phone' => '123456', 'same_as_billing' => 1, 'language' => 'de', ]); $consultant = User::forceCreate([ 'email' => 'consultant-'.uniqid('', true).'@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'admin' => 0, 'account_id' => $account->id, ]); $shoppingUser = ShoppingUser::create([ 'auth_user_id' => $consultant->id, 'member_id' => $consultant->id, 'billing_country_id' => $country->id, 'shipping_country_id' => $country->id, 'billing_email' => $consultant->email, 'shipping_email' => $consultant->email, 'billing_firstname' => 'Max', 'billing_lastname' => 'Muster', 'shipping_firstname' => 'Max', 'shipping_lastname' => 'Muster', 'same_as_billing' => 1, 'is_for' => 'me', 'is_from' => 'user_order', ]); $abo = UserAbo::create([ 'user_id' => $consultant->id, 'member_id' => $consultant->id, 'shopping_user_id' => $shoppingUser->id, 'is_for' => 'me', 'email' => $consultant->email, 'payone_userid' => random_int(100000, 999999), 'clearingtype' => 'cc', 'active' => true, 'status' => 2, 'abo_interval' => 5, 'next_date' => now()->addDays(30)->toDateString(), ]); $productA = makeProduct(['12'], 50, 19); $productB = makeProduct(['12'], 30, 19); $itemA = UserAboItem::create([ 'user_abo_id' => $abo->id, 'product_id' => $productA->id, 'comp' => 0, 'qty' => 3, 'status' => 1, ]); $itemB = UserAboItem::create([ 'user_abo_id' => $abo->id, 'product_id' => $productB->id, 'comp' => 0, 'qty' => 1, 'status' => 1, ]); return ['abo' => $abo, 'consultant' => $consultant, 'itemA' => $itemA, 'itemB' => $itemB]; } function makeAboAdminUser(): User { return User::forceCreate([ 'email' => 'admin-'.uniqid('', true).'@example.com', 'password' => bcrypt('secret'), 'lang' => 'de', 'admin' => 2, ]); } /** * Simuliert den AJAX-Call der Abo-Detailseite (iq-modal-cart.js) an AboController@update. * * @param array $payload */ function callAboCartUpdate(string $view, int $aboId, array $payload): mixed { $request = app('request'); $request->headers->set('X-Requested-With', 'XMLHttpRequest'); $request->merge($payload); return (new AboController(app(AboRepository::class)))->update($view, $aboId); } describe('Admin bearbeitet Abo-Produkte trotz Mindestlaufzeit', function () { it('erlaubt dem Admin das Reduzieren der Menge während der Mindestlaufzeit', function () { $fixture = makeMinDurationAboFixture(); $this->actingAs(makeAboAdminUser()); $response = callAboCartUpdate('admin', $fixture['abo']->id, [ 'action' => 'updateCart', 'product_id' => $fixture['itemA']->product_id, 'order_item_id' => $fixture['itemA']->id, 'cart_order_id' => $fixture['abo']->id, 'qty' => 2, ]); expect($response->getStatusCode())->toBe(200) ->and($fixture['itemA']->fresh()->qty)->toBe(2); }); it('erlaubt dem Admin das Entfernen eines Produkts während der Mindestlaufzeit', function () { $fixture = makeMinDurationAboFixture(); $this->actingAs(makeAboAdminUser()); $response = callAboCartUpdate('admin', $fixture['abo']->id, [ 'action' => 'removeFromCart', 'product_id' => $fixture['itemB']->product_id, 'order_item_id' => $fixture['itemB']->id, 'cart_order_id' => $fixture['abo']->id, ]); expect($response->getStatusCode())->toBe(200) ->and(UserAboItem::find($fixture['itemB']->id))->toBeNull(); }); it('blockiert das Reduzieren für den Berater weiterhin (Add-only, Menge bleibt)', function () { $fixture = makeMinDurationAboFixture(); $this->actingAs($fixture['consultant']); callAboCartUpdate('me', $fixture['abo']->id, [ 'action' => 'updateCart', 'product_id' => $fixture['itemA']->product_id, 'order_item_id' => $fixture['itemA']->id, 'cart_order_id' => $fixture['abo']->id, 'qty' => 1, ]); expect($fixture['itemA']->fresh()->qty)->toBe(3); }); it('blockiert das Entfernen für den Berater weiterhin (Add-only, 403)', function () { $fixture = makeMinDurationAboFixture(); $this->actingAs($fixture['consultant']); $response = callAboCartUpdate('me', $fixture['abo']->id, [ 'action' => 'removeFromCart', 'product_id' => $fixture['itemB']->product_id, 'order_item_id' => $fixture['itemB']->id, 'cart_order_id' => $fixture['abo']->id, ]); expect($response->getStatusCode())->toBe(403) ->and(UserAboItem::find($fixture['itemB']->id))->not->toBeNull(); }); it('verbietet Nicht-Admins die Admin-Sicht (view=admin => 403)', function () { $fixture = makeMinDurationAboFixture(); $this->actingAs($fixture['consultant']); expect(fn () => callAboCartUpdate('admin', $fixture['abo']->id, [ 'action' => 'removeFromCart', 'product_id' => $fixture['itemB']->product_id, 'order_item_id' => $fixture['itemB']->id, 'cart_order_id' => $fixture['abo']->id, ]))->toThrow(HttpException::class); }); });