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
|
package com.cubetiqs.money
|
||||||
|
|
||||||
open class Money(
|
open class Money(
|
||||||
var value: Double,
|
private var value: Double = 0.0,
|
||||||
@SpecialString(trim = true, upperCase = true) private var currency: String = "USD"
|
private val currency: StdMoney.Currency = MoneyCurrency.USD,
|
||||||
) : StdMoney {
|
) : StdMoney, StdMoney.Operator<Money>, StdMoney.ExchangeOperator {
|
||||||
|
|
||||||
//////////////////// - PROPERTIES - ////////////////////
|
//////////////////// - PROPERTIES - ////////////////////
|
||||||
|
|
||||||
override fun getMoneyValue(): Double {
|
override fun getMoneyValue(): Double {
|
||||||
return this.value
|
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
|
return this.currency
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,11 +25,48 @@ open class Money(
|
|||||||
return "Money(value=${getMoneyValue()}, currency='${getMoneyCurrency()}')"
|
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 {
|
companion object {
|
||||||
val ZERO: StdMoney
|
val ZERO: StdMoney
|
||||||
get() = Money(value = 0.0)
|
get() = Money()
|
||||||
|
|
||||||
val ONE: StdMoney
|
val ONE: StdMoney
|
||||||
get() = Money(value = 1.0)
|
get() = Money(value = 1.0)
|
||||||
|
|
||||||
val TEN: StdMoney
|
val TEN: StdMoney
|
||||||
get() = Money(value = 10.0)
|
get() = Money(value = 10.0)
|
||||||
|
|
||||||
@ -33,18 +74,22 @@ open class Money(
|
|||||||
* Create a new money object with custom value
|
* Create a new money object with custom value
|
||||||
*
|
*
|
||||||
* @param value Double
|
* @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)
|
return Money(value = value, currency = currency)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun from(value: Double, currency: String): Money {
|
||||||
* Create a new money object with custom value
|
return create(value, object : StdMoney.Currency {
|
||||||
*
|
override fun getCurrency(): String {
|
||||||
* @param value Double
|
return currency.toUpperCase().trim()
|
||||||
* @param currency MoneyCurrency
|
}
|
||||||
*/
|
})
|
||||||
fun create(value: Double, currency: MoneyCurrency = MoneyCurrency.USD): StdMoney = create(value, currency.name)
|
}
|
||||||
|
|
||||||
|
fun from(money: StdMoney): Money {
|
||||||
|
return create(value = money.getMoneyValue(), currency = money.getMoneyCurrency())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.cubetiqs.money
|
package com.cubetiqs.money
|
||||||
|
|
||||||
fun StdMoney.addMoney(value: Double, currency: String): StdMoney {
|
fun StdMoney.addMoney(value: Double, currency: StdMoney.Currency): StdMoney {
|
||||||
return this + Money.create(value, currency)
|
this + Money.create(value, currency)
|
||||||
|
return this
|
||||||
}
|
}
|
@ -67,8 +67,8 @@ object MoneyConfig {
|
|||||||
fun getConfig() = config
|
fun getConfig() = config
|
||||||
|
|
||||||
@Throws(MoneyCurrencyStateException::class)
|
@Throws(MoneyCurrencyStateException::class)
|
||||||
fun getRate(currency: String): Double {
|
fun getRate(currency: StdMoney.Currency): Double {
|
||||||
return getConfig()[currency.toUpperCase()]
|
return getConfig()[currency.getCurrency().toUpperCase()]
|
||||||
?: throw MoneyCurrencyStateException("money currency $currency is not valid!")
|
?: throw MoneyCurrencyStateException("money currency $currency is not valid!")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,43 @@
|
|||||||
package com.cubetiqs.money
|
package com.cubetiqs.money
|
||||||
|
|
||||||
enum class MoneyCurrency {
|
import java.io.Serializable
|
||||||
USD,
|
|
||||||
KHR,
|
/**
|
||||||
EUR
|
* 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
|
package com.cubetiqs.money
|
||||||
|
|
||||||
object MoneyExchangeUtils {
|
object MoneyExchangeUtils {
|
||||||
fun exchange(exchangeFrom: StdMoney, exchangeToCurrency: String): StdMoney {
|
fun exchange(exchangeFrom: StdMoney, exchangeToCurrency: StdMoney.Currency): StdMoney {
|
||||||
val rateFrom = MoneyConfig.getRate(exchangeFrom.getMoneyCurrency())
|
val rateFrom = MoneyConfig.getRate(exchangeFrom.getMoneyCurrency())
|
||||||
val rateTo = MoneyConfig.getRate(exchangeToCurrency)
|
val rateTo = MoneyConfig.getRate(exchangeToCurrency)
|
||||||
return Money(value = computeRate(rateFrom, rateTo, amountFrom = exchangeFrom.getMoneyValue()), currency = 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 {
|
private fun computeRate(rateFrom: Double, rateTo: Double, baseRate: Double = 1.0, amountFrom: Double = 1.0): Double {
|
||||||
return amountFrom * ((baseRate / rateFrom) / (baseRate / rateTo))
|
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
|
package com.cubetiqs.money
|
||||||
|
|
||||||
fun StdMoney.exchangeTo(currency: String): StdMoney {
|
fun StdMoney.exchangeTo(currency: StdMoney.Currency): StdMoney {
|
||||||
return MoneyExchangeUtils.exchange(this, currency)
|
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
|
package com.cubetiqs.money
|
||||||
|
|
||||||
|
// unary operators
|
||||||
operator fun StdMoney.unaryMinus() = (-getMoneyValue())
|
operator fun StdMoney.unaryMinus() = (-getMoneyValue())
|
||||||
operator fun StdMoney.unaryPlus() = (+getMoneyValue())
|
operator fun StdMoney.unaryPlus() = (+getMoneyValue())
|
||||||
operator fun Money.inc() = Money(value++)
|
|
||||||
operator fun Money.dec() = Money(value--)
|
// operators
|
||||||
operator fun StdMoney.plus(other: StdMoney) = Money(getMoneyValue() + other.getMoneyValue())
|
operator fun StdMoney.inc() = Money.from(this).inc()
|
||||||
operator fun StdMoney.times(other: StdMoney) = Money(getMoneyValue() * other.getMoneyValue())
|
operator fun StdMoney.dec() = Money.from(this).dec()
|
||||||
operator fun StdMoney.div(other: StdMoney) = Money(getMoneyValue() / other.getMoneyValue())
|
operator fun StdMoney.plus(other: StdMoney) = Money.from(this).plusAssign(other)
|
||||||
operator fun Money.timesAssign(other: StdMoney) {
|
operator fun StdMoney.times(other: StdMoney) = Money.from(this).multiplyAssign(other)
|
||||||
this.value = this.getMoneyValue() * other.getMoneyValue()
|
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
|
* @return String
|
||||||
*/
|
*/
|
||||||
@SpecialString
|
fun getMoneyCurrency(): Currency
|
||||||
fun getMoneyCurrency(): String
|
|
||||||
|
/**
|
||||||
|
* 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.MoneyConfig
|
||||||
import com.cubetiqs.money.MoneyCurrency
|
import com.cubetiqs.money.MoneyCurrency
|
||||||
import com.cubetiqs.money.MoneyExchangeUtils
|
import com.cubetiqs.money.MoneyExchangeUtils
|
||||||
import com.cubetiqs.money.SpecialStringProcessor
|
|
||||||
import org.junit.Assert
|
import org.junit.Assert
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
class MoneyTests {
|
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
|
@Test
|
||||||
fun exchange_2usd_to_khr_test() {
|
fun exchange_2usd_to_khr_test() {
|
||||||
val properties = MoneyConfig
|
val properties = MoneyConfig
|
||||||
@ -32,27 +19,13 @@ class MoneyTests {
|
|||||||
.setProperties(properties)
|
.setProperties(properties)
|
||||||
.parse("USD:1,KHR:4000")
|
.parse("USD:1,KHR:4000")
|
||||||
|
|
||||||
|
// Is valid for money config?
|
||||||
Assert.assertTrue(MoneyConfig.isValid())
|
Assert.assertTrue(MoneyConfig.isValid())
|
||||||
|
|
||||||
println(MoneyConfig.getConfig())
|
|
||||||
|
|
||||||
val moneyUsd = Money(2.0)
|
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)
|
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