Skip to content

Commit

Permalink
Call new elements/detach endpoint for customer sessions. (#9801)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaynewstrom-stripe authored Dec 18, 2024
1 parent 976faec commit aeb503c
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,15 @@ abstract class AbsFakeStripeRepository : StripeRepository {
TODO("Not yet implemented")
}

override suspend fun detachPaymentMethod(
customerSessionClientSecret: String,
productUsageTokens: Set<String>,
paymentMethodId: String,
requestOptions: ApiRequest.Options
): Result<PaymentMethod> {
TODO("Not yet implemented")
}

override suspend fun getPaymentMethods(
listPaymentMethodsParams: ListPaymentMethodsParams,
productUsageTokens: Set<String>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,36 @@ class StripeApiRepository @JvmOverloads internal constructor(
}
}

/**
* Analytics event: [PaymentAnalyticsEvent.CustomerDetachPaymentMethod]
*/
@Throws(
InvalidRequestException::class,
APIConnectionException::class,
APIException::class,
AuthenticationException::class,
CardException::class
)
override suspend fun detachPaymentMethod(
customerSessionClientSecret: String,
productUsageTokens: Set<String>,
paymentMethodId: String,
requestOptions: ApiRequest.Options
): Result<PaymentMethod> {
return fetchStripeModelResult(
apiRequest = apiRequestFactory.createPost(
url = getElementsDetachPaymentMethodUrl(paymentMethodId),
options = requestOptions,
params = mapOf("customer_session_client_secret" to customerSessionClientSecret),
),
jsonParser = PaymentMethodJsonParser()
) {
fireAnalyticsRequest(
paymentAnalyticsRequestFactory.createDetachPaymentMethod(productUsageTokens)
)
}
}

/**
* Retrieve a Customer's [PaymentMethod]s
*
Expand Down Expand Up @@ -1383,6 +1413,14 @@ class StripeApiRepository @JvmOverloads internal constructor(
return getApiUrl("payment_methods/%s/detach", paymentMethodId)
}

/**
* @return `https://api.stripe.com/v1/payment_methods/:id/detach`
*/
@VisibleForTesting
internal fun getElementsDetachPaymentMethodUrl(paymentMethodId: String): String {
return getApiUrl("elements/payment_methods/%s/detach", paymentMethodId)
}

override suspend fun retrieveElementsSession(
params: ElementsSessionParams,
options: ApiRequest.Options,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@ interface StripeRepository {
requestOptions: ApiRequest.Options
): Result<PaymentMethod>

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
suspend fun detachPaymentMethod(
customerSessionClientSecret: String,
productUsageTokens: Set<String>,
paymentMethodId: String,
requestOptions: ApiRequest.Options
): Result<PaymentMethod>

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
suspend fun getPaymentMethods(
listPaymentMethodsParams: ListPaymentMethodsParams,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,18 @@ internal class StripeApiRepositoryTest {
assertThat(detachUrl).isEqualTo(expectedUrl)
}

@Test
fun testGetElementsDetachPaymentMethodUrl() {
val paymentMethodId = "pm_1ETDEa2eZvKYlo2CN5828c52"
val detachUrl = stripeApiRepository.getElementsDetachPaymentMethodUrl(paymentMethodId)
val expectedUrl = arrayOf(
"https://api.stripe.com/v1/elements/payment_methods/",
paymentMethodId,
"/detach"
).joinToString("")
assertThat(detachUrl).isEqualTo(expectedUrl)
}

@Test
fun testGetPaymentMethodsUrl() {
assertThat(StripeApiRepository.paymentMethodsUrl)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,14 +113,26 @@ internal class CustomerApiRepository @Inject constructor(
paymentMethodId
)
} else {
stripeRepository.detachPaymentMethod(
productUsageTokens = productUsageTokens,
paymentMethodId = paymentMethodId,
requestOptions = ApiRequest.Options(
apiKey = customerInfo.ephemeralKeySecret,
stripeAccount = lazyPaymentConfig.get().stripeAccountId,
if (customerInfo.customerSessionClientSecret != null) {
stripeRepository.detachPaymentMethod(
customerSessionClientSecret = customerInfo.customerSessionClientSecret,
productUsageTokens = productUsageTokens,
paymentMethodId = paymentMethodId,
requestOptions = ApiRequest.Options(
apiKey = customerInfo.ephemeralKeySecret,
stripeAccount = lazyPaymentConfig.get().stripeAccountId,
)
)
)
} else {
stripeRepository.detachPaymentMethod(
productUsageTokens = productUsageTokens,
paymentMethodId = paymentMethodId,
requestOptions = ApiRequest.Options(
apiKey = customerInfo.ephemeralKeySecret,
stripeAccount = lazyPaymentConfig.get().stripeAccountId,
)
)
}
}

return result.onFailure {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ class CustomerSessionCustomerSheetActivityTest {
networkRule.enqueue(
host("api.stripe.com"),
method("POST"),
path("/v1/payment_methods/$id/detach")
path("/v1/elements/payment_methods/$id/detach")
) { response ->
response.createPaymentMethodDetachResponse(id = id)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,28 @@ internal class CustomerRepositoryTest {
assertThat(result.isFailure).isTrue()
}

@Test
fun `detachPaymentMethod() should call elements endpoint when customerSessionClientSecret exists`() =
runTest {
givenElementsDetachPaymentMethodReturns(
Result.success(
PaymentMethodFixtures.CARD_PAYMENT_METHOD
)
)

val result = repository.detachPaymentMethod(
customerInfo = CustomerRepository.CustomerInfo(
id = "customer_id",
ephemeralKeySecret = "ephemeral_key",
customerSessionClientSecret = "cuss_123",
),
paymentMethodId = "payment_method_id",
canRemoveDuplicates = false,
)

assertThat(result.getOrNull()).isEqualTo(PaymentMethodFixtures.CARD_PAYMENT_METHOD)
}

@Test
fun `detachPaymentMethod() with 'canRemoveDuplicates' as 'true' should remove duplicate payment methods and remove provided payment method ID last`() =
runTest {
Expand Down Expand Up @@ -643,6 +665,21 @@ internal class CustomerRepositoryTest {
}
}

private fun givenElementsDetachPaymentMethodReturns(
result: Result<PaymentMethod>
) {
stripeRepository.stub {
onBlocking {
detachPaymentMethod(
customerSessionClientSecret = any(),
productUsageTokens = any(),
paymentMethodId = anyString(),
requestOptions = any(),
)
}.doReturn(result)
}
}

private fun givenAttachPaymentMethodReturns(
result: Result<PaymentMethod>
) {
Expand Down

0 comments on commit aeb503c

Please sign in to comment.