330 lines
11 KiB
PHP
330 lines
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Enums\PriceType;
|
|
use App\Enums\ProductStatus;
|
|
use App\Enums\ProductType;
|
|
use App\Models\Category;
|
|
use App\Models\Hub;
|
|
use App\Models\Partner;
|
|
use App\Models\Product;
|
|
use App\Models\User;
|
|
use Illuminate\Http\UploadedFile;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use Spatie\Permission\Models\Role;
|
|
|
|
beforeEach(function () {
|
|
app()[\Spatie\Permission\PermissionRegistrar::class]->forgetCachedPermissions();
|
|
Role::create(['name' => 'Retailer']);
|
|
Role::create(['name' => 'Manufacturer']);
|
|
Role::create(['name' => 'Customer']);
|
|
});
|
|
|
|
function makeRetailerWithHub(): array
|
|
{
|
|
$hub = Hub::factory()->create();
|
|
$partner = Partner::factory()->setupCompleted()->create(['hub_id' => $hub->id]);
|
|
$user = User::factory()->create(['partner_id' => $partner->id]);
|
|
$user->assignRole('Retailer');
|
|
|
|
return [$user, $partner, $hub];
|
|
}
|
|
|
|
test('retailer can access teaser product creation page', function () {
|
|
[$user] = makeRetailerWithHub();
|
|
|
|
$this->actingAs($user)
|
|
->get(route('products.create.teaser'))
|
|
->assertSuccessful();
|
|
});
|
|
|
|
test('manufacturer can access teaser product creation page', function () {
|
|
$hub = Hub::factory()->create();
|
|
$partner = Partner::factory()->setupCompleted()->create(['hub_id' => $hub->id]);
|
|
$user = User::factory()->create(['partner_id' => $partner->id]);
|
|
$user->assignRole('Manufacturer');
|
|
|
|
$this->actingAs($user)
|
|
->get(route('products.create.teaser'))
|
|
->assertSuccessful();
|
|
});
|
|
|
|
test('customer cannot access teaser product creation page', function () {
|
|
$customer = User::factory()->create();
|
|
$customer->assignRole('Customer');
|
|
|
|
$this->actingAs($customer)
|
|
->get(route('products.create.teaser'))
|
|
->assertForbidden();
|
|
});
|
|
|
|
test('retailer can create teaser product with from_price', function () {
|
|
Storage::fake('public');
|
|
[$user, $partner, $hub] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Sideboard Eiche')
|
|
->set('descriptionShort', 'Schönes Massivholz-Sideboard aus regionaler Fertigung.')
|
|
->set('priceType', 'from_price')
|
|
->set('priceDisplayText', 'Ab 1.800 €')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'active')
|
|
->set('mainImages', [UploadedFile::fake()->image('product.jpg', 800, 600)])
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$product = Product::where('name', 'Sideboard Eiche')->first();
|
|
|
|
expect($product)->not->toBeNull();
|
|
expect($product->product_type)->toBe(ProductType::LocalStock);
|
|
expect($product->price_type)->toBe(PriceType::FromPrice);
|
|
expect($product->price_display_text)->toBe('Ab 1.800 €');
|
|
expect($product->partner_id)->toBe($partner->id);
|
|
expect($product->hub_id)->toBe($hub->id);
|
|
expect($product->is_curated)->toBeFalse();
|
|
});
|
|
|
|
test('retailer can create teaser product with on_request price', function () {
|
|
Storage::fake('public');
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Küche Massivholz')
|
|
->set('descriptionShort', 'Individuelle Küche auf Maß.')
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'draft')
|
|
->set('mainImages', [UploadedFile::fake()->image('kitchen.jpg', 800, 600)])
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$product = Product::where('name', 'Küche Massivholz')->first();
|
|
expect($product->price_type)->toBe(PriceType::OnRequest);
|
|
});
|
|
|
|
test('teaser product rejects fixed price type', function () {
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Produkt mit Festpreis')
|
|
->set('descriptionShort', 'Beschreibung.')
|
|
->set('priceType', 'fixed')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'active')
|
|
->call('save')
|
|
->assertHasErrors(['priceType']);
|
|
});
|
|
|
|
test('teaser product requires price display text when from_price', function () {
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Produkt')
|
|
->set('descriptionShort', 'Beschreibung.')
|
|
->set('priceType', 'from_price')
|
|
->set('priceDisplayText', '')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'active')
|
|
->call('save')
|
|
->assertHasErrors(['priceDisplayText']);
|
|
});
|
|
|
|
test('teaser product requires name', function () {
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', '')
|
|
->set('descriptionShort', 'Beschreibung.')
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', $category->id)
|
|
->call('save')
|
|
->assertHasErrors(['name' => 'required']);
|
|
});
|
|
|
|
test('teaser product description short max 180 characters', function () {
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Test')
|
|
->set('descriptionShort', str_repeat('x', 181))
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', $category->id)
|
|
->call('save')
|
|
->assertHasErrors(['descriptionShort' => 'max']);
|
|
});
|
|
|
|
test('teaser product requires category', function () {
|
|
[$user] = makeRetailerWithHub();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Test Produkt')
|
|
->set('descriptionShort', 'Beschreibung.')
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', null)
|
|
->call('save')
|
|
->assertHasErrors(['categoryId' => 'required']);
|
|
});
|
|
|
|
test('manufacturer can create teaser product', function () {
|
|
Storage::fake('public');
|
|
$hub = Hub::factory()->create();
|
|
$partner = Partner::factory()->setupCompleted()->create(['hub_id' => $hub->id]);
|
|
$user = User::factory()->create(['partner_id' => $partner->id]);
|
|
$user->assignRole('Manufacturer');
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Hersteller Teaser-Produkt')
|
|
->set('descriptionShort', 'Ein Teaser-Produkt vom Hersteller.')
|
|
->set('priceType', 'from_price')
|
|
->set('priceDisplayText', 'Ab 3.200 €')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'active')
|
|
->set('mainImages', [UploadedFile::fake()->image('product.jpg', 800, 600)])
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$product = Product::where('name', 'Hersteller Teaser-Produkt')->first();
|
|
|
|
expect($product)->not->toBeNull();
|
|
expect($product->product_type)->toBe(ProductType::LocalStock);
|
|
expect($product->partner_id)->toBe($partner->id);
|
|
expect($product->hub_id)->toBe($hub->id);
|
|
});
|
|
|
|
test('created teaser product is automatically not curated', function () {
|
|
Storage::fake('public');
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Nicht kuratiertes Produkt')
|
|
->set('descriptionShort', 'Test.')
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'active')
|
|
->set('mainImages', [UploadedFile::fake()->image('test.jpg', 800, 600)])
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$product = Product::where('name', 'Nicht kuratiertes Produkt')->first();
|
|
expect($product->is_curated)->toBeFalse();
|
|
expect($product->product_type)->toBe(ProductType::LocalStock);
|
|
});
|
|
|
|
test('submitting teaser product as active sets status to pending', function () {
|
|
Storage::fake('public');
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Pending Teaser')
|
|
->set('descriptionShort', 'Test zur Freigabe.')
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'active')
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$product = Product::where('name', 'Pending Teaser')->first();
|
|
expect($product->status)->toBe(ProductStatus::Pending);
|
|
});
|
|
|
|
test('saving teaser product as draft keeps status as draft', function () {
|
|
Storage::fake('public');
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Draft Teaser')
|
|
->set('descriptionShort', 'Test Entwurf.')
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'draft')
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$product = Product::where('name', 'Draft Teaser')->first();
|
|
expect($product->status)->toBe(ProductStatus::Draft);
|
|
});
|
|
|
|
test('teaser product generates b2in article number on create', function () {
|
|
Storage::fake('public');
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Teaser mit Nummer')
|
|
->set('descriptionShort', 'Test Artikelnummer.')
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', $category->id)
|
|
->set('status', 'active')
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$product = Product::where('name', 'Teaser mit Nummer')->first();
|
|
expect($product->b2in_article_number)->toStartWith('B2IN-');
|
|
expect($product->b2in_article_number)->toBe('B2IN-000001');
|
|
});
|
|
|
|
test('teaser product saves partner product number', function () {
|
|
Storage::fake('public');
|
|
[$user] = makeRetailerWithHub();
|
|
$category = Category::factory()->create();
|
|
|
|
$this->actingAs($user);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->set('name', 'Teaser mit Partnernummer')
|
|
->set('descriptionShort', 'Test Partnernummer.')
|
|
->set('priceType', 'on_request')
|
|
->set('categoryId', $category->id)
|
|
->set('partnerProductNumber', 'MY-CUSTOM-001')
|
|
->set('status', 'active')
|
|
->call('save')
|
|
->assertHasNoErrors();
|
|
|
|
$product = Product::where('name', 'Teaser mit Partnernummer')->first();
|
|
expect($product->partner_product_number)->toBe('MY-CUSTOM-001');
|
|
});
|
|
|
|
test('teaser product auto-generates partner product number on mount', function () {
|
|
[$user, $partner] = makeRetailerWithHub();
|
|
$this->actingAs($user);
|
|
|
|
$expectedNumber = sprintf('P%03d-%04d', $partner->id, 1);
|
|
|
|
Livewire\Volt\Volt::test('products.form-teaser')
|
|
->assertSet('partnerProductNumber', $expectedNumber);
|
|
});
|