attributes->get('tenant'); if (! $tenant) { return response()->json([ 'data' => [], 'message' => 'Tenant not found.', ], 404); } if (! $tenant->paddle_customer_id) { try { $this->paddleCustomers->ensureCustomerId($tenant); } catch (\Throwable $exception) { Log::warning('Failed to resolve Paddle customer for tenant', [ 'tenant_id' => $tenant->id, 'error' => $exception->getMessage(), ]); return response()->json([ 'data' => [], 'message' => 'Failed to resolve Paddle customer.', ], 502); } } $cursor = $request->query('cursor'); $perPage = (int) $request->query('per_page', 25); $query = [ 'per_page' => max(1, min($perPage, 100)), ]; if ($cursor) { $query['after'] = $cursor; } try { $result = $this->paddleTransactions->listForCustomer($tenant->paddle_customer_id, $query); } catch (\Throwable $exception) { Log::warning('Failed to load Paddle transactions', [ 'tenant_id' => $tenant->id, 'error' => $exception->getMessage(), ]); return response()->json([ 'data' => [], 'message' => 'Failed to load Paddle transactions.', ], 502); } return response()->json([ 'data' => $result['data'], 'meta' => $result['meta'], ]); } public function addons(Request $request): JsonResponse { $tenant = $request->attributes->get('tenant'); if (! $tenant) { return response()->json([ 'data' => [], 'message' => 'Tenant not found.', ], 404); } $perPage = max(1, min((int) $request->query('per_page', 25), 100)); $page = max(1, (int) $request->query('page', 1)); $paginator = EventPackageAddon::query() ->where('tenant_id', $tenant->id) ->with(['event:id,name,slug']) ->orderByDesc('purchased_at') ->orderByDesc('created_at') ->paginate($perPage, ['*'], 'page', $page); $data = $paginator->getCollection()->map(function (EventPackageAddon $addon) { return [ 'id' => $addon->id, 'addon_key' => $addon->addon_key, 'label' => $addon->metadata['label'] ?? null, 'quantity' => (int) ($addon->quantity ?? 1), 'status' => $addon->status, 'amount' => $addon->amount !== null ? (float) $addon->amount : null, 'currency' => $addon->currency, 'extra_photos' => (int) $addon->extra_photos, 'extra_guests' => (int) $addon->extra_guests, 'extra_gallery_days' => (int) $addon->extra_gallery_days, 'purchased_at' => $addon->purchased_at?->toIso8601String(), 'receipt_url' => Arr::get($addon->receipt_payload, 'receipt_url'), 'event' => $addon->event ? [ 'id' => $addon->event->id, 'slug' => $addon->event->slug, 'name' => $addon->event->name, ] : null, ]; })->values(); return response()->json([ 'data' => $data, 'meta' => [ 'current_page' => $paginator->currentPage(), 'last_page' => $paginator->lastPage(), 'per_page' => $paginator->perPage(), 'total' => $paginator->total(), ], ]); } public function portal(Request $request): JsonResponse { $tenant = $request->attributes->get('tenant'); if (! $tenant) { return response()->json([ 'message' => 'Tenant not found.', ], 404); } $customerId = null; try { $customerId = $this->paddleCustomers->ensureCustomerId($tenant); Log::debug('Creating Paddle customer portal session', [ 'tenant_id' => $tenant->id, 'paddle_customer_id' => $customerId, 'paddle_environment' => config('paddle.environment'), 'paddle_base_url' => config('paddle.base_url'), ]); $session = $this->portalSessions->createSession($customerId); } catch (\Throwable $exception) { $context = [ 'tenant_id' => $tenant->id, 'paddle_customer_id' => $customerId ?? $tenant->paddle_customer_id, 'error' => $exception->getMessage(), 'paddle_environment' => config('paddle.environment'), 'paddle_base_url' => config('paddle.base_url'), ]; if ($exception instanceof PaddleException) { $context['paddle_status'] = $exception->status(); $context['paddle_error_code'] = Arr::get($exception->context(), 'error.code'); $context['paddle_error_message'] = Arr::get($exception->context(), 'error.message'); $context['paddle_error_detail'] = Arr::get($exception->context(), 'error.detail'); $context['paddle_error_doc_url'] = Arr::get($exception->context(), 'error.documentation_url'); $context['paddle_request_id'] = Arr::get($exception->context(), 'meta.request_id'); $context['paddle_errors'] = Arr::get($exception->context(), 'error.errors'); } Log::warning('Failed to create Paddle customer portal session', [ ...$context, ]); return response()->json([ 'message' => 'Failed to create Paddle customer portal session.', ], 502); } $url = Arr::get($session, 'data.urls.general.overview') ?? Arr::get($session, 'data.urls.general') ?? Arr::get($session, 'urls.general.overview') ?? Arr::get($session, 'urls.general'); if (! $url) { $sessionData = Arr::get($session, 'data'); $sessionUrls = Arr::get($session, 'data.urls') ?? Arr::get($session, 'urls'); Log::warning('Paddle customer portal session missing URL', [ 'tenant_id' => $tenant->id, 'paddle_customer_id' => $customerId ?? $tenant->paddle_customer_id, 'paddle_environment' => config('paddle.environment'), 'paddle_base_url' => config('paddle.base_url'), 'session_keys' => array_keys($session), 'session_data_keys' => is_array($sessionData) ? array_keys($sessionData) : null, 'session_url_keys' => is_array($sessionUrls) ? array_keys($sessionUrls) : null, ]); return response()->json([ 'message' => 'Paddle customer portal session missing URL.', ], 502); } return response()->json([ 'url' => $url, ]); } }