Die Admin-Detailseite postete Warenkorb-Aktionen mit view=me/ot, wodurch Add-only-Modus und Change-Lock auch fuer Admins griffen (Reduzieren wurde verworfen, Entfernen lieferte 403). Formular postet jetzt mit view=admin; checkPermissions laesst view=admin nur noch fuer Admins zu (schliesst zugleich die Luecke, dass unbekannte Views alle Besitzer-Pruefungen uebersprangen). Co-authored-by: Cursor <cursoragent@cursor.com>
197 lines
6.9 KiB
PHP
197 lines
6.9 KiB
PHP
<?php
|
|
|
|
use App\Http\Controllers\User\AboController;
|
|
use App\Models\Country;
|
|
use App\Models\Setting;
|
|
use App\Models\Shipping;
|
|
use App\Models\ShippingCountry;
|
|
use App\Models\ShoppingUser;
|
|
use App\Models\UserAbo;
|
|
use App\Models\UserAboItem;
|
|
use App\Models\UserAccount;
|
|
use App\Repositories\AboRepository;
|
|
use App\User;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Symfony\Component\HttpKernel\Exception\HttpException;
|
|
|
|
uses(Tests\TestCase::class, RefreshDatabase::class);
|
|
|
|
/**
|
|
* Berater-Abo ('me') innerhalb der Mindestlaufzeit (0 bezahlte Lieferungen, Minimum 6)
|
|
* mit zwei Basis-Produkten, außerhalb des Change-Lock-Fensters (next_date weit entfernt).
|
|
*
|
|
* @return array{abo: UserAbo, consultant: User, itemA: UserAboItem, itemB: UserAboItem}
|
|
*/
|
|
function makeMinDurationAboFixture(): array
|
|
{
|
|
Setting::setContentBySlug('abo-min-duration', 6, 'int');
|
|
|
|
$country = Country::create([
|
|
'code' => '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<string, mixed> $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);
|
|
});
|
|
});
|