corda/src/Amounts.kt

50 lines
2.1 KiB
Kotlin

import java.math.BigDecimal
import java.util.*
import kotlin.math.div
/**
* Amount represents a positive quantity of currency, measured in pennies, which are the smallest representable units.
* Note that "pennies" are not necessarily 1/100ths of a currency unit, but are the actual smallest amount used in
* whatever currency the amount represents.
*
* Amounts of different currencies *do not mix* and attempting to add or subtract two amounts of different currencies
* will throw [IllegalArgumentException]. Amounts may not be negative.
*/
data class Amount(val pennies: Int, val currency: Currency) : Comparable<Amount> {
init {
// Negative amounts are of course a vital part of any ledger, but negative values are only valid in certain
// contexts: you cannot send a negative amount of cash, but you can (sometimes) have a negative balance.
require(pennies >= 0) { "Negative amounts are not allowed: $pennies" }
}
operator fun plus(other: Amount): Amount {
checkCurrency(other)
return Amount(pennies + other.pennies, currency)
}
operator fun minus(other: Amount): Amount {
checkCurrency(other)
return Amount(pennies - other.pennies, currency)
}
private fun checkCurrency(other: Amount) {
require(other.currency == currency) { "Currency mismatch: ${other.currency} vs $currency" }
}
operator fun div(other: Int): Amount = Amount(pennies / other, currency)
operator fun times(other: Int): Amount = Amount(pennies * other, currency)
override fun toString(): String = currency.currencyCode + " " + (BigDecimal(pennies) / BigDecimal(100)).toPlainString()
override fun compareTo(other: Amount): Int {
checkCurrency(other)
return pennies.compareTo(other.pennies)
}
}
// Note: this will throw an exception if the iterable is empty.
fun Iterable<Amount>.sum() = reduce { left, right -> left + right }
fun Iterable<Amount>.sumOrZero(currency: Currency) = if (iterator().hasNext()) sum() else Amount(0, currency)
// TODO: Think about how positive-only vs positive-or-negative amounts can be represented in the type system.