1
0
mirror of https://github.com/invoiceninja/invoiceninja.git synced 2024-11-10 21:22:58 +01:00

Merge pull request #5731 from turbo124/v5-develop

Refactor for Stripe Connect
This commit is contained in:
David Bomba 2021-05-18 17:09:44 +10:00 committed by GitHub
commit 9493a43f38
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 313 additions and 38 deletions

View File

@ -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',

View File

@ -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;

View File

@ -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
@ -38,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)
@ -45,53 +50,75 @@ class StripeConnectController extends BaseController
if ($company_gateway) {
$config = decrypt($company_gateway->config);
$config = $company_gateway->getConfig();
if(property_exists($config, 'account_id'))
return render('gateways.stripe.connect.existing');
}
else
$company_gateway = CompanyGatewayFactory::create($request->getCompany()->id, $request->getContact()->id);
return view('auth.connect.existing');
/* Set Credit Card To Enabled */
$gateway_types = $company_gateway->driver(new Client)->gatewayTypes();
}
$stripe_client_id = config('ninja.ninja_stripe_client_id');
$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);
}
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'),
]);
// nlog($response);
$company = Company::where('company_key', $request->getTokenContent()['company_key'])->first();
$company_gateway = CompanyGatewayFactory::create($company->id, $company->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->setConfig([]);
$company_gateway->save();
$payload = [
'account_id' => $response->stripe_user_id,
"token_type" => 'bearer',
"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)) {
$config = json_decode(decrypt($company_gateway->config));
$config->account_id = $account_id;
$company_gateway->config = encrypt(json_encode($config));
$payload['account_id'] = $account_id;
$company_gateway->setConfig($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,
];
$account = Account::create($data);
$link = Account::link($account->id, $token);
$company_gateway->config = encrypt(json_encode(['account_id' => $account->id]));
$company_gateway->setConfig($payload);
$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);
// }
}

View File

@ -110,7 +110,6 @@ class Kernel extends HttpKernel
ShareErrorsFromSession::class,
VerifyCsrfToken::class,
SubstituteBindings::class,
//\App\Http\Middleware\StartupCheck::class,
QueryLogging::class,
],
'shop' => [

View File

@ -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;
}

View File

@ -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;

View File

@ -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.
*

View File

@ -0,0 +1,73 @@
<?php
/**
* Invoice Ninja (https://invoiceninja.com).
*
* @link https://github.com/invoiceninja/invoiceninja source repository
*
* @copyright Copyright (c) 2021. Invoice Ninja LLC (https://invoiceninja.com)
*
* @license https://opensource.org/licenses/AAL
*/
namespace App\PaymentDrivers\Stripe\Connect;
use Stripe\Stripe;
class ConnectOauth
{
/**
* Response payload
* "token_type": "bearer",
"stripe_publishable_key": "{PUBLISHABLE_KEY}",
"scope": "read_write",
"livemode": false,
"stripe_user_id": "{ACCOUNT_ID}",
"refresh_token": "{REFRESH_TOKEN}",
"access_token": "{ACCESS_TOKEN}"
*/
public function getAccountId($code)
{
Stripe::setApiKey(config('ninja.ninja_stripe_key'));
$response = \Stripe\OAuth::token([
'grant_type' => '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,
]);
}
}

View File

@ -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),
];

View File

@ -0,0 +1,13 @@
@extends('layouts.ninja')
@section('meta_title', ctrans('texts.success'))
@section('body')
<div class="flex flex-col justify-center items-center mt-10">
<div class="mb-4">
<svg height="60" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 468 222.5" xml:space="preserve"><style>.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#635bff}</style><path class="st0" d="M414 113.4c0-25.6-12.4-45.8-36.1-45.8-23.8 0-38.2 20.2-38.2 45.6 0 30.1 17 45.3 41.4 45.3 11.9 0 20.9-2.7 27.7-6.5v-20c-6.8 3.4-14.6 5.5-24.5 5.5-9.7 0-18.3-3.4-19.4-15.2h48.9c0-1.3.2-6.5.2-8.9zm-49.4-9.5c0-11.3 6.9-16 13.2-16 6.1 0 12.6 4.7 12.6 16h-25.8zM301.1 67.6c-9.8 0-16.1 4.6-19.6 7.8l-1.3-6.2h-22v116.6l25-5.3.1-28.3c3.6 2.6 8.9 6.3 17.7 6.3 17.9 0 34.2-14.4 34.2-46.1-.1-29-16.6-44.8-34.1-44.8zm-6 68.9c-5.9 0-9.4-2.1-11.8-4.7l-.1-37.1c2.6-2.9 6.2-4.9 11.9-4.9 9.1 0 15.4 10.2 15.4 23.3 0 13.4-6.2 23.4-15.4 23.4zM223.8 61.7l25.1-5.4V36l-25.1 5.3zM223.8 69.3h25.1v87.5h-25.1zM196.9 76.7l-1.6-7.4h-21.6v87.5h25V97.5c5.9-7.7 15.9-6.3 19-5.2v-23c-3.2-1.2-14.9-3.4-20.8 7.4zM146.9 47.6l-24.4 5.2-.1 80.1c0 14.8 11.1 25.7 25.9 25.7 8.2 0 14.2-1.5 17.5-3.3V135c-3.2 1.3-19 5.9-19-8.9V90.6h19V69.3h-19l.1-21.7zM79.3 94.7c0-3.9 3.2-5.4 8.5-5.4 7.6 0 17.2 2.3 24.8 6.4V72.2c-8.3-3.3-16.5-4.6-24.8-4.6C67.5 67.6 54 78.2 54 95.9c0 27.6 38 23.2 38 35.1 0 4.6-4 6.1-9.6 6.1-8.3 0-18.9-3.4-27.3-8v23.8c9.3 4 18.7 5.7 27.3 5.7 20.8 0 35.1-10.3 35.1-28.2-.1-29.8-38.2-24.5-38.2-35.7z"/></svg>
</div>
<p>Connecting your account using Stripe has been successfully completed.</p>
<span>Click <a class="font-semibold hover:underline" href="{{ url('/#/settings/company_gateways') }}">here</a> to continue.</span>
</div>
@endsection

View File

@ -0,0 +1,13 @@
@extends('layouts.ninja')
@section('meta_title', ctrans('texts.success'))
@section('body')
<div class="flex flex-col justify-center items-center mt-10">
<div class="mb-4">
<svg height="60" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" x="0" y="0" viewBox="0 0 468 222.5" xml:space="preserve"><style>.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#635bff}</style><path class="st0" d="M414 113.4c0-25.6-12.4-45.8-36.1-45.8-23.8 0-38.2 20.2-38.2 45.6 0 30.1 17 45.3 41.4 45.3 11.9 0 20.9-2.7 27.7-6.5v-20c-6.8 3.4-14.6 5.5-24.5 5.5-9.7 0-18.3-3.4-19.4-15.2h48.9c0-1.3.2-6.5.2-8.9zm-49.4-9.5c0-11.3 6.9-16 13.2-16 6.1 0 12.6 4.7 12.6 16h-25.8zM301.1 67.6c-9.8 0-16.1 4.6-19.6 7.8l-1.3-6.2h-22v116.6l25-5.3.1-28.3c3.6 2.6 8.9 6.3 17.7 6.3 17.9 0 34.2-14.4 34.2-46.1-.1-29-16.6-44.8-34.1-44.8zm-6 68.9c-5.9 0-9.4-2.1-11.8-4.7l-.1-37.1c2.6-2.9 6.2-4.9 11.9-4.9 9.1 0 15.4 10.2 15.4 23.3 0 13.4-6.2 23.4-15.4 23.4zM223.8 61.7l25.1-5.4V36l-25.1 5.3zM223.8 69.3h25.1v87.5h-25.1zM196.9 76.7l-1.6-7.4h-21.6v87.5h25V97.5c5.9-7.7 15.9-6.3 19-5.2v-23c-3.2-1.2-14.9-3.4-20.8 7.4zM146.9 47.6l-24.4 5.2-.1 80.1c0 14.8 11.1 25.7 25.9 25.7 8.2 0 14.2-1.5 17.5-3.3V135c-3.2 1.3-19 5.9-19-8.9V90.6h19V69.3h-19l.1-21.7zM79.3 94.7c0-3.9 3.2-5.4 8.5-5.4 7.6 0 17.2 2.3 24.8 6.4V72.2c-8.3-3.3-16.5-4.6-24.8-4.6C67.5 67.6 54 78.2 54 95.9c0 27.6 38 23.2 38 35.1 0 4.6-4 6.1-9.6 6.1-8.3 0-18.9-3.4-27.3-8v23.8c9.3 4 18.7 5.7 27.3 5.7 20.8 0 35.1-10.3 35.1-28.2-.1-29.8-38.2-24.5-38.2-35.7z"/></svg>
</div>
<p>You have already configured a Stripe Connect account.</p>
<span>Click <a class="font-semibold hover:underline" href="{{ url('/#/settings/company_gateways') }}">here</a> to continue.</span>
</div>
@endsection

View File

@ -0,0 +1,115 @@
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<!-- Error: {{ session('error') }} -->
@if (config('services.analytics.tracking_id'))
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-122229484-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', '{{ config('services.analytics.tracking_id') }}', {'anonymize_ip': true});
function trackEvent(category, action) {
ga('send', 'event', category, action, this.src);
}
</script>
<script>
Vue.config.devtools = true;
</script>
@else
<script>
function gtag() {
}
</script>
@endif
<!-- Title -->
@auth()
<title></title>
@endauth
@guest
<title>@yield('meta_title', '') {{ config('app.name') }}</title>
@endguest
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="@yield('meta_description')"/>
<!-- CSRF Token -->
<meta name="csrf-token" content="{{ csrf_token() }}">
<!-- Scripts -->
<script src="{{ mix('js/app.js') }}" defer></script>
<script src="https://cdn.jsdelivr.net/gh/alpinejs/alpine@v2.7.x/dist/alpine.min.js" defer></script>
<!-- Fonts -->
<link rel="dns-prefetch" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css?family=Open+Sans&display=swap" rel="stylesheet" type="text/css">
<!-- Styles -->
<link href="{{ mix('css/app.css') }}" rel="stylesheet">
<link rel="canonical" href="{{ config('ninja.site_url') }}/{{ request()->path() }}"/>
@livewireStyles
{{-- Feel free to push anything to header using @push('header') --}}
@stack('head')
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.css" />
</head>
<body class="antialiased">
@if(session()->has('message'))
<div class="py-1 text-sm text-center text-white bg-primary disposable-alert">
{{ session('message') }}
</div>
@endif
@yield('body')
@livewireScripts
<script src="https://cdn.jsdelivr.net/npm/cookieconsent@3/build/cookieconsent.min.js" data-cfasync="false"></script>
<script>
window.addEventListener("load", function(){
if (! window.cookieconsent) {
return;
}
window.cookieconsent.initialise({
"palette": {
"popup": {
"background": "#000"
},
"button": {
"background": "#f1d600"
},
},
"content": {
"href": "https://www.invoiceninja.com/privacy-policy/",
"message": "This website uses cookies to ensure you get the best experience on our website.",
"dismiss": "Got it!",
"link": "Learn more",
}
})}
);
</script>
</body>
<footer>
@yield('footer')
@stack('footer')
</footer>
</html>