*/ public function tiers(): array { $provider = $this->resolveProvider(); $checkoutCurrency = Str::upper((string) config('checkout.currency', 'EUR')); return collect(config('gift-vouchers.tiers', [])) ->map(function (array $tier) use ($provider, $checkoutCurrency): array { $currency = Str::upper($tier['currency'] ?? 'EUR'); $variantId = $tier['lemonsqueezy_variant_id'] ?? null; $canCheckout = $provider === CheckoutSession::PROVIDER_PAYPAL ? $currency === $checkoutCurrency : ! empty($variantId); return [ 'key' => $tier['key'], 'label' => $tier['label'], 'amount' => (float) $tier['amount'], 'currency' => $currency, 'lemonsqueezy_variant_id' => $variantId, 'can_checkout' => $canCheckout, ]; }) ->values() ->all(); } /** * @param array{tier_key:string,purchaser_email:string,recipient_email?:string|null,recipient_name?:string|null,message?:string|null,success_url?:string|null,return_url?:string|null} $data * @return array{checkout_url:?string,expires_at:?string,id:?string} */ public function create(array $data): array { $provider = $this->resolveProvider(); if ($provider === CheckoutSession::PROVIDER_PAYPAL) { return $this->createPayPalCheckout($data); } $tier = $this->findTier($data['tier_key']); if (! $tier || empty($tier['lemonsqueezy_variant_id'])) { throw ValidationException::withMessages([ 'tier_key' => __('Gift voucher is not available right now.'), ]); } $customData = array_filter([ 'type' => 'gift_voucher', 'tier_key' => $tier['key'], 'purchaser_email' => $data['purchaser_email'], 'recipient_email' => $data['recipient_email'] ?? null, 'recipient_name' => $data['recipient_name'] ?? null, 'message' => $data['message'] ?? null, 'app_locale' => App::getLocale(), 'success_url' => $data['success_url'] ?? null, 'return_url' => $data['return_url'] ?? null, 'lemonsqueezy_variant_id' => $tier['lemonsqueezy_variant_id'], ], static fn ($value) => $value !== null && $value !== ''); return $this->checkout->createVariantCheckout( (string) $tier['lemonsqueezy_variant_id'], $customData, [ 'success_url' => $data['success_url'] ?? null, 'return_url' => $data['return_url'] ?? null, 'customer_email' => $data['purchaser_email'], ] ); } /** * @return array|null */ protected function findTier(string $key): ?array { $tiers = collect(config('gift-vouchers.tiers', [])) ->keyBy('key'); $tier = $tiers->get($key); if (! $tier) { return null; } $tier['currency'] = Str::upper($tier['currency'] ?? 'EUR'); return $tier; } /** * @param array{tier_key:string,purchaser_email:string,recipient_email?:string|null,recipient_name?:string|null,message?:string|null,success_url?:string|null,return_url?:string|null} $data * @return array{checkout_url:?string,expires_at:?string,id:?string} */ protected function createPayPalCheckout(array $data): array { $tier = $this->findTier($data['tier_key']); if (! $tier) { throw ValidationException::withMessages([ 'tier_key' => __('Gift voucher is not available right now.'), ]); } $currency = Str::upper($tier['currency'] ?? 'EUR'); $checkoutCurrency = Str::upper((string) config('checkout.currency', 'EUR')); if ($currency !== $checkoutCurrency) { throw ValidationException::withMessages([ 'tier_key' => __('Gift voucher currency is not supported.'), ]); } $voucher = GiftVoucher::create([ 'code' => $this->generateCode(), 'amount' => (float) $tier['amount'], 'currency' => $currency, 'status' => GiftVoucher::STATUS_PENDING, 'purchaser_email' => $data['purchaser_email'], 'recipient_email' => $data['recipient_email'] ?? null, 'recipient_name' => $data['recipient_name'] ?? null, 'message' => $data['message'] ?? null, 'metadata' => array_filter([ 'tier_key' => $tier['key'], 'app_locale' => App::getLocale(), 'success_url' => $data['success_url'] ?? null, 'return_url' => $data['return_url'] ?? null, ], static fn ($value) => $value !== null && $value !== ''), 'expires_at' => now()->addYears((int) config('gift-vouchers.default_valid_years', 5)), ]); $successUrl = $data['success_url'] ?? null; $returnUrl = $data['return_url'] ?? $successUrl; $paypalReturnUrl = route('paypal.gift-voucher.return', absolute: true); try { $order = $this->paypalOrders->createSimpleOrder( referenceId: 'gift-voucher-'.$voucher->id, description: $tier['label'] ?? 'Gift Voucher', amount: (float) $tier['amount'], currency: $currency, options: [ 'custom_id' => 'gift_voucher_'.$voucher->id, 'return_url' => $paypalReturnUrl, 'cancel_url' => $paypalReturnUrl, 'locale' => App::getLocale(), 'request_id' => 'gift-voucher-'.$voucher->id, ], ); } catch (PayPalException) { $voucher->delete(); throw ValidationException::withMessages([ 'tier_key' => __('Unable to create PayPal checkout.'), ]); } $orderId = $order['id'] ?? null; if (! is_string($orderId) || $orderId === '') { $voucher->delete(); throw ValidationException::withMessages([ 'tier_key' => __('PayPal order ID missing.'), ]); } $approveUrl = $this->paypalOrders->resolveApproveUrl($order); $voucher->forceFill([ 'paypal_order_id' => $orderId, 'metadata' => array_merge($voucher->metadata ?? [], array_filter([ 'paypal_order_id' => $orderId, 'paypal_approve_url' => $approveUrl, 'paypal_success_url' => $successUrl, 'paypal_cancel_url' => $returnUrl, 'paypal_created_at' => now()->toIso8601String(), ])), ])->save(); return [ 'checkout_url' => $approveUrl, 'expires_at' => null, 'id' => $orderId, ]; } protected function resolveProvider(): ?string { $provider = config('gift-vouchers.provider'); if (is_string($provider) && $provider !== '') { return $provider; } $default = config('checkout.default_provider'); return is_string($default) && $default !== '' ? $default : null; } protected function generateCode(): string { return 'GIFT-'.Str::upper(Str::random(8)); } }