Added support for 113 new currencies (#1853)

refs https://github.com/TryGhost/Team/issues/473

This list of currencies was compiled by taking the union of the UK and US from
https://stripe.com/docs/currencies and removing all non-decimal currencies, e.g.
Japanese Yen.

The members module does not need any additional logic to handle these currencies,
however we do need to clean up hardcoded currency symbols in favour of using the new
`{{price}}` helper and `Intl.NumberFormat`
This commit is contained in:
Fabien 'egg' O'Carroll 2021-02-25 09:47:08 +00:00 committed by GitHub
parent e253dfc0f0
commit 34b2162c32
3 changed files with 188 additions and 88 deletions

View File

@ -56,7 +56,7 @@
</div>
{{else}}
<div class="gh-expandable-block">
<div class="gh-expandable-header">
<div>

View File

@ -1,30 +1,10 @@
import Component from '@ember/component';
import {computed} from '@ember/object';
import {currencies} from 'ghost-admin/utils/currency';
import {reads} from '@ember/object/computed';
import {inject as service} from '@ember/service';
import {task} from 'ember-concurrency';
export const CURRENCIES = [
{
label: 'USD - US Dollar', value: 'usd', symbol: '$'
},
{
label: 'AUD - Australian Dollar', value: 'aud', symbol: '$'
},
{
label: 'CAD - Canadian Dollar', value: 'cad', symbol: '$'
},
{
label: 'EUR - Euro', value: 'eur', symbol: '€'
},
{
label: 'GBP - British Pound', value: 'gbp', symbol: '£'
},
{
label: 'INR - Indian Rupee', value: 'inr', symbol: '₹'
}
];
export default Component.extend({
feature: service(),
config: service(),
@ -47,7 +27,7 @@ export default Component.extend({
stripeDirect: reads('config.stripeDirect'),
allowSelfSignup: reads('settings.membersAllowFreeSignup'),
/** OLD **/
stripeDirectPublicKey: reads('settings.stripePublishableKey'),
stripeDirectSecretKey: reads('settings.stripeSecretKey'),
@ -59,7 +39,7 @@ export default Component.extend({
portalSettingsBorderColor: reads('settings.accentColor'),
selectedCurrency: computed('stripePlans.monthly.currency', function () {
return CURRENCIES.findBy('value', this.get('stripePlans.monthly.currency'));
return this.get('currencies').findBy('value', this.get('stripePlans.monthly.currency'));
}),
blogDomain: computed('config.blogDomain', function () {
@ -87,7 +67,13 @@ export default Component.extend({
init() {
this._super(...arguments);
this.set('currencies', CURRENCIES);
this.set('currencies', currencies.map((currency) => {
return {
value: currency.isoCode.toLowerCase(),
label: `${currency.isoCode} - ${currency.name}`,
isoCode: currency.isoCode
};
}));
if (this.get('stripeConnectAccountId')) {
this.set('membersStripeOpen', false);
} else {
@ -124,45 +110,7 @@ export default Component.extend({
},
validateStripePlans() {
this.get('settings.errors').remove('stripePlans');
this.get('settings.hasValidated').removeObject('stripePlans');
if (this._scratchStripeYearlyAmount === null) {
this._scratchStripeYearlyAmount = this.get('stripePlans').yearly.amount;
}
if (this._scratchStripeMonthlyAmount === null) {
this._scratchStripeMonthlyAmount = this.get('stripePlans').monthly.amount;
}
try {
const selectedCurrency = this.selectedCurrency;
const yearlyAmount = parseInt(this._scratchStripeYearlyAmount);
const monthlyAmount = parseInt(this._scratchStripeMonthlyAmount);
if (!yearlyAmount || yearlyAmount < 1 || !monthlyAmount || monthlyAmount < 1) {
throw new TypeError(`Subscription amount must be at least ${selectedCurrency.symbol}1.00`);
}
const updatedPlans = this.get('settings.stripePlans').map((plan) => {
if (plan.name !== 'Complimentary') {
let newAmount;
if (plan.interval === 'year') {
newAmount = yearlyAmount * 100;
} else if (plan.interval === 'month') {
newAmount = monthlyAmount * 100;
}
return Object.assign({}, plan, {
amount: newAmount
});
}
return plan;
});
this.set('settings.stripePlans', updatedPlans);
} catch (err) {
this.get('settings.errors').add('stripePlans', err.message);
} finally {
this.get('settings.hasValidated').pushObject('stripePlans');
}
this.validateStripePlans();
},
setStripePlansCurrency(event) {
@ -190,6 +138,9 @@ export default Component.extend({
}
this.set('settings.stripePlans', updatedPlans);
this.set('_scratchStripeYearlyAmount', null);
this.set('_scratchStripeMonthlyAmount', null);
this.validateStripePlans();
},
setStripeConnectIntegrationToken(event) {
@ -224,6 +175,53 @@ export default Component.extend({
}
},
validateStripePlans() {
this.get('settings.errors').remove('stripePlans');
this.get('settings.hasValidated').removeObject('stripePlans');
if (this._scratchStripeYearlyAmount === null) {
this._scratchStripeYearlyAmount = this.get('stripePlans').yearly.amount;
}
if (this._scratchStripeMonthlyAmount === null) {
this._scratchStripeMonthlyAmount = this.get('stripePlans').monthly.amount;
}
try {
const selectedCurrency = this.selectedCurrency;
const yearlyAmount = parseInt(this._scratchStripeYearlyAmount);
const monthlyAmount = parseInt(this._scratchStripeMonthlyAmount);
if (!yearlyAmount || yearlyAmount < 1 || !monthlyAmount || monthlyAmount < 1) {
const minimum = Intl.NumberFormat(this.settings.get('lang'), {
currency: selectedCurrency.isoCode,
style: 'currency'
}).format(1);
throw new TypeError(`Subscription amount must be at least ${minimum}`);
}
const updatedPlans = this.get('settings.stripePlans').map((plan) => {
if (plan.name !== 'Complimentary') {
let newAmount;
if (plan.interval === 'year') {
newAmount = yearlyAmount * 100;
} else if (plan.interval === 'month') {
newAmount = monthlyAmount * 100;
}
return Object.assign({}, plan, {
amount: newAmount
});
}
return plan;
});
this.set('settings.stripePlans', updatedPlans);
} catch (err) {
this.get('settings.errors').add('stripePlans', err.message);
} finally {
this.get('settings.hasValidated').pushObject('stripePlans');
}
},
openDisconnectStripeConnectModal: task(function* () {
this.set('hasActiveStripeSubscriptions', false);
if (!this.get('stripeConnectAccountId')) {

View File

@ -1,28 +1,130 @@
export const currencies = [
{isoCode: 'AED', name: 'United Arab Emirates dirham'},
{isoCode: 'AFN', name: 'Afghan afghani'},
{isoCode: 'ALL', name: 'Albanian lek'},
{isoCode: 'AMD', name: 'Armenian dram'},
{isoCode: 'ANG', name: 'Netherlands Antillean guilder'},
{isoCode: 'AOA', name: 'Angolan kwanza'},
{isoCode: 'ARS', name: 'Argentine peso'},
{isoCode: 'AUD', name: 'Austrialian dollar'},
{isoCode: 'AWG', name: 'Aruban florin'},
{isoCode: 'AZN', name: 'Azerbaijani manat'},
{isoCode: 'BAM', name: 'Bosnia and Herzegovina convertible mark'},
{isoCode: 'BBD', name: 'Barbados dollar'},
{isoCode: 'BDT', name: 'Bangladeshi taka'},
{isoCode: 'BGN', name: 'Bulgarian lev'},
{isoCode: 'BMD', name: 'Bermudian dollar'},
{isoCode: 'BND', name: 'Brunei dollar'},
{isoCode: 'BOB', name: 'Boliviano'},
{isoCode: 'BRL', name: 'Brazilian real'},
{isoCode: 'BSD', name: 'Bahamian dollar'},
{isoCode: 'BWP', name: 'Botswana pula'},
{isoCode: 'BZD', name: 'Belize dollar'},
{isoCode: 'CAD', name: 'Canadian dollar'},
{isoCode: 'CDF', name: 'Congolese franc'},
{isoCode: 'CHF', name: 'Swiss franc'},
{isoCode: 'CNY', name: 'Chinese yuan'},
{isoCode: 'COP', name: 'Colombian peso'},
{isoCode: 'CRC', name: 'Costa Rican colon'},
{isoCode: 'CVE', name: 'Cape Verdean escudo'},
{isoCode: 'CZK', name: 'Czech koruna'},
{isoCode: 'DKK', name: 'Danish krone'},
{isoCode: 'DOP', name: 'Dominican peso'},
{isoCode: 'DZD', name: 'Algerian dinar'},
{isoCode: 'EGP', name: 'Egyptian pound'},
{isoCode: 'ETB', name: 'Ethiopian birr'},
{isoCode: 'EUR', name: 'Euro'},
{isoCode: 'FJD', name: 'Fiji dollar'},
{isoCode: 'FKP', name: 'Falkland Islands pound'},
{isoCode: 'GBP', name: 'Pound sterling'},
{isoCode: 'GEL', name: 'Georgian lari'},
{isoCode: 'GIP', name: 'Gibraltar pound'},
{isoCode: 'GMD', name: 'Gambian dalasi'},
{isoCode: 'GTQ', name: 'Guatemalan queztal'},
{isoCode: 'GYD', name: 'Guyanese dollar'},
{isoCode: 'HKD', name: 'Hong Kong dollar'},
{isoCode: 'HNL', name: 'Honduran lempira'},
{isoCode: 'HRK', name: 'Croation kuna'},
{isoCode: 'HTG', name: 'Haitian gourde'},
{isoCode: 'HUF', name: 'Hungarian forint'},
{isoCode: 'IDR', name: 'Indonesian rupiah'},
{isoCode: 'ILS', name: 'Israeli new shekel'},
{isoCode: 'INR', name: 'Indian rupee'},
{isoCode: 'ISK', name: 'Icelandic króna'},
{isoCode: 'JMD', name: 'Jamaican dollar'},
{isoCode: 'KES', name: 'Kenyan shilling'},
{isoCode: 'KGS', name: 'Kyrgyzstani som'},
{isoCode: 'KHR', name: 'Cambodian riel'},
{isoCode: 'KYD', name: 'Cayman Islands dollar'},
{isoCode: 'KZT', name: 'Kazakhstani tenge'},
{isoCode: 'LAK', name: 'Lao kip'},
{isoCode: 'LBP', name: 'Lebanese pound'},
{isoCode: 'LKR', name: 'Sri Lankan rupee'},
{isoCode: 'LRD', name: 'Liberian dollar'},
{isoCode: 'LSL', name: 'Lesotho loti'},
{isoCode: 'MAD', name: 'Moroccan dirham'},
{isoCode: 'MDL', name: 'Moldovan leu'},
{isoCode: 'MKD', name: 'Macedonian denar'},
{isoCode: 'MMK', name: 'Myanmar kyat'},
{isoCode: 'MNT', name: 'Mongolian tögrög'},
{isoCode: 'MOP', name: 'Macanese pataca'},
{isoCode: 'MRO', name: 'Mauritanian ouguiya'},
{isoCode: 'MUR', name: 'Mauritian rupee'},
{isoCode: 'MVR', name: 'Maldivian rufiyaa'},
{isoCode: 'MWK', name: 'Malawian kwacha'},
{isoCode: 'MXN', name: 'Mexican peso'},
{isoCode: 'MYR', name: 'Malaysian ringgit'},
{isoCode: 'MZN', name: 'Mozambican metical'},
{isoCode: 'NAD', name: 'Namibian dollar'},
{isoCode: 'NGN', name: 'Nigerian naira'},
{isoCode: 'NIO', name: 'Nicaraguan córdoba'},
{isoCode: 'NOK', name: 'Norwegian krone'},
{isoCode: 'NPR', name: 'Nepalese rupee'},
{isoCode: 'NZD', name: 'New Zealand dollar'},
{isoCode: 'PAB', name: 'Panamanian balboa'},
{isoCode: 'PEN', name: 'Peruvian sol'},
{isoCode: 'PGK', name: 'Papua New Guinean kina'},
{isoCode: 'PHP', name: 'Philippine peso'},
{isoCode: 'PKR', name: 'Pakistani rupee'},
{isoCode: 'PLN', name: 'Polish złoty'},
{isoCode: 'QAR', name: 'Qatari riyal'},
{isoCode: 'RON', name: 'Romanian leu'},
{isoCode: 'RSD', name: 'Serbian dinar'},
{isoCode: 'RUB', name: 'Russian ruble'},
{isoCode: 'SAR', name: 'Saudi riyal'},
{isoCode: 'SBD', name: 'Solomon Islands dollar'},
{isoCode: 'SCR', name: 'Seychelles rupee'},
{isoCode: 'SEK', name: 'Swedish krona'},
{isoCode: 'SGD', name: 'Singapore dollar'},
{isoCode: 'SHP', name: 'Saint Helena pound'},
{isoCode: 'SLL', name: 'Sierra Leonean leone'},
{isoCode: 'SOS', name: 'Somali shilling'},
{isoCode: 'SRD', name: 'Surinamese dollar'},
{isoCode: 'STD', name: 'São Tomé and Príncipe dobra'},
{isoCode: 'SZL', name: 'Salvadoran colón'},
{isoCode: 'THB', name: 'Thai baht'},
{isoCode: 'TJS', name: 'Tajikistani somoni'},
{isoCode: 'TOP', name: 'Tongan paʻanga'},
{isoCode: 'TRY', name: 'Turkish lira'},
{isoCode: 'TTD', name: 'Trinidad and Tobago dollar'},
{isoCode: 'TWD', name: 'New Taiwan dollar'},
{isoCode: 'TZS', name: 'Tanzanian shilling'},
{isoCode: 'UAH', name: 'Ukrainian hryvnia'},
{isoCode: 'USD', name: 'United States dollar'},
{isoCode: 'UYU', name: 'Uruauayan peso'},
{isoCode: 'UZS', name: 'Uzbekistan som'},
{isoCode: 'WST', name: 'Samoan tala'},
{isoCode: 'XCD', name: 'East Caribbean dollar'},
{isoCode: 'YER', name: 'Yemeni rial'},
{isoCode: 'ZAR', name: 'South African rand'},
{isoCode: 'ZMW', name: 'Zambian kwacha'}
];
export function getSymbol(currency) {
switch (currency) {
case 'usd':
case 'aud':
case 'cad':
return '$';
case 'eur':
return '€';
case 'gbp':
return '£';
case 'inr':
return '₹';
}
return null;
return Intl.NumberFormat('en', {currency, style: 'currency'}).format(0).replace(/[\d\s.]/g, '');
}
export function getNonDecimal(amount, currency) {
switch (currency) {
case 'usd':
case 'aud':
case 'cad':
case 'eur':
case 'gbp':
case 'inr':
return amount / 100;
}
return null;
// We currently only support decimal currencies
export function getNonDecimal(amount/*, currency*/) {
return amount / 100;
}