Added a validation for a minimum suggested amount for Tips & Donations (#17653)

closes https://github.com/TryGhost/Product/issues/3695

- Stripe has minimum charge amounts per currency, see
https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
- We double these limits in our validation, to take into account
currency conversions to the main currency used on the Stripe account. If
the publishers enters a suggested amount below the limit, they will see
an error in Admin
- 0 is permitted as default value and corresponds to "no suggested
amount"
This commit is contained in:
Sag 2023-08-09 16:36:29 +02:00 committed by GitHub
parent d24b41f99f
commit 99a9dea988
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 58 additions and 1 deletions

View File

@ -73,7 +73,11 @@
@class="gh-btn gh-btn-black gh-btn-icon" />
</div>
</GhFormGroup>
</div>
{{#if this.tipsAndDonationsError}}
<p class="gh-setting-error"><span class="red">{{this.tipsAndDonationsError}}</span></p>
{{/if}}
</GhFormGroup>
</div>
{{/liquid-if}}

View File

@ -2,10 +2,11 @@ import Component from '@glimmer/component';
import copyTextToClipboard from 'ghost-admin/utils/copy-text-to-clipboard';
import envConfig from 'ghost-admin/config/environment';
import {action} from '@ember/object';
import {currencies} from 'ghost-admin/utils/currency';
import {currencies, getSymbol, minimumAmountForCurrency} from 'ghost-admin/utils/currency';
import {inject} from 'ghost-admin/decorators/inject';
import {inject as service} from '@ember/service';
import {task, timeout} from 'ember-concurrency';
import {tracked} from '@glimmer/tracking';
const CURRENCIES = currencies.map((currency) => {
return {
@ -20,6 +21,7 @@ export default class TipsAndDonations extends Component {
@service membersUtils;
@inject config;
@tracked tipsAndDonationsError = '';
get allCurrencies() {
return CURRENCIES;
@ -58,7 +60,16 @@ export default class TipsAndDonations extends Component {
setDonationsSuggestedAmount(event) {
const amount = Math.abs(event.target.value);
const amountInCents = Math.round(amount * 100);
const currency = this.settings.donationsCurrency;
const symbol = getSymbol(currency);
const minimumAmount = minimumAmountForCurrency(currency);
if (amountInCents !== 0 && amountInCents < minimumAmount) {
this.tipsAndDonationsError = `The suggested amount cannot be less than ${symbol}${minimumAmount / 100}.`;
return;
}
this.tipsAndDonationsError = '';
this.settings.donationsSuggestedAmount = amountInCents;
}

View File

@ -162,3 +162,45 @@ export function getCurrencyOptions() {
}
];
}
/*
* Returns the minimum charge amount for a given currency,
* based on Stripe's requirements. Values here are double the Stripe limits, to take conversions to the settlement currency into account.
* @see https://stripe.com/docs/currencies#minimum-and-maximum-charge-amounts
* @param {String} currency Currency in the 3-letter ISO format (e.g. "USD", "EUR")
* @retuns {Number} Minimum amount in cents (e.g. 100 for $1.00)
*/
export function minimumAmountForCurrency(currency) {
switch (currency) {
case 'AED':
return 400;
case 'BGN':
return 200;
case 'CZK':
return 3000;
case 'DKK':
return 500;
case 'HKD':
return 800;
case 'HUF':
return 25000;
case 'JPY':
return 10000;
case 'MXN':
return 2000;
case 'MYR':
return 400;
case 'NOK':
return 600;
case 'PLN':
return 400;
case 'RON':
return 400;
case 'SEK':
return 600;
case 'THB':
return 2000;
default:
return 100;
}
}