Fixed the batch computation on money value and money object with string values and builder values and fixed generator for first + next computation concepts with operators
This commit is contained in:
parent
980b741ee9
commit
f3f41e9c67
@ -9,19 +9,11 @@ import java.util.*
|
|||||||
* @author sombochea
|
* @author sombochea
|
||||||
*/
|
*/
|
||||||
class MoneyObject(
|
class MoneyObject(
|
||||||
val value: Double,
|
var value: Double,
|
||||||
val currency: String,
|
var currency: String,
|
||||||
var operator: MoneyOperator? = null,
|
var operator: MoneyOperator? = null,
|
||||||
var with: MoneyObject? = null,
|
var with: MoneyObject? = null,
|
||||||
) : StdMoney {
|
) : StdMoney {
|
||||||
fun appendWith(with: MoneyObject?) {
|
|
||||||
if (this.with == null) {
|
|
||||||
this.with = with
|
|
||||||
} else {
|
|
||||||
this.with!!.appendWith(with)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMoneyCurrency(): StdMoney.Currency {
|
override fun getMoneyCurrency(): StdMoney.Currency {
|
||||||
return StdMoney.initCurrency(currency)
|
return StdMoney.initCurrency(currency)
|
||||||
}
|
}
|
||||||
@ -30,20 +22,51 @@ class MoneyObject(
|
|||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generate(): StdMoney {
|
fun appendWithNext(with: MoneyObject?) {
|
||||||
if (this.with != null) {
|
if (with == null) {
|
||||||
val withGenerated = this.with!!.generate()
|
return
|
||||||
return when (operator) {
|
}
|
||||||
MoneyOperator.PLUS -> this plusWith withGenerated
|
|
||||||
MoneyOperator.MINUS -> this minusWith withGenerated
|
if (this.with == null) {
|
||||||
MoneyOperator.DIVIDE -> this divideWith withGenerated
|
this.with = with
|
||||||
MoneyOperator.MULTIPLY -> this multiplyWith withGenerated
|
} else {
|
||||||
// if operator is null or empty with default Plus operator
|
this.with!!.appendWithNext(with)
|
||||||
else -> this plusWith withGenerated
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return StdMoney.initMoney(value, currency = StdMoney.initCurrency(currency))
|
/**
|
||||||
|
* Internal Generate the value by next compute (First and next)
|
||||||
|
*
|
||||||
|
* Example: we have 3 items => [10, 20, 50]
|
||||||
|
* We want to sum of them => [10 + 20] => [30 + 50] => 80
|
||||||
|
*/
|
||||||
|
private fun generate(): StdMoney {
|
||||||
|
// get next record for compute with
|
||||||
|
var next = this.with
|
||||||
|
// get first operator
|
||||||
|
var operatorFirst = this.operator
|
||||||
|
while (next != null) {
|
||||||
|
val temp = when (operatorFirst) {
|
||||||
|
MoneyOperator.PLUS -> this plusWith next
|
||||||
|
MoneyOperator.MINUS -> this minusWith next
|
||||||
|
MoneyOperator.DIVIDE -> this divideWith next
|
||||||
|
MoneyOperator.MULTIPLY -> this multiplyWith next
|
||||||
|
// if operator is null or empty with default Plus operator
|
||||||
|
else -> this plusWith next
|
||||||
|
}
|
||||||
|
// move the temp value that computed
|
||||||
|
this.value = temp.getMoneyValue()
|
||||||
|
// move the currency into parent, if changed
|
||||||
|
this.currency = temp.getMoneyCurrency().getCurrency()
|
||||||
|
// move the first operator to previous next operator
|
||||||
|
// example: first ops = +, then next ops = -, then inside next ops = *, n
|
||||||
|
// return next: first ops = -, then next ops = *, then n
|
||||||
|
operatorFirst = next.operator
|
||||||
|
// move next element
|
||||||
|
next = next.with
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
fun compute(): StdMoney {
|
fun compute(): StdMoney {
|
||||||
@ -68,32 +91,46 @@ class MoneyObject(
|
|||||||
MULTIPLY;
|
MULTIPLY;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun operator(value: Char?): MoneyOperator {
|
fun operator(value: Any?, defaultOperator: MoneyOperator? = null): MoneyOperator {
|
||||||
return try {
|
return try {
|
||||||
when (value!!) {
|
when (val temp = value!!) {
|
||||||
|
is String -> {
|
||||||
|
if (temp.length == 1) {
|
||||||
|
operator(temp[0])
|
||||||
|
} else {
|
||||||
|
valueOf(temp.toUpperCase().trim())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is Char -> {
|
||||||
|
when (temp) {
|
||||||
'+' -> PLUS
|
'+' -> PLUS
|
||||||
'-' -> MINUS
|
'-' -> MINUS
|
||||||
'/' -> DIVIDE
|
'/' -> DIVIDE
|
||||||
'*' -> MULTIPLY
|
'*' -> MULTIPLY
|
||||||
else -> throw IllegalArgumentException("operator not found with value: $value!")
|
else -> throw IllegalArgumentException("operator not found with value: $temp!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> throw IllegalArgumentException("operator not found by value: $value!")
|
||||||
}
|
}
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
throw IllegalArgumentException("operator not found!")
|
defaultOperator ?: throw IllegalArgumentException("operator not found!")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoneyGeneratorBuilder {
|
class MoneyObjectBuilder {
|
||||||
|
private val defaultCurrency = MoneyCurrency.USD.getCurrency()
|
||||||
|
|
||||||
private var currency: String? = null
|
private var currency: String? = null
|
||||||
private val withs: MutableCollection<MoneyObject> = LinkedList()
|
private val withs: Deque<MoneyObject> = ArrayDeque()
|
||||||
|
|
||||||
fun withCurrency(currency: String) = apply {
|
fun withCurrency(currency: String) = apply {
|
||||||
this.currency = currency
|
this.currency = currency
|
||||||
}
|
}
|
||||||
|
|
||||||
fun with(`object`: MoneyObject) = apply {
|
fun with(value: MoneyObject) = apply {
|
||||||
this.withs.add(`object`)
|
this.withs.add(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun with(value: Double, currency: String, operator: MoneyOperator = MoneyOperator.PLUS) = apply {
|
fun with(value: Double, currency: String, operator: MoneyOperator = MoneyOperator.PLUS) = apply {
|
||||||
@ -112,21 +149,36 @@ class MoneyObject(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example: String format => usd:1:+,khr:4000.0:-,usd:1 => 1 + (4000 eh) - 1 = 1USD
|
||||||
|
*/
|
||||||
|
fun parseFromString(valuesString: String) = apply {
|
||||||
|
val valueGroups = valuesString.split(",")
|
||||||
|
valueGroups.forEach { value ->
|
||||||
|
val tempValue = value.trim().split(":")
|
||||||
|
if (tempValue.isNotEmpty() && !tempValue.firstOrNull().isNullOrEmpty()) {
|
||||||
|
this.with(
|
||||||
|
tempValue.getOrNull(1)?.toDoubleOrNull() ?: 0.0,
|
||||||
|
tempValue.firstOrNull() ?: defaultCurrency,
|
||||||
|
MoneyOperator.operator(tempValue.getOrNull(2), MoneyOperator.PLUS),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun build(): MoneyObject {
|
fun build(): MoneyObject {
|
||||||
val first: MoneyObject
|
val first: MoneyObject = if (this.currency.isNullOrEmpty() && withs.isNotEmpty()) {
|
||||||
if (this.currency.isNullOrEmpty() && withs.isNotEmpty()) {
|
withs.removeFirst()
|
||||||
first = withs.first()
|
|
||||||
withs.remove(first)
|
|
||||||
} else {
|
} else {
|
||||||
first = MoneyObject(
|
MoneyObject(
|
||||||
value = 0.0,
|
value = 0.0,
|
||||||
|
currency = this.currency ?: defaultCurrency,
|
||||||
operator = MoneyOperator.PLUS,
|
operator = MoneyOperator.PLUS,
|
||||||
currency = this.currency ?: MoneyCurrency.USD.getCurrency()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
withs.forEach { with ->
|
while (withs.isNotEmpty()) {
|
||||||
first.appendWith(with)
|
first.appendWithNext(withs.pop())
|
||||||
}
|
}
|
||||||
|
|
||||||
return first
|
return first
|
||||||
@ -138,6 +190,6 @@ class MoneyObject(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun builder() = MoneyGeneratorBuilder()
|
fun builder() = MoneyObjectBuilder()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -14,6 +14,14 @@ class MoneyTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object MyBatchRates {
|
||||||
|
fun getJsonRates(): String {
|
||||||
|
return """
|
||||||
|
{"USD": 1.0,"KHR": 4000.0, "eur": 0.5}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun exchange_2usd_to_khr_test() {
|
fun exchange_2usd_to_khr_test() {
|
||||||
initMoneyConfig()
|
initMoneyConfig()
|
||||||
@ -47,14 +55,6 @@ class MoneyTests {
|
|||||||
Assert.assertEquals(156000.0, sum.getMoneyValue(), 0.0)
|
Assert.assertEquals(156000.0, sum.getMoneyValue(), 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
object MyBatchRates {
|
|
||||||
fun getJsonRates(): String {
|
|
||||||
return """
|
|
||||||
{"USD": 1.0,"KHR": 4000.0, "eur": 0.5}
|
|
||||||
""".trimIndent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun moneyGenerator() {
|
fun moneyGenerator() {
|
||||||
initMoneyConfig()
|
initMoneyConfig()
|
||||||
@ -102,4 +102,37 @@ class MoneyTests {
|
|||||||
|
|
||||||
Assert.assertEquals(expected, result.getMoneyValue(), 0.0)
|
Assert.assertEquals(expected, result.getMoneyValue(), 0.0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun moneyGeneratorBuilderWithStringValues() {
|
||||||
|
initMoneyConfig()
|
||||||
|
|
||||||
|
val values = "usd:1:+,khr:4000:-,usd:1:+,eur:1:+" // result = 3
|
||||||
|
val expected1 = 3.0
|
||||||
|
val expected2 = 3.5
|
||||||
|
|
||||||
|
val builder = MoneyObject.builder()
|
||||||
|
.withCurrency("usd")
|
||||||
|
.with(1.0, "usd", '-')
|
||||||
|
.with(4000.0, "khr")
|
||||||
|
.with(1.0, "usd")
|
||||||
|
.with(1.0, "usd")
|
||||||
|
.with(1.0, "usd")
|
||||||
|
.with(1.0, "usd")
|
||||||
|
.with(1.0, "eur", '-') // 2 usd
|
||||||
|
.with(1.0, "usd")
|
||||||
|
.with(2.0, "usd", '/')
|
||||||
|
.with(2.0, "usd")
|
||||||
|
.build() // 3.5
|
||||||
|
|
||||||
|
val result1 = MoneyObject.builder()
|
||||||
|
.parseFromString(values)
|
||||||
|
.withCurrency("usd")
|
||||||
|
.build()
|
||||||
|
.compute()
|
||||||
|
val result2 = builder.compute()
|
||||||
|
|
||||||
|
Assert.assertEquals(expected1, result1.getMoneyValue(), 0.0)
|
||||||
|
Assert.assertEquals(expected2, result2.getMoneyValue(), 0.0)
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user