Skip to content

Commit aef01d1

Browse files
nomanrangelix
authored andcommitted
feat: select last successful purchase provider for meld quotes
1 parent 0e41cda commit aef01d1

File tree

19 files changed

+355
-71
lines changed

19 files changed

+355
-71
lines changed

common/src/commonMain/kotlin/com/blockstream/common/di/CommonModule.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.blockstream.domain.hardware.VerifyAddressUseCase
1212
import com.blockstream.domain.meld.CreateCryptoQuoteUseCase
1313
import com.blockstream.domain.meld.CreateCryptoWidgetUseCase
1414
import com.blockstream.domain.meld.DefaultValuesUseCase
15+
import com.blockstream.domain.meld.GetLastSuccessfulPurchaseExchange
1516
import com.blockstream.domain.meld.MeldUseCase
1617
import com.blockstream.domain.navigation.NavigateToWallet
1718
import com.blockstream.green.data.dataModule
@@ -65,4 +66,8 @@ val commonModule = module {
6566
factory {
6667
ObserveBitcoinPriceHistory(get())
6768
}
69+
70+
factory {
71+
GetLastSuccessfulPurchaseExchange(get())
72+
}
6873
}

common/src/commonMain/kotlin/com/blockstream/common/models/exchange/BuyViewModel.kt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import com.blockstream.common.sideeffects.SideEffects
2626
import com.blockstream.common.utils.StringHolder
2727
import com.blockstream.common.utils.UserInput
2828
import com.blockstream.domain.hardware.VerifyAddressUseCase
29+
import com.blockstream.domain.meld.GetLastSuccessfulPurchaseExchange
2930
import com.blockstream.domain.meld.MeldUseCase
3031
import com.blockstream.green.data.meld.data.QuoteResponse
3132
import com.blockstream.green.data.meld.data.QuotesResponse
@@ -57,6 +58,7 @@ abstract class BuyViewModelAbstract(
5758
internal val meldUseCase: MeldUseCase by inject()
5859
internal val verifyAddressUseCase: VerifyAddressUseCase by inject()
5960
private val localeManager: LocaleManager by inject()
61+
internal val getLastSuccessfulPurchaseExchange: GetLastSuccessfulPurchaseExchange by inject()
6062

6163
abstract val showRecoveryConfirmation: StateFlow<Boolean>
6264
abstract val showAccountSelector: StateFlow<Boolean>
@@ -177,6 +179,11 @@ class BuyViewModel(greenWallet: GreenWallet) :
177179
// Default to Fiat denomination
178180
_denomination.value = Denomination.defaultOrFiat(session, isFiat = true)
179181

182+
183+
viewModelScope.launch {
184+
getLastSuccessfulPurchaseExchange(GetLastSuccessfulPurchaseExchange.Params(greenWallet.xPubHashId))
185+
}
186+
180187
session.ifConnected {
181188
val accounts = session.accounts.value.filter { it.isBitcoin }
182189

@@ -201,17 +208,22 @@ class BuyViewModel(greenWallet: GreenWallet) :
201208
}
202209

203210

204-
quotes.onEach { list ->
211+
combine(quotes, getLastSuccessfulPurchaseExchange.observe()) { quotesList: List<QuoteResponse>, lastProvider: String? ->
205212
_quote.value = quote.value?.takeIf { userPickedQuote.value }?.let { quote ->
206-
// keep the same provider
207-
list.find {
213+
// keep the same provider if user picked it
214+
quotesList.find {
208215
it.serviceProvider == quote.serviceProvider
209216
}
210-
} ?: list.firstOrNull()?.also {
217+
} ?: lastProvider?.let { provider ->
218+
// otherwise, try to find the last successful provider
219+
quotesList.find { it.serviceProvider == provider }
220+
} ?: quotesList.firstOrNull()?.also {
221+
// fallback to first available quote
211222
userPickedQuote.value = false
212223
}
213224
}.launchIn(this)
214225

226+
215227
session.ifConnected {
216228
combine(amount, country) { amount, _ ->
217229
updateQuotes(amount)

common/src/commonMain/kotlin/com/blockstream/domain/meld/CreateCryptoWidgetUseCase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import com.blockstream.green.data.meld.data.CryptoWidget
66
import com.blockstream.green.data.meld.data.QuoteResponse
77
import com.blockstream.green.network.NetworkResponse
88

9-
class CreateCryptoWidgetUseCase constructor(
9+
class CreateCryptoWidgetUseCase(
1010
private val meldRepository: MeldRepository
1111
) {
1212
suspend operator fun invoke(
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.blockstream.domain.meld
2+
3+
import com.blockstream.green.data.meld.MeldRepository
4+
import com.blockstream.green.data.meld.data.MeldTransactionStatus
5+
import com.blockstream.green.domain.base.NetworkBoundInMemoryUseCase
6+
import com.blockstream.green.network.NetworkResponse
7+
import kotlinx.coroutines.flow.Flow
8+
9+
class GetLastSuccessfulPurchaseExchange(
10+
private val meldRepository: MeldRepository
11+
) : NetworkBoundInMemoryUseCase<GetLastSuccessfulPurchaseExchange.Params, String?>() {
12+
override suspend fun doWork(params: Params) {
13+
val response = meldRepository.getTransactions(params.externalCustomerId, listOf(MeldTransactionStatus.SETTLED))
14+
15+
if (response is NetworkResponse.Success && response.data.transactions.isNotEmpty()) {
16+
set(response.data.transactions.first().serviceProvider)
17+
}
18+
}
19+
20+
override fun createObservable(params: Params): Flow<String?> {
21+
return get()
22+
}
23+
24+
data class Params(
25+
val externalCustomerId: String
26+
)
27+
28+
}

data/src/commonMain/kotlin/com/blockstream/green/data/DataModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import org.koin.dsl.module
77
//expect val platformDataModule: Module
88

99
val dataModule = module {
10-
single { GreenWebooksHttpClient(get()) }
10+
single { GreenWebhooksHttpClient(get()) }
1111

1212
includes(meldModule)
1313
includes(notificationsDataModule)

data/src/commonMain/kotlin/com/blockstream/green/data/GreenWebooksHttpClient.kt renamed to data/src/commonMain/kotlin/com/blockstream/green/data/GreenWebhooksHttpClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import com.blockstream.green.data.config.AppInfo
44
import com.blockstream.green.network.AppHttpClient
55
import io.ktor.client.plugins.defaultRequest
66

7-
class GreenWebooksHttpClient(appInfo: AppInfo) : AppHttpClient(appInfo.isDevelopmentOrDebug, {
7+
class GreenWebhooksHttpClient(appInfo: AppInfo) : AppHttpClient(appInfo.isDevelopmentOrDebug, {
88
defaultRequest {
99
url(if (appInfo.isProduction) BASE_URL else DEV_BASE_URL)
1010
}

data/src/commonMain/kotlin/com/blockstream/green/data/meld/MeldRepository.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ import com.blockstream.green.data.meld.data.CryptoQuoteRequest
55
import com.blockstream.green.data.meld.data.CryptoWidget
66
import com.blockstream.green.data.meld.data.CryptoWidgetRequest
77
import com.blockstream.green.data.meld.data.LimitsResponse
8+
import com.blockstream.green.data.meld.data.MeldTransactionStatus
89
import com.blockstream.green.data.meld.data.QuotesResponse
910
import com.blockstream.green.data.meld.datasource.MeldLocalDataSource
1011
import com.blockstream.green.data.meld.datasource.MeldRemoteDataSource
1112
import com.blockstream.green.data.meld.models.Country
13+
import com.blockstream.green.data.meld.models.MeldTransactionResponse
1214
import com.blockstream.green.network.NetworkResponse
1315

1416
class MeldRepository(
@@ -26,8 +28,10 @@ class MeldRepository(
2628
return remoteDataSource.getCryptoLimits(fiatCurrency)
2729
}
2830

29-
suspend fun getTransactions(externalCustomerId: String): NetworkResponse<LimitsResponse> {
30-
return remoteDataSource.getTransactions(externalCustomerId)
31+
suspend fun getTransactions(
32+
externalCustomerId: String, statuses: List<MeldTransactionStatus> = emptyList()
33+
): NetworkResponse<MeldTransactionResponse> {
34+
return remoteDataSource.getTransactions(externalCustomerId, statuses)
3135
}
3236

3337
suspend fun getCountries(): NetworkResponse<List<Country>> {
@@ -44,6 +48,7 @@ class MeldRepository(
4448
localDataSource.saveCountries(countriesWithEmojis)
4549
NetworkResponse.Success(countriesWithEmojis)
4650
}
51+
4752
is NetworkResponse.Error -> response
4853
}
4954
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.blockstream.green.data.meld.data
2+
3+
enum class MeldTransactionStatus {
4+
PENDING_CREATED,
5+
PENDING,
6+
PROCESSING,
7+
AUTHORIZED,
8+
AUTHORIZATION_EXPIRED,
9+
SETTLING,
10+
SETTLED,
11+
REFUNDED,
12+
DECLINED,
13+
CANCELLED,
14+
FAILED,
15+
ERROR,
16+
VOIDED,
17+
TWO_FA_REQUIRED,
18+
TWO_FA_PROVIDED
19+
}

data/src/commonMain/kotlin/com/blockstream/green/data/meld/data/Resources.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ object Resources {
88
class Payments() {
99

1010
@Resource("transactions")
11-
class Transactions(val parent: Payments = Payments(), val externalCustomerIds: String)
11+
class Transactions(val parent: Payments = Payments(), val externalCustomerIds: String, val statuses: String)
1212

1313
@Resource("crypto")
1414
class Crypto(val parent: Payments = Payments()) {

data/src/commonMain/kotlin/com/blockstream/green/data/meld/datasource/MeldRemoteDataSource.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,11 @@ import com.blockstream.green.data.meld.data.CryptoQuoteRequest
55
import com.blockstream.green.data.meld.data.CryptoWidget
66
import com.blockstream.green.data.meld.data.CryptoWidgetRequest
77
import com.blockstream.green.data.meld.data.LimitsResponse
8+
import com.blockstream.green.data.meld.data.MeldTransactionStatus
89
import com.blockstream.green.data.meld.data.QuotesResponse
910
import com.blockstream.green.data.meld.data.Resources
1011
import com.blockstream.green.data.meld.models.Country
12+
import com.blockstream.green.data.meld.models.MeldTransactionResponse
1113
import com.blockstream.green.network.NetworkResponse
1214

1315
class MeldRemoteDataSource(
@@ -25,8 +27,11 @@ class MeldRemoteDataSource(
2527
return client.get(Resources.Payments.Crypto.Limits(fiatCurrency = fiatCurrency))
2628
}
2729

28-
suspend fun getTransactions(externalCustomerId: String): NetworkResponse<LimitsResponse> {
29-
return client.get(Resources.Payments.Transactions(externalCustomerIds = externalCustomerId))
30+
suspend fun getTransactions(
31+
externalCustomerId: String,
32+
statuses: List<MeldTransactionStatus> = emptyList()
33+
): NetworkResponse<MeldTransactionResponse> {
34+
return client.get(Resources.Payments.Transactions(externalCustomerIds = externalCustomerId, statuses = statuses.joinToString(",")))
3035
}
3136

3237
suspend fun getCountries(): NetworkResponse<List<Country>> {

0 commit comments

Comments
 (0)