diff --git a/app/Http/Requests/ClientPortal/Payments/PaymentResponseRequest.php b/app/Http/Requests/ClientPortal/Payments/PaymentResponseRequest.php
index d3980f4b89af..3a917f339e2f 100644
--- a/app/Http/Requests/ClientPortal/Payments/PaymentResponseRequest.php
+++ b/app/Http/Requests/ClientPortal/Payments/PaymentResponseRequest.php
@@ -37,6 +37,11 @@ class PaymentResponseRequest extends FormRequest
return PaymentHash::whereRaw('BINARY `hash`= ?', [$input['payment_hash']])->first();
}
+ public function shouldStoreToken(): bool
+ {
+ return (bool) $this->store_card;
+ }
+
public function prepareForValidation()
{
if ($this->has('store_card')) {
diff --git a/app/PaymentDrivers/Mollie/CreditCard.php b/app/PaymentDrivers/Mollie/CreditCard.php
index d67b6f249bf9..22806fb44e71 100644
--- a/app/PaymentDrivers/Mollie/CreditCard.php
+++ b/app/PaymentDrivers/Mollie/CreditCard.php
@@ -31,9 +31,9 @@ class CreditCard
/**
* Show the page for credit card payments.
- *
- * @param array $data
- * @return Factory|View
+ *
+ * @param array $data
+ * @return Factory|View
*/
public function paymentView(array $data)
{
@@ -44,9 +44,9 @@ class CreditCard
/**
* Create a payment object.
- *
- * @param PaymentResponseRequest $request
- * @return mixed
+ *
+ * @param PaymentResponseRequest $request
+ * @return mixed
*/
public function paymentResponse(PaymentResponseRequest $request)
{
@@ -58,16 +58,7 @@ class CreditCard
->withData('client_id', $this->mollie->client->id);
try {
- $customer = $this->mollie->gateway->customers->create([
- 'name' => $this->mollie->client->name,
- 'metadata' => [
- 'id' => $this->mollie->client->hashed_id,
- ],
- ]);
-
- $payment = $this->mollie->gateway->payments->create([
- 'customerId' => $customer->id,
- 'sequenceType' => 'first',
+ $data = [
'amount' => [
'currency' => $this->mollie->client->currency()->code,
'value' => $amount,
@@ -80,7 +71,26 @@ class CreditCard
]),
'webhookUrl' => 'https://invoiceninja.com',
'cardToken' => $request->token,
- ]);
+ ];
+
+ if ($request->shouldStoreToken()) {
+ $customer = $this->mollie->gateway->customers->create([
+ 'name' => $this->mollie->client->name,
+ 'email' => $this->mollie->client->present()->email(),
+ 'metadata' => [
+ 'id' => $this->mollie->client->hashed_id,
+ ],
+ ]);
+
+ $data['customerId'] = $customer->id;
+ $data['sequenceType'] = 'first';
+
+ $this->mollie->payment_hash
+ ->withData('mollieCustomerId', $customer->id)
+ ->withData('shouldStoreToken', true);
+ }
+
+ $payment = $this->mollie->gateway->payments->create($data);
if ($payment->status === 'paid') {
$this->mollie->logSuccessfulGatewayResponse(
@@ -107,6 +117,27 @@ class CreditCard
{
$payment_hash = $this->mollie->payment_hash;
+ if ($payment_hash->data->shouldStoreToken) {
+ try {
+ $mandates = \iterator_to_array($this->mollie->gateway->mandates->listForId($payment_hash->data->mollieCustomerId));
+ } catch (\Mollie\Api\Exceptions\ApiException $e) {
+ return $this->processUnsuccessfulPayment($e);
+ }
+
+ $payment_meta = new \stdClass;
+ $payment_meta->exp_month = (string) $mandates[0]->details->cardExpiryDate;
+ $payment_meta->exp_year = (string) '';
+ $payment_meta->brand = (string) $mandates[0]->details->cardLabel;
+ $payment_meta->last4 = (string) $mandates[0]->details->cardNumber;
+ $payment_meta->type = GatewayType::CREDIT_CARD;
+
+ $this->mollie->storeGatewayToken([
+ 'token' => $mandates[0]->id,
+ 'payment_method_id' => GatewayType::CREDIT_CARD,
+ 'payment_meta' => $payment_meta,
+ ]);
+ }
+
$data = [
'gateway_type_id' => GatewayType::CREDIT_CARD,
'amount' => array_sum(array_column($payment_hash->invoices(), 'amount')) + $payment_hash->fee_total,
@@ -151,9 +182,9 @@ class CreditCard
/**
* Show authorization page.
- *
- * @param array $data
- * @return Factory|View
+ *
+ * @param array $data
+ * @return Factory|View
*/
public function authorizeView(array $data)
{
@@ -162,9 +193,9 @@ class CreditCard
/**
* Handle authorization response.
- *
- * @param mixed $request
- * @return RedirectResponse
+ *
+ * @param mixed $request
+ * @return RedirectResponse
*/
public function authorizeResponse($request): RedirectResponse
{
diff --git a/resources/views/portal/ninja2020/gateways/mollie/credit_card/pay.blade.php b/resources/views/portal/ninja2020/gateways/mollie/credit_card/pay.blade.php
index d6a4d7db4f56..a99e55c6dfca 100644
--- a/resources/views/portal/ninja2020/gateways/mollie/credit_card/pay.blade.php
+++ b/resources/views/portal/ninja2020/gateways/mollie/credit_card/pay.blade.php
@@ -29,26 +29,19 @@ ctrans('texts.credit_card')])
@include('portal.ninja2020.gateways.includes.payment_details')
@component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')])
- @if(count($tokens) > 0)
- @foreach($tokens as $token)
+ @if (count($tokens) > 0)
+ @foreach ($tokens as $token)
@endforeach
@endif
@endcomponent
@@ -83,13 +76,7 @@ ctrans('texts.credit_card')])
@endcomponent
- @component('portal.ninja2020.components.general.card-element-single')
- If you want to save the card for future purchases, please click on the
- Payment methods page and authorize the credit card manually.
-
-
- After that, come back to this page and select your payment method.
- @endcomponent
+ @include('portal.ninja2020.gateways.includes.save_card')
@include('portal.ninja2020.gateways.includes.pay_now')
@endsection
@@ -193,6 +180,15 @@ ctrans('texts.credit_card')])
return;
}
+ let tokenBillingCheckbox = document.querySelector(
+ 'input[name="token-billing-checkbox"]:checked'
+ );
+
+ if (tokenBillingCheckbox) {
+ document.querySelector('input[name="store_card"]').value =
+ tokenBillingCheckbox.value;
+ }
+
document.querySelector('input[name=token]').value = token;
document.getElementById('server-response').submit();
});