Files
fotospiel-app/app/Http/Controllers/Api/StripeWebhookController.php
Codex Agent 79b209de9a Limit-Status im Upload-Flow anzeigen (Warnbanner + Sperrzustände).
Upload-Fehlercodes auswerten und freundliche Dialoge zeigen.
2025-11-01 19:50:17 +01:00

190 lines
6.2 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\EventPackage;
use App\Models\PackagePurchase;
use App\Models\TenantPackage;
use App\Models\User;
use App\Services\Checkout\CheckoutWebhookService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Stripe\Exception\SignatureVerificationException;
use Stripe\Webhook;
class StripeWebhookController extends Controller
{
public function __construct(private CheckoutWebhookService $checkoutWebhooks) {}
public function handleWebhook(Request $request)
{
$payload = $request->getContent();
$sigHeader = $request->header('Stripe-Signature');
$endpointSecret = config('services.stripe.webhook_secret');
try {
$event = Webhook::constructEvent(
$payload,
$sigHeader,
$endpointSecret
);
} catch (SignatureVerificationException $e) {
return ApiError::response(
'stripe_invalid_signature',
'Ungültige Signatur',
'Die Signatur der Stripe-Anfrage ist ungültig.',
400
);
} catch (\UnexpectedValueException $e) {
return ApiError::response(
'stripe_invalid_payload',
'Ungültige Daten',
'Der Stripe Payload konnte nicht gelesen werden.',
400
);
}
$eventArray = method_exists($event, 'toArray') ? $event->toArray() : (array) $event;
if ($this->checkoutWebhooks->handleStripeEvent($eventArray)) {
return response()->json(['status' => 'success'], 200);
}
// Legacy handlers for legacy marketing checkout
return $this->handleLegacyEvent($eventArray);
}
private function handleLegacyEvent(array $event)
{
$type = $event['type'] ?? null;
switch ($type) {
case 'payment_intent.succeeded':
$paymentIntent = $event['data']['object'] ?? [];
$this->handlePaymentIntentSucceeded($paymentIntent);
break;
case 'invoice.paid':
$invoice = $event['data']['object'] ?? [];
$this->handleInvoicePaid($invoice);
break;
default:
Log::info('Unhandled Stripe event', ['type' => $type]);
}
return response()->json(['status' => 'success'], 200);
}
private function handlePaymentIntentSucceeded(array $paymentIntent): void
{
$metadata = $paymentIntent['metadata'] ?? [];
$packageId = $metadata['package_id'] ?? null;
$type = $metadata['type'] ?? null;
if (! $packageId || ! $type) {
Log::warning('Stripe intent missing metadata payload', ['metadata' => $metadata]);
return;
}
DB::transaction(function () use ($paymentIntent, $metadata, $packageId, $type) {
$purchase = PackagePurchase::create([
'package_id' => $packageId,
'type' => $type,
'provider_id' => 'stripe',
'transaction_id' => $paymentIntent['id'] ?? null,
'price' => isset($paymentIntent['amount_received'])
? $paymentIntent['amount_received'] / 100
: 0,
'metadata' => $metadata,
]);
if ($type === 'endcustomer_event') {
$eventId = $metadata['event_id'] ?? null;
if (! $eventId) {
return;
}
EventPackage::create([
'event_id' => $eventId,
'package_id' => $packageId,
'package_purchase_id' => $purchase->id,
'used_photos' => 0,
'used_guests' => 0,
'expires_at' => now()->addDays(30),
]);
} elseif ($type === 'reseller_subscription') {
$tenantId = $metadata['tenant_id'] ?? null;
if (! $tenantId) {
return;
}
TenantPackage::create([
'tenant_id' => $tenantId,
'package_id' => $packageId,
'package_purchase_id' => $purchase->id,
'used_events' => 0,
'active' => true,
'expires_at' => now()->addYear(),
]);
$user = User::find($metadata['user_id'] ?? null);
if ($user) {
$user->update(['role' => 'tenant_admin']);
}
}
});
}
private function handleInvoicePaid(array $invoice): void
{
$subscription = $invoice['subscription'] ?? null;
$metadata = $subscription['metadata'] ?? [];
if (! isset($metadata['tenant_id'], $metadata['package_id'])) {
return;
}
$tenantId = $metadata['tenant_id'];
$packageId = $metadata['package_id'];
$tenantPackage = TenantPackage::where('tenant_id', $tenantId)
->where('package_id', $packageId)
->where('stripe_subscription_id', $subscription)
->first();
if ($tenantPackage) {
$tenantPackage->update([
'active' => true,
'expires_at' => now()->addYear(),
]);
} else {
TenantPackage::create([
'tenant_id' => $tenantId,
'package_id' => $packageId,
'stripe_subscription_id' => $subscription,
'used_events' => 0,
'active' => true,
'expires_at' => now()->addYear(),
]);
$user = User::find($metadata['user_id'] ?? null);
if ($user) {
$user->update(['role' => 'tenant_admin']);
}
}
PackagePurchase::create([
'package_id' => $packageId,
'type' => 'reseller_subscription',
'provider_id' => 'stripe',
'transaction_id' => $invoice['id'] ?? null,
'price' => isset($invoice['amount_paid']) ? $invoice['amount_paid'] / 100 : 0,
'metadata' => $metadata,
]);
}
}