Add more functinos for money extension and fixed the curreny and object currency and default std money value and more

This commit is contained in:
Sambo Chea 2021-02-08 16:08:00 +07:00
parent 36599b5fb5
commit 3a7141cf76
8 changed files with 185 additions and 43 deletions

View File

@ -12,7 +12,7 @@ open class Money(
// not imply with exchange rate yet // not imply with exchange rate yet
override fun StdMoney.getExchangedTo(currency: StdMoney.Currency): Double { override fun StdMoney.getExchangedTo(currency: StdMoney.Currency): Double {
return getMoneyValue() return MoneyExchangeUtils.exchange(this, currency).getMoneyValue()
} }
override fun getMoneyCurrency(): StdMoney.Currency { override fun getMoneyCurrency(): StdMoney.Currency {
@ -22,7 +22,7 @@ open class Money(
//////////////////// - GENERIC - //////////////////// //////////////////// - GENERIC - ////////////////////
override fun toString(): String { override fun toString(): String {
return "Money(value=${getMoneyValue()}, currency='${getMoneyCurrency()}')" return "Money(value=${getMoneyValue()}, currency='${getMoneyCurrency().getCurrency()}')"
} }
override fun inc(): Money = apply { override fun inc(): Money = apply {
@ -38,6 +38,11 @@ open class Money(
return Money(value = temp, currency = this.currency) return Money(value = temp, currency = this.currency)
} }
override fun minus(other: StdMoney): Money {
val temp = this.value - other.getExchangedTo(this.currency)
return Money(value = temp, currency = this.currency)
}
override fun divide(other: StdMoney): Money { override fun divide(other: StdMoney): Money {
val temp = this.value / other.getExchangedTo(this.currency) val temp = this.value / other.getExchangedTo(this.currency)
return Money(value = temp, currency = this.currency) return Money(value = temp, currency = this.currency)
@ -48,27 +53,28 @@ open class Money(
return Money(value = temp, currency = this.currency) return Money(value = temp, currency = this.currency)
} }
override fun plusAssign(other: StdMoney) { override fun plusAssign(other: StdMoney): Money = apply {
this.value = this.value + other.getExchangedTo(this.currency) this.value = this.value + other.getExchangedTo(this.currency)
} }
override fun divideAssign(other: StdMoney) { override fun minusAssign(other: StdMoney): Money = apply {
this.value = this.value - other.getExchangedTo(this.currency)
}
override fun divideAssign(other: StdMoney): Money = apply {
this.value = this.value / other.getExchangedTo(this.currency) this.value = this.value / other.getExchangedTo(this.currency)
} }
override fun multiplyAssign(other: StdMoney) { override fun multiplyAssign(other: StdMoney): Money = apply {
this.value = this.value * other.getExchangedTo(this.getMoneyCurrency()) this.value = this.value * other.getExchangedTo(this.getMoneyCurrency())
} }
companion object { companion object {
val ZERO: StdMoney
get() = Money()
val ONE: StdMoney val ONE: StdMoney
get() = Money(value = 1.0) get() = StdMoney.initMoney(1.0)
val TEN: StdMoney val TEN: StdMoney
get() = Money(value = 10.0) get() = StdMoney.initMoney(10.0)
/** /**
* Create a new money object with custom value * Create a new money object with custom value
@ -81,11 +87,7 @@ open class Money(
} }
fun from(value: Double, currency: String): Money { fun from(value: Double, currency: String): Money {
return create(value, object : StdMoney.Currency { return create(value, StdMoney.initCurrency(currency))
override fun getCurrency(): String {
return currency.toUpperCase().trim()
}
})
} }
fun from(money: StdMoney): Money { fun from(money: StdMoney): Money {

View File

@ -11,7 +11,7 @@ import java.io.Serializable
open class MoneyCurrency( open class MoneyCurrency(
private val name: String, private val name: String,
private val symbol: String? = null, private val symbol: String? = null,
private val configs: Map<String, Any?>? = null, private var configs: Map<String, Any?>? = null,
) : Serializable, StdMoney.Currency { ) : Serializable, StdMoney.Currency {
override fun getCurrency(): String { override fun getCurrency(): String {
return name.toUpperCase().trim() return name.toUpperCase().trim()
@ -21,6 +21,14 @@ open class MoneyCurrency(
return symbol ?: getConfigs()["symbol"]?.toString() return symbol ?: getConfigs()["symbol"]?.toString()
} }
fun addConfig(key: String, value: Any?) = apply {
if (this.configs.isNullOrEmpty()) {
this.configs = mutableMapOf(key to value)
} else {
(this.configs as MutableMap)[key] = value
}
}
fun getConfigs(): Map<String, Any?> { fun getConfigs(): Map<String, Any?> {
return configs ?: emptyMap() return configs ?: emptyMap()
} }
@ -35,9 +43,9 @@ open class MoneyCurrency(
} }
val USD val USD
get() = create("USD") get() = StdMoney.USD
val KHR val KHR
get() = create("KHR") get() = StdMoney.KHR
} }
} }

View File

@ -11,11 +11,7 @@ object MoneyExchangeUtils {
return amountFrom * ((baseRate / rateFrom) / (baseRate / rateTo)) return amountFrom * ((baseRate / rateFrom) / (baseRate / rateTo))
} }
fun getBaseCurrency(): MoneyCurrency { fun getBaseCurrency(): StdMoney.Currency {
return MoneyCurrency.USD return StdMoney.USD
}
fun getExchangeRate(currency: MoneyCurrency): Double {
return 0.0
} }
} }

View File

@ -1,9 +1,99 @@
package com.cubetiqs.money package com.cubetiqs.money
fun StdMoney.exchangeTo(currency: StdMoney.Currency): StdMoney { infix fun StdMoney.exchangeTo(currency: StdMoney.Currency): StdMoney {
return MoneyExchangeUtils.exchange(this, currency) return MoneyExchangeUtils.exchange(this, currency)
} }
infix fun StdMoney.exchangeTo(currency: String): StdMoney = this exchangeTo object : StdMoney.Currency {
override fun getCurrency(): String {
return currency.toUpperCase().trim()
}
}
infix fun StdMoney.plusWith(other: StdMoney): StdMoney = this + other
infix fun StdMoney.minusWith(other: StdMoney): StdMoney = this - other
infix fun StdMoney.divideWith(other: StdMoney): StdMoney = this / other
infix fun StdMoney.multiplyWith(other: StdMoney): StdMoney = this * other
infix fun StdMoney.plusOf(value: Number): StdMoney = object : StdMoney {
override fun getMoneyCurrency(): StdMoney.Currency {
return this@plusOf.getMoneyCurrency()
}
override fun getMoneyValue(): Double {
return this@plusOf.getMoneyValue() + value.toDouble()
}
}
infix fun StdMoney.minusOf(value: Number): StdMoney = object : StdMoney {
override fun getMoneyCurrency(): StdMoney.Currency {
return this@minusOf.getMoneyCurrency()
}
override fun getMoneyValue(): Double {
return this@minusOf.getMoneyValue() - value.toDouble()
}
}
infix fun StdMoney.divideOf(value: Number): StdMoney = object : StdMoney {
override fun getMoneyCurrency(): StdMoney.Currency {
return this@divideOf.getMoneyCurrency()
}
override fun getMoneyValue(): Double {
return this@divideOf.getMoneyValue() / value.toDouble()
}
}
infix fun StdMoney.multiplyOf(value: Number): StdMoney = object : StdMoney {
override fun getMoneyCurrency(): StdMoney.Currency {
return this@multiplyOf.getMoneyCurrency()
}
override fun getMoneyValue(): Double {
return this@multiplyOf.getMoneyValue() * value.toDouble()
}
}
infix fun Number.withCurrency(currency: StdMoney.Currency): StdMoney = object : StdMoney {
override fun getMoneyCurrency(): StdMoney.Currency {
return currency
}
override fun getMoneyValue(): Double {
return this@withCurrency.toDouble()
}
}
infix fun Number.withCurrency(currency: String): StdMoney = this withCurrency object : StdMoney.Currency {
override fun getCurrency(): String {
return currency.toUpperCase().trim()
}
}
// toString function for StdMoney interface
fun StdMoney.asString(): String = "StdMoney(value=${getMoneyValue()}, currency=${getMoneyCurrency().getCurrency()})"
fun StdMoney.asMoneyString(): String = "${getMoneyValue()}:${getMoneyCurrency().getCurrency()}"
fun String?.fromStringToMoney(): StdMoney {
val values = this?.split(":")
if (values.isNullOrEmpty()) {
return StdMoney.ZERO
}
val currency = StdMoney.initCurrency(values.firstOrNull())
val value = values.lastOrNull()?.toDouble() ?: 0.0
return object : StdMoney {
override fun getMoneyCurrency(): StdMoney.Currency {
return currency
}
override fun getMoneyValue(): Double {
return value
}
}
}
fun StdMoney.isMatchedCurrency(currency: StdMoney.Currency) = fun StdMoney.isMatchedCurrency(currency: StdMoney.Currency) =
this.getMoneyCurrency().getCurrency().equals(currency.getCurrency(), ignoreCase = true) this.getMoneyCurrency().getCurrency().equals(currency.getCurrency(), ignoreCase = true)

View File

@ -4,7 +4,7 @@ import java.io.Serializable
sealed class MoneyObject : Serializable, StdMoney { sealed class MoneyObject : Serializable, StdMoney {
private var value: Double = 0.0 private var value: Double = 0.0
private var currency: MoneyCurrency = MoneyCurrency.USD private var currency: StdMoney.Currency = MoneyCurrency.USD
private val moneyStates: MutableMap<MoneyCurrency, MoneyState> = mutableMapOf() private val moneyStates: MutableMap<MoneyCurrency, MoneyState> = mutableMapOf()
constructor(value: Double, currency: MoneyCurrency) { constructor(value: Double, currency: MoneyCurrency) {
@ -32,7 +32,7 @@ sealed class MoneyObject : Serializable, StdMoney {
companion object { companion object {
@JvmStatic @JvmStatic
private fun defaultCurrency(): MoneyCurrency { private fun defaultCurrency(): StdMoney.Currency {
return MoneyExchangeUtils.getBaseCurrency() return MoneyExchangeUtils.getBaseCurrency()
} }
} }

View File

@ -7,11 +7,21 @@ operator fun StdMoney.unaryPlus() = (+getMoneyValue())
// operators // operators
operator fun StdMoney.inc() = Money.from(this).inc() operator fun StdMoney.inc() = Money.from(this).inc()
operator fun StdMoney.dec() = Money.from(this).dec() operator fun StdMoney.dec() = Money.from(this).dec()
operator fun StdMoney.plus(other: StdMoney) = Money.from(this).plusAssign(other) operator fun StdMoney.plus(other: StdMoney): StdMoney {
val result = Money.from(this)
result.plusAssign(other)
return result
}
operator fun StdMoney.minus(other: StdMoney): StdMoney {
val result = Money.from(this)
result.minusAssign(other)
return result
}
operator fun StdMoney.times(other: StdMoney) = Money.from(this).multiplyAssign(other) operator fun StdMoney.times(other: StdMoney) = Money.from(this).multiplyAssign(other)
operator fun StdMoney.div(other: StdMoney) = Money.from(this).divideAssign(other) operator fun StdMoney.div(other: StdMoney) = Money.from(this).divideAssign(other)
// assign operators // assign operators
operator fun Money.timesAssign(other: StdMoney) = this.multiplyAssign(other) operator fun Money.timesAssign(other: StdMoney) = this.multiplyAssign(other).nor()
operator fun Money.plusAssign(other: StdMoney) = this.plusAssign(other) operator fun Money.plusAssign(other: StdMoney) = this.plusAssign(other).nor()
operator fun Money.divAssign(other: StdMoney) = this.divideAssign(other) operator fun Money.minusAssign(other: StdMoney) = this.minusAssign(other).nor()
operator fun Money.divAssign(other: StdMoney) = this.divideAssign(other).nor()

View File

@ -35,6 +35,7 @@ interface StdMoney {
interface Operator<T : StdMoney> { interface Operator<T : StdMoney> {
fun plus(other: StdMoney): T fun plus(other: StdMoney): T
fun minus(other: StdMoney): T
fun divide(other: StdMoney): T fun divide(other: StdMoney): T
fun inc(): T fun inc(): T
@ -42,8 +43,42 @@ interface StdMoney {
fun multiply(other: StdMoney): T fun multiply(other: StdMoney): T
// assign operators // assign operators
fun plusAssign(other: StdMoney) fun plusAssign(other: StdMoney): T
fun divideAssign(other: StdMoney) fun minusAssign(other: StdMoney): T
fun multiplyAssign(other: StdMoney) fun divideAssign(other: StdMoney): T
fun multiplyAssign(other: StdMoney): T
// none-of-return
fun nor() {}
}
companion object {
fun initCurrency(currency: String?): Currency {
return object : Currency {
override fun getCurrency(): String {
return currency?.toUpperCase()?.trim() ?: "USD"
}
}
}
val USD
get() = initCurrency("USD")
val KHR
get() = initCurrency("KHR")
fun initMoney(initValue: Double, currency: Currency = USD): StdMoney {
return object : StdMoney {
override fun getMoneyCurrency(): Currency {
return currency
}
override fun getMoneyValue(): Double {
return initValue
}
}
}
val ZERO
get() = initMoney(0.0, USD)
} }
} }

View File

@ -5,13 +5,6 @@ import org.junit.Test
class MoneyTests { class MoneyTests {
@Test @Test
fun exchange_2usd_to_khr_test() { fun exchange_2usd_to_khr_test() {
// val properties = MoneyConfig
// .MoneyConfigProperties
// .MoneyConfigPropertiesBuilder()
// .setDeliEqual(':')
// .setDeliSplit(',')
// .build()
applyMoneyConfig { applyMoneyConfig {
setProperties(buildMoneyConfigProperties { setProperties(buildMoneyConfigProperties {
setDeliEqual(':') setDeliEqual(':')
@ -26,11 +19,19 @@ class MoneyTests {
// Is valid for money config? // Is valid for money config?
Assert.assertTrue(MoneyConfig.isValid()) Assert.assertTrue(MoneyConfig.isValid())
val moneyUsd = Money(2.0) // arithmetic operators calculation
val moneyKhr = MoneyExchangeUtils.exchange(moneyUsd, MoneyCurrency.create("KHR")) val moneyUsd =
(2 withCurrency "usd") divideWith (2 withCurrency "usd") plusOf 1 minusOf 1 plusOf 1 multiplyOf 2 divideOf 2 divideWith (8000 withCurrency "khr") plusOf 1
val moneyKhr = moneyUsd exchangeTo "khr"
// Is correct exchange? // Is correct exchange?
Assert.assertEquals(8000.0, moneyKhr.getMoneyValue(), 0.0) Assert.assertEquals(8000.0, moneyKhr.getMoneyValue(), 0.0)
// complex operators and exchanging
val sum =
((moneyUsd + moneyKhr) * Money.TEN) exchangeTo MoneyCurrency.KHR minusWith (Money.ONE exchangeTo MoneyCurrency.KHR)
Assert.assertEquals(156000.0, sum.getMoneyValue(), 0.0)
} }
object MyBatchRates { object MyBatchRates {