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:
commit
9493a43f38
@ -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',
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
// }
|
||||
}
|
||||
|
@ -110,7 +110,6 @@ class Kernel extends HttpKernel
|
||||
ShareErrorsFromSession::class,
|
||||
VerifyCsrfToken::class,
|
||||
SubstituteBindings::class,
|
||||
//\App\Http\Middleware\StartupCheck::class,
|
||||
QueryLogging::class,
|
||||
],
|
||||
'shop' => [
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
*
|
||||
|
73
app/PaymentDrivers/Stripe/Connect/ConnectOauth.php
Normal file
73
app/PaymentDrivers/Stripe/Connect/ConnectOauth.php
Normal 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,
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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),
|
||||
];
|
||||
|
13
resources/views/auth/connect/completed.blade.php
Normal file
13
resources/views/auth/connect/completed.blade.php
Normal 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
|
13
resources/views/auth/connect/existing.blade.php
Normal file
13
resources/views/auth/connect/existing.blade.php
Normal 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
|
115
resources/views/layouts/ninja.blade.php
Normal file
115
resources/views/layouts/ninja.blade.php
Normal 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>
|
Loading…
Reference in New Issue
Block a user