Checkout‑Registrierung validiert jetzt die E‑Mail‑Länge, und die Checkout‑Flows sind Paddle‑only: Stripe‑Endpoints/
Services/Helpers sind entfernt, API/Frontend angepasst, Tests auf Paddle umgestellt. Außerdem wurde die CSP gestrafft und Stripe‑Texte in den Abandoned‑Checkout‑Mails ersetzt.
This commit is contained in:
@@ -25,63 +25,6 @@ class CheckoutWebhookService
|
||||
private readonly GiftVoucherService $giftVouchers,
|
||||
) {}
|
||||
|
||||
public function handleStripeEvent(array $event): bool
|
||||
{
|
||||
$eventType = $event['type'] ?? null;
|
||||
$intent = $event['data']['object'] ?? null;
|
||||
|
||||
if (! $eventType || ! is_array($intent)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! str_starts_with($eventType, 'payment_intent.')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$intentId = $intent['id'] ?? null;
|
||||
|
||||
if (! $intentId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$session = $this->locateStripeSession($intent);
|
||||
|
||||
if (! $session) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$lock = Cache::lock("checkout:webhook:stripe:{$intentId}", 30);
|
||||
|
||||
if (! $lock->get()) {
|
||||
Log::info('[CheckoutWebhook] Stripe intent lock busy', [
|
||||
'intent_id' => $intentId,
|
||||
'session_id' => $session->id,
|
||||
]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
$session->forceFill([
|
||||
'stripe_payment_intent_id' => $session->stripe_payment_intent_id ?: $intentId,
|
||||
'provider' => CheckoutSession::PROVIDER_STRIPE,
|
||||
])->save();
|
||||
|
||||
$metadata = [
|
||||
'stripe_last_event' => $eventType,
|
||||
'stripe_last_event_id' => $event['id'] ?? null,
|
||||
'stripe_intent_status' => $intent['status'] ?? null,
|
||||
'stripe_last_update_at' => now()->toIso8601String(),
|
||||
];
|
||||
|
||||
$this->mergeProviderMetadata($session, $metadata);
|
||||
|
||||
return $this->applyStripeIntent($session, $eventType, $intent);
|
||||
} finally {
|
||||
$lock->release();
|
||||
}
|
||||
}
|
||||
|
||||
public function handlePaddleEvent(array $event): bool
|
||||
{
|
||||
$eventType = $event['event_type'] ?? null;
|
||||
@@ -158,51 +101,6 @@ class CheckoutWebhookService
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyStripeIntent(CheckoutSession $session, string $eventType, array $intent): bool
|
||||
{
|
||||
switch ($eventType) {
|
||||
case 'payment_intent.processing':
|
||||
case 'payment_intent.amount_capturable_updated':
|
||||
$this->sessions->markProcessing($session, [
|
||||
'stripe_intent_status' => $intent['status'] ?? null,
|
||||
]);
|
||||
|
||||
return true;
|
||||
|
||||
case 'payment_intent.requires_action':
|
||||
$reason = $intent['next_action']['type'] ?? 'requires_action';
|
||||
$this->sessions->markRequiresCustomerAction($session, $reason);
|
||||
|
||||
return true;
|
||||
|
||||
case 'payment_intent.payment_failed':
|
||||
$failure = $intent['last_payment_error']['message'] ?? 'payment_failed';
|
||||
$this->sessions->markFailed($session, $failure);
|
||||
|
||||
return true;
|
||||
|
||||
case 'payment_intent.succeeded':
|
||||
if ($session->status !== CheckoutSession::STATUS_COMPLETED) {
|
||||
$this->sessions->markProcessing($session, [
|
||||
'stripe_intent_status' => $intent['status'] ?? null,
|
||||
]);
|
||||
|
||||
$this->assignment->finalise($session, [
|
||||
'source' => 'stripe_webhook',
|
||||
'stripe_payment_intent_id' => $intent['id'] ?? null,
|
||||
'stripe_charge_id' => $this->extractStripeChargeId($intent),
|
||||
]);
|
||||
|
||||
$this->sessions->markCompleted($session, now());
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyPaddleEvent(CheckoutSession $session, string $eventType, array $data): bool
|
||||
{
|
||||
$status = strtolower((string) ($data['status'] ?? ''));
|
||||
@@ -417,30 +315,6 @@ class CheckoutWebhookService
|
||||
$session->save();
|
||||
}
|
||||
|
||||
protected function locateStripeSession(array $intent): ?CheckoutSession
|
||||
{
|
||||
$intentId = $intent['id'] ?? null;
|
||||
|
||||
if ($intentId) {
|
||||
$session = CheckoutSession::query()
|
||||
->where('stripe_payment_intent_id', $intentId)
|
||||
->first();
|
||||
|
||||
if ($session) {
|
||||
return $session;
|
||||
}
|
||||
}
|
||||
|
||||
$metadata = $intent['metadata'] ?? [];
|
||||
$sessionId = $metadata['checkout_session_id'] ?? null;
|
||||
|
||||
if ($sessionId) {
|
||||
return CheckoutSession::find($sessionId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function isGiftVoucherEvent(array $data): bool
|
||||
{
|
||||
$metadata = $data['metadata'] ?? [];
|
||||
@@ -498,14 +372,4 @@ class CheckoutWebhookService
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function extractStripeChargeId(array $intent): ?string
|
||||
{
|
||||
$charges = $intent['charges']['data'] ?? null;
|
||||
if (is_array($charges) && count($charges) > 0) {
|
||||
return $charges[0]['id'] ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user