Skip to content

Commit

Permalink
v0.2.1
Browse files Browse the repository at this point in the history
  • Loading branch information
smaugfm committed Nov 11, 2020
1 parent b739a71 commit 3f63f60
Show file tree
Hide file tree
Showing 13 changed files with 76 additions and 21 deletions.
1 change: 1 addition & 0 deletions .idea/codeStyles/Project.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion detektBaseline.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
<ID>ComplexMethod:PayeeSuggestor.kt$PayeeSuggestor$private fun jaroSimilarity(s1: String, s2: String): Double</ID>
<ID>LongParameterList:TelegramApi.kt$TelegramApi$( chatId: Any, text: String, parseMode: String? = null, disableWebPagePreview: Boolean? = null, disableNotification: Boolean? = null, replyTo: Int? = null, markup: ReplyKeyboard? = null, )</ID>
<ID>LongParameterList:TelegramApi.kt$TelegramApi$( chatId: Any? = null, messageId: Int? = null, inlineMessageId: String? = null, text: String, parseMode: String? = null, disableWebPagePreview: Boolean? = null, markup: InlineKeyboardMarkup? = null )</ID>
<ID>LongParameterList:Util.kt$( description: String, mcc: String, amount: String, category: String, payee: String, id: String )</ID>
<ID>LongParameterList:Util.kt$( description: String, mcc: String, amount: String, category: String, payee: String, id: String, )</ID>
<ID>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 &lt; s2MatchIndex) transpositions += 1 s2MatchIndex = j break }</ID>
<ID>MagicNumber:CallbackQueryHandler.kt$CallbackQueryHandler$3</ID>
<ID>MagicNumber:CallbackQueryHandler.kt$CallbackQueryHandler$6</ID>
<ID>MagicNumber:PayeeSuggestor.kt$PayeeSuggestor$0.1</ID>
<ID>MagicNumber:PayeeSuggestor.kt$PayeeSuggestor$0.8</ID>
<ID>MagicNumber:PayeeSuggestor.kt$PayeeSuggestor$3.0</ID>
<ID>MagicNumber:Util.kt$10.0</ID>
<ID>NewLineAtEndOfFile:CurrencyAsStringSerializer.kt$com.github.smaugfm.serializers.CurrencyAsStringSerializer.kt</ID>
<ID>ReturnCount:PayeeSuggestor.kt$PayeeSuggestor$private fun jaroSimilarity(s1: String, s2: String): Double</ID>
</CurrentIssues>
</SmellBaseline>
Original file line number Diff line number Diff line change
@@ -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<Currency> {
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)
}
}
11 changes: 10 additions & 1 deletion src/main/kotlin/com/github/smaugfm/settings/Mappings.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
@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 { }

@Serializable
data class Mappings(
@Serializable(with = HashBiMapAsMapSerializer::class)
private val monoAcc2Ynab: BiMap<String, String>,
private val monoAccToCurrency: Map<String, Currency>,
private val monoAcc2Telegram: Map<String, Int>,
private val mccToCategory: Map<Int, String>,
val unknownPayeeId: String,
Expand All @@ -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")
Expand All @@ -33,6 +42,6 @@ data class Mappings(
}

companion object {
val Empty = Mappings(HashBiMap(), emptyMap(), emptyMap(), "", "")
val Empty = Mappings(HashBiMap(), emptyMap(), emptyMap(), emptyMap(), "", "")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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())
)
Expand Down
17 changes: 12 additions & 5 deletions src/main/kotlin/com/github/smaugfm/telegram/handlers/Util.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<KClass<out TransactionActionType>>
pressed: Set<KClass<out TransactionActionType>>,
): InlineKeyboardMarkup {
return InlineKeyboardMarkup(
listOf(
Expand All @@ -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, "")
}
Expand All @@ -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) {
Expand All @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion src/main/kotlin/com/github/smaugfm/util/Util.kt
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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 =
Expand Down
2 changes: 1 addition & 1 deletion src/test/kotlin/com/github/smaugfm/Playground.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
2 changes: 2 additions & 0 deletions src/test/kotlin/com/github/smaugfm/settings/SettingsTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class TelegramHandlerTest {
val statementItem = mockk<MonoStatementItem>()
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")
Expand All @@ -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())
Expand All @@ -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)
Expand Down Expand Up @@ -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<Message> {
every { text } returns adjustedMessage
every { entities } returns listOf(
Expand Down Expand Up @@ -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())

Expand Down Expand Up @@ -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 {
Expand Down
12 changes: 9 additions & 3 deletions src/test/kotlin/com/github/smaugfm/ynab/YnabApiTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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()
}
Expand Down

0 comments on commit 3f63f60

Please sign in to comment.