Commit eb63e456 authored by Illya Klymov's avatar Illya Klymov

Merge branch '211423-expose-a-portion-of-free-com-users-to-the-new-purchase-flow' into 'master'

Expose some free users to new purchase flow

See merge request gitlab-org/gitlab!29232
parents 76a8a8c7 4ee0f178
...@@ -175,6 +175,10 @@ class Namespace < ApplicationRecord ...@@ -175,6 +175,10 @@ class Namespace < ApplicationRecord
kind == 'user' kind == 'user'
end end
def group?
type == 'Group'
end
def find_fork_of(project) def find_fork_of(project)
return unless project.fork_network return unless project.fork_network
......
...@@ -23,9 +23,24 @@ const determineSelectedPlan = (planId, plans) => { ...@@ -23,9 +23,24 @@ const determineSelectedPlan = (planId, plans) => {
return plans[0] && plans[0].value; return plans[0] && plans[0].value;
}; };
const determineNumberOfUsers = (groupId, groups) => {
if (!groupId || !groups) {
return 1;
}
const chosenGroup = groups.find(group => group.value === groupId);
if (chosenGroup?.numberOfUsers > 1) {
return chosenGroup.numberOfUsers;
}
return 1;
};
export default ({ export default ({
planData = '[]', planData = '[]',
planId, planId,
namespaceId,
setupForCompany, setupForCompany,
fullName, fullName,
newUser, newUser,
...@@ -33,6 +48,8 @@ export default ({ ...@@ -33,6 +48,8 @@ export default ({
}) => { }) => {
const availablePlans = parsePlanData(planData); const availablePlans = parsePlanData(planData);
const isNewUser = parseBoolean(newUser); const isNewUser = parseBoolean(newUser);
const groupId = parseInt(namespaceId, 10) || null;
const groups = parseGroupData(groupData);
return { return {
currentStep: STEPS[0], currentStep: STEPS[0],
...@@ -41,10 +58,10 @@ export default ({ ...@@ -41,10 +58,10 @@ export default ({
selectedPlan: determineSelectedPlan(planId, availablePlans), selectedPlan: determineSelectedPlan(planId, availablePlans),
isNewUser, isNewUser,
fullName, fullName,
groupData: parseGroupData(groupData), groupData: groups,
selectedGroup: null, selectedGroup: groupId,
organizationName: null, organizationName: null,
numberOfUsers: 1, numberOfUsers: determineNumberOfUsers(groupId, groups),
country: null, country: null,
streetAddressLine1: null, streetAddressLine1: null,
streetAddressLine2: null, streetAddressLine2: null,
......
...@@ -42,8 +42,18 @@ module BillingPlansHelper ...@@ -42,8 +42,18 @@ module BillingPlansHelper
"#{EE::SUBSCRIPTIONS_URL}/gitlab/namespaces/#{group.id}/upgrade/#{plan.id}" "#{EE::SUBSCRIPTIONS_URL}/gitlab/namespaces/#{group.id}/upgrade/#{plan.id}"
end end
def use_new_purchase_flow?(namespace)
namespace.group? &&
namespace.actual_plan_name == Plan::FREE &&
Feature.enabled?(:free_group_new_purchase_flow, current_user)
end
def plan_purchase_url(group, plan) def plan_purchase_url(group, plan)
"#{plan.purchase_link.href}&gl_namespace_id=#{group.id}" if use_new_purchase_flow?(group)
new_subscriptions_path(plan_id: plan.id, namespace_id: group.id)
else
"#{plan.purchase_link.href}&gl_namespace_id=#{group.id}"
end
end end
def plan_feature_short_list(plan) def plan_feature_short_list(plan)
......
...@@ -9,6 +9,7 @@ module SubscriptionsHelper ...@@ -9,6 +9,7 @@ module SubscriptionsHelper
full_name: current_user.name, full_name: current_user.name,
plan_data: plan_data.to_json, plan_data: plan_data.to_json,
plan_id: params[:plan_id], plan_id: params[:plan_id],
namespace_id: params[:namespace_id],
new_user: new_user?.to_s, new_user: new_user?.to_s,
group_data: group_data.to_json group_data: group_data.to_json
} }
......
...@@ -35,4 +35,5 @@ ...@@ -35,4 +35,5 @@
.card-footer.p-3 .card-footer.p-3
.pull-right{ class: ("invisible" unless purchase_link.action == 'upgrade' || is_current_plan) } .pull-right{ class: ("invisible" unless purchase_link.action == 'upgrade' || is_current_plan) }
- upgrade_button_class = "disabled" if is_current_plan && !namespace.trial_active? - upgrade_button_class = "disabled" if is_current_plan && !namespace.trial_active?
= link_to s_('BillingPlan|Upgrade'), plan_purchase_or_upgrade_url(namespace, plan, current_plan), class: "btn btn-success #{upgrade_button_class}" - cta_class = '-new' if use_new_purchase_flow?(namespace)
= link_to s_('BillingPlan|Upgrade'), plan_purchase_or_upgrade_url(namespace, plan, current_plan), class: "btn btn-success #{upgrade_button_class} billing-cta-purchase#{cta_class}"
...@@ -19,6 +19,7 @@ describe('Order Summary', () => { ...@@ -19,6 +19,7 @@ describe('Order Summary', () => {
const initialData = { const initialData = {
planData: JSON.stringify(planData), planData: JSON.stringify(planData),
planId: 'thirdPlanId', planId: 'thirdPlanId',
namespaceId: null,
fullName: 'Full Name', fullName: 'Full Name',
}; };
......
...@@ -23,12 +23,16 @@ describe('Subscription Details', () => { ...@@ -23,12 +23,16 @@ describe('Subscription Details', () => {
{ id: 483, name: 'My second group', users: 12 }, { id: 483, name: 'My second group', users: 12 },
]; ];
const initialData = { let initialNamespaceId = null;
planData: JSON.stringify(planData), const initialData = namespaceId => {
groupData: JSON.stringify(groupData), return {
planId: 'secondPlanId', planData: JSON.stringify(planData),
setupForCompany: 'true', groupData: JSON.stringify(groupData),
fullName: 'Full Name', planId: 'secondPlanId',
namespaceId,
setupForCompany: 'true',
fullName: 'Full Name',
};
}; };
const createComponent = () => { const createComponent = () => {
...@@ -44,7 +48,7 @@ describe('Subscription Details', () => { ...@@ -44,7 +48,7 @@ describe('Subscription Details', () => {
const companyLink = () => wrapper.find({ ref: 'company-link' }); const companyLink = () => wrapper.find({ ref: 'company-link' });
beforeEach(() => { beforeEach(() => {
store = createStore(initialData); store = createStore(initialData(initialNamespaceId));
createComponent(); createComponent();
}); });
...@@ -191,6 +195,55 @@ describe('Subscription Details', () => { ...@@ -191,6 +195,55 @@ describe('Subscription Details', () => {
}); });
}); });
describe('An existing user coming from group billing page', () => {
beforeEach(() => {
initialNamespaceId = '132';
store.state.isNewUser = false;
});
it('should not display an input field for the company or group name', () => {
expect(organizationNameInput().exists()).toBe(false);
});
it('should display the group select', () => {
expect(groupSelect().exists()).toBe(true);
});
it('should enable the number of users input field', () => {
expect(numberOfUsersInput().attributes('disabled')).toBeUndefined();
});
it('should set the min number of users to 3', () => {
expect(numberOfUsersInput().attributes('min')).toBe('3');
});
it('should set the selected group to initial namespace id', () => {
expect(groupSelect().element.value).toBe('132');
});
it('should not show a link to change to setting up for a company', () => {
expect(companyLink().exists()).toBe(false);
});
describe('selecting an existing group', () => {
beforeEach(() => {
store.commit(types.UPDATE_SELECTED_GROUP, 483);
});
it('should display the correct description', () => {
expect(wrapper.text()).toContain('Your subscription will be applied to this group');
});
it('should set the min number of users to 12', () => {
expect(numberOfUsersInput().attributes('min')).toBe('12');
});
it('should set the selected group to the user selected namespace id', () => {
expect(groupSelect().element.value).toBe('483');
});
});
});
describe('validations', () => { describe('validations', () => {
const isStepValid = () => wrapper.find(Step).props('isValid'); const isStepValid = () => wrapper.find(Step).props('isValid');
......
...@@ -19,6 +19,7 @@ describe('projectsSelector default state', () => { ...@@ -19,6 +19,7 @@ describe('projectsSelector default state', () => {
planData: JSON.stringify(planData), planData: JSON.stringify(planData),
groupData: JSON.stringify(groupData), groupData: JSON.stringify(groupData),
planId: 'secondPlanId', planId: 'secondPlanId',
namespaceId: null,
setupForCompany: 'true', setupForCompany: 'true',
fullName: 'Full Name', fullName: 'Full Name',
newUser: 'true', newUser: 'true',
......
...@@ -58,4 +58,33 @@ describe BillingPlansHelper do ...@@ -58,4 +58,33 @@ describe BillingPlansHelper do
end end
end end
end end
describe '#use_new_purchase_flow?' do
using RSpec::Parameterized::TableSyntax
where free_group_new_purchase: [true, false],
type: ['Group', nil],
plan: Plan.all_plans
with_them do
let_it_be(:user) { create(:user) }
let(:namespace) do
create :namespace, type: type,
gitlab_subscription: create(:gitlab_subscription, hosted_plan: create("#{plan}_plan".to_sym))
end
before do
allow(helper).to receive(:current_user).and_return(user)
stub_feature_flags free_group_new_purchase_flow: free_group_new_purchase
end
subject { helper.use_new_purchase_flow?(namespace) }
it do
result = free_group_new_purchase && type == 'Group' && plan == Plan::FREE
is_expected.to be(result)
end
end
end
end end
...@@ -22,7 +22,7 @@ describe SubscriptionsHelper do ...@@ -22,7 +22,7 @@ describe SubscriptionsHelper do
end end
before do before do
allow(helper).to receive(:params).and_return(plan_id: 'bronze_id') allow(helper).to receive(:params).and_return(plan_id: 'bronze_id', namespace_id: nil)
allow_next_instance_of(FetchSubscriptionPlansService) do |instance| allow_next_instance_of(FetchSubscriptionPlansService) do |instance|
allow(instance).to receive(:execute).and_return(raw_plan_data) allow(instance).to receive(:execute).and_return(raw_plan_data)
end end
...@@ -33,6 +33,7 @@ describe SubscriptionsHelper do ...@@ -33,6 +33,7 @@ describe SubscriptionsHelper do
let_it_be(:group) { create(:group, name: 'My Namespace') } let_it_be(:group) { create(:group, name: 'My Namespace') }
before do before do
allow(helper).to receive(:params).and_return(plan_id: 'bronze_id', namespace_id: group.id.to_s)
allow(helper).to receive(:current_user).and_return(user) allow(helper).to receive(:current_user).and_return(user)
group.add_owner(user) group.add_owner(user)
end end
...@@ -43,6 +44,7 @@ describe SubscriptionsHelper do ...@@ -43,6 +44,7 @@ describe SubscriptionsHelper do
it { is_expected.to include(full_name: 'First Last') } it { is_expected.to include(full_name: 'First Last') }
it { is_expected.to include(plan_data: '[{"id":"bronze_id","code":"bronze","price_per_year":48.0}]') } it { is_expected.to include(plan_data: '[{"id":"bronze_id","code":"bronze","price_per_year":48.0}]') }
it { is_expected.to include(plan_id: 'bronze_id') } it { is_expected.to include(plan_id: 'bronze_id') }
it { is_expected.to include(namespace_id: group.id.to_s) }
it { is_expected.to include(group_data: %Q{[{"id":#{group.id},"name":"My Namespace","users":1}]}) } it { is_expected.to include(group_data: %Q{[{"id":#{group.id},"name":"My Namespace","users":1}]}) }
describe 'new_user' do describe 'new_user' 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