Updated on 2026-08-14
This commit is contained in:
parent
8a749438bf
commit
8098476fde
15 changed files with 459 additions and 180 deletions
|
|
@ -26,9 +26,11 @@ import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
|||
import com.tangem.domain.pay.flow.PaymentAccountStatusProducer
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||
import com.tangem.domain.pay.repository.*
|
||||
import com.tangem.domain.pay.usecase.ChangeCardFrozenStateUseCase
|
||||
import com.tangem.domain.pay.usecase.GetPaymentAccountCryptoCurrencyStatusUseCase
|
||||
import com.tangem.domain.pay.usecase.ProduceTangemPayInitialDataUseCase
|
||||
import com.tangem.domain.pay.usecase.SetTangemPayCardLimitUseCase
|
||||
import com.tangem.domain.pay.usecase.StartTangemPayOrderPollingUseCase
|
||||
import com.tangem.domain.pay.usecase.UpdateTangemPayCardNameUseCase
|
||||
import com.tangem.domain.tangempay.GetTangemPayCurrencyStatusUseCase
|
||||
import com.tangem.domain.tangempay.GetTangemPayCustomerIdUseCase
|
||||
|
|
@ -172,5 +174,27 @@ internal interface TangemPayDataModule {
|
|||
): ProduceTangemPayInitialDataUseCase {
|
||||
return ProduceTangemPayInitialDataUseCase(repository = repository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideChangeCardFrozenStateUseCase(
|
||||
cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
startTangemPayOrderPollingUseCase: StartTangemPayOrderPollingUseCase,
|
||||
appCoroutineScope: AppCoroutineScope,
|
||||
): ChangeCardFrozenStateUseCase {
|
||||
return ChangeCardFrozenStateUseCase(
|
||||
cardDetailsRepository = cardDetailsRepository,
|
||||
startTangemPayOrderPollingUseCase = startTangemPayOrderPollingUseCase,
|
||||
appCoroutineScope = appCoroutineScope,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideStartTangemPayPollingUseCase(
|
||||
cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
|
||||
): StartTangemPayOrderPollingUseCase {
|
||||
return StartTangemPayOrderPollingUseCase(cardDetailsRepository, paymentAccountStatusFetcher)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,12 +7,11 @@ import com.tangem.core.error.UniversalError
|
|||
import com.tangem.data.pay.util.OrderStatusConverter
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.api.pay.models.request.ReissueCardRequest
|
||||
import com.tangem.datasource.api.pay.models.response.OrderResponse
|
||||
import com.tangem.datasource.local.visa.TangemPayReissueCardStore
|
||||
import com.tangem.domain.models.pay.TangemPayReissueCardFee
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.TangemPayReissueOrderInfo
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayReissueCardRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.utils.coroutines.runSuspendCatching
|
||||
|
|
@ -22,6 +21,7 @@ internal class DefaultReissueCardRepository @Inject constructor(
|
|||
private val tangemPayApi: TangemPayApi,
|
||||
private val requestHelper: TangemPayRequestPerformer,
|
||||
private val tangemPayReissueCardStore: TangemPayReissueCardStore,
|
||||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
) : TangemPayReissueCardRepository {
|
||||
|
||||
override suspend fun getReissueCardFee(userWalletId: UserWalletId): Either<VisaApiError, TangemPayReissueCardFee> =
|
||||
|
|
@ -53,14 +53,14 @@ internal class DefaultReissueCardRepository @Inject constructor(
|
|||
override suspend fun reissueCard(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
): Either<VisaApiError, TangemPayReissueOrderInfo> = either {
|
||||
): Either<VisaApiError, TangemPayOrderInfo> = either {
|
||||
val response = requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.reissueCard(
|
||||
authHeader = authHeader,
|
||||
body = ReissueCardRequest(cardId = cardId),
|
||||
)
|
||||
}.bind()
|
||||
TangemPayReissueOrderInfo(
|
||||
TangemPayOrderInfo(
|
||||
orderId = response.result.orderId,
|
||||
orderStatus = OrderStatusConverter.convert(response.result.status),
|
||||
)
|
||||
|
|
@ -77,28 +77,14 @@ internal class DefaultReissueCardRepository @Inject constructor(
|
|||
override suspend fun getReissueOrderInfo(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
): Either<UniversalError, TangemPayReissueOrderInfo?> = either {
|
||||
): Either<UniversalError, TangemPayOrderInfo?> = either {
|
||||
val orderId = runSuspendCatching { tangemPayReissueCardStore.getOrderId(cardId) }.getOrNull()
|
||||
|
||||
if (orderId == null) {
|
||||
return null.right()
|
||||
}
|
||||
|
||||
val order = requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.getOrder(authHeader, orderId)
|
||||
}.bind()
|
||||
|
||||
val result = order.result ?: raise(VisaApiError.Unspecified)
|
||||
|
||||
TangemPayReissueOrderInfo(
|
||||
orderId = result.id,
|
||||
orderStatus = when (result.status) {
|
||||
OrderResponse.Result.Status.NEW -> OrderStatus.NEW
|
||||
OrderResponse.Result.Status.PROCESSING -> OrderStatus.PROCESSING
|
||||
OrderResponse.Result.Status.COMPLETED -> OrderStatus.COMPLETED
|
||||
OrderResponse.Result.Status.CANCELED -> OrderStatus.CANCELED
|
||||
},
|
||||
)
|
||||
cardDetailsRepository.getOrderInfo(userWalletId, orderId).bind()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package com.tangem.data.pay.repository
|
|||
import arrow.core.Either
|
||||
import arrow.core.left
|
||||
import arrow.core.raise.catch
|
||||
import arrow.core.raise.either
|
||||
import arrow.core.right
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.data.pay.util.RainCryptoUtil
|
||||
|
|
@ -22,22 +23,17 @@ import com.tangem.datasource.local.visa.TangemPayCardFrozenStateStore
|
|||
import com.tangem.datasource.local.visa.TangemPayStorage
|
||||
import com.tangem.domain.models.account.CardDisplayName
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.SetPinResult
|
||||
import com.tangem.domain.pay.model.TangemPayCardBalance
|
||||
import com.tangem.domain.pay.model.TangemPayCardDetails
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import com.tangem.utils.logging.TangemLogger
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
private const val TAG = "TangemPay: CardDetailsRepository"
|
||||
|
||||
|
|
@ -51,12 +47,8 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
private val storage: TangemPayStorage,
|
||||
private val cardFrozenStateStore: TangemPayCardFrozenStateStore,
|
||||
private val errorConverter: TangemPayErrorConverter,
|
||||
private val pollingScope: AppCoroutineScope,
|
||||
) : TangemPayCardDetailsRepository {
|
||||
|
||||
private val pollingJobs = mutableMapOf<String, Job>()
|
||||
private val storePollingMutex = Mutex()
|
||||
|
||||
override suspend fun getCardBalance(userWalletId: UserWalletId): Either<UniversalError, TangemPayCardBalance> {
|
||||
return catch(
|
||||
block = {
|
||||
|
|
@ -201,123 +193,43 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
override suspend fun freezeCard(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
): Either<UniversalError, TangemPayCardFrozenState> {
|
||||
cardFrozenStateStore.store(cardId, TangemPayCardFrozenState.Pending)
|
||||
return requestHelper.performRequest(userWalletId) {
|
||||
): Either<UniversalError, TangemPayOrderInfo> = either {
|
||||
val response = requestHelper.performRequest(userWalletId) {
|
||||
tangemPayApi.freezeCard(authHeader = it, body = FreezeUnfreezeCardRequest(cardId = cardId))
|
||||
}.onLeft {
|
||||
cardFrozenStateStore.store(cardId, TangemPayCardFrozenState.Unfrozen)
|
||||
}.map { response ->
|
||||
val state = when (response.result?.status) {
|
||||
FreezeUnfreezeCardResponse.Status.COMPLETED -> TangemPayCardFrozenState.Frozen
|
||||
FreezeUnfreezeCardResponse.Status.NEW,
|
||||
FreezeUnfreezeCardResponse.Status.PROCESSING,
|
||||
-> TangemPayCardFrozenState.Pending
|
||||
FreezeUnfreezeCardResponse.Status.CANCELED,
|
||||
null,
|
||||
-> TangemPayCardFrozenState.Unfrozen
|
||||
}
|
||||
if (state == TangemPayCardFrozenState.Pending) {
|
||||
startOrderIdPolling(
|
||||
userWalletId = userWalletId,
|
||||
cardId = cardId,
|
||||
orderId = response.result?.orderId,
|
||||
isFreeze = true,
|
||||
)
|
||||
}
|
||||
cardFrozenStateStore.store(cardId, state)
|
||||
}.bind()
|
||||
|
||||
state
|
||||
}
|
||||
val result = response.result ?: raise(VisaApiError.Unspecified)
|
||||
|
||||
TangemPayOrderInfo(
|
||||
orderId = result.orderId,
|
||||
orderStatus = when (result.status) {
|
||||
FreezeUnfreezeCardResponse.Status.NEW -> OrderStatus.NEW
|
||||
FreezeUnfreezeCardResponse.Status.PROCESSING -> OrderStatus.PROCESSING
|
||||
FreezeUnfreezeCardResponse.Status.COMPLETED -> OrderStatus.COMPLETED
|
||||
FreezeUnfreezeCardResponse.Status.CANCELED -> OrderStatus.CANCELED
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun unfreezeCard(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
): Either<UniversalError, TangemPayCardFrozenState> {
|
||||
cardFrozenStateStore.store(cardId, TangemPayCardFrozenState.Pending)
|
||||
return requestHelper.performRequest(userWalletId) {
|
||||
): Either<UniversalError, TangemPayOrderInfo> = either {
|
||||
val response = requestHelper.performRequest(userWalletId) {
|
||||
tangemPayApi.unfreezeCard(authHeader = it, body = FreezeUnfreezeCardRequest(cardId = cardId))
|
||||
}.onLeft {
|
||||
cardFrozenStateStore.store(cardId, TangemPayCardFrozenState.Frozen)
|
||||
}.map { response ->
|
||||
val state = when (response.result?.status) {
|
||||
FreezeUnfreezeCardResponse.Status.COMPLETED -> TangemPayCardFrozenState.Unfrozen
|
||||
FreezeUnfreezeCardResponse.Status.NEW,
|
||||
FreezeUnfreezeCardResponse.Status.PROCESSING,
|
||||
-> TangemPayCardFrozenState.Pending
|
||||
FreezeUnfreezeCardResponse.Status.CANCELED,
|
||||
null,
|
||||
-> TangemPayCardFrozenState.Frozen
|
||||
}
|
||||
if (state == TangemPayCardFrozenState.Pending) {
|
||||
startOrderIdPolling(
|
||||
userWalletId = userWalletId,
|
||||
cardId = cardId,
|
||||
orderId = response.result?.orderId,
|
||||
isFreeze = false,
|
||||
)
|
||||
}
|
||||
cardFrozenStateStore.store(cardId, state)
|
||||
}.bind()
|
||||
|
||||
state
|
||||
}
|
||||
}
|
||||
val result = response.result ?: raise(VisaApiError.Unspecified)
|
||||
|
||||
private suspend fun startOrderIdPolling(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
orderId: String?,
|
||||
isFreeze: Boolean,
|
||||
) {
|
||||
if (orderId.isNullOrEmpty()) return
|
||||
storePollingMutex.withLock {
|
||||
if (pollingJobs.containsKey(orderId)) return
|
||||
val pollingJob = pollingScope.launch {
|
||||
try {
|
||||
var retryCount = 0
|
||||
while (isActive && pollingJobs.containsKey(orderId)) {
|
||||
delay(duration = 5.seconds)
|
||||
|
||||
val orderStatus = requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.getOrder(authHeader, orderId)
|
||||
}
|
||||
|
||||
orderStatus.onRight { response ->
|
||||
val status = response.result?.status
|
||||
if (status == Status.COMPLETED || status == Status.CANCELED) {
|
||||
// Remove from jobs
|
||||
pollingJobs.remove(key = orderId)
|
||||
|
||||
// Final card state
|
||||
val finalState = when {
|
||||
status == Status.COMPLETED && isFreeze
|
||||
-> TangemPayCardFrozenState.Frozen
|
||||
status == Status.COMPLETED && !isFreeze
|
||||
-> TangemPayCardFrozenState.Unfrozen
|
||||
else -> return@launch
|
||||
}
|
||||
|
||||
cardFrozenStateStore.store(cardId, finalState)
|
||||
}
|
||||
}.onLeft { error ->
|
||||
TangemLogger.e("error ${error.errorCode}")
|
||||
// stop retrying after 3 errors
|
||||
if (retryCount > MAX_POLLING_RETRIES) {
|
||||
pollingJobs.remove(key = orderId)
|
||||
}
|
||||
}
|
||||
retryCount++
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
TangemLogger.e("Error", e)
|
||||
storePollingMutex.withLock {
|
||||
pollingJobs.remove(orderId)
|
||||
}
|
||||
}
|
||||
}
|
||||
pollingJobs[orderId] = pollingJob
|
||||
}
|
||||
TangemPayOrderInfo(
|
||||
orderId = result.orderId,
|
||||
orderStatus = when (result.status) {
|
||||
FreezeUnfreezeCardResponse.Status.NEW -> OrderStatus.NEW
|
||||
FreezeUnfreezeCardResponse.Status.PROCESSING -> OrderStatus.PROCESSING
|
||||
FreezeUnfreezeCardResponse.Status.COMPLETED -> OrderStatus.COMPLETED
|
||||
FreezeUnfreezeCardResponse.Status.CANCELED -> OrderStatus.CANCELED
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun updateCardDisplayName(
|
||||
|
|
@ -376,6 +288,31 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
return cardFrozenStateStore.getSyncOrNull(cardId)
|
||||
}
|
||||
|
||||
override suspend fun setCardFrozenState(cardId: String, state: TangemPayCardFrozenState) {
|
||||
cardFrozenStateStore.store(cardId, state)
|
||||
}
|
||||
|
||||
override suspend fun getOrderInfo(
|
||||
userWalletId: UserWalletId,
|
||||
orderId: String,
|
||||
): Either<UniversalError, TangemPayOrderInfo> = either {
|
||||
val order = requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.getOrder(authHeader, orderId)
|
||||
}.bind()
|
||||
|
||||
val result = order.result ?: raise(VisaApiError.Unspecified)
|
||||
|
||||
TangemPayOrderInfo(
|
||||
orderId = result.id,
|
||||
orderStatus = when (result.status) {
|
||||
Status.NEW -> OrderStatus.NEW
|
||||
Status.PROCESSING -> OrderStatus.PROCESSING
|
||||
Status.COMPLETED -> OrderStatus.COMPLETED
|
||||
Status.CANCELED -> OrderStatus.CANCELED
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
private suspend fun getPublicKeyBase64(): String {
|
||||
val env = apiConfigsManager.getEnvironmentConfig(ApiConfig.ID.TangemPay).environment
|
||||
return when (env) {
|
||||
|
|
@ -395,8 +332,4 @@ internal class DefaultTangemPayCardDetailsRepository @Inject constructor(
|
|||
TangemLogger.withTag(TAG).e("Error", throwable)
|
||||
return errorConverter.convert(throwable).left()
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val MAX_POLLING_RETRIES = 3
|
||||
}
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.pay.model.SetPinResult
|
||||
import com.tangem.domain.pay.model.TangemPayCardBalance
|
||||
import com.tangem.domain.pay.model.TangemPayCardDetails
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
|
@ -65,12 +66,12 @@ internal class MockAwareTangemPayCardDetailsRepository @Inject constructor(
|
|||
override suspend fun freezeCard(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
): Either<UniversalError, TangemPayCardFrozenState> = real.freezeCard(userWalletId, cardId)
|
||||
): Either<UniversalError, TangemPayOrderInfo> = real.freezeCard(userWalletId, cardId)
|
||||
|
||||
override suspend fun unfreezeCard(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
): Either<UniversalError, TangemPayCardFrozenState> = real.unfreezeCard(userWalletId, cardId)
|
||||
): Either<UniversalError, TangemPayOrderInfo> = real.unfreezeCard(userWalletId, cardId)
|
||||
|
||||
override fun cardFrozenState(cardId: String): Flow<TangemPayCardFrozenState> =
|
||||
real.cardFrozenState(cardId)
|
||||
|
|
@ -78,6 +79,14 @@ internal class MockAwareTangemPayCardDetailsRepository @Inject constructor(
|
|||
override suspend fun cardFrozenStateSync(cardId: String): TangemPayCardFrozenState? =
|
||||
real.cardFrozenStateSync(cardId)
|
||||
|
||||
override suspend fun setCardFrozenState(cardId: String, state: TangemPayCardFrozenState) =
|
||||
real.setCardFrozenState(cardId, state)
|
||||
|
||||
override suspend fun getOrderInfo(
|
||||
userWalletId: UserWalletId,
|
||||
orderId: String,
|
||||
): Either<UniversalError, TangemPayOrderInfo> = real.getOrderInfo(userWalletId, orderId)
|
||||
|
||||
override suspend fun updateCardDisplayName(
|
||||
cardId: String,
|
||||
userWalletId: UserWalletId,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,10 @@ android {
|
|||
namespace = "com.tangem.domain.visa"
|
||||
}
|
||||
|
||||
tasks.withType<Test>().configureEach {
|
||||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
/** Project - Core */
|
||||
api(projects.core.pagination)
|
||||
|
|
@ -34,4 +38,12 @@ dependencies {
|
|||
implementation(deps.moshi)
|
||||
implementation(deps.moshi.kotlin)
|
||||
ksp(deps.moshi.kotlin.codegen)
|
||||
|
||||
/** Tests */
|
||||
testImplementation(deps.test.junit5)
|
||||
testRuntimeOnly(deps.test.junit5.engine)
|
||||
testImplementation(deps.test.mockk)
|
||||
testImplementation(deps.test.coroutine)
|
||||
testImplementation(deps.test.truth)
|
||||
testImplementation(projects.common.test)
|
||||
}
|
||||
|
|
@ -5,4 +5,7 @@ enum class OrderStatus {
|
|||
PROCESSING,
|
||||
COMPLETED,
|
||||
CANCELED,
|
||||
}
|
||||
}
|
||||
|
||||
val OrderStatus.isFinalStatus
|
||||
get() = this == OrderStatus.COMPLETED || this == OrderStatus.CANCELED
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package com.tangem.domain.pay.model
|
||||
|
||||
data class TangemPayReissueOrderInfo(
|
||||
data class TangemPayOrderInfo(
|
||||
val orderId: String,
|
||||
val orderStatus: OrderStatus,
|
||||
)
|
||||
|
|
@ -7,6 +7,7 @@ import com.tangem.domain.models.wallet.UserWalletId
|
|||
import com.tangem.domain.pay.model.SetPinResult
|
||||
import com.tangem.domain.pay.model.TangemPayCardBalance
|
||||
import com.tangem.domain.pay.model.TangemPayCardDetails
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
|
|
@ -24,14 +25,12 @@ interface TangemPayCardDetailsRepository {
|
|||
|
||||
suspend fun setAddToWalletAsDone(userWalletId: UserWalletId): Either<UniversalError, Unit>
|
||||
|
||||
suspend fun freezeCard(userWalletId: UserWalletId, cardId: String): Either<UniversalError, TangemPayCardFrozenState>
|
||||
suspend fun unfreezeCard(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
): Either<UniversalError, TangemPayCardFrozenState>
|
||||
suspend fun freezeCard(userWalletId: UserWalletId, cardId: String): Either<UniversalError, TangemPayOrderInfo>
|
||||
suspend fun unfreezeCard(userWalletId: UserWalletId, cardId: String): Either<UniversalError, TangemPayOrderInfo>
|
||||
|
||||
fun cardFrozenState(cardId: String): Flow<TangemPayCardFrozenState>
|
||||
suspend fun cardFrozenStateSync(cardId: String): TangemPayCardFrozenState?
|
||||
suspend fun setCardFrozenState(cardId: String, state: TangemPayCardFrozenState)
|
||||
|
||||
suspend fun updateCardDisplayName(
|
||||
cardId: String,
|
||||
|
|
@ -44,4 +43,6 @@ interface TangemPayCardDetailsRepository {
|
|||
userWalletId: UserWalletId,
|
||||
limit: String,
|
||||
): Either<UniversalError, Unit>
|
||||
|
||||
suspend fun getOrderInfo(userWalletId: UserWalletId, orderId: String): Either<UniversalError, TangemPayOrderInfo>
|
||||
}
|
||||
|
|
@ -4,19 +4,19 @@ import arrow.core.Either
|
|||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.models.pay.TangemPayReissueCardFee
|
||||
import com.tangem.domain.pay.model.TangemPayReissueOrderInfo
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
|
||||
interface TangemPayReissueCardRepository {
|
||||
|
||||
suspend fun getReissueCardFee(userWalletId: UserWalletId): Either<VisaApiError, TangemPayReissueCardFee>
|
||||
|
||||
suspend fun reissueCard(userWalletId: UserWalletId, cardId: String): Either<VisaApiError, TangemPayReissueOrderInfo>
|
||||
suspend fun reissueCard(userWalletId: UserWalletId, cardId: String): Either<VisaApiError, TangemPayOrderInfo>
|
||||
|
||||
suspend fun storeReissueOrderId(cardId: String, orderId: String): Either<UniversalError, Unit>
|
||||
|
||||
suspend fun getReissueOrderInfo(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
): Either<UniversalError, TangemPayReissueOrderInfo?>
|
||||
): Either<UniversalError, TangemPayOrderInfo?>
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.tangem.domain.pay.usecase
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.raise.either
|
||||
import com.tangem.core.error.UniversalError
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||
import kotlinx.coroutines.async
|
||||
|
||||
class ChangeCardFrozenStateUseCase(
|
||||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
private val startTangemPayOrderPollingUseCase: StartTangemPayOrderPollingUseCase,
|
||||
private val appCoroutineScope: AppCoroutineScope,
|
||||
) {
|
||||
suspend operator fun invoke(
|
||||
userWalletId: UserWalletId,
|
||||
cardId: String,
|
||||
isFreezing: Boolean,
|
||||
): Either<UniversalError, Unit> {
|
||||
val successState = if (isFreezing) TangemPayCardFrozenState.Frozen else TangemPayCardFrozenState.Unfrozen
|
||||
val failState = if (isFreezing) TangemPayCardFrozenState.Unfrozen else TangemPayCardFrozenState.Frozen
|
||||
return either {
|
||||
cardDetailsRepository.setCardFrozenState(cardId, TangemPayCardFrozenState.Pending)
|
||||
|
||||
val order = if (isFreezing) {
|
||||
cardDetailsRepository.freezeCard(userWalletId, cardId).bind()
|
||||
} else {
|
||||
cardDetailsRepository.unfreezeCard(userWalletId, cardId).bind()
|
||||
}
|
||||
|
||||
val isCompleted = appCoroutineScope.async {
|
||||
val isCompleted = startTangemPayOrderPollingUseCase(order, userWalletId)
|
||||
cardDetailsRepository.setCardFrozenState(cardId, if (isCompleted) successState else failState)
|
||||
isCompleted
|
||||
}.await()
|
||||
|
||||
if (!isCompleted) raise(VisaApiError.Unspecified)
|
||||
}.onLeft {
|
||||
cardDetailsRepository.setCardFrozenState(cardId, failState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.tangem.domain.pay.usecase
|
||||
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.pay.model.isFinalStatus
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
class StartTangemPayOrderPollingUseCase(
|
||||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
|
||||
) {
|
||||
suspend operator fun invoke(order: TangemPayOrderInfo, userWalletId: UserWalletId): Boolean {
|
||||
while (true) {
|
||||
val newOrder = if (order.orderStatus.isFinalStatus) {
|
||||
order
|
||||
} else {
|
||||
cardDetailsRepository.getOrderInfo(userWalletId, order.orderId).getOrNull()
|
||||
}
|
||||
|
||||
if (newOrder != null && newOrder.orderStatus.isFinalStatus) {
|
||||
paymentAccountStatusFetcher.invoke(userWalletId)
|
||||
return newOrder.orderStatus == OrderStatus.COMPLETED
|
||||
}
|
||||
|
||||
delay(POLLING_DELAY)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val POLLING_DELAY = 3000L
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package com.tangem.domain.pay.usecase
|
||||
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.common.test.TestAppCoroutineScope
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.coVerifyOrder
|
||||
import io.mockk.mockk
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class ChangeCardFrozenStateUseCaseTest {
|
||||
|
||||
private val cardDetailsRepository: TangemPayCardDetailsRepository = mockk(relaxUnitFun = true)
|
||||
private val startPollingUseCase: StartTangemPayOrderPollingUseCase = mockk()
|
||||
|
||||
@Test
|
||||
fun `GIVEN freezeCard fails WHEN invoke with isFreezing=true THEN sets Pending then Unfrozen and returns Left`() =
|
||||
runTest {
|
||||
val useCase = createUseCase()
|
||||
coEvery {
|
||||
cardDetailsRepository.freezeCard(USER_WALLET_ID, CARD_ID)
|
||||
} returns VisaApiError.Unspecified.left()
|
||||
|
||||
val result = useCase(USER_WALLET_ID, CARD_ID, isFreezing = true)
|
||||
|
||||
assertThat(result.isLeft()).isTrue()
|
||||
coVerifyOrder {
|
||||
cardDetailsRepository.setCardFrozenState(CARD_ID, TangemPayCardFrozenState.Pending)
|
||||
cardDetailsRepository.setCardFrozenState(CARD_ID, TangemPayCardFrozenState.Unfrozen)
|
||||
}
|
||||
coVerify(exactly = 0) { startPollingUseCase(any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN unfreezeCard fails WHEN invoke with isFreezing=false THEN sets Pending then Frozen and returns Left`() =
|
||||
runTest {
|
||||
val useCase = createUseCase()
|
||||
coEvery {
|
||||
cardDetailsRepository.unfreezeCard(USER_WALLET_ID, CARD_ID)
|
||||
} returns VisaApiError.Unspecified.left()
|
||||
|
||||
val result = useCase(USER_WALLET_ID, CARD_ID, isFreezing = false)
|
||||
|
||||
assertThat(result.isLeft()).isTrue()
|
||||
coVerifyOrder {
|
||||
cardDetailsRepository.setCardFrozenState(CARD_ID, TangemPayCardFrozenState.Pending)
|
||||
cardDetailsRepository.setCardFrozenState(CARD_ID, TangemPayCardFrozenState.Frozen)
|
||||
}
|
||||
coVerify(exactly = 0) { startPollingUseCase(any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN freeze succeeds and order COMPLETED WHEN invoke with isFreezing=true THEN sets Frozen and returns Right`() =
|
||||
runTest {
|
||||
val useCase = createUseCase()
|
||||
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.COMPLETED)
|
||||
coEvery { cardDetailsRepository.freezeCard(USER_WALLET_ID, CARD_ID) } returns order.right()
|
||||
coEvery { startPollingUseCase(order, USER_WALLET_ID) } returns true
|
||||
|
||||
val result = useCase(USER_WALLET_ID, CARD_ID, isFreezing = true)
|
||||
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerifyOrder {
|
||||
cardDetailsRepository.setCardFrozenState(CARD_ID, TangemPayCardFrozenState.Pending)
|
||||
cardDetailsRepository.setCardFrozenState(CARD_ID, TangemPayCardFrozenState.Frozen)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN unfreeze succeeds and order COMPLETED WHEN invoke with isFreezing=false THEN sets Unfrozen and returns Right`() =
|
||||
runTest {
|
||||
val useCase = createUseCase()
|
||||
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.COMPLETED)
|
||||
coEvery { cardDetailsRepository.unfreezeCard(USER_WALLET_ID, CARD_ID) } returns order.right()
|
||||
coEvery { startPollingUseCase(order, USER_WALLET_ID) } returns true
|
||||
|
||||
val result = useCase(USER_WALLET_ID, CARD_ID, isFreezing = false)
|
||||
|
||||
assertThat(result.isRight()).isTrue()
|
||||
coVerifyOrder {
|
||||
cardDetailsRepository.setCardFrozenState(CARD_ID, TangemPayCardFrozenState.Pending)
|
||||
cardDetailsRepository.setCardFrozenState(CARD_ID, TangemPayCardFrozenState.Unfrozen)
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestScope.createUseCase() = ChangeCardFrozenStateUseCase(
|
||||
cardDetailsRepository = cardDetailsRepository,
|
||||
startTangemPayOrderPollingUseCase = startPollingUseCase,
|
||||
appCoroutineScope = TestAppCoroutineScope(this),
|
||||
)
|
||||
|
||||
private companion object {
|
||||
val USER_WALLET_ID = UserWalletId("aabbcc112233")
|
||||
const val CARD_ID = "card-test-id"
|
||||
const val ORDER_ID = "order-test-1"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
package com.tangem.domain.pay.usecase
|
||||
|
||||
import arrow.core.left
|
||||
import arrow.core.right
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import io.mockk.*
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
internal class StartTangemPayOrderPollingUseCaseTest {
|
||||
|
||||
private val cardDetailsRepository: TangemPayCardDetailsRepository = mockk()
|
||||
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher = mockk()
|
||||
|
||||
private val useCase = StartTangemPayOrderPollingUseCase(
|
||||
cardDetailsRepository = cardDetailsRepository,
|
||||
paymentAccountStatusFetcher = paymentAccountStatusFetcher,
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `GIVEN order already COMPLETED WHEN invoke THEN returns true without polling`() = runTest {
|
||||
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.COMPLETED)
|
||||
coEvery { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) } returns Unit.right()
|
||||
|
||||
val result = useCase(order, USER_WALLET_ID)
|
||||
|
||||
assertThat(result).isTrue()
|
||||
coVerify(exactly = 1) { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) }
|
||||
coVerify(exactly = 0) { cardDetailsRepository.getOrderInfo(any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN order already CANCELED WHEN invoke THEN returns false without polling`() = runTest {
|
||||
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.CANCELED)
|
||||
coEvery { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) } returns Unit.right()
|
||||
|
||||
val result = useCase(order, USER_WALLET_ID)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
coVerify(exactly = 1) { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) }
|
||||
coVerify(exactly = 0) { cardDetailsRepository.getOrderInfo(any(), any()) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN processing order WHEN poll returns COMPLETED THEN returns true and fetches status`() = runTest {
|
||||
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.PROCESSING)
|
||||
coEvery {
|
||||
cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID)
|
||||
} returns TangemPayOrderInfo(ORDER_ID, OrderStatus.COMPLETED).right()
|
||||
coEvery { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) } returns Unit.right()
|
||||
|
||||
val result = useCase(order, USER_WALLET_ID)
|
||||
|
||||
assertThat(result).isTrue()
|
||||
coVerify(exactly = 1) { cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID) }
|
||||
coVerify(exactly = 1) { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN processing order WHEN poll returns CANCELED THEN returns false and fetches status`() = runTest {
|
||||
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.PROCESSING)
|
||||
coEvery {
|
||||
cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID)
|
||||
} returns TangemPayOrderInfo(ORDER_ID, OrderStatus.CANCELED).right()
|
||||
coEvery { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) } returns Unit.right()
|
||||
|
||||
val result = useCase(order, USER_WALLET_ID)
|
||||
|
||||
assertThat(result).isFalse()
|
||||
coVerify(exactly = 1) { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN new order WHEN getOrderInfo fails once then returns COMPLETED THEN returns true after two polls`() = runTest {
|
||||
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.NEW)
|
||||
coEvery {
|
||||
cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID)
|
||||
} returnsMany listOf(
|
||||
VisaApiError.Unspecified.left(),
|
||||
TangemPayOrderInfo(ORDER_ID, OrderStatus.COMPLETED).right(),
|
||||
)
|
||||
coEvery { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) } returns Unit.right()
|
||||
|
||||
val result = useCase(order, USER_WALLET_ID)
|
||||
|
||||
assertThat(result).isTrue()
|
||||
coVerify(exactly = 2) { cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `GIVEN processing order WHEN multiple non-final polls then COMPLETED THEN returns true after all polls`() = runTest {
|
||||
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.PROCESSING)
|
||||
coEvery {
|
||||
cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID)
|
||||
} returnsMany listOf(
|
||||
TangemPayOrderInfo(ORDER_ID, OrderStatus.PROCESSING).right(),
|
||||
TangemPayOrderInfo(ORDER_ID, OrderStatus.NEW).right(),
|
||||
TangemPayOrderInfo(ORDER_ID, OrderStatus.COMPLETED).right(),
|
||||
)
|
||||
coEvery { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) } returns Unit.right()
|
||||
|
||||
val result = useCase(order, USER_WALLET_ID)
|
||||
|
||||
assertThat(result).isTrue()
|
||||
coVerify(exactly = 3) { cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID) }
|
||||
coVerify(exactly = 1) { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) }
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val USER_WALLET_ID = UserWalletId("aabbcc112233")
|
||||
const val ORDER_ID = "order-test-1"
|
||||
}
|
||||
}
|
||||
|
|
@ -7,7 +7,7 @@ import com.tangem.core.decompose.context.AppComponentContext
|
|||
import com.tangem.core.decompose.model.getOrCreateModel
|
||||
import com.tangem.core.ui.decompose.ComposableBottomSheetComponent
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.TangemPayReissueOrderInfo
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.features.tangempay.model.TangemPayReissueCardModel
|
||||
import com.tangem.features.tangempay.ui.TangemPayReissueCardContent
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ internal class TangemPayReissueCardComponent(
|
|||
}
|
||||
|
||||
internal interface ReissueCardListener {
|
||||
fun onReissueOrderCreate(order: TangemPayReissueOrderInfo)
|
||||
fun onReissueOrderCreate(order: TangemPayOrderInfo)
|
||||
fun onDismissReissueCard()
|
||||
fun onClickAddFunds()
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import com.tangem.core.ui.format.bigdecimal.format
|
|||
import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode
|
||||
import com.tangem.core.ui.format.bigdecimal.optionalDecimals
|
||||
import com.tangem.core.ui.message.SnackbarMessage
|
||||
import com.tangem.core.ui.test.TangemPayTestTags
|
||||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.TokenReceiveConfig
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
|
|
@ -28,12 +29,12 @@ import com.tangem.domain.models.pay.TangemPayCard
|
|||
import com.tangem.domain.models.pay.TangemPayCardLimitPeriod
|
||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.TangemPayReissueOrderInfo
|
||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||
import com.tangem.domain.pay.model.TangemPayTopUpData
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayReissueCardRepository
|
||||
import com.tangem.domain.pay.usecase.ChangeCardFrozenStateUseCase
|
||||
import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
||||
import com.tangem.domain.visa.model.TangemPayCardFrozenState
|
||||
import com.tangem.features.tangempay.components.AddFundsListener
|
||||
import com.tangem.features.tangempay.components.ReissueCardListener
|
||||
import com.tangem.features.tangempay.components.TangemPayCardPageComponent
|
||||
|
|
@ -63,12 +64,14 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
private val uiMessageSender: UiMessageSender,
|
||||
private val reissueCardRepository: TangemPayReissueCardRepository,
|
||||
private val changeCardFrozenStateUseCase: ChangeCardFrozenStateUseCase,
|
||||
) : Model(), ViewPinListener, ReissueCardListener, AddFundsListener {
|
||||
|
||||
private val params: TangemPayCardPageComponent.Params = paramsContainer.require()
|
||||
|
||||
private val addToWalletBannerJobHolder = JobHolder()
|
||||
private val addFundsJobHolder = JobHolder()
|
||||
private val frozenStateJobHolder = JobHolder()
|
||||
|
||||
val uiState: StateFlow<TangemPayCardPageUM>
|
||||
field = MutableStateFlow(
|
||||
|
|
@ -119,12 +122,18 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
TangemPayCardPageSetting(
|
||||
title = TextReference.Res(R.string.tangempay_card_details_change_pin),
|
||||
onSettingClick = { onClickChangePIN(card.hasPinCode) },
|
||||
testTag = com.tangem.core.ui.test.TangemPayTestTags.CHANGE_PIN_ROW,
|
||||
testTag = TangemPayTestTags.CHANGE_PIN_ROW,
|
||||
),
|
||||
TangemPayCardPageSetting(
|
||||
title = TextReference.Res(R.string.tangempay_card_details_freeze_card),
|
||||
title = TextReference.Res(
|
||||
if (card.isFrozen) {
|
||||
R.string.tangempay_card_details_unfreeze_card
|
||||
} else {
|
||||
R.string.tangempay_card_details_freeze_card
|
||||
},
|
||||
),
|
||||
onSettingClick = { onClickFreezeOrUnfreezeCard(card.isFrozen) },
|
||||
testTag = com.tangem.core.ui.test.TangemPayTestTags.FREEZE_CARD_ROW,
|
||||
testTag = TangemPayTestTags.FREEZE_CARD_ROW,
|
||||
),
|
||||
TangemPayCardPageSetting(
|
||||
title = TextReference.Res(R.string.tangempay_card_details_reissue_card),
|
||||
|
|
@ -152,6 +161,8 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onClickFreezeOrUnfreezeCard(isFrozen: Boolean) {
|
||||
if (frozenStateJobHolder.isActive) return
|
||||
|
||||
val message = if (isFrozen) {
|
||||
TangemPayMessagesFactory.createUnfreezeCardMessage(onUnfreezeClicked = ::unfreezeCard)
|
||||
} else {
|
||||
|
|
@ -165,7 +176,7 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
bottomSheetNavigation.activate(TangemPayCardNavigation.ReissueCard)
|
||||
}
|
||||
|
||||
override fun onReissueOrderCreate(order: TangemPayReissueOrderInfo) {
|
||||
override fun onReissueOrderCreate(order: TangemPayOrderInfo) {
|
||||
bottomSheetNavigation.dismiss()
|
||||
onReissueOrderStatusReceived(order.orderStatus)
|
||||
if (order.orderStatus != OrderStatus.CANCELED) {
|
||||
|
|
@ -238,40 +249,34 @@ internal class TangemPayCardPageModel @Inject constructor(
|
|||
|
||||
private fun freezeCard() {
|
||||
modelScope.launch {
|
||||
cardDetailsRepository.freezeCard(
|
||||
changeCardFrozenStateUseCase(
|
||||
userWalletId = params.userWalletId,
|
||||
cardId = params.config.cardId,
|
||||
isFreezing = true,
|
||||
).onLeft {
|
||||
val message = SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_failed))
|
||||
uiMessageSender.send(message)
|
||||
}.onRight { state ->
|
||||
val message = if (state == TangemPayCardFrozenState.Frozen) {
|
||||
SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_success))
|
||||
} else {
|
||||
SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_failed))
|
||||
}
|
||||
}.onRight {
|
||||
val message = SnackbarMessage(resourceReference(R.string.tangem_pay_freeze_card_success))
|
||||
uiMessageSender.send(message)
|
||||
}
|
||||
}
|
||||
}.saveIn(frozenStateJobHolder)
|
||||
}
|
||||
|
||||
private fun unfreezeCard() {
|
||||
modelScope.launch {
|
||||
cardDetailsRepository.unfreezeCard(
|
||||
changeCardFrozenStateUseCase(
|
||||
userWalletId = params.userWalletId,
|
||||
cardId = params.config.cardId,
|
||||
isFreezing = false,
|
||||
).onLeft {
|
||||
val message = SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_failed))
|
||||
uiMessageSender.send(message)
|
||||
}.onRight { state ->
|
||||
val message = if (state == TangemPayCardFrozenState.Unfrozen) {
|
||||
SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_success))
|
||||
} else {
|
||||
SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_failed))
|
||||
}
|
||||
}.onRight {
|
||||
val message = SnackbarMessage(resourceReference(R.string.tangem_pay_unfreeze_card_success))
|
||||
uiMessageSender.send(message)
|
||||
}
|
||||
}
|
||||
}.saveIn(frozenStateJobHolder)
|
||||
}
|
||||
|
||||
private fun fetchAddToWalletBanner() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue