*/ public function tiers(): array { return collect(config('gift-vouchers.tiers', [])) ->map(function (array $tier): array { $currency = Str::upper($tier['currency'] ?? 'EUR'); $priceId = $tier['paddle_price_id'] ?? null; return [ 'key' => $tier['key'], 'label' => $tier['label'], 'amount' => (float) $tier['amount'], 'currency' => $currency, 'paddle_price_id' => $priceId, 'can_checkout' => ! empty($priceId), ]; }) ->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 { $tier = $this->findTier($data['tier_key']); if (! $tier || empty($tier['paddle_price_id'])) { throw ValidationException::withMessages([ 'tier_key' => __('Gift voucher is not available right now.'), ]); } $customerId = $this->ensureCustomerId($data['purchaser_email']); $payload = [ 'items' => [ [ 'price_id' => $tier['paddle_price_id'], 'quantity' => 1, ], ], 'customer_id' => $customerId, 'custom_data' => 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, 'cancel_url' => $data['return_url'] ?? null, ]), ]; $response = $this->client->post('/transactions', $payload); return [ 'checkout_url' => Arr::get($response, 'data.checkout.url') ?? Arr::get($response, 'checkout.url') ?? Arr::get($response, 'data.url') ?? Arr::get($response, 'url'), 'expires_at' => Arr::get($response, 'data.checkout.expires_at') ?? Arr::get($response, 'data.expires_at') ?? Arr::get($response, 'expires_at'), 'id' => Arr::get($response, 'data.id') ?? Arr::get($response, 'id'), ]; } /** * @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; } protected function ensureCustomerId(string $email): string { $payload = ['email' => $email]; try { $response = $this->client->post('/customers', $payload); } catch (PaddleException $exception) { $customerId = $this->resolveExistingCustomerId($email, $exception); if ($customerId) { return $customerId; } throw $exception; } $customerId = Arr::get($response, 'data.id') ?? Arr::get($response, 'id'); if (! $customerId) { throw new PaddleException('Failed to create Paddle customer.'); } return $customerId; } protected function resolveExistingCustomerId(string $email, PaddleException $exception): ?string { if ($exception->status() !== 409 || Arr::get($exception->context(), 'error.code') !== 'customer_already_exists') { return null; } $response = $this->client->get('/customers', [ 'email' => $email, 'per_page' => 1, ]); return Arr::get($response, 'data.0.id') ?? Arr::get($response, 'data.0.customer_id'); } }