diff --git a/cp/app/Controllers/FinancialsController.php b/cp/app/Controllers/FinancialsController.php index d88fa1a..7ee54c7 100644 --- a/cp/app/Controllers/FinancialsController.php +++ b/cp/app/Controllers/FinancialsController.php @@ -264,6 +264,50 @@ class FinancialsController extends Controller return $response->withHeader('Content-Type', 'application/json'); } + public function createCryptoPayment(Request $request, Response $response) + { + $postData = $request->getParsedBody(); + $amount = $postData['amount']; // Make sure to validate and sanitize this amount + + // Your registrar ID and unique identifier + $registrarId = $_SESSION['auth_registrar_id']; + $uniqueIdentifier = Uuid::uuid4()->toString(); // Generates a unique UUID + + $delimiter = '|'; + $combinedString = $registrarId . $delimiter . $uniqueIdentifier; + $merchantReference = bin2hex($combinedString); + + $data = [ + 'price_amount' => $amount, + 'price_currency' => $_SESSION['_currency'], + 'order_id' => $merchantReference, + 'success_url' => envi('APP_URL').'/payment-success-crypto', + 'cancel_url' => envi('APP_URL').'/payment-cancel', + ]; + + $client = new Client(); + $apiKey = envi('NOW_API_KEY'); + + try { + $response = $client->request('POST', 'https://api.nowpayments.io/v1/invoice', [ + 'headers' => [ + 'x-api-key' => $apiKey, + 'Content-Type' => 'application/json', + ], + 'json' => $data, + ]); + + $statusCode = $response->getStatusCode(); + $body = $response->getBody()->getContents(); + + $response->getBody()->write(json_encode($body)); + return $response->withHeader('Content-Type', 'application/json'); + } catch (GuzzleException $e) { + $this->container->get('flash')->addMessage('error', 'We encountered an issue while processing your payment. Details: ' . $e->getMessage()); + return $response->withHeader('Location', '/deposit')->withStatus(302); + } + } + public function successStripe(Request $request, Response $response) { $session_id = $request->getQueryParams()['session_id'] ?? null; @@ -374,7 +418,124 @@ class FinancialsController extends Controller $this->container->get('flash')->addMessage('error', 'Failure: '.$e->getMessage()); return $response->withHeader('Location', '/deposit')->withStatus(302); } + } + + public function successCrypto(Request $request, Response $response) + { + $client = new Client(); + + $queryParams = $request->getQueryParams(); + if (!isset($queryParams['paymentId']) || $queryParams['paymentId'] == 0) { + $this->container->get('flash')->addMessage('info', 'No paymentId provided.'); + return view($response,'admin/financials/success-crypto.twig'); + } else { + $paymentId = $queryParams['paymentId']; + $apiKey = envi('NOW_API_KEY'); + $url = 'https://api.nowpayments.io/v1/payment/' . $paymentId; + + try { + $apiclient = $client->request('GET', $url, [ + 'headers' => [ + 'x-api-key' => $apiKey, + ], + ]); + + $statusCode = $apiclient->getStatusCode(); + $body = $apiclient->getBody()->getContents(); + $data = json_decode($body, true); + + if ($statusCode === 200) { // Check if the request was successful + if (isset($data['payment_status']) && $data['payment_status'] === 'finished') { + try { + $amount = $data['pay_amount']; + $merchantReference = hex2bin($data['order_description']); + $delimiter = '|'; + + // Split to get the original components + list($registrarId, $uniqueIdentifier) = explode($delimiter, $merchantReference, 2); + + $isPositiveNumberWithTwoDecimals = filter_var($amount, FILTER_VALIDATE_FLOAT) !== false && preg_match('/^\d+(\.\d{1,2})?$/', $amount); + + if ($isPositiveNumberWithTwoDecimals) { + $db->beginTransaction(); + + try { + $currentDateTime = new \DateTime(); + $date = $currentDateTime->format('Y-m-d H:i:s.v'); + $db->insert( + 'statement', + [ + 'registrar_id' => $registrarId, + 'date' => $date, + 'command' => 'create', + 'domain_name' => 'deposit', + 'length_in_months' => 0, + 'fromS' => $date, + 'toS' => $date, + 'amount' => $amount + ] + ); + + $db->insert( + 'payment_history', + [ + 'registrar_id' => $registrarId, + 'date' => $date, + 'description' => 'registrar balance deposit via Crypto ('.$data['payment_id'].')', + 'amount' => $amount + ] + ); + + $db->exec( + 'UPDATE registrar SET accountBalance = (accountBalance + ?) WHERE id = ?', + [ + $amount, + $registrarId, + ] + ); + + $db->commit(); + } catch (Exception $e) { + $this->container->get('flash')->addMessage('success', 'Request failed: ' . $e->getMessage()); + return $response->withHeader('Location', '/payment-success-crypto')->withStatus(302); + } + + return view($response, 'admin/financials/success-crypto.twig', [ + 'status' => $data['payment_status'], + 'paymentId' => $paymentId + ]); + } else { + $this->container->get('flash')->addMessage('success', 'Request failed. Reload page.'); + return $response->withHeader('Location', '/payment-success-crypto')->withStatus(302); + } + } catch (\Exception $e) { + $this->container->get('flash')->addMessage('success', 'Request failed: ' . $e->getMessage()); + return $response->withHeader('Location', '/payment-success-crypto')->withStatus(302); + } + } else if (isset($data['payment_status']) && $data['payment_status'] === 'expired') { + return view($response, 'admin/financials/success-crypto.twig', [ + 'status' => $data['payment_status'], + 'paymentId' => $paymentId + ]); + } else { + return view($response, 'admin/financials/success-crypto.twig', [ + 'status' => $data['payment_status'], + 'paymentId' => $paymentId + ]); + } + } else { + $this->container->get('flash')->addMessage('success', 'Failed to retrieve payment information. Status Code: ' . $statusCode); + return $response->withHeader('Location', '/payment-success-crypto')->withStatus(302); + } + + } catch (GuzzleException $e) { + $this->container->get('flash')->addMessage('success', 'Request failed: ' . $e->getMessage()); + return $response->withHeader('Location', '/payment-success-crypto')->withStatus(302); + } + } + + return view($response,'admin/financials/success-crypto.twig'); } public function webhookAdyen(Request $request, Response $response) diff --git a/cp/bootstrap/app.php b/cp/bootstrap/app.php index dc28448..5543019 100644 --- a/cp/bootstrap/app.php +++ b/cp/bootstrap/app.php @@ -237,6 +237,9 @@ $csrfMiddleware = function ($request, $handler) use ($container) { if ($path && $path === '/create-adyen-payment') { return $handler->handle($request); } + if ($path && $path === '/create-crypto-payment') { + return $handler->handle($request); + } // If not skipped, apply the CSRF Guard return $csrf->process($request, $handler); diff --git a/cp/env-sample b/cp/env-sample index 2a48c82..4767cca 100644 --- a/cp/env-sample +++ b/cp/env-sample @@ -35,4 +35,6 @@ ADYEN_BASIC_AUTH_USER='adyen-basic-auth-user' ADYEN_BASIC_AUTH_PASS='adyen-basic-auth-pass' ADYEN_HMAC_KEY='adyen-hmac-key' +NOW_API_KEY='now-api-key' + TEST_TLDS=.test,.com.test \ No newline at end of file diff --git a/cp/resources/views/admin/financials/deposit-registrar.twig b/cp/resources/views/admin/financials/deposit-registrar.twig index 498e1c5..ee6da10 100644 --- a/cp/resources/views/admin/financials/deposit-registrar.twig +++ b/cp/resources/views/admin/financials/deposit-registrar.twig @@ -43,8 +43,10 @@
- + + +
@@ -99,5 +101,26 @@ console.error('Error:', error); }); }); + + document.getElementById('cryptoPayment').addEventListener('click', function(e) { + e.preventDefault(); + + var form = document.getElementById('depositForm'); + var formData = new FormData(form); + + fetch('/create-crypto-payment', { + method: 'POST', + body: formData + }) + .then(function(response) { + return response.json(); + }) + .then(function(data) { + window.location.href = data.invoice_url; + }) + .catch(function(error) { + console.error('Error:', error); + }); + }); {% endblock %} \ No newline at end of file diff --git a/cp/resources/views/admin/financials/success-crypto.twig b/cp/resources/views/admin/financials/success-crypto.twig new file mode 100644 index 0000000..387bac0 --- /dev/null +++ b/cp/resources/views/admin/financials/success-crypto.twig @@ -0,0 +1,58 @@ +{% extends "layouts/app.twig" %} + +{% block title %}{{ __('Crypto Payment Status') }}{% endblock %} + +{% block content %} +
+ + + +
+
+
+ {% include 'partials/flash.twig' %} + {% if status is defined and paymentId is defined %} +
+
+

