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(); });