Added registrar deposit option via crypto

This commit is contained in:
Pinga 2024-02-13 14:44:04 +02:00
parent b2859bbfc3
commit bb032c71b2
6 changed files with 250 additions and 1 deletions

View file

@ -264,6 +264,50 @@ class FinancialsController extends Controller
return $response->withHeader('Content-Type', 'application/json'); 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) public function successStripe(Request $request, Response $response)
{ {
$session_id = $request->getQueryParams()['session_id'] ?? null; $session_id = $request->getQueryParams()['session_id'] ?? null;
@ -374,7 +418,124 @@ class FinancialsController extends Controller
$this->container->get('flash')->addMessage('error', 'Failure: '.$e->getMessage()); $this->container->get('flash')->addMessage('error', 'Failure: '.$e->getMessage());
return $response->withHeader('Location', '/deposit')->withStatus(302); 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) public function webhookAdyen(Request $request, Response $response)

View file

@ -237,6 +237,9 @@ $csrfMiddleware = function ($request, $handler) use ($container) {
if ($path && $path === '/create-adyen-payment') { if ($path && $path === '/create-adyen-payment') {
return $handler->handle($request); return $handler->handle($request);
} }
if ($path && $path === '/create-crypto-payment') {
return $handler->handle($request);
}
// If not skipped, apply the CSRF Guard // If not skipped, apply the CSRF Guard
return $csrf->process($request, $handler); return $csrf->process($request, $handler);

View file

@ -35,4 +35,6 @@ ADYEN_BASIC_AUTH_USER='adyen-basic-auth-user'
ADYEN_BASIC_AUTH_PASS='adyen-basic-auth-pass' ADYEN_BASIC_AUTH_PASS='adyen-basic-auth-pass'
ADYEN_HMAC_KEY='adyen-hmac-key' ADYEN_HMAC_KEY='adyen-hmac-key'
NOW_API_KEY='now-api-key'
TEST_TLDS=.test,.com.test TEST_TLDS=.test,.com.test

View file

@ -43,8 +43,10 @@
<div class="row align-items-center"> <div class="row align-items-center">
<div class="d-grid gap-2 d-md-block"> <div class="d-grid gap-2 d-md-block">
<button type="submit" class="btn btn-primary"><svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M11.453 8.056c0 -.623 .518 -.979 1.442 -.979c1.69 0 3.41 .343 4.605 .923l.5 -4c-.948 -.449 -2.82 -1 -5.5 -1c-1.895 0 -3.373 .087 -4.5 1c-1.172 .956 -2 2.33 -2 4c0 3.03 1.958 4.906 5 6c1.961 .69 3 .743 3 1.5c0 .735 -.851 1.5 -2 1.5c-1.423 0 -3.963 -.609 -5.5 -1.5l-.5 4c1.321 .734 3.474 1.5 6 1.5c2 0 3.957 -.468 5.084 -1.36c1.263 -.979 1.916 -2.268 1.916 -4.14c0 -3.096 -1.915 -4.547 -5 -5.637c-1.646 -.605 -2.544 -1.07 -2.544 -1.807z" /></svg> {{ __('Deposit with Stripe') }}</button> <button type="submit" class="btn btn-primary"><svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M11.453 8.056c0 -.623 .518 -.979 1.442 -.979c1.69 0 3.41 .343 4.605 .923l.5 -4c-.948 -.449 -2.82 -1 -5.5 -1c-1.895 0 -3.373 .087 -4.5 1c-1.172 .956 -2 2.33 -2 4c0 3.03 1.958 4.906 5 6c1.961 .69 3 .743 3 1.5c0 .735 -.851 1.5 -2 1.5c-1.423 0 -3.963 -.609 -5.5 -1.5l-.5 4c1.321 .734 3.474 1.5 6 1.5c2 0 3.957 -.468 5.084 -1.36c1.263 -.979 1.916 -2.268 1.916 -4.14c0 -3.096 -1.915 -4.547 -5 -5.637c-1.646 -.605 -2.544 -1.07 -2.544 -1.807z" /></svg> {{ __('Deposit with Stripe') }}</button>
<button type="button" id="adyenPayment" class="btn btn-primary"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-letter-a" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 20v-12a4 4 0 0 1 4 -4h2a4 4 0 0 1 4 4v12" /><path d="M7 13l10 0" /></svg> {{ __('Deposit with Adyen') }}</button> <button type="button" id="adyenPayment" class="btn btn-primary"><svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-letter-a" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M7 20v-12a4 4 0 0 1 4 -4h2a4 4 0 0 1 4 4v12" /><path d="M7 13l10 0" /></svg> {{ __('Deposit with Adyen') }}</button>
<button type="button" id="cryptoPayment" class="btn btn-primary"><svg xmlns="http://www.w3.org/2000/svg" class="icon" width="24" height="24" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M6 6h8a3 3 0 0 1 0 6a3 3 0 0 1 0 6h-8" /><path d="M8 6l0 12" /><path d="M8 12l6 0" /><path d="M9 3l0 3" /><path d="M13 3l0 3" /><path d="M9 18l0 3" /><path d="M13 18l0 3" /></svg></svg> {{ __('Deposit with Crypto') }}</button>
</div> </div>
</div> </div>
</div> </div>
@ -99,5 +101,26 @@
console.error('Error:', error); 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);
});
});
</script> </script>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,58 @@
{% extends "layouts/app.twig" %}
{% block title %}{{ __('Crypto Payment Status') }}{% endblock %}
{% block content %}
<div class="page-wrapper">
<!-- Page header -->
<div class="page-header d-print-none">
<div class="container-xl">
<div class="row g-2 align-items-center">
<div class="col">
<!-- Page pre-title -->
<div class="page-pretitle">
{{ __('Overview') }}
</div>
<h2 class="page-title">
{{ __('Crypto Payment Status') }}
</h2>
</div>
</div>
</div>
</div>
<!-- Page body -->
<div class="page-body">
<div class="container-xl">
<div class="col-12">
{% include 'partials/flash.twig' %}
{% if status is defined and paymentId is defined %}
<div class="card">
<div class="card-body">
<h4>{{ __('Payment Status:') }} {{ status }}</h4>
{% if status == 'finished' %}
<p class="text-success">Your payment has been successfully processed and finished.</p>
{% elseif status == 'expired' %}
<p class="text-warning">Your payment has expired. Please initiate a new payment if you wish to proceed.</p>
{% else %}
<p class="text-primary">The status of your payment is currently '{{ status }}'. Please <a href="#" onclick="window.location.reload(); return false;"><u>check back</u></a> later for updates.</p>
{% endif %}
</div>
</div>
{% else %}
<div class="card">
<div class="card-body">
<h4>{{ __('Payment Status Unavailable') }}</h4>
<p class="text-secondary">{{ __('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:') }}</p>
<p class="text-secondary"><strong>/payment-success-crypto?paymentId=YOUR_PAYMENT_ID_HERE</strong></p>
<p class="text-secondary">{{ __('Replace') }} <strong>YOUR_PAYMENT_ID_HERE</strong> {{ __('with your actual payment ID.') }}</p>
<p class="text-secondary">{{ __('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.') }}</p>
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
{% include 'partials/footer.twig' %}
</div>
{% endblock %}

View file

@ -101,8 +101,10 @@ $app->group('', function ($route) {
$route->map(['GET', 'POST'], '/deposit', FinancialsController::class .':deposit')->setName('deposit'); $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-payment', FinancialsController::class .':createStripePayment')->setName('createStripePayment');
$route->map(['GET', 'POST'], '/create-adyen-payment', FinancialsController::class .':createAdyenPayment')->setName('createAdyenPayment'); $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', FinancialsController::class .':successStripe')->setName('successStripe');
$route->map(['GET', 'POST'], '/payment-success-adyen', FinancialsController::class .':successAdyen')->setName('successAdyen'); $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->map(['GET', 'POST'], '/payment-cancel', FinancialsController::class .':cancel')->setName('cancel');
$route->get('/transactions', FinancialsController::class .':transactions')->setName('transactions'); $route->get('/transactions', FinancialsController::class .':transactions')->setName('transactions');
$route->get('/overview', FinancialsController::class .':overview')->setName('overview'); $route->get('/overview', FinancialsController::class .':overview')->setName('overview');