Updated on 2026-08-14
This commit is contained in:
parent
8196faae1c
commit
1157642722
6 changed files with 55 additions and 21 deletions
|
|
@ -49,7 +49,7 @@ object OrderConflictRules {
|
|||
private fun blocks(intent: OrderIntent, order: Order): Boolean {
|
||||
if (!order.isActive) return false
|
||||
return when (intent) {
|
||||
OrderIntent.IssueCard -> order.type.isIssuing()
|
||||
OrderIntent.IssueCard -> order.type.isIssuing
|
||||
OrderIntent.Withdraw -> order.type == OrderType.WITHDRAW
|
||||
is OrderIntent.Freeze -> sameProductInstance(order, intent.productInstanceId) &&
|
||||
order.type.isFreezeOrReissue()
|
||||
|
|
@ -65,15 +65,7 @@ object OrderConflictRules {
|
|||
return order.productInstanceId == productInstanceId
|
||||
}
|
||||
|
||||
private fun OrderType.isIssuing(): Boolean {
|
||||
return this == OrderType.CARD_ISSUE_ADDITIONAL ||
|
||||
this == OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC ||
|
||||
this == OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC_V2
|
||||
}
|
||||
|
||||
private fun OrderType.isFreezeOrReissue(): Boolean {
|
||||
return this == OrderType.CARD_FREEZE ||
|
||||
this == OrderType.CARD_UNFREEZE ||
|
||||
this == OrderType.CARD_REISSUE
|
||||
return this.isFreezingUnfreezing || this.isReissuing
|
||||
}
|
||||
}
|
||||
|
|
@ -8,8 +8,16 @@ enum class OrderStatus {
|
|||
;
|
||||
|
||||
/** An order is active while it is still being processed (NEW or PROCESSING). */
|
||||
val isActive: Boolean get() = this == NEW || this == PROCESSING
|
||||
val isActive: Boolean get() = activeStatuses.contains(this)
|
||||
|
||||
/** Terminal statuses (COMPLETED or CANCELED) — used to invalidate the local order hint. */
|
||||
val isTerminal: Boolean get() = this == COMPLETED || this == CANCELED
|
||||
val isTerminal: Boolean get() = terminalStatuses.contains(this)
|
||||
|
||||
companion object {
|
||||
/** Statuses of an in-flight order (still being processed). */
|
||||
val activeStatuses: Set<OrderStatus> = setOf(NEW, PROCESSING)
|
||||
|
||||
/** Statuses of a finished order — no further state changes are expected. */
|
||||
val terminalStatuses: Set<OrderStatus> = setOf(COMPLETED, CANCELED)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.tangem.domain.pay.model
|
||||
|
||||
import com.tangem.domain.pay.model.OrderType.Companion.fromString
|
||||
import com.tangem.domain.pay.model.OrderType.Companion.issueCardTypes
|
||||
|
||||
/**
|
||||
* Order type used for findOrders filtering and order-conflict checks.
|
||||
|
|
@ -10,8 +11,9 @@ import com.tangem.domain.pay.model.OrderType.Companion.fromString
|
|||
*/
|
||||
enum class OrderType(val wireValue: String) {
|
||||
CARD_ISSUE_ADDITIONAL("CARD_ISSUE_ADDITIONAL"),
|
||||
CARD_ISSUE_VIRTUAL_RAIN_KYC_V2("CARD_ISSUE_VIRTUAL_RAIN_KYC_V2"),
|
||||
CARD_ISSUE_VIRTUAL_RAIN("CARD_ISSUE_VIRTUAL_RAIN"),
|
||||
CARD_ISSUE_VIRTUAL_RAIN_KYC("CARD_ISSUE_VIRTUAL_RAIN_KYC"),
|
||||
CARD_ISSUE_VIRTUAL_RAIN_KYC_V2("CARD_ISSUE_VIRTUAL_RAIN_KYC_V2"),
|
||||
CARD_REISSUE("CARD_REISSUE"),
|
||||
CARD_FREEZE("CARD_FREEZE"),
|
||||
CARD_UNFREEZE("CARD_UNFREEZE"),
|
||||
|
|
@ -19,7 +21,29 @@ enum class OrderType(val wireValue: String) {
|
|||
UNKNOWN(""),
|
||||
;
|
||||
|
||||
/** `true` for any card-issuance order type — see [issueCardTypes]. */
|
||||
val isIssuing: Boolean get() = issueCardTypes.contains(this)
|
||||
|
||||
/** `true` for card freeze / unfreeze orders. */
|
||||
val isFreezingUnfreezing: Boolean get() = this == CARD_FREEZE || this == CARD_UNFREEZE
|
||||
|
||||
/** `true` for card reissue orders. */
|
||||
val isReissuing: Boolean get() = this == CARD_REISSUE
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* All order types that represent issuing a card: the first virtual card (and its KYC
|
||||
* variants) and an additional card. Used both to filter `findOrders` and to detect
|
||||
* issue-card conflicts.
|
||||
*/
|
||||
val issueCardTypes = setOf(
|
||||
CARD_ISSUE_ADDITIONAL,
|
||||
CARD_ISSUE_VIRTUAL_RAIN,
|
||||
CARD_ISSUE_VIRTUAL_RAIN_KYC,
|
||||
CARD_ISSUE_VIRTUAL_RAIN_KYC_V2,
|
||||
)
|
||||
|
||||
fun fromString(value: String?): OrderType {
|
||||
if (value.isNullOrBlank()) return UNKNOWN
|
||||
return entries.firstOrNull { it.wireValue == value || it.name == value } ?: UNKNOWN
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import arrow.core.raise.catch
|
|||
import arrow.core.raise.either
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.Offer
|
||||
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.CustomerOffersRepository
|
||||
|
|
@ -56,11 +57,8 @@ class IssueAdditionalCardUseCase(
|
|||
customerOrderRepository
|
||||
.findOrders(
|
||||
userWalletId = userWalletId,
|
||||
types = setOf(
|
||||
offer.data.orderType,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC_V2,
|
||||
),
|
||||
types = setOf(offer.data.orderType) + OrderType.issueCardTypes,
|
||||
statuses = OrderStatus.activeStatuses,
|
||||
)
|
||||
.bind()
|
||||
},
|
||||
|
|
|
|||
|
|
@ -26,6 +26,15 @@ internal class OrderConflictRulesTest {
|
|||
assertThat(resolution).isInstanceOf(ConflictResolution.Blocked::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `IssueCard is blocked by an active plain virtual-card issue order`() {
|
||||
val active = listOf(order(type = OrderType.CARD_ISSUE_VIRTUAL_RAIN, status = OrderStatus.PROCESSING))
|
||||
|
||||
val resolution = OrderConflictRules.resolve(OrderIntent.IssueCard, active)
|
||||
|
||||
assertThat(resolution).isInstanceOf(ConflictResolution.Blocked::class.java)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `IssueCard is allowed when only withdraw is active`() {
|
||||
val active = listOf(order(type = OrderType.WITHDRAW, status = OrderStatus.PROCESSING))
|
||||
|
|
|
|||
|
|
@ -67,10 +67,11 @@ internal class IssueAdditionalCardUseCaseTest {
|
|||
userWalletId,
|
||||
types = setOf(
|
||||
OrderType.CARD_ISSUE_ADDITIONAL,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC_V2,
|
||||
),
|
||||
statuses = emptySet(),
|
||||
statuses = setOf(OrderStatus.NEW, OrderStatus.PROCESSING),
|
||||
)
|
||||
} returns listOf(existing).right()
|
||||
|
||||
|
|
@ -89,10 +90,11 @@ internal class IssueAdditionalCardUseCaseTest {
|
|||
userWalletId,
|
||||
types = setOf(
|
||||
OrderType.CARD_ISSUE_ADDITIONAL,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC_V2,
|
||||
),
|
||||
statuses = emptySet(),
|
||||
statuses = setOf(OrderStatus.NEW, OrderStatus.PROCESSING),
|
||||
)
|
||||
} returns emptyList<Order>().right()
|
||||
coEvery {
|
||||
|
|
@ -117,10 +119,11 @@ internal class IssueAdditionalCardUseCaseTest {
|
|||
userWalletId,
|
||||
types = setOf(
|
||||
OrderType.CARD_ISSUE_ADDITIONAL,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC,
|
||||
OrderType.CARD_ISSUE_VIRTUAL_RAIN_KYC_V2,
|
||||
),
|
||||
statuses = emptySet(),
|
||||
statuses = setOf(OrderStatus.NEW, OrderStatus.PROCESSING),
|
||||
)
|
||||
} returns emptyList<Order>().right()
|
||||
val newOrder = order(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue