91 lines
3.2 KiB
PHP
91 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers;
|
|
|
|
use App\Models\EventPurchase;
|
|
use App\Models\Tenant;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\Log;
|
|
|
|
class StripeWebhookController extends Controller
|
|
{
|
|
public function handle(Request $request)
|
|
{
|
|
$payload = $request->getContent();
|
|
$sig = $request->header('Stripe-Signature');
|
|
$secret = config('services.stripe.webhook');
|
|
|
|
if (!$secret || !$sig) {
|
|
abort(400, 'Missing signature');
|
|
}
|
|
|
|
$expectedSig = 'v1=' . hash_hmac('sha256', $payload, $secret);
|
|
|
|
if (!hash_equals($expectedSig, $sig)) {
|
|
abort(400, 'Invalid signature');
|
|
}
|
|
|
|
$event = json_decode($payload, true);
|
|
|
|
if (json_last_error() !== JSON_ERROR_NONE) {
|
|
Log::error('Invalid JSON in Stripe webhook: ' . json_last_error_msg());
|
|
return response('', 200);
|
|
}
|
|
|
|
if ($event['type'] === 'checkout.session.completed') {
|
|
$session = $event['data']['object'];
|
|
$receiptId = $session['id'];
|
|
|
|
// Idempotency check
|
|
if (EventPurchase::where('external_receipt_id', $receiptId)->exists()) {
|
|
return response('', 200);
|
|
}
|
|
|
|
$tenantId = $session['metadata']['tenant_id'] ?? null;
|
|
|
|
if (!$tenantId) {
|
|
Log::warning('No tenant_id in Stripe metadata', ['receipt_id' => $receiptId]);
|
|
// Dispatch job for retry or manual resolution
|
|
\App\Jobs\ValidateStripeWebhookJob::dispatch($payload, $sig);
|
|
return response('', 200);
|
|
}
|
|
|
|
$tenant = Tenant::find($tenantId);
|
|
|
|
if (!$tenant) {
|
|
Log::error('Tenant not found for Stripe webhook', ['tenant_id' => $tenantId]);
|
|
\App\Jobs\ValidateStripeWebhookJob::dispatch($payload, $sig);
|
|
return response('', 200);
|
|
}
|
|
|
|
$amount = $session['amount_total'] / 100;
|
|
$currency = $session['currency'];
|
|
$eventsPurchased = (int) ($session['metadata']['events_purchased'] ?? 1);
|
|
|
|
DB::transaction(function () use ($tenant, $amount, $currency, $eventsPurchased, $receiptId) {
|
|
$purchase = EventPurchase::create([
|
|
'tenant_id' => $tenant->id,
|
|
'events_purchased' => $eventsPurchased,
|
|
'amount' => $amount,
|
|
'currency' => $currency,
|
|
'provider' => 'stripe',
|
|
'external_receipt_id' => $receiptId,
|
|
'status' => 'completed',
|
|
'purchased_at' => now(),
|
|
]);
|
|
|
|
$tenant->incrementCredits($eventsPurchased, 'purchase', null, $purchase->id);
|
|
});
|
|
|
|
Log::info('Processed Stripe purchase', ['receipt_id' => $receiptId, 'tenant_id' => $tenantId]);
|
|
} else {
|
|
// For other event types, log or dispatch job if needed
|
|
Log::info('Unhandled Stripe event', ['type' => $event['type']]);
|
|
// Optionally dispatch job for processing other events
|
|
\App\Jobs\ValidateStripeWebhookJob::dispatch($payload, $sig);
|
|
}
|
|
|
|
return response('', 200);
|
|
}
|
|
} |