Updated on 2026-08-14

This commit is contained in:
Tangem 2025-08-24 14:16:45 +05:00
parent db08399066
commit ae809ece30
28 changed files with 939 additions and 10 deletions

View file

@ -1,12 +1,17 @@
package com.tangem.data.wallets
import arrow.core.Either
import arrow.core.left
import arrow.core.right
import com.tangem.data.wallets.converters.UserWalletRemoteInfoConverter
import com.tangem.data.wallets.converters.WalletIdBodyConverter
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.common.response.ApiResponseError.HttpException
import com.tangem.datasource.api.common.response.fold
import com.tangem.datasource.api.common.response.getOrThrow
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.MarkUserWalletWasCreatedBody
import com.tangem.datasource.api.tangemTech.models.PromocodeActivationBody
import com.tangem.datasource.api.tangemTech.models.SeedPhraseNotificationDTO
import com.tangem.datasource.api.tangemTech.models.SeedPhraseNotificationDTO.Status
import com.tangem.datasource.api.tangemTech.models.WalletBody
@ -23,6 +28,7 @@ import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.models.SeedPhraseNotificationsStatus
import com.tangem.domain.wallets.models.UserWalletRemoteInfo
import com.tangem.domain.wallets.models.errors.ActivatePromoCodeError
import com.tangem.domain.wallets.repository.WalletsRepository
import com.tangem.utils.WEEK_MILLIS
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
@ -308,4 +314,28 @@ internal class DefaultWalletsRepository(
body = walletsBody,
).getOrThrow()
}
override suspend fun activatePromoCode(
promoCode: String,
bitcoinAddress: String,
): Either<ActivatePromoCodeError, String> = withContext(dispatchers.io) {
tangemTechApi.activatePromoCode(
body = PromocodeActivationBody(
promoCode = promoCode,
address = bitcoinAddress,
),
).fold({
return@fold it.status.right()
}, { error ->
val error = when (error) {
is HttpException -> when (error.code) {
HttpException.Code.NOT_FOUND -> ActivatePromoCodeError.InvalidPromoCode
HttpException.Code.CONFLICT -> ActivatePromoCodeError.PromocodeAlreadyUsed
else -> ActivatePromoCodeError.ActivationFailed
}
else -> ActivatePromoCodeError.ActivationFailed
}
return@fold error.left()
},)
}
}

View file

@ -6,12 +6,16 @@ import com.google.common.truth.Truth.assertThat
import com.squareup.moshi.Moshi
import com.tangem.datasource.api.common.AuthProvider
import com.tangem.datasource.api.common.response.ApiResponse
import com.tangem.datasource.api.common.response.ApiResponseError.HttpException
import com.tangem.datasource.api.tangemTech.TangemTechApi
import com.tangem.datasource.api.tangemTech.models.WalletResponse
import com.tangem.datasource.api.tangemTech.models.PromocodeActivationBody
import com.tangem.datasource.api.tangemTech.models.PromocodeActivationResponse
import com.tangem.datasource.local.preferences.AppPreferencesStore
import com.tangem.datasource.local.preferences.PreferencesKeys
import com.tangem.domain.models.wallet.UserWallet
import com.tangem.domain.models.wallet.UserWalletId
import com.tangem.domain.wallets.models.errors.ActivatePromoCodeError
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
import com.tangem.utils.coroutines.TestingCoroutineDispatcherProvider
import io.mockk.coEvery
@ -235,4 +239,64 @@ class DefaultWalletsRepositoryTest {
)
}
}
@Test
fun `GIVEN valid data WHEN activatePromoCode THEN returns Right with status and calls API`() = runTest {
// GIVEN
val promoCode = "PROMO123"
val address = "bc1qexampleaddress"
coEvery { tangemTechApi.activatePromoCode(any()) } returns ApiResponse.Success(
PromocodeActivationResponse(status = "activated"),
)
// WHEN
val result = repository.activatePromoCode(promoCode = promoCode, bitcoinAddress = address)
// THEN
var right: String? = null
var left: ActivatePromoCodeError? = null
result.fold({ left = it }, { right = it })
assertThat(left).isNull()
assertThat(right).isEqualTo("activated")
coVerify(exactly = 1) {
tangemTechApi.activatePromoCode(
match { it is PromocodeActivationBody && it.promoCode == promoCode && it.address == address },
)
}
}
@Test
fun `GIVEN NOT_FOUND error WHEN activatePromoCode THEN returns Left InvalidPromoCode`() = runTest {
// GIVEN
coEvery { tangemTechApi.activatePromoCode(any()) } returns
ApiResponse.Error(
HttpException(code = HttpException.Code.NOT_FOUND, message = null, errorBody = null),
) as ApiResponse<PromocodeActivationResponse>
// WHEN
val result = repository.activatePromoCode(promoCode = "PROMO", bitcoinAddress = "addr")
// THEN
var error: ActivatePromoCodeError? = null
result.fold({ error = it }, { })
assertThat(error).isEqualTo(ActivatePromoCodeError.InvalidPromoCode)
}
@Test
fun `GIVEN CONFLICT error WHEN activatePromoCode THEN returns Left PromocodeAlreadyUsed`() = runTest {
// GIVEN
coEvery { tangemTechApi.activatePromoCode(any()) } returns
ApiResponse.Error(
HttpException(code = HttpException.Code.CONFLICT, message = null, errorBody = null),
) as ApiResponse<PromocodeActivationResponse>
// WHEN
val result = repository.activatePromoCode(promoCode = "PROMO", bitcoinAddress = "addr")
// THEN
var error: ActivatePromoCodeError? = null
result.fold({ error = it }, { })
assertThat(error).isEqualTo(ActivatePromoCodeError.PromocodeAlreadyUsed)
}
}