1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
/*
This file is part of GNU Taler
(C) 2019 Taler Systems S.A.
GNU Taler is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 3, or (at your option) any later version.
GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.taler.wallet
import org.json.JSONObject
import kotlin.math.round
private const val FRACTIONAL_BASE = 1e8
data class Amount(val currency: String, val amount: String) {
fun isZero(): Boolean {
return amount.toDouble() == 0.0
}
companion object {
fun fromJson(jsonAmount: JSONObject): Amount {
val amountCurrency = jsonAmount.getString("currency")
val amountValue = jsonAmount.getString("value")
val amountFraction = jsonAmount.getString("fraction")
val amountIntValue = Integer.parseInt(amountValue)
val amountIntFraction = Integer.parseInt(amountFraction)
return Amount(
amountCurrency,
(amountIntValue + amountIntFraction / FRACTIONAL_BASE).toString()
)
}
fun fromString(strAmount: String): Amount {
val components = strAmount.split(":")
return Amount(components[0], components[1])
}
}
}
class ParsedAmount(
/**
* name of the currency using either a three-character ISO 4217 currency code,
* or a regional currency identifier starting with a "*" followed by at most 10 characters.
* ISO 4217 exponents in the name are not supported,
* although the "fraction" is corresponds to an ISO 4217 exponent of 6.
*/
val currency: String,
/**
* unsigned 32 bit value in the currency,
* note that "1" here would correspond to 1 EUR or 1 USD, depending on currency, not 1 cent.
*/
val value: UInt,
/**
* unsigned 32 bit fractional value to be added to value
* representing an additional currency fraction,
* in units of one millionth (1e-6) of the base currency value.
* For example, a fraction of 500,000 would correspond to 50 cents.
*/
val fraction: Double
) {
companion object {
fun parseAmount(str: String): ParsedAmount {
val split = str.split(":")
check(split.size == 2)
val currency = split[0]
val valueSplit = split[1].split(".")
val value = valueSplit[0].toUInt()
val fraction: Double = if (valueSplit.size > 1) {
round("0.${valueSplit[1]}".toDouble() * FRACTIONAL_BASE)
} else 0.0
return ParsedAmount(currency, value, fraction)
}
}
operator fun minus(other: ParsedAmount): ParsedAmount {
check(currency == other.currency) { "Can only subtract from same currency" }
var resultValue = value
var resultFraction = fraction
if (resultFraction < other.fraction) {
if (resultValue < 1u) {
return ParsedAmount(currency, 0u, 0.0)
}
resultValue--
resultFraction += FRACTIONAL_BASE
}
check(resultFraction >= other.fraction)
resultFraction -= other.fraction
if (resultValue < other.value) {
return ParsedAmount(currency, 0u, 0.0)
}
resultValue -= other.value
return ParsedAmount(currency, resultValue, resultFraction)
}
fun isZero(): Boolean {
return value == 0u && fraction == 0.0
}
fun toJSONString(): String {
return "$currency:${getValueString()}"
}
override fun toString(): String {
return "${getValueString()} $currency"
}
private fun getValueString(): String {
return "$value${(fraction / FRACTIONAL_BASE).toString().substring(1)}"
}
}
|