Migrate billing from Paddle to Lemon Squeezy
This commit is contained in:
@@ -2,34 +2,32 @@
|
||||
|
||||
namespace App\Services\GiftVouchers;
|
||||
|
||||
use App\Services\Paddle\Exceptions\PaddleException;
|
||||
use App\Services\Paddle\PaddleClient;
|
||||
use Illuminate\Support\Arr;
|
||||
use App\Services\LemonSqueezy\LemonSqueezyCheckoutService;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class GiftVoucherCheckoutService
|
||||
{
|
||||
public function __construct(private readonly PaddleClient $client) {}
|
||||
public function __construct(private readonly LemonSqueezyCheckoutService $checkout) {}
|
||||
|
||||
/**
|
||||
* @return array<int, array{key:string,label:string,amount:float,currency:string,paddle_price_id?:string|null,can_checkout:bool}>
|
||||
* @return array<int, array{key:string,label:string,amount:float,currency:string,lemonsqueezy_variant_id?:string|null,can_checkout:bool}>
|
||||
*/
|
||||
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;
|
||||
$variantId = $tier['lemonsqueezy_variant_id'] ?? null;
|
||||
|
||||
return [
|
||||
'key' => $tier['key'],
|
||||
'label' => $tier['label'],
|
||||
'amount' => (float) $tier['amount'],
|
||||
'currency' => $currency,
|
||||
'paddle_price_id' => $priceId,
|
||||
'can_checkout' => ! empty($priceId),
|
||||
'lemonsqueezy_variant_id' => $variantId,
|
||||
'can_checkout' => ! empty($variantId),
|
||||
];
|
||||
})
|
||||
->values()
|
||||
@@ -44,47 +42,34 @@ class GiftVoucherCheckoutService
|
||||
{
|
||||
$tier = $this->findTier($data['tier_key']);
|
||||
|
||||
if (! $tier || empty($tier['paddle_price_id'])) {
|
||||
if (! $tier || empty($tier['lemonsqueezy_variant_id'])) {
|
||||
throw ValidationException::withMessages([
|
||||
'tier_key' => __('Gift voucher is not available right now.'),
|
||||
]);
|
||||
}
|
||||
|
||||
$customerId = $this->ensureCustomerId($data['purchaser_email']);
|
||||
$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 !== '');
|
||||
|
||||
$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(),
|
||||
return $this->checkout->createVariantCheckout(
|
||||
(string) $tier['lemonsqueezy_variant_id'],
|
||||
$customData,
|
||||
[
|
||||
'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_url' => $data['return_url'] ?? null,
|
||||
'customer_email' => $data['purchaser_email'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,43 +90,4 @@ class GiftVoucherCheckoutService
|
||||
|
||||
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');
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user