Commit 01e2be5f authored by Ammar Alakkad's avatar Ammar Alakkad Committed by Peter Leitzen

Add manual renew button to billings page

parent 87a0c544
...@@ -7,7 +7,7 @@ export default { ...@@ -7,7 +7,7 @@ export default {
components: { components: {
SubscriptionTable, SubscriptionTable,
}, },
inject: ['planUpgradeHref', 'namespaceId', 'customerPortalUrl', 'namespaceName'], inject: ['planUpgradeHref', 'planRenewHref', 'namespaceId', 'customerPortalUrl', 'namespaceName'],
created() { created() {
this.setNamespaceId(this.namespaceId); this.setNamespaceId(this.namespaceId);
}, },
...@@ -21,6 +21,7 @@ export default { ...@@ -21,6 +21,7 @@ export default {
<subscription-table <subscription-table
:namespace-name="namespaceName" :namespace-name="namespaceName"
:plan-upgrade-href="planUpgradeHref" :plan-upgrade-href="planUpgradeHref"
:plan-renew-href="planRenewHref"
:customer-portal-url="customerPortalUrl" :customer-portal-url="customerPortalUrl"
/> />
</template> </template>
...@@ -27,6 +27,11 @@ export default { ...@@ -27,6 +27,11 @@ export default {
required: false, required: false,
default: '', default: '',
}, },
planRenewHref: {
type: String,
required: false,
default: '',
},
}, },
computed: { computed: {
...mapState(['isLoadingSubscription', 'hasErrorSubscription', 'plan', 'tables', 'endpoint']), ...mapState(['isLoadingSubscription', 'hasErrorSubscription', 'plan', 'tables', 'endpoint']),
...@@ -48,6 +53,16 @@ export default { ...@@ -48,6 +53,16 @@ export default {
!this.isFreePlan && this.planUpgradeHref ? this.planUpgradeHref : this.customerPortalUrl, !this.isFreePlan && this.planUpgradeHref ? this.planUpgradeHref : this.customerPortalUrl,
}; };
}, },
renewButton() {
if (this.isFreePlan && !this.plan.trial && !gon.features.saasManualRenewButton) {
return null;
}
return {
text: s__('SubscriptionTable|Renew'),
href: this.planRenewHref,
};
},
manageButton() { manageButton() {
if (this.isFreePlan) { if (this.isFreePlan) {
return null; return null;
...@@ -59,7 +74,7 @@ export default { ...@@ -59,7 +74,7 @@ export default {
}; };
}, },
buttons() { buttons() {
return [this.upgradeButton, this.manageButton].filter(Boolean); return [this.upgradeButton, this.renewButton, this.manageButton].filter(Boolean);
}, },
visibleRows() { visibleRows() {
let tableKey = TABLE_TYPE_DEFAULT; let tableKey = TABLE_TYPE_DEFAULT;
......
...@@ -16,6 +16,7 @@ export default (containerId = 'js-billing-plans') => { ...@@ -16,6 +16,7 @@ export default (containerId = 'js-billing-plans') => {
namespaceId, namespaceId,
namespaceName, namespaceName,
planUpgradeHref, planUpgradeHref,
planRenewHref,
customerPortalUrl, customerPortalUrl,
billableSeatsHref, billableSeatsHref,
} = containerEl.dataset; } = containerEl.dataset;
...@@ -27,6 +28,7 @@ export default (containerId = 'js-billing-plans') => { ...@@ -27,6 +28,7 @@ export default (containerId = 'js-billing-plans') => {
namespaceId, namespaceId,
namespaceName, namespaceName,
planUpgradeHref, planUpgradeHref,
planRenewHref,
customerPortalUrl, customerPortalUrl,
billableSeatsHref, billableSeatsHref,
apiBillableMemberListFeatureEnabled: gon?.features?.apiBillableMemberList || false, apiBillableMemberListFeatureEnabled: gon?.features?.apiBillableMemberList || false,
......
...@@ -6,6 +6,7 @@ class Groups::BillingsController < Groups::ApplicationController ...@@ -6,6 +6,7 @@ class Groups::BillingsController < Groups::ApplicationController
before_action only: [:index] do before_action only: [:index] do
push_frontend_feature_flag(:api_billable_member_list) push_frontend_feature_flag(:api_billable_member_list)
push_frontend_feature_flag(:saas_manual_renew_button)
end end
layout 'group_settings' layout 'group_settings'
......
...@@ -16,6 +16,7 @@ module BillingPlansHelper ...@@ -16,6 +16,7 @@ module BillingPlansHelper
namespace_id: group.id, namespace_id: group.id,
namespace_name: group.name, namespace_name: group.name,
plan_upgrade_href: plan_upgrade_url(group, plan), plan_upgrade_href: plan_upgrade_url(group, plan),
plan_renew_href: plan_renew_url(group),
customer_portal_url: "#{EE::SUBSCRIPTIONS_URL}/subscriptions", customer_portal_url: "#{EE::SUBSCRIPTIONS_URL}/subscriptions",
billable_seats_href: billable_seats_href(group) billable_seats_href: billable_seats_href(group)
} }
...@@ -95,6 +96,12 @@ module BillingPlansHelper ...@@ -95,6 +96,12 @@ 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 plan_renew_url(group)
return unless group
"#{EE::SUBSCRIPTIONS_URL}/gitlab/namespaces/#{group.id}/renew"
end
def billable_seats_href(group) def billable_seats_href(group)
return unless Feature.enabled?(:api_billable_member_list, group) return unless Feature.enabled?(:api_billable_member_list, group)
......
---
title: Add manual renew button to billings page
merge_request: 48610
author:
type: other
---
name: saas_manual_renew_button
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48610
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/288804
milestone: '13.7'
type: development
group: group::fulfillment
default_enabled: false
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SubscriptionTable component given a bronze plan with state: isFreePlan=false, upgradable=true, isTrialPlan=false has Upgrade and Manage buttons 1`] = ` exports[`SubscriptionTable component given a bronze plan with state: isFreePlan=false, upgradable=true, isTrialPlan=false has Upgrade and Renew and Manage buttons 1`] = `
Array [ Array [
Object { Object {
"href": "http://test.host/plan/upgrade/bronze", "href": "http://test.host/plan/upgrade/bronze",
"text": "Upgrade", "text": "Upgrade",
}, },
Object {
"href": "http://test.host/plan/renew",
"text": "Renew",
},
Object { Object {
"href": "https://customers.gitlab.com/subscriptions", "href": "https://customers.gitlab.com/subscriptions",
"text": "Manage", "text": "Manage",
...@@ -13,12 +17,16 @@ Array [ ...@@ -13,12 +17,16 @@ Array [
] ]
`; `;
exports[`SubscriptionTable component given a free plan with state: isFreePlan=true, upgradable=true, isTrialPlan=false has Upgrade and Manage buttons 1`] = ` exports[`SubscriptionTable component given a free plan with state: isFreePlan=true, upgradable=true, isTrialPlan=false has Upgrade and Renew and Manage buttons 1`] = `
Array [ Array [
Object { Object {
"href": "http://test.host/plan/upgrade/free", "href": "http://test.host/plan/upgrade/free",
"text": "Upgrade", "text": "Upgrade",
}, },
Object {
"href": "http://test.host/plan/renew",
"text": "Renew",
},
Object { Object {
"href": "https://customers.gitlab.com/subscriptions", "href": "https://customers.gitlab.com/subscriptions",
"text": "Manage", "text": "Manage",
...@@ -26,8 +34,12 @@ Array [ ...@@ -26,8 +34,12 @@ Array [
] ]
`; `;
exports[`SubscriptionTable component given a gold plan with state: isFreePlan=false, upgradable=false, isTrialPlan=false has Manage button 1`] = ` exports[`SubscriptionTable component given a gold plan with state: isFreePlan=false, upgradable=false, isTrialPlan=false has Renew and Manage buttons 1`] = `
Array [ Array [
Object {
"href": "http://test.host/plan/renew",
"text": "Renew",
},
Object { Object {
"href": "https://customers.gitlab.com/subscriptions", "href": "https://customers.gitlab.com/subscriptions",
"text": "Manage", "text": "Manage",
...@@ -37,6 +49,10 @@ Array [ ...@@ -37,6 +49,10 @@ Array [
exports[`SubscriptionTable component given a trial-gold plan with state: isFreePlan=false, upgradable=false, isTrialPlan=true has Manage button 1`] = ` exports[`SubscriptionTable component given a trial-gold plan with state: isFreePlan=false, upgradable=false, isTrialPlan=true has Manage button 1`] = `
Array [ Array [
Object {
"href": "http://test.host/plan/renew",
"text": "Renew",
},
Object { Object {
"href": "https://customers.gitlab.com/subscriptions", "href": "https://customers.gitlab.com/subscriptions",
"text": "Manage", "text": "Manage",
......
...@@ -17,6 +17,7 @@ describe('SubscriptionApp component', () => { ...@@ -17,6 +17,7 @@ describe('SubscriptionApp component', () => {
namespaceId: '42', namespaceId: '42',
namespaceName: 'bronze', namespaceName: 'bronze',
planUpgradeHref: '/url', planUpgradeHref: '/url',
planRenewHref: '/url/for/renew',
customerPortalUrl: 'https://customers.gitlab.com/subscriptions', customerPortalUrl: 'https://customers.gitlab.com/subscriptions',
}; };
...@@ -58,6 +59,7 @@ describe('SubscriptionApp component', () => { ...@@ -58,6 +59,7 @@ describe('SubscriptionApp component', () => {
expectComponentWithProps(SubscriptionTable, { expectComponentWithProps(SubscriptionTable, {
namespaceName: providedFields.namespaceName, namespaceName: providedFields.namespaceName,
planUpgradeHref: providedFields.planUpgradeHref, planUpgradeHref: providedFields.planUpgradeHref,
planRenewHref: providedFields.planRenewHref,
customerPortalUrl: providedFields.customerPortalUrl, customerPortalUrl: providedFields.customerPortalUrl,
}); });
}); });
......
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui'; import { GlLoadingIcon } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants'; import { createLocalVue, shallowMount } from '@vue/test-utils';
import initialStore from 'ee/billings/subscriptions/store';
import * as types from 'ee/billings/subscriptions/store/mutation_types';
import SubscriptionTable from 'ee/billings/subscriptions/components/subscription_table.vue'; import SubscriptionTable from 'ee/billings/subscriptions/components/subscription_table.vue';
import SubscriptionTableRow from 'ee/billings/subscriptions/components/subscription_table_row.vue'; import SubscriptionTableRow from 'ee/billings/subscriptions/components/subscription_table_row.vue';
import initialStore from 'ee/billings/subscriptions/store';
import * as types from 'ee/billings/subscriptions/store/mutation_types';
import { mockDataSubscription } from 'ee_jest/billings/mock_data'; import { mockDataSubscription } from 'ee_jest/billings/mock_data';
import { TEST_HOST } from 'helpers/test_constants';
import Vuex from 'vuex';
const TEST_NAMESPACE_NAME = 'GitLab.com'; const TEST_NAMESPACE_NAME = 'GitLab.com';
const CUSTOMER_PORTAL_URL = 'https://customers.gitlab.com/subscriptions'; const CUSTOMER_PORTAL_URL = 'https://customers.gitlab.com/subscriptions';
...@@ -42,6 +42,7 @@ describe('SubscriptionTable component', () => { ...@@ -42,6 +42,7 @@ describe('SubscriptionTable component', () => {
propsData: { propsData: {
namespaceName: TEST_NAMESPACE_NAME, namespaceName: TEST_NAMESPACE_NAME,
planUpgradeHref: '/url/', planUpgradeHref: '/url/',
planRenewHref: '/url/for/renew',
customerPortalUrl: CUSTOMER_PORTAL_URL, customerPortalUrl: CUSTOMER_PORTAL_URL,
}, },
}); });
...@@ -90,21 +91,23 @@ describe('SubscriptionTable component', () => { ...@@ -90,21 +91,23 @@ describe('SubscriptionTable component', () => {
describe.each` describe.each`
planName | isFreePlan | upgradable | isTrialPlan | snapshotDesc planName | isFreePlan | upgradable | isTrialPlan | snapshotDesc
${'free'} | ${true} | ${true} | ${false} | ${'has Upgrade and Manage buttons'} ${'free'} | ${true} | ${true} | ${false} | ${'has Upgrade and Renew and Manage buttons'}
${'trial-gold'} | ${false} | ${false} | ${true} | ${'has Manage button'} ${'trial-gold'} | ${false} | ${false} | ${true} | ${'has Manage button'}
${'gold'} | ${false} | ${false} | ${false} | ${'has Manage button'} ${'gold'} | ${false} | ${false} | ${false} | ${'has Renew and Manage buttons'}
${'bronze'} | ${false} | ${true} | ${false} | ${'has Upgrade and Manage buttons'} ${'bronze'} | ${false} | ${true} | ${false} | ${'has Upgrade and Renew and Manage buttons'}
`( `(
'given a $planName plan with state: isFreePlan=$isFreePlan, upgradable=$upgradable, isTrialPlan=$isTrialPlan', 'given a $planName plan with state: isFreePlan=$isFreePlan, upgradable=$upgradable, isTrialPlan=$isTrialPlan',
({ planName, isFreePlan, upgradable, snapshotDesc }) => { ({ planName, isFreePlan, upgradable, snapshotDesc }) => {
beforeEach(() => { beforeEach(() => {
const planUpgradeHref = `${TEST_HOST}/plan/upgrade/${planName}`; const planUpgradeHref = `${TEST_HOST}/plan/upgrade/${planName}`;
const planRenewHref = `${TEST_HOST}/plan/renew`;
factory({ factory({
propsData: { propsData: {
namespaceName: TEST_NAMESPACE_NAME, namespaceName: TEST_NAMESPACE_NAME,
customerPortalUrl: CUSTOMER_PORTAL_URL, customerPortalUrl: CUSTOMER_PORTAL_URL,
planUpgradeHref, planUpgradeHref,
planRenewHref,
}, },
}); });
...@@ -126,4 +129,27 @@ describe('SubscriptionTable component', () => { ...@@ -126,4 +129,27 @@ describe('SubscriptionTable component', () => {
}); });
}, },
); );
describe('render button', () => {
window.gon = { features: {} };
afterEach(() => {
window.gon.features = {};
});
it('renders the renew button when feature flag is on', () => {
gon.features.saasManualRenewButton = true;
factory({ propsData: { namespaceName: TEST_NAMESPACE_NAME } });
expect(findButtonProps()).toStrictEqual([
{ text: 'Upgrade', href: '' },
{ text: 'Renew', href: '' },
]);
});
it('does not render the renew button when the feature flag is off', () => {
gon.features.saasManualRenewButton = false;
factory({ propsData: { namespaceName: TEST_NAMESPACE_NAME } });
expect(findButtonProps()).toStrictEqual([{ text: 'Upgrade', href: '' }]);
});
});
}); });
...@@ -15,12 +15,15 @@ RSpec.describe BillingPlansHelper do ...@@ -15,12 +15,15 @@ RSpec.describe BillingPlansHelper do
it 'returns data attributes' do it 'returns data attributes' do
upgrade_href = upgrade_href =
"#{EE::SUBSCRIPTIONS_URL}/gitlab/namespaces/#{group.id}/upgrade/#{plan.id}" "#{EE::SUBSCRIPTIONS_URL}/gitlab/namespaces/#{group.id}/upgrade/#{plan.id}"
renew_href =
"#{EE::SUBSCRIPTIONS_URL}/gitlab/namespaces/#{group.id}/renew"
billable_seats_href = helper.group_seat_usage_path(group) billable_seats_href = helper.group_seat_usage_path(group)
expect(helper.subscription_plan_data_attributes(group, plan)) expect(helper.subscription_plan_data_attributes(group, plan))
.to eq(namespace_id: group.id, .to eq(namespace_id: group.id,
namespace_name: group.name, namespace_name: group.name,
plan_upgrade_href: upgrade_href, plan_upgrade_href: upgrade_href,
plan_renew_href: renew_href,
customer_portal_url: customer_portal_url, customer_portal_url: customer_portal_url,
billable_seats_href: billable_seats_href) billable_seats_href: billable_seats_href)
end end
...@@ -38,6 +41,7 @@ RSpec.describe BillingPlansHelper do ...@@ -38,6 +41,7 @@ RSpec.describe BillingPlansHelper do
let(:plan) { Hashie::Mash.new(id: nil) } let(:plan) { Hashie::Mash.new(id: nil) }
it 'returns data attributes without upgrade href' do it 'returns data attributes without upgrade href' do
renew_href = "#{EE::SUBSCRIPTIONS_URL}/gitlab/namespaces/#{group.id}/renew"
billable_seats_href = helper.group_seat_usage_path(group) billable_seats_href = helper.group_seat_usage_path(group)
expect(helper.subscription_plan_data_attributes(group, plan)) expect(helper.subscription_plan_data_attributes(group, plan))
...@@ -45,6 +49,7 @@ RSpec.describe BillingPlansHelper do ...@@ -45,6 +49,7 @@ RSpec.describe BillingPlansHelper do
namespace_name: group.name, namespace_name: group.name,
customer_portal_url: customer_portal_url, customer_portal_url: customer_portal_url,
billable_seats_href: billable_seats_href, billable_seats_href: billable_seats_href,
plan_renew_href: renew_href,
plan_upgrade_href: nil) plan_upgrade_href: nil)
end end
end end
......
...@@ -26188,6 +26188,9 @@ msgstr "" ...@@ -26188,6 +26188,9 @@ msgstr ""
msgid "SubscriptionTable|Next invoice" msgid "SubscriptionTable|Next invoice"
msgstr "" msgstr ""
msgid "SubscriptionTable|Renew"
msgstr ""
msgid "SubscriptionTable|Seats currently in use" msgid "SubscriptionTable|Seats currently in use"
msgstr "" 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