diff --git a/app/PaymentDrivers/Stripe/BACS.php b/app/PaymentDrivers/Stripe/BACS.php new file mode 100644 index 000000000000..ca7edbcbe3c5 --- /dev/null +++ b/app/PaymentDrivers/Stripe/BACS.php @@ -0,0 +1,213 @@ +stripe = $stripe; + } + + public function authorizeView(array $data) + { + $intent['intent'] = $this->stripe->getSetupIntent(); + + return render('gateways.stripe.bacs.authorize', array_merge($data, $intent)); + } + + public function authorizeResponse($request) + { + $this->stripe->init(); + + $stripe_response = json_decode($request->input('gateway_response')); + + $customer = $this->stripe->findOrCreateCustomer(); + + $this->stripe->attach($stripe_response->payment_method, $customer); + + $stripe_method = $this->stripe->getStripePaymentMethod($stripe_response->payment_method); + + $this->storePaymentMethod($stripe_method, $request->payment_method_id, $customer); + + return redirect()->route('client.payment_methods.index'); + } + + public function paymentView(array $data) + { + + // $description = $this->stripe->decodeUnicodeString(ctrans('texts.invoices') . ': ' . collect($data['invoices'])->pluck('invoice_number')) . " for client {$this->stripe->client->present()->name()}"; + $invoice_numbers = collect($data['invoices'])->pluck('invoice_number')->implode(','); + $description = ctrans('texts.stripe_payment_text', ['invoicenumber' => $invoice_numbers, 'amount' => Number::formatMoney($data['total']['amount_with_fee'], $this->stripe->client), 'client' => $this->stripe->client->present()->name()]); + + $payment_intent_data = [ + 'amount' => $this->stripe->convertToStripeAmount($data['total']['amount_with_fee'], $this->stripe->client->currency()->precision, $this->stripe->client->currency()), + 'currency' => $this->stripe->client->getCurrencyCode(), + 'customer' => $this->stripe->findOrCreateCustomer(), + 'description' => $description, + 'metadata' => [ + 'payment_hash' => $this->stripe->payment_hash->hash, + 'gateway_type_id' => GatewayType::BACS, + ], + 'setup_future_usage' => 'off_session', + ]; + + $data['intent'] = $this->stripe->createPaymentIntent($payment_intent_data); + $data['gateway'] = $this->stripe; + + return render('gateways.stripe.bacs.pay', $data); + } + public function paymentResponse(PaymentResponseRequest $request) + { + $this->stripe->init(); + + $state = [ + 'server_response' => json_decode($request->gateway_response), + 'payment_hash' => $request->payment_hash, + ]; + + $state = array_merge($state, $request->all()); + $state['store_card'] = boolval($state['store_card']); + + if ($request->has('token') && ! is_null($request->token)) { + $state['store_card'] = false; + } + + $state['payment_intent'] = PaymentIntent::retrieve($state['server_response']->id, array_merge($this->stripe->stripe_connect_auth, ['idempotency_key' => uniqid("st",true)])); + $state['customer'] = $state['payment_intent']->customer; + + $this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, $state); + $this->stripe->payment_hash->save(); + + $server_response = $this->stripe->payment_hash->data->server_response; + + if ($server_response->status == 'succeeded') { + $this->stripe->logSuccessfulGatewayResponse(['response' => json_decode($request->gateway_response), 'data' => $this->stripe->payment_hash], SystemLog::TYPE_STRIPE); + + return $this->processSuccessfulPayment(); + } + + return $this->processUnsuccessfulPayment($server_response); + } + + public function processSuccessfulPayment() + { + UpdateCustomer::dispatch($this->stripe->company_gateway->company->company_key, $this->stripe->company_gateway->id, $this->stripe->client->id); + + $stripe_method = $this->stripe->getStripePaymentMethod($this->stripe->payment_hash->data->server_response->payment_method); + + $data = [ + 'payment_method' => $this->stripe->payment_hash->data->server_response->payment_method, + 'payment_type' => PaymentType::parseCardType(strtolower($stripe_method->card->brand)) ?: PaymentType::CREDIT_CARD_OTHER, + 'amount' => $this->stripe->convertFromStripeAmount($this->stripe->payment_hash->data->server_response->amount, $this->stripe->client->currency()->precision, $this->stripe->client->currency()), + 'transaction_reference' => isset($this->stripe->payment_hash->data->payment_intent->latest_charge) ? $this->stripe->payment_hash->data->payment_intent->latest_charge : optional($this->stripe->payment_hash->data->payment_intent->charges->data[0])->id, + 'gateway_type_id' => GatewayType::CREDIT_CARD, + ]; + + $this->stripe->payment_hash->data = array_merge((array) $this->stripe->payment_hash->data, ['amount' => $data['amount']]); + $this->stripe->payment_hash->save(); + + if ($this->stripe->payment_hash->data->store_card) { + $customer = new \stdClass; + $customer->id = $this->stripe->payment_hash->data->customer; + + $this->stripe->attach($this->stripe->payment_hash->data->server_response->payment_method, $customer); + + $stripe_method = $this->stripe->getStripePaymentMethod($this->stripe->payment_hash->data->server_response->payment_method); + + $this->storePaymentMethod($stripe_method, $this->stripe->payment_hash->data->payment_method_id, $customer); + } + + $payment = $this->stripe->createPayment($data, Payment::STATUS_COMPLETED); + + SystemLogger::dispatch( + ['response' => $this->stripe->payment_hash->data->server_response, 'data' => $data], + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_SUCCESS, + SystemLog::TYPE_STRIPE, + $this->stripe->client, + $this->stripe->client->company, + ); + + //If the user has come from a subscription double check here if we need to redirect. + //08-08-2022 + if($payment->invoices()->whereHas('subscription')->exists()){ + $subscription = $payment->invoices()->first()->subscription; + + if($subscription && array_key_exists('return_url', $subscription->webhook_configuration) && strlen($subscription->webhook_configuration['return_url']) >=1) + return redirect($subscription->webhook_configuration['return_url']); + + } + //08-08-2022 + + return redirect()->route('client.payments.show', ['payment' => $this->stripe->encodePrimaryKey($payment->id)]); + } + + public function processUnsuccessfulPayment($server_response) + { + $this->stripe->sendFailureMail($server_response->cancellation_reason); + + $message = [ + 'server_response' => $server_response, + 'data' => $this->stripe->payment_hash->data, + ]; + + SystemLogger::dispatch( + $message, + SystemLog::CATEGORY_GATEWAY_RESPONSE, + SystemLog::EVENT_GATEWAY_FAILURE, + SystemLog::TYPE_STRIPE, + $this->stripe->client, + $this->stripe->client->company, + ); + + throw new PaymentFailed('Failed to process the payment.', 500); + } + + private function storePaymentMethod(PaymentMethod $method, $payment_method_id, $customer) + { + try { + $payment_meta = new \stdClass; + $payment_meta->exp_month = (string) $method->card->exp_month; + $payment_meta->exp_year = (string) $method->card->exp_year; + $payment_meta->brand = (string) $method->card->brand; + $payment_meta->last4 = (string) $method->card->last4; + $payment_meta->type = GatewayType::BACS; + + $data = [ + 'payment_meta' => $payment_meta, + 'token' => $method->id, + 'payment_method_id' => $payment_method_id, + ]; + + $this->stripe->storeGatewayToken($data, ['gateway_customer_reference' => $customer->id]); + } catch (\Exception $e) { + return $this->stripe->processInternallyFailedPayment($this->stripe, $e); + } + } +} diff --git a/resources/views/portal/ninja2020/gateways/stripe/bacs/authorize.blade.php b/resources/views/portal/ninja2020/gateways/stripe/bacs/authorize.blade.php new file mode 100644 index 000000000000..7a0052785397 --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/stripe/bacs/authorize.blade.php @@ -0,0 +1,42 @@ +@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'BACS', 'card_title' => 'BACS']) + +@section('gateway_head') + + @if($gateway->getConfigField('account_id')) + + + @else + + @endif + + + + +@endsection + +@section('gateway_content') +
+ + + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.method')]) + {{ ctrans('texts.credit_card') }} + @endcomponent + + @include('portal.ninja2020.gateways.stripe.includes.card_widget', ['show_save_method' => false]) + + @component('portal.ninja2020.gateways.includes.pay_now', ['id' => 'authorize-card']) + {{ ctrans('texts.add_payment_method') }} + @endcomponent +@endsection + +@section('gateway_footer') + + +@endsection diff --git a/resources/views/portal/ninja2020/gateways/stripe/bacs/pay.blade.php b/resources/views/portal/ninja2020/gateways/stripe/bacs/pay.blade.php new file mode 100644 index 000000000000..a20313b7899d --- /dev/null +++ b/resources/views/portal/ninja2020/gateways/stripe/bacs/pay.blade.php @@ -0,0 +1,97 @@ +@extends('portal.ninja2020.layout.payments', ['gateway_title' => 'Credit card', 'card_title' => 'Credit card']) + +@php + $gateway_instance = $gateway instanceof \App\Models\CompanyGateway ? $gateway : $gateway->company_gateway; + $token_billing_string = 'true'; + + if($gateway_instance->token_billing == 'off' || $gateway_instance->token_billing == 'optin'){ + $token_billing_string = 'false'; + } + + +@endphp + +@section('gateway_head') + @if($gateway->company_gateway->getConfigField('account_id')) + + + @else + + @endif + + + + + +@endsection + +@section('gateway_content') + + + + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.payment_type')]) + {{ ctrans('texts.credit_card') }} + @endcomponent + + @include('portal.ninja2020.gateways.includes.payment_details') + + @component('portal.ninja2020.components.general.card-element', ['title' => ctrans('texts.pay_with')]) +