Skip to content

Commit

Permalink
Filter CustomerSheet saved payment methods the same as we filter paym…
Browse files Browse the repository at this point in the history
…ent sheet payment methods. (#7587)
  • Loading branch information
jaynewstrom-stripe authored Nov 3, 2023
1 parent 341170f commit cfffa1d
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 75 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.stripe.android.core.networking.ApiRequest
import com.stripe.android.model.Customer
import com.stripe.android.model.ListPaymentMethodsParams
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.wallets.Wallet
import com.stripe.android.networking.StripeRepository
import com.stripe.android.payments.core.injection.PRODUCT_USAGE
import com.stripe.android.paymentsheet.PaymentSheet
Expand Down Expand Up @@ -50,7 +51,13 @@ internal class CustomerApiRepository @Inject constructor(
types: List<PaymentMethod.Type>,
silentlyFail: Boolean,
): Result<List<PaymentMethod>> = withContext(workContext) {
val requests = types.map { paymentMethodType ->
val requests = types.filter { paymentMethodType ->
paymentMethodType in setOf(
PaymentMethod.Type.Card,
PaymentMethod.Type.USBankAccount,
PaymentMethod.Type.SepaDebit,
)
}.map { paymentMethodType ->
async {
stripeRepository.getPaymentMethods(
listPaymentMethodsParams = ListPaymentMethodsParams(
Expand All @@ -76,8 +83,15 @@ internal class CustomerApiRepository @Inject constructor(
return@withContext Result.failure(it)
}
},
onSuccess = {
paymentMethods.addAll(it)
onSuccess = { customerPaymentMethods ->
val walletTypesToRemove = setOf(Wallet.Type.ApplePay, Wallet.Type.GooglePay, Wallet.Type.SamsungPay)
paymentMethods.addAll(
customerPaymentMethods.filter { paymentMethod ->
val isCardWithWallet = paymentMethod.type == PaymentMethod.Type.Card &&
walletTypesToRemove.contains(paymentMethod.card?.wallet?.walletType)
!isCardWithWallet
}
)
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import com.stripe.android.model.ElementsSession
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.PaymentMethod.Type.Link
import com.stripe.android.model.StripeIntent
import com.stripe.android.model.wallets.Wallet
import com.stripe.android.payments.core.injection.APP_NAME
import com.stripe.android.paymentsheet.PaymentSheet
import com.stripe.android.paymentsheet.PaymentSheet.InitializationMode.DeferredIntent
Expand Down Expand Up @@ -216,23 +215,11 @@ internal class DefaultPaymentSheetLoader @Inject constructor(
PaymentMethod.Type.fromCode(it.code)
}

val walletTypesToRemove = setOf(Wallet.Type.ApplePay, Wallet.Type.GooglePay, Wallet.Type.SamsungPay)

val paymentMethods = customerRepository.getPaymentMethods(
customerConfig = customerConfig,
types = paymentMethodTypes.filter { paymentMethodType ->
paymentMethodType in setOf(
PaymentMethod.Type.Card,
PaymentMethod.Type.USBankAccount,
PaymentMethod.Type.SepaDebit,
)
},
types = paymentMethodTypes,
silentlyFail = true,
).getOrDefault(emptyList()).filter { paymentMethod ->
val isCardWithWallet = paymentMethod.type == PaymentMethod.Type.Card &&
walletTypesToRemove.contains(paymentMethod.card?.wallet?.walletType)
!isCardWithWallet
}
).getOrDefault(emptyList())

return paymentMethods.filter { paymentMethod ->
paymentMethod.hasExpectedDetails()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import com.stripe.android.core.Logger
import com.stripe.android.model.ListPaymentMethodsParams
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.PaymentMethodFixtures
import com.stripe.android.model.wallets.Wallet
import com.stripe.android.networking.StripeRepository
import com.stripe.android.paymentsheet.PaymentSheet
import kotlinx.coroutines.test.UnconfinedTestDispatcher
Expand Down Expand Up @@ -64,6 +65,80 @@ internal class CustomerRepositoryTest {
)
}

// PayPal isn't supported as a saved payment method due to issues with on-session.
// See: https://docs.google.com/document/d/1_bCPJXxhV4Kdgy7LX7HPwpZfElN3a2DcYUooiWC9SgM
@Test
fun `getPaymentMethods() should filter unsupported payment method types`() =
runTest {
givenGetPaymentMethodsReturns(
Result.success(emptyList())
)

repository.getPaymentMethods(
PaymentSheet.CustomerConfiguration(
"customer_id",
"ephemeral_key"
),
listOf(PaymentMethod.Type.Card, PaymentMethod.Type.PayPal),
true,
)

verify(stripeRepository).getPaymentMethods(
listPaymentMethodsParams = eq(
ListPaymentMethodsParams(
customerId = "customer_id",
paymentMethodType = PaymentMethod.Type.Card
)
),
productUsageTokens = any(),
requestOptions = any()
)
}

@Test
fun `getPaymentMethods() should filter cards attached to wallets`() =
runTest {
givenGetPaymentMethodsReturns(
Result.success(emptyList())
)

val mockedReturnPaymentMethods = listOf(
PaymentMethodFixtures.CARD_PAYMENT_METHOD,
PaymentMethodFixtures.CARD_PAYMENT_METHOD.copy(
card = PaymentMethodFixtures.CARD_PAYMENT_METHOD.copy(id = "filtered").card?.copy(
wallet = Wallet.GooglePayWallet("3000")
)
)
)

stripeRepository.stub {
onBlocking {
getPaymentMethods(
listPaymentMethodsParams = eq(
ListPaymentMethodsParams(
customerId = "customer_id",
paymentMethodType = PaymentMethod.Type.Card
)
),
productUsageTokens = any(),
requestOptions = any()
)
}.thenReturn(Result.success(mockedReturnPaymentMethods))
}

val result = repository.getPaymentMethods(
PaymentSheet.CustomerConfiguration(
"customer_id",
"ephemeral_key"
),
listOf(PaymentMethod.Type.Card),
true,
).getOrThrow()

assertThat(result).hasSize(1)
assertThat(result[0].id).isEqualTo("pm_123456789")
}

@Test
fun `getPaymentMethods() should return empty list on failure when silent failures`() =
runTest {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -324,31 +324,6 @@ internal class DefaultPaymentSheetLoaderTest {
.containsExactly(PaymentMethodFixtures.CARD_PAYMENT_METHOD)
}

@Test
fun `load() with customer should filter out cards attached to a filtered wallet`() =
runTest {
val result = createPaymentSheetLoader(
customerRepo = FakeCustomerRepository(
listOf(
PaymentMethodFixtures.CARD_PAYMENT_METHOD,
PaymentMethodFixtures.CARD_PAYMENT_METHOD.copy(
card = PaymentMethodFixtures.CARD_PAYMENT_METHOD.card?.copy(
wallet = Wallet.GooglePayWallet("3000")
)
)
)
)
).load(
initializationMode = PaymentSheet.InitializationMode.PaymentIntent(
clientSecret = PaymentSheetFixtures.PAYMENT_INTENT_CLIENT_SECRET.value,
),
PaymentSheetFixtures.CONFIG_CUSTOMER_WITH_GOOGLEPAY
).getOrThrow()

assertThat(result.customerPaymentMethods)
.containsExactly(PaymentMethodFixtures.CARD_PAYMENT_METHOD)
}

@Test
fun `load() with customer should not filter out cards attached to a wallet`() =
runTest {
Expand All @@ -375,38 +350,6 @@ internal class DefaultPaymentSheetLoaderTest {
.containsExactly(PaymentMethodFixtures.CARD_PAYMENT_METHOD, cardWithAmexWallet)
}

// PayPal isn't supported as a saved payment method due to issues with on-session.
// See: https://docs.google.com/document/d/1_bCPJXxhV4Kdgy7LX7HPwpZfElN3a2DcYUooiWC9SgM
@Test
fun `load() with customer should filter out PayPal`() = runTest {
var requestPaymentMethodTypes: List<PaymentMethod.Type>? = null
val result = createPaymentSheetLoader(
customerRepo = object : FakeCustomerRepository() {
override suspend fun getPaymentMethods(
customerConfig: PaymentSheet.CustomerConfiguration,
types: List<PaymentMethod.Type>,
silentlyFail: Boolean
): Result<List<PaymentMethod>> {
requestPaymentMethodTypes = types
return Result.success(listOf(PaymentMethodFixtures.CARD_PAYMENT_METHOD))
}
},
stripeIntent = PaymentIntentFixtures.PI_REQUIRES_PAYMENT_METHOD.copy(
paymentMethodTypes = listOf("card", "paypal")
)
).load(
initializationMode = PaymentSheet.InitializationMode.PaymentIntent(
clientSecret = PaymentSheetFixtures.CLIENT_SECRET,
),
paymentSheetConfiguration = PaymentSheetFixtures.CONFIG_CUSTOMER,
).getOrThrow()

assertThat(result.customerPaymentMethods)
.containsExactly(PaymentMethodFixtures.CARD_PAYMENT_METHOD)
assertThat(requestPaymentMethodTypes)
.containsExactly(PaymentMethod.Type.Card)
}

@Test
fun `load() with customer should allow sepa`() = runTest {
var requestPaymentMethodTypes: List<PaymentMethod.Type>? = null
Expand Down

0 comments on commit cfffa1d

Please sign in to comment.