Forráskód Böngészése

feat: ✨ Added StripeWebhook Route

IceToast 3 éve
szülő
commit
16f7f4cb99

+ 4 - 0
.env.example

@@ -27,6 +27,10 @@ PAYPAL_EMAIL=
 #stripe details, you only need "test" for testing! you can do this by setting the APP_ENV to local
 STRIPE_TEST_SECRET=
 STRIPE_SECRET=
+#https://dashboard.stripe.com/webhooks
+STRIPE_ENDPOINT_TEST_SECRET=
+STRIPE_ENDPOINT_SECRET=
+
 #stripe payment methods, comma seperated list of methods you want to support:
 #read into https://stripe.com/docs/payments/payment-methods/integration-options and/or https://stripe.com/docs/payments/payment-methods/overview
 STRIPE_METHODS=

+ 113 - 37
app/Http/Controllers/Admin/PaymentController.php

@@ -17,6 +17,7 @@ use Illuminate\Http\JsonResponse;
 use Illuminate\Http\RedirectResponse;
 use Illuminate\Http\Request;
 use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Log;
 use PayPalCheckoutSdk\Core\PayPalHttpClient;
 use PayPalCheckoutSdk\Core\ProductionEnvironment;
 use PayPalCheckoutSdk\Core\SandboxEnvironment;
