From aabe29fb5c6ad111f326d1f871adc48538f09417 Mon Sep 17 00:00:00 2001 From: Pinga <121483313+getpinga@users.noreply.github.com> Date: Mon, 20 Jan 2025 14:51:59 +0200 Subject: [PATCH] Added support for Nicky.me payment gateway --- cp/app/Controllers/FinancialsController.php | 187 ++++++++++++++++++ cp/env-sample | 2 + cp/public/assets/nicky.svg | 26 +++ .../admin/financials/deposit-registrar.twig | 106 +++++++++- .../views/admin/financials/success-nicky.twig | 64 ++++++ cp/routes/web.php | 2 + docs/configuration.md | 2 + 7 files changed, 388 insertions(+), 1 deletion(-) create mode 100644 cp/public/assets/nicky.svg create mode 100644 cp/resources/views/admin/financials/success-nicky.twig diff --git a/cp/app/Controllers/FinancialsController.php b/cp/app/Controllers/FinancialsController.php index 589d2d7..c6e5b9c 100644 --- a/cp/app/Controllers/FinancialsController.php +++ b/cp/app/Controllers/FinancialsController.php @@ -333,6 +333,82 @@ class FinancialsController extends Controller return $response->withStatus(500)->withHeader('Content-Type', 'application/json'); } } + + public function createNickyPayment(Request $request, Response $response) + { + $postData = $request->getParsedBody(); + $amount = $postData['amount']; // Make sure to validate and sanitize this amount + + // Registrar ID and unique identifier + $registrarId = $_SESSION['auth_registrar_id']; + + // Generate a 10-character alphanumeric random string for the invoice reference + $invoiceReference = strtoupper(bin2hex(random_bytes(5))); // 10 characters, all caps + + // Map currency to Nicky's blockchainAssetId + $blockchainAssetId = match ($_SESSION['_currency']) { + 'USD' => 'USD.USD', + 'EUR' => 'EUR.EUR', + default => throw new Exception('Unsupported currency: ' . $_SESSION['_currency']), + }; + + // Prepare the payload for the API + $data = [ + 'blockchainAssetId' => $blockchainAssetId, + 'amountExpectedNative' => $amount, + 'billDetails' => [ + 'invoiceReference' => $invoiceReference, + 'description' => 'Deposit for registrar ' . $registrarId, + ], + 'requester' => [ + 'email' => $_SESSION['auth_email'], + 'name' => $_SESSION['auth_username'], + ], + 'sendNotification' => true, + 'successUrl' => envi('APP_URL') . '/payment-success-nicky', + 'cancelUrl' => envi('APP_URL') . '/payment-cancel', + ]; + + $url = 'https://api-public.pay.nicky.me/api/public/PaymentRequestPublicApi/create'; + $apiKey = envi('NICKY_API_KEY'); + + $client = new Client(); + + try { + $apiResponse = $client->request('POST', $url, [ + 'headers' => [ + 'x-api-key' => $apiKey, + 'Content-Type' => 'application/json', + ], + 'json' => $data, + ]); + + $body = json_decode($apiResponse->getBody()->getContents(), true); + + if (isset($body['bill']['shortId'])) { + $paymentUrl = "https://pay.nicky.me/home?paymentId=" . $body['bill']['shortId']; + + // Store the shortId in the session or database for future reference + $_SESSION['nicky_shortId'] = $body['bill']['shortId']; + + // Return the payment URL as JSON + $response->getBody()->write(json_encode(['invoice_url' => $paymentUrl])); + return $response->withHeader('Content-Type', 'application/json')->withStatus(200); + } else { + throw new Exception('API response does not contain a payment URL.'); + } + } catch (GuzzleException $e) { + unset($_SESSION['nicky_shortId']); + + $errorResponse = [ + 'error' => 'We encountered an issue while processing your payment.', + 'details' => $e->getMessage(), + ]; + + $response->getBody()->write(json_encode($errorResponse)); + return $response->withStatus(500)->withHeader('Content-Type', 'application/json'); + } + } public function successStripe(Request $request, Response $response) { @@ -563,6 +639,117 @@ class FinancialsController extends Controller return view($response,'admin/financials/success-crypto.twig'); } + + public function successNicky(Request $request, Response $response) + { + $client = new Client(); + $sessionShortId = $_SESSION['nicky_shortId'] ?? null; + + if (!$sessionShortId) { + $this->container->get('flash')->addMessage('info', 'No payment reference found in session.'); + return view($response, 'admin/financials/success-nicky.twig'); + } + + $url = 'https://api-public.pay.nicky.me/api/public/PaymentRequestPublicApi/get-by-short-id?shortId=' . urlencode($sessionShortId); + $apiKey = envi('NICKY_API_KEY'); + + try { + $apiResponse = $client->request('GET', $url, [ + 'headers' => [ + 'x-api-key' => $apiKey, + 'Content-Type' => 'application/json', + ], + ]); + + $statusCode = $apiResponse->getStatusCode(); + $responseBody = json_decode($apiResponse->getBody()->getContents(), true); + + if ($statusCode === 200 && isset($responseBody['status'])) { + $status = $responseBody['status']; + $amount = $responseBody['amountNative'] ?? 0; + $paymentId = $responseBody['id'] ?? null; + $description = $responseBody['bill']['description'] ?? 'No description'; + + if ($status === "None" || $status === "PaymentValidationRequired" || $status === "PaymentPending") { + return view($response, 'admin/financials/success-nicky.twig', [ + 'status' => $status, + 'paymentId' => $paymentId + ]); + } elseif ($status === "Finished") { + // Record the successful transaction in the database + $db = $this->container->get('db'); + $registrarId = $_SESSION['auth_registrar_id']; + + $currentDateTime = new \DateTime(); + $date = $currentDateTime->format('Y-m-d H:i:s.v'); + + $db->beginTransaction(); + try { + $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 Nicky ('.$paymentId.')', + 'amount' => $amount, + ] + ); + + $db->exec( + 'UPDATE registrar SET accountBalance = (accountBalance + ?) WHERE id = ?', + [ + $amount, + $registrarId, + ] + ); + + $db->commit(); + } catch (\Exception $e) { + $db->rollBack(); + $this->container->get('flash')->addMessage('error', 'Transaction recording failed: ' . $e->getMessage()); + return $response->withHeader('Location', '/payment-success-nicky')->withStatus(302); + } + + unset($_SESSION['nicky_shortId']); + + // Redirect to success page with details + return view($response, 'admin/financials/success-nicky.twig', [ + 'status' => $status, + 'paymentId' => $paymentId, + ]); + } else { + unset($_SESSION['nicky_shortId']); + + // Handle unexpected statuses + return view($response, 'admin/financials/success-nicky.twig', [ + 'status' => $status, + 'paymentId' => $paymentId, + ]); + } + } else { + unset($_SESSION['nicky_shortId']); + $this->container->get('flash')->addMessage('error', 'Failed to retrieve payment information.'); + return $response->withHeader('Location', '/payment-success-nicky')->withStatus(302); + } + } catch (GuzzleException $e) { + $this->container->get('flash')->addMessage('error', 'Request failed: ' . $e->getMessage()); + return $response->withHeader('Location', '/payment-success-nicky')->withStatus(302); + } + } public function webhookAdyen(Request $request, Response $response) { diff --git a/cp/env-sample b/cp/env-sample index 2a9394b..a2f4c03 100644 --- a/cp/env-sample +++ b/cp/env-sample @@ -41,4 +41,6 @@ ADYEN_HMAC_KEY='adyen-hmac-key' NOW_API_KEY='now-api-key' +NICKY_API_KEY='nicky-api-key' + TEST_TLDS=.test,.com.test \ No newline at end of file diff --git a/cp/public/assets/nicky.svg b/cp/public/assets/nicky.svg new file mode 100644 index 0000000..4f7cfc9 --- /dev/null +++ b/cp/public/assets/nicky.svg @@ -0,0 +1,26 @@ + diff --git a/cp/resources/views/admin/financials/deposit-registrar.twig b/cp/resources/views/admin/financials/deposit-registrar.twig index 7062cc5..fcae7aa 100644 --- a/cp/resources/views/admin/financials/deposit-registrar.twig +++ b/cp/resources/views/admin/financials/deposit-registrar.twig @@ -4,6 +4,46 @@ {% block content %} + +
+ Your payment is currently in progress. Please check back later for updates. +
+ {% elseif status == 'Canceled' %} ++ Your payment has been cancelled. Please initiate a new payment if you wish to proceed. +
+ {% else %} ++ Your payment has been successfully processed and completed. +
+ {% endif %} +{{ __('It appears the payment details could not be found in your session. This may happen if the session has expired or if you accessed this page directly without completing the payment process.') }}
+{{ __('To proceed, please restart the payment process. If you have already completed a payment and believe this is an error, check your email for the payment confirmation details or contact our support team for assistance.') }}
+{{ __('We recommend initiating a new payment to ensure your transaction is properly credited.') }}
+ +