Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Fix feature sync #136

Merged
merged 3 commits into from
Aug 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions src/Models/PlanSubscription.php
Original file line number Diff line number Diff line change
Expand Up @@ -326,17 +326,13 @@ public function syncPlanFeatures(Plan $plan = null): PlanSubscription
*/
private function deleteFeaturesNotInPlan(Plan $plan)
{
// Retrieve current features that are not related to a plan
$featuresWithPlan = $this->features()->withoutPlan()->get();
// Retrieve current subscription features tags
$subscriptionFeatureTags = $this->features()->get()->pluck('tag');
// Retrieve desired plan features tags
$planFeatureTags = $plan->features()->pluck('tag');

// Retrieve selected plan features
$planFeatures = $plan->features();

// Use tags to find which features are no longer in selected plan
$featuresWithPlanTags = $featuresWithPlan->pluck('tag');
$planFeatureTags = $planFeatures->pluck('tag');

$featuresWithoutPlan = $featuresWithPlanTags->diff($planFeatureTags);
// Use those tags to get which features are not in desired plan
$featuresWithoutPlan = $subscriptionFeatureTags->diff($planFeatureTags);

// Delete not found features
$this->features()->whereIn('tag', $featuresWithoutPlan->all())->delete();
Expand Down
85 changes: 85 additions & 0 deletions tests/Unit/PlanSubscriptionFeatureTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,89 @@ public function testSyncOneSubscriptionFeature()
$this->assertTrue($feature->value === $feature->subscription->plan->getFeatureByTag($feature->tag)->value);
}

/**
* Consume all of a feature and check if it can be used
*/
public function testConsumeAllFeature()
{
$this->testUser->subscription('main')->recordFeatureUsage('social_cat_profiles', 10);
$this->assertFalse($this->testUser->subscription('main')->canUseFeature('social_cat_profiles'));
}

/**
* Consume all of a feature and renew
*/
public function testConsumeAllFeatureAndRenew()
{
$this->testUser->subscription('main')->recordFeatureUsage('social_cat_profiles', 10);
$this->testUser->subscription('main')->renew();
$this->assertFalse($this->testUser->subscription('main')->canUseFeature('social_cat_profiles'));
}

/**
* Consume all of a feature and check next period
*/
public function testRenewToNextPeriodAndThenUseFeature()
{
$this->testUser->subscription('main')->renew();
$usage = $this->testUser->subscription('main')->recordFeatureUsage('social_cat_profiles', 1);
$this->assertTrue($usage->used === 1);
}

/**
* Cancel subscription immediately and check for usage
*/
public function testImmediateCancelSubscriptionAndThenUseFeature()
{
$this->testUser->subscription('main')->cancel(true);
$this->assertFalse($this->testUser->subscription('main')->canUseFeature('social_cat_profiles'));
}

/**
* Cancel subscription and check for usage
*/
public function testCancelSubscriptionAndThenUseFeature()
{
$this->testUser->subscription('main')->cancel();
$this->assertTrue($this->testUser->subscription('main')->canUseFeature('social_cat_profiles'));
}

/**
* Cancel subscription and check for usage next period
*/
public function testCancelSubscriptionThenMoveToNextPeriodAndThenUseFeature()
{
$this->testUser->subscription('main')->cancel();
// Travel 1 second after end of subscription
$this->travelTo($this->testUser->subscription('main')->ends_at->addSecond());
$this->assertFalse($this->testUser->subscription('main')->canUseFeature('social_cat_profiles'));
}

/**
* Test use attached feature without plan relation
*/
public function testCanUseFeatureNotExistingInPlan()
{
$this->assertTrue($this->testUser->subscription('main')->canUseFeature('social_cat_profiles'));
}

/**
* Test use attached feature existing in current related plan
*/
public function testCannotUseFeatureExistingInCurrentRelatedPlan()
{
$this->expectException('Illuminate\Database\QueryException');
$this->expectExceptionMessage('UNIQUE constraint failed');
$this->testUser->subscription('main')->features()->create(['tag' => 'social_profiles', 'name' => 'Social profiles', 'value' => 10, 'sort_order' => 10]);
}

/**
* Test deletion of features not in synced plan
*/
public function testDeleteAttachedFeatures()
{
$this->testUser->subscription('main')->features()->create(['tag' => 'attached_feature', 'name' => 'An attached feature that does not exist in plan.', 'value' => 10, 'sort_order' => 10]);
$this->testUser->subscription('main')->syncPlanFeatures($this->testPlanBasic);
$this->assertEmpty($this->testUser->subscription('main')->features()->withoutPlan()->get());
}
}
130 changes: 0 additions & 130 deletions tests/Unit/PlanSubscriptionFeatureWithoutPlanUsageTest.php

This file was deleted.

41 changes: 41 additions & 0 deletions tests/Unit/PlanSubscriptionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\QueryException;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Config;

class PlanSubscriptionTest extends TestCase
{
Expand Down Expand Up @@ -130,4 +131,44 @@ public function testNonExistingSubscriptionException()
$this->expectException('Bpuig\Subby\Exceptions\InvalidPlanSubscription');
$this->testUser->subscription('secondary');
}

/**
* Cancel subscription without fallback plan
*/
public function testCancelSubscriptionWithoutFallbackPlan()
{
Config::set('subby.fallback_plan_tag', null);
$this->testUser->subscription('main')->cancel();
$this->assertNotNull($this->testUser->subscription('main')->canceled_at);
}

/**
* Cancel subscription with fallback plan
*/
public function testCancelSubscriptionWithFallbackPlan()
{
Config::set('subby.fallback_plan_tag', 'pro');
$this->testUser->subscription('main')->cancel();
$this->assertTrue($this->testUser->subscription('main')->plan->tag === 'pro');
}

/**
* Cancel subscription with a fallback plan that does not exist
*/
public function testCancelSubscriptionWithInexistentFallbackPlan()
{
Config::set('subby.fallback_plan_tag', 'super-pro');
$this->expectException('UnexpectedValueException');
$this->testUser->subscription('main')->cancel();
}

/**
* Cancel subscription with fallback plan and ignore it
*/
public function testCancelSubscriptionAndIgnoreFallbackPlan()
{
Config::set('subby.fallback_plan_tag', 'pro');
$this->testUser->subscription('main')->cancel(false, true);
$this->assertTrue($this->testUser->subscription('main')->plan->tag === 'basic');
}
}