{{ __('Payment Status:') }} {{ status }}

+ {% if status == 'finished' %} +

Your payment has been successfully processed and finished.

+ {% elseif status == 'expired' %} +

Your payment has expired. Please initiate a new payment if you wish to proceed.

+ {% else %} +

The status of your payment is currently '{{ status }}'. Please check back later for updates.

+ {% endif %} +
+
+ {% else %} +
+
+

{{ __('Payment Status Unavailable') }}

+

{{ __('It appears you\'ve accessed this page directly without specifying a payment ID. To view the status of your payment and ensure it is credited once completed, please make sure to include the paymentId parameter in the URL, like so:') }}

+

/payment-success-crypto?paymentId=YOUR_PAYMENT_ID_HERE

+

{{ __('Replace') }} YOUR_PAYMENT_ID_HERE {{ __('with your actual payment ID.') }}

+

{{ __('If you\'re unsure of your payment ID or if you\'ve encountered this message after completing a payment, please check your email for the payment confirmation, which should include the necessary payment ID. Alternatively, you can contact our support team for assistance.') }}

+
+
+ {% endif %} +
+
+
+
+ {% include 'partials/footer.twig' %} + +{% endblock %} \ No newline at end of file diff --git a/cp/routes/web.php b/cp/routes/web.php index ae6bfbb..274ac2a 100644 --- a/cp/routes/web.php +++ b/cp/routes/web.php @@ -101,8 +101,10 @@ $app->group('', function ($route) { $route->map(['GET', 'POST'], '/deposit', FinancialsController::class .':deposit')->setName('deposit'); $route->map(['GET', 'POST'], '/create-payment', FinancialsController::class .':createStripePayment')->setName('createStripePayment'); $route->map(['GET', 'POST'], '/create-adyen-payment', FinancialsController::class .':createAdyenPayment')->setName('createAdyenPayment'); + $route->map(['GET', 'POST'], '/create-crypto-payment', FinancialsController::class .':createCryptoPayment')->setName('createCryptoPayment'); $route->map(['GET', 'POST'], '/payment-success', FinancialsController::class .':successStripe')->setName('successStripe'); $route->map(['GET', 'POST'], '/payment-success-adyen', FinancialsController::class .':successAdyen')->setName('successAdyen'); + $route->map(['GET', 'POST'], '/payment-success-crypto', FinancialsController::class .':successCrypto')->setName('successCrypto'); $route->map(['GET', 'POST'], '/payment-cancel', FinancialsController::class .':cancel')->setName('cancel'); $route->get('/transactions', FinancialsController::class .':transactions')->setName('transactions'); $route->get('/overview', FinancialsController::class .':overview')->setName('overview');