Add PayPal support for add-on and gift voucher checkout
This commit is contained in:
@@ -2,24 +2,37 @@
|
||||
|
||||
namespace App\Services\GiftVouchers;
|
||||
|
||||
use App\Models\CheckoutSession;
|
||||
use App\Models\GiftVoucher;
|
||||
use App\Services\LemonSqueezy\LemonSqueezyCheckoutService;
|
||||
use App\Services\PayPal\Exceptions\PayPalException;
|
||||
use App\Services\PayPal\PayPalOrderService;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
|
||||
class GiftVoucherCheckoutService
|
||||
{
|
||||
public function __construct(private readonly LemonSqueezyCheckoutService $checkout) {}
|
||||
public function __construct(
|
||||
private readonly LemonSqueezyCheckoutService $checkout,
|
||||
private readonly PayPalOrderService $paypalOrders,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @return array<int, array{key:string,label:string,amount:float,currency:string,lemonsqueezy_variant_id?:string|null,can_checkout:bool}>
|
||||
*/
|
||||
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): array {
|
||||
->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'],
|
||||
@@ -27,7 +40,7 @@ class GiftVoucherCheckoutService
|
||||
'amount' => (float) $tier['amount'],
|
||||
'currency' => $currency,
|
||||
'lemonsqueezy_variant_id' => $variantId,
|
||||
'can_checkout' => ! empty($variantId),
|
||||
'can_checkout' => $canCheckout,
|
||||
];
|
||||
})
|
||||
->values()
|
||||
@@ -40,6 +53,12 @@ class GiftVoucherCheckoutService
|
||||
*/
|
||||
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'])) {
|
||||
@@ -90,4 +109,119 @@ class GiftVoucherCheckoutService
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user