瀏覽代碼

feat: ✨ Create Mollie payment gateway extension

IceToast 2 年之前
父節點
當前提交
c95cde5cde

+ 146 - 0
app/Extensions/PaymentGateways/Mollie/MollieExtension.php

@@ -0,0 +1,146 @@
+<?php
+
+namespace App\Extensions\PaymentGateways\Mollie;
+
+use App\Helpers\AbstractExtension;
+use App\Events\PaymentEvent;
+use App\Events\UserUpdateCreditsEvent;
+use App\Models\PartnerDiscount;
+use App\Models\Payment;
+use App\Models\ShopProduct;
+use App\Models\User;
+use Exception;
+use Illuminate\Http\JsonResponse;
+use Illuminate\Http\Request;
+use Illuminate\Http\Response;
+use Illuminate\Support\Facades\Auth;
+use Illuminate\Support\Facades\Redirect;
+use Illuminate\Support\Facades\Log;
+use Illuminate\Support\Facades\Http;
+
+/**
+ * Summary of PayPalExtension
+ */
+class MollieExtension extends AbstractExtension
+{
+    public static function getConfig(): array
+    {
+        return [
+            "name" => "Mollie",
+            "RoutesIgnoreCsrf" => [
+                "payment/MollieWebhook"
+            ],
+        ];
+    }
+
+    static function pay(Request $request): void
+    {
+        $url = 'https://api.mollie.com/v2/payments';
+        $settings = new MollieSettings();
+
+        $user = Auth::user();
+        $shopProduct = ShopProduct::findOrFail($request->shopProduct);
+        $discount = PartnerDiscount::getDiscount();
+
+        // create a new payment
+        $payment = Payment::create([
+            'user_id' => $user->id,
+            'payment_id' => null,
+            'payment_method' => 'mollie',
+            'type' => $shopProduct->type,
+            'status' => 'open',
+            'amount' => $shopProduct->quantity,
+            'price' => $shopProduct->price - ($shopProduct->price * $discount / 100),
+            'tax_value' => $shopProduct->getTaxValue(),
+            'tax_percent' => $shopProduct->getTaxPercent(),
+            'total_price' => $shopProduct->getTotalPrice(),
+            'currency_code' => $shopProduct->currency_code,
+            'shop_item_product_id' => $shopProduct->id,
+        ]);
+
+        try {
+            $response = Http::withHeaders([
+                'Content-Type' => 'application/json',
+                'Authorization' => 'Bearer ' . $settings->api_key,
+            ])->post($url, [
+                'amount' => [
+                    'currency' => $shopProduct->currency_code,
+                    'value' => number_format($shopProduct->getTotalPrice(), 2, '.', ''),
+                ],
+                'description' => "Order #{$payment->id}",
+                'redirectUrl' => route('payment.mollieSuccess', ['payment' => $payment->id]),
+                'cancelUrl' => route('payment.cancel'),
+                'webhookUrl' => url('/extensions/payment/MollieWebhook'),
+                'metadata' => [
+                    'payment_id' => $payment->id,
+                ],
+            ]);
+
+            if ($response->status() != 201) {
+                Log::error('Mollie Payment: ' . $response->json()['title']);
+                $payment->delete();
+
+                Redirect::route('store.index')->with('error', __('Payment failed'))->send();
+                return;
+            }
+
+            $payment->update([
+                'payment_id' => $response->json()['id'],
+            ]);
+
+            Redirect::away($response->json()['_links']['checkout']['href'])->send();
+            return;
+        } catch (Exception $ex) {
+            Log::error('Mollie Payment: ' . $ex->getMessage());
+            $payment->delete();
+
+            Redirect::route('store.index')->with('error', __('Payment failed'))->send();
+            return;
+        }
+    }
+
+    static function success(Request $request): void
+    {
+        $payment = Payment::findOrFail($request->input('payment'));
+        $payment->status = 'pending';
+
+        Redirect::route('home')->with('success', 'Your payment is being processed')->send();
+        return;
+    }
+
+    static function webhook(Request $request): JsonResponse
+    {
+        $url = 'https://api.mollie.com/v2/payments/' . $request->id;
+        $settings = new MollieSettings();
+
+        try {
+            $response = Http::withHeaders([
+                'Content-Type' => 'application/json',
+                'Authorization' => 'Bearer ' . $settings->api_key,
+            ])->get($url);
+            if ($response->status() != 200) {
+                Log::error('Mollie Payment Webhook: ' . $response->json()['title']);
+                return response()->json(['success' => false]);
+            }
+
+            $payment = Payment::findOrFail($response->json()['metadata']['payment_id']);
+            $payment->status->update([
+                'status' => $response->json()['status'],
+            ]);
+
+            $shopProduct = ShopProduct::findOrFail($payment->shop_item_product_id);
+            event(new PaymentEvent($payment, $payment, $shopProduct));
+
+            if ($response->json()['status'] == 'paid') {
+                $user = User::findOrFail($payment->user_id);
+                event(new UserUpdateCreditsEvent($user));
+            }
+        } catch (Exception $ex) {
+            Log::error('Mollie Payment Webhook: ' . $ex->getMessage());
+            return response()->json(['success' => false]);
+        }
+
+        // return a 200 status code
+        return response()->json(['success' => true]);
+    }
+}

+ 36 - 0
app/Extensions/PaymentGateways/Mollie/MollieSettings.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace App\Extensions\PaymentGateways\Mollie;
+
+use Spatie\LaravelSettings\Settings;
+
+class MollieSettings extends Settings
+{
+
+    public bool $enabled = false;
+    public ?string $api_key;
+
+    public static function group(): string
+    {
+        return 'mollie';
+    }
+
+    public static function encrypted(): array
+    {
+        return [
+            "api_key",
+        ];
+    }
+
+    public static function getOptionInputData()
+    {
+        return [
+            'category_icon' => 'fas fa-dollar-sign',
+            'api_key' => [
+                'type' => 'string',
+                'label' => 'API Key',
+                'description' => 'The API Key of your Mollie App',
+            ]
+        ];
+    }
+}

+ 18 - 0
app/Extensions/PaymentGateways/Mollie/migrations/2023_03_26_215801_create_mollie_settings.php

@@ -0,0 +1,18 @@
+<?php
+
+use Spatie\LaravelSettings\Migrations\SettingsMigration;
+
+class CreateMollieSettings extends SettingsMigration
+{
+    public function up(): void
+    {
+        $this->migrator->addEncrypted('mollie.api_key', null);
+        $this->migrator->add('mollie.enabled', false);
+    }
+
+    public function down(): void
+    {
+        $this->migrator->delete('mollie.api_key');
+        $this->migrator->delete('mollie.enabled');
+    }
+}

+ 17 - 0
app/Extensions/PaymentGateways/Mollie/web_routes.php

@@ -0,0 +1,17 @@
+<?php
+
+use App\Extensions\PaymentGateways\Mollie\MollieExtension;
+use Illuminate\Support\Facades\Route;
+
+Route::middleware(['web', 'auth'])->group(function () {
+    Route::get('payment/MolliePay/{shopProduct}', function () {
+        MollieExtension::pay(request());
+    })->name('payment.MolliePay');
+
+    Route::get(
+        'payment/PayPalSuccess',
+        function () {
+            MollieExtension::success(request());
+        }
+    )->name('payment.MollieSuccess');
+});

+ 3 - 1
app/Listeners/CreateInvoice.php

@@ -11,6 +11,7 @@ class CreateInvoice
     use Invoiceable;
 
     private $invoice_enabled;
+    private $invoice_settings;
 
     /**
      * Create the event listener.
@@ -20,6 +21,7 @@ class CreateInvoice
     public function __construct(InvoiceSettings $invoice_settings)
     {
         $this->invoice_enabled = $invoice_settings->enabled;
+        $this->invoice_settings = $invoice_settings;
     }
 
     /**
@@ -32,7 +34,7 @@ class CreateInvoice
     {
         if ($this->invoice_enabled) {
             // create invoice using the trait
-            $this->createInvoice($event->payment, $event->shopProduct);
+            $this->createInvoice($event->payment, $event->shopProduct, $this->invoice_settings);
         }
     }
 }

二進制
public/images/Extensions/PaymentGateways/mollie_logo.png