diff --git a/core/src/main/kotlin/net/corda/core/contracts/FinanceTypes.kt b/core/src/main/kotlin/net/corda/core/contracts/FinanceTypes.kt index bcdca06360..02e1b6263b 100644 --- a/core/src/main/kotlin/net/corda/core/contracts/FinanceTypes.kt +++ b/core/src/main/kotlin/net/corda/core/contracts/FinanceTypes.kt @@ -48,6 +48,58 @@ data class Amount(val quantity: Long, val token: T) : Comparable> { val longQuantity = quantity.movePointRight(currency.defaultFractionDigits).toLong() return Amount(longQuantity, currency) } + + private val currencySymbols: Map = mapOf( + "$" to USD, + "£" to GBP, + "€" to EUR + ) + private val currencyCodes: Map by lazy { Currency.getAvailableCurrencies().map { it.currencyCode to it }.toMap() } + + /** + * Returns an amount that is equal to the given currency amount in text. Examples of what is supported: + * + * - 12 USD + * - 14.50 USD + * - 10 USD + * - 30 CHF + * - $10.24 + * - £13 + * - €5000 + * + * Note this method does NOT respect internationalisation rules: it ignores commas and uses . as the + * decimal point separator, always. It also ignores the users locale: $ is special cased to be USD, + * £ is special cased to GBP and € is special cased to Euro. Thus an input of $12 expecting some other + * countries dollar will not work. Do your own parsing if you need correct handling of currency amounts + * with locale-sensitive handling. + * + * @throws IllegalArgumentException if the input string was not understood. + */ + fun parseCurrency(input: String): Amount { + val i = input.filter { it != ',' } + try { + // First check the symbols at the front. + for ((symbol, currency) in currencySymbols) { + if (i.startsWith(symbol)) { + val rest = i.substring(symbol.length) + return fromDecimal(BigDecimal(rest), currency) + } + } + // Now check the codes at the end. + val split = i.split(' ') + if (split.size == 2) { + val (rest, code) = split + for ((cc, currency) in currencyCodes) { + if (cc == code) { + return fromDecimal(BigDecimal(rest), currency) + } + } + } + } catch(e: Exception) { + throw IllegalArgumentException("Could not parse $input as a currency", e) + } + throw IllegalArgumentException("Did not recognise the currency in $input or could not parse") + } } init { diff --git a/core/src/test/kotlin/net/corda/core/contracts/AmountTests.kt b/core/src/test/kotlin/net/corda/core/contracts/AmountTests.kt index 00a7ca8d2f..986a8b2c8b 100644 --- a/core/src/test/kotlin/net/corda/core/contracts/AmountTests.kt +++ b/core/src/test/kotlin/net/corda/core/contracts/AmountTests.kt @@ -23,4 +23,12 @@ class AmountTests { assertEquals(expected, amount.toDecimal()) assertEquals(amount, Amount.fromDecimal(amount.toDecimal(), amount.token)) } + + @Test + fun parsing() { + assertEquals(Amount(1234L, GBP), Amount.parseCurrency("£12.34")) + assertEquals(Amount(1200L, GBP), Amount.parseCurrency("£12")) + assertEquals(Amount(1000L, USD), Amount.parseCurrency("$10")) + assertEquals(Amount(1500000000L, CHF), Amount.parseCurrency("15,000,000 CHF")) + } } \ No newline at end of file