@@ -285,48 +286,67 @@ class PaymentController extends Controller
         $stripeClient = $this->getStripeClient();
 
         try{
-        $paymentSession = $stripeClient->checkout->sessions->retrieve($request->input('session_id'));
-        $capturedPaymentIntent = $stripeClient->paymentIntents->capture($paymentSession->payment_intent);
-        if ($capturedPaymentIntent->status == "succeeded") {
+            //get stripe data
+            $paymentSession = $stripeClient->checkout->sessions->retrieve($request->input('session_id'));
+            $paymentIntent = $stripeClient->paymentIntents->retrieve($paymentSession->payment_intent);
 
-            //update credits
-            $user->increment('credits', $creditProduct->quantity);
+            //get DB entry of this payment ID if existing
+            $paymentDbEntry = Payment::where('payment_id', $paymentSession->payment_intent)->count();
 
-            //update server limit
-            if (Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) {
-                if ($user->server_limit < Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
-                    $user->update(['server_limit' => Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
+            // check if payment is 100% completed and payment does not exist in db already
+            if ($paymentSession->status == "complete" && $paymentIntent->status == "succeeded" && $paymentDbEntry == 0) {
+
+                //update credits
+                $user->increment('credits', $creditProduct->quantity);
+
+                //update server limit
+                if (Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE') !== 0) {
+                    if ($user->server_limit < Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE')) {
+                        $user->update(['server_limit' => Configuration::getValueByKey('SERVER_LIMIT_AFTER_IRL_PURCHASE')]);
+                    }
                 }
-            }
 
-            //update role
-            if ($user->role == 'member') {
-                $user->update(['role' => 'client']);
-            }
+                //update role
+                if ($user->role == 'member') {
+                    $user->update(['role' => 'client']);
+                }
 
-            //store payment
-            $payment = Payment::create([
-                'user_id' => $user->id,
-                'payment_id' => $capturedPaymentIntent->id,
-                'payment_method' => 'stripe',
-                'type' => 'Credits',
-                'status' => 'paid',
-                'amount' => $creditProduct->quantity,
-                'price' => $creditProduct->price,
-                'tax_value' => $creditProduct->getTaxValue(),
-                'total_price' => $creditProduct->getTotalPrice(),
-                'tax_percent' => $creditProduct->getTaxPercent(),
-                'currency_code' => $creditProduct->currency_code,
-            ]);
-
-            //payment notification
-            $user->notify(new ConfirmPaymentNotification($payment));
-
-            event(new UserUpdateCreditsEvent($user));
-
-            //redirect back to home
-            return redirect()->route('home')->with('success', __('Your credit balance has been increased!'));
-        }
+                //store payment
+                $payment = Payment::create([
+                    'user_id' => $user->id,
+                    'payment_id' => $paymentSession->payment_intent,
+                    'payment_method' => 'stripe',
+                    'type' => 'Credits',
+                    'status' => 'paid',
+                    'amount' => $creditProduct->quantity,
+                    'price' => $creditProduct->price,
+                    'tax_value' => $creditProduct->getTaxValue(),
+                    'total_price' => $creditProduct->getTotalPrice(),
+                    'tax_percent' => $creditProduct->getTaxPercent(),
+                    'currency_code' => $creditProduct->currency_code,
+                ]);
+
+                //payment notification
+                $user->notify(new ConfirmPaymentNotification($payment));
+
+                event(new UserUpdateCreditsEvent($user));
+
+                //redirect back to home
+                return redirect()->route('home')->with('success', __('Your credit balance has been increased!'));
+            }else{
+                if($paymentIntent->status != "processing"){
+                    //redirect back to home
+                    return redirect()->route('home')->with('success', __('Your payment is being processed!'));
+                }
+                if($paymentDbEntry == 0){
+                    $stripeClient->paymentIntents->cancel($paymentIntent->id);
+
+                    //redirect back to home
+                    return redirect()->route('home')->with('success', __('Your payment has been canceled!'));
+                }else{
+                    abort(402);
+                }
+            }
         }catch (HttpException $ex) {
             if (env('APP_ENV') == 'local') {
                 echo $ex->statusCode;
@@ -337,6 +357,50 @@ class PaymentController extends Controller
         }
     }
 
+    /**
+     * @param Request $request
+     */
+    public function StripeWebhooks(Request $request)
+    {
+
+        \Stripe\Stripe::setApiKey($this->getStripeSecret());
+
+
+
+        try {
+            $payload = @file_get_contents('php://input');
+            $sig_header = $request->header('Stripe-Signature');
+            $event = null;
+            $event = \Stripe\Webhook::constructEvent(
+                $payload, $sig_header, $this->getStripeEndpointSecret()
+            );
+        } catch(\UnexpectedValueException $e) {
+            // Invalid payload
+
+            abort(400);
+        } catch(\Stripe\Exception\SignatureVerificationException $e) {
+            // Invalid signature
+
+            abort(400);
+
+        }
+
+        // Handle the event
+        switch ($event->type) {
+            case 'payment_intent.succeeded':
+                $paymentIntent = $event->data->object; // contains a \Stripe\PaymentIntent
+                error_log($paymentIntent->status);
+                break;
+            case 'payment_method.attached':
+                $paymentMethod = $event->data->object; // contains a \Stripe\PaymentMethod
+                error_log($paymentMethod);
+                break;
+            // ... handle other event types
+            default:
+                echo 'Received unknown event type ' . $event->type;
+        }
+    }
+
     /**
      * @return \Stripe\StripeClient
      */
@@ -355,6 +419,18 @@ class PaymentController extends Controller
             :  env('STRIPE_SECRET');
     }
 
+    /**
+     * @return string
+     */
+    protected function getStripeEndpointSecret()
+    {
+        return env('APP_ENV') == 'local'
+            ?  env('STRIPE_ENDPOINT_TEST_SECRET')
+            :  env('STRIPE_ENDPOINT_SECRET');
+    }
+
+
+
 
     /**
      * @return JsonResponse|mixed

+ 1 - 1
app/Http/Middleware/VerifyCsrfToken.php

@@ -12,6 +12,6 @@ class VerifyCsrfToken extends Middleware
      * @var array
      */
     protected $except = [
-        //
+        'payment/StripeWebhooks'
     ];
 }

+ 3 - 1
routes/web.php

@@ -40,6 +40,9 @@ Route::middleware('guest')->get('/', function () {
 
 Auth::routes(['verify' => true]);
 
+# Stripe WebhookRoute -> validation in Route Handler
+Route::post('payment/StripeWebhooks', [PaymentController::class, 'StripeWebhooks'])->name('payment.StripeWebhooks');
+
 Route::middleware(['auth', 'checkSuspended'])->group(function () {
     #resend verification email
     Route::get('/email/verification-notification', function (Request $request) {
@@ -66,7 +69,6 @@ Route::middleware(['auth', 'checkSuspended'])->group(function () {
     Route::get('payment/PaypalSuccess', [PaymentController::class, 'PaypalSuccess'])->name('payment.PaypalSuccess');
     Route::get('payment/StripePay/{creditProduct}', [PaymentController::class, 'StripePay'])->name('payment.StripePay');
     Route::get('payment/StripeSuccess', [PaymentController::class, 'StripeSuccess'])->name('payment.StripeSuccess');
-
     Route::get('payment/Cancel', [PaymentController::class, 'Cancel'])->name('payment.Cancel');