feature: implement stripe webhook
This commit is contained in:
parent
a51a2cd436
commit
14cb5a36ae
27
backend/app/Actions/MarkPaymentAsPaidAction.php
Normal file
27
backend/app/Actions/MarkPaymentAsPaidAction.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Actions;
|
||||
|
||||
use App\Enums\PaymentStatusEnum;
|
||||
use App\Models\Payment;
|
||||
use App\Models\PaymentStatus;
|
||||
use Symfony\Component\Translation\Exception\NotFoundResourceException;
|
||||
|
||||
final readonly class MarkPaymentAsPaidAction
|
||||
{
|
||||
/**
|
||||
* Execute the action.
|
||||
*
|
||||
* @throws NotFoundResourceException
|
||||
*/
|
||||
public function execute(Payment $payment): bool
|
||||
{
|
||||
$status = PaymentStatus::whereName(PaymentStatusEnum::Paid->value)->value('id');
|
||||
if (! $status) {
|
||||
throw new NotFoundResourceException('Paid Status not found');
|
||||
}
|
||||
$payment->payment_status_id = $status;
|
||||
|
||||
return $payment->save();
|
||||
}
|
||||
}
|
||||
8
backend/app/Enums/StripeEventType.php
Normal file
8
backend/app/Enums/StripeEventType.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum StripeEventType: string
|
||||
{
|
||||
case CheckoutSessionCompleted = 'checkout.session.completed';
|
||||
}
|
||||
55
backend/app/Http/Controllers/StripeWebhookController.php
Normal file
55
backend/app/Http/Controllers/StripeWebhookController.php
Normal file
@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Actions\MarkPaymentAsPaidAction;
|
||||
use App\Enums\StripeEventType;
|
||||
use App\Models\Payment;
|
||||
use Illuminate\Http\Request;
|
||||
use Log;
|
||||
use Stripe\Exception\SignatureVerificationException;
|
||||
use Stripe\Webhook;
|
||||
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
class StripeWebhookController extends Controller
|
||||
{
|
||||
public function __construct(private readonly MarkPaymentAsPaidAction $paidAction)
|
||||
{
|
||||
}
|
||||
|
||||
public function __invoke(Request $request)
|
||||
{
|
||||
$payload = $request->getContent();
|
||||
$sigHeader = $request->header('Stripe-Signature');
|
||||
try {
|
||||
$event = Webhook::constructEvent($payload, $sigHeader, config('services.stripe.webhook'));
|
||||
} catch (SignatureVerificationException|UnexpectedValueException $e) {
|
||||
Log::error('Stripe webhook signature verification error.', [$e->getMessage()]);
|
||||
throw new BadRequestHttpException('Invalid Signature');
|
||||
}
|
||||
if ($event->type === StripeEventType::CheckoutSessionCompleted->value) {
|
||||
$sessionId = $event->data->object->id ?? null;
|
||||
if ($sessionId) {
|
||||
$this->handleCheckoutSessionCompleted($sessionId);
|
||||
} else {
|
||||
throw new NotFoundHttpException('Session id not found in event');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function handleCheckoutSessionCompleted(string $sessionId): void
|
||||
{
|
||||
$payment = Payment::where('transaction_id', $sessionId)->first();
|
||||
|
||||
if (! $payment) {
|
||||
Log::error('Stripe Webhook: Payment record not found.', ['session_id' => $sessionId]);
|
||||
throw new NotFoundHttpException('Payment record not found');
|
||||
}
|
||||
|
||||
$this->paidAction->execute($payment);
|
||||
|
||||
Log::info('Stripe Webhook: Payment successfully marked as paid', ['order_id' => $payment->order_id]);
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@
|
||||
use App\Http\Controllers\ProductController;
|
||||
use App\Http\Controllers\ProductImagesController;
|
||||
use App\Http\Controllers\RegisteredUserController;
|
||||
use App\Http\Controllers\StripeWebhookController;
|
||||
use App\Http\Controllers\UserAddressController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
@ -34,3 +35,5 @@
|
||||
});
|
||||
Route::get('/categories', [ProductCategoryController::class, 'index']);
|
||||
Route::apiResource('products', ProductController::class);
|
||||
|
||||
Route::post('/webhook/stripe', StripeWebhookController::class);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user