Updated on 2026-08-14
This commit is contained in:
parent
5618f44c8b
commit
084bad17ab
18 changed files with 452 additions and 192 deletions
|
|
@ -75,6 +75,10 @@ internal interface TangemPayDataModule {
|
|||
@Singleton
|
||||
fun bindCloseCardRepository(repository: DefaultCloseCardRepository): TangemPayCloseCardRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindIssueCardRepository(repository: DefaultIssueCardRepository): TangemPayIssueCardRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindTangemPayCryptoCurrencyFactory(factory: DefaultTangemPayCurrencyFactory): TangemPayCurrencyFactory
|
||||
|
|
@ -269,8 +273,17 @@ internal interface TangemPayDataModule {
|
|||
fun provideIssueAdditionalCardUseCase(
|
||||
customerOffersRepository: CustomerOffersRepository,
|
||||
customerOrderRepository: CustomerOrderRepository,
|
||||
issueCardRepository: TangemPayIssueCardRepository,
|
||||
startTangemPayOrderPollingUseCase: StartTangemPayOrderPollingUseCase,
|
||||
appCoroutineScope: AppCoroutineScope,
|
||||
): IssueAdditionalCardUseCase {
|
||||
return IssueAdditionalCardUseCase(customerOffersRepository, customerOrderRepository)
|
||||
return IssueAdditionalCardUseCase(
|
||||
customerOffersRepository = customerOffersRepository,
|
||||
customerOrderRepository = customerOrderRepository,
|
||||
issueCardRepository = issueCardRepository,
|
||||
startTangemPayOrderPollingUseCase = startTangemPayOrderPollingUseCase,
|
||||
appCoroutineScope = appCoroutineScope,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -53,6 +53,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
private val singleQuoteSupplier: SingleQuoteStatusSupplier,
|
||||
private val closeCardRepository: TangemPayCloseCardRepository,
|
||||
private val cardDetailsRepository: TangemPayCardDetailsRepository,
|
||||
private val issueCardRepository: TangemPayIssueCardRepository,
|
||||
) : PaymentAccountStatusFetcher {
|
||||
|
||||
private val logger = TangemLogger.withTag(TAG)
|
||||
|
|
@ -360,13 +361,17 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
|
||||
if (tangemPayCards.isEmpty()) return PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
|
||||
// Additional-card issuance: the backend omits the new card until it is provisioned, so surface a
|
||||
// placeholder for every locally tracked in-flight issuance order alongside the real cards.
|
||||
val issuingCards = buildIssuingCards(userWalletId)
|
||||
|
||||
return PaymentAccountStatusValue.Loaded(
|
||||
source = StatusSource.ACTUAL,
|
||||
customerId = customerId,
|
||||
depositAddress = cryptoBalance.depositAddress,
|
||||
cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId),
|
||||
fiatRate = fiatRate,
|
||||
cards = tangemPayCards,
|
||||
cards = tangemPayCards + issuingCards,
|
||||
balance = PaymentAccountStatusValue.Balance(
|
||||
fiatBalance = fiatBalance,
|
||||
cryptoBalance = cryptoBalance,
|
||||
|
|
@ -399,6 +404,37 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the issuing placeholder cards from locally tracked additional-card orders. Each order is
|
||||
* re-checked against the backend; terminal orders are dropped (and forgotten) because the real card
|
||||
* is now part of [CustomerInfo], while in-flight orders surface as an issuing placeholder card.
|
||||
*/
|
||||
private suspend fun buildIssuingCards(userWalletId: UserWalletId): List<TangemPayCard> {
|
||||
val orderIds = issueCardRepository.getIssueOrderIds(userWalletId)
|
||||
return orderIds.mapNotNull { orderId ->
|
||||
val order = cardDetailsRepository.getOrderInfo(userWalletId, orderId).getOrNull()
|
||||
if (order != null && order.orderStatus.isTerminal) {
|
||||
issueCardRepository.removeIssueOrderId(userWalletId, orderId)
|
||||
null
|
||||
} else {
|
||||
issuingPlaceholderCard(orderId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Placeholder card for an additional card that is still being issued (no backend card yet). */
|
||||
private fun issuingPlaceholderCard(orderId: String): TangemPayCard = TangemPayCard(
|
||||
id = orderId,
|
||||
productInstanceId = orderId,
|
||||
cardStatus = TangemPayCard.Status.INACTIVE,
|
||||
hasPinCode = false,
|
||||
displayName = null,
|
||||
limit = null,
|
||||
frozenState = TangemPayCardFrozenState.Unfrozen,
|
||||
lastDigits = "",
|
||||
state = TangemPayCardState.Issuing,
|
||||
)
|
||||
|
||||
private suspend fun VisaApiError.mapToPaymentAccountStatus(userWalletId: UserWalletId): PaymentAccountStatusValue {
|
||||
return when (this) {
|
||||
is VisaApiError.RefreshTokenExpired -> PaymentAccountStatusValue.Error.NotSynced
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
package com.tangem.data.pay.repository
|
||||
|
||||
import com.tangem.datasource.local.visa.TangemPayIssueCardStore
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.repository.TangemPayIssueCardRepository
|
||||
import com.tangem.utils.coroutines.runSuspendCatching
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultIssueCardRepository @Inject constructor(
|
||||
private val tangemPayIssueCardStore: TangemPayIssueCardStore,
|
||||
) : TangemPayIssueCardRepository {
|
||||
|
||||
override suspend fun storeIssueOrderId(userWalletId: UserWalletId, orderId: String) {
|
||||
runSuspendCatching { tangemPayIssueCardStore.addIssueOrderId(userWalletId, orderId) }
|
||||
}
|
||||
|
||||
override suspend fun getIssueOrderIds(userWalletId: UserWalletId): List<String> {
|
||||
return runSuspendCatching { tangemPayIssueCardStore.getIssueOrderIds(userWalletId) }
|
||||
.getOrDefault(emptyList())
|
||||
}
|
||||
|
||||
override suspend fun removeIssueOrderId(userWalletId: UserWalletId, orderId: String) {
|
||||
runSuspendCatching { tangemPayIssueCardStore.removeIssueOrderId(userWalletId, orderId) }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue