Commit 0c6d62df authored by Andrei Stoicescu's avatar Andrei Stoicescu Committed by Stan Hu

Add graphQL connection

Add service to get plan upgrade info
Add specs for new helper methods
parent 53e03973
......@@ -19,21 +19,81 @@
}
}
$gutter-small: $gl-spacing-scale-6;
$gutter: $gl-spacing-scale-7;
$badge-height: $gl-spacing-scale-7;
.billing-plans {
// This color is not part of the GitLab-UI/Pajamas specifications.
// We're using it only for marketing purposes
$highlight-color: #6e49cb;
margin-bottom: $gutter-small;
> * + * {
margin-top: $gutter-small;
}
.card-wrapper-has-badge {
.card {
@include gl-border-1;
@include gl-border-solid;
@include gl-rounded-top-left-none;
@include gl-rounded-top-right-none;
border-color: $highlight-color;
}
}
.card-badge {
@include gl-rounded-top-left-base;
@include gl-rounded-top-right-base;
@include gl-font-weight-bold;
@include gl-px-5;
@include gl-text-white;
background-color: $highlight-color;
// These border radii values are not defined in gitlab-ui,
// but they are consistent with the startup-*.scss .card overrides
border-top-left-radius: 0.25rem;
border-top-right-radius: 0.25rem;
line-height: $badge-height;
&-text {
@include gl-display-block;
@include gl-text-truncate;
}
}
.card {
@include gl-mb-0;
&-active {
background-color: $gray-light;
}
.card-body {
.price-per-month {
.price-description {
align-items: center;
display: flex;
flex-direction: row;
color: $blue-500;
font-size: 48px;
font-size: 45px;
font-weight: $gl-font-weight-bold;
line-height: 1;
.price-rebate {
color: $blue-400;
font-size: 20px;
text-decoration: line-through;
}
.price-cut {
text-decoration: line-through;
}
.conditions {
list-style: none;
font-size: $gl-font-size-large;
......@@ -42,15 +102,62 @@
}
}
.price-per-year {
.price-conclusion {
@include gl-font-base;
color: $blue-500;
font-size: $gl-font-size-small;
font-weight: $gl-font-weight-bold;
}
}
}
}
@media (min-width: $breakpoint-md) {
.billing-plans {
@include gl-display-flex;
@include gl-flex-wrap;
@include gl-justify-content-space-between;
> * + * {
@include gl-mt-0;
}
.card-wrapper {
margin-bottom: $gutter-small;
padding-top: $badge-height;
width: calc(50% - #{$gutter-small} / 2);
&-has-badge {
@include gl-pt-0;
.card {
height: calc(100% - #{$badge-height});
}
}
}
.card {
@include gl-h-full;
}
}
}
@media (min-width: $breakpoint-lg) {
.billing-plans {
flex-wrap: nowrap;
> * + * {
margin-left: $gutter;
}
.card-wrapper {
@include gl-flex-fill-1;
@include gl-mb-0;
@include gl-overflow-hidden;
@include gl-w-auto;
}
}
}
.subscription-table {
.flex-grid {
.grid-cell {
......
# frozen_string_literal: true
module BillingPlansHelper
include Gitlab::Utils::StrongMemoize
def subscription_plan_info(plans_data, current_plan_code)
current_plan = plans_data.find { |plan| plan.code == current_plan_code && plan.current_subscription_plan? }
current_plan || plans_data.find { |plan| plan.code == current_plan_code }
......@@ -10,6 +12,28 @@ module BillingPlansHelper
number_to_currency(value, unit: '$', strip_insignificant_zeros: true, format: "%u%n")
end
def upgrade_offer_type(namespace, plan)
return :no_offer if namespace.actual_plan_name != Plan::BRONZE || !offer_from_previous_tier?(namespace.id, plan.id)
upgrade_for_free?(namespace.id) ? :upgrade_for_free : :upgrade_for_offer
end
def has_upgrade?(upgrade_offer)
upgrade_offer == :upgrade_for_free || upgrade_offer == :upgrade_for_offer
end
def show_contact_sales_button?(purchase_link_action, upgrade_offer)
return false unless purchase_link_action == 'upgrade'
upgrade_offer == :upgrade_for_offer ||
(experiment_enabled?(:contact_sales_btn_in_app) && upgrade_offer == :no_offer)
end
def show_upgrade_button?(purchase_link_action, upgrade_offer)
purchase_link_action == 'upgrade' &&
(upgrade_offer == :no_offer || upgrade_offer == :upgrade_for_free)
end
def subscription_plan_data_attributes(namespace, plan)
return {} unless namespace
......@@ -34,11 +58,6 @@ module BillingPlansHelper
namespace.group? && (namespace.actual_plan_name == Plan::FREE || namespace.trial_active?)
end
def show_contact_sales_button?(purchase_link_action)
experiment_enabled?(:contact_sales_btn_in_app) &&
purchase_link_action == 'upgrade'
end
def experiment_tracking_data_for_button_click(button_label)
return {} unless Gitlab::Experimentation.active?(:contact_sales_btn_in_app)
......@@ -139,4 +158,24 @@ module BillingPlansHelper
def billable_seats_href(group)
group_seat_usage_path(group)
end
def offer_from_previous_tier?(namespace_id, plan_id)
upgrade_plan_id = upgrade_plan_data(namespace_id)[:upgrade_plan_id]
return false unless upgrade_plan_id
upgrade_plan_id == plan_id
end
def upgrade_for_free?(namespace_id)
!!upgrade_plan_data(namespace_id)[:upgrade_for_free]
end
def upgrade_plan_data(namespace_id)
strong_memoize(:upgrade_plan_data) do
GitlabSubscriptions::PlanUpgradeService
.new(namespace_id: namespace_id)
.execute
end
end
end
# frozen_string_literal: true
module GitlabSubscriptions
class PlanUpgradeService
def initialize(namespace_id:)
@namespace_id = namespace_id
end
def execute
result = client.plan_upgrade_offer(@namespace_id)
plan_id = result[:assisted_upgrade_plan_id] || result[:free_upgrade_plan_id] unless result[:eligible_for_free_upgrade].nil?
{
upgrade_for_free: result[:eligible_for_free_upgrade],
upgrade_plan_id: plan_id
}
end
private
def client
Gitlab::SubscriptionPortal::Client
end
end
end
- purchase_link = plan.purchase_link
- plan_name = plan.name
- show_deprecated_plan = ::Feature.enabled?(:hide_deprecated_billing_plans) && plan.deprecated?
- has_upgrade = has_upgrade?(plan_offer_type)
- if show_deprecated_plan
- plan_name += ' (Legacy)'
- faq_link_url = 'https://about.gitlab.com/gitlab-com/#faq'
- faq_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe % { url: faq_link_url }
.card.h-100{ class: ("card-active" if is_current || show_deprecated_plan) }
.card-header.gl-font-weight-bold.d-flex.flex-row.justify-content-between.flex-wrap
%div
= plan_name
- if is_current
.text-muted
= _("Current Plan")
.card-wrapper{ class: ("card-wrapper-has-badge" if has_upgrade) }
- if has_upgrade
.card-badge
%span.card-badge-text
- case plan_offer_type
- when :upgrade_for_free
= s_("BillingPlans|Free upgrade!")
- else
= _("Upgrade offers available!")
.card{ class: ("card-active" if is_current || show_deprecated_plan) }
.card-header.gl-font-weight-bold.d-flex.flex-row.justify-content-between.flex-wrap
%div
= plan_name
- if is_current
.text-muted
= s_("BillingPlans|Current Plan")
.card-body
- if show_deprecated_plan
= s_("The %{plan_name} is no longer available to purchase. For more information about how this will impact you, check our %{faq_link_start}frequently asked questions%{faq_link_end}.").html_safe % { plan_name: plan.name, faq_link_start: faq_link_start, faq_link_end: '</a>'.html_safe }
- else
.price-per-month
.gl-mr-2
= number_to_plan_currency(plan.price_per_month)
.card-body
- if show_deprecated_plan
= s_("The %{plan_name} is no longer available to purchase. For more information about how this will impact you, check our %{faq_link_start}frequently asked questions%{faq_link_end}.").html_safe % { plan_name: plan.name, faq_link_start: faq_link_start, faq_link_end: '</a>'.html_safe }
- else
.price-description
.gl-mr-2.gl-display-flex.gl-align-items-center
- case plan_offer_type
- when :upgrade_for_free
%span.gl-mr-3.price-rebate
= number_to_plan_currency(plan.price_per_month)
%span
= number_to_plan_currency(plan.upgrade_price_per_month)
- when :upgrade_for_offer
%span.price-cut
= number_to_plan_currency(plan.price_per_month)
- else
%span
= number_to_plan_currency(plan.price_per_month)
%ul.conditions.gl-p-0.gl-my-auto
%li= s_("BillingPlans|per user")
%li= s_("BillingPlans|monthly")
.price-per-year.text-left{ class: ("invisible" unless plan.price_per_year > 0) }
- price_per_year = number_to_plan_currency(plan.price_per_year)
= s_("BillingPlans|billed annually at %{price_per_year}") % { price_per_year: price_per_year }
%ul.conditions.gl-p-0.gl-my-auto
%li= s_("BillingPlans|per user")
%li= s_("BillingPlans|monthly")
.price-conclusion{ class: ("invisible" unless plan.price_per_year > 0) }
- case plan_offer_type
- when :upgrade_for_free
= s_("BillingPlans|for the remainder of your subscription")
- else
- price_per_year = number_to_plan_currency(plan.price_per_year)
= s_("BillingPlans|billed annually at %{price_per_year}") % { price_per_year: price_per_year }
%hr.gl-my-3
%hr.gl-my-3
%ul.unstyled-list
- plan_feature_list(plan).each do |feature|
- feature_class = "gl-p-0!"
- if feature.highlight
- feature_class += " gl-font-weight-bold"
%li{ class: "#{feature_class}" }
= feature.title
%li.gl-p-0.gl-pt-3
- if plan.about_page_href
= link_to s_("BillingPlans|See all %{plan_name} features") % { plan_name: plan.name }, EE::SUBSCRIPTIONS_COMPARISON_URL
%ul.unstyled-list
- plan_feature_list(plan).each do |feature|
- feature_class = "gl-p-0!"
- if feature.highlight
- feature_class += " gl-font-weight-bold"
%li{ class: "#{feature_class}" }
= feature.title
%li.gl-p-0.gl-pt-3
- if plan.about_page_href
= link_to s_("BillingPlans|See all %{plan_name} features") % { plan_name: plan.name }, EE::SUBSCRIPTIONS_COMPARISON_URL
- if purchase_link
.card-footer
.float-right{ class: ("invisible" unless purchase_link.action == 'upgrade' || is_current) }
- if show_contact_sales_button?(purchase_link.action)
= link_to s_('BillingPlan|Contact sales'), "#{contact_sales_url}?test=inappcontactsales#{plan.code}", class: "btn btn-success-secondary gl-button", data: { **experiment_tracking_data_for_button_click('contact_sales') }
- cta_class = '-new' if use_new_purchase_flow?(namespace)
- upgrade_button_classes = upgrade_button_css_classes(namespace, plan, is_current)
= link_to s_('BillingPlan|Upgrade'), plan_purchase_or_upgrade_url(namespace, plan), class: "#{upgrade_button_classes} billing-cta-purchase#{cta_class}", data: { **experiment_tracking_data_for_button_click('upgrade') }
- cta_class = '-new' if use_new_purchase_flow?(namespace)
- upgrade_button_classes = upgrade_button_css_classes(namespace, plan, is_current)
- upgrade_button_text = plan_offer_type === :upgrade_for_free ? s_('BillingPlan|Upgrade for free') : s_('BillingPlan|Upgrade')
- show_upgrade_button = show_upgrade_button?(purchase_link.action, plan_offer_type)
- show_contact_sales_button = show_contact_sales_button?(purchase_link.action, plan_offer_type)
.gl-min-h-7.gl-display-flex.gl-flex-wrap.gl-justify-content-end
- if show_contact_sales_button
= link_to s_('BillingPlan|Contact sales'), "#{contact_sales_url}?test=inappcontactsales#{plan.code}", class: [("btn gl-button"), (show_upgrade_button ? "btn-success-secondary" : "btn-success")], data: { **experiment_tracking_data_for_button_click('contact_sales') }
- if show_upgrade_button
= link_to upgrade_button_text, plan_purchase_or_upgrade_url(namespace, plan), class: "#{upgrade_button_classes} billing-cta-purchase#{cta_class} gl-ml-3", data: { **experiment_tracking_data_for_button_click('upgrade') }
......@@ -3,7 +3,7 @@
- if namespace_for_user
= render_if_exists 'trials/banner', namespace: namespace
.billing-plan-header.content-block.center
.billing-plan-header.content-block.center.gl-mb-5
.billing-plan-logo
- if namespace_for_user
.avatar-container.s96.home-panel-avatar.gl-mr-3.float-none.mx-auto.mb-4.mt-1
......
......@@ -7,12 +7,12 @@
- if show_plans?(namespace)
- plans = billing_available_plans(plans_data, current_plan)
.billing-plans.gl-mt-5.row.justify-content-center
.billing-plans
- plans.each do |plan|
- is_default_plan = current_plan.nil? && plan.default?
- is_current = plan.code == current_plan&.code || is_default_plan
.col-md-6.col-lg-3.gl-mb-5
= render 'shared/billings/billing_plan', namespace: namespace, plan: plan, is_current: is_current
= render 'shared/billings/billing_plan', namespace: namespace, plan: plan, is_current: is_current,
plan_offer_type: upgrade_offer_type(namespace, plan)
- if namespace.gitlab_subscription&.has_a_paid_hosted_plan?
.center.gl-mb-7
......
......@@ -45,6 +45,35 @@ module Gitlab
end
end
def plan_upgrade_offer(namespace_id)
query = <<~GQL
{
subscription(namespaceId: "#{namespace_id}") {
eoaStarterBronzeEligible
assistedUpgradePlanId
freeUpgradePlanId
}
}
GQL
response = http_post("graphql", admin_headers, { query: query }).dig(:data)
if response['errors'].blank?
eligible = response.dig('data', 'subscription', 'eoaStarterBronzeEligible')
assisted_upgrade = response.dig('data', 'subscription', 'assistedUpgradePlanId')
free_upgrade = response.dig('data', 'subscription', 'freeUpgradePlanId')
{
success: true,
eligible_for_free_upgrade: eligible,
assisted_upgrade_plan_id: assisted_upgrade,
free_upgrade_plan_id: free_upgrade
}
else
{ success: false }
end
end
private
def http_get(path, headers)
......
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Billing plan pages', :feature do
include StubRequests
include SubscriptionPortalHelpers
let(:user) { create(:user) }
let(:namespace) { user.namespace }
......@@ -22,6 +23,7 @@ RSpec.describe 'Billing plan pages', :feature do
stub_experiment_for_subject(contact_sales_btn_in_app: true)
stub_full_request("#{EE::SUBSCRIPTIONS_URL}/gitlab_plans?plan=#{plan.name}&namespace_id=#{namespace.id}")
.to_return(status: 200, body: plans_data.to_json)
stub_eoa_eligibility_request(namespace.id)
stub_application_setting(check_namespace_plan: true)
allow(Gitlab).to receive(:com?) { true }
gitlab_sign_in(user)
......@@ -159,8 +161,7 @@ RSpec.describe 'Billing plan pages', :feature do
expect(action).not_to have_link('Upgrade')
expect(action).not_to have_css('.disabled')
when 'current_plan'
expect(action).to have_link('Upgrade')
expect(action).to have_css('.disabled')
expect(action).not_to have_link('Upgrade')
when 'upgrade'
expect(action).to have_link('Upgrade')
expect(action).not_to have_css('.disabled')
......@@ -254,7 +255,6 @@ RSpec.describe 'Billing plan pages', :feature do
expect(action).not_to have_link('Upgrade')
expect(action).not_to have_css('.disabled')
when 'current_plan'
expect(action).to have_link('Upgrade')
expect(action).not_to have_css('.disabled')
when 'upgrade'
expect(action).to have_link('Upgrade')
......
......@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe 'Groups > Billing', :js do
include StubRequests
include SubscriptionPortalHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
......@@ -18,6 +19,7 @@ RSpec.describe 'Groups > Billing', :js do
end
before do
stub_eoa_eligibility_request(group.id)
stub_full_request("#{EE::SUBSCRIPTIONS_URL}/gitlab_plans?plan=#{plan}&namespace_id=#{group.id}")
.with(headers: { 'Accept' => 'application/json' })
.to_return(status: 200, body: File.new(Rails.root.join('ee/spec/fixtures/gitlab_com_plans.json')))
......
......@@ -8,7 +8,7 @@ RSpec.describe BillingPlansHelper do
let(:group) { build(:group) }
let(:plan) do
Hashie::Mash.new(id: 'external-paid-plan-hash-code', name: 'Bronze Plan')
OpenStruct.new(id: 'external-paid-plan-hash-code', name: 'Bronze Plan')
end
context 'when group and plan with ID present' do
......@@ -61,7 +61,7 @@ RSpec.describe BillingPlansHelper do
end
context 'when plan with ID not present' do
let(:plan) { Hashie::Mash.new(id: nil, name: 'Bronze Plan') }
let(:plan) { OpenStruct.new(id: nil, name: 'Bronze Plan') }
it 'returns data attributes without upgrade href' do
add_seats_href = "#{EE::SUBSCRIPTIONS_URL}/gitlab/namespaces/#{group.id}/extra_seats"
......@@ -149,16 +149,77 @@ RSpec.describe BillingPlansHelper do
end
end
describe '#upgrade_offer_type' do
using RSpec::Parameterized::TableSyntax
let(:plan) { OpenStruct.new({ id: '123456789' }) }
context 'when plan has a valid property' do
where(:plan_name, :for_free, :plan_id, :result) do
Plan::BRONZE | true | '123456789' | :upgrade_for_free
Plan::BRONZE | true | '987654321' | :no_offer
Plan::BRONZE | true | nil | :no_offer
Plan::BRONZE | false | '123456789' | :upgrade_for_offer
Plan::BRONZE | false | nil | :no_offer
Plan::BRONZE | nil | nil | :no_offer
Plan::SILVER | nil | nil | :no_offer
nil | true | nil | :no_offer
end
with_them do
let(:namespace) do
OpenStruct.new(
{
actual_plan_name: plan_name,
id: '000000000'
}
)
end
before do
allow_next_instance_of(GitlabSubscriptions::PlanUpgradeService) do |instance|
expect(instance).to receive(:execute).once.and_return({
upgrade_for_free: for_free,
upgrade_plan_id: plan_id
})
end
end
subject { helper.upgrade_offer_type(namespace, plan) }
it { is_expected.to eq(result) }
end
end
end
describe '#has_upgrade?' do
using RSpec::Parameterized::TableSyntax
where(:offer_type, :result) do
:no_offer | false
:upgrade_for_free | true
:upgrade_for_offer | true
end
with_them do
subject { helper.has_upgrade?(offer_type) }
it { is_expected.to eq(result) }
end
end
describe '#show_contact_sales_button?' do
using RSpec::Parameterized::TableSyntax
where(:experiment_enabled, :link_action, :result) do
true | 'downgrade' | false
true | 'current' | false
true | 'upgrade' | true
false | 'downgrade' | false
false | 'current' | false
false | 'upgrade' | false
where(:experiment_enabled, :link_action, :upgrade_offer, :result) do
true | 'upgrade' | :no_offer | true
true | 'upgrade' | :upgrade_for_offer | true
true | 'no_upgrade' | :no_offer | false
true | 'no_upgrade' | :upgrade_for_offer | false
false | 'upgrade' | :no_offer | false
false | 'upgrade' | :upgrade_for_offer | true
false | 'no_upgrade' | :no_offer | false
false | 'no_upgrade' | :upgrade_for_offer | false
end
with_them do
......@@ -166,7 +227,26 @@ RSpec.describe BillingPlansHelper do
allow(helper).to receive(:experiment_enabled?).with(:contact_sales_btn_in_app).and_return(experiment_enabled)
end
subject { helper.show_contact_sales_button?(link_action) }
subject { helper.show_contact_sales_button?(link_action, upgrade_offer) }
it { is_expected.to eq(result) }
end
end
describe '#show_upgrade_button?' do
using RSpec::Parameterized::TableSyntax
where(:link_action, :upgrade_offer, :result) do
'upgrade' | :no_offer | true
'upgrade' | :upgrade_for_free | true
'upgrade' | :upgrade_for_offer | false
'no_upgrade' | :no_offer | false
'no_upgrade' | :upgrade_for_free | false
'no_upgrade' | :upgrade_for_offer | false
end
with_them do
subject { helper.show_upgrade_button?(link_action, upgrade_offer) }
it { is_expected.to eq(result) }
end
......@@ -277,7 +357,7 @@ RSpec.describe BillingPlansHelper do
end
with_them do
let(:namespace) { Hashie::Mash.new(trial_active: trial_active) }
let(:namespace) { OpenStruct.new(trial_active: trial_active) }
subject { helper.upgrade_button_css_classes(namespace, plan, is_current_plan) }
......@@ -305,7 +385,7 @@ RSpec.describe BillingPlansHelper do
end
context 'when namespace is on an active plan' do
let(:current_plan) { Hashie::Mash.new(code: 'silver') }
let(:current_plan) { OpenStruct.new(code: 'silver') }
it 'returns plans without deprecated' do
expect(helper.billing_available_plans(plans_data, nil)).to eq([plan])
......@@ -313,7 +393,7 @@ RSpec.describe BillingPlansHelper do
end
context 'when namespace is on a deprecated plan' do
let(:current_plan) { Hashie::Mash.new(code: 'bronze') }
let(:current_plan) { OpenStruct.new(code: 'bronze') }
it 'returns plans with a deprecated plan' do
expect(helper.billing_available_plans(plans_data, current_plan)).to eq(plans_data)
......@@ -321,7 +401,7 @@ RSpec.describe BillingPlansHelper do
end
context 'when namespace is on a deprecated plan that has hide_deprecated_card set to true' do
let(:current_plan) { Hashie::Mash.new(code: 'bronze') }
let(:current_plan) { OpenStruct.new(code: 'bronze') }
let(:deprecated_plan) { double('Plan', deprecated?: true, code: 'bronze', hide_deprecated_card?: true) }
it 'returns plans without the deprecated plan' do
......@@ -330,7 +410,7 @@ RSpec.describe BillingPlansHelper do
end
context 'when namespace is on a plan that has hide_deprecated_card set to true, but deprecated? is false' do
let(:current_plan) { Hashie::Mash.new(code: 'silver') }
let(:current_plan) { OpenStruct.new(code: 'silver') }
let(:plan) { double('Plan', deprecated?: false, code: 'silver', hide_deprecated_card?: true) }
it 'returns plans with the deprecated plan' do
......
......@@ -137,4 +137,100 @@ RSpec.describe Gitlab::SubscriptionPortal::Client do
expect(result).to eq({ errors: ["invalid activation code"], success: false })
end
end
describe '#plan_upgrade_offer' do
let(:namespace_id) { 111 }
let(:headers) do
{
"Accept" => "application/json",
"Content-Type" => "application/json",
"X-Admin-Email" => "gl_com_api@gitlab.com",
"X-Admin-Token" => "customer_admin_token"
}
end
let(:params) do
{ query: <<~GQL
{
subscription(namespaceId: "{:namespace_id=>#{namespace_id}}") {
eoaStarterBronzeEligible
assistedUpgradePlanId
freeUpgradePlanId
}
}
GQL
}
end
subject(:plan_upgrade_offer) { described_class.plan_upgrade_offer(namespace_id: namespace_id) }
context 'when the response contains errors' do
before do
expect(described_class).to receive(:http_post).with('graphql', headers, params).and_return(response)
end
let(:response) do
{
success: true,
data: {
'errors' => [{ 'message' => 'this will be ignored' }]
}
}
end
it 'returns a failure' do
expect(plan_upgrade_offer).to eq({ success: false })
end
end
context 'when the response does not contain errors' do
using RSpec::Parameterized::TableSyntax
where(:eligible, :assisted_plan_id, :free_plan_id) do
true | '111111' | '111111'
true | '111111' | nil
true | nil | '111111'
end
with_them do
before do
allow(described_class).to receive(:http_post).and_return({
success: true,
data: { "data" => { "subscription" => {
"eoaStarterBronzeEligible" => eligible,
"assistedUpgradePlanId" => assisted_plan_id,
"freeUpgradePlanId" => free_plan_id
} } }
})
end
it 'returns the correct response' do
expect(plan_upgrade_offer).to eq({
success: true,
eligible_for_free_upgrade: eligible,
assisted_upgrade_plan_id: assisted_plan_id,
free_upgrade_plan_id: free_plan_id
})
end
end
context 'when subscription is nil' do
before do
allow(described_class).to receive(:http_post).and_return({
success: true,
data: { "data" => { "subscription" => nil } }
})
end
it 'returns the correct response' do
expect(plan_upgrade_offer).to eq({
success: true,
eligible_for_free_upgrade: nil,
assisted_upgrade_plan_id: nil,
free_upgrade_plan_id: nil
})
end
end
end
end
end
......@@ -10,7 +10,7 @@ RSpec.describe FetchSubscriptionPlansService do
let(:plan) { 'bronze' }
let(:response_mock) { double(body: [{ 'foo' => 'bar' }].to_json) }
context 'when successully fetching plans data' do
context 'when successfully fetching plans data' do
it 'returns parsed JSON' do
expect(Gitlab::HTTP).to receive(:get)
.with(
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSubscriptions::PlanUpgradeService do
subject(:execute) { described_class.new(namespace_id: namespace_id).execute }
let(:namespace_id) { '111' }
describe '#execute' do
using RSpec::Parameterized::TableSyntax
before do
allow(Gitlab::SubscriptionPortal::Client).to receive(:plan_upgrade_offer).and_return(response)
end
context 'when the response is a failure' do
let(:response) { { success: false } }
it 'returns nil values' do
expect(execute).to eq({
upgrade_for_free: nil,
upgrade_plan_id: nil
})
end
end
context 'when the response is successful' do
where(:eligible, :assisted_id, :free_id, :plan_id) do
true | '111' | '222' | '111'
true | nil | '222' | '222'
true | '111' | nil | '111'
true | nil | nil | nil
false | '111' | '222' | '111'
false | '111' | nil | '111'
false | nil | '222' | '222'
nil | '111' | '222' | nil
end
with_them do
let(:response) do
{
success: true,
eligible_for_free_upgrade: eligible,
assisted_upgrade_plan_id: assisted_id,
free_upgrade_plan_id: free_id
}
end
before do
expect(Gitlab::SubscriptionPortal::Client).to receive(:plan_upgrade_offer).once.and_return(response)
end
it 'returns the correct values' do
expect(execute).to eq({
upgrade_for_free: eligible,
upgrade_plan_id: plan_id
})
end
end
end
end
end
# frozen_string_literal: true
module SubscriptionPortalHelpers
include StubRequests
def stub_eoa_eligibility_request(namespace_id)
stub_full_request("#{EE::SUBSCRIPTIONS_URL}/graphql", method: :post)
.with(
body: "{\"query\":\"{\\n subscription(namespaceId: \\\"#{namespace_id}\\\") {\\n eoaStarterBronzeEligible\\n assistedUpgradePlanId\\n freeUpgradePlanId\\n }\\n}\\n\"}",
headers: {
'Accept' => 'application/json',
'Content-Type' => 'application/json',
'X-Admin-Email' => EE::SUBSCRIPTION_PORTAL_ADMIN_EMAIL,
'X-Admin-Token' => EE::SUBSCRIPTION_PORTAL_ADMIN_TOKEN
}
)
.to_return(
status: 200,
headers: { 'Content-Type' => 'application/json' },
body: stubbed_eoa_eligibility_response_body
)
end
private
def stubbed_eoa_eligibility_response_body
{
"data": {
"subscription": {
"eoaStarterBronzeEligible": false,
"assistedUpgradePlanId": nil,
"freeUpgradePlanId": nil
}
}
}.to_json
end
end
......@@ -4457,6 +4457,12 @@ msgstr ""
msgid "BillingPlans|Congratulations, your free trial is activated."
msgstr ""
msgid "BillingPlans|Current Plan"
msgstr ""
msgid "BillingPlans|Free upgrade!"
msgstr ""
msgid "BillingPlans|If you would like to downgrade your plan please contact %{support_link_start}Customer Support%{support_link_end}."
msgstr ""
......@@ -4490,6 +4496,9 @@ msgstr ""
msgid "BillingPlans|billed annually at %{price_per_year}"
msgstr ""
msgid "BillingPlans|for the remainder of your subscription"
msgstr ""
msgid "BillingPlans|frequently asked questions"
msgstr ""
......@@ -4505,6 +4514,9 @@ msgstr ""
msgid "BillingPlan|Upgrade"
msgstr ""
msgid "BillingPlan|Upgrade for free"
msgstr ""
msgid "Billing|An email address is only visible for users with public emails."
msgstr ""
......@@ -8510,9 +8522,6 @@ msgstr ""
msgid "Current Branch"
msgstr ""
msgid "Current Plan"
msgstr ""
msgid "Current Project"
msgstr ""
......@@ -30638,6 +30647,9 @@ msgstr ""
msgid "Updating"
msgstr ""
msgid "Upgrade offers available!"
msgstr ""
msgid "Upgrade your plan"
msgstr ""
......
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