diff --git a/app/Extensions/PaymentGateways/Mollie/MollieExtension.php b/app/Extensions/PaymentGateways/Mollie/MollieExtension.php new file mode 100644 index 00000000..4c0920ea --- /dev/null +++ b/app/Extensions/PaymentGateways/Mollie/MollieExtension.php @@ -0,0 +1,146 @@ + "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]); + } +} diff --git a/app/Extensions/PaymentGateways/Mollie/MollieSettings.php b/app/Extensions/PaymentGateways/Mollie/MollieSettings.php new file mode 100644 index 00000000..976025d2 --- /dev/null +++ b/app/Extensions/PaymentGateways/Mollie/MollieSettings.php @@ -0,0 +1,36 @@ + 'fas fa-dollar-sign', + 'api_key' => [ + 'type' => 'string', + 'label' => 'API Key', + 'description' => 'The API Key of your Mollie App', + ] + ]; + } +} diff --git a/app/Extensions/PaymentGateways/Mollie/migrations/2023_03_26_215801_create_mollie_settings.php b/app/Extensions/PaymentGateways/Mollie/migrations/2023_03_26_215801_create_mollie_settings.php new file mode 100644 index 00000000..a3b6bfd0 --- /dev/null +++ b/app/Extensions/PaymentGateways/Mollie/migrations/2023_03_26_215801_create_mollie_settings.php @@ -0,0 +1,18 @@ +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'); + } +} diff --git a/app/Extensions/PaymentGateways/Mollie/web_routes.php b/app/Extensions/PaymentGateways/Mollie/web_routes.php new file mode 100644 index 00000000..3d95e4b0 --- /dev/null +++ b/app/Extensions/PaymentGateways/Mollie/web_routes.php @@ -0,0 +1,17 @@ +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'); +}); diff --git a/app/Listeners/CreateInvoice.php b/app/Listeners/CreateInvoice.php index f81364a3..9fc7d0bf 100644 --- a/app/Listeners/CreateInvoice.php +++ b/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); } } } diff --git a/public/images/Extensions/PaymentGateways/mollie_logo.png b/public/images/Extensions/PaymentGateways/mollie_logo.png new file mode 100644 index 00000000..6b233765 Binary files /dev/null and b/public/images/Extensions/PaymentGateways/mollie_logo.png differ