diff --git a/app/Http/Controllers/Oasis/SubscriptionController.php b/app/Http/Controllers/Oasis/SubscriptionController.php index 1aa6daa6..14016f14 100644 --- a/app/Http/Controllers/Oasis/SubscriptionController.php +++ b/app/Http/Controllers/Oasis/SubscriptionController.php @@ -4,11 +4,19 @@ namespace App\Http\Controllers\Oasis; use App\Http\Controllers\Controller; use App\Http\Resources\Oasis\SubscriptionRequestResource; +use App\Http\Resources\PlanResource; use App\Models\Oasis\SubscriptionRequest; +use App\Services\StripeService; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Cache; class SubscriptionController extends Controller { + public function __construct() + { + $this->stripe = resolve(StripeService::class); + } + /** * Get subscription request details * @@ -21,4 +29,41 @@ class SubscriptionController extends Controller new SubscriptionRequestResource($order), 200 ); } + + /** + * Subscribe user + * + * @param Request $request + * @param SubscriptionRequest $order + * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Contracts\Routing\ResponseFactory|\Illuminate\Http\Response + */ + public function subscribe(Request $request, SubscriptionRequest $order) + { + // Create subscription + $order->user + ->newSubscription('main', $order->requested_plan) + ->create( + $this->stripe + ->getOrSetDefaultPaymentMethod($request, $order->user) + ); + + // Get requested plan + $plan = $this->stripe + ->getPlan($order->requested_plan); + + // Update Subscription request + $order->update([ + 'status' => 'payed' + ]); + + // Update user storage limit + $order->user + ->settings() + ->update([ + 'storage_capacity' => $plan['product']['metadata']['capacity'], + 'payment_activation' => 1, + ]); + + return response('Done!', 204); + } } diff --git a/app/Http/Resources/Oasis/SubscriptionRequestResource.php b/app/Http/Resources/Oasis/SubscriptionRequestResource.php index 58afa3f8..1ff3fa97 100644 --- a/app/Http/Resources/Oasis/SubscriptionRequestResource.php +++ b/app/Http/Resources/Oasis/SubscriptionRequestResource.php @@ -43,26 +43,10 @@ class SubscriptionRequestResource extends JsonResource ] ], 'plan' => new PlanResource( - $this->get_plan($this->requested_plan) + resolve(StripeService::class)->getPlan($this->requested_plan) ), ] ], ]; } - - /** - * @param $slug - * @return mixed - */ - private function get_plan($slug) - { - if (Cache::has("plan-$slug")) { - return Cache::get("plan-$slug"); - } - - return Cache::rememberForever("plan-$slug", function () use ($slug) { - return resolve(StripeService::class) - ->getPlan($slug); - }); - } } diff --git a/app/Services/StripeService.php b/app/Services/StripeService.php index 6277e1ec..38ed899c 100644 --- a/app/Services/StripeService.php +++ b/app/Services/StripeService.php @@ -5,6 +5,7 @@ namespace App\Services; use App\Models\User; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Cache; use Illuminate\Support\Str; use Laravel\Cashier\Exceptions\IncompletePayment; use Laravel\Cashier\Exceptions\PaymentActionRequired; @@ -13,6 +14,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException; class StripeService { + /** * Stripe Service constructor. */ @@ -241,10 +243,20 @@ class StripeService */ public function getPlan($id) { - $plan = $this->stripe->plans()->find($id); - $product = $this->stripe->products()->find($plan['product']); + if (Cache::has("plan-$id")) { + return Cache::get("plan-$id"); + } - return compact('plan', 'product'); + return Cache::rememberForever("plan-$id", function () use ($id) { + + $plan = $this->stripe->plans()->find($id); + $product = $this->stripe->products()->find($plan['product']); + + return [ + 'plan' => $plan, + 'product' => $product, + ]; + }); } /** diff --git a/database/migrations/oasis/2021_03_22_094908_create_subscription_requests_table.php b/database/migrations/oasis/2021_03_22_094908_create_subscription_requests_table.php index a0c6000d..33ab6e9a 100644 --- a/database/migrations/oasis/2021_03_22_094908_create_subscription_requests_table.php +++ b/database/migrations/oasis/2021_03_22_094908_create_subscription_requests_table.php @@ -16,6 +16,7 @@ class CreateSubscriptionRequestsTable extends Migration Schema::create('subscription_requests', function (Blueprint $table) { $table->uuid('id')->primary()->index(); $table->uuid('user_id')->index(); + $table->string('creator'); $table->string('requested_plan'); $table->enum('status', ['requested', 'payed', 'cancelled'])->default('requested'); $table->timestamps(); diff --git a/routes/oasis.php b/routes/oasis.php index d5130070..45aae97f 100644 --- a/routes/oasis.php +++ b/routes/oasis.php @@ -10,3 +10,4 @@ Route::group(['middleware' => 'auth:sanctum', 'prefix' => 'admin'], function () }); Route::get('/subscription-request/{order}', [SubscriptionController::class, 'get_subscription_request']); +Route::post('/subscribe/{order}', [SubscriptionController::class, 'subscribe']); diff --git a/tests/Feature/Oasis/OasisSubscriptionTest.php b/tests/Feature/Oasis/OasisSubscriptionTest.php index df2c4fd6..ed58f3dd 100644 --- a/tests/Feature/Oasis/OasisSubscriptionTest.php +++ b/tests/Feature/Oasis/OasisSubscriptionTest.php @@ -3,13 +3,52 @@ namespace Tests\Feature\Oasis; use App\Models\User; +use Cartalyst\Stripe\Stripe; use Illuminate\Foundation\Testing\DatabaseMigrations; +use Laravel\Cashier\Subscription; use Tests\TestCase; class OasisSubscriptionTest extends TestCase { use DatabaseMigrations; + private $plan; + + private $billing; + + public function __construct() + { + parent::__construct(); + + // Define test plan to subscribe + $this->plan = [ + 'data' => [ + 'id' => "virtualni-sanon-basic", + 'type' => "plans", + 'attributes' => [ + 'name' => "Virtuální šanon BASIC", + 'description' => "Obsahuje 5 GB pro Vaše firemní data, 577 Kč (bez DPH). Cena zahrnuje i pojištění v hodnotě 50 Kč (pojištění obsahuje možnost obnovy dat z minulosti - verzování)", + 'price' => "CZK 699.00", + 'capacity' => 50, + 'capacity_formatted' => "50GB", + 'currency' => "CZK", + 'tax_rates' => [], + ], + ], + ]; + + // Define test billing to subscribe + $this->billing = [ + 'billing_address' => '2794 Alfreda Mount Suite 467 East Crystalberg', + 'billing_city' => 'Christianfort', + 'billing_country' => 'SK', + 'billing_name' => 'Heidi Romaguera PhD', + 'billing_phone_number' => '+421', + 'billing_postal_code' => '59445', + 'billing_state' => 'SK', + ]; + } + /** * @test */ @@ -31,4 +70,60 @@ class OasisSubscriptionTest extends TestCase 'requested_plan' => 'virtualni-sanon-basic', ]); } + + /** + * @test + */ + public function it_subscribe_user_and_pay_for_it() + { + $user = User::factory(User::class) + ->create(['role' => 'user']); + + $user + ->subscriptionRequest() + ->create([ + 'requested_plan' => 'virtualni-sanon-basic', + ]); + + // Register payment method + $stripe = Stripe::make(config('cashier.secret'), '2020-03-02'); + + // Create test payment method + $paymentMethod = $stripe->paymentMethods()->create([ + 'type' => 'card', + 'card' => [ + 'number' => '4242424242424242', + 'exp_month' => 11, + 'exp_year' => 2022, + 'cvc' => '123' + ], + ]); + + // Create stripe customer + $user->createOrGetStripeCustomer(); + + $this->postJson("/api/oasis/subscribe/{$user->subscriptionRequest->id}", [ + 'billing' => $this->billing, + 'plan' => $this->plan, + 'payment' => [ + 'meta' => [ + 'pm' => $paymentMethod['id'] + ], + ], + ])->assertStatus(204); + + $this->assertDatabaseHas('subscriptions', [ + 'stripe_status' => 'active' + ]); + + $this->assertDatabaseHas('user_settings', [ + 'storage_capacity' => 50, + 'payment_activation' => 1, + ]); + + $this->assertDatabaseMissing('users', [ + 'stripe_id' => null, + 'card_brand' => null, + ]); + } }