From 9599c8de4fab14823cf1f022e60c64f46c291cff Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 18 May 2021 12:13:00 +1000 Subject: [PATCH 1/4] Refactor for Stripe Connect --- app/Exceptions/Handler.php | 2 +- .../Controllers/StripeConnectController.php | 93 ++++++++++---- app/Http/Kernel.php | 1 - .../InitializeStripeConnectRequest.php | 3 + app/Models/User.php | 9 ++ .../Stripe/Connect/ConnectOauth.php | 73 +++++++++++ config/ninja.php | 1 + .../views/auth/connect/completed.blade.php | 13 ++ .../views/auth/connect/existing.blade.php | 13 ++ resources/views/layouts/ninja.blade.php | 115 ++++++++++++++++++ 10 files changed, 297 insertions(+), 26 deletions(-) create mode 100644 app/PaymentDrivers/Stripe/Connect/ConnectOauth.php create mode 100644 resources/views/auth/connect/completed.blade.php create mode 100644 resources/views/auth/connect/existing.blade.php create mode 100644 resources/views/layouts/ninja.blade.php diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index f95c0d3cbf3d..808d999b4d6e 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -83,7 +83,7 @@ class Handler extends ExceptionHandler 'email' => 'anonymous@example.com', 'name' => 'Anonymous User', ]); - } elseif (auth()->guard('user') && auth()->guard('user')->user() && auth()->user()->company() && auth()->user()->company()->account->report_errors) { + } elseif (auth()->guard('user') && auth()->guard('user')->user() && auth()->user()->companyIsSet() && auth()->user()->company()->account->report_errors) { $scope->setUser([ 'id' => auth()->user()->account->key, 'email' => 'anonymous@example.com', diff --git a/app/Http/Controllers/StripeConnectController.php b/app/Http/Controllers/StripeConnectController.php index 325b5755f583..bebaf917c857 100644 --- a/app/Http/Controllers/StripeConnectController.php +++ b/app/Http/Controllers/StripeConnectController.php @@ -17,8 +17,11 @@ use App\Factory\CompanyGatewayFactory; use App\Http\Requests\StripeConnect\InitializeStripeConnectRequest; use App\Libraries\MultiDB; use App\Models\Client; +use App\Models\Company; use App\Models\CompanyGateway; +use App\Models\GatewayType; use App\PaymentDrivers\Stripe\Connect\Account; +use Illuminate\Http\Request; use Stripe\Exception\ApiErrorException; class StripeConnectController extends BaseController @@ -48,50 +51,74 @@ class StripeConnectController extends BaseController $config = decrypt($company_gateway->config); if(property_exists($config, 'account_id')) - return render('gateways.stripe.connect.existing'); + return view('auth.connect.existing'); + } - else - $company_gateway = CompanyGatewayFactory::create($request->getCompany()->id, $request->getContact()->id); - /* Set Credit Card To Enabled */ - $gateway_types = $company_gateway->driver(new Client)->gatewayTypes(); + $company = Company::where('company_key', $request->getTokenContent()['company_key'])->first(); + + auth()->login($request->getContact(), true); + $stripe_client_id = config('ninja.ninja_stripe_client_id'); + auth()->user()->setCompany($company); + + $redirect_uri = 'http://ninja.test:8000/stripe/completed'; + + $endpoint = "https://connect.stripe.com/oauth/authorize?response_type=code&client_id={$stripe_client_id}&redirect_uri={$redirect_uri}&scope=read_write&state={$token}"; + + return redirect($endpoint); + } + + public function completed(InitializeStripeConnectRequest $request) + { + + \Stripe\Stripe::setApiKey(config('ninja.ninja_stripe_key')); + + $response = \Stripe\OAuth::token([ + 'grant_type' => 'authorization_code', + 'code' => $request->input('code'), + ]); + + $company = Company::where('company_key', $request->getTokenContent()['company_key'])->first(); + auth()->user()->setCompany($company); + + $company_gateway = CompanyGatewayFactory::create($company->id, auth()->user()->id); $fees_and_limits = new \stdClass; - $fees_and_limits->{$gateway_types[0]} = new FeesAndLimits; - + $fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits; $company_gateway->gateway_key = 'd14dd26a47cecc30fdd65700bfb67b34'; $company_gateway->fees_and_limits = $fees_and_limits; + $company_gateway->config = encrypt(json_encode([])); $company_gateway->save(); + $payload = [ + 'account_id' => $response->stripe_user_id, + "token_type" => 'bearer', + "stripe_publishable_key" => $request->input('stripe_publishable_key'), + "scope" => $request->input('scope'), + "livemode" => $request->input('livemode'), + "stripe_user_id" => $request->input('stripe_user_id'), + "refresh_token" => $request->input('refresh_token'), + "access_token" => $request->input('access_token') + ]; + /* Link account if existing account exists */ if($account_id = $this->checkAccountAlreadyLinkToEmail($company_gateway, $request->getContact()->email)) { $config = json_decode(decrypt($company_gateway->config)); - $config->account_id = $account_id; - $company_gateway->config = encrypt(json_encode($config)); + $company_gateway->config = encrypt(json_encode($payload)); $company_gateway->save(); - return render('gateways.stripe.connect.existing'); + return view('auth.connect.existing'); + } - $data = [ - 'type' => 'standard', - 'email' => $request->getContact()->email, - 'country' => $request->getCompany()->country()->iso_3166_2, - ]; + $company_gateway->config = encrypt(json_encode($payload)); - $account = Account::create($data); - $link = Account::link($account->id, $token); - $company_gateway->config = encrypt(json_encode(['account_id' => $account->id])); $company_gateway->save(); - return redirect($link['url']); - } - - public function completed() - { - return render('gateways.stripe.connect.completed'); + //response here + return view('auth.connect.completed'); } @@ -111,4 +138,22 @@ class StripeConnectController extends BaseController return false; } + + + + + /********************************* + * Stripe OAuth + */ + + // public function initialize(InitializeStripeConnectRequest $request, string $token) + // { + + // $stripe_key = config('ninja.ninja_stripe_key'); + + // $endpoint = "https://connect.stripe.com/oauth/authorize?response_type=code&client_id={$stripe_key}&scope=read_write"; + + // return redirect($endpoint); + + // } } diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 8163eff9fe12..af167fd5a50a 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -110,7 +110,6 @@ class Kernel extends HttpKernel ShareErrorsFromSession::class, VerifyCsrfToken::class, SubstituteBindings::class, - //\App\Http\Middleware\StartupCheck::class, QueryLogging::class, ], 'shop' => [ diff --git a/app/Http/Requests/StripeConnect/InitializeStripeConnectRequest.php b/app/Http/Requests/StripeConnect/InitializeStripeConnectRequest.php index ca0bd52d201b..26f2d0e66f28 100644 --- a/app/Http/Requests/StripeConnect/InitializeStripeConnectRequest.php +++ b/app/Http/Requests/StripeConnect/InitializeStripeConnectRequest.php @@ -49,6 +49,9 @@ class InitializeStripeConnectRequest extends FormRequest */ public function getTokenContent() { + if($this->state) + $this->token = $this->state; + $data = Cache::get($this->token); return $data; diff --git a/app/Models/User.php b/app/Models/User.php index 460f8a0bb2ea..9c785ea117b1 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -179,10 +179,19 @@ class User extends Authenticatable implements MustVerifyEmail return $company_token->company; } + // return false; throw new \Exception('No Company Found'); //return Company::find(config('ninja.company_id')); } + public function companyIsSet() + { + if($this->company) + return true; + + return false; + } + /** * Returns the current company. * diff --git a/app/PaymentDrivers/Stripe/Connect/ConnectOauth.php b/app/PaymentDrivers/Stripe/Connect/ConnectOauth.php new file mode 100644 index 000000000000..951b7d2b5c31 --- /dev/null +++ b/app/PaymentDrivers/Stripe/Connect/ConnectOauth.php @@ -0,0 +1,73 @@ + 'authorization_code', + 'code' => $code, + ]); + + // Access the connected account id in the response + $connected_account_id = $response->stripe_user_id; + + return $response; + //return $connected_account_id; + } + + + /** + * Revokes access to Stripe from Invoice Ninja + * for the given account id + */ + public function revoke($account_id) + { + + Stripe::setApiKey(config('ninja.ninja_stripe_key')); + + \Stripe\OAuth::deauthorize([ + 'client_id' => config('ninja.ninja_stripe_key'), + 'stripe_user_id' => $account_id, + ]); + + } + +} + + + + + + + + + diff --git a/config/ninja.php b/config/ninja.php index da450f69b7b7..923e620c2134 100644 --- a/config/ninja.php +++ b/config/ninja.php @@ -149,6 +149,7 @@ return [ 'invoiceninja_hosted_pdf_generation' => env('NINJA_HOSTED_PDF', false), 'ninja_stripe_key' => env('NINJA_STRIPE_KEY', null), 'ninja_stripe_publishable_key' => env('NINJA_PUBLISHABLE_KEY', null), + 'ninja_stripe_client_id' => env('NINJA_STRIPE_CLIENT_ID', null), 'pdf_generator' => env('PDF_GENERATOR', false), 'internal_queue_enabled' => env('INTERNAL_QUEUE_ENABLED', true), ]; diff --git a/resources/views/auth/connect/completed.blade.php b/resources/views/auth/connect/completed.blade.php new file mode 100644 index 000000000000..3d9999add5c6 --- /dev/null +++ b/resources/views/auth/connect/completed.blade.php @@ -0,0 +1,13 @@ +@extends('layouts.ninja') +@section('meta_title', ctrans('texts.success')) + +@section('body') +
+
+ +
+ +

Connecting your account using Stripe has been successfully completed.

+ Click here to continue. +
+@endsection diff --git a/resources/views/auth/connect/existing.blade.php b/resources/views/auth/connect/existing.blade.php new file mode 100644 index 000000000000..dd9b7804ec08 --- /dev/null +++ b/resources/views/auth/connect/existing.blade.php @@ -0,0 +1,13 @@ +@extends('layouts.ninja') +@section('meta_title', ctrans('texts.success')) + +@section('body') +
+
+ +
+ +

You have already configured a Stripe Connect account.

+ Click here to continue. +
+@endsection diff --git a/resources/views/layouts/ninja.blade.php b/resources/views/layouts/ninja.blade.php new file mode 100644 index 000000000000..d0dd62b8067c --- /dev/null +++ b/resources/views/layouts/ninja.blade.php @@ -0,0 +1,115 @@ + + + + + + + @if (config('services.analytics.tracking_id')) + + + + @else + + @endif + + + + @auth() + + @endauth + + @guest + @yield('meta_title', '') — {{ config('app.name') }} + @endguest + + + + + + + + + + + + + + + + + + + + + + @livewireStyles + + {{-- Feel free to push anything to header using @push('header') --}} + @stack('head') + + + + + + + @if(session()->has('message')) +
+ {{ session('message') }} +
+ @endif + + @yield('body') + + @livewireScripts + + + + + + + + From f39bdaef7391662b09fa96dc45bb25acd39690ec Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 18 May 2021 13:28:59 +1000 Subject: [PATCH 2/4] Fixes for Stripe Connect --- app/Http/Controllers/StripeConnectController.php | 12 ++---------- app/Http/Middleware/RedirectIfAuthenticated.php | 14 ++++++++------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/app/Http/Controllers/StripeConnectController.php b/app/Http/Controllers/StripeConnectController.php index bebaf917c857..ff0a84e6f3aa 100644 --- a/app/Http/Controllers/StripeConnectController.php +++ b/app/Http/Controllers/StripeConnectController.php @@ -53,17 +53,10 @@ class StripeConnectController extends BaseController if(property_exists($config, 'account_id')) return view('auth.connect.existing'); - } - $company = Company::where('company_key', $request->getTokenContent()['company_key'])->first(); - - auth()->login($request->getContact(), true); $stripe_client_id = config('ninja.ninja_stripe_client_id'); - auth()->user()->setCompany($company); - $redirect_uri = 'http://ninja.test:8000/stripe/completed'; - $endpoint = "https://connect.stripe.com/oauth/authorize?response_type=code&client_id={$stripe_client_id}&redirect_uri={$redirect_uri}&scope=read_write&state={$token}"; return redirect($endpoint); @@ -80,9 +73,8 @@ class StripeConnectController extends BaseController ]); $company = Company::where('company_key', $request->getTokenContent()['company_key'])->first(); - auth()->user()->setCompany($company); - $company_gateway = CompanyGatewayFactory::create($company->id, auth()->user()->id); + $company_gateway = CompanyGatewayFactory::create($company->id, $company->owner()->id); $fees_and_limits = new \stdClass; $fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits; $company_gateway->gateway_key = 'd14dd26a47cecc30fdd65700bfb67b34'; @@ -114,9 +106,9 @@ class StripeConnectController extends BaseController } $company_gateway->config = encrypt(json_encode($payload)); - $company_gateway->save(); + auth()->logout(); //response here return view('auth.connect.completed'); } diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index 7800854f76bf..9ea2931d4c03 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/app/Http/Middleware/RedirectIfAuthenticated.php @@ -34,14 +34,16 @@ class RedirectIfAuthenticated } break; case 'user': - if (Auth::guard($guard)->check()) { - return redirect()->route('dashboard.index'); - } + Auth::logout(); + // if (Auth::guard($guard)->check()) { + // return redirect()->route('dashboard.index'); + // } break; default: - if (Auth::guard($guard)->check()) { - return redirect('/'); - } + Auth::logout(); + // if (Auth::guard($guard)->check()) { + // return redirect('/'); + // } break; } From d515a1ee97a0231e3d18bba2793d8632708e1fbf Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 18 May 2021 14:02:57 +1000 Subject: [PATCH 3/4] Fixes for stripe connect --- app/Http/Controllers/StripeConnectController.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/Http/Controllers/StripeConnectController.php b/app/Http/Controllers/StripeConnectController.php index ff0a84e6f3aa..e47611a51b81 100644 --- a/app/Http/Controllers/StripeConnectController.php +++ b/app/Http/Controllers/StripeConnectController.php @@ -74,7 +74,7 @@ class StripeConnectController extends BaseController $company = Company::where('company_key', $request->getTokenContent()['company_key'])->first(); - $company_gateway = CompanyGatewayFactory::create($company->id, $company->owner()->id); + $company_gateway = CompanyGatewayFactory::create($company->id, $company->id); $fees_and_limits = new \stdClass; $fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits; $company_gateway->gateway_key = 'd14dd26a47cecc30fdd65700bfb67b34'; @@ -96,19 +96,17 @@ class StripeConnectController extends BaseController /* Link account if existing account exists */ if($account_id = $this->checkAccountAlreadyLinkToEmail($company_gateway, $request->getContact()->email)) { - $config = json_decode(decrypt($company_gateway->config)); - - $company_gateway->config = encrypt(json_encode($payload)); + $payload['account_id'] = $account_id; + $company_gateway->config = $company_gateway->setConfig($payload); $company_gateway->save(); return view('auth.connect.existing'); } - $company_gateway->config = encrypt(json_encode($payload)); + $company_gateway->config = $company_gateway->setConfig($payload); $company_gateway->save(); - auth()->logout(); //response here return view('auth.connect.completed'); } From 3f373d873f7a342cab27b892b3de6c50fa09d3aa Mon Sep 17 00:00:00 2001 From: David Bomba Date: Tue, 18 May 2021 15:53:00 +1000 Subject: [PATCH 4/4] Fixes for Stripe Connect --- app/Factory/CompanyGatewayFactory.php | 2 ++ .../Controllers/StripeConnectController.php | 30 ++++++++++++------- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/app/Factory/CompanyGatewayFactory.php b/app/Factory/CompanyGatewayFactory.php index f19391ce3b78..879ce0a3b676 100644 --- a/app/Factory/CompanyGatewayFactory.php +++ b/app/Factory/CompanyGatewayFactory.php @@ -21,6 +21,8 @@ class CompanyGatewayFactory $company_gateway = new CompanyGateway; $company_gateway->company_id = $company_id; $company_gateway->user_id = $user_id; + $company_gateway->require_billing_address = false; + $company_gateway->require_shipping_address = false; // $company_gateway->fees_and_limits = new FeesAndLimits; return $company_gateway; diff --git a/app/Http/Controllers/StripeConnectController.php b/app/Http/Controllers/StripeConnectController.php index e47611a51b81..e545c16cebac 100644 --- a/app/Http/Controllers/StripeConnectController.php +++ b/app/Http/Controllers/StripeConnectController.php @@ -41,6 +41,8 @@ class StripeConnectController extends BaseController MultiDB::findAndSetDbByCompanyKey($request->getTokenContent()['company_key']); + $company = Company::where('company_key', $request->getTokenContent()['company_key'])->first(); + $company_gateway = CompanyGateway::query() ->where('gateway_key', 'd14dd26a47cecc30fdd65700bfb67b34') ->where('company_id', $request->getCompany()->id) @@ -48,7 +50,7 @@ class StripeConnectController extends BaseController if ($company_gateway) { - $config = decrypt($company_gateway->config); + $config = $company_gateway->getConfig(); if(property_exists($config, 'account_id')) return view('auth.connect.existing'); @@ -59,6 +61,12 @@ class StripeConnectController extends BaseController $redirect_uri = 'http://ninja.test:8000/stripe/completed'; $endpoint = "https://connect.stripe.com/oauth/authorize?response_type=code&client_id={$stripe_client_id}&redirect_uri={$redirect_uri}&scope=read_write&state={$token}"; + if($email = $request->getContact()->email) + $endpoint .= "&stripe_user[email]={$email}"; + + $company_name = str_replace(" ", "_", $company->present()->name()); + $endpoint .= "&stripe_user[business_name]={$company_name}"; + return redirect($endpoint); } @@ -72,6 +80,8 @@ class StripeConnectController extends BaseController 'code' => $request->input('code'), ]); + // nlog($response); + $company = Company::where('company_key', $request->getTokenContent()['company_key'])->first(); $company_gateway = CompanyGatewayFactory::create($company->id, $company->id); @@ -79,32 +89,32 @@ class StripeConnectController extends BaseController $fees_and_limits->{GatewayType::CREDIT_CARD} = new FeesAndLimits; $company_gateway->gateway_key = 'd14dd26a47cecc30fdd65700bfb67b34'; $company_gateway->fees_and_limits = $fees_and_limits; - $company_gateway->config = encrypt(json_encode([])); + $company_gateway->setConfig([]); $company_gateway->save(); $payload = [ 'account_id' => $response->stripe_user_id, "token_type" => 'bearer', - "stripe_publishable_key" => $request->input('stripe_publishable_key'), - "scope" => $request->input('scope'), - "livemode" => $request->input('livemode'), - "stripe_user_id" => $request->input('stripe_user_id'), - "refresh_token" => $request->input('refresh_token'), - "access_token" => $request->input('access_token') + "stripe_publishable_key" => $response->stripe_publishable_key, + "scope" => $response->scope, + "livemode" => $response->livemode, + "stripe_user_id" => $response->stripe_user_id, + "refresh_token" => $response->refresh_token, + "access_token" => $response->access_token ]; /* Link account if existing account exists */ if($account_id = $this->checkAccountAlreadyLinkToEmail($company_gateway, $request->getContact()->email)) { $payload['account_id'] = $account_id; - $company_gateway->config = $company_gateway->setConfig($payload); + $company_gateway->setConfig($payload); $company_gateway->save(); return view('auth.connect.existing'); } - $company_gateway->config = $company_gateway->setConfig($payload); + $company_gateway->setConfig($payload); $company_gateway->save(); //response here