Stripe gateway fixes; Support for Adyen

This commit is contained in:
Pinga 2024-02-13 07:36:42 +02:00
parent 6f9c4a4406
commit 94e0f2a445
6 changed files with 123 additions and 46 deletions

View file

@ -6,6 +6,8 @@ use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Container\ContainerInterface; use Psr\Container\ContainerInterface;
use Mpociot\VatCalculator\VatCalculator; use Mpociot\VatCalculator\VatCalculator;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class FinancialsController extends Controller class FinancialsController extends Controller
{ {
@ -122,7 +124,7 @@ class FinancialsController extends Controller
$registrar_id = $data['registrar']; $registrar_id = $data['registrar'];
$registrars = $db->select("SELECT id, clid, name FROM registrar"); $registrars = $db->select("SELECT id, clid, name FROM registrar");
$amount = $data['amount']; $amount = $data['amount'];
$description = empty($data['description']) ? "funds added to account balance" : $data['description']; $description = empty($data['description']) ? "Funds Added to Account Balance" : $data['description'];
$isPositiveNumberWithTwoDecimals = filter_var($amount, FILTER_VALIDATE_FLOAT) !== false && preg_match('/^\d+(\.\d{1,2})?$/', $amount); $isPositiveNumberWithTwoDecimals = filter_var($amount, FILTER_VALIDATE_FLOAT) !== false && preg_match('/^\d+(\.\d{1,2})?$/', $amount);
@ -189,7 +191,7 @@ class FinancialsController extends Controller
]); ]);
} }
public function createPayment(Request $request, Response $response) public function createStripePayment(Request $request, Response $response)
{ {
$postData = $request->getParsedBody(); $postData = $request->getParsedBody();
$amount = $postData['amount']; // Make sure to validate and sanitize this amount $amount = $postData['amount']; // Make sure to validate and sanitize this amount
@ -223,7 +225,37 @@ class FinancialsController extends Controller
return $response->withHeader('Content-Type', 'application/json'); return $response->withHeader('Content-Type', 'application/json');
} }
public function success(Request $request, Response $response) public function createAdyenPayment(Request $request, Response $response)
{
$postData = $request->getParsedBody();
$amount = $postData['amount']; // Make sure to validate and sanitize this amount
// Convert amount to cents
$amountInCents = $amount * 100;
$client = new \Adyen\Client();
$client->setApplicationName('Namingo');
$client->setEnvironment(\Adyen\Environment::TEST);
$client->setXApiKey(envi('ADYEN_API_KEY'));
$service = new \Adyen\Service\Checkout($client);
$params = array(
'amount' => array(
'currency' => $_SESSION['_currency'],
'value' => $amountInCents
),
'merchantAccount' => envi('ADYEN_MERCHANT_ID'),
'reference' => 'Registrar Balance Deposit',
'returnUrl' => envi('APP_URL').'/payment-success-adyen',
'mode' => 'hosted',
'themeId' => envi('ADYEN_THEME_ID')
);
$result = $service->sessions($params);
$response->getBody()->write(json_encode($result));
return $response->withHeader('Content-Type', 'application/json');
}
public function successStripe(Request $request, Response $response)
{ {
$session_id = $request->getQueryParams()['session_id'] ?? null; $session_id = $request->getQueryParams()['session_id'] ?? null;
$db = $this->container->get('db'); $db = $this->container->get('db');
@ -265,7 +297,7 @@ class FinancialsController extends Controller
[ [
'registrar_id' => $_SESSION['auth_registrar_id'], 'registrar_id' => $_SESSION['auth_registrar_id'],
'date' => $date, 'date' => $date,
'description' => 'Registrar Balance Deposit via Stripe ('.$paymentIntentId.')', 'description' => 'registrar balance deposit via Stripe ('.$paymentIntentId.')',
'amount' => $amount 'amount' => $amount
] ]
); );
@ -280,48 +312,62 @@ class FinancialsController extends Controller
$db->commit(); $db->commit();
} catch (Exception $e) { } catch (Exception $e) {
$db->rollBack(); $this->container->get('flash')->addMessage('error', 'Failure: '.$e->getMessage());
$balance = $db->selectRow('SELECT name, accountBalance, creditLimit FROM registrar WHERE id = ?', return $response->withHeader('Location', '/deposit')->withStatus(302);
[ $_SESSION["auth_registrar_id"] ]
);
return view($response, 'admin/financials/deposit-registrar.twig', [
'error' => $e->getMessage(),
'balance' => $balance
]);
} }
$balance = $db->selectRow('SELECT name, accountBalance, creditLimit FROM registrar WHERE id = ?', $this->container->get('flash')->addMessage('success', 'Deposit successfully added. The registrar\'s account balance has been updated.');
[ $_SESSION["auth_registrar_id"] ] return $response->withHeader('Location', '/deposit')->withStatus(302);
);
return view($response, 'admin/financials/deposit-registrar.twig', [
'deposit' => $amount,
'balance' => $balance
]);
} else { } else {
$balance = $db->selectRow('SELECT name, accountBalance, creditLimit FROM registrar WHERE id = ?', $this->container->get('flash')->addMessage('error', 'Invalid entry: Deposit amount must be positive. Please enter a valid amount.');
[ $_SESSION["auth_registrar_id"] ] return $response->withHeader('Location', '/deposit')->withStatus(302);
);
return view($response, 'admin/financials/deposit-registrar.twig', [
'error' => 'Invalid entry: Deposit amount must be positive. Please enter a valid amount.',
'balance' => $balance
]);
} }
} catch (\Exception $e) { } catch (\Exception $e) {
$balance = $db->selectRow('SELECT name, accountBalance, creditLimit FROM registrar WHERE id = ?', $this->container->get('flash')->addMessage('error', 'We encountered an issue while processing your payment. Please check your payment details and try again.');
[ $_SESSION["auth_registrar_id"] ] return $response->withHeader('Location', '/deposit')->withStatus(302);
);
return view($response, 'admin/financials/deposit-registrar.twig', [
'error' => 'We encountered an issue while processing your payment. Please check your payment details and try again.',
'balance' => $balance
]);
} }
} }
} }
public function successAdyen(Request $request, Response $response)
{
$sessionId = $request->getQueryParams()['sessionId'] ?? null;
$sessionResult = $request->getQueryParams()['sessionResult'] ?? null;
$db = $this->container->get('db');
$client = new Client([
'base_uri' => envi('ADYEN_BASE_URI'),
'timeout' => 2.0,
]);
try {
$apicall = $client->request('GET', "sessions/$sessionId", [
'query' => ['sessionResult' => $sessionResult],
'headers' => [
'X-API-Key' => envi('ADYEN_API_KEY'),
'Content-Type' => 'application/json',
],
]);
$data = json_decode($apicall->getBody(), true);
$status = $data['status'] ?? 'unknown';
if ($status == 'completed') {
echo $status;
$this->container->get('flash')->addMessage('success', 'Deposit successfully added. The registrar\'s account balance has been updated.');
return $response->withHeader('Location', '/deposit')->withStatus(302);
} else {
$this->container->get('flash')->addMessage('error', 'We encountered an issue while processing your payment. Please check your payment details and try again.');
return $response->withHeader('Location', '/deposit')->withStatus(302);
}
} catch (RequestException $e) {
$this->container->get('flash')->addMessage('error', 'Failure: '.$e->getMessage());
return $response->withHeader('Location', '/deposit')->withStatus(302);
}
}
public function cancel(Request $request, Response $response) public function cancel(Request $request, Response $response)
{ {
return view($response,'admin/financials/cancel.twig'); return view($response,'admin/financials/cancel.twig');

View file

@ -41,7 +41,8 @@
"league/flysystem": "^3.23", "league/flysystem": "^3.23",
"mpociot/vat-calculator": "^3.7", "mpociot/vat-calculator": "^3.7",
"ramsey/uuid": "^4.7", "ramsey/uuid": "^4.7",
"selective/xmldsig": "^3.1" "selective/xmldsig": "^3.1",
"adyen/php-api-library": "^17.1"
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {

View file

@ -27,4 +27,9 @@ MAIL_API_PROVIDER='sendgrid'
STRIPE_SECRET_KEY='stripe-secret-key' STRIPE_SECRET_KEY='stripe-secret-key'
STRIPE_PUBLISHABLE_KEY='stripe-publishable-key' STRIPE_PUBLISHABLE_KEY='stripe-publishable-key'
ADYEN_API_KEY='adyen-api-key'
ADYEN_MERCHANT_ID='adyen-merchant-id'
ADYEN_THEME_ID='adyen-theme-id'
ADYEN_BASE_URI='https://checkout-test.adyen.com/v70/'
TEST_TLDS=.test,.com.test TEST_TLDS=.test,.com.test

View file

@ -27,7 +27,7 @@
{% include 'partials/flash.twig' %} {% include 'partials/flash.twig' %}
<div class="card"> <div class="card">
<div class="card-body"> <div class="card-body">
<form id="depositForm" action="/deposit" method="post"> <form id="depositForm" action="#" method="post">
{{ csrf.field | raw }} {{ csrf.field | raw }}
<div class="deposit-info"> <div class="deposit-info">
<h5>{{ __('Current Balance for') }} {{ balance.name }}</h5> <h5>{{ __('Current Balance for') }} {{ balance.name }}</h5>
@ -46,8 +46,10 @@
</div> </div>
<div class="card-footer"> <div class="card-footer">
<div class="row align-items-center"> <div class="row align-items-center">
<div class="col-auto"> <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 icon-tabler icon-tabler-brand-stripe" 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>
</div> </div>
</div> </div>
</div> </div>
@ -81,5 +83,26 @@
console.error('Error:', error); console.error('Error:', error);
}); });
}); });
document.getElementById('adyenPayment').addEventListener('click', function(e) {
e.preventDefault();
var form = document.getElementById('depositForm');
var formData = new FormData(form);
fetch('/create-adyen-payment', {
method: 'POST',
body: formData
})
.then(function(response) {
return response.json();
})
.then(function(data) {
window.location.href = data.url;
})
.catch(function(error) {
console.error('Error:', error);
});
});
</script> </script>
{% endblock %} {% endblock %}

View file

@ -170,7 +170,7 @@
</a> </a>
</div> </div>
</li>{% endif %} </li>{% endif %}
<li {{ is_current_url('deposit') or is_current_url('transactions') or is_current_url('overview') or is_current_url('invoices') or is_current_url('success') or 'invoice' in currentUri ? 'class="nav-item dropdown active"' : 'class="nav-item dropdown"' }}> <li {{ is_current_url('deposit') or is_current_url('transactions') or is_current_url('overview') or is_current_url('invoices') or is_current_url('successStripe') or 'invoice' in currentUri ? 'class="nav-item dropdown active"' : 'class="nav-item dropdown"' }}>
<a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false"> <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown" data-bs-auto-close="outside" role="button" aria-expanded="false">
<span class="nav-link-icon d-md-none d-lg-inline-block"><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><path d="M7 9m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z"></path><path d="M14 14m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path><path d="M17 9v-2a2 2 0 0 0 -2 -2h-10a2 2 0 0 0 -2 2v6a2 2 0 0 0 2 2h2"></path></svg> <span class="nav-link-icon d-md-none d-lg-inline-block"><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><path d="M7 9m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z"></path><path d="M14 14m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0"></path><path d="M17 9v-2a2 2 0 0 0 -2 -2h-10a2 2 0 0 0 -2 2v6a2 2 0 0 0 2 2h2"></path></svg>
</span> </span>

View file

@ -98,8 +98,10 @@ $app->group('', function ($route) {
$route->get('/invoices', FinancialsController::class .':invoices')->setName('invoices'); $route->get('/invoices', FinancialsController::class .':invoices')->setName('invoices');
$route->get('/invoice/{invoice}', FinancialsController::class . ':viewInvoice')->setName('viewInvoice'); $route->get('/invoice/{invoice}', FinancialsController::class . ':viewInvoice')->setName('viewInvoice');
$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 .':createPayment')->setName('createPayment'); $route->map(['GET', 'POST'], '/create-payment', FinancialsController::class .':createStripePayment')->setName('createStripePayment');
$route->map(['GET', 'POST'], '/payment-success', FinancialsController::class .':success')->setName('success'); $route->map(['GET', 'POST'], '/create-adyen-payment', FinancialsController::class .':createAdyenPayment')->setName('createAdyenPayment');
$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-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');