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\Container\ContainerInterface;
use Mpociot\VatCalculator\VatCalculator;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
class FinancialsController extends Controller
{
@ -122,7 +124,7 @@ class FinancialsController extends Controller
$registrar_id = $data['registrar'];
$registrars = $db->select("SELECT id, clid, name FROM registrar");
$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);
@ -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();
$amount = $postData['amount']; // Make sure to validate and sanitize this amount
@ -223,11 +225,41 @@ class FinancialsController extends Controller
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;
$db = $this->container->get('db');
if ($session_id) {
\Stripe\Stripe::setApiKey(envi('STRIPE_SECRET_KEY'));
@ -265,7 +297,7 @@ class FinancialsController extends Controller
[
'registrar_id' => $_SESSION['auth_registrar_id'],
'date' => $date,
'description' => 'Registrar Balance Deposit via Stripe ('.$paymentIntentId.')',
'description' => 'registrar balance deposit via Stripe ('.$paymentIntentId.')',
'amount' => $amount
]
);
@ -280,48 +312,62 @@ class FinancialsController extends Controller
$db->commit();
} catch (Exception $e) {
$db->rollBack();
$balance = $db->selectRow('SELECT name, accountBalance, creditLimit FROM registrar WHERE id = ?',
[ $_SESSION["auth_registrar_id"] ]
);
return view($response, 'admin/financials/deposit-registrar.twig', [
'error' => $e->getMessage(),
'balance' => $balance
]);
$this->container->get('flash')->addMessage('error', 'Failure: '.$e->getMessage());
return $response->withHeader('Location', '/deposit')->withStatus(302);
}
$balance = $db->selectRow('SELECT name, accountBalance, creditLimit FROM registrar WHERE id = ?',
[ $_SESSION["auth_registrar_id"] ]
);
return view($response, 'admin/financials/deposit-registrar.twig', [
'deposit' => $amount,
'balance' => $balance
]);
$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 {
$balance = $db->selectRow('SELECT name, accountBalance, creditLimit FROM registrar WHERE id = ?',
[ $_SESSION["auth_registrar_id"] ]
);
return view($response, 'admin/financials/deposit-registrar.twig', [
'error' => 'Invalid entry: Deposit amount must be positive. Please enter a valid amount.',
'balance' => $balance
]);
$this->container->get('flash')->addMessage('error', 'Invalid entry: Deposit amount must be positive. Please enter a valid amount.');
return $response->withHeader('Location', '/deposit')->withStatus(302);
}
} catch (\Exception $e) {
$balance = $db->selectRow('SELECT name, accountBalance, creditLimit FROM registrar WHERE id = ?',
[ $_SESSION["auth_registrar_id"] ]
);
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
]);
$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);
}
}
}
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)
{
return view($response,'admin/financials/cancel.twig');

View file

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

View file

@ -27,4 +27,9 @@ MAIL_API_PROVIDER='sendgrid'
STRIPE_SECRET_KEY='stripe-secret-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

View file

@ -27,7 +27,7 @@
{% include 'partials/flash.twig' %}
<div class="card">
<div class="card-body">
<form id="depositForm" action="/deposit" method="post">
<form id="depositForm" action="#" method="post">
{{ csrf.field | raw }}
<div class="deposit-info">
<h5>{{ __('Current Balance for') }} {{ balance.name }}</h5>
@ -46,8 +46,10 @@
</div>
<div class="card-footer">
<div class="row align-items-center">
<div class="col-auto">
<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>
<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="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>
@ -81,5 +83,26 @@
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>
{% endblock %}

View file

@ -170,7 +170,7 @@
</a>
</div>
</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">
<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>

View file

@ -94,12 +94,14 @@ $app->group('', function ($route) {
$route->get('/poll', LogsController::class .':poll')->setName('poll');
$route->get('/log', LogsController::class .':log')->setName('log');
$route->get('/reports', ReportsController::class .':view')->setName('reports');
$route->get('/invoices', FinancialsController::class .':invoices')->setName('invoices');
$route->get('/invoice/{invoice}', FinancialsController::class . ':viewInvoice')->setName('viewInvoice');
$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'], '/payment-success', FinancialsController::class .':success')->setName('success');
$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'], '/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->get('/transactions', FinancialsController::class .':transactions')->setName('transactions');
$route->get('/overview', FinancialsController::class .':overview')->setName('overview');