Added support for setting custom currency on member's plans

refs c0512e30bb

- Adds a dropdown allowing to select and set custom currency.
- At the moment we don't have a specific way to interface with the members configuration API so all values are set directly on existing "config JSON". Ideally we should add more validations and be more precise what values can be set for the `stripeProcessor.config.*` values.
- Saves selected currency in `stripeProcessor.config.currency` variable.
This commit is contained in:
Nazar Gargol 2020-03-04 13:31:39 +08:00
parent 86460ffef6
commit 1c9a4399e0
4 changed files with 82 additions and 9 deletions

View File

@ -37,7 +37,7 @@ export default Component.extend({
status: subscription.status,
startDate: subscription.start_date ? moment(subscription.start_date).format('MMM DD YYYY') : '-',
plan: subscription.plan,
dollarAmount: parseInt(subscription.plan.amount) ? (subscription.plan.amount / 100) : 0,
amount: parseInt(subscription.plan.amount) ? (subscription.plan.amount / 100) : 0,
cancelAtPeriodEnd: subscription.cancel_at_period_end,
validUntil: subscription.current_period_end ? moment(subscription.current_period_end).format('MMM DD YYYY') : '-'
};

View File

@ -7,13 +7,40 @@ import {set} from '@ember/object';
const US = {flag: '🇺🇸', name: 'US', baseUrl: 'https://api.mailgun.net/v3'};
const EU = {flag: '🇪🇺', name: 'EU', baseUrl: 'https://api.eu.mailgun.net/v3'};
const CURRENCIES = [
{
label: 'USD - US Dollar', value: 'usd'
},
{
label: 'AUD - Australian Dollar', value: 'aud'
},
{
label: 'CAD - Canadian Dollar', value: 'cad'
},
{
label: 'EUR - Euro', value: 'eur'
},
{
label: 'GBP - British Pound', value: 'gbp'
}
];
export default Component.extend({
feature: service(),
config: service(),
mediaQueries: service(),
currencies: null,
// passed in actions
setMembersSubscriptionSettings() {},
defaultContentVisibility: reads('settings.defaultContentVisibility'),
selectedCurrency: computed('subscriptionSettings.stripeConfig.plans.monthly.currency', function () {
return CURRENCIES.findBy('value', this.get('subscriptionSettings.stripeConfig.plans.monthly.currency'));
}),
mailgunRegion: computed('settings.bulkEmailSettings.baseUrl', function () {
if (!this.settings.get('bulkEmailSettings.baseUrl')) {
return US;
@ -37,8 +64,12 @@ export default Component.extend({
});
let monthlyPlan = stripeProcessor.config.plans.find(plan => plan.interval === 'month');
let yearlyPlan = stripeProcessor.config.plans.find(plan => plan.interval === 'year');
monthlyPlan.dollarAmount = parseInt(monthlyPlan.amount) ? (monthlyPlan.amount / 100) : 0;
yearlyPlan.dollarAmount = parseInt(yearlyPlan.amount) ? (yearlyPlan.amount / 100) : 0;
// NOTE: need to be careful about division by zero if we introduce zero decimal currencies
// ref.: https://stripe.com/docs/currencies#zero-decimal
monthlyPlan.amount = parseInt(monthlyPlan.amount) ? (monthlyPlan.amount / 100) : 0;
yearlyPlan.amount = parseInt(yearlyPlan.amount) ? (yearlyPlan.amount / 100) : 0;
stripeProcessor.config.plans = {
monthly: monthlyPlan,
yearly: yearlyPlan
@ -64,12 +95,14 @@ export default Component.extend({
init() {
this._super(...arguments);
this.set('mailgunRegions', [US, EU]);
this.set('currencies', CURRENCIES);
},
actions: {
setDefaultContentVisibility(value) {
this.setDefaultContentVisibility(value);
},
setBulkEmailSettings(key, event) {
let bulkEmailSettings = this.get('settings.bulkEmailSettings') || {};
bulkEmailSettings[key] = event.target.value;
@ -78,11 +111,13 @@ export default Component.extend({
}
this.setBulkEmailSettings(bulkEmailSettings);
},
setBulkEmailRegion(region) {
let bulkEmailSettings = this.get('settings.bulkEmailSettings') || {};
set(bulkEmailSettings, 'baseUrl', region.baseUrl);
this.setBulkEmailSettings(bulkEmailSettings);
},
setSubscriptionSettings(key, event) {
let subscriptionSettings = this.settings.parseSubscriptionSettings(this.get('settings.membersSubscriptionSettings'));
let stripeProcessor = subscriptionSettings.paymentProcessors.find((proc) => {
@ -113,6 +148,27 @@ export default Component.extend({
if (key === 'fromAddress') {
subscriptionSettings.fromAddress = event.target.value;
}
if (key === 'currency') {
stripeProcessor.config.plans.forEach((plan) => {
if (plan.name !== 'Complimentary') {
plan.currency = event.value;
}
});
// NOTE: need to keep Complimentary plans with all available currencies so they don't conflict
// when applied to members with existing subscriptions in different currencies (ref. https://stripe.com/docs/billing/customer#currency)
let currentCurrencyComplimentary = stripeProcessor.config.plans.filter(plan => (plan.currency === event.value && plan.name === 'Complimentary'));
if (!currentCurrencyComplimentary.length) {
let complimentary = stripeProcessor.config.plans.find(plan => (plan.name === 'Complimentary'));
let newComplimentary = Object.assign({}, complimentary, {currency: event.value});
stripeProcessor.config.plans.push(newComplimentary);
}
stripeProcessor.config.currency = event.value;
}
this.setMembersSubscriptionSettings(subscriptionSettings);
}
}

View File

@ -132,7 +132,7 @@
<td class="gh-member-stripe-label">Plan</td>
<td class="gh-member-stripe-data">
{{subscription.plan.nickname}}
<span class="midgrey">({{subscription.dollarAmount}}
<span class="midgrey">({{subscription.amount}}
<span class="ttu">{{subscription.plan.currency}}</span>/{{subscription.plan.interval}})
</span>
</td>

View File

@ -65,17 +65,35 @@
{{#liquid-if this.membersPricingOpen}}
<div class="w-100 w-50-l flex flex-column flex-row-ns mt8">
<div class="w-100">
<GhFormGroup @class="for-select">
<label class="fw6 f8"for="currency">Plan currency</label>
<span class="gh-select mt1">
{{one-way-select this.selectedCurrency
id="currency"
name="currency"
options=(readonly this.currencies)
optionValuePath="value"
optionLabelPath="label"
update=(action "setSubscriptionSettings" "currency")
}}
{{svg-jar "arrow-down-small"}}
</span>
</GhFormGroup>
</div>
</div>
<div class="w-100 w-50-l flex flex-column flex-row-ns">
<div class="w-100 w-50-ns mr3-ns">
<GhFormGroup>
<label class="fw6 f8">Monthly price</label>
<div class="flex items-center justify-center mt1 gh-input-group gh-labs-price-label">
<GhTextInput
@value={{readonly this.subscriptionSettings.stripeConfig.plans.monthly.dollarAmount}}
@value={{readonly this.subscriptionSettings.stripeConfig.plans.monthly.amount}}
@type="number"
@input={{action "setSubscriptionSettings" "month"}}
/>
<span class="gh-input-append">USD/month</span>
<span class="gh-input-append"><span class="ttu">{{this.subscriptionSettings.stripeConfig.plans.monthly.currency}}</span>/month</span>
</div>
</GhFormGroup>
</div>
@ -84,16 +102,15 @@
<label class="fw6 f8">Yearly price</label>
<div class="flex items-center justify-center mt1 gh-input-group gh-labs-price-label">
<GhTextInput
@value={{readonly this.subscriptionSettings.stripeConfig.plans.yearly.dollarAmount}}
@value={{readonly this.subscriptionSettings.stripeConfig.plans.yearly.amount}}
@type="number"
@input={{action "setSubscriptionSettings" "year"}}
/>
<span class="gh-input-append">USD/year</span>
<span class="gh-input-append"><span class="ttu">{{this.subscriptionSettings.stripeConfig.plans.yearly.currency}}</span>/year</span>
</div>
</GhFormGroup>
</div>
</div>
<div class="f8 fw4 midgrey">Currently only USD is supported, more currencies <a href="https://ghost.org/docs/members/" target="_blank" rel="noopener">coming soon</a></div>
{{/liquid-if}}
</section>