create([ 'key' => 'local', 'name' => 'Local', 'driver' => 'local', 'config' => [], 'is_hot' => true, 'is_default' => true, 'is_active' => true, 'priority' => 1, ]); } public function test_guest_upload_blocked_when_photo_limit_reached(): void { Bus::fake(); $tenant = Tenant::factory()->create(); $event = Event::factory()->for($tenant)->create([ 'status' => 'published', ]); $package = Package::factory()->endcustomer()->create([ 'max_photos' => 1, 'max_guests' => null, ]); EventPackage::create([ 'event_id' => $event->id, 'package_id' => $package->id, 'purchased_price' => $package->price, 'purchased_at' => now(), 'used_photos' => 1, 'used_guests' => 0, 'gallery_expires_at' => now()->addDays(7), ]); $emotion = Emotion::factory()->create(); $emotion->eventTypes()->attach($event->event_type_id); /** @var EventJoinTokenService $tokenService */ $tokenService = $this->app->make(EventJoinTokenService::class); $joinToken = $tokenService->createToken($event, ['label' => 'Test']); $token = $joinToken->plain_token; $response = $this->post("/api/v1/events/{$token}/upload", [ 'photo' => UploadedFile::fake()->image('limit.jpg', 800, 600), ], [ 'X-Device-Id' => 'device-123', ]); $response->assertStatus(402); $response->assertJsonPath('error.code', 'photo_limit_exceeded'); Bus::assertNothingDispatched(); } public function test_guest_upload_increments_usage_and_succeeds(): void { Bus::fake(); $tenant = Tenant::factory()->create(); $event = Event::factory()->for($tenant)->create([ 'status' => 'published', ]); $package = Package::factory()->endcustomer()->create([ 'max_photos' => 2, 'max_guests' => null, ]); $eventPackage = EventPackage::create([ 'event_id' => $event->id, 'package_id' => $package->id, 'purchased_price' => $package->price, 'purchased_at' => now(), 'used_photos' => 1, 'used_guests' => 0, 'gallery_expires_at' => now()->addDays(7), ]); $emotion = Emotion::factory()->create(); $emotion->eventTypes()->attach($event->event_type_id); /** @var EventJoinTokenService $tokenService */ $tokenService = $this->app->make(EventJoinTokenService::class); $token = $tokenService->createToken($event, ['label' => 'Test'])->plain_token; $response = $this->post("/api/v1/events/{$token}/upload", [ 'photo' => UploadedFile::fake()->image('success.jpg', 1024, 768), ], [ 'X-Device-Id' => 'device-456', ]); $response->assertCreated(); $this->assertEquals( 2, $eventPackage->refresh()->used_photos ); $thresholdJobs = Bus::dispatched(SendEventPackagePhotoThresholdWarning::class); $this->assertGreaterThanOrEqual(2, $thresholdJobs->count()); Bus::assertDispatched(SendEventPackagePhotoLimitNotification::class); } }