Add and updated for whole the money modules with new style and some operators and computation
But money object not full implementation yet, because we need the exchange and filter the object states for money
This commit is contained in:
parent
19130727e3
commit
31760ee901
@ -1,17 +1,21 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
open class Money(
|
||||
var value: Double,
|
||||
@SpecialString(trim = true, upperCase = true) private var currency: String = "USD"
|
||||
) : StdMoney {
|
||||
|
||||
private var value: Double = 0.0,
|
||||
private val currency: StdMoney.Currency = MoneyCurrency.USD,
|
||||
) : StdMoney, StdMoney.Operator<Money>, StdMoney.ExchangeOperator {
|
||||
//////////////////// - PROPERTIES - ////////////////////
|
||||
|
||||
override fun getMoneyValue(): Double {
|
||||
return this.value
|
||||
}
|
||||
|
||||
override fun getMoneyCurrency(): String {
|
||||
// not imply with exchange rate yet
|
||||
override fun StdMoney.getExchangedTo(currency: StdMoney.Currency): Double {
|
||||
return getMoneyValue()
|
||||
}
|
||||
|
||||
override fun getMoneyCurrency(): StdMoney.Currency {
|
||||
return this.currency
|
||||
}
|
||||
|
||||
@ -21,11 +25,48 @@ open class Money(
|
||||
return "Money(value=${getMoneyValue()}, currency='${getMoneyCurrency()}')"
|
||||
}
|
||||
|
||||
override fun inc(): Money = apply {
|
||||
this.value += 1
|
||||
}
|
||||
|
||||
override fun dec(): Money = apply {
|
||||
this.value -= 1
|
||||
}
|
||||
|
||||
override fun plus(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)
|
||||
}
|
||||
|
||||
override fun multiply(other: StdMoney): Money {
|
||||
val temp = this.value * other.getExchangedTo(this.getMoneyCurrency())
|
||||
return Money(value = temp, currency = this.currency)
|
||||
}
|
||||
|
||||
override fun plusAssign(other: StdMoney) {
|
||||
this.value = this.value + other.getExchangedTo(this.currency)
|
||||
}
|
||||
|
||||
override fun divideAssign(other: StdMoney) {
|
||||
this.value = this.value / other.getExchangedTo(this.currency)
|
||||
}
|
||||
|
||||
override fun multiplyAssign(other: StdMoney) {
|
||||
this.value = this.value * other.getExchangedTo(this.getMoneyCurrency())
|
||||
}
|
||||
|
||||
companion object {
|
||||
val ZERO: StdMoney
|
||||
get() = Money(value = 0.0)
|
||||
get() = Money()
|
||||
|
||||
val ONE: StdMoney
|
||||
get() = Money(value = 1.0)
|
||||
|
||||
val TEN: StdMoney
|
||||
get() = Money(value = 10.0)
|
||||
|
||||
@ -33,18 +74,22 @@ open class Money(
|
||||
* Create a new money object with custom value
|
||||
*
|
||||
* @param value Double
|
||||
* @param currency String
|
||||
* @param currency MoneyCurrency
|
||||
*/
|
||||
fun create(value: Double, currency: String = MoneyCurrency.USD.name): StdMoney {
|
||||
fun create(value: Double, currency: StdMoney.Currency): Money {
|
||||
return Money(value = value, currency = currency)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new money object with custom value
|
||||
*
|
||||
* @param value Double
|
||||
* @param currency MoneyCurrency
|
||||
*/
|
||||
fun create(value: Double, currency: MoneyCurrency = MoneyCurrency.USD): StdMoney = create(value, currency.name)
|
||||
fun from(value: Double, currency: String): Money {
|
||||
return create(value, object : StdMoney.Currency {
|
||||
override fun getCurrency(): String {
|
||||
return currency.toUpperCase().trim()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun from(money: StdMoney): Money {
|
||||
return create(value = money.getMoneyValue(), currency = money.getMoneyCurrency())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
fun StdMoney.addMoney(value: Double, currency: String): StdMoney {
|
||||
return this + Money.create(value, currency)
|
||||
fun StdMoney.addMoney(value: Double, currency: StdMoney.Currency): StdMoney {
|
||||
this + Money.create(value, currency)
|
||||
return this
|
||||
}
|
@ -67,8 +67,8 @@ object MoneyConfig {
|
||||
fun getConfig() = config
|
||||
|
||||
@Throws(MoneyCurrencyStateException::class)
|
||||
fun getRate(currency: String): Double {
|
||||
return getConfig()[currency.toUpperCase()]
|
||||
fun getRate(currency: StdMoney.Currency): Double {
|
||||
return getConfig()[currency.getCurrency().toUpperCase()]
|
||||
?: throw MoneyCurrencyStateException("money currency $currency is not valid!")
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,43 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
enum class MoneyCurrency {
|
||||
USD,
|
||||
KHR,
|
||||
EUR
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* Money Currency Object with flexible currency based on data and configs
|
||||
*
|
||||
* @author sombochea
|
||||
* @since 1.0
|
||||
*/
|
||||
open class MoneyCurrency(
|
||||
private val name: String,
|
||||
private val symbol: String? = null,
|
||||
private val configs: Map<String, Any?>? = null,
|
||||
) : Serializable, StdMoney.Currency {
|
||||
override fun getCurrency(): String {
|
||||
return name.toUpperCase().trim()
|
||||
}
|
||||
|
||||
fun getSymbol(): String? {
|
||||
return symbol ?: getConfigs()["symbol"]?.toString()
|
||||
}
|
||||
|
||||
fun getConfigs(): Map<String, Any?> {
|
||||
return configs ?: emptyMap()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "MoneyCurrency(name='$name', symbol=$symbol, configs=$configs)"
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun create(name: String): MoneyCurrency {
|
||||
return MoneyCurrency(name = name)
|
||||
}
|
||||
|
||||
val USD
|
||||
get() = create("USD")
|
||||
|
||||
val KHR
|
||||
get() = create("KHR")
|
||||
}
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
interface MoneyExchangeAdapter {
|
||||
fun getRate(currency: String): Double
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
interface MoneyExchangeProvider {
|
||||
fun getRate(currency: StdMoney.Currency): Double
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
object MoneyExchangeUtils {
|
||||
fun exchange(exchangeFrom: StdMoney, exchangeToCurrency: String): StdMoney {
|
||||
fun exchange(exchangeFrom: StdMoney, exchangeToCurrency: StdMoney.Currency): StdMoney {
|
||||
val rateFrom = MoneyConfig.getRate(exchangeFrom.getMoneyCurrency())
|
||||
val rateTo = MoneyConfig.getRate(exchangeToCurrency)
|
||||
return Money(value = computeRate(rateFrom, rateTo, amountFrom = exchangeFrom.getMoneyValue()), currency = exchangeToCurrency)
|
||||
@ -10,4 +10,12 @@ object MoneyExchangeUtils {
|
||||
private fun computeRate(rateFrom: Double, rateTo: Double, baseRate: Double = 1.0, amountFrom: Double = 1.0): Double {
|
||||
return amountFrom * ((baseRate / rateFrom) / (baseRate / rateTo))
|
||||
}
|
||||
|
||||
fun getBaseCurrency(): MoneyCurrency {
|
||||
return MoneyCurrency.USD
|
||||
}
|
||||
|
||||
fun getExchangeRate(currency: MoneyCurrency): Double {
|
||||
return 0.0
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
fun StdMoney.exchangeTo(currency: String): StdMoney {
|
||||
fun StdMoney.exchangeTo(currency: StdMoney.Currency): StdMoney {
|
||||
return MoneyExchangeUtils.exchange(this, currency)
|
||||
}
|
||||
|
||||
fun StdMoney.isMatchedCurrency(currency: String) = this.getMoneyCurrency().equals(currency, ignoreCase = true)
|
||||
fun StdMoney.isMatchedCurrency(currency: StdMoney.Currency) = this.getMoneyCurrency().getCurrency().equals(currency.getCurrency(), ignoreCase = true)
|
15
src/main/kotlin/com/cubetiqs/money/MoneyHistory.kt
Normal file
15
src/main/kotlin/com/cubetiqs/money/MoneyHistory.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* @author sombochea <Sambo Chea>
|
||||
* @email sombochea@cubetiqs.com>
|
||||
* @date 08/02/21
|
||||
* @since 1.0
|
||||
*/
|
||||
data class MoneyHistory(
|
||||
val valueOn: String? = null,
|
||||
val valueOf: String? = null,
|
||||
val currency: String? = null
|
||||
) : Serializable
|
47
src/main/kotlin/com/cubetiqs/money/MoneyObject.kt
Normal file
47
src/main/kotlin/com/cubetiqs/money/MoneyObject.kt
Normal file
@ -0,0 +1,47 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
sealed class MoneyObject : Serializable, StdMoney {
|
||||
private var value: Double = 0.0
|
||||
private var currency: MoneyCurrency = MoneyCurrency.USD
|
||||
private val moneyStates: MutableMap<MoneyCurrency, MoneyState> = mutableMapOf()
|
||||
|
||||
constructor(value: Double, currency: MoneyCurrency) {
|
||||
this.value = value
|
||||
this.currency = currency
|
||||
isComputed = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if computed, set it to true. Because we no need to add the same value again after once
|
||||
* computed.
|
||||
*/
|
||||
@Transient
|
||||
var isComputed = false
|
||||
private set
|
||||
|
||||
@Transient
|
||||
var isInit = false
|
||||
private set
|
||||
|
||||
/** Calculate the value. Must be call after complete add money. */
|
||||
fun compute(): MoneyObject = apply {
|
||||
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
private fun defaultCurrency(): MoneyCurrency {
|
||||
return MoneyExchangeUtils.getBaseCurrency()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMoneyValue(): Double {
|
||||
return value
|
||||
}
|
||||
|
||||
override fun getMoneyCurrency(): StdMoney.Currency {
|
||||
return currency
|
||||
}
|
||||
}
|
@ -1,12 +1,17 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
// unary operators
|
||||
operator fun StdMoney.unaryMinus() = (-getMoneyValue())
|
||||
operator fun StdMoney.unaryPlus() = (+getMoneyValue())
|
||||
operator fun Money.inc() = Money(value++)
|
||||
operator fun Money.dec() = Money(value--)
|
||||
operator fun StdMoney.plus(other: StdMoney) = Money(getMoneyValue() + other.getMoneyValue())
|
||||
operator fun StdMoney.times(other: StdMoney) = Money(getMoneyValue() * other.getMoneyValue())
|
||||
operator fun StdMoney.div(other: StdMoney) = Money(getMoneyValue() / other.getMoneyValue())
|
||||
operator fun Money.timesAssign(other: StdMoney) {
|
||||
this.value = this.getMoneyValue() * other.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.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)
|
15
src/main/kotlin/com/cubetiqs/money/MoneyState.kt
Normal file
15
src/main/kotlin/com/cubetiqs/money/MoneyState.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package com.cubetiqs.money
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
/**
|
||||
* @author sombochea <Sambo Chea>
|
||||
* @email sombochea@cubetiqs.com
|
||||
* @date 08/02/21
|
||||
* @since 1.0
|
||||
*/
|
||||
data class MoneyState(
|
||||
var value: String? = null,
|
||||
var currency: String? = null,
|
||||
var history: MoneyHistory? = null
|
||||
) : Serializable
|
@ -20,6 +20,30 @@ interface StdMoney {
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
@SpecialString
|
||||
fun getMoneyCurrency(): String
|
||||
fun getMoneyCurrency(): Currency
|
||||
|
||||
/**
|
||||
* Allow for money currency called and implemented
|
||||
*/
|
||||
interface Currency {
|
||||
fun getCurrency(): String
|
||||
}
|
||||
|
||||
interface ExchangeOperator {
|
||||
fun StdMoney.getExchangedTo(currency: Currency): Double
|
||||
}
|
||||
|
||||
interface Operator<T : StdMoney> {
|
||||
fun plus(other: StdMoney): T
|
||||
fun divide(other: StdMoney): T
|
||||
|
||||
fun inc(): T
|
||||
fun dec(): T
|
||||
fun multiply(other: StdMoney): T
|
||||
|
||||
// assign operators
|
||||
fun plusAssign(other: StdMoney)
|
||||
fun divideAssign(other: StdMoney)
|
||||
fun multiplyAssign(other: StdMoney)
|
||||
}
|
||||
}
|
@ -2,23 +2,10 @@ import com.cubetiqs.money.Money
|
||||
import com.cubetiqs.money.MoneyConfig
|
||||
import com.cubetiqs.money.MoneyCurrency
|
||||
import com.cubetiqs.money.MoneyExchangeUtils
|
||||
import com.cubetiqs.money.SpecialStringProcessor
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class MoneyTests {
|
||||
@Test
|
||||
fun money_operator_test() {
|
||||
// val money = Money(10.0)
|
||||
// val money2 = Money(20.0)
|
||||
// money *= money
|
||||
// println((money + money2) * money2)
|
||||
// Assert.assertEquals(100.0, money.value, 0.0)
|
||||
|
||||
val test = SpecialStringProcessor().serialize(Money(1.0, " usd "))
|
||||
println(test)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun exchange_2usd_to_khr_test() {
|
||||
val properties = MoneyConfig
|
||||
@ -32,27 +19,13 @@ class MoneyTests {
|
||||
.setProperties(properties)
|
||||
.parse("USD:1,KHR:4000")
|
||||
|
||||
// Is valid for money config?
|
||||
Assert.assertTrue(MoneyConfig.isValid())
|
||||
|
||||
println(MoneyConfig.getConfig())
|
||||
|
||||
val moneyUsd = Money(2.0)
|
||||
val moneyKhr = MoneyExchangeUtils.exchange(moneyUsd, "KHR")
|
||||
val moneyKhr = MoneyExchangeUtils.exchange(moneyUsd, MoneyCurrency.create("KHR"))
|
||||
|
||||
// Is correct exchange?
|
||||
Assert.assertEquals(8000.0, moneyKhr.getMoneyValue(), 0.0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun money_exchange_config_builder_test() {
|
||||
MoneyConfig.propertiesBuilder
|
||||
.setDeliEqual('=')
|
||||
.setDeliSplit(';')
|
||||
|
||||
MoneyConfig.parse("USD:1,KHR=4000,EUR=0.99")
|
||||
|
||||
val moneyUsd = Money.ONE
|
||||
val moneyKhr = Money.create(20000.0, MoneyCurrency.KHR)
|
||||
|
||||
val result = moneyUsd
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user