Add money object with generator and builder for operators the values from builder with batch and remove unused files and functions was updated for some operators

This commit is contained in:
Sambo Chea 2021-02-08 18:53:46 +07:00
parent 3a7141cf76
commit 980b741ee9
5 changed files with 201 additions and 74 deletions

View File

@ -65,7 +65,7 @@ object MoneyConfig {
MoneyConfig.config.put(currency, value) MoneyConfig.config.put(currency, value)
} }
} else { } else {
throw MoneyCurrencyStateException("money config format is not valid!") throw MoneyCurrencyStateException("money config format $temp is not valid!")
} }
} }
} }
@ -107,8 +107,8 @@ object MoneyConfig {
@Throws(MoneyCurrencyStateException::class) @Throws(MoneyCurrencyStateException::class)
fun getRate(currency: StdMoney.Currency): Double { fun getRate(currency: StdMoney.Currency): Double {
return getConfig()[currency.getCurrency().toUpperCase()] return getConfig()[currency.getCurrency().toUpperCase().trim()]
?: throw MoneyCurrencyStateException("money currency $currency is not valid!") ?: throw MoneyCurrencyStateException("money currency ${currency.getCurrency()} is not valid!")
} }
class MoneyConfigProperties( class MoneyConfigProperties(

View File

@ -1,15 +0,0 @@
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

View File

@ -1,47 +1,143 @@
package com.cubetiqs.money package com.cubetiqs.money
import java.io.Serializable import java.util.*
sealed class MoneyObject : Serializable, StdMoney { /**
private var value: Double = 0.0 * Money Object Generator (Quick building the money)
private var currency: StdMoney.Currency = MoneyCurrency.USD *
private val moneyStates: MutableMap<MoneyCurrency, MoneyState> = mutableMapOf() * @since 1.0
* @author sombochea
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 class MoneyObject(
var isComputed = false val value: Double,
private set val currency: String,
var operator: MoneyOperator? = null,
@Transient var with: MoneyObject? = null,
var isInit = false ) : StdMoney {
private set fun appendWith(with: MoneyObject?) {
if (this.with == null) {
/** Calculate the value. Must be call after complete add money. */ this.with = with
fun compute(): MoneyObject = apply { } else {
this.with!!.appendWith(with)
}
} }
companion object { override fun getMoneyCurrency(): StdMoney.Currency {
@JvmStatic return StdMoney.initCurrency(currency)
private fun defaultCurrency(): StdMoney.Currency {
return MoneyExchangeUtils.getBaseCurrency()
}
} }
override fun getMoneyValue(): Double { override fun getMoneyValue(): Double {
return value return value
} }
override fun getMoneyCurrency(): StdMoney.Currency { private fun generate(): StdMoney {
return currency if (this.with != null) {
val withGenerated = this.with!!.generate()
return when (operator) {
MoneyOperator.PLUS -> this plusWith withGenerated
MoneyOperator.MINUS -> this minusWith withGenerated
MoneyOperator.DIVIDE -> this divideWith withGenerated
MoneyOperator.MULTIPLY -> this multiplyWith withGenerated
// if operator is null or empty with default Plus operator
else -> this plusWith withGenerated
}
}
return StdMoney.initMoney(value, currency = StdMoney.initCurrency(currency))
}
fun compute(): StdMoney {
return generate()
}
override fun toString(): String {
return "MoneyObject(value=$value, currency='$currency', operator=$operator, with=$with)"
}
enum class MoneyOperator {
// (+)
PLUS,
// (-)
MINUS,
// (/)
DIVIDE,
// (*)
MULTIPLY;
companion object {
fun operator(value: Char?): MoneyOperator {
return try {
when (value!!) {
'+' -> PLUS
'-' -> MINUS
'/' -> DIVIDE
'*' -> MULTIPLY
else -> throw IllegalArgumentException("operator not found with value: $value!")
}
} catch (ex: Exception) {
throw IllegalArgumentException("operator not found!")
}
}
}
}
class MoneyGeneratorBuilder {
private var currency: String? = null
private val withs: MutableCollection<MoneyObject> = LinkedList()
fun withCurrency(currency: String) = apply {
this.currency = currency
}
fun with(`object`: MoneyObject) = apply {
this.withs.add(`object`)
}
fun with(value: Double, currency: String, operator: MoneyOperator = MoneyOperator.PLUS) = apply {
this.with(
MoneyObject(
value, currency, operator
)
)
}
fun with(value: Double, currency: String, operator: Char) = apply {
this.with(
MoneyObject(
value, currency, MoneyOperator.operator(operator)
)
)
}
fun build(): MoneyObject {
val first: MoneyObject
if (this.currency.isNullOrEmpty() && withs.isNotEmpty()) {
first = withs.first()
withs.remove(first)
} else {
first = MoneyObject(
value = 0.0,
operator = MoneyOperator.PLUS,
currency = this.currency ?: MoneyCurrency.USD.getCurrency()
)
}
withs.forEach { with ->
first.appendWith(with)
}
return first
}
override fun toString(): String {
return "MoneyGeneratorBuilder(currency=$currency, withs=$withs)"
}
}
companion object {
fun builder() = MoneyGeneratorBuilder()
} }
} }

View File

@ -1,15 +0,0 @@
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

View File

@ -3,18 +3,31 @@ import org.junit.Assert
import org.junit.Test import org.junit.Test
class MoneyTests { class MoneyTests {
@Test private fun initMoneyConfig() {
fun exchange_2usd_to_khr_test() {
applyMoneyConfig { applyMoneyConfig {
setProperties(buildMoneyConfigProperties { setProperties(buildMoneyConfigProperties {
setDeliEqual(':') setDeliEqual(':')
setDeliSplit(',') setDeliSplit(',')
}) })
// parse("USD:1,KHR:4000")
// appendRate("usd", 1.0)
// appendRate("khr", 4000.0)
fromJson(MyBatchRates.getJsonRates()) fromJson(MyBatchRates.getJsonRates())
} }
}
@Test
fun exchange_2usd_to_khr_test() {
initMoneyConfig()
// applyMoneyConfig {
// setProperties(buildMoneyConfigProperties {
// setDeliEqual(':')
// setDeliSplit(',')
// })
// // parse("USD:1,KHR:4000")
// // appendRate("usd", 1.0)
// // appendRate("khr", 4000.0)
// fromJson(MyBatchRates.getJsonRates())
// }
// Is valid for money config? // Is valid for money config?
Assert.assertTrue(MoneyConfig.isValid()) Assert.assertTrue(MoneyConfig.isValid())
@ -37,8 +50,56 @@ class MoneyTests {
object MyBatchRates { object MyBatchRates {
fun getJsonRates(): String { fun getJsonRates(): String {
return """ return """
{"USD": 1.0,"KHR": 4000.0} {"USD": 1.0,"KHR": 4000.0, "eur": 0.5}
""".trimIndent() """.trimIndent()
} }
} }
@Test
fun moneyGenerator() {
initMoneyConfig()
val moneyGen = MoneyObject(
value = 1.0,
currency = "usd",
operator = MoneyObject.MoneyOperator.PLUS,
with = MoneyObject(
value = 8000.0,
currency = "khr",
operator = MoneyObject.MoneyOperator.MINUS,
with = MoneyObject(
value = 1000.0,
currency = "khr",
)
)
)
val result = moneyGen.compute()
Assert.assertEquals(2.75, result.getMoneyValue(), 0.0)
}
@Test
fun moneyGeneratorBuilder() {
initMoneyConfig()
val expected = 72000.0
val builder = MoneyObject.builder()
.with(10.0, "usd", '+')
.with(1.5, "eur", '+')
.with(8000.0, "khr")
.with(10000.0, "khr")
.with(2000.0, "khr")
.with(.5, "eur", '-')
.with(1.0, "usd")
.withCurrency("khr")
.build()
val result = builder.compute()
println(result)
Assert.assertEquals(expected, result.getMoneyValue(), 0.0)
}
} }