Updated on 2026-08-14
This commit is contained in:
parent
76cfb2e462
commit
5ca696d677
17 changed files with 431 additions and 0 deletions
|
|
@ -301,6 +301,11 @@ internal interface TangemPayDataModule {
|
|||
return GetCustomerOffersUseCase(customerOffersRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideGetCashbackSummaryUseCase(cashbackRepository: CashbackRepository): GetCashbackSummaryUseCase {
|
||||
return GetCashbackSummaryUseCase(cashbackRepository)
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideCheckOrderConflictUseCase(
|
||||
customerOrderRepository: CustomerOrderRepository,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package com.tangem.data.pay.repository
|
||||
|
||||
import arrow.core.Either
|
||||
import com.tangem.data.pay.util.CashbackSummaryConverter
|
||||
import com.tangem.datasource.api.pay.TangemPayApi
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.CashbackSummary
|
||||
import com.tangem.domain.pay.repository.CashbackRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class DefaultCashbackRepository @Inject constructor(
|
||||
private val tangemPayApi: TangemPayApi,
|
||||
private val requestHelper: TangemPayRequestPerformer,
|
||||
) : CashbackRepository {
|
||||
|
||||
override suspend fun getCashbackSummary(userWalletId: UserWalletId): Either<VisaApiError, CashbackSummary> {
|
||||
return requestHelper.performRequest(userWalletId) { authHeader ->
|
||||
tangemPayApi.getCashbackSummary(authHeader = authHeader)
|
||||
}.map(CashbackSummaryConverter::convert)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.tangem.data.pay.util
|
||||
|
||||
import com.tangem.datasource.api.pay.models.response.CashbackSummaryResponse
|
||||
import com.tangem.domain.pay.model.CashbackDisplayMode
|
||||
import com.tangem.domain.pay.model.CashbackProgramStatus
|
||||
import com.tangem.domain.pay.model.CashbackSummary
|
||||
import com.tangem.domain.pay.model.TangemPayCashback
|
||||
import com.tangem.utils.converter.Converter
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
|
||||
/** Maps [CashbackSummaryResponse] (BFF) to the domain [CashbackSummary]. */
|
||||
internal object CashbackSummaryConverter : Converter<CashbackSummaryResponse, CashbackSummary> {
|
||||
|
||||
override fun convert(value: CashbackSummaryResponse): CashbackSummary {
|
||||
return when (CashbackProgramStatus.fromString(value.cashbackProgramStatus)) {
|
||||
CashbackProgramStatus.ENABLED -> toEnabled(value)
|
||||
CashbackProgramStatus.DEACTIVATED -> CashbackSummary.Deactivated
|
||||
CashbackProgramStatus.DISABLED -> CashbackSummary.Disabled
|
||||
CashbackProgramStatus.UNKNOWN -> CashbackSummary.Unknown
|
||||
}
|
||||
}
|
||||
|
||||
private fun toEnabled(value: CashbackSummaryResponse): CashbackSummary {
|
||||
val period = value.period ?: return CashbackSummary.Unknown
|
||||
val payoutStart = period.payoutStartDate?.let(DateTime::parse) ?: return CashbackSummary.Unknown
|
||||
val payoutEnd = period.payoutEndDate?.let(DateTime::parse) ?: return CashbackSummary.Unknown
|
||||
|
||||
return CashbackSummary.Enabled(
|
||||
displayMode = CashbackDisplayMode.fromString(value.cashbackDisplayMode),
|
||||
cashback = TangemPayCashback(
|
||||
confirmedAmount = value.confirmedAmount ?: BigDecimal.ZERO,
|
||||
currency = value.currency.orEmpty(),
|
||||
period = TangemPayCashback.Period(
|
||||
year = period.year,
|
||||
month = period.month,
|
||||
payoutStart = payoutStart,
|
||||
payoutEnd = payoutEnd,
|
||||
),
|
||||
),
|
||||
pendingAmount = value.pendingAmount ?: BigDecimal.ZERO,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.data.pay.di
|
||||
|
||||
import com.tangem.data.pay.repository.MockAwareCashbackRepository
|
||||
import com.tangem.data.pay.repository.MockAwareOnboardingRepository
|
||||
import com.tangem.data.pay.repository.MockAwareTangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.repository.CashbackRepository
|
||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import dagger.Binds
|
||||
|
|
@ -21,4 +23,8 @@ internal interface TangemPayDataMockedModule {
|
|||
@Binds
|
||||
@Singleton
|
||||
fun bindCardDetailsRepository(repository: MockAwareTangemPayCardDetailsRepository): TangemPayCardDetailsRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindCashbackRepository(repository: MockAwareCashbackRepository): CashbackRepository
|
||||
}
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
package com.tangem.data.pay.repository
|
||||
|
||||
import arrow.core.Either
|
||||
import arrow.core.right
|
||||
import com.tangem.datasource.api.common.config.ApiConfig
|
||||
import com.tangem.datasource.api.common.config.ApiEnvironment
|
||||
import com.tangem.datasource.api.common.config.managers.ApiConfigsManager
|
||||
import com.tangem.domain.models.wallet.UserWalletId
|
||||
import com.tangem.domain.pay.model.CashbackDisplayMode
|
||||
import com.tangem.domain.pay.model.CashbackSummary
|
||||
import com.tangem.domain.pay.model.TangemPayCashback
|
||||
import com.tangem.domain.pay.repository.CashbackRepository
|
||||
import com.tangem.domain.visa.error.VisaApiError
|
||||
import org.joda.time.DateTime
|
||||
import java.math.BigDecimal
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
/** In MOCK env returns a canned cashback summary; otherwise delegates to [DefaultCashbackRepository]. */
|
||||
@Singleton
|
||||
internal class MockAwareCashbackRepository @Inject constructor(
|
||||
private val real: DefaultCashbackRepository,
|
||||
private val apiConfigsManager: ApiConfigsManager,
|
||||
) : CashbackRepository {
|
||||
|
||||
private val isMockMode: Boolean
|
||||
get() = apiConfigsManager
|
||||
.getEnvironmentConfig(ApiConfig.ID.TangemPay)
|
||||
.environment == ApiEnvironment.MOCK
|
||||
|
||||
override suspend fun getCashbackSummary(userWalletId: UserWalletId): Either<VisaApiError, CashbackSummary> {
|
||||
if (isMockMode) return MOCK_SUMMARY.right()
|
||||
return real.getCashbackSummary(userWalletId)
|
||||
}
|
||||
|
||||
private companion object {
|
||||
val MOCK_SUMMARY = CashbackSummary.Enabled(
|
||||
displayMode = CashbackDisplayMode.FULL,
|
||||
cashback = TangemPayCashback(
|
||||
confirmedAmount = BigDecimal("22.54"),
|
||||
currency = "USD",
|
||||
period = TangemPayCashback.Period(
|
||||
year = 2026,
|
||||
month = 6,
|
||||
payoutStart = DateTime.parse("2026-07-02"),
|
||||
payoutEnd = DateTime.parse("2026-07-05"),
|
||||
),
|
||||
),
|
||||
pendingAmount = BigDecimal("13.65"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.tangem.data.pay.di
|
||||
|
||||
import com.tangem.data.pay.repository.DefaultCashbackRepository
|
||||
import com.tangem.data.pay.repository.DefaultOnboardingRepository
|
||||
import com.tangem.data.pay.repository.DefaultTangemPayCardDetailsRepository
|
||||
import com.tangem.domain.pay.repository.CashbackRepository
|
||||
import com.tangem.domain.pay.repository.OnboardingRepository
|
||||
import com.tangem.domain.pay.repository.TangemPayCardDetailsRepository
|
||||
import dagger.Binds
|
||||
|
|
@ -21,4 +23,8 @@ internal interface TangemPayDataProductionModule {
|
|||
@Binds
|
||||
@Singleton
|
||||
fun bindCardDetailsRepository(repository: DefaultTangemPayCardDetailsRepository): TangemPayCardDetailsRepository
|
||||
|
||||
@Binds
|
||||
@Singleton
|
||||
fun bindCashbackRepository(repository: DefaultCashbackRepository): CashbackRepository
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package com.tangem.data.pay.util
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.tangem.datasource.api.pay.models.response.CashbackSummaryResponse
|
||||
import com.tangem.domain.pay.model.CashbackDisplayMode
|
||||
import com.tangem.domain.pay.model.CashbackSummary
|
||||
import com.tangem.domain.pay.model.TangemPayCashback
|
||||
import org.joda.time.DateTime
|
||||
import org.junit.jupiter.api.TestInstance
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.MethodSource
|
||||
import java.math.BigDecimal
|
||||
|
||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||
internal class CashbackSummaryConverterTest {
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("provideTestModels")
|
||||
fun convert(model: ConvertModel) {
|
||||
// Act
|
||||
val actual = CashbackSummaryConverter.convert(model.response)
|
||||
|
||||
// Assert
|
||||
assertThat(actual).isEqualTo(model.expected)
|
||||
}
|
||||
|
||||
@Suppress("LongMethod")
|
||||
private fun provideTestModels() = listOf(
|
||||
ConvertModel(
|
||||
name = "enabled + full -> Enabled(FULL)",
|
||||
response = createResponse(status = "enabled", displayMode = "full"),
|
||||
expected = CashbackSummary.Enabled(
|
||||
displayMode = CashbackDisplayMode.FULL,
|
||||
cashback = expectedCashback(),
|
||||
pendingAmount = BigDecimal("13.65"),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
name = "enabled + alt_block -> Enabled(ALT_BLOCK)",
|
||||
response = createResponse(status = "enabled", displayMode = "alt_block"),
|
||||
expected = CashbackSummary.Enabled(
|
||||
displayMode = CashbackDisplayMode.ALT_BLOCK,
|
||||
cashback = expectedCashback(),
|
||||
pendingAmount = BigDecimal("13.65"),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
name = "enabled + missing display mode -> Enabled(FULL)",
|
||||
response = createResponse(status = "enabled", displayMode = null),
|
||||
expected = CashbackSummary.Enabled(
|
||||
displayMode = CashbackDisplayMode.FULL,
|
||||
cashback = expectedCashback(),
|
||||
pendingAmount = BigDecimal("13.65"),
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
name = "enabled + zero amounts -> Enabled with zeros",
|
||||
response = createResponse(
|
||||
status = "enabled",
|
||||
displayMode = "full",
|
||||
confirmedAmount = null,
|
||||
pendingAmount = null,
|
||||
),
|
||||
expected = CashbackSummary.Enabled(
|
||||
displayMode = CashbackDisplayMode.FULL,
|
||||
cashback = expectedCashback(confirmedAmount = BigDecimal.ZERO),
|
||||
pendingAmount = BigDecimal.ZERO,
|
||||
),
|
||||
),
|
||||
ConvertModel(
|
||||
name = "enabled but missing period -> Unknown",
|
||||
response = createResponse(status = "enabled", period = null),
|
||||
expected = CashbackSummary.Unknown,
|
||||
),
|
||||
ConvertModel(
|
||||
name = "deactivated -> Deactivated",
|
||||
response = createResponse(status = "deactivated"),
|
||||
expected = CashbackSummary.Deactivated,
|
||||
),
|
||||
ConvertModel(
|
||||
name = "disabled -> Disabled",
|
||||
response = createResponse(status = "disabled"),
|
||||
expected = CashbackSummary.Disabled,
|
||||
),
|
||||
ConvertModel(
|
||||
name = "unavailable -> Disabled",
|
||||
response = createResponse(status = "unavailable"),
|
||||
expected = CashbackSummary.Disabled,
|
||||
),
|
||||
ConvertModel(
|
||||
name = "unrecognized status -> Unknown",
|
||||
response = createResponse(status = "something_new"),
|
||||
expected = CashbackSummary.Unknown,
|
||||
),
|
||||
)
|
||||
|
||||
internal data class ConvertModel(
|
||||
val name: String,
|
||||
val response: CashbackSummaryResponse,
|
||||
val expected: CashbackSummary,
|
||||
) {
|
||||
override fun toString(): String = name
|
||||
}
|
||||
|
||||
private companion object {
|
||||
|
||||
fun createResponse(
|
||||
status: String = "enabled",
|
||||
displayMode: String? = "full",
|
||||
period: CashbackSummaryResponse.Period? = CashbackSummaryResponse.Period(
|
||||
year = 2026,
|
||||
month = 6,
|
||||
payoutStartDate = "2026-07-02",
|
||||
payoutEndDate = "2026-07-05",
|
||||
),
|
||||
confirmedAmount: BigDecimal? = BigDecimal("22.54"),
|
||||
pendingAmount: BigDecimal? = BigDecimal("13.65"),
|
||||
currency: String? = "USD",
|
||||
) = CashbackSummaryResponse(
|
||||
cashbackProgramStatus = status,
|
||||
cashbackDisplayMode = displayMode,
|
||||
period = period,
|
||||
confirmedAmount = confirmedAmount,
|
||||
pendingAmount = pendingAmount,
|
||||
currency = currency,
|
||||
)
|
||||
|
||||
fun expectedCashback(confirmedAmount: BigDecimal = BigDecimal("22.54")) = TangemPayCashback(
|
||||
confirmedAmount = confirmedAmount,
|
||||
currency = "USD",
|
||||
period = TangemPayCashback.Period(
|
||||
year = 2026,
|
||||
month = 6,
|
||||
payoutStart = DateTime.parse("2026-07-02"),
|
||||
payoutEnd = DateTime.parse("2026-07-05"),
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue