diff --git a/backend/app/Actions/MarkPaymentAsPaidAction.php b/backend/app/Actions/MarkPaymentAsPaidAction.php new file mode 100644 index 0000000..e9b9898 --- /dev/null +++ b/backend/app/Actions/MarkPaymentAsPaidAction.php @@ -0,0 +1,27 @@ +value)->value('id'); + if (! $status) { + throw new NotFoundResourceException('Paid Status not found'); + } + $payment->payment_status_id = $status; + + return $payment->save(); + } +} diff --git a/backend/app/Enums/StripeEventType.php b/backend/app/Enums/StripeEventType.php new file mode 100644 index 0000000..0433d93 --- /dev/null +++ b/backend/app/Enums/StripeEventType.php @@ -0,0 +1,8 @@ +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]); + } +} diff --git a/backend/routes/api.php b/backend/routes/api.php index 139acd8..dbfb7fb 100644 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -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);