attributes->get('tenant'); if (! $tenant) { return response()->json([ 'data' => [], 'message' => 'Tenant not found.', ], 404); } if (! $tenant->lemonsqueezy_customer_id) { return response()->json([ 'data' => [], 'meta' => [ 'next' => null, 'previous' => null, 'has_more' => false, ], ]); } $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->orders->listForCustomer($tenant->lemonsqueezy_customer_id, $query); } catch (\Throwable $exception) { Log::warning('Failed to load Lemon Squeezy transactions', [ 'tenant_id' => $tenant->id, 'error' => $exception->getMessage(), ]); return response()->json([ 'data' => [], 'message' => 'Failed to load Lemon Squeezy 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); } $subscriptionId = null; try { $subscriptionId = $tenant->getActiveResellerPackage()?->lemonsqueezy_subscription_id; if (! $subscriptionId) { return response()->json([ 'message' => 'No active subscription found.', ], 404); } Log::debug('Fetching Lemon Squeezy subscription portal URL', [ 'tenant_id' => $tenant->id, 'lemonsqueezy_subscription_id' => $subscriptionId, ]); $subscription = $this->subscriptions->retrieve($subscriptionId); } catch (\Throwable $exception) { $context = [ 'tenant_id' => $tenant->id, 'lemonsqueezy_customer_id' => $tenant->lemonsqueezy_customer_id, 'lemonsqueezy_subscription_id' => $subscriptionId ?? null, 'error' => $exception->getMessage(), ]; if ($exception instanceof LemonSqueezyException) { $context['lemonsqueezy_status'] = $exception->status(); $context['lemonsqueezy_error'] = Arr::get($exception->context(), 'errors.0'); $context['lemonsqueezy_errors'] = Arr::get($exception->context(), 'errors'); $context['lemonsqueezy_request_id'] = Arr::get($exception->context(), 'meta.request_id'); } Log::warning('Failed to fetch Lemon Squeezy subscription portal URL', [ ...$context, ]); return response()->json([ 'message' => 'Failed to fetch Lemon Squeezy subscription portal URL.', ], 502); } $url = $this->subscriptions->portalUrl($subscription) ?? $this->subscriptions->updatePaymentMethodUrl($subscription); if (! $url) { $sessionData = Arr::get($subscription, 'data'); $sessionUrls = Arr::get($subscription, 'attributes.urls'); Log::warning('Lemon Squeezy subscription missing portal URL', [ 'tenant_id' => $tenant->id, 'lemonsqueezy_customer_id' => $tenant->lemonsqueezy_customer_id, 'lemonsqueezy_subscription_id' => $subscriptionId ?? null, 'subscription_keys' => array_keys($subscription), 'session_data_keys' => is_array($sessionData) ? array_keys($sessionData) : null, 'session_url_keys' => is_array($sessionUrls) ? array_keys($sessionUrls) : null, ]); return response()->json([ 'message' => 'Lemon Squeezy subscription missing portal URL.', ], 502); } return response()->json([ 'url' => $url, ]); } }