Updated on 2026-08-14
This commit is contained in:
parent
0ab5d41ba0
commit
ccb9aa9110
9 changed files with 272 additions and 119 deletions
|
|
@ -255,10 +255,18 @@ internal interface TangemPayDataModule {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
fun provideRestoreActiveOrdersUseCase(
|
fun provideRestoreActiveIssueOrdersUseCase(
|
||||||
customerOrderRepository: CustomerOrderRepository,
|
customerOrderRepository: CustomerOrderRepository,
|
||||||
): RestoreActiveOrdersUseCase {
|
issueCardRepository: TangemPayIssueCardRepository,
|
||||||
return RestoreActiveOrdersUseCase(customerOrderRepository)
|
startTangemPayOrderPollingUseCase: StartTangemPayOrderPollingUseCase,
|
||||||
|
appCoroutineScope: AppCoroutineScope,
|
||||||
|
): RestoreActiveIssueOrdersUseCase {
|
||||||
|
return RestoreActiveIssueOrdersUseCase(
|
||||||
|
customerOrderRepository = customerOrderRepository,
|
||||||
|
issueCardRepository = issueCardRepository,
|
||||||
|
startTangemPayOrderPollingUseCase = startTangemPayOrderPollingUseCase,
|
||||||
|
appCoroutineScope = appCoroutineScope,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.tangem.domain.pay.usecase
|
||||||
|
|
||||||
|
import arrow.core.Either
|
||||||
|
import arrow.core.raise.Raise
|
||||||
|
import arrow.core.raise.catch
|
||||||
|
import arrow.core.raise.either
|
||||||
|
import com.tangem.domain.models.wallet.UserWalletId
|
||||||
|
import com.tangem.domain.pay.model.OrderStatus
|
||||||
|
import com.tangem.domain.pay.model.OrderType
|
||||||
|
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||||
|
import com.tangem.domain.pay.repository.CustomerOrderRepository
|
||||||
|
import com.tangem.domain.pay.repository.TangemPayIssueCardRepository
|
||||||
|
import com.tangem.domain.visa.error.VisaApiError
|
||||||
|
import com.tangem.utils.coroutines.AppCoroutineScope
|
||||||
|
import com.tangem.utils.logging.TangemLogger
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores in-flight card-issuance orders on app launch / when returning to the wallet screen.
|
||||||
|
*
|
||||||
|
* `findOrders` is the source of truth — a locally stored order id is only a hint that does not
|
||||||
|
|
||||||
|
* survive a force close. This use case re-discovers the active issue orders, persists their ids so
|
||||||
|
* the payment-account state renders an "issuing" placeholder card, and (re)starts polling so the
|
||||||
|
* placeholder is driven to its terminal state.
|
||||||
|
*
|
||||||
|
* Non-fatal exceptions are logged and collapsed to [VisaApiError.Unspecified]; the caller treats the
|
||||||
|
* result as fire-and-forget.
|
||||||
|
*
|
||||||
|
* @property customerOrderRepository source of truth for active orders.
|
||||||
|
* @property issueCardRepository persists issue-order ids for placeholder rendering.
|
||||||
|
* @property startTangemPayOrderPollingUseCase drives a restored order to its terminal state.
|
||||||
|
*/
|
||||||
|
class RestoreActiveIssueOrdersUseCase(
|
||||||
|
private val customerOrderRepository: CustomerOrderRepository,
|
||||||
|
private val issueCardRepository: TangemPayIssueCardRepository,
|
||||||
|
private val startTangemPayOrderPollingUseCase: StartTangemPayOrderPollingUseCase,
|
||||||
|
private val appCoroutineScope: AppCoroutineScope,
|
||||||
|
) {
|
||||||
|
suspend operator fun invoke(userWalletId: UserWalletId): Either<VisaApiError, Unit> = either {
|
||||||
|
val orders = catch(
|
||||||
|
block = {
|
||||||
|
customerOrderRepository.findOrders(
|
||||||
|
userWalletId = userWalletId,
|
||||||
|
types = OrderType.issueCardTypes,
|
||||||
|
statuses = OrderStatus.activeStatuses,
|
||||||
|
).bind()
|
||||||
|
},
|
||||||
|
catch = { handleError(it) },
|
||||||
|
).filter { it.status.isActive }
|
||||||
|
|
||||||
|
orders.forEach { order ->
|
||||||
|
issueCardRepository.storeIssueOrderId(userWalletId = userWalletId, orderId = order.id)
|
||||||
|
|
||||||
|
appCoroutineScope.launch {
|
||||||
|
startTangemPayOrderPollingUseCase(
|
||||||
|
order = TangemPayOrderInfo(orderId = order.id, orderStatus = order.status),
|
||||||
|
userWalletId = userWalletId,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Raise<VisaApiError>.handleError(throwable: Throwable): Nothing {
|
||||||
|
TangemLogger.e("Error in RestoreActiveIssueOrdersUseCase", throwable)
|
||||||
|
raise(VisaApiError.Unspecified)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package com.tangem.domain.pay.usecase
|
|
||||||
|
|
||||||
import arrow.core.Either
|
|
||||||
import com.tangem.domain.models.wallet.UserWalletId
|
|
||||||
import com.tangem.domain.pay.model.Order
|
|
||||||
import com.tangem.domain.pay.model.OrderStatus
|
|
||||||
import com.tangem.domain.pay.repository.CustomerOrderRepository
|
|
||||||
import com.tangem.domain.visa.error.VisaApiError
|
|
||||||
|
|
||||||
/**
|
|
||||||
|
|
||||||
* same customer.
|
|
||||||
*
|
|
||||||
* Wraps `findOrders` (the source of truth) and filters to the active set (NEW / PROCESSING).
|
|
||||||
* The caller decides how to dispatch each order to the appropriate flow.
|
|
||||||
*/
|
|
||||||
class RestoreActiveOrdersUseCase(
|
|
||||||
private val customerOrderRepository: CustomerOrderRepository,
|
|
||||||
) {
|
|
||||||
suspend operator fun invoke(userWalletId: UserWalletId): Either<VisaApiError, List<Order>> {
|
|
||||||
return customerOrderRepository.findOrders(
|
|
||||||
userWalletId = userWalletId,
|
|
||||||
statuses = ACTIVE_STATUSES,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
val ACTIVE_STATUSES: Set<OrderStatus> = setOf(OrderStatus.NEW, OrderStatus.PROCESSING)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -6,25 +6,43 @@ import com.tangem.domain.pay.model.OrderStatus
|
||||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
class StartTangemPayOrderPollingUseCase(
|
class StartTangemPayOrderPollingUseCase(
|
||||||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||||
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
|
private val paymentAccountStatusFetcher: PaymentAccountStatusFetcher,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Order keys (`walletId:orderId`) currently being polled. Keeps polling idempotent so callers that
|
||||||
|
* may fire repeatedly for the same order (e.g. order restore on every wallet (re)load) never spawn a
|
||||||
|
* second poller for it.
|
||||||
|
*/
|
||||||
|
private val activeOrders = ConcurrentHashMap.newKeySet<String>()
|
||||||
|
|
||||||
suspend operator fun invoke(order: TangemPayOrderInfo, userWalletId: UserWalletId): Boolean {
|
suspend operator fun invoke(order: TangemPayOrderInfo, userWalletId: UserWalletId): Boolean {
|
||||||
while (true) {
|
// A poller for this exact order is already running — `false` only reaches fire-and-forget issue
|
||||||
val newOrder = if (order.orderStatus.isTerminal) {
|
// callers (restore / issue-additional); the awaiting freeze caller always polls a fresh order id.
|
||||||
order
|
val key = "${userWalletId.stringValue}:${order.orderId}"
|
||||||
} else {
|
if (!activeOrders.add(key)) return false
|
||||||
cardDetailsRepository.getOrderInfo(userWalletId, order.orderId).getOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newOrder != null && newOrder.orderStatus.isTerminal) {
|
try {
|
||||||
paymentAccountStatusFetcher.invoke(userWalletId)
|
while (true) {
|
||||||
return newOrder.orderStatus == OrderStatus.COMPLETED
|
val newOrder = if (order.orderStatus.isTerminal) {
|
||||||
}
|
order
|
||||||
|
} else {
|
||||||
|
cardDetailsRepository.getOrderInfo(userWalletId, order.orderId).getOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
delay(POLLING_DELAY)
|
if (newOrder != null && newOrder.orderStatus.isTerminal) {
|
||||||
|
paymentAccountStatusFetcher.invoke(userWalletId)
|
||||||
|
return newOrder.orderStatus == OrderStatus.COMPLETED
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(POLLING_DELAY)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
activeOrders.remove(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
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.model.Order
|
||||||
|
import com.tangem.domain.pay.model.OrderStatus
|
||||||
|
import com.tangem.domain.pay.model.OrderType
|
||||||
|
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||||
|
import com.tangem.domain.pay.repository.CustomerOrderRepository
|
||||||
|
import com.tangem.domain.pay.repository.TangemPayIssueCardRepository
|
||||||
|
import com.tangem.domain.visa.error.VisaApiError
|
||||||
|
import com.tangem.test.core.TestAppCoroutineScope
|
||||||
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.mockk
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
internal class RestoreActiveIssueOrdersUseCaseTest {
|
||||||
|
|
||||||
|
private val orderRepository: CustomerOrderRepository = mockk()
|
||||||
|
private val issueCardRepository: TangemPayIssueCardRepository = mockk(relaxed = true)
|
||||||
|
private val startTangemPayOrderPollingUseCase: StartTangemPayOrderPollingUseCase = mockk(relaxed = true)
|
||||||
|
private val useCase = RestoreActiveIssueOrdersUseCase(
|
||||||
|
customerOrderRepository = orderRepository,
|
||||||
|
issueCardRepository = issueCardRepository,
|
||||||
|
startTangemPayOrderPollingUseCase = startTangemPayOrderPollingUseCase,
|
||||||
|
appCoroutineScope = TestAppCoroutineScope(),
|
||||||
|
)
|
||||||
|
private val userWalletId = UserWalletId("1234567890ABCDEF")
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN active issue orders WHEN invoke THEN each order is stored and polled`() = runTest {
|
||||||
|
// Arrange
|
||||||
|
val first = order(id = "first", type = OrderType.CARD_ISSUE_ADDITIONAL, status = OrderStatus.NEW)
|
||||||
|
val second = order(id = "second", type = OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC, status = OrderStatus.PROCESSING)
|
||||||
|
coEvery {
|
||||||
|
orderRepository.findOrders(
|
||||||
|
userWalletId = userWalletId,
|
||||||
|
types = ISSUE_ORDER_TYPES,
|
||||||
|
statuses = ACTIVE_STATUSES,
|
||||||
|
)
|
||||||
|
} returns listOf(first, second).right()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = useCase(userWalletId)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result.isRight()).isTrue()
|
||||||
|
coVerify(exactly = 1) { issueCardRepository.storeIssueOrderId(userWalletId, first.id) }
|
||||||
|
coVerify(exactly = 1) { issueCardRepository.storeIssueOrderId(userWalletId, second.id) }
|
||||||
|
coVerify(exactly = 1) {
|
||||||
|
startTangemPayOrderPollingUseCase(TangemPayOrderInfo(first.id, first.status), userWalletId)
|
||||||
|
}
|
||||||
|
coVerify(exactly = 1) {
|
||||||
|
startTangemPayOrderPollingUseCase(TangemPayOrderInfo(second.id, second.status), userWalletId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN no active orders WHEN invoke THEN nothing is stored or polled`() = runTest {
|
||||||
|
// Arrange
|
||||||
|
coEvery {
|
||||||
|
orderRepository.findOrders(userWalletId, types = ISSUE_ORDER_TYPES, statuses = ACTIVE_STATUSES)
|
||||||
|
} returns emptyList<Order>().right()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = useCase(userWalletId)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result.isRight()).isTrue()
|
||||||
|
coVerify(exactly = 0) { issueCardRepository.storeIssueOrderId(any(), any()) }
|
||||||
|
coVerify(exactly = 0) { startTangemPayOrderPollingUseCase(any(), any()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN a terminal order leaks through WHEN invoke THEN it is filtered out`() = runTest {
|
||||||
|
// Arrange
|
||||||
|
val completed = order(id = "done", type = OrderType.CARD_ISSUE_ADDITIONAL, status = OrderStatus.COMPLETED)
|
||||||
|
coEvery {
|
||||||
|
orderRepository.findOrders(userWalletId, types = ISSUE_ORDER_TYPES, statuses = ACTIVE_STATUSES)
|
||||||
|
} returns listOf(completed).right()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = useCase(userWalletId)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result.isRight()).isTrue()
|
||||||
|
coVerify(exactly = 0) { issueCardRepository.storeIssueOrderId(any(), any()) }
|
||||||
|
coVerify(exactly = 0) { startTangemPayOrderPollingUseCase(any(), any()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN findOrders fails WHEN invoke THEN returns Unspecified and stores nothing`() = runTest {
|
||||||
|
// Arrange
|
||||||
|
coEvery {
|
||||||
|
orderRepository.findOrders(userWalletId, types = ISSUE_ORDER_TYPES, statuses = ACTIVE_STATUSES)
|
||||||
|
} returns VisaApiError.Unspecified.left()
|
||||||
|
|
||||||
|
// Act
|
||||||
|
val result = useCase(userWalletId)
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
assertThat(result.leftOrNull()).isEqualTo(VisaApiError.Unspecified)
|
||||||
|
coVerify(exactly = 0) { issueCardRepository.storeIssueOrderId(any(), any()) }
|
||||||
|
coVerify(exactly = 0) { startTangemPayOrderPollingUseCase(any(), any()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun order(id: String, type: OrderType, status: OrderStatus): Order = Order(
|
||||||
|
id = id,
|
||||||
|
customerId = "customer",
|
||||||
|
type = type,
|
||||||
|
status = status,
|
||||||
|
step = null,
|
||||||
|
stepChangeCode = null,
|
||||||
|
productInstanceId = null,
|
||||||
|
paymentAccountId = null,
|
||||||
|
cardId = null,
|
||||||
|
withdrawTxHash = null,
|
||||||
|
createdAt = null,
|
||||||
|
updatedAt = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
val ISSUE_ORDER_TYPES = OrderType.issueCardTypes
|
||||||
|
val ACTIVE_STATUSES = OrderStatus.activeStatuses
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,72 +0,0 @@
|
||||||
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.model.Order
|
|
||||||
import com.tangem.domain.pay.model.OrderStatus
|
|
||||||
import com.tangem.domain.pay.model.OrderType
|
|
||||||
import com.tangem.domain.pay.repository.CustomerOrderRepository
|
|
||||||
import com.tangem.domain.visa.error.VisaApiError
|
|
||||||
import io.mockk.coEvery
|
|
||||||
import io.mockk.coVerify
|
|
||||||
import io.mockk.mockk
|
|
||||||
import kotlinx.coroutines.test.runTest
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
|
|
||||||
internal class RestoreActiveOrdersUseCaseTest {
|
|
||||||
|
|
||||||
private val repository: CustomerOrderRepository = mockk()
|
|
||||||
private val useCase = RestoreActiveOrdersUseCase(repository)
|
|
||||||
private val userWalletId = UserWalletId("1234567890ABCDEF")
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `passes only NEW and PROCESSING statuses to findOrders`() = runTest {
|
|
||||||
val expected = setOf(OrderStatus.NEW, OrderStatus.PROCESSING)
|
|
||||||
coEvery { repository.findOrders(userWalletId, types = emptySet(), statuses = expected) } returns
|
|
||||||
emptyList<Order>().right()
|
|
||||||
|
|
||||||
useCase(userWalletId)
|
|
||||||
|
|
||||||
coVerify(exactly = 1) { repository.findOrders(userWalletId, types = emptySet(), statuses = expected) }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `returns the orders found by the repository`() = runTest {
|
|
||||||
val orders = listOf(
|
|
||||||
order(id = "issue", type = OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC, status = OrderStatus.PROCESSING),
|
|
||||||
order(id = "withdraw", type = OrderType.WITHDRAW, status = OrderStatus.NEW),
|
|
||||||
)
|
|
||||||
coEvery { repository.findOrders(userWalletId, types = emptySet(), statuses = any()) } returns orders.right()
|
|
||||||
|
|
||||||
val result = useCase(userWalletId)
|
|
||||||
|
|
||||||
assertThat(result.getOrNull()).containsExactlyElementsIn(orders)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `surfaces repository errors`() = runTest {
|
|
||||||
coEvery { repository.findOrders(userWalletId, types = emptySet(), statuses = any()) } returns
|
|
||||||
VisaApiError.Unspecified.left()
|
|
||||||
|
|
||||||
val result = useCase(userWalletId)
|
|
||||||
|
|
||||||
assertThat(result.leftOrNull()).isEqualTo(VisaApiError.Unspecified)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun order(id: String, type: OrderType, status: OrderStatus): Order = Order(
|
|
||||||
id = id,
|
|
||||||
customerId = "customer",
|
|
||||||
type = type,
|
|
||||||
status = status,
|
|
||||||
step = null,
|
|
||||||
stepChangeCode = null,
|
|
||||||
productInstanceId = null,
|
|
||||||
paymentAccountId = null,
|
|
||||||
cardId = null,
|
|
||||||
withdrawTxHash = null,
|
|
||||||
createdAt = null,
|
|
||||||
updatedAt = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -9,7 +9,11 @@ import com.tangem.domain.pay.model.OrderStatus
|
||||||
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
import com.tangem.domain.pay.model.TangemPayOrderInfo
|
||||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||||
import com.tangem.domain.visa.error.VisaApiError
|
import com.tangem.domain.visa.error.VisaApiError
|
||||||
import io.mockk.*
|
import io.mockk.coEvery
|
||||||
|
import io.mockk.coVerify
|
||||||
|
import io.mockk.mockk
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.test.runCurrent
|
||||||
import kotlinx.coroutines.test.runTest
|
import kotlinx.coroutines.test.runTest
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
|
@ -112,6 +116,28 @@ internal class StartTangemPayOrderPollingUseCaseTest {
|
||||||
coVerify(exactly = 1) { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) }
|
coVerify(exactly = 1) { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `GIVEN order already being polled WHEN invoke again for same order THEN returns false without a second poll`() =
|
||||||
|
runTest {
|
||||||
|
// Arrange — first poller never reaches a terminal status, so it keeps polling.
|
||||||
|
val order = TangemPayOrderInfo(ORDER_ID, OrderStatus.PROCESSING)
|
||||||
|
coEvery { cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID) } returns
|
||||||
|
TangemPayOrderInfo(ORDER_ID, OrderStatus.PROCESSING).right()
|
||||||
|
|
||||||
|
// Act — start the first poller, let it register the order and park in its poll delay,
|
||||||
|
// then invoke again for the same order.
|
||||||
|
val firstPoller = launch { useCase(order, USER_WALLET_ID) }
|
||||||
|
runCurrent()
|
||||||
|
val secondResult = useCase(order, USER_WALLET_ID)
|
||||||
|
|
||||||
|
// Assert — the duplicate invoke is a no-op (no extra getOrderInfo, no status fetch).
|
||||||
|
assertThat(secondResult).isFalse()
|
||||||
|
coVerify(exactly = 1) { cardDetailsRepository.getOrderInfo(USER_WALLET_ID, ORDER_ID) }
|
||||||
|
coVerify(exactly = 0) { paymentAccountStatusFetcher.invoke(USER_WALLET_ID) }
|
||||||
|
|
||||||
|
firstPoller.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
val USER_WALLET_ID = UserWalletId("aabbcc112233")
|
val USER_WALLET_ID = UserWalletId("aabbcc112233")
|
||||||
const val ORDER_ID = "order-test-1"
|
const val ORDER_ID = "order-test-1"
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import com.tangem.domain.notifications.GetIsHuaweiDeviceWithoutGoogleServicesUse
|
||||||
import com.tangem.domain.notifications.repository.NotificationsRepository
|
import com.tangem.domain.notifications.repository.NotificationsRepository
|
||||||
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
import com.tangem.domain.pay.flow.PaymentAccountStatusFetcher
|
||||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||||
|
import com.tangem.domain.pushnotificationpreferences.PreloadWalletPushNotificationPreferencesUseCase
|
||||||
import com.tangem.domain.qrscanning.models.ClassifiedQrContent
|
import com.tangem.domain.qrscanning.models.ClassifiedQrContent
|
||||||
import com.tangem.domain.qrscanning.models.QrResultSource
|
import com.tangem.domain.qrscanning.models.QrResultSource
|
||||||
import com.tangem.domain.qrscanning.models.QrSendTarget
|
import com.tangem.domain.qrscanning.models.QrSendTarget
|
||||||
|
|
@ -47,7 +48,6 @@ import com.tangem.feature.wallet.presentation.wallet.analytics.utils.SelectedWal
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory
|
import com.tangem.feature.wallet.presentation.wallet.domain.OnrampStatusFactory
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletContentFetcher
|
import com.tangem.feature.wallet.presentation.wallet.domain.WalletContentFetcher
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
|
import com.tangem.feature.wallet.presentation.wallet.domain.WalletImageResolver
|
||||||
import com.tangem.domain.pushnotificationpreferences.PreloadWalletPushNotificationPreferencesUseCase
|
|
||||||
import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase
|
import com.tangem.feature.wallet.presentation.wallet.domain.WalletNameMigrationUseCase
|
||||||
import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader
|
import com.tangem.feature.wallet.presentation.wallet.loaders.WalletScreenContentLoader
|
||||||
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
import com.tangem.feature.wallet.presentation.wallet.state.WalletStateController
|
||||||
|
|
@ -62,8 +62,8 @@ import com.tangem.feature.wallet.presentation.wallet.ui.components.visa.KycRejec
|
||||||
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
|
import com.tangem.feature.wallet.presentation.wallet.utils.ScreenLifecycleProvider
|
||||||
import com.tangem.features.biometry.AskBiometryComponent
|
import com.tangem.features.biometry.AskBiometryComponent
|
||||||
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
import com.tangem.features.hotwallet.HotWalletFeatureToggles
|
||||||
import com.tangem.features.pushnotificationsettings.PushNotificationSettingsFeatureToggles
|
|
||||||
import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks
|
import com.tangem.features.pushnotifications.api.PushNotificationsModelCallbacks
|
||||||
|
import com.tangem.features.pushnotificationsettings.PushNotificationSettingsFeatureToggles
|
||||||
import com.tangem.features.wallet.deeplink.WalletDeepLinkActionListener
|
import com.tangem.features.wallet.deeplink.WalletDeepLinkActionListener
|
||||||
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
import com.tangem.features.wallet.featuretoggles.WalletFeatureToggles
|
||||||
import com.tangem.utils.Provider
|
import com.tangem.utils.Provider
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.tangem.feature.wallet.presentation.wallet.subscribers
|
||||||
import com.tangem.domain.models.wallet.UserWallet
|
import com.tangem.domain.models.wallet.UserWallet
|
||||||
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
import com.tangem.domain.pay.flow.PaymentAccountStatusSupplier
|
||||||
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
import com.tangem.domain.pay.repository.TangemPayWithdrawRepository
|
||||||
|
import com.tangem.domain.pay.usecase.RestoreActiveIssueOrdersUseCase
|
||||||
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletTangemPayAnalyticsEventSender
|
import com.tangem.feature.wallet.presentation.wallet.analytics.utils.WalletTangemPayAnalyticsEventSender
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
|
|
@ -14,6 +15,7 @@ import kotlinx.coroutines.launch
|
||||||
internal class TangemPayMainSubscriber @AssistedInject constructor(
|
internal class TangemPayMainSubscriber @AssistedInject constructor(
|
||||||
@Assisted private val userWallet: UserWallet,
|
@Assisted private val userWallet: UserWallet,
|
||||||
private val tangemPayWithdrawRepository: TangemPayWithdrawRepository,
|
private val tangemPayWithdrawRepository: TangemPayWithdrawRepository,
|
||||||
|
private val restoreActiveIssueOrdersUseCase: RestoreActiveIssueOrdersUseCase,
|
||||||
private val paymentAccountStatusSupplier: PaymentAccountStatusSupplier,
|
private val paymentAccountStatusSupplier: PaymentAccountStatusSupplier,
|
||||||
private val analytics: WalletTangemPayAnalyticsEventSender,
|
private val analytics: WalletTangemPayAnalyticsEventSender,
|
||||||
) : WalletSubscriber() {
|
) : WalletSubscriber() {
|
||||||
|
|
@ -23,6 +25,9 @@ internal class TangemPayMainSubscriber @AssistedInject constructor(
|
||||||
// TODO: Doston move this logic to proper place(e.g. WalletBalanceFetcher)
|
// TODO: Doston move this logic to proper place(e.g. WalletBalanceFetcher)
|
||||||
tangemPayWithdrawRepository.pollWithdrawOrdersIfNeeds(userWallet)
|
tangemPayWithdrawRepository.pollWithdrawOrdersIfNeeds(userWallet)
|
||||||
}
|
}
|
||||||
|
coroutineScope.launch {
|
||||||
|
restoreActiveIssueOrdersUseCase(userWallet.walletId)
|
||||||
|
}
|
||||||
subscribeToStatus(coroutineScope)
|
subscribeToStatus(coroutineScope)
|
||||||
return emptyFlow<Any>()
|
return emptyFlow<Any>()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue