Files
fotospiel-app/app/Http/Controllers/StripeWebhookController.php

247 lines
8.4 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\PackagePurchase;
use App\Models\TenantPackage;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Stripe\Stripe;
use Stripe\Webhook;
class StripeWebhookController extends Controller
{
public function __construct()
{
Stripe::setApiKey(config('services.stripe.secret'));
}
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 (\Exception $e) {
Log::error('Stripe webhook signature verification failed: ' . $e->getMessage());
return response()->json(['error' => 'Invalid signature'], 400);
}
switch ($event['type']) {
case 'checkout.session.completed':
$session = $event['data']['object'];
if ($session['mode'] === 'subscription' && isset($session['metadata']['subscription']) && $session['metadata']['subscription'] === 'true') {
$this->handleSubscriptionStarted($session);
}
break;
case 'payment_intent.succeeded':
$paymentIntent = $event['data']['object'];
$this->handlePaymentIntentSucceeded($paymentIntent);
break;
case 'invoice.payment_succeeded':
$invoice = $event['data']['object'];
$this->handleInvoicePaymentSucceeded($invoice);
break;
case 'invoice.payment_failed':
$invoice = $event['data']['object'];
$this->handleInvoicePaymentFailed($invoice);
break;
default:
Log::info('Unhandled Stripe event type: ' . $event['type']);
}
return response()->json(['status' => 'success']);
}
private function handlePaymentIntentSucceeded($paymentIntent)
{
$metadata = $paymentIntent['metadata'];
if (!$metadata['user_id'] && !$metadata['tenant_id'] || !$metadata['package_id']) {
Log::warning('Missing metadata in Stripe payment intent: ' . $paymentIntent['id']);
return;
}
$userId = $metadata['user_id'] ?? null;
$tenantId = $metadata['tenant_id'] ?? null;
$packageId = $metadata['package_id'];
$type = $metadata['type'] ?? 'endcustomer_event';
if ($userId && !$tenantId) {
$tenant = \App\Models\Tenant::where('user_id', $userId)->first();
if ($tenant) {
$tenantId = $tenant->id;
} else {
Log::error('Tenant not found for user_id: ' . $userId);
return;
}
}
if (!$tenantId) {
Log::error('No tenant_id found for Stripe payment intent: ' . $paymentIntent['id']);
return;
}
// Create PackagePurchase for one-off payment
\App\Models\PackagePurchase::create([
'tenant_id' => $tenantId,
'package_id' => $packageId,
'provider_id' => $paymentIntent['id'],
'price' => $paymentIntent['amount_received'] / 100,
'type' => $type,
'purchased_at' => now(),
'refunded' => false,
]);
if ($type === 'endcustomer_event') {
// For event packages, assume event_id from metadata or handle separately
// TODO: Link to specific event if provided
}
Log::info('Package purchase created via Stripe payment intent: ' . $paymentIntent['id'] . ' for tenant ' . $tenantId);
}
private function handleInvoicePaymentSucceeded($invoice)
{
$subscription = $invoice['subscription'];
$metadata = $invoice['metadata'];
if (!$metadata['user_id'] && !$metadata['tenant_id'] || !$metadata['package_id']) {
Log::warning('Missing metadata in Stripe invoice: ' . $invoice['id']);
return;
}
$userId = $metadata['user_id'] ?? null;
$tenantId = $metadata['tenant_id'] ?? null;
$packageId = $metadata['package_id'];
if ($userId && !$tenantId) {
$tenant = \App\Models\Tenant::where('user_id', $userId)->first();
if ($tenant) {
$tenantId = $tenant->id;
} else {
Log::error('Tenant not found for user_id: ' . $userId);
return;
}
}
if (!$tenantId) {
Log::error('No tenant_id found for Stripe invoice: ' . $invoice['id']);
return;
}
// Update or create TenantPackage for subscription
\App\Models\TenantPackage::updateOrCreate(
[
'tenant_id' => $tenantId,
'package_id' => $packageId,
],
[
'purchased_at' => now(),
'expires_at' => now()->addYear(), // Renew annually
'active' => true,
]
);
// Create or update PackagePurchase
\App\Models\PackagePurchase::updateOrCreate(
[
'tenant_id' => $tenantId,
'package_id' => $packageId,
'provider_id' => $subscription,
],
[
'price' => $invoice['amount_paid'] / 100,
'type' => 'reseller_subscription',
'purchased_at' => now(),
'refunded' => false,
]
);
Log::info('Subscription renewed via Stripe invoice: ' . $invoice['id'] . ' for tenant ' . $tenantId);
}
private function handleInvoicePaymentFailed($invoice)
{
$subscription = $invoice['subscription'];
Log::warning('Stripe invoice payment failed: ' . $invoice['id'] . ' for subscription ' . $subscription);
// TODO: Deactivate package or notify tenant
// e.g., TenantPackage::where('provider_id', $subscription)->update(['active' => false]);
}
private function handleSubscriptionStarted($session)
{
$metadata = $session['metadata'];
if (!$metadata['user_id'] && !$metadata['tenant_id'] || !$metadata['package_id']) {
Log::warning('Missing metadata in Stripe checkout session: ' . $session['id']);
return;
}
$userId = $metadata['user_id'] ?? null;
$tenantId = $metadata['tenant_id'] ?? null;
$packageId = $metadata['package_id'];
$type = $metadata['type'] ?? 'reseller_subscription';
if ($userId && !$tenantId) {
$tenant = \App\Models\Tenant::where('user_id', $userId)->first();
if ($tenant) {
$tenantId = $tenant->id;
} else {
Log::error('Tenant not found for user_id: ' . $userId);
return;
}
}
if (!$tenantId) {
Log::error('No tenant_id found for Stripe checkout session: ' . $session['id']);
return;
}
$subscriptionId = $session['subscription']['id'] ?? null;
if (!$subscriptionId) {
Log::error('No subscription ID in checkout session: ' . $session['id']);
return;
}
// Activate TenantPackage for initial subscription
\App\Models\TenantPackage::updateOrCreate(
[
'tenant_id' => $tenantId,
'package_id' => $packageId,
],
[
'purchased_at' => now(),
'expires_at' => now()->addYear(),
'active' => true,
]
);
// Create initial PackagePurchase
\App\Models\PackagePurchase::create([
'tenant_id' => $tenantId,
'package_id' => $packageId,
'provider_id' => $subscriptionId,
'price' => $session['amount_total'] / 100,
'type' => $type,
'purchased_at' => now(),
'refunded' => false,
]);
// Update tenant subscription fields if needed
$tenant = \App\Models\Tenant::find($tenantId);
if ($tenant) {
$tenant->update([
'subscription_id' => $subscriptionId,
'subscription_status' => 'active',
]);
}
Log::info('Initial subscription activated via Stripe checkout session: ' . $session['id'] . ' for tenant ' . $tenantId);
}
}