136 lines
4.7 KiB
PHP
136 lines
4.7 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\PackagePurchase;
|
|
use App\Models\EventPackage;
|
|
use App\Models\TenantPackage;
|
|
use Illuminate\Http\Request;
|
|
use Stripe\Webhook;
|
|
use Illuminate\Support\Facades\Log;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
use Stripe\Exception\SignatureVerificationException;
|
|
|
|
class StripeWebhookController extends Controller
|
|
{
|
|
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 response()->json(['error' => 'Invalid signature'], 400);
|
|
} catch (\UnexpectedValueException $e) {
|
|
return response()->json(['error' => 'Invalid payload'], 400);
|
|
}
|
|
|
|
// Handle the event
|
|
switch ($event['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' => $event['type']]);
|
|
}
|
|
|
|
return response()->json(['status' => 'success'], 200);
|
|
}
|
|
|
|
private function handlePaymentIntentSucceeded(array $paymentIntent)
|
|
{
|
|
$metadata = $paymentIntent['metadata'];
|
|
$packageId = $metadata['package_id'];
|
|
$type = $metadata['type'];
|
|
|
|
\DB::transaction(function () use ($paymentIntent, $metadata, $packageId, $type) {
|
|
// Create purchase record
|
|
$purchase = PackagePurchase::create([
|
|
'package_id' => $packageId,
|
|
'type' => $type,
|
|
'provider_id' => 'stripe',
|
|
'transaction_id' => $paymentIntent['id'],
|
|
'purchased_price' => $paymentIntent['amount_received'] / 100,
|
|
'metadata' => $metadata,
|
|
]);
|
|
|
|
if ($type === 'endcustomer_event') {
|
|
$eventId = $metadata['event_id'];
|
|
EventPackage::create([
|
|
'event_id' => $eventId,
|
|
'package_id' => $packageId,
|
|
'package_purchase_id' => $purchase->id,
|
|
'used_photos' => 0,
|
|
'used_guests' => 0,
|
|
'expires_at' => now()->addDays(30), // Default, or from package
|
|
]);
|
|
} elseif ($type === 'reseller_subscription') {
|
|
$tenantId = $metadata['tenant_id'];
|
|
TenantPackage::create([
|
|
'tenant_id' => $tenantId,
|
|
'package_id' => $packageId,
|
|
'package_purchase_id' => $purchase->id,
|
|
'used_events' => 0,
|
|
'active' => true,
|
|
'expires_at' => now()->addYear(),
|
|
]);
|
|
}
|
|
});
|
|
}
|
|
|
|
private function handleInvoicePaid(array $invoice)
|
|
{
|
|
$subscription = $invoice['subscription'];
|
|
$metadata = $subscription['metadata'] ?? [];
|
|
|
|
if (isset($metadata['tenant_id'])) {
|
|
$tenantId = $metadata['tenant_id'];
|
|
$packageId = $metadata['package_id'];
|
|
|
|
// Renew or create tenant package
|
|
$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(),
|
|
]);
|
|
}
|
|
|
|
// Create purchase record
|
|
PackagePurchase::create([
|
|
'package_id' => $packageId,
|
|
'type' => 'reseller_subscription',
|
|
'provider_id' => 'stripe',
|
|
'transaction_id' => $invoice['id'],
|
|
'purchased_price' => $invoice['amount_paid'] / 100,
|
|
'metadata' => $metadata,
|
|
]);
|
|
}
|
|
}
|
|
} |