Updated on 2026-08-14
This commit is contained in:
parent
640ba5af98
commit
6f257991e5
39 changed files with 1526 additions and 110 deletions
|
|
@ -5,12 +5,7 @@ import com.tangem.datasource.local.visa.entity.PaymentAccountStatusValueDM
|
|||
import com.tangem.domain.models.StatusSource
|
||||
import com.tangem.domain.models.account.CardDisplayName
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.pay.TangemPayCard
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.domain.models.pay.TangemPayCardLimit
|
||||
import com.tangem.domain.models.pay.TangemPayCardLimitData
|
||||
import com.tangem.domain.models.pay.TangemPayCardLimitPeriod
|
||||
import com.tangem.domain.models.pay.TangemPayCardState
|
||||
import com.tangem.domain.models.pay.*
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayCurrencyFactory
|
||||
import javax.inject.Inject
|
||||
|
|
@ -48,6 +43,8 @@ internal class PaymentAccountStatusValueDMConverter @Inject constructor(
|
|||
cards = value.cards.map { card ->
|
||||
PaymentAccountStatusValueDM.TangemPayCard(
|
||||
id = card.id,
|
||||
productInstanceId = card.productInstanceId,
|
||||
cardStatus = card.cardStatus.name,
|
||||
hasPinCode = card.hasPinCode,
|
||||
displayName = card.displayName?.value,
|
||||
actualDailyLimit = card.limit?.actualCardLimit?.amount,
|
||||
|
|
@ -103,6 +100,8 @@ internal class PaymentAccountStatusValueDMConverter @Inject constructor(
|
|||
cards = value.cards.map { card ->
|
||||
TangemPayCard(
|
||||
id = card.id,
|
||||
productInstanceId = card.productInstanceId,
|
||||
cardStatus = TangemPayCard.Status.fromString(card.cardStatus),
|
||||
hasPinCode = card.hasPinCode,
|
||||
displayName = card.displayName?.let { CardDisplayName(it).getOrElse { null } },
|
||||
limit = TangemPayCardLimitData(
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ internal interface TangemPayDataModule {
|
|||
@Singleton
|
||||
fun bindCustomerOrderRepository(repository: DefaultCustomerOrderRepository): CustomerOrderRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindCustomerOffersRepository(repository: DefaultCustomerOffersRepository): CustomerOffersRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindReissueCardRepository(repository: DefaultReissueCardRepository): TangemPayReissueCardRepository
|
||||
|
|
@ -231,5 +235,42 @@ internal interface TangemPayDataModule {
|
|||
paymentAccountStatusFetcher = paymentAccountStatusFetcher,
|
||||
)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideGetCustomerOffersUseCase(
|
||||
customerOffersRepository: CustomerOffersRepository,
|
||||
): GetCustomerOffersUseCase {
|
||||
return GetCustomerOffersUseCase(customerOffersRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideCheckOrderConflictUseCase(
|
||||
customerOrderRepository: CustomerOrderRepository,
|
||||
): CheckOrderConflictUseCase {
|
||||
return CheckOrderConflictUseCase(customerOrderRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideRestoreActiveOrdersUseCase(
|
||||
customerOrderRepository: CustomerOrderRepository,
|
||||
): RestoreActiveOrdersUseCase {
|
||||
return RestoreActiveOrdersUseCase(customerOrderRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideValidateLocalOrderHintUseCase(
|
||||
customerOrderRepository: CustomerOrderRepository,
|
||||
onboardingRepository: OnboardingRepository,
|
||||
): ValidateLocalOrderHintUseCase {
|
||||
return ValidateLocalOrderHintUseCase(customerOrderRepository, onboardingRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideIssueAdditionalCardUseCase(
|
||||
customerOffersRepository: CustomerOffersRepository,
|
||||
customerOrderRepository: CustomerOrderRepository,
|
||||
): IssueAdditionalCardUseCase {
|
||||
return IssueAdditionalCardUseCase(customerOffersRepository, customerOrderRepository)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,7 +10,9 @@ import com.tangem.domain.models.account.PaymentAccountStatusValue
|
|||
import com.tangem.domain.models.account.hasAccountData
|
||||
import com.tangem.domain.models.kyc.KycStatus
|
||||
import com.tangem.domain.models.pay.TangemPayCard
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.domain.models.pay.TangemPayCardLimitData
|
||||
import com.tangem.domain.models.pay.TangemPayCardState
|
||||
import com.tangem.domain.models.quote.QuoteStatus
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.TangemPayCurrencyFactory
|
||||
|
|
@ -20,17 +22,10 @@ import com.tangem.domain.pay.model.CustomerInfo
|
|||
import com.tangem.domain.pay.model.OrderData
|
||||
import com.tangem.domain.pay.model.OrderStatus
|
||||
import com.tangem.domain.pay.model.TangemPayEntryPoint
|
||||
import com.tangem.domain.pay.repository.CustomerOrderRepository
|
||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayReissueCardRepository
|
||||
import com.tangem.domain.pay.repository.*
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusProducer
|
||||
import com.tangem.domain.quotes.single.SingleQuoteStatusSupplier
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.domain.models.pay.TangemPayCardState
|
||||
import com.tangem.domain.pay.model.isFinalStatus
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayCloseCardRepository
|
||||
import com.tangem.security.DeviceSecurityInfoProvider
|
||||
import com.tangem.security.isSecurityExposed
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
|
|
@ -284,8 +279,6 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
val quotesData = singleQuoteSupplier.getSyncOrNull(
|
||||
params = SingleQuoteStatusProducer.Params(rawCurrencyId = TangemPayCurrencyFactory.TOKEN_ID),
|
||||
)?.value as? QuoteStatus.Data
|
||||
val cardInfo = this.cardInfo
|
||||
val productInstance = this.productInstance
|
||||
|
||||
val isDeactivated = productInstance?.status == CustomerInfo.ProductInstance.Status.DEACTIVATED
|
||||
val isFormer = state == CustomerInfo.State.FORMER
|
||||
|
|
@ -315,10 +308,11 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
error = null,
|
||||
)
|
||||
}
|
||||
cardInfo != null && productInstance != null && !customerId.isNullOrEmpty() -> convertToContentState(
|
||||
cards.isNotEmpty() && productInstances.isNotEmpty() &&
|
||||
fiatBalance != null && cryptoBalance != null && !customerId.isNullOrEmpty() -> convertToContentState(
|
||||
userWalletId = userWalletId,
|
||||
productInstance = productInstance,
|
||||
cardInfo = cardInfo,
|
||||
fiatBalance = fiatBalance,
|
||||
cryptoBalance = cryptoBalance,
|
||||
fiatRate = quotesData?.fiatRate,
|
||||
customerId = requireNotNull(customerId) { "CustomerId must not be null" },
|
||||
)
|
||||
|
|
@ -326,45 +320,57 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun convertToContentState(
|
||||
/**
|
||||
* Builds the [PaymentAccountStatusValue.Loaded] content state with the full list of cards.
|
||||
* Each card is the join of a product instance with its card info by `cardId`; balances are
|
||||
* payment-account-level (shared across cards). Falls back to [PaymentAccountStatusValue.IssuingCard]
|
||||
* when no card has both a product instance and card info yet (e.g. issuance in progress).
|
||||
*/
|
||||
private suspend fun CustomerInfo.convertToContentState(
|
||||
userWalletId: UserWalletId,
|
||||
productInstance: CustomerInfo.ProductInstance,
|
||||
cardInfo: CustomerInfo.CardInfo,
|
||||
fiatBalance: PaymentAccountStatusValue.FiatBalance,
|
||||
cryptoBalance: PaymentAccountStatusValue.CryptoBalance,
|
||||
customerId: String,
|
||||
fiatRate: BigDecimal?,
|
||||
): PaymentAccountStatusValue {
|
||||
val cardId = productInstance.cardId
|
||||
val cardState = getCardState(cardId, userWalletId)
|
||||
val cardFrozenState = cardDetailsRepository.cardFrozenStateSync(cardId)
|
||||
val cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId)
|
||||
val cardsById = cards.associateBy { it.cardId }
|
||||
val tangemPayCards = productInstances.mapNotNull { productInstance ->
|
||||
val cardInfo = cardsById[productInstance.cardId] ?: return@mapNotNull null
|
||||
val cardId = productInstance.cardId
|
||||
val cardFrozenState = cardDetailsRepository.cardFrozenStateSync(cardId)
|
||||
TangemPayCard(
|
||||
id = cardId,
|
||||
productInstanceId = productInstance.id,
|
||||
cardStatus = cardInfo.cardStatus,
|
||||
hasPinCode = cardInfo.isPinSet,
|
||||
displayName = productInstance.displayName,
|
||||
limit = TangemPayCardLimitData(
|
||||
actualCardLimit = productInstance.actualCardLimit,
|
||||
adminCardLimit = productInstance.adminCardLimit,
|
||||
),
|
||||
frozenState = if (cardFrozenState == TangemPayCardFrozenState.Pending) {
|
||||
TangemPayCardFrozenState.Pending
|
||||
} else {
|
||||
productInstance.frozenState
|
||||
},
|
||||
lastDigits = cardInfo.lastFourDigits,
|
||||
state = getCardState(cardId, userWalletId),
|
||||
)
|
||||
}
|
||||
|
||||
if (tangemPayCards.isEmpty()) return PaymentAccountStatusValue.IssuingCard(source = StatusSource.ACTUAL)
|
||||
|
||||
return PaymentAccountStatusValue.Loaded(
|
||||
source = StatusSource.ACTUAL,
|
||||
customerId = customerId,
|
||||
depositAddress = cardInfo.depositAddress,
|
||||
balance = PaymentAccountStatusValue.Balance(
|
||||
fiatBalance = cardInfo.fiatBalance,
|
||||
cryptoBalance = cardInfo.cryptoBalance,
|
||||
availableForWithdrawal = cardInfo.availableForWithdrawal,
|
||||
),
|
||||
cryptoCurrency = cryptoCurrency,
|
||||
depositAddress = cryptoBalance.depositAddress,
|
||||
cryptoCurrency = tangemPayCurrencyFactory.create(userWalletId),
|
||||
fiatRate = fiatRate,
|
||||
cards = listOf(
|
||||
TangemPayCard(
|
||||
id = cardId,
|
||||
hasPinCode = cardInfo.isPinSet,
|
||||
displayName = productInstance.displayName,
|
||||
limit = TangemPayCardLimitData(
|
||||
actualCardLimit = productInstance.actualCardLimit,
|
||||
adminCardLimit = productInstance.adminCardLimit,
|
||||
),
|
||||
frozenState = if (cardFrozenState == TangemPayCardFrozenState.Pending) {
|
||||
TangemPayCardFrozenState.Pending
|
||||
} else {
|
||||
productInstance.frozenState
|
||||
},
|
||||
lastDigits = cardInfo.lastFourDigits,
|
||||
state = cardState,
|
||||
),
|
||||
cards = tangemPayCards,
|
||||
balance = PaymentAccountStatusValue.Balance(
|
||||
fiatBalance = fiatBalance,
|
||||
cryptoBalance = cryptoBalance,
|
||||
availableForWithdrawal = availableForWithdrawal.orZero(),
|
||||
),
|
||||
error = null,
|
||||
)
|
||||
|
|
@ -375,7 +381,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
val reissueOrderId = reissueCardRepository.getReissueOrderId(userWalletId, cardId).getOrNull()
|
||||
return if (closingOrderId != null) {
|
||||
val order = cardDetailsRepository.getOrderInfo(userWalletId, closingOrderId).getOrNull()
|
||||
if (order != null && order.orderStatus.isFinalStatus) {
|
||||
if (order != null && order.orderStatus.isTerminal) {
|
||||
closeCardRepository.setCloseOrderId(cardId, null)
|
||||
TangemPayCardState.Active
|
||||
} else {
|
||||
|
|
@ -383,7 +389,7 @@ internal class DefaultPaymentAccountStatusFetcher @Inject constructor(
|
|||
}
|
||||
} else if (reissueOrderId != null) {
|
||||
val order = cardDetailsRepository.getOrderInfo(userWalletId, reissueOrderId).getOrNull()
|
||||
if (order != null && order.orderStatus.isFinalStatus) {
|
||||
if (order != null && order.orderStatus.isTerminal) {
|
||||
TangemPayCardState.Active
|
||||
} else {
|
||||
TangemPayCardState.Reissuing
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package com.tangem.data.pay.repository
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.api.pay.models.response.CustomerOffersResponse
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.Offer
|
||||
import com.tangem.domain.pay.model.OrderType
|
||||
import com.tangem.domain.pay.repository.CustomerOffersRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import java.util.Currency
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultCustomerOffersRepository @Inject constructor(
|
||||
private val tangemPayApi: TangemPayApi,
|
||||
private val requestHelper: TangemPayRequestPerformer,
|
||||
) : CustomerOffersRepository {
|
||||
|
||||
override suspend fun getOffers(userWalletId: UserWalletId): Either<VisaApiError, List<Offer>> {
|
||||
return requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.getCustomerOffers(authHeader = authHeader)
|
||||
}.map { response ->
|
||||
response.result.map { it.toDomain() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun CustomerOffersResponse.Offer.toDomain(): Offer {
|
||||
return Offer(
|
||||
type = Offer.Type.fromString(type),
|
||||
fee = Offer.Fee(amount = fee.amount, currency = Currency.getInstance(fee.currency)),
|
||||
data = Offer.Data(
|
||||
specificationName = data.specificationName,
|
||||
orderType = OrderType.fromString(data.orderType),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +1,15 @@
|
|||
package com.tangem.data.pay.repository
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.data.pay.util.OrderConverter
|
||||
import com.tangem.data.pay.util.OrderStatusConverter
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.datasource.api.pay.models.request.OrderRequest
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.Order
|
||||
import com.tangem.domain.pay.model.OrderData
|
||||
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 javax.inject.Inject
|
||||
|
|
@ -27,4 +31,47 @@ internal class DefaultCustomerOrderRepository @Inject constructor(
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun findOrders(
|
||||
userWalletId: UserWalletId,
|
||||
types: Set<OrderType>,
|
||||
statuses: Set<OrderStatus>,
|
||||
): Either<VisaApiError, List<Order>> {
|
||||
val typeWire = types.map(OrderType::wireValue).takeIf { it.isNotEmpty() }
|
||||
val statusWire = statuses.map(OrderStatus::name).takeIf { it.isNotEmpty() }
|
||||
return requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.findOrders(
|
||||
authHeader = authHeader,
|
||||
orderTypes = typeWire,
|
||||
orderStatuses = statusWire,
|
||||
)
|
||||
}.map { response ->
|
||||
response.result.map(OrderConverter::convert)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun createOrder(
|
||||
userWalletId: UserWalletId,
|
||||
type: OrderType,
|
||||
specificationName: String,
|
||||
idempotencyKey: String,
|
||||
): Either<VisaApiError, Order> {
|
||||
val walletAddress = requestHelper.getCustomerWalletAddress(userWalletId)
|
||||
return requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.createOrder(
|
||||
authHeader = authHeader,
|
||||
body = OrderRequest(
|
||||
data = OrderRequest.Data(
|
||||
customerWalletAddress = walletAddress,
|
||||
specificationName = specificationName,
|
||||
type = type.wireValue,
|
||||
),
|
||||
idempotencyKey = idempotencyKey,
|
||||
),
|
||||
)
|
||||
}.map { response ->
|
||||
val result = requireNotNull(response.result) { "createOrder returned empty result" }
|
||||
OrderConverter.convert(result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ import com.tangem.domain.tangempay.TangemPayAnalyticsEvents
|
|||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import com.tangem.utils.coroutines.CoroutineDispatcherProvider
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.util.UUID
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -144,7 +145,10 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
val walletAddress = requestHelper.getCustomerWalletAddress(userWalletId)
|
||||
requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
val data = OrderRequest.Data(customerWalletAddress = walletAddress)
|
||||
tangemPayApi.createOrder(authHeader, body = OrderRequest(data = data))
|
||||
tangemPayApi.createOrder(
|
||||
authHeader = authHeader,
|
||||
body = OrderRequest(data = data, idempotencyKey = UUID.randomUUID().toString()),
|
||||
)
|
||||
}.map { response ->
|
||||
val result = requireNotNull(response.result)
|
||||
tangemPayStorage.storeOrderId(walletAddress, result.id)
|
||||
|
|
@ -165,7 +169,8 @@ internal class DefaultOnboardingRepository @Inject constructor(
|
|||
val customerInfo = CustomerInfoConverter.convert(response)
|
||||
sendKycAnalytics(customerInfo.kycStatus)
|
||||
|
||||
customerInfo.productInstance?.let { instance ->
|
||||
// Keep the per-card frozen state up to date for every card.
|
||||
customerInfo.productInstances.forEach { instance ->
|
||||
cardFrozenStateStore.store(key = instance.cardId, value = instance.frozenState)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,65 +7,70 @@ import com.tangem.datasource.api.pay.models.response.FiatBalance
|
|||
import com.tangem.domain.models.account.CardDisplayName
|
||||
import com.tangem.domain.models.account.PaymentAccountStatusValue
|
||||
import com.tangem.domain.models.kyc.KycStatus
|
||||
import com.tangem.domain.models.pay.TangemPayCard
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.domain.models.pay.TangemPayCardLimit
|
||||
import com.tangem.domain.models.pay.TangemPayCardLimitPeriod
|
||||
import com.tangem.domain.pay.model.CustomerInfo
|
||||
import com.tangem.domain.pay.model.CustomerInfo.CardInfo
|
||||
import com.tangem.domain.pay.model.CustomerInfo.ProductInstance
|
||||
import com.tangem.domain.pay.model.CustomerInfo.ProductInstance.Status
|
||||
import com.tangem.domain.models.pay.TangemPayCardFrozenState
|
||||
import com.tangem.utils.converter.Converter
|
||||
import com.tangem.utils.extensions.orZero
|
||||
|
||||
internal object CustomerInfoConverter : Converter<CustomerMeResponse.Result, CustomerInfo> {
|
||||
@Suppress("ComplexCondition")
|
||||
override fun convert(value: CustomerMeResponse.Result): CustomerInfo {
|
||||
val kycStatus = KycStatus.fromString(status = value.kyc?.status)
|
||||
val card = value.card
|
||||
val fiatBalance = value.balance?.fiat
|
||||
val cryptoBalance = value.balance?.crypto
|
||||
val paymentAccount = value.paymentAccount
|
||||
val cardInfo = if (paymentAccount != null && card != null && fiatBalance != null && cryptoBalance != null) {
|
||||
CardInfo(
|
||||
lastFourDigits = card.cardNumberEnd,
|
||||
balance = fiatBalance.availableBalance,
|
||||
currencyCode = fiatBalance.currency,
|
||||
depositAddress = value.depositAddress,
|
||||
isPinSet = value.card?.isPinSet == true,
|
||||
fiatBalance = fiatBalance.toDomain(),
|
||||
cryptoBalance = cryptoBalance.toDomain(),
|
||||
availableForWithdrawal = value.balance?.availableForWithdrawal?.amount.orZero(),
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
val productInstance = value.productInstance?.let { instance ->
|
||||
val status = instance.status.toDomain()
|
||||
val cardFrozenState = when (status) {
|
||||
Status.ACTIVE -> TangemPayCardFrozenState.Unfrozen
|
||||
else -> TangemPayCardFrozenState.Frozen
|
||||
}
|
||||
val displayName = instance.displayName?.ifEmpty { null }
|
||||
|
||||
ProductInstance(
|
||||
id = instance.id,
|
||||
cardId = instance.cardId,
|
||||
frozenState = cardFrozenState,
|
||||
status = status,
|
||||
displayName = if (displayName != null) CardDisplayName(displayName).getOrElse { null } else null,
|
||||
actualCardLimit = instance.actualCardLimit?.parseCardLimit(),
|
||||
adminCardLimit = instance.adminCardLimit?.parseCardLimit(),
|
||||
)
|
||||
val productInstances = value.productInstances.map { it.toDomain() }
|
||||
val cards = if (value.paymentAccount == null || value.balance == null) {
|
||||
emptyList()
|
||||
} else {
|
||||
value.cards.mapIndexed { index, cardWire ->
|
||||
// Legacy single-card has no card_id on the card object → join to the single product instance.
|
||||
val cardId = cardWire.cardId ?: value.productInstances.getOrNull(index)?.cardId.orEmpty()
|
||||
buildCardInfo(cardId = cardId, card = cardWire)
|
||||
}
|
||||
}
|
||||
|
||||
return CustomerInfo(
|
||||
customerId = value.id,
|
||||
productInstance = productInstance,
|
||||
productInstances = productInstances,
|
||||
cards = cards,
|
||||
kycStatus = kycStatus,
|
||||
cardInfo = cardInfo,
|
||||
state = CustomerInfo.State.fromString(value.state),
|
||||
fiatBalance = fiatBalance?.toDomain(),
|
||||
cryptoBalance = cryptoBalance?.toDomain(),
|
||||
availableForWithdrawal = value.balance?.availableForWithdrawal?.amount,
|
||||
availableForWithdrawal = value.balance?.availableForWithdrawal?.amount.orZero(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun CustomerMeResponse.ProductInstance.toDomain(): ProductInstance {
|
||||
val status = status.toDomain()
|
||||
val cardFrozenState = when (status) {
|
||||
Status.ACTIVE -> TangemPayCardFrozenState.Unfrozen
|
||||
else -> TangemPayCardFrozenState.Frozen
|
||||
}
|
||||
val name = displayName?.ifEmpty { null }
|
||||
return ProductInstance(
|
||||
id = id,
|
||||
cardId = cardId,
|
||||
frozenState = cardFrozenState,
|
||||
status = status,
|
||||
displayName = if (name != null) CardDisplayName(name).getOrElse { null } else null,
|
||||
actualCardLimit = actualCardLimit?.parseCardLimit(),
|
||||
adminCardLimit = adminCardLimit?.parseCardLimit(),
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildCardInfo(cardId: String, card: CustomerMeResponse.Card): CardInfo {
|
||||
return CardInfo(
|
||||
cardId = cardId,
|
||||
cardStatus = TangemPayCard.Status.fromString(card.cardStatus),
|
||||
lastFourDigits = card.cardNumberEnd,
|
||||
isPinSet = card.isPinSet == true,
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package com.tangem.data.pay.util
|
||||
|
||||
import com.tangem.datasource.api.pay.models.response.OrderResponse
|
||||
import com.tangem.domain.pay.model.Order
|
||||
import com.tangem.domain.pay.model.OrderType
|
||||
|
||||
/** Maps a wire `OrderResponse.Result` into the domain [Order] model. */
|
||||
internal object OrderConverter {
|
||||
|
||||
fun convert(value: OrderResponse.Result): Order {
|
||||
val status = OrderStatusConverter.convert(value.status)
|
||||
val type = OrderType.fromString(value.type ?: value.data.type)
|
||||
return Order(
|
||||
id = value.id,
|
||||
customerId = value.customerId,
|
||||
type = type,
|
||||
status = status,
|
||||
step = value.step,
|
||||
stepChangeCode = value.stepChangeCode,
|
||||
productInstanceId = value.data.productInstanceId,
|
||||
paymentAccountId = value.data.paymentAccountId,
|
||||
cardId = null, // Card id not in v1 response shape; resolved via productInstanceId.
|
||||
withdrawTxHash = value.data.transactionHash?.ifEmpty { null },
|
||||
createdAt = value.createdAt,
|
||||
updatedAt = value.updatedAt,
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue