diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 7d83415..4d1576e 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -17,6 +17,7 @@
+
diff --git a/build.gradle.kts b/build.gradle.kts
index e744867..9f5ac1c 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -10,7 +10,7 @@ plugins {
}
group = "com.github.smaugfm"
-version = "0.2-alpha"
+version = "0.2.1-alpha"
val myMavenRepoReadUrl: String by project
val myMavenRepoReadUsername: String by project
diff --git a/detektBaseline.xml b/detektBaseline.xml
index 87da838..26369cc 100644
--- a/detektBaseline.xml
+++ b/detektBaseline.xml
@@ -5,7 +5,7 @@
ComplexMethod:PayeeSuggestor.kt$PayeeSuggestor$private fun jaroSimilarity(s1: String, s2: String): Double
LongParameterList:TelegramApi.kt$TelegramApi$( chatId: Any, text: String, parseMode: String? = null, disableWebPagePreview: Boolean? = null, disableNotification: Boolean? = null, replyTo: Int? = null, markup: ReplyKeyboard? = null, )
LongParameterList:TelegramApi.kt$TelegramApi$( chatId: Any? = null, messageId: Int? = null, inlineMessageId: String? = null, text: String, parseMode: String? = null, disableWebPagePreview: Boolean? = null, markup: InlineKeyboardMarkup? = null )
- LongParameterList:Util.kt$( description: String, mcc: String, amount: String, category: String, payee: String, id: String )
+ LongParameterList:Util.kt$( description: String, mcc: String, amount: String, category: String, payee: String, id: String, )
LoopWithTooManyJumpStatements:PayeeSuggestor.kt$PayeeSuggestor$for (j in start..end) { val c2 = s2[j] if (c1 != c2 || s2Consumed[j]) continue s2Consumed[j] = true matches += 1 if (j < s2MatchIndex) transpositions += 1 s2MatchIndex = j break }
MagicNumber:CallbackQueryHandler.kt$CallbackQueryHandler$3
MagicNumber:CallbackQueryHandler.kt$CallbackQueryHandler$6
@@ -13,6 +13,7 @@
MagicNumber:PayeeSuggestor.kt$PayeeSuggestor$0.8
MagicNumber:PayeeSuggestor.kt$PayeeSuggestor$3.0
MagicNumber:Util.kt$10.0
+ NewLineAtEndOfFile:CurrencyAsStringSerializer.kt$com.github.smaugfm.serializers.CurrencyAsStringSerializer.kt
ReturnCount:PayeeSuggestor.kt$PayeeSuggestor$private fun jaroSimilarity(s1: String, s2: String): Double
diff --git a/src/main/kotlin/com/github/smaugfm/serializers/CurrencyAsStringSerializer.kt b/src/main/kotlin/com/github/smaugfm/serializers/CurrencyAsStringSerializer.kt
new file mode 100644
index 0000000..38c8c3a
--- /dev/null
+++ b/src/main/kotlin/com/github/smaugfm/serializers/CurrencyAsStringSerializer.kt
@@ -0,0 +1,21 @@
+package com.github.smaugfm.serializers
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import java.util.Currency
+
+class CurrencyAsStringSerializer : KSerializer {
+ override val descriptor = PrimitiveSerialDescriptor(this::class.qualifiedName!!, PrimitiveKind.STRING)
+
+ override fun deserialize(decoder: Decoder): Currency {
+ val currencyCode = decoder.decodeString()
+ return Currency.getInstance(currencyCode)
+ }
+
+ override fun serialize(encoder: Encoder, value: Currency) {
+ encoder.encodeString(value.currencyCode)
+ }
+}
diff --git a/src/main/kotlin/com/github/smaugfm/settings/Mappings.kt b/src/main/kotlin/com/github/smaugfm/settings/Mappings.kt
index 94ca418..59ef6d8 100644
--- a/src/main/kotlin/com/github/smaugfm/settings/Mappings.kt
+++ b/src/main/kotlin/com/github/smaugfm/settings/Mappings.kt
@@ -1,10 +1,16 @@
+@file:UseSerializers(CurrencyAsStringSerializer::class)
+
package com.github.smaugfm.settings
+import com.github.smaugfm.mono.MonoAccountId
+import com.github.smaugfm.serializers.CurrencyAsStringSerializer
import com.github.smaugfm.serializers.HashBiMapAsMapSerializer
import io.michaelrocks.bimap.BiMap
import io.michaelrocks.bimap.HashBiMap
import kotlinx.serialization.Serializable
+import kotlinx.serialization.UseSerializers
import mu.KotlinLogging
+import java.util.Currency
private val logger = KotlinLogging.logger { }
@@ -12,6 +18,7 @@ private val logger = KotlinLogging.logger { }
data class Mappings(
@Serializable(with = HashBiMapAsMapSerializer::class)
private val monoAcc2Ynab: BiMap,
+ private val monoAccToCurrency: Map,
private val monoAcc2Telegram: Map,
private val mccToCategory: Map,
val unknownPayeeId: String,
@@ -22,6 +29,8 @@ data class Mappings(
fun getMccCategoryOverride(mccCode: Int): String? = mccToCategory[mccCode]
+ fun getAccountCurrency(monoAccountId: MonoAccountId): Currency? = monoAccToCurrency[monoAccountId]
+
fun getYnabAccByMono(monoAcc: String): String? = monoAcc2Ynab[monoAcc].also {
if (it == null)
logger.error("Could not find YNAB account for Mono account $monoAcc")
@@ -33,6 +42,6 @@ data class Mappings(
}
companion object {
- val Empty = Mappings(HashBiMap(), emptyMap(), emptyMap(), "", "")
+ val Empty = Mappings(HashBiMap(), emptyMap(), emptyMap(), emptyMap(), "", "")
}
}
diff --git a/src/main/kotlin/com/github/smaugfm/telegram/handlers/CallbackQueryHandler.kt b/src/main/kotlin/com/github/smaugfm/telegram/handlers/CallbackQueryHandler.kt
index c380a7e..0337fb1 100644
--- a/src/main/kotlin/com/github/smaugfm/telegram/handlers/CallbackQueryHandler.kt
+++ b/src/main/kotlin/com/github/smaugfm/telegram/handlers/CallbackQueryHandler.kt
@@ -47,7 +47,7 @@ class CallbackQueryHandler(
val updatedText = updateHTMLStatementMessage(updatedTransaction, event.message)
val updatedMarkup = updateMarkupKeyboard(type, event.message.reply_markup!!)
- if (stripHTMLtagsFromMessage(updatedText) != event.message.text ||
+ if (stripHTMLTagsFromMessage(updatedText) != event.message.text ||
updatedMarkup != event.message.reply_markup
) {
with(event.message) {
diff --git a/src/main/kotlin/com/github/smaugfm/telegram/handlers/SendStatementMessageHandler.kt b/src/main/kotlin/com/github/smaugfm/telegram/handlers/SendStatementMessageHandler.kt
index 9fc6fe7..75e1c53 100644
--- a/src/main/kotlin/com/github/smaugfm/telegram/handlers/SendStatementMessageHandler.kt
+++ b/src/main/kotlin/com/github/smaugfm/telegram/handlers/SendStatementMessageHandler.kt
@@ -22,12 +22,13 @@ class SendStatementMessageHandler(
event: Event.Telegram.SendStatementMessage,
) {
val monoResponse = event.mono
+ val accountCurrency = mappings.getAccountCurrency(event.mono.account)!!
val transaction = event.transaction
val telegramChatId = mappings.getTelegramChatIdAccByMono(monoResponse.account) ?: return
telegram.sendMessage(
telegramChatId,
- formatHTMLStatementMessage(monoResponse.statementItem, transaction),
+ formatHTMLStatementMessage(accountCurrency, monoResponse.statementItem, transaction),
"HTML",
markup = formatInlineKeyboard(emptySet())
)
diff --git a/src/main/kotlin/com/github/smaugfm/telegram/handlers/Util.kt b/src/main/kotlin/com/github/smaugfm/telegram/handlers/Util.kt
index 19a7598..620a9c5 100644
--- a/src/main/kotlin/com/github/smaugfm/telegram/handlers/Util.kt
+++ b/src/main/kotlin/com/github/smaugfm/telegram/handlers/Util.kt
@@ -10,10 +10,11 @@ import com.github.smaugfm.util.MCC
import com.github.smaugfm.util.formatAmount
import com.github.smaugfm.util.replaceNewLines
import com.github.smaugfm.ynab.YnabTransactionDetail
+import java.util.Currency
import kotlin.reflect.KClass
internal fun formatInlineKeyboard(
- pressed: Set>
+ pressed: Set>,
): InlineKeyboardMarkup {
return InlineKeyboardMarkup(
listOf(
@@ -29,7 +30,7 @@ internal fun formatInlineKeyboard(
)
}
-internal fun stripHTMLtagsFromMessage(messageText: String): String {
+internal fun stripHTMLTagsFromMessage(messageText: String): String {
val replaceHtml = Regex("<.*?>")
return replaceHtml.replace(messageText, "")
}
@@ -40,7 +41,7 @@ internal fun formatHTMLStatementMessage(
amount: String,
category: String,
payee: String,
- id: String
+ id: String,
): String {
val builder = StringBuilder("Новая транзакция Monobank добавлена в YNAB\n")
return with(Unit) {
@@ -56,15 +57,21 @@ internal fun formatHTMLStatementMessage(
}
}
+internal fun formatAmountWithCurrency(amount: Long, currency: Currency) =
+ currency.formatAmount(amount) + currency.currencyCode
+
internal fun formatHTMLStatementMessage(
+ accountCurrency: Currency,
monoStatementItem: MonoStatementItem,
transaction: YnabTransactionDetail,
): String {
with(monoStatementItem) {
+ val accountAmount = formatAmountWithCurrency(amount, accountCurrency)
+ val operationAmount = formatAmountWithCurrency(this.operationAmount, currencyCode)
return formatHTMLStatementMessage(
description.replaceNewLines(),
- MCC.mapRussian[mcc] ?: "Неизвестный MCC",
- currencyCode.formatAmount(amount) + currencyCode.currencyCode,
+ (MCC.mapRussian[mcc] ?: "Неизвестный MCC") + " ($mcc)",
+ accountAmount + (if (accountCurrency != currencyCode) " ($operationAmount)" else ""),
transaction.category_name ?: "",
transaction.payee_name ?: "",
transaction.id,
diff --git a/src/main/kotlin/com/github/smaugfm/util/Util.kt b/src/main/kotlin/com/github/smaugfm/util/Util.kt
index ceb4cb3..5d507c4 100644
--- a/src/main/kotlin/com/github/smaugfm/util/Util.kt
+++ b/src/main/kotlin/com/github/smaugfm/util/Util.kt
@@ -1,6 +1,7 @@
package com.github.smaugfm.util
import java.util.Currency
+import kotlin.math.abs
import kotlin.math.pow
fun Number.formatW(w: Int = 2): String {
@@ -9,7 +10,7 @@ fun Number.formatW(w: Int = 2): String {
fun Currency.formatAmount(amount: Long): String {
val delimiter = (10.0.pow(defaultFractionDigits)).toInt()
- return "${amount / delimiter}.${((amount % delimiter).formatW())}"
+ return "${amount / delimiter}.${(abs(amount % delimiter).formatW())}"
}
fun String.replaceNewLines(): String =
diff --git a/src/test/kotlin/com/github/smaugfm/Playground.kt b/src/test/kotlin/com/github/smaugfm/Playground.kt
index 1091a3b..5337107 100644
--- a/src/test/kotlin/com/github/smaugfm/Playground.kt
+++ b/src/test/kotlin/com/github/smaugfm/Playground.kt
@@ -27,7 +27,7 @@ class Playground {
fun `Get last 29 days Mono transactions`() {
runBlocking {
val window = 30
- val untilDays = window * 7
+ val untilDays = 30
val settings = Settings.loadDefault()
val mono = MonoApi(settings.monoTokens.drop(1).first())
diff --git a/src/test/kotlin/com/github/smaugfm/settings/SettingsTest.kt b/src/test/kotlin/com/github/smaugfm/settings/SettingsTest.kt
index a5f6d6b..a6bb1c7 100644
--- a/src/test/kotlin/com/github/smaugfm/settings/SettingsTest.kt
+++ b/src/test/kotlin/com/github/smaugfm/settings/SettingsTest.kt
@@ -6,6 +6,7 @@ import assertk.assertions.isSuccess
import com.github.smaugfm.util.HashBiMap
import org.junit.jupiter.api.Test
import java.nio.file.Files
+import java.util.Currency
class SettingsTest {
@Test
@@ -22,6 +23,7 @@ class SettingsTest {
"vasa2" to "vasa3",
"vasa4" to "vasa5"
),
+ mapOf("aaa" to Currency.getInstance("UAH")),
mapOf(
"vasa6" to 12324,
"vasa7" to 123242,
diff --git a/src/test/kotlin/com/github/smaugfm/telegram/handlers/TelegramHandlerTest.kt b/src/test/kotlin/com/github/smaugfm/telegram/handlers/TelegramHandlerTest.kt
index 58bae14..d9ec1ed 100644
--- a/src/test/kotlin/com/github/smaugfm/telegram/handlers/TelegramHandlerTest.kt
+++ b/src/test/kotlin/com/github/smaugfm/telegram/handlers/TelegramHandlerTest.kt
@@ -43,6 +43,7 @@ class TelegramHandlerTest {
val statementItem = mockk()
every { statementItem.time } returns Clock.System.now() - 2.days
every { statementItem.amount } returns -11500
+ every { statementItem.operationAmount } returns -11500
every { statementItem.mcc } returns 5722
every { statementItem.description } returns description
every { statementItem.currencyCode } returns Currency.getInstance("UAH")
@@ -65,6 +66,7 @@ class TelegramHandlerTest {
val payee = "Rozetka"
coEvery { api.sendMessage(any(), any(), any(), any(), any(), any(), any()) } returns Unit
every { mappings.getTelegramChatIdAccByMono(any()) } returns chatId
+ every { mappings.getAccountCurrency(any()) } returns Currency.getInstance("UAH")
val (monoResponse, transaction) =
getMonoResponseAndTransaction(payee, payee, monoAccount, UUID.randomUUID().toString())
@@ -74,7 +76,7 @@ class TelegramHandlerTest {
Event.Telegram.SendStatementMessage(monoResponse, transaction)
)
}
- val message = formatHTMLStatementMessage(monoResponse.statementItem, transaction)
+ val message = formatHTMLStatementMessage(Currency.getInstance("UAH"), monoResponse.statementItem, transaction)
coVerify {
mappings.getTelegramChatIdAccByMono(monoAccount)
@@ -120,8 +122,12 @@ class TelegramHandlerTest {
val (monoResponse, transaction) =
getMonoResponseAndTransaction(payee, payee, "vasa", id)
- val messageText = formatHTMLStatementMessage(monoResponse.statementItem, transaction)
- val adjustedMessage = stripHTMLtagsFromMessage(messageText)
+ val messageText = formatHTMLStatementMessage(
+ Currency.getInstance("UAH"),
+ monoResponse.statementItem,
+ transaction
+ )
+ val adjustedMessage = stripHTMLTagsFromMessage(messageText)
val message = mockk {
every { text } returns adjustedMessage
every { entities } returns listOf(
@@ -160,8 +166,8 @@ class TelegramHandlerTest {
every { id } returns transactionId
}
- val messageText = stripHTMLtagsFromMessage(
- formatHTMLStatementMessage(monoResponse.statementItem, transaction)
+ val messageText = stripHTMLTagsFromMessage(
+ formatHTMLStatementMessage(Currency.getInstance("UAH"), monoResponse.statementItem, transaction)
)
val keyboard = formatInlineKeyboard(emptySet())
@@ -198,7 +204,7 @@ class TelegramHandlerTest {
}
val updatedMessageText =
- formatHTMLStatementMessage(monoResponse.statementItem, updatedTransaction)
+ formatHTMLStatementMessage(Currency.getInstance("UAH"), monoResponse.statementItem, updatedTransaction)
val updatedMarkup = formatInlineKeyboard(setOf(TransactionActionType.MakePayee::class))
coVerify {
diff --git a/src/test/kotlin/com/github/smaugfm/ynab/YnabApiTest.kt b/src/test/kotlin/com/github/smaugfm/ynab/YnabApiTest.kt
index 4de3206..a532b64 100644
--- a/src/test/kotlin/com/github/smaugfm/ynab/YnabApiTest.kt
+++ b/src/test/kotlin/com/github/smaugfm/ynab/YnabApiTest.kt
@@ -13,6 +13,7 @@ import org.junit.jupiter.api.Test
class YnabApiTest {
private val settings = Settings.loadDefault()
private val api = YnabApi(settings.ynabToken, "692ab9be-240a-4847-96c1-80aa21709e9c")
+
private val handler = YnabHandler(api, settings.mappings)
private val accountId = "1355f021-05fc-446b-b2e8-19eb44dd8ede"
@@ -69,9 +70,14 @@ class YnabApiTest {
@Test
fun `Get categories`() {
runBlocking {
- api.getCategories().map { it.categories }.flatten().map { it.id to it.name }.forEach {
- println(it)
- }
+ api
+ .getCategories()
+ .map { it.categories }
+ .flatten()
+ .map { it.id to it.name }
+ .forEach {
+ println("${it.first} - ${it.second}")
+ }
}
println()
}