From 46602a21c59496bc385f39ee0569793967440f47 Mon Sep 17 00:00:00 2001 From: David Bomba Date: Wed, 25 Sep 2019 12:07:33 +1000 Subject: [PATCH] Stripe payments --- .../ClientPortal/InvoiceController.php | 6 +- .../ClientPortal/PaymentController.php | 44 +++--- app/Models/Client.php | 27 ++-- app/PaymentDrivers/StripePaymentDriver.php | 47 +++++- .../portal/default/gateways/pay_now.blade.php | 4 +- .../gateways/stripe/add_credit_card.blade.php | 2 - .../gateways/stripe/credit_card.blade.php | 143 ++++++++++++++++++ .../portal/default/invoices/payment.blade.php | 45 ++++-- routes/client.php | 2 +- 9 files changed, 266 insertions(+), 54 deletions(-) create mode 100644 resources/views/portal/default/gateways/stripe/credit_card.blade.php diff --git a/app/Http/Controllers/ClientPortal/InvoiceController.php b/app/Http/Controllers/ClientPortal/InvoiceController.php index 1bb91f728d2f..ac18c8ccbc4f 100644 --- a/app/Http/Controllers/ClientPortal/InvoiceController.php +++ b/app/Http/Controllers/ClientPortal/InvoiceController.php @@ -120,8 +120,7 @@ class InvoiceController extends Controller ->whereClientId(auth()->user()->client->id) ->get(); - $total = $invoices->sum('balance'); - + $total = $invoices->sum('balance'); $invoices->filter(function ($invoice){ return $invoice->isPayable(); @@ -131,8 +130,6 @@ class InvoiceController extends Controller return $invoice; }); - - $formatted_total = Number::formatMoney($total, auth()->user()->client); $payment_methods = auth()->user()->client->getPaymentMethods($total); @@ -142,6 +139,7 @@ class InvoiceController extends Controller 'invoices' => $invoices, 'formatted_total' => $formatted_total, 'payment_methods' => $payment_methods, + 'hashed_ids' => $ids, 'total' => $total, ]; diff --git a/app/Http/Controllers/ClientPortal/PaymentController.php b/app/Http/Controllers/ClientPortal/PaymentController.php index 73be23385af9..0770470d5bfd 100644 --- a/app/Http/Controllers/ClientPortal/PaymentController.php +++ b/app/Http/Controllers/ClientPortal/PaymentController.php @@ -11,26 +11,30 @@ namespace App\Http\Controllers\ClientPortal; -use Cache; use App\Filters\PaymentFilters; use App\Http\Controllers\Controller; use App\Models\CompanyGateway; +use App\Models\Invoice; use App\Models\Payment; +use App\Utils\Number; +use App\Utils\Traits\MakesDates; use App\Utils\Traits\MakesHash; +use Cache; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; use Yajra\DataTables\Facades\DataTables; use Yajra\DataTables\Html\Builder; /** - * Class InvoiceController - * @package App\Http\Controllers\ClientPortal\InvoiceController + * Class PaymentController + * @package App\Http\Controllers\ClientPortal\PaymentController */ class PaymentController extends Controller { use MakesHash; + use MakesDates; /** * Show the list of Invoices @@ -84,41 +88,47 @@ class PaymentController extends Controller * The request will also contain the amount * and invoice ids for reference. * - * @param int $company_gateway_id The CompanyGateway ID - * @param int $gateway_type_id The gateway_type_id ID * @return void */ - public function process($company_gateway_id) + public function process() { - $invoices = Invoice::whereIn('id', $this->transformKeys(request()->input('invoice_ids'))) + $invoices = Invoice::whereIn('id', $this->transformKeys(explode(",",request()->input('hashed_ids')))) ->whereClientId(auth()->user()->client->id) ->get(); - $amount = request()->input('amount'); + $amount = $invoices->sum('balance'); - //build a cache record to maintain state - $cache_hash = str_random(config('ninja.key_length')); + $invoices->filter(function ($invoice){ + return $invoice->isPayable(); + })->map(function ($invoice){ + $invoice->balance = Number::formatMoney($invoice->balance, $invoice->client); + $invoice->due_date = $this->formatDate($invoice->due_date, $invoice->client->date_format()); + return $invoice; + }); - Cache::put($cache_hash, 'value', now()->addMinutes(10)); + $payment_methods = auth()->user()->client->getPaymentMethods($amount); //boot the payment gateway - $gateway = CompanyGateway::find($company_gateway_id); + $gateway = CompanyGateway::find(request()->input('company_gateway_id')); + + $payment_method_id = request()->input('payment_method_id'); //if there is a gateway fee, now is the time to calculate it //and add it to the invoice $data = [ - 'cache_hash' => $cache_hash, 'invoices' => $invoices, 'amount' => $amount, 'fee' => $gateway->calcGatewayFee($amount), - 'amount_with_fee' => ($amount + $gateway->calcGatewayFee($amount)), - 'gateway' => $gateway, - 'token' => auth()->user()->client->gateway_token($gateway->id), + 'amount_with_fee' => $amount + $gateway->calcGatewayFee($amount), + 'token' => auth()->user()->client->gateway_token($gateway->id, $payment_method_id), + 'payment_method_id' => $payment_method_id, ]; - return view('gateways.pay_now', $data); + + return $gateway->driver(auth()->user()->client)->processPayment($data); + } diff --git a/app/Models/Client.php b/app/Models/Client.php index 1035334baae8..4993a78ced45 100644 --- a/app/Models/Client.php +++ b/app/Models/Client.php @@ -110,15 +110,15 @@ class Client extends BaseModel * Allows the storage of multiple tokens * per client per gateway per payment_method * - * @param int $gateway_id The gateway ID + * @param int $company_gateway_id The company gateway ID * @param int $payment_method_id The payment method ID * @return ClientGatewayToken The client token record */ - public function gateway_token($gateway_id, $payment_method_id) + public function gateway_token($company_gateway_id, $payment_method_id) { - return $this->gateway_tokens - ->whereCompanyGatewayId($gateway_id) - ->wherePaymentMethod_id($payment_method_id) + return $this->gateway_tokens() + ->whereCompanyGatewayId($company_gateway_id) + ->whereGatewayTypeId($payment_method_id) ->first(); } @@ -264,6 +264,14 @@ class Client extends BaseModel return null; } + public function getCurrencyCode() + { + if ($this->currency) { + return $this->currency->code; + } + + return 'USD'; + } /** * Generates an array of payment urls per client * for a given amount. @@ -324,11 +332,10 @@ class Client extends BaseModel $fee_label = $gateway->calcGatewayFeeLabel($amount, $this); - $payment_urls[] = [ - 'label' => ctrans('texts.' . $gateway->getTypeAlias($gateway_type_id)) . $fee_label, - 'url' => URL::signedRoute('client.payments.process', [ - 'company_gateway_id' => $gateway_id, - 'gateway_type_id' => $gateway_type_id]) + $payment_urls[] = [ + 'label' => ctrans('texts.' . $gateway->getTypeAlias($gateway_type_id)) . $fee_label, + 'company_gateway_id' => $gateway_id, + 'gateway_type_id' => $gateway_type_id ]; } diff --git a/app/PaymentDrivers/StripePaymentDriver.php b/app/PaymentDrivers/StripePaymentDriver.php index 4e3625238da9..c430e69bebd1 100644 --- a/app/PaymentDrivers/StripePaymentDriver.php +++ b/app/PaymentDrivers/StripePaymentDriver.php @@ -68,7 +68,7 @@ class StripePaymentDriver extends BasePaymentDriver { $types = [ GatewayType::CREDIT_CARD, - GatewayType::TOKEN, + //GatewayType::TOKEN, ]; if($this->company_gateway->getSofortEnabled() && $this->invitation && $this->client() && isset($this->client()->country) && in_array($this->client()->country, ['AUT', 'BEL', 'DEU', 'ITA', 'NLD', 'ESP'])) @@ -130,6 +130,7 @@ class StripePaymentDriver extends BasePaymentDriver public function authorizeCreditCardView($data) { + $intent['intent'] = $this->getSetupIntent(); return view('portal.default.gateways.stripe.add_credit_card', array_merge($data, $intent)); @@ -185,13 +186,52 @@ class StripePaymentDriver extends BasePaymentDriver return redirect()->route('client.payment_methods.index'); } + /** + * Processes the payment with this gateway + * + * @var invoices + * @var amount + * @var fee + * @var amount_with_fee + * @var token + * @var payment_method_id + * @param array $data variables required to build payment page + * @return view Gateway and payment method specific view + */ + public function processPayment(array $data) + { + $payment_intent_data = [ + 'amount' => $data['amount_with_fee']*100, + 'currency' => $this->client->getCurrencyCode(), + 'customer' => $this->findOrCreateCustomer(), + 'description' => $data['invoices']->pluck('id'), + ]; + + if($data['token']) + $payment_intent_data['payment_method'] = $data['token']->token; + else{ +// $payment_intent_data['setup_future_usage'] = 'off_session'; +// $payment_intent_data['save_payment_method'] = true; +// $payment_intent_data['confirm'] = true; + } + + + $data['intent'] = $this->createPaymentIntent($payment_intent_data); + $data['gateway'] = $this; + + return view($this->viewForType($data['payment_method_id']), $data); + + } + + + /** * Creates a new String Payment Intent * * @param array $data The data array to be passed to Stripe * @return PaymentIntent The Stripe payment intent object */ - public function createIntent($data) :?\Stripe\PaymentIntent + public function createPaymentIntent($data) :?\Stripe\PaymentIntent { $this->init(); @@ -258,6 +298,9 @@ class StripePaymentDriver extends BasePaymentDriver } + if(!$customer) + throw Exception('Unable to create gateway customer'); + return $customer; } diff --git a/resources/views/portal/default/gateways/pay_now.blade.php b/resources/views/portal/default/gateways/pay_now.blade.php index e55099e5b655..08ef3faaaf75 100644 --- a/resources/views/portal/default/gateways/pay_now.blade.php +++ b/resources/views/portal/default/gateways/pay_now.blade.php @@ -49,8 +49,8 @@ - @include($gateway->driver(auth()->user()->client)->viewForType($gateway_type_id)) - + @yield('pay_now') + diff --git a/resources/views/portal/default/gateways/stripe/add_credit_card.blade.php b/resources/views/portal/default/gateways/stripe/add_credit_card.blade.php index 9db743ab6485..67388a0e6998 100644 --- a/resources/views/portal/default/gateways/stripe/add_credit_card.blade.php +++ b/resources/views/portal/default/gateways/stripe/add_credit_card.blade.php @@ -40,8 +40,6 @@ {{ ctrans('texts.save') }} - - @endsection diff --git a/resources/views/portal/default/gateways/stripe/credit_card.blade.php b/resources/views/portal/default/gateways/stripe/credit_card.blade.php new file mode 100644 index 000000000000..5fec358fd5a1 --- /dev/null +++ b/resources/views/portal/default/gateways/stripe/credit_card.blade.php @@ -0,0 +1,143 @@ +@extends('portal.default.gateways.pay_now') + +@section('pay_now') + +@if($token) +
+
+ +
+
+
+
+
+ +
+
+ +@else +
+
+ +
+ + +
+
+
+ +
+ + +
+ + + + +
+ +
+
+@endif + +@endsection + +@push('scripts') + + + + +@endpush + +@push('css') + + +@endpush \ No newline at end of file diff --git a/resources/views/portal/default/invoices/payment.blade.php b/resources/views/portal/default/invoices/payment.blade.php index 6be5fd6aff8a..9c69a7974266 100644 --- a/resources/views/portal/default/invoices/payment.blade.php +++ b/resources/views/portal/default/invoices/payment.blade.php @@ -5,6 +5,19 @@ @section('body')
+{!! Former::framework('TwitterBootstrap4'); !!} + +{!! Former::horizontal_open() + ->id('payment_form') + ->route('client.payments.process') + ->method('POST'); !!} + +{!! Former::hidden('hashed_ids')->id('hashed_ids')->value($hashed_ids) !!} +{!! Former::hidden('company_gateway_id')->id('company_gateway_id') !!} +{!! Former::hidden('payment_method_id')->id('payment_method_id') !!} + +{!! Former::close() !!} +
@@ -43,22 +56,13 @@
-
- - -
- -
- - - +
+ +
@@ -172,6 +176,15 @@ $("#modal_pay_now_button").on('click', function(e){ }); + function paymentMethod(company_gateway_id, payment_method_id) + { + $('#company_gateway_id').val(company_gateway_id); + $('#payment_method_id').val(payment_method_id); + $('#payment_form').submit(); + + } + + function getSignature() { //check in signature is required diff --git a/routes/client.php b/routes/client.php index e9b973c5876d..c5cae630faa8 100644 --- a/routes/client.php +++ b/routes/client.php @@ -24,7 +24,7 @@ Route::group(['middleware' => ['auth:contact'], 'prefix' => 'client', 'as' => 'c Route::get('recurring_invoices', 'ClientPortal\RecurringInvoiceController@index')->name('recurring_invoices.index'); Route::get('payments', 'ClientPortal\PaymentController@index')->name('payments.index'); - Route::get('payments/{company_gateway_id}/{payment_method_id}', 'PaymentController@process')->name('payments.process')->middleware('signed'); + Route::post('payments/process', 'ClientPortal\PaymentController@process')->name('payments.process'); Route::get('profile/{client_contact}/edit', 'ClientPortal\ProfileController@edit')->name('profile.edit'); Route::put('profile/{client_contact}/edit', 'ClientPortal\ProfileController@update')->name('profile.update');