catalog->find($addonKey)) { throw ValidationException::withMessages([ 'addon_key' => __('Unbekanntes Add-on.'), ]); } $priceId = $this->catalog->resolvePriceId($addonKey); if (! $priceId) { throw ValidationException::withMessages([ 'addon_key' => __('Für dieses Add-on ist kein Paddle-Preis hinterlegt.'), ]); } $event->loadMissing('eventPackage'); if (! $event->eventPackage) { throw ValidationException::withMessages([ 'event' => __('Kein Paket für dieses Event hinterlegt.'), ]); } $addonIntent = (string) Str::uuid(); $increments = $this->catalog->resolveIncrements($addonKey); $metadata = [ 'tenant_id' => (string) $tenant->id, 'event_id' => (string) $event->id, 'event_package_id' => (string) $event->eventPackage->id, 'addon_key' => $addonKey, 'addon_intent' => $addonIntent, 'quantity' => $quantity, 'legal_version' => $this->resolveLegalVersion(), 'accepted_terms' => $acceptedTerms ? '1' : '0', 'accepted_waiver' => $acceptedWaiver ? '1' : '0', ]; $requestPayload = array_filter([ 'customer_id' => $tenant->paddle_customer_id, 'items' => [ [ 'price_id' => $priceId, 'quantity' => $quantity, ], ], 'metadata' => $metadata, 'success_url' => $payload['success_url'] ?? null, 'cancel_url' => $payload['cancel_url'] ?? null, ], static fn ($value) => $value !== null && $value !== ''); $response = $this->paddle->post('/checkout/links', $requestPayload); $checkoutUrl = Arr::get($response, 'data.url') ?? Arr::get($response, 'url'); $checkoutId = Arr::get($response, 'data.id') ?? Arr::get($response, 'id'); if (! $checkoutUrl) { Log::warning('Paddle addon checkout response missing url', ['response' => $response]); } EventPackageAddon::create([ 'event_package_id' => $event->eventPackage->id, 'event_id' => $event->id, 'tenant_id' => $tenant->id, 'addon_key' => $addonKey, 'quantity' => $quantity, 'price_id' => $priceId, 'checkout_id' => $checkoutId, 'transaction_id' => null, 'status' => 'pending', 'metadata' => array_merge($metadata, [ 'increments' => $increments, 'provider_payload' => $response, 'consents' => [ 'legal_version' => $metadata['legal_version'], 'accepted_terms_at' => $acceptedTerms ? now()->toIso8601String() : null, 'digital_content_waiver_at' => $acceptedWaiver ? now()->toIso8601String() : null, ], ]), 'extra_photos' => ($increments['extra_photos'] ?? 0) * $quantity, 'extra_guests' => ($increments['extra_guests'] ?? 0) * $quantity, 'extra_gallery_days' => ($increments['extra_gallery_days'] ?? 0) * $quantity, ]); return [ 'checkout_url' => $checkoutUrl, 'expires_at' => Arr::get($response, 'data.expires_at') ?? Arr::get($response, 'expires_at'), 'id' => $checkoutId, ]; } protected function resolveLegalVersion(): string { return config('app.legal_version', now()->toDateString()); } }