Migrate billing from Paddle to Lemon Squeezy
This commit is contained in:
@@ -5,12 +5,11 @@ namespace App\Services\GiftVouchers;
|
||||
use App\Enums\CouponStatus;
|
||||
use App\Enums\CouponType;
|
||||
use App\Jobs\NotifyGiftVoucherReminder;
|
||||
use App\Jobs\SyncCouponToPaddle;
|
||||
use App\Mail\GiftVoucherIssued;
|
||||
use App\Models\Coupon;
|
||||
use App\Models\GiftVoucher;
|
||||
use App\Models\Package;
|
||||
use App\Services\Paddle\PaddleTransactionService;
|
||||
use App\Services\LemonSqueezy\LemonSqueezyOrderService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
@@ -21,15 +20,15 @@ use Illuminate\Validation\ValidationException;
|
||||
|
||||
class GiftVoucherService
|
||||
{
|
||||
public function __construct(private readonly PaddleTransactionService $transactions) {}
|
||||
public function __construct(private readonly LemonSqueezyOrderService $orders) {}
|
||||
|
||||
/**
|
||||
* Create a voucher from a Paddle transaction payload.
|
||||
* Create a voucher from a Lemon Squeezy order payload.
|
||||
*/
|
||||
public function issueFromPaddle(array $payload): GiftVoucher
|
||||
public function issueFromLemonSqueezy(array $payload): GiftVoucher
|
||||
{
|
||||
$metadata = $this->extractCustomData($payload);
|
||||
$priceId = $this->resolvePriceId($payload);
|
||||
$variantId = $this->resolveVariantId($payload);
|
||||
$amount = $this->resolveAmount($payload);
|
||||
$currency = Str::upper($this->resolveCurrency($payload));
|
||||
$locale = $metadata['app_locale'] ?? app()->getLocale();
|
||||
@@ -37,9 +36,10 @@ class GiftVoucherService
|
||||
|
||||
$expiresAt = now()->addYears((int) config('gift-vouchers.default_valid_years', 5));
|
||||
|
||||
if (! empty($payload['id'])) {
|
||||
$orderId = data_get($payload, 'data.id');
|
||||
if ($orderId) {
|
||||
$existing = GiftVoucher::query()
|
||||
->where('paddle_transaction_id', $payload['id'])
|
||||
->where('lemonsqueezy_order_id', $orderId)
|
||||
->first();
|
||||
}
|
||||
|
||||
@@ -47,19 +47,19 @@ class GiftVoucherService
|
||||
|
||||
$voucher = GiftVoucher::query()->updateOrCreate(
|
||||
[
|
||||
'paddle_transaction_id' => $payload['id'] ?? null,
|
||||
'lemonsqueezy_order_id' => $orderId,
|
||||
],
|
||||
[
|
||||
'code' => $metadata['gift_code'] ?? $this->generateCode(),
|
||||
'amount' => $amount,
|
||||
'currency' => $currency,
|
||||
'status' => GiftVoucher::STATUS_ISSUED,
|
||||
'purchaser_email' => $metadata['purchaser_email'] ?? Arr::get($payload, 'customer.email'),
|
||||
'purchaser_email' => $metadata['purchaser_email'] ?? data_get($payload, 'data.attributes.user_email'),
|
||||
'recipient_email' => $metadata['recipient_email'] ?? null,
|
||||
'recipient_name' => $metadata['recipient_name'] ?? null,
|
||||
'message' => $metadata['message'] ?? null,
|
||||
'paddle_checkout_id' => $payload['checkout_id'] ?? Arr::get($payload, 'details.checkout_id'),
|
||||
'paddle_price_id' => $priceId,
|
||||
'lemonsqueezy_checkout_id' => data_get($payload, 'data.attributes.checkout_id'),
|
||||
'lemonsqueezy_variant_id' => $variantId,
|
||||
'metadata' => $mergedMetadata,
|
||||
'expires_at' => $expiresAt,
|
||||
'refunded_at' => null,
|
||||
@@ -70,7 +70,6 @@ class GiftVoucherService
|
||||
if (! $voucher->coupon_id) {
|
||||
$coupon = $this->createCouponForVoucher($voucher);
|
||||
$voucher->forceFill(['coupon_id' => $coupon->id])->save();
|
||||
SyncCouponToPaddle::dispatch($coupon);
|
||||
}
|
||||
|
||||
$notificationsSent = (bool) Arr::get($voucher->metadata ?? [], 'notifications_sent', false);
|
||||
@@ -128,13 +127,13 @@ class GiftVoucherService
|
||||
]);
|
||||
}
|
||||
|
||||
if (! $voucher->paddle_transaction_id) {
|
||||
if (! $voucher->lemonsqueezy_order_id) {
|
||||
throw ValidationException::withMessages([
|
||||
'voucher' => __('Missing Paddle transaction for refund.'),
|
||||
'voucher' => __('Missing Lemon Squeezy order for refund.'),
|
||||
]);
|
||||
}
|
||||
|
||||
$response = $this->transactions->refund($voucher->paddle_transaction_id, array_filter([
|
||||
$response = $this->orders->refund($voucher->lemonsqueezy_order_id, array_filter([
|
||||
'reason' => $reason,
|
||||
]));
|
||||
|
||||
@@ -172,6 +171,7 @@ class GiftVoucherService
|
||||
'description' => 'Geschenkgutschein '.number_format((float) $voucher->amount, 2).' '.$voucher->currency.' für Endkunden-Pakete.',
|
||||
'starts_at' => now(),
|
||||
'ends_at' => $voucher->expires_at,
|
||||
'lemonsqueezy_discount_id' => $voucher->code,
|
||||
]);
|
||||
|
||||
if ($packages->isNotEmpty()) {
|
||||
@@ -187,41 +187,32 @@ class GiftVoucherService
|
||||
|
||||
return Package::query()
|
||||
->whereIn('type', $types)
|
||||
->whereNotNull('paddle_price_id')
|
||||
->whereNotNull('lemonsqueezy_variant_id')
|
||||
->get(['id']);
|
||||
}
|
||||
|
||||
protected function resolvePriceId(array $payload): ?string
|
||||
protected function resolveVariantId(array $payload): ?string
|
||||
{
|
||||
$metadata = $this->extractCustomData($payload);
|
||||
|
||||
if (is_array($metadata) && ! empty($metadata['paddle_price_id'])) {
|
||||
return $metadata['paddle_price_id'];
|
||||
if (is_array($metadata) && ! empty($metadata['lemonsqueezy_variant_id'])) {
|
||||
return $metadata['lemonsqueezy_variant_id'];
|
||||
}
|
||||
|
||||
$items = Arr::get($payload, 'items', Arr::get($payload, 'details.items', []));
|
||||
if (is_array($items) && isset($items[0]['price_id'])) {
|
||||
return $items[0]['price_id'];
|
||||
}
|
||||
|
||||
return $payload['price_id'] ?? null;
|
||||
return data_get($payload, 'data.attributes.variant_id');
|
||||
}
|
||||
|
||||
protected function resolveAmount(array $payload): float
|
||||
{
|
||||
$tiers = Collection::make(config('gift-vouchers.tiers', []))
|
||||
->keyBy(fn ($tier) => $tier['paddle_price_id'] ?? null);
|
||||
->keyBy(fn ($tier) => $tier['lemonsqueezy_variant_id'] ?? null);
|
||||
|
||||
$priceId = $this->resolvePriceId($payload);
|
||||
if ($priceId && $tiers->has($priceId)) {
|
||||
return (float) $tiers->get($priceId)['amount'];
|
||||
$variantId = $this->resolveVariantId($payload);
|
||||
if ($variantId && $tiers->has($variantId)) {
|
||||
return (float) $tiers->get($variantId)['amount'];
|
||||
}
|
||||
|
||||
$amount = Arr::get($payload, 'totals.grand_total.amount')
|
||||
?? Arr::get($payload, 'totals.grand_total')
|
||||
?? Arr::get($payload, 'details.totals.grand_total.amount')
|
||||
?? Arr::get($payload, 'details.totals.grand_total')
|
||||
?? Arr::get($payload, 'amount');
|
||||
$amount = data_get($payload, 'data.attributes.total');
|
||||
|
||||
if (is_numeric($amount)) {
|
||||
$value = (float) $amount;
|
||||
@@ -236,10 +227,7 @@ class GiftVoucherService
|
||||
|
||||
protected function resolveCurrency(array $payload): string
|
||||
{
|
||||
return $payload['currency_code']
|
||||
?? Arr::get($payload, 'details.totals.currency_code')
|
||||
?? Arr::get($payload, 'currency')
|
||||
?? 'EUR';
|
||||
return (string) (data_get($payload, 'data.attributes.currency') ?? 'EUR');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,8 +238,16 @@ class GiftVoucherService
|
||||
{
|
||||
$customData = [];
|
||||
|
||||
if (isset($payload['meta']['custom_data']) && is_array($payload['meta']['custom_data'])) {
|
||||
$customData = $payload['meta']['custom_data'];
|
||||
}
|
||||
|
||||
if (isset($payload['attributes']['custom_data']) && is_array($payload['attributes']['custom_data'])) {
|
||||
$customData = array_merge($customData, $payload['attributes']['custom_data']);
|
||||
}
|
||||
|
||||
if (isset($payload['custom_data']) && is_array($payload['custom_data'])) {
|
||||
$customData = $payload['custom_data'];
|
||||
$customData = array_merge($customData, $payload['custom_data']);
|
||||
}
|
||||
|
||||
if (isset($payload['customData']) && is_array($payload['customData'])) {
|
||||
|
||||
Reference in New Issue
Block a user