From 416443e7de02177ef604523eb0fc444d15deba29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dani=C3=ABl=20van=20Drunen?= Date: Mon, 27 Jul 2020 18:09:38 +0200 Subject: [PATCH] Support upgrading of user's plan through Stripe --- .env.example | 4 ++ .env.travis | 4 ++ app/Actions/CreateStripeCheckoutAction.php | 42 +++++++++++++ app/Actions/CreateStripeCustomerAction.php | 30 +++++++++ app/Exceptions/UserStripelessException.php | 10 +++ app/Http/Controllers/SettingsController.php | 15 +++++ app/Models/User.php | 1 + composer.json | 1 + composer.lock | 62 ++++++++++++++++++- config/stripe.php | 7 +++ resources/views/settings/billing.blade.php | 11 +++- resources/views/settings/layout.blade.php | 1 + .../views/stripe_checkout_redirect.blade.php | 17 +++++ routes/web.php | 1 + 14 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 app/Actions/CreateStripeCheckoutAction.php create mode 100644 app/Actions/CreateStripeCustomerAction.php create mode 100644 app/Exceptions/UserStripelessException.php create mode 100644 config/stripe.php create mode 100644 resources/views/stripe_checkout_redirect.blade.php diff --git a/.env.example b/.env.example index c496f8eb..4f779709 100644 --- a/.env.example +++ b/.env.example @@ -37,3 +37,7 @@ SUGGESTION_BOX_ENABLED=false PLANS_ENABLED=false PLANS_STANDARD_MAXIMUM_SPACES=2 PLANS_PREMIUM_MAXIMUM_SPACES=null + +STRIPE_KEY= +STRIPE_SECRET= +STRIPE_PREMIUM_PLAN_PRICE_ID= diff --git a/.env.travis b/.env.travis index 73eeb584..91146cde 100644 --- a/.env.travis +++ b/.env.travis @@ -37,3 +37,7 @@ SUGGESTION_BOX_ENABLED=false PLANS_ENABLED=true PLANS_STANDARD_MAXIMUM_SPACES=2 PLANS_PREMIUM_MAXIMUM_SPACES=null + +STRIPE_KEY= +STRIPE_SECRET= +STRIPE_PREMIUM_PLAN_PRICE_ID= diff --git a/app/Actions/CreateStripeCheckoutAction.php b/app/Actions/CreateStripeCheckoutAction.php new file mode 100644 index 00000000..5bbf6aac --- /dev/null +++ b/app/Actions/CreateStripeCheckoutAction.php @@ -0,0 +1,42 @@ +stripe_customer_id) { + throw new UserStripelessException(); + } + + $stripe = new StripeClient(config('stripe.secret')); + + $stripeCheckout = $stripe->checkout->sessions->create([ + 'success_url' => route('settings.billing'), + 'cancel_url' => route('settings.billing'), + 'mode' => 'subscription', + 'payment_method_types' => ['card'], + 'customer' => $user->stripe_customer_id, + 'line_items' => [ + [ + 'price' => config('stripe.premium_plan_price_id'), + 'quantity' => 1 + ] + ] + ]); + + return $stripeCheckout->id; + } +} diff --git a/app/Actions/CreateStripeCustomerAction.php b/app/Actions/CreateStripeCustomerAction.php new file mode 100644 index 00000000..a2ea50bc --- /dev/null +++ b/app/Actions/CreateStripeCustomerAction.php @@ -0,0 +1,30 @@ +customers->create([ + 'name' => $user->name, + 'email' => $user->email + ]); + + $user->update([ + 'stripe_customer_id' => $customer->id + ]); + } +} diff --git a/app/Exceptions/UserStripelessException.php b/app/Exceptions/UserStripelessException.php new file mode 100644 index 00000000..e77aaa2b --- /dev/null +++ b/app/Exceptions/UserStripelessException.php @@ -0,0 +1,10 @@ + $user]); } + + public function postUpgrade(Request $request) + { + $user = $request->user(); + + if (!$user->stripe_customer_id) { + (new CreateStripeCustomerAction())->execute($user->id); + } + + $stripeCheckoutId = (new CreateStripeCheckoutAction())->execute($user->id); + + return view('stripe_checkout_redirect', ['stripeCheckoutId' => $stripeCheckoutId]); + } } diff --git a/app/Models/User.php b/app/Models/User.php index 7c0dbf24..a0f87c8c 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -15,6 +15,7 @@ class User extends Authenticatable 'password', 'verification_token', 'last_verification_mail_sent_at', + 'stripe_customer_id', 'plan' ]; diff --git a/composer.json b/composer.json index 393bda50..2e46c0bb 100644 --- a/composer.json +++ b/composer.json @@ -15,6 +15,7 @@ "laravel/tinker": "^2.0", "martinlindhe/laravel-vue-i18n-generator": "^0.1.39", "nesbot/carbon": "^2.32", + "stripe/stripe-php": "^7.44", "symfony/dom-crawler": "^5.1", "symfony/process": "^5.0" }, diff --git a/composer.lock b/composer.lock index 299f3bc7..4a302ac9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "eecd2d8d9d6ba271f2f66cc8b02e6712", + "content-hash": "89086ecf8de284c17ef7eea0461c77c2", "packages": [ { "name": "asm89/stack-cors", @@ -2318,6 +2318,63 @@ ], "time": "2020-03-29T20:13:32+00:00" }, + { + "name": "stripe/stripe-php", + "version": "v7.44.0", + "source": { + "type": "git", + "url": "https://github.com/stripe/stripe-php.git", + "reference": "b39ccc77358fbe0d462e6cc89ac01b7a0c896f35" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/stripe/stripe-php/zipball/b39ccc77358fbe0d462e6cc89ac01b7a0c896f35", + "reference": "b39ccc77358fbe0d462e6cc89ac01b7a0c896f35", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=5.6.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "2.16.1", + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5.7", + "squizlabs/php_codesniffer": "^3.3", + "symfony/process": "~3.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "psr-4": { + "Stripe\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Stripe and contributors", + "homepage": "https://github.com/stripe/stripe-php/contributors" + } + ], + "description": "Stripe PHP Library", + "homepage": "https://stripe.com/", + "keywords": [ + "api", + "payment processing", + "stripe" + ], + "time": "2020-07-20T21:25:50+00:00" + }, { "name": "swiftmailer/swiftmailer", "version": "v6.2.3", @@ -5859,5 +5916,6 @@ "platform": { "php": ">=5.6.4" }, - "platform-dev": [] + "platform-dev": [], + "plugin-api-version": "1.1.0" } diff --git a/config/stripe.php b/config/stripe.php new file mode 100644 index 00000000..9de20823 --- /dev/null +++ b/config/stripe.php @@ -0,0 +1,7 @@ + env('STRIPE_KEY'), + 'secret' => env('STRIPE_SECRET'), + 'premium_plan_price_id' => env('STRIPE_PREMIUM_PLAN_PRICE_ID') +]; diff --git a/resources/views/settings/billing.blade.php b/resources/views/settings/billing.blade.php index 0c7fe3bd..f49dacaf 100644 --- a/resources/views/settings/billing.blade.php +++ b/resources/views/settings/billing.blade.php @@ -4,7 +4,7 @@

{{ __('general.billing') }}

@endsection -@section('settings_body') +@section('settings_body_formless')
@@ -12,7 +12,14 @@
{{ ucfirst($user->plan) }}
€ 0.00
- Upgrade + @if ($user->plan === 'standard') +
+ {{ csrf_field() }} + +
+ @else + Cancel + @endif
diff --git a/resources/views/settings/layout.blade.php b/resources/views/settings/layout.blade.php index 2fbea9bb..51befb45 100644 --- a/resources/views/settings/layout.blade.php +++ b/resources/views/settings/layout.blade.php @@ -23,6 +23,7 @@ {{ csrf_field() }} @yield('settings_body') + @yield('settings_body_formless') diff --git a/resources/views/stripe_checkout_redirect.blade.php b/resources/views/stripe_checkout_redirect.blade.php new file mode 100644 index 00000000..b81ee42b --- /dev/null +++ b/resources/views/stripe_checkout_redirect.blade.php @@ -0,0 +1,17 @@ + + + + + + + diff --git a/routes/web.php b/routes/web.php index f9746385..180b1f70 100644 --- a/routes/web.php +++ b/routes/web.php @@ -122,6 +122,7 @@ Route::get('/settings/account', [SettingsController::class, 'getAccount'])->name('account'); Route::get('/settings/preferences', [SettingsController::class, 'getPreferences'])->name('preferences'); Route::get('/settings/billing', [SettingsController::class, 'getBilling'])->name('billing')->middleware('stripe'); + Route::post('/settings/billing/upgrade', [SettingsController::class, 'postUpgrade'])->name('billing.upgrade')->middleware('stripe'); Route::get('/settings/spaces', [SettingsController::class, 'getSpaces'])->name('spaces.index'); });