From 3a7141cf7683687e5fac188133bbae5b7fda67e8 Mon Sep 17 00:00:00 2001 From: Sambo Chea Date: Mon, 8 Feb 2021 16:08:00 +0700 Subject: [PATCH] Add more functinos for money extension and fixed the curreny and object currency and default std money value and more --- src/main/kotlin/com/cubetiqs/money/Money.kt | 32 ++++--- .../com/cubetiqs/money/MoneyCurrency.kt | 14 ++- .../com/cubetiqs/money/MoneyExchangeUtils.kt | 8 +- .../com/cubetiqs/money/MoneyExtension.kt | 92 ++++++++++++++++++- .../kotlin/com/cubetiqs/money/MoneyObject.kt | 4 +- .../com/cubetiqs/money/MoneyOperator.kt | 18 +++- .../kotlin/com/cubetiqs/money/StdMoney.kt | 41 ++++++++- src/test/kotlin/MoneyTests.kt | 19 ++-- 8 files changed, 185 insertions(+), 43 deletions(-) diff --git a/src/main/kotlin/com/cubetiqs/money/Money.kt b/src/main/kotlin/com/cubetiqs/money/Money.kt index 6e22ac9..380ff38 100644 --- a/src/main/kotlin/com/cubetiqs/money/Money.kt +++ b/src/main/kotlin/com/cubetiqs/money/Money.kt @@ -12,7 +12,7 @@ open class Money( // not imply with exchange rate yet override fun StdMoney.getExchangedTo(currency: StdMoney.Currency): Double { - return getMoneyValue() + return MoneyExchangeUtils.exchange(this, currency).getMoneyValue() } override fun getMoneyCurrency(): StdMoney.Currency { @@ -22,7 +22,7 @@ open class Money( //////////////////// - GENERIC - //////////////////// override fun toString(): String { - return "Money(value=${getMoneyValue()}, currency='${getMoneyCurrency()}')" + return "Money(value=${getMoneyValue()}, currency='${getMoneyCurrency().getCurrency()}')" } override fun inc(): Money = apply { @@ -38,6 +38,11 @@ open class Money( 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 { val temp = this.value / other.getExchangedTo(this.currency) return Money(value = temp, currency = this.currency) @@ -48,27 +53,28 @@ open class Money( 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) } - 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) } - override fun multiplyAssign(other: StdMoney) { + override fun multiplyAssign(other: StdMoney): Money = apply { this.value = this.value * other.getExchangedTo(this.getMoneyCurrency()) } companion object { - val ZERO: StdMoney - get() = Money() - val ONE: StdMoney - get() = Money(value = 1.0) + get() = StdMoney.initMoney(1.0) val TEN: StdMoney - get() = Money(value = 10.0) + get() = StdMoney.initMoney(10.0) /** * Create a new money object with custom value @@ -81,11 +87,7 @@ open class Money( } fun from(value: Double, currency: String): Money { - return create(value, object : StdMoney.Currency { - override fun getCurrency(): String { - return currency.toUpperCase().trim() - } - }) + return create(value, StdMoney.initCurrency(currency)) } fun from(money: StdMoney): Money { diff --git a/src/main/kotlin/com/cubetiqs/money/MoneyCurrency.kt b/src/main/kotlin/com/cubetiqs/money/MoneyCurrency.kt index fdf7934..ee8bda9 100644 --- a/src/main/kotlin/com/cubetiqs/money/MoneyCurrency.kt +++ b/src/main/kotlin/com/cubetiqs/money/MoneyCurrency.kt @@ -11,7 +11,7 @@ import java.io.Serializable open class MoneyCurrency( private val name: String, private val symbol: String? = null, - private val configs: Map? = null, + private var configs: Map? = null, ) : Serializable, StdMoney.Currency { override fun getCurrency(): String { return name.toUpperCase().trim() @@ -21,6 +21,14 @@ open class MoneyCurrency( 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 { return configs ?: emptyMap() } @@ -35,9 +43,9 @@ open class MoneyCurrency( } val USD - get() = create("USD") + get() = StdMoney.USD val KHR - get() = create("KHR") + get() = StdMoney.KHR } } \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/money/MoneyExchangeUtils.kt b/src/main/kotlin/com/cubetiqs/money/MoneyExchangeUtils.kt index 7f6a3b5..fe9f2a5 100644 --- a/src/main/kotlin/com/cubetiqs/money/MoneyExchangeUtils.kt +++ b/src/main/kotlin/com/cubetiqs/money/MoneyExchangeUtils.kt @@ -11,11 +11,7 @@ object MoneyExchangeUtils { return amountFrom * ((baseRate / rateFrom) / (baseRate / rateTo)) } - fun getBaseCurrency(): MoneyCurrency { - return MoneyCurrency.USD - } - - fun getExchangeRate(currency: MoneyCurrency): Double { - return 0.0 + fun getBaseCurrency(): StdMoney.Currency { + return StdMoney.USD } } \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/money/MoneyExtension.kt b/src/main/kotlin/com/cubetiqs/money/MoneyExtension.kt index baa1fbb..e82a0e6 100644 --- a/src/main/kotlin/com/cubetiqs/money/MoneyExtension.kt +++ b/src/main/kotlin/com/cubetiqs/money/MoneyExtension.kt @@ -1,9 +1,99 @@ package com.cubetiqs.money -fun StdMoney.exchangeTo(currency: StdMoney.Currency): StdMoney { +infix fun StdMoney.exchangeTo(currency: StdMoney.Currency): StdMoney { 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) = this.getMoneyCurrency().getCurrency().equals(currency.getCurrency(), ignoreCase = true) diff --git a/src/main/kotlin/com/cubetiqs/money/MoneyObject.kt b/src/main/kotlin/com/cubetiqs/money/MoneyObject.kt index 00514bb..099a36d 100644 --- a/src/main/kotlin/com/cubetiqs/money/MoneyObject.kt +++ b/src/main/kotlin/com/cubetiqs/money/MoneyObject.kt @@ -4,7 +4,7 @@ import java.io.Serializable sealed class MoneyObject : Serializable, StdMoney { private var value: Double = 0.0 - private var currency: MoneyCurrency = MoneyCurrency.USD + private var currency: StdMoney.Currency = MoneyCurrency.USD private val moneyStates: MutableMap = mutableMapOf() constructor(value: Double, currency: MoneyCurrency) { @@ -32,7 +32,7 @@ sealed class MoneyObject : Serializable, StdMoney { companion object { @JvmStatic - private fun defaultCurrency(): MoneyCurrency { + private fun defaultCurrency(): StdMoney.Currency { return MoneyExchangeUtils.getBaseCurrency() } } diff --git a/src/main/kotlin/com/cubetiqs/money/MoneyOperator.kt b/src/main/kotlin/com/cubetiqs/money/MoneyOperator.kt index d862856..9d3b3eb 100644 --- a/src/main/kotlin/com/cubetiqs/money/MoneyOperator.kt +++ b/src/main/kotlin/com/cubetiqs/money/MoneyOperator.kt @@ -7,11 +7,21 @@ operator fun StdMoney.unaryPlus() = (+getMoneyValue()) // operators operator fun StdMoney.inc() = Money.from(this).inc() 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.div(other: StdMoney) = Money.from(this).divideAssign(other) // assign operators -operator fun Money.timesAssign(other: StdMoney) = this.multiplyAssign(other) -operator fun Money.plusAssign(other: StdMoney) = this.plusAssign(other) -operator fun Money.divAssign(other: StdMoney) = this.divideAssign(other) \ No newline at end of file +operator fun Money.timesAssign(other: StdMoney) = this.multiplyAssign(other).nor() +operator fun Money.plusAssign(other: StdMoney) = this.plusAssign(other).nor() +operator fun Money.minusAssign(other: StdMoney) = this.minusAssign(other).nor() +operator fun Money.divAssign(other: StdMoney) = this.divideAssign(other).nor() \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/money/StdMoney.kt b/src/main/kotlin/com/cubetiqs/money/StdMoney.kt index 33074c9..0857fde 100644 --- a/src/main/kotlin/com/cubetiqs/money/StdMoney.kt +++ b/src/main/kotlin/com/cubetiqs/money/StdMoney.kt @@ -35,6 +35,7 @@ interface StdMoney { interface Operator { fun plus(other: StdMoney): T + fun minus(other: StdMoney): T fun divide(other: StdMoney): T fun inc(): T @@ -42,8 +43,42 @@ interface StdMoney { fun multiply(other: StdMoney): T // assign operators - fun plusAssign(other: StdMoney) - fun divideAssign(other: StdMoney) - fun multiplyAssign(other: StdMoney) + fun plusAssign(other: StdMoney): T + fun minusAssign(other: StdMoney): T + 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) } } \ No newline at end of file diff --git a/src/test/kotlin/MoneyTests.kt b/src/test/kotlin/MoneyTests.kt index 951835c..15ebec6 100644 --- a/src/test/kotlin/MoneyTests.kt +++ b/src/test/kotlin/MoneyTests.kt @@ -5,13 +5,6 @@ import org.junit.Test class MoneyTests { @Test fun exchange_2usd_to_khr_test() { -// val properties = MoneyConfig -// .MoneyConfigProperties -// .MoneyConfigPropertiesBuilder() -// .setDeliEqual(':') -// .setDeliSplit(',') -// .build() - applyMoneyConfig { setProperties(buildMoneyConfigProperties { setDeliEqual(':') @@ -26,11 +19,19 @@ class MoneyTests { // Is valid for money config? Assert.assertTrue(MoneyConfig.isValid()) - val moneyUsd = Money(2.0) - val moneyKhr = MoneyExchangeUtils.exchange(moneyUsd, MoneyCurrency.create("KHR")) + // arithmetic operators calculation + 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? 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 {