Compare commits

...

6 Commits

Author SHA1 Message Date
e82fb280ab Add special string for annotation and its processor for only field
Updated std money and add money arithemtic
2020-08-27 21:42:05 +07:00
4dc6ae521c Add money extension and operator 2020-08-27 10:48:31 +07:00
377809383d Add money create for static funcs 2020-08-27 10:45:57 +07:00
a8841a537d Add build and publish the jar libra 2020-08-27 10:19:50 +07:00
32441f7de6 Updated valid for money config 2020-08-27 08:48:18 +07:00
7204246dc9 Add tests for money 2020-08-27 08:46:33 +07:00
14 changed files with 200 additions and 27 deletions

6
.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@@ -1,5 +1,7 @@
plugins { plugins {
kotlin("jvm") version "1.4.0" kotlin("jvm") version "1.4.0"
`java-library`
id("de.marcphilipp.nexus-publish") version "0.4.0"
} }
group = "com.cubetiqs.libra" group = "com.cubetiqs.libra"
@@ -13,3 +15,22 @@ dependencies {
implementation(kotlin("stdlib")) implementation(kotlin("stdlib"))
testImplementation("org.junit.vintage:junit-vintage-engine:5.6.2") testImplementation("org.junit.vintage:junit-vintage-engine:5.6.2")
} }
publishing {
publications {
create<MavenPublication>("mavenJava") {
from(components["java"])
}
}
}
nexusPublishing {
repositories {
create("mavenJava") {
nexusUrl.set(uri("https://nexus.osa.cubetiqs.com/repository/local-maven-dev/"))
snapshotRepositoryUrl.set(uri("https://nexus.osa.cubetiqs.com/repository/local-maven-dev/"))
username.set("cubetiq")
password.set("cube17tiq")
}
}
}

View File

@@ -2,7 +2,7 @@ package com.cubetiqs.libra.moneyutils
open class Money( open class Money(
var value: Double, var value: Double,
private var currency: String = "USD" @SpecialString(trim = true, upperCase = true) private var currency: String = "USD"
) : StdMoney { ) : StdMoney {
//////////////////// - PROPERTIES - //////////////////// //////////////////// - PROPERTIES - ////////////////////
@@ -12,7 +12,7 @@ open class Money(
} }
override fun getMoneyCurrency(): String { override fun getMoneyCurrency(): String {
return this.currency.toUpperCase() return this.currency
} }
//////////////////// - GENERIC - //////////////////// //////////////////// - GENERIC - ////////////////////
@@ -24,5 +24,27 @@ open class Money(
companion object { companion object {
val ZERO: StdMoney val ZERO: StdMoney
get() = Money(value = 0.0) get() = Money(value = 0.0)
val ONE: StdMoney
get() = Money(value = 1.0)
val TEN: StdMoney
get() = Money(value = 10.0)
/**
* Create a new money object with custom value
*
* @param value Double
* @param currency String
*/
fun create(value: Double, currency: String = MoneyCurrency.USD.name): StdMoney {
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)
} }
} }

View File

@@ -0,0 +1,5 @@
package com.cubetiqs.libra.moneyutils
fun StdMoney.addMoney(value: Double, currency: String): StdMoney {
return this + Money.create(value, currency)
}

View File

@@ -15,8 +15,11 @@ object MoneyConfig {
* Value is the rate * Value is the rate
*/ */
private val config: MutableMap<String, Double> = mutableMapOf() private val config: MutableMap<String, Double> = mutableMapOf()
private var valid: Boolean = false
fun isValid() = valid // validate the config, if have it's valid
fun isValid(): Boolean {
return this.config.isNotEmpty()
}
/** /**
* Money properties for money config format * Money properties for money config format
@@ -58,9 +61,6 @@ object MoneyConfig {
throw MoneyCurrencyStateException("money config format is not valid!") throw MoneyCurrencyStateException("money config format is not valid!")
} }
} }
// validate the config is load or not
this.valid = this.config.isNotEmpty()
} }
// all currencies with its rate // all currencies with its rate

View File

@@ -0,0 +1,7 @@
package com.cubetiqs.libra.moneyutils
enum class MoneyCurrency {
USD,
KHR,
EUR
}

View File

@@ -0,0 +1,5 @@
package com.cubetiqs.libra.moneyutils
interface MoneyExchangeAdapter {
fun getRate(currency: String): Double
}

View File

@@ -0,0 +1,7 @@
package com.cubetiqs.libra.moneyutils
fun StdMoney.exchangeTo(currency: String): StdMoney {
return MoneyExchangeUtils.exchange(this, currency)
}
fun StdMoney.isMatchedCurrency(currency: String) = this.getMoneyCurrency().equals(currency, ignoreCase = true)

View File

@@ -1,13 +1,12 @@
package com.cubetiqs.libra.moneyutils package com.cubetiqs.libra.moneyutils
operator fun Money.unaryMinus() = (-getMoneyValue()) operator fun StdMoney.unaryMinus() = (-getMoneyValue())
operator fun Money.unaryPlus() = (+getMoneyValue()) operator fun StdMoney.unaryPlus() = (+getMoneyValue())
operator fun Money.inc() = Money(value++) operator fun Money.inc() = Money(value++)
operator fun Money.dec() = Money(value--) operator fun Money.dec() = Money(value--)
operator fun Money.plus(other: Money) = Money(value + other.value) operator fun StdMoney.plus(other: StdMoney) = Money(getMoneyValue() + other.getMoneyValue())
operator fun Money.times(other: Money) = Money(value * other.value) operator fun StdMoney.times(other: StdMoney) = Money(getMoneyValue() * other.getMoneyValue())
operator fun Money.div(other: Money) = Money(value / other.value) operator fun StdMoney.div(other: StdMoney) = Money(getMoneyValue() / other.getMoneyValue())
operator fun Money.timesAssign(other: Money) { operator fun Money.timesAssign(other: StdMoney) {
this.value = this.value * other.value this.value = this.getMoneyValue() * other.getMoneyValue()
} }
operator fun Money.not() = this.value != this.value

View File

@@ -0,0 +1,5 @@
package com.cubetiqs.libra.moneyutils
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class SpecialString(val value: String = "", val upperCase: Boolean = true, val trim: Boolean = true)

View File

@@ -0,0 +1,37 @@
package com.cubetiqs.libra.moneyutils
import java.lang.reflect.Field
class SpecialStringProcessor: ISerializer {
override fun <T> serialize(data: T?): T? {
if (data == null) return null
val clazz = data.javaClass
clazz.declaredFields.forEach {
it.isAccessible = true
if (it.isAnnotationPresent(SpecialString::class.java) && it.genericType == String::class.java) {
val annotationValues = it.getAnnotation(SpecialString::class.java)
var value = it.get(data).toString()
if (annotationValues.trim) {
value = value.trim()
}
if (annotationValues.upperCase) {
value = value.toUpperCase()
}
it.set(data, value)
}
}
return data
}
private fun getSerializeKey(field: Field): String {
val annotationValue = field.getAnnotation(SpecialString::class.java).value
return if (annotationValue.isEmpty()) {
field.name
} else annotationValue
}
}
interface ISerializer {
fun <T> serialize(data: T?): T?
}

View File

@@ -20,5 +20,6 @@ interface StdMoney {
* *
* @return String * @return String
*/ */
@SpecialString
fun getMoneyCurrency(): String fun getMoneyCurrency(): String
} }

View File

@@ -1,21 +1,26 @@
import com.cubetiqs.libra.moneyutils.Money import com.cubetiqs.libra.moneyutils.Money
import com.cubetiqs.libra.moneyutils.MoneyConfig import com.cubetiqs.libra.moneyutils.MoneyConfig
import com.cubetiqs.libra.moneyutils.MoneyCurrency
import com.cubetiqs.libra.moneyutils.MoneyExchangeUtils import com.cubetiqs.libra.moneyutils.MoneyExchangeUtils
import com.cubetiqs.libra.moneyutils.plus import com.cubetiqs.libra.moneyutils.SpecialStringProcessor
import com.cubetiqs.libra.moneyutils.times
import com.cubetiqs.libra.moneyutils.timesAssign
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
class MoneyTests { class MoneyTests {
@Test @Test
fun test() { fun money_operator_test() {
val money = Money(10.0) // val money = Money(10.0)
val money2 = Money(20.0) // val money2 = Money(20.0)
money *= money // money *= money
println((money + money2) * money2) // println((money + money2) * money2)
Assert.assertEquals(10, 10) // 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 val properties = MoneyConfig
.MoneyConfigProperties .MoneyConfigProperties
.MoneyConfigPropertiesBuilder() .MoneyConfigPropertiesBuilder()
@@ -27,11 +32,27 @@ class MoneyTests {
.setProperties(properties) .setProperties(properties)
.parse("USD:1,KHR:4000") .parse("USD:1,KHR:4000")
Assert.assertTrue(MoneyConfig.isValid())
println(MoneyConfig.getConfig()) println(MoneyConfig.getConfig())
val moneyUsd = Money(10.0) val moneyUsd = Money(2.0)
val moneyKhr = MoneyExchangeUtils.exchange(moneyUsd, "KHR") val moneyKhr = MoneyExchangeUtils.exchange(moneyUsd, "KHR")
Assert.assertEquals(40000.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
} }
} }

View File

@@ -0,0 +1,37 @@
import org.junit.Test
class ObjectTests {
@Test
fun builder_object_test() {
val person = Person
.builder()
.name("Sambo Chea")
.id(10)
.build()
println(person)
}
}
data class Person(val id: Long? = null, val name: String? = null) {
companion object {
fun builder(): PersonBuilder {
return PersonBuilder()
}
}
}
class PersonBuilder {
private var id: Long? = null
private var name: String? = null
fun id(id: Long?) = apply { this.id = id }
fun name(name: String?) = apply { this.name = name }
fun build(): Person {
return Person(id, name)
}
}