Commit 07551703 authored by Dylan Griffith's avatar Dylan Griffith

Merge branch '321364-implement-new-plan-constants' into 'master'

Use new plan constants in Plan/Namespace logic

See merge request gitlab-org/gitlab!54191
parents 61a32e5e f7af9f81
......@@ -85,7 +85,7 @@ module BillingPlansHelper
end
def show_plans?(namespace)
namespace.trial_active? || !namespace.gold_plan?
namespace.trial_active? || !(namespace.gold_plan? || namespace.ultimate_plan?)
end
def show_trial_banner?(namespace)
......
......@@ -290,21 +290,21 @@ module EE
end
# For now, we are not billing for members with a Guest role for subscriptions
# with a Gold plan. The other plans will treat Guest members as a regular member
# with a Gold/Ultimate plan. The other plans will treat Guest members as a regular member
# for billing purposes.
#
# We are plucking the user_ids from the "Members" table in an array and
# converting the array of user_ids to a Set which will have unique user_ids.
def billed_user_ids(requested_hosted_plan = nil)
if [actual_plan_name, requested_hosted_plan].include?(::Plan::GOLD)
strong_memoize(:gold_billed_user_ids) do
if ([actual_plan_name, requested_hosted_plan] & [::Plan::GOLD, ::Plan::ULTIMATE]).any?
strong_memoize(:billed_user_ids) do
(billed_group_members.non_guests.distinct.pluck(:user_id) +
billed_project_members.non_guests.distinct.pluck(:user_id) +
billed_shared_non_guests_group_members.non_guests.distinct.pluck(:user_id) +
billed_invited_non_guests_group_to_project_members.non_guests.distinct.pluck(:user_id)).to_set
end
else
strong_memoize(:non_gold_billed_user_ids) do
strong_memoize(:non_billed_user_ids) do
(billed_group_members.distinct.pluck(:user_id) +
billed_project_members.distinct.pluck(:user_id) +
billed_shared_group_members.distinct.pluck(:user_id) +
......
......@@ -11,13 +11,13 @@ module EE
include ::Gitlab::Utils::StrongMemoize
NAMESPACE_PLANS_TO_LICENSE_PLANS = {
::Plan::BRONZE => License::STARTER_PLAN,
::Plan::SILVER => License::PREMIUM_PLAN,
::Plan::GOLD => License::ULTIMATE_PLAN
::Plan::BRONZE => License::STARTER_PLAN,
[::Plan::SILVER, ::Plan::PREMIUM] => License::PREMIUM_PLAN,
[::Plan::GOLD, ::Plan::ULTIMATE] => License::ULTIMATE_PLAN
}.freeze
LICENSE_PLANS_TO_NAMESPACE_PLANS = NAMESPACE_PLANS_TO_LICENSE_PLANS.invert.freeze
PLANS = (NAMESPACE_PLANS_TO_LICENSE_PLANS.keys + [Plan::FREE]).freeze
PLANS = (NAMESPACE_PLANS_TO_LICENSE_PLANS.keys + [Plan::FREE]).flatten.freeze
TEMPORARY_STORAGE_INCREASE_DAYS = 30
prepended do
......@@ -108,7 +108,7 @@ module EE
extend ::Gitlab::Utils::Override
def plans_with_feature(feature)
LICENSE_PLANS_TO_NAMESPACE_PLANS.values_at(*License.plans_with_feature(feature))
LICENSE_PLANS_TO_NAMESPACE_PLANS.values_at(*License.plans_with_feature(feature)).flatten
end
end
......@@ -334,10 +334,18 @@ module EE
actual_plan_name == ::Plan::SILVER
end
def premium_plan?
actual_plan_name == ::Plan::PREMIUM
end
def gold_plan?
actual_plan_name == ::Plan::GOLD
end
def ultimate_plan?
actual_plan_name == ::Plan::ULTIMATE
end
def plan_eligible_for_trial?
::Plan::PLANS_ELIGIBLE_FOR_TRIAL.include?(actual_plan_name)
end
......
......@@ -9,10 +9,12 @@ module EE
FREE = 'free'.freeze
BRONZE = 'bronze'.freeze
SILVER = 'silver'.freeze
PREMIUM = 'premium'.freeze
GOLD = 'gold'.freeze
ULTIMATE = 'ultimate'.freeze
EE_DEFAULT_PLANS = (const_get(:DEFAULT_PLANS, false) + [FREE]).freeze
PAID_HOSTED_PLANS = [BRONZE, SILVER, GOLD].freeze
PAID_HOSTED_PLANS = [BRONZE, SILVER, PREMIUM, GOLD, ULTIMATE].freeze
EE_ALL_PLANS = (EE_DEFAULT_PLANS + PAID_HOSTED_PLANS).freeze
PLANS_ELIGIBLE_FOR_TRIAL = EE_DEFAULT_PLANS
......
......@@ -357,8 +357,8 @@ module EE
end
def owns_upgradeable_namespace?
!owns_paid_namespace?(plans: [::Plan::GOLD]) &&
owns_paid_namespace?(plans: [::Plan::BRONZE, ::Plan::SILVER])
!owns_paid_namespace?(plans: [::Plan::GOLD, ::Plan::ULTIMATE]) &&
owns_paid_namespace?(plans: [::Plan::BRONZE, ::Plan::SILVER, ::Plan::PREMIUM])
end
# Returns the groups a user has access to, either through a membership or a project authorization
......
......@@ -86,6 +86,8 @@ class GitlabSubscription < ApplicationRecord
end
def upgradable?
return false if [::Plan::GOLD, ::Plan::ULTIMATE].include?(plan_name)
has_a_paid_hosted_plan? &&
!expired? &&
plan_name != Plan::PAID_HOSTED_PLANS[-1]
......
......@@ -42,8 +42,16 @@ FactoryBot.define do
association :hosted_plan, factory: :silver_plan
end
trait :premium do
association :hosted_plan, factory: :premium_plan
end
trait :gold do
association :hosted_plan, factory: :gold_plan
end
trait :ultimate do
association :hosted_plan, factory: :ultimate_plan
end
end
end
......@@ -326,13 +326,15 @@ RSpec.describe EE::UserCalloutsHelper do
shared_examples 'shows and hides the banner depending on circumstances' do
where(:show_billing_eoa_banner, :actual_plan_name, :dismissed_callout, :travel_to_date, :result) do
true | ::Plan::BRONZE | false | eoa_bronze_plan_end_date - 1.day | true
true | ::Plan::BRONZE | false | eoa_bronze_plan_end_date | false
true | ::Plan::BRONZE | false | eoa_bronze_plan_end_date + 1.day | false
true | ::Plan::BRONZE | true | eoa_bronze_plan_end_date - 1.day | false
true | ::Plan::SILVER | false | eoa_bronze_plan_end_date - 1.day | false
true | ::Plan::GOLD | false | eoa_bronze_plan_end_date - 1.day | false
false | ::Plan::BRONZE | false | eoa_bronze_plan_end_date - 1.day | false
true | ::Plan::BRONZE | false | eoa_bronze_plan_end_date - 1.day | true
true | ::Plan::BRONZE | false | eoa_bronze_plan_end_date | false
true | ::Plan::BRONZE | false | eoa_bronze_plan_end_date + 1.day | false
true | ::Plan::BRONZE | true | eoa_bronze_plan_end_date - 1.day | false
true | ::Plan::SILVER | false | eoa_bronze_plan_end_date - 1.day | false
true | ::Plan::PREMIUM | false | eoa_bronze_plan_end_date - 1.day | false
true | ::Plan::GOLD | false | eoa_bronze_plan_end_date - 1.day | false
true | ::Plan::ULTIMATE | false | eoa_bronze_plan_end_date - 1.day | false
false | ::Plan::BRONZE | false | eoa_bronze_plan_end_date - 1.day | false
end
with_them do
......
......@@ -6,6 +6,8 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do
include ActionView::Helpers::SanitizeHelper
describe 'message' do
using RSpec::Parameterized::TableSyntax
subject { strip_tags(message) }
let(:subscribable) { double(:license) }
......@@ -22,238 +24,246 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do
let(:grace_period_effective_from) { expired_date - 35.days }
let(:today) { Time.utc(2020, 3, 7, 10) }
let(:expired_date) { Time.utc(2020, 3, 9, 10).to_date }
let(:plan_name) { ::Plan::GOLD }
before do
allow_any_instance_of(Gitlab::ExpiringSubscriptionMessage).to receive(:grace_period_effective_from).and_return(grace_period_effective_from)
end
around do |example|
travel_to(today) do
example.run
end
where(:plan_name) do
[
[::Plan::GOLD],
[::Plan::ULTIMATE]
]
end
context 'subscribable installed' do
let(:auto_renew) { false }
with_them do
before do
allow(subscribable).to receive(:plan).and_return(plan_name)
allow(subscribable).to receive(:expires_at).and_return(expired_date)
allow(subscribable).to receive(:auto_renew).and_return(auto_renew)
allow_any_instance_of(Gitlab::ExpiringSubscriptionMessage).to receive(:grace_period_effective_from).and_return(grace_period_effective_from)
end
context 'subscribable should not notify admins' do
it 'returns nil' do
allow(subscribable).to receive(:notify_admins?).and_return(false)
allow(subscribable).to receive(:notify_users?).and_return(false)
expect(subject).to be nil
around do |example|
travel_to(today) do
example.run
end
end
context 'subscribable should notify admins' do
context 'subscribable installed' do
let(:auto_renew) { false }
before do
allow(subscribable).to receive(:notify_admins?).and_return(true)
allow(subscribable).to receive(:plan).and_return(plan_name)
allow(subscribable).to receive(:expires_at).and_return(expired_date)
allow(subscribable).to receive(:auto_renew).and_return(auto_renew)
end
context 'admin signed in' do
let(:signed_in) { true }
let(:is_admin) { true }
context 'subscribable should not notify admins' do
it 'returns nil' do
allow(subscribable).to receive(:notify_admins?).and_return(false)
allow(subscribable).to receive(:notify_users?).and_return(false)
expect(subject).to be nil
end
end
context 'subscribable expired' do
let(:expired_date) { Time.utc(2020, 3, 1, 10).to_date }
context 'subscribable should notify admins' do
before do
allow(subscribable).to receive(:notify_admins?).and_return(true)
end
before do
allow(subscribable).to receive(:expired?).and_return(true)
allow(subscribable).to receive(:expires_at).and_return(expired_date)
end
context 'admin signed in' do
let(:signed_in) { true }
let(:is_admin) { true }
context 'subscribable expired' do
let(:expired_date) { Time.utc(2020, 3, 1, 10).to_date }
context 'when it blocks changes' do
before do
allow(subscribable).to receive(:will_block_changes?).and_return(true)
allow(subscribable).to receive(:expired?).and_return(true)
allow(subscribable).to receive(:expires_at).and_return(expired_date)
end
context 'when it is currently blocking changes' do
let(:plan_name) { ::Plan::FREE }
context 'when it blocks changes' do
before do
allow(subscribable).to receive(:block_changes?).and_return(true)
allow(subscribable).to receive(:block_changes_at).and_return(expired_date)
allow(subscribable).to receive(:will_block_changes?).and_return(true)
end
context "when the subscription hasn't been properly downgraded yet" do
let(:plan_name) { ::Plan::SILVER }
context 'when it is currently blocking changes' do
let(:plan_name) { ::Plan::FREE }
it "shows the expiring message" do
expect(subject).to include('Your subscription expired! No worries, you can still use all the Silver features for now. You have 0 days to renew your subscription.')
before do
allow(subscribable).to receive(:block_changes?).and_return(true)
allow(subscribable).to receive(:block_changes_at).and_return(expired_date)
end
end
it 'has a nice subject' do
expect(subject).to include('Your subscription has been downgraded.')
end
context "when the subscription hasn't been properly downgraded yet" do
let(:plan_name) { ::Plan::PREMIUM }
context 'no namespace' do
it 'has an expiration blocking message' do
expect(subject).to include("You didn't renew your subscription so it was downgraded to the GitLab Core Plan")
it "shows the expiring message" do
expect(subject).to include('Your subscription expired! No worries, you can still use all the Premium features for now. You have 0 days to renew your subscription.')
end
end
end
context 'with namespace' do
let(:namespace) { double(:namespace, name: 'No Limit Records') }
it 'has a nice subject' do
expect(subject).to include('Your subscription has been downgraded.')
end
it 'has an expiration blocking message' do
expect(subject).to include("You didn't renew your subscription for No Limit Records so it was downgraded to the free plan")
context 'no namespace' do
it 'has an expiration blocking message' do
expect(subject).to include("You didn't renew your subscription so it was downgraded to the GitLab Core Plan")
end
end
context 'is auto_renew' do
let(:auto_renew) { true }
context 'with namespace' do
let(:namespace) { double(:namespace, name: 'No Limit Records') }
it 'has a nice subject' do
expect(subject).to include('Something went wrong with your automatic subscription renewal')
it 'has an expiration blocking message' do
expect(subject).to include("You didn't renew your subscription for No Limit Records so it was downgraded to the free plan")
end
it 'has an expiration blocking message' do
expect(subject).to include("We tried to automatically renew your subscription for No Limit Records on 2020-03-01 but something went wrong so your subscription was downgraded to the free plan. Don't worry, your data is safe. We suggest you check your payment method and get in touch with our support team (support@gitlab.com). They'll gladly help with your subscription renewal.")
context 'is auto_renew' do
let(:auto_renew) { true }
it 'has a nice subject' do
expect(subject).to include('Something went wrong with your automatic subscription renewal')
end
it 'has an expiration blocking message' do
expect(subject).to include("We tried to automatically renew your subscription for No Limit Records on 2020-03-01 but something went wrong so your subscription was downgraded to the free plan. Don't worry, your data is safe. We suggest you check your payment method and get in touch with our support team (support@gitlab.com). They'll gladly help with your subscription renewal.")
end
end
end
end
end
context 'when it is not currently blocking changes' do
let(:plan_name) { ::Plan::GOLD }
context 'when it is not currently blocking changes' do
let(:plan_name) { ::Plan::ULTIMATE }
before do
allow(subscribable).to receive(:block_changes?).and_return(false)
allow(subscribable).to receive(:block_changes_at).and_return((today + 4.days).to_date)
end
before do
allow(subscribable).to receive(:block_changes?).and_return(false)
allow(subscribable).to receive(:block_changes_at).and_return((today + 4.days).to_date)
end
it 'has a nice subject' do
allow(subscribable).to receive(:will_block_changes?).and_return(false)
it 'has a nice subject' do
allow(subscribable).to receive(:will_block_changes?).and_return(false)
expect(subject).to include('Your subscription expired!')
end
expect(subject).to include('Your subscription expired!')
end
it 'has an expiration blocking message' do
allow(subscribable).to receive(:block_changes_at).and_return(Time.utc(2020, 3, 9, 10).to_date)
allow(subscribable).to receive(:is_a?).with(::License).and_return(true)
it 'has an expiration blocking message' do
allow(subscribable).to receive(:block_changes_at).and_return(Time.utc(2020, 3, 9, 10).to_date)
allow(subscribable).to receive(:is_a?).with(::License).and_return(true)
expect(subject).to include('No worries, you can still use all the Gold features for now. You have 2 days to renew your subscription.')
expect(subject).to include('No worries, you can still use all the Ultimate features for now. You have 2 days to renew your subscription.')
end
end
end
end
end
context 'subscribable is expiring soon' do
before do
allow(subscribable).to receive(:expired?).and_return(false)
allow(subscribable).to receive(:will_block_changes?).and_return(true)
allow(subscribable).to receive(:block_changes_at).and_return(expired_date)
end
it 'has a nice subject' do
expect(subject).to include('Your subscription will expire in 2 days')
end
context 'subscribable is expiring soon' do
before do
allow(subscribable).to receive(:expired?).and_return(false)
allow(subscribable).to receive(:will_block_changes?).and_return(true)
allow(subscribable).to receive(:block_changes_at).and_return(expired_date)
end
context 'without namespace' do
it 'has an expiration blocking message' do
expect(subject).to include('Your Gold subscription will expire on 2020-03-09. After that, you will not be able to create issues or merge requests as well as many other features.')
it 'has a nice subject' do
expect(subject).to include('Your subscription will expire in 2 days')
end
end
context 'when a future dated license is applied' do
before do
create(:license, created_at: Time.current, data: build(:gitlab_license, starts_at: expired_date, expires_at: Date.current + 13.months).export)
context 'without namespace' do
it 'has an expiration blocking message' do
expect(subject).to include("Your #{plan_name.capitalize} subscription will expire on 2020-03-09. After that, you will not be able to create issues or merge requests as well as many other features.")
end
end
it 'returns nil' do
expect(subject).to be nil
context 'when a future dated license is applied' do
before do
create(:license, created_at: Time.current, data: build(:gitlab_license, starts_at: expired_date, expires_at: Date.current + 13.months).export)
end
it 'returns nil' do
expect(subject).to be nil
end
end
end
context 'with namespace' do
let(:namespace) { double(:namespace, name: 'No Limit Records') }
context 'with namespace' do
let(:namespace) { double(:namespace, name: 'No Limit Records') }
it 'has gold plan specific messaging' do
allow(subscribable).to receive(:plan).and_return('gold')
it 'has gold plan specific messaging' do
allow(subscribable).to receive(:plan).and_return('gold')
expect(subject).to include('Your Gold subscription for No Limit Records will expire on 2020-03-09. After that, you will not be able to use merge approvals or epics as well as many security features.')
end
expect(subject).to include('Your Gold subscription for No Limit Records will expire on 2020-03-09. After that, you will not be able to use merge approvals or epics as well as many security features.')
end
it 'has silver plan specific messaging' do
allow(subscribable).to receive(:plan).and_return('silver')
it 'has silver plan specific messaging' do
allow(subscribable).to receive(:plan).and_return('silver')
expect(subject).to include('Your Silver subscription for No Limit Records will expire on 2020-03-09. After that, you will not be able to use merge approvals or epics as well as many other features.')
end
expect(subject).to include('Your Silver subscription for No Limit Records will expire on 2020-03-09. After that, you will not be able to use merge approvals or epics as well as many other features.')
end
it 'has bronze plan specific messaging' do
allow(subscribable).to receive(:plan).and_return('bronze')
it 'has bronze plan specific messaging' do
allow(subscribable).to receive(:plan).and_return('bronze')
expect(subject).to include('Your Bronze subscription for No Limit Records will expire on 2020-03-09. After that, you will not be able to use merge approvals or code quality as well as many other features.')
end
expect(subject).to include('Your Bronze subscription for No Limit Records will expire on 2020-03-09. After that, you will not be able to use merge approvals or code quality as well as many other features.')
end
context 'is auto_renew nil' do
let(:auto_renew) { nil }
context 'is auto_renew nil' do
let(:auto_renew) { nil }
it 'returns nil' do
expect(subject).to be nil
it 'returns nil' do
expect(subject).to be nil
end
end
end
context 'is auto_renew' do
let(:auto_renew) { true }
context 'is auto_renew' do
let(:auto_renew) { true }
it 'returns nil' do
expect(subject).to be nil
it 'returns nil' do
expect(subject).to be nil
end
end
end
end
end
context 'subscribable expired a long time ago' do
let(:expired_date) { today.to_date - 1.year }
let(:grace_period_effective_from) { today.to_date - 25.days }
before do
allow(subscribable).to receive(:expires_at).and_return(expired_date)
allow(subscribable).to receive(:block_changes_at).and_return(expired_date)
allow(subscribable).to receive(:expired?).and_return(true)
allow(subscribable).to receive(:will_block_changes?).and_return(true)
allow(subscribable).to receive(:block_changes?).and_return(true)
allow(subscribable).to receive(:plan).and_return('free')
end
context 'subscribable expired a long time ago' do
let(:expired_date) { today.to_date - 1.year }
let(:grace_period_effective_from) { today.to_date - 25.days }
context 'and is past the cutoff date' do
let(:grace_period_effective_from) { today.to_date - 40.days }
before do
allow(subscribable).to receive(:expires_at).and_return(expired_date)
allow(subscribable).to receive(:block_changes_at).and_return(expired_date)
allow(subscribable).to receive(:expired?).and_return(true)
allow(subscribable).to receive(:will_block_changes?).and_return(true)
allow(subscribable).to receive(:block_changes?).and_return(true)
allow(subscribable).to receive(:plan).and_return('free')
end
it 'has a nice subject' do
expect(subject).to include('Your subscription has been downgraded')
context 'and is past the cutoff date' do
let(:grace_period_effective_from) { today.to_date - 40.days }
it 'has a nice subject' do
expect(subject).to include('Your subscription has been downgraded')
end
end
end
context 'and is 30 days past the cutoff date' do
let(:grace_period_effective_from) { today.to_date - 60.days }
context 'and is 30 days past the cutoff date' do
let(:grace_period_effective_from) { today.to_date - 60.days }
it 'stops displaying' do
expect(subject).to be nil
it 'stops displaying' do
expect(subject).to be nil
end
end
end
context 'and not past the cutoff date' do
it 'has a nice subject' do
expect(subject).to include('Your subscription will expire in 5 days')
context 'and not past the cutoff date' do
it 'has a nice subject' do
expect(subject).to include('Your subscription will expire in 5 days')
end
end
end
end
end
end
end
context 'no subscribable installed' do
let(:subscribable) { nil }
context 'no subscribable installed' do
let(:subscribable) { nil }
it { is_expected.to be_blank }
it { is_expected.to be_blank }
end
end
end
end
......@@ -196,11 +196,13 @@ RSpec.describe Namespace do
subject { described_class.in_default_plan.ids }
where(:plan_name, :expect_in_default_plan) do
::Plan::FREE | true
::Plan::DEFAULT | true
::Plan::BRONZE | false
::Plan::SILVER | false
::Plan::GOLD | false
::Plan::FREE | true
::Plan::DEFAULT | true
::Plan::BRONZE | false
::Plan::SILVER | false
::Plan::PREMIUM | false
::Plan::GOLD | false
::Plan::ULTIMATE | false
end
with_them do
......@@ -263,12 +265,23 @@ RSpec.describe Namespace do
end
context 'in active trial gold plan' do
before do
create :gitlab_subscription, ::Plan::GOLD, :active_trial, namespace: namespace
create :gitlab_subscription, ::Plan::GOLD, :active_trial, namespace: sub_namespace
using RSpec::Parameterized::TableSyntax
where(:plan_name) do
[
[::Plan::GOLD],
[::Plan::ULTIMATE]
]
end
it { is_expected.to eq([namespace.id]) }
with_them do
before do
create :gitlab_subscription, plan_name, :active_trial, namespace: namespace
create :gitlab_subscription, plan_name, :active_trial, namespace: sub_namespace
end
it { is_expected.to eq([namespace.id]) }
end
end
context 'with a paid plan and not in trial' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment