Hintergründe zum EventInvitePage Layout Customizer hinzugefügt. Badge und CTA entfernt, Textfelder zu Textareas gemacht. Geschenkgutscheine verbessert, E-Mail-Versand ergänzt + Resend + Confirmationseite mit Code-Copy und Link zur Package-Seite, die den Code als URL-Parameter enthält.
This commit is contained in:
@@ -5,6 +5,8 @@ namespace App\Services\GiftVouchers;
|
||||
use App\Enums\CouponStatus;
|
||||
use App\Enums\CouponType;
|
||||
use App\Jobs\SyncCouponToPaddle;
|
||||
use App\Mail\GiftVoucherIssued;
|
||||
use App\Jobs\NotifyGiftVoucherReminder;
|
||||
use App\Models\Coupon;
|
||||
use App\Models\GiftVoucher;
|
||||
use App\Models\Package;
|
||||
@@ -12,8 +14,10 @@ use App\Services\Paddle\PaddleTransactionService;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Carbon\Carbon;
|
||||
|
||||
class GiftVoucherService
|
||||
{
|
||||
@@ -28,9 +32,19 @@ class GiftVoucherService
|
||||
$priceId = $this->resolvePriceId($payload);
|
||||
$amount = $this->resolveAmount($payload);
|
||||
$currency = Str::upper($this->resolveCurrency($payload));
|
||||
$locale = $metadata['app_locale'] ?? app()->getLocale();
|
||||
$existing = null;
|
||||
|
||||
$expiresAt = now()->addYears((int) config('gift-vouchers.default_valid_years', 5));
|
||||
|
||||
if (! empty($payload['id'])) {
|
||||
$existing = GiftVoucher::query()
|
||||
->where('paddle_transaction_id', $payload['id'])
|
||||
->first();
|
||||
}
|
||||
|
||||
$mergedMetadata = array_merge($existing?->metadata ?? [], $metadata);
|
||||
|
||||
$voucher = GiftVoucher::query()->updateOrCreate(
|
||||
[
|
||||
'paddle_transaction_id' => $payload['id'] ?? null,
|
||||
@@ -46,7 +60,7 @@ class GiftVoucherService
|
||||
'message' => $metadata['message'] ?? null,
|
||||
'paddle_checkout_id' => $payload['checkout_id'] ?? Arr::get($payload, 'details.checkout_id'),
|
||||
'paddle_price_id' => $priceId,
|
||||
'metadata' => $metadata,
|
||||
'metadata' => $mergedMetadata,
|
||||
'expires_at' => $expiresAt,
|
||||
'refunded_at' => null,
|
||||
'redeemed_at' => null,
|
||||
@@ -59,9 +73,29 @@ class GiftVoucherService
|
||||
SyncCouponToPaddle::dispatch($coupon);
|
||||
}
|
||||
|
||||
$notificationsSent = (bool) Arr::get($voucher->metadata ?? [], 'notifications_sent', false);
|
||||
|
||||
if (! $notificationsSent) {
|
||||
$this->sendNotifications($voucher, locale: $locale);
|
||||
}
|
||||
|
||||
return $voucher;
|
||||
}
|
||||
|
||||
public function resend(GiftVoucher $voucher, ?string $locale = null, ?bool $recipientOnly = null): void
|
||||
{
|
||||
$this->sendNotifications($voucher, force: true, locale: $locale, recipientOnly: $recipientOnly);
|
||||
}
|
||||
|
||||
public function scheduleRecipientDelivery(GiftVoucher $voucher, Carbon $when, ?string $locale = null): void
|
||||
{
|
||||
$voucher->forceFill([
|
||||
'recipient_delivery_scheduled_at' => $when,
|
||||
])->save();
|
||||
|
||||
$this->sendNotifications($voucher, force: true, when: $when, locale: $locale, recipientOnly: true);
|
||||
}
|
||||
|
||||
public function markRedeemed(?Coupon $coupon, ?string $transactionId = null): void
|
||||
{
|
||||
if (! $coupon?->giftVoucher) {
|
||||
@@ -212,4 +246,65 @@ class GiftVoucherService
|
||||
{
|
||||
return 'GIFT-'.Str::upper(Str::random(8));
|
||||
}
|
||||
|
||||
protected function sendNotifications(
|
||||
GiftVoucher $voucher,
|
||||
bool $force = false,
|
||||
?Carbon $when = null,
|
||||
?string $locale = null,
|
||||
?bool $recipientOnly = null
|
||||
): void {
|
||||
$alreadySent = (bool) Arr::get($voucher->metadata ?? [], 'notifications_sent', false);
|
||||
|
||||
if ($alreadySent && ! $force) {
|
||||
return;
|
||||
}
|
||||
|
||||
$purchaserMail = $voucher->purchaser_email ? Mail::to($voucher->purchaser_email) : null;
|
||||
$recipientMail = $voucher->recipient_email && $voucher->recipient_email !== $voucher->purchaser_email
|
||||
? Mail::to($voucher->recipient_email)
|
||||
: null;
|
||||
|
||||
if (! $recipientOnly && $purchaserMail) {
|
||||
$mailable = (new GiftVoucherIssued($voucher, false))->locale($locale);
|
||||
$when ? $purchaserMail->later($when, $mailable) : $purchaserMail->queue($mailable);
|
||||
}
|
||||
|
||||
if ($recipientMail) {
|
||||
$mailable = (new GiftVoucherIssued($voucher, true))->locale($locale);
|
||||
$when ? $recipientMail->later($when, $mailable) : $recipientMail->queue($mailable);
|
||||
}
|
||||
|
||||
$metadata = $voucher->metadata ?? [];
|
||||
if (! $recipientOnly) {
|
||||
$metadata['notifications_sent'] = true;
|
||||
}
|
||||
$voucher->forceFill([
|
||||
'metadata' => $metadata,
|
||||
'recipient_delivery_sent_at' => $when ? $voucher->recipient_delivery_sent_at : ($recipientMail ? now() : $voucher->recipient_delivery_sent_at),
|
||||
])->save();
|
||||
|
||||
$this->scheduleReminders($voucher);
|
||||
}
|
||||
|
||||
protected function scheduleReminders(GiftVoucher $voucher): void
|
||||
{
|
||||
if ($voucher->isRedeemed() || $voucher->isRefunded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$reminderDays = (int) config('gift-vouchers.reminder_days', 7);
|
||||
$expiryReminderDays = (int) config('gift-vouchers.expiry_reminder_days', 14);
|
||||
|
||||
if ($reminderDays > 0) {
|
||||
NotifyGiftVoucherReminder::dispatch($voucher)->delay(now()->addDays($reminderDays));
|
||||
}
|
||||
|
||||
if ($voucher->expires_at && $expiryReminderDays > 0) {
|
||||
$when = $voucher->expires_at->copy()->subDays($expiryReminderDays);
|
||||
if ($when->isFuture()) {
|
||||
NotifyGiftVoucherReminder::dispatch($voucher, true)->delay($when);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user