Commit b493ec7b authored by Angelo Gulina's avatar Angelo Gulina Committed by Vitaly Slobodin

Display subtotal and tax line in Subscription Purchase

parent 521671b1
<script> <script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { mapState, mapGetters } from 'vuex'; import { mapState, mapGetters } from 'vuex';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import formattingMixins from '../../formatting_mixins'; import formattingMixins from '../../formatting_mixins';
export default { export default {
components: {
GlLink,
GlSprintf,
},
mixins: [formattingMixins], mixins: [formattingMixins],
computed: { computed: {
...mapState(['startDate', 'taxRate', 'numberOfUsers']), ...mapState(['startDate', 'taxRate', 'numberOfUsers']),
...@@ -16,6 +21,12 @@ export default { ...@@ -16,6 +21,12 @@ export default {
'totalAmount', 'totalAmount',
'usersPresent', 'usersPresent',
]), ]),
taxAmount() {
return this.taxRate ? this.formatAmount(this.vat, this.usersPresent) : '';
},
taxLine() {
return `${this.$options.i18n.tax} ${this.$options.i18n.taxNote}`;
},
}, },
i18n: { i18n: {
selectedPlanText: s__('Checkout|%{selectedPlanText} plan'), selectedPlanText: s__('Checkout|%{selectedPlanText} plan'),
...@@ -24,13 +35,14 @@ export default { ...@@ -24,13 +35,14 @@ export default {
dates: s__('Checkout|%{startDate} - %{endDate}'), dates: s__('Checkout|%{startDate} - %{endDate}'),
subtotal: s__('Checkout|Subtotal'), subtotal: s__('Checkout|Subtotal'),
tax: s__('Checkout|Tax'), tax: s__('Checkout|Tax'),
taxNote: s__('Checkout|(may be %{linkStart}charged upon purchase%{linkEnd})'),
total: s__('Checkout|Total'), total: s__('Checkout|Total'),
}, },
}; };
</script> </script>
<template> <template>
<div> <div>
<div class="d-flex justify-content-between bold gl-mt-3 gl-mb-3"> <div class="gl-display-flex gl-justify-content-space-between gl-font-weight-bold gl-my-3">
<div class="js-selected-plan"> <div class="js-selected-plan">
{{ sprintf($options.i18n.selectedPlanText, { selectedPlanText }) }} {{ sprintf($options.i18n.selectedPlanText, { selectedPlanText }) }}
<span v-if="usersPresent" class="js-number-of-users">{{ <span v-if="usersPresent" class="js-number-of-users">{{
...@@ -39,14 +51,14 @@ export default { ...@@ -39,14 +51,14 @@ export default {
</div> </div>
<div class="js-amount">{{ formatAmount(totalExVat, usersPresent) }}</div> <div class="js-amount">{{ formatAmount(totalExVat, usersPresent) }}</div>
</div> </div>
<div class="text-secondary js-per-user"> <div class="gl-text-gray-500 js-per-user">
{{ {{
sprintf($options.i18n.pricePerUserPerYear, { sprintf($options.i18n.pricePerUserPerYear, {
selectedPlanPrice: selectedPlanPrice.toLocaleString(), selectedPlanPrice: selectedPlanPrice.toLocaleString(),
}) })
}} }}
</div> </div>
<div class="text-secondary js-dates"> <div class="gl-text-gray-500 js-dates">
{{ {{
sprintf($options.i18n.dates, { sprintf($options.i18n.dates, {
startDate: formatDate(startDate), startDate: formatDate(startDate),
...@@ -54,19 +66,31 @@ export default { ...@@ -54,19 +66,31 @@ export default {
}) })
}} }}
</div> </div>
<div v-if="taxRate"> <div>
<div class="border-bottom gl-mt-3 gl-mb-3"></div> <div class="border-bottom gl-mt-3 gl-mb-3"></div>
<div class="d-flex justify-content-between text-secondary"> <div class="gl-display-flex gl-justify-content-space-between gl-text-gray-500">
<div>{{ $options.i18n.subtotal }}</div> <div>{{ $options.i18n.subtotal }}</div>
<div class="js-total-ex-vat">{{ formatAmount(totalExVat, usersPresent) }}</div> <div class="js-total-ex-vat">{{ formatAmount(totalExVat, usersPresent) }}</div>
</div> </div>
<div class="d-flex justify-content-between text-secondary"> <div class="gl-display-flex gl-justify-content-space-between gl-text-gray-500">
<div>{{ $options.i18n.tax }}</div> <div data-testid="tax-info-line">
<div class="js-vat">{{ formatAmount(vat, usersPresent) }}</div> <gl-sprintf :message="taxLine">
<template #link="{ content }">
<gl-link
class="gl-text-decoration-underline gl-text-gray-500"
href="https://about.gitlab.com/handbook/tax/#indirect-taxes-management"
target="_blank"
data-testid="tax-help-link"
>{{ content }}</gl-link
>
</template>
</gl-sprintf>
</div>
<div class="js-vat">{{ taxAmount }}</div>
</div> </div>
</div> </div>
<div class="border-bottom gl-mt-3 gl-mb-3"></div> <div class="gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-mt-3 gl-mb-3"></div>
<div class="d-flex justify-content-between bold gl-font-lg"> <div class="gl-display-flex gl-justify-content-space-between gl-font-lg gl-font-weight-bold">
<div>{{ $options.i18n.total }}</div> <div>{{ $options.i18n.total }}</div>
<div class="js-total-amount">{{ formatAmount(totalAmount, usersPresent) }}</div> <div class="js-total-amount">{{ formatAmount(totalAmount, usersPresent) }}</div>
</div> </div>
......
import { mount, createLocalVue } from '@vue/test-utils'; import { createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex'; import Vuex from 'vuex';
import Component from 'ee/subscriptions/new/components/order_summary.vue'; import Component from 'ee/subscriptions/new/components/order_summary.vue';
import createStore from 'ee/subscriptions/new/store'; import createStore from 'ee/subscriptions/new/store';
import * as types from 'ee/subscriptions/new/store/mutation_types'; import * as types from 'ee/subscriptions/new/store/mutation_types';
import { mountExtended } from 'helpers/vue_test_utils_helper';
describe('Order Summary', () => { describe('Order Summary', () => {
const localVue = createLocalVue(); const localVue = createLocalVue();
...@@ -23,10 +24,12 @@ describe('Order Summary', () => { ...@@ -23,10 +24,12 @@ describe('Order Summary', () => {
fullName: 'Full Name', fullName: 'Full Name',
}; };
const store = createStore(initialData); const findTaxInfoLine = () => wrapper.findByTestId('tax-info-line');
const findTaxHelpLink = () => wrapper.findByTestId('tax-help-link');
const store = createStore(initialData);
const createComponent = (opts = {}) => { const createComponent = (opts = {}) => {
wrapper = mount(Component, { wrapper = mountExtended(Component, {
localVue, localVue,
store, store,
...opts, ...opts,
...@@ -47,7 +50,7 @@ describe('Order Summary', () => { ...@@ -47,7 +50,7 @@ describe('Order Summary', () => {
store.commit(types.UPDATE_IS_SETUP_FOR_COMPANY, false); store.commit(types.UPDATE_IS_SETUP_FOR_COMPANY, false);
}); });
it('should display the title with the passed name', () => { it('displays the title with the passed name', () => {
expect(wrapper.find('h4').text()).toContain("Full Name's GitLab subscription"); expect(wrapper.find('h4').text()).toContain("Full Name's GitLab subscription");
}); });
}); });
...@@ -58,7 +61,7 @@ describe('Order Summary', () => { ...@@ -58,7 +61,7 @@ describe('Order Summary', () => {
}); });
describe('Without a group name provided', () => { describe('Without a group name provided', () => {
it('should display the title with the default name', () => { it('displays the title with the default name', () => {
expect(wrapper.find('h4').text()).toContain("Your organization's GitLab subscription"); expect(wrapper.find('h4').text()).toContain("Your organization's GitLab subscription");
}); });
}); });
...@@ -68,7 +71,7 @@ describe('Order Summary', () => { ...@@ -68,7 +71,7 @@ describe('Order Summary', () => {
store.commit(types.UPDATE_ORGANIZATION_NAME, 'My group'); store.commit(types.UPDATE_ORGANIZATION_NAME, 'My group');
}); });
it('when given a group name, it should display the title with the group name', () => { it('displays the title with the group name', () => {
expect(wrapper.find('h4').text()).toContain("My group's GitLab subscription"); expect(wrapper.find('h4').text()).toContain("My group's GitLab subscription");
}); });
}); });
...@@ -77,30 +80,30 @@ describe('Order Summary', () => { ...@@ -77,30 +80,30 @@ describe('Order Summary', () => {
describe('Changing the plan', () => { describe('Changing the plan', () => {
describe('the selected plan', () => { describe('the selected plan', () => {
it('should display the chosen plan', () => { it('displays the chosen plan', () => {
expect(wrapper.find('.js-selected-plan').text()).toContain('Gold plan'); expect(wrapper.find('.js-selected-plan').text()).toContain('Gold plan');
}); });
it('should display the correct formatted amount price per user', () => { it('displays the correct formatted amount price per user', () => {
expect(wrapper.find('.js-per-user').text()).toContain('$1,188 per user per year'); expect(wrapper.find('.js-per-user').text()).toContain('$1,188 per user per year');
}); });
}); });
describe('the default plan', () => { describe('with the default plan', () => {
beforeEach(() => { beforeEach(() => {
store.commit(types.UPDATE_SELECTED_PLAN, 'firstPlanId'); store.commit(types.UPDATE_SELECTED_PLAN, 'firstPlanId');
store.commit(types.UPDATE_NUMBER_OF_USERS, 1); store.commit(types.UPDATE_NUMBER_OF_USERS, 1);
}); });
it('should display the chosen plan', () => { it('displays the chosen plan', () => {
expect(wrapper.find('.js-selected-plan').text()).toContain('Bronze plan'); expect(wrapper.find('.js-selected-plan').text()).toContain('Bronze plan');
}); });
it('should display the correct formatted amount price per user', () => { it('displays the correct formatted amount price per user', () => {
expect(wrapper.find('.js-per-user').text()).toContain('$48 per user per year'); expect(wrapper.find('.js-per-user').text()).toContain('$48 per user per year');
}); });
it('should display the correct formatted total amount', () => { it('displays the correct formatted total amount', () => {
expect(wrapper.find('.js-total-amount').text()).toContain('$48'); expect(wrapper.find('.js-total-amount').text()).toContain('$48');
}); });
}); });
...@@ -112,48 +115,48 @@ describe('Order Summary', () => { ...@@ -112,48 +115,48 @@ describe('Order Summary', () => {
store.commit(types.UPDATE_NUMBER_OF_USERS, 1); store.commit(types.UPDATE_NUMBER_OF_USERS, 1);
}); });
describe('the default of 1 selected user', () => { describe('with the default of 1 selected user', () => {
it('should display the correct number of users', () => { it('displays the correct number of users', () => {
expect(wrapper.find('.js-number-of-users').text()).toContain('(x1)'); expect(wrapper.find('.js-number-of-users').text()).toContain('(x1)');
}); });
it('should display the correct formatted amount price per user', () => { it('displays the correct formatted amount price per user', () => {
expect(wrapper.find('.js-per-user').text()).toContain('$1,188 per user per year'); expect(wrapper.find('.js-per-user').text()).toContain('$1,188 per user per year');
}); });
it('should display the correct multiplied formatted amount of the chosen plan', () => { it('displays the correct multiplied formatted amount of the chosen plan', () => {
expect(wrapper.find('.js-amount').text()).toContain('$1,188'); expect(wrapper.find('.js-amount').text()).toContain('$1,188');
}); });
it('should display the correct formatted total amount', () => { it('displays the correct formatted total amount', () => {
expect(wrapper.find('.js-total-amount').text()).toContain('$1,188'); expect(wrapper.find('.js-total-amount').text()).toContain('$1,188');
}); });
}); });
describe('3 selected users', () => { describe('with 3 selected users', () => {
beforeEach(() => { beforeEach(() => {
store.commit(types.UPDATE_SELECTED_PLAN, 'thirdPlanId'); store.commit(types.UPDATE_SELECTED_PLAN, 'thirdPlanId');
store.commit(types.UPDATE_NUMBER_OF_USERS, 3); store.commit(types.UPDATE_NUMBER_OF_USERS, 3);
}); });
it('should display the correct number of users', () => { it('displays the correct number of users', () => {
expect(wrapper.find('.js-number-of-users').text()).toContain('(x3)'); expect(wrapper.find('.js-number-of-users').text()).toContain('(x3)');
}); });
it('should display the correct formatted amount price per user', () => { it('displays the correct formatted amount price per user', () => {
expect(wrapper.find('.js-per-user').text()).toContain('$1,188 per user per year'); expect(wrapper.find('.js-per-user').text()).toContain('$1,188 per user per year');
}); });
it('should display the correct multiplied formatted amount of the chosen plan', () => { it('displays the correct multiplied formatted amount of the chosen plan', () => {
expect(wrapper.find('.js-amount').text()).toContain('$3,564'); expect(wrapper.find('.js-amount').text()).toContain('$3,564');
}); });
it('should display the correct formatted total amount', () => { it('displays the correct formatted total amount', () => {
expect(wrapper.find('.js-total-amount').text()).toContain('$3,564'); expect(wrapper.find('.js-total-amount').text()).toContain('$3,564');
}); });
}); });
describe('no selected users', () => { describe('with no selected users', () => {
beforeEach(() => { beforeEach(() => {
store.commit(types.UPDATE_SELECTED_PLAN, 'thirdPlanId'); store.commit(types.UPDATE_SELECTED_PLAN, 'thirdPlanId');
store.commit(types.UPDATE_NUMBER_OF_USERS, 0); store.commit(types.UPDATE_NUMBER_OF_USERS, 0);
...@@ -163,7 +166,7 @@ describe('Order Summary', () => { ...@@ -163,7 +166,7 @@ describe('Order Summary', () => {
expect(wrapper.find('.js-number-of-users').exists()).toBe(false); expect(wrapper.find('.js-number-of-users').exists()).toBe(false);
}); });
it('should display the correct formatted amount price per user', () => { it('displays the correct formatted amount price per user', () => {
expect(wrapper.find('.js-per-user').text()).toContain('$1,188 per user per year'); expect(wrapper.find('.js-per-user').text()).toContain('$1,188 per user per year');
}); });
...@@ -171,7 +174,7 @@ describe('Order Summary', () => { ...@@ -171,7 +174,7 @@ describe('Order Summary', () => {
expect(wrapper.find('.js-amount').text()).toContain('-'); expect(wrapper.find('.js-amount').text()).toContain('-');
}); });
it('should display the correct formatted total amount', () => { it('displays the correct formatted total amount', () => {
expect(wrapper.find('.js-total-amount').text()).toContain('-'); expect(wrapper.find('.js-total-amount').text()).toContain('-');
}); });
}); });
...@@ -187,13 +190,25 @@ describe('Order Summary', () => { ...@@ -187,13 +190,25 @@ describe('Order Summary', () => {
}); });
describe('tax rate', () => { describe('tax rate', () => {
describe('a tax rate of 0', () => { describe('with a tax rate of 0', () => {
it('should not display the total amount excluding vat', () => { it('displays the total amount excluding vat', () => {
expect(wrapper.find('.js-total-ex-vat').exists()).toBe(false); expect(wrapper.find('.js-total-ex-vat').exists()).toBe(true);
});
it('displays the vat amount with a stopgap', () => {
expect(wrapper.find('.js-vat').text()).toBe('');
});
it('displays an info line', () => {
expect(findTaxInfoLine().text()).toMatchInterpolatedText(
'Tax (may be charged upon purchase)',
);
}); });
it('should not display the vat amount', () => { it('contains a help link', () => {
expect(wrapper.find('.js-vat').exists()).toBe(false); expect(findTaxHelpLink().attributes('href')).toBe(
'https://about.gitlab.com/handbook/tax/#indirect-taxes-management',
);
}); });
}); });
...@@ -202,17 +217,29 @@ describe('Order Summary', () => { ...@@ -202,17 +217,29 @@ describe('Order Summary', () => {
store.state.taxRate = 0.08; store.state.taxRate = 0.08;
}); });
it('should display the total amount excluding vat', () => { it('displays the total amount excluding vat', () => {
expect(wrapper.find('.js-total-ex-vat').text()).toContain('$1,188'); expect(wrapper.find('.js-total-ex-vat').text()).toContain('$1,188');
}); });
it('should display the vat amount', () => { it('displays the vat amount', () => {
expect(wrapper.find('.js-vat').text()).toContain('$95.04'); expect(wrapper.find('.js-vat').text()).toContain('$95.04');
}); });
it('should display the total amount including the vat', () => { it('displays the total amount including the vat', () => {
expect(wrapper.find('.js-total-amount').text()).toContain('$1,283.04'); expect(wrapper.find('.js-total-amount').text()).toContain('$1,283.04');
}); });
it('displays an info line', () => {
expect(findTaxInfoLine().text()).toMatchInterpolatedText(
'Tax (may be charged upon purchase)',
);
});
it('contains a help link', () => {
expect(findTaxHelpLink().attributes('href')).toBe(
'https://about.gitlab.com/handbook/tax/#indirect-taxes-management',
);
});
}); });
}); });
}); });
......
...@@ -6497,6 +6497,9 @@ msgstr "" ...@@ -6497,6 +6497,9 @@ msgstr ""
msgid "Checkout|%{totalCiMinutes} CI minutes" msgid "Checkout|%{totalCiMinutes} CI minutes"
msgstr "" msgstr ""
msgid "Checkout|(may be %{linkStart}charged upon purchase%{linkEnd})"
msgstr ""
msgid "Checkout|(x%{numberOfUsers})" msgid "Checkout|(x%{numberOfUsers})"
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