From 1e06ca91fe574833a2f463a8e4c6b4738fd03f2a Mon Sep 17 00:00:00 2001 From: Sujan Poudel Date: Thu, 4 Jan 2024 08:11:25 +0545 Subject: [PATCH] forex country info (#49) --- .../sujanpoudel/playdeals/domain/ForexRate.kt | 8 +++++- .../playdeals/jobs/ForexFetcher.kt | 24 +++++++++++++++- .../playdeals/api/forex/GetForexApiTest.kt | 28 +++++++++++++++++-- 3 files changed, 56 insertions(+), 4 deletions(-) diff --git a/backend/src/main/kotlin/me/sujanpoudel/playdeals/domain/ForexRate.kt b/backend/src/main/kotlin/me/sujanpoudel/playdeals/domain/ForexRate.kt index 286e35f..f47a190 100644 --- a/backend/src/main/kotlin/me/sujanpoudel/playdeals/domain/ForexRate.kt +++ b/backend/src/main/kotlin/me/sujanpoudel/playdeals/domain/ForexRate.kt @@ -8,4 +8,10 @@ data class ForexRate( val rates: List ) -data class ConversionRate(val currency: String, val rate: Float) +data class ConversionRate( + val currency: String, + val symbol: String, + val name: String, + val flag: String, + val rate: Float +) diff --git a/backend/src/main/kotlin/me/sujanpoudel/playdeals/jobs/ForexFetcher.kt b/backend/src/main/kotlin/me/sujanpoudel/playdeals/jobs/ForexFetcher.kt index 5d87dd3..a16d17e 100644 --- a/backend/src/main/kotlin/me/sujanpoudel/playdeals/jobs/ForexFetcher.kt +++ b/backend/src/main/kotlin/me/sujanpoudel/playdeals/jobs/ForexFetcher.kt @@ -19,6 +19,8 @@ import org.kodein.di.instance import java.time.Duration import java.time.OffsetDateTime import java.time.ZoneOffset +import java.util.Currency +import java.util.Locale import java.util.UUID class ForexFetcher( @@ -57,10 +59,23 @@ class ForexFetcher( val epochSeconds = response.getLong("timestamp") val usdRate = response.getJsonObject("rates").getNumber("USD").toFloat() + val currencyLocale = Locale.getAvailableLocales().associateBy { + kotlin.runCatching { Currency.getInstance(it) }.getOrNull() ?: Locale.getDefault() + } + return ForexRate( timestamp = OffsetDateTime.ofInstant(java.time.Instant.ofEpochSecond(epochSeconds), ZoneOffset.UTC), rates = response.getJsonObject("rates").map { - ConversionRate(it.key, (it.value as Number).toFloat() / usdRate) + val currency = kotlin.runCatching { Currency.getInstance(it.key) }.getOrNull() + val locale = currencyLocale.getOrDefault(currency, Locale.US) + + ConversionRate( + currency = it.key, + symbol = currency?.getSymbol(locale) ?: "$", + name = currency?.displayName ?: it.key, + flag = locale.flagEmoji, + rate = (it.value as Number).toFloat() / usdRate + ) } ) } @@ -89,3 +104,10 @@ suspend fun KeyValuesRepository.getForexRate(): ForexRate? = get(KEY_FOREX_RATE) } suspend fun KeyValuesRepository.saveForexRate(forexRate: ForexRate) = set(KEY_FOREX_RATE, Json.encode(forexRate)) + +private val Locale.flagEmoji: String + get() { + val firstLetter = Character.codePointAt(country, 0) - 0x41 + 0x1F1E6 + val secondLetter = Character.codePointAt(country, 1) - 0x41 + 0x1F1E6 + return String(Character.toChars(firstLetter)) + String(Character.toChars(secondLetter)) + } diff --git a/backend/src/test/kotlin/me/sujanpoudel/playdeals/api/forex/GetForexApiTest.kt b/backend/src/test/kotlin/me/sujanpoudel/playdeals/api/forex/GetForexApiTest.kt index 5b40a58..4711820 100644 --- a/backend/src/test/kotlin/me/sujanpoudel/playdeals/api/forex/GetForexApiTest.kt +++ b/backend/src/test/kotlin/me/sujanpoudel/playdeals/api/forex/GetForexApiTest.kt @@ -8,17 +8,38 @@ import me.sujanpoudel.playdeals.IntegrationTest import me.sujanpoudel.playdeals.domain.ConversionRate import me.sujanpoudel.playdeals.domain.ForexRate import me.sujanpoudel.playdeals.get +import me.sujanpoudel.playdeals.jobs.getForexRate import me.sujanpoudel.playdeals.jobs.saveForexRate import me.sujanpoudel.playdeals.repositories.KeyValuesRepository import org.junit.jupiter.api.Test import java.time.OffsetDateTime +import java.time.ZoneOffset class GetForexApiTest(vertx: Vertx) : IntegrationTest(vertx) { + + @Test + fun `Key value repo should properly store the forex rate`() = runTest { + val repository = di.get() + + val forexRate = ForexRate( + timestamp = OffsetDateTime.now().withOffsetSameInstant(ZoneOffset.UTC), + rates = listOf(ConversionRate("USD", "$", "US Dollar", "🇺🇸", 1.1f)) + ) + repository.saveForexRate(forexRate) + + val savedForexRate = repository.getForexRate() + + savedForexRate shouldBe forexRate + } + @Test fun `should return forex if there is data`() = runTest { val repository = di.get() - val forexRate = ForexRate(OffsetDateTime.now(), listOf(ConversionRate("USD", 1.1f))) + val forexRate = ForexRate( + timestamp = OffsetDateTime.now().withOffsetSameInstant(ZoneOffset.UTC), + rates = listOf(ConversionRate("USD", "$", "US Dollar", "🇺🇸", 1.1f)) + ) repository.saveForexRate(forexRate) @@ -28,11 +49,14 @@ class GetForexApiTest(vertx: Vertx) : IntegrationTest(vertx) { .bodyAsJsonObject() response.getJsonObject("data").also { data -> - OffsetDateTime.parse(data.getString("timestamp")).toEpochSecond() shouldBe forexRate.timestamp.toEpochSecond() + OffsetDateTime.parse(data.getString("timestamp")) shouldBe forexRate.timestamp data.getJsonArray("rates").also { rates -> rates.size() shouldBe 1 (rates.first() as JsonObject).also { rate -> rate.getString("currency") shouldBe "USD" + rate.getString("symbol") shouldBe "$" + rate.getString("name") shouldBe "US Dollar" + rate.getString("flag") shouldBe "🇺🇸" rate.getFloat("rate") shouldBe 1.1f } }