create(); $this->attachPackage($event, ['basic_uploads', 'ai_styling']); $style = AiStyle::query()->create([ 'key' => 'premium-package-style', 'name' => 'Premium Package Style', 'provider' => 'runware', 'provider_model' => 'runware-default', 'is_active' => true, 'is_premium' => true, ]); $service = app(AiStyleAccessService::class); $this->assertTrue($service->canUseStyle($event->fresh(), $style)); } public function test_addon_entitlement_cannot_use_premium_style_by_default(): void { $event = Event::factory()->create(); $eventPackage = $this->attachPackage($event, ['basic_uploads']); $this->attachAddon($event, $eventPackage); $style = AiStyle::query()->create([ 'key' => 'premium-addon-blocked', 'name' => 'Premium Addon Blocked', 'provider' => 'runware', 'provider_model' => 'runware-default', 'is_active' => true, 'is_premium' => true, ]); $service = app(AiStyleAccessService::class); $this->assertFalse($service->canUseStyle($event->fresh(), $style)); } public function test_addon_entitlement_can_use_premium_style_when_style_metadata_allows_it(): void { $event = Event::factory()->create(); $eventPackage = $this->attachPackage($event, ['basic_uploads']); $this->attachAddon($event, $eventPackage); $style = AiStyle::query()->create([ 'key' => 'premium-addon-allowed', 'name' => 'Premium Addon Allowed', 'provider' => 'runware', 'provider_model' => 'runware-default', 'is_active' => true, 'is_premium' => true, 'metadata' => [ 'entitlements' => [ 'allow_with_addon' => true, ], ], ]); $service = app(AiStyleAccessService::class); $this->assertTrue($service->canUseStyle($event->fresh(), $style)); } public function test_required_package_feature_blocks_style_when_missing(): void { $event = Event::factory()->create(); $this->attachPackage($event, ['basic_uploads', 'ai_styling']); $style = AiStyle::query()->create([ 'key' => 'advanced-only-style', 'name' => 'Advanced Only', 'provider' => 'runware', 'provider_model' => 'runware-default', 'is_active' => true, 'metadata' => [ 'entitlements' => [ 'required_package_features' => ['advanced_analytics'], ], ], ]); $service = app(AiStyleAccessService::class); $this->assertFalse($service->canUseStyle($event->fresh(), $style)); } public function test_required_package_feature_allows_style_when_present(): void { $event = Event::factory()->create(); $this->attachPackage($event, ['basic_uploads', 'ai_styling', 'advanced_analytics']); $style = AiStyle::query()->create([ 'key' => 'advanced-available-style', 'name' => 'Advanced Available', 'provider' => 'runware', 'provider_model' => 'runware-default', 'is_active' => true, 'metadata' => [ 'entitlements' => [ 'required_package_features' => ['advanced_analytics'], ], ], ]); $service = app(AiStyleAccessService::class); $this->assertTrue($service->canUseStyle($event->fresh(), $style)); } /** * @param array $features */ private function attachPackage(Event $event, array $features): EventPackage { $package = Package::factory()->endcustomer()->create([ 'features' => $features, ]); return EventPackage::query()->create([ 'event_id' => $event->id, 'package_id' => $package->id, 'purchased_price' => $package->price, 'purchased_at' => now(), 'gallery_expires_at' => now()->addDays(30), ]); } private function attachAddon(Event $event, EventPackage $eventPackage): EventPackageAddon { return EventPackageAddon::query()->create([ 'event_package_id' => $eventPackage->id, 'event_id' => $event->id, 'tenant_id' => $event->tenant_id, 'addon_key' => 'ai_styling_unlock', 'quantity' => 1, 'status' => 'completed', 'purchased_at' => now(), ]); } }