Updated on 2026-08-14

This commit is contained in:
Tangem 2026-06-08 16:03:08 +05:00
parent 24d7953389
commit 8683516c59
24 changed files with 817 additions and 148 deletions

View file

@ -10,6 +10,7 @@ import com.tangem.datasource.api.common.adapter.*
import com.tangem.datasource.local.config.providers.models.ProviderModel
import com.tangem.datasource.local.network.entity.NetworkStatusDM
import com.tangem.datasource.local.visa.entity.PaymentAccountStatusValueDM
import com.tangem.datasource.local.visa.entity.VirtualAccountStatusValueDM
import com.tangem.datasource.utils.SerializeNullsFactory
import com.tangem.domain.models.scan.serialization.*
import dagger.Module
@ -56,6 +57,18 @@ class MoshiModule {
.withSubtype(PaymentAccountStatusValueDM.DeactivatedAccount::class.java, "deactivated_account")
.withSubtype(PaymentAccountStatusValueDM.CardIssueFailed::class.java, "card_issue_failed"),
)
.add(
NamePolymorphicAdapterFactory.of(VirtualAccountStatusValueDM::class.java)
.withSubtype(VirtualAccountStatusValueDM.Empty::class.java, "empty")
.withSubtype(VirtualAccountStatusValueDM.NotCreated::class.java, "not_created")
.withSubtype(VirtualAccountStatusValueDM.UnderReview::class.java, "kyc_status")
.withSubtype(VirtualAccountStatusValueDM.Provisioning::class.java, "provisioning")
.withSubtype(
VirtualAccountStatusValueDM.CountryNotSupported::class.java,
"country_not_supported",
)
.withSubtype(VirtualAccountStatusValueDM.ActiveAccount::class.java, "active_account"),
)
.add(
PolymorphicJsonAdapterFactory.of(NFTCollection.Identifier::class.java, "bc")
.withSubtype(NFTCollection.Identifier.EVM::class.java, "evm")

View file

@ -0,0 +1,71 @@
@file:Suppress("BooleanPropertyNaming")
package com.tangem.datasource.local.visa.entity
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass
import com.tangem.domain.models.kyc.KycStatus
import dev.onenowy.moshipolymorphicadapter.PolymorphicAdapterType
import dev.onenowy.moshipolymorphicadapter.annotations.NameLabel
import java.math.BigDecimal
/**
* Virtual account status for storage in the local cache.
*
* @see [com.tangem.domain.models.account.AccountStatus.Virtual]
*/
@JsonClass(generateAdapter = true, generator = PolymorphicAdapterType.NAME_POLYMORPHIC_ADAPTER)
sealed interface VirtualAccountStatusValueDM {
@NameLabel("empty")
data class Empty(
@Json(name = "empty") val marker: Boolean = true,
) : VirtualAccountStatusValueDM
@NameLabel("not_created")
data class NotCreated(
@Json(name = "not_created") val marker: Boolean = true,
) : VirtualAccountStatusValueDM
@NameLabel("kyc_status")
data class UnderReview(
@Json(name = "kyc_status") val kycStatus: KycStatus,
@Json(name = "customer_id") val customerId: String,
) : VirtualAccountStatusValueDM
@NameLabel("provisioning")
data class Provisioning(
@Json(name = "provisioning") val marker: Boolean = true,
) : VirtualAccountStatusValueDM
@NameLabel("country_not_supported")
data class CountryNotSupported(
@Json(name = "country_not_supported") val marker: Boolean = true,
) : VirtualAccountStatusValueDM
@NameLabel("active_account")
data class ActiveAccount(
@Json(name = "active_account") val marker: Boolean = true,
@Json(name = "customer_id") val customerId: String,
@Json(name = "currency_code") val currencyCode: String,
@Json(name = "deposit_address") val depositAddress: String?,
@Json(name = "fiat_balance") val fiatBalance: FiatBalanceDM,
@Json(name = "crypto_balance") val cryptoBalance: CryptoBalanceDM,
@Json(name = "fiat_rate") val fiatRate: BigDecimal?,
@Json(name = "available_for_withdrawal") val availableForWithdrawal: BigDecimal,
) : VirtualAccountStatusValueDM
@JsonClass(generateAdapter = true)
data class FiatBalanceDM(
@Json(name = "available_balance") val availableBalance: BigDecimal,
@Json(name = "currency") val currency: String,
)
@JsonClass(generateAdapter = true)
data class CryptoBalanceDM(
@Json(name = "id") val id: String,
@Json(name = "chain_id") val chainId: Long,
@Json(name = "deposit_address") val depositAddress: String,
@Json(name = "token_contract_address") val tokenContractAddress: String,
@Json(name = "balance") val balance: BigDecimal,
)
}

View file

@ -0,0 +1,74 @@
package com.tangem.datasource.local.visa.entity
import com.google.common.truth.Truth
import com.squareup.moshi.adapter
import com.tangem.datasource.di.MoshiModule
import org.junit.jupiter.api.Test
import java.math.BigDecimal
/**
* Verifies that the network Moshi (see [MoshiModule.provideNetworkMoshi]) resolves and round-trips the
* polymorphic [VirtualAccountStatusValueDM] adapter.
*
* Guards against the missing `NamePolymorphicAdapterFactory` registration that caused a runtime
* `ClassNotFoundException: ...VirtualAccountStatusValueDMJsonAdapter` (the adapter is registered manually,
* not generated).
*/
class VirtualAccountStatusValueDMSerializationTest {
@OptIn(ExperimentalStdlibApi::class)
private val adapter = MoshiModule().provideNetworkMoshi().adapter<VirtualAccountStatusValueDM>()
@Test
fun `round-trip NotCreated`() {
val model: VirtualAccountStatusValueDM = VirtualAccountStatusValueDM.NotCreated()
val restored = adapter.fromJson(adapter.toJson(model))
Truth.assertThat(restored).isInstanceOf(VirtualAccountStatusValueDM.NotCreated::class.java)
}
@Test
fun `round-trip Provisioning`() {
val model: VirtualAccountStatusValueDM = VirtualAccountStatusValueDM.Provisioning()
val restored = adapter.fromJson(adapter.toJson(model))
Truth.assertThat(restored).isInstanceOf(VirtualAccountStatusValueDM.Provisioning::class.java)
}
@Test
fun `round-trip CountryNotSupported`() {
val model: VirtualAccountStatusValueDM = VirtualAccountStatusValueDM.CountryNotSupported()
val restored = adapter.fromJson(adapter.toJson(model))
Truth.assertThat(restored).isInstanceOf(VirtualAccountStatusValueDM.CountryNotSupported::class.java)
}
@Test
fun `round-trip ActiveAccount`() {
val model: VirtualAccountStatusValueDM = VirtualAccountStatusValueDM.ActiveAccount(
customerId = "cust-1",
currencyCode = "USD",
depositAddress = "0xabc",
fiatBalance = VirtualAccountStatusValueDM.FiatBalanceDM(
availableBalance = BigDecimal("101.56"),
currency = "USD",
),
cryptoBalance = VirtualAccountStatusValueDM.CryptoBalanceDM(
id = "usd-coin",
chainId = 137L,
depositAddress = "0xabc",
tokenContractAddress = "0xdef",
balance = BigDecimal("101.56"),
),
fiatRate = BigDecimal("0.95"),
availableForWithdrawal = BigDecimal("100.00"),
)
val restored = adapter.fromJson(adapter.toJson(model))
Truth.assertThat(restored).isEqualTo(model)
}
}