Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create PaymentIntent and SetupIntent async retrieval methods #2413

Merged
merged 1 commit into from
Apr 22, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 92 additions & 2 deletions stripe/src/main/java/com/stripe/android/Stripe.kt
Original file line number Diff line number Diff line change
Expand Up @@ -295,14 +295,46 @@ class Stripe internal constructor(
}
}

/**
* Retrieve a [PaymentIntent] asynchronously.
*
* See [Retrieve a PaymentIntent](https://stripe.com/docs/api/payment_intents/retrieve).
* `GET /v1/payment_intents/:id`
*
* @param clientSecret the client_secret with which to retrieve the [PaymentIntent]
* @param stripeAccountId Optional, the Connect account to associate with this request.
* By default, will use the Connect account that was used to instantiate the `Stripe` object, if specified.
* @param callback a [ApiResultCallback] to receive the result or error
*/
@Throws(APIException::class, AuthenticationException::class,
InvalidRequestException::class, APIConnectionException::class)
@WorkerThread
@JvmOverloads
fun retrievePaymentIntent(
clientSecret: String,
stripeAccountId: String? = this.stripeAccountId,
callback: ApiResultCallback<PaymentIntent>
) {
RetrievePaymentIntentTask(
stripeRepository,
clientSecret,
ApiRequest.Options(
apiKey = publishableKey,
stripeAccount = stripeAccountId
),
workScope,
callback
).execute()
}

/**
* Blocking method to retrieve a [PaymentIntent] object.
* Do not call this on the UI thread or your app will crash.
*
* See [Retrieve a PaymentIntent](https://stripe.com/docs/api/payment_intents/retrieve).
* `GET /v1/payment_intents/:id`
*
* @param clientSecret the client_secret with which to retrieve the PaymentIntent
* @param clientSecret the client_secret with which to retrieve the [PaymentIntent]
* @param stripeAccountId Optional, the Connect account to associate with this request.
* By default, will use the Connect account that was used to instantiate the `Stripe` object, if specified.
* @return a [PaymentIntent] or `null` if a problem occurred
Expand Down Expand Up @@ -520,14 +552,46 @@ class Stripe internal constructor(
}
}

/**
* Retrieve a [SetupIntent] asynchronously.
*
* See [Retrieve a SetupIntent](https://stripe.com/docs/api/setup_intents/retrieve).
* `GET /v1/setup_intents/:id`
*
* @param clientSecret the client_secret with which to retrieve the [SetupIntent]
* @param stripeAccountId Optional, the Connect account to associate with this request.
* By default, will use the Connect account that was used to instantiate the `Stripe` object, if specified.
* @param callback a [ApiResultCallback] to receive the result or error
*/
@Throws(APIException::class, AuthenticationException::class,
InvalidRequestException::class, APIConnectionException::class)
@WorkerThread
@JvmOverloads
fun retrieveSetupIntent(
clientSecret: String,
stripeAccountId: String? = this.stripeAccountId,
callback: ApiResultCallback<SetupIntent>
) {
RetrieveSetupIntentTask(
stripeRepository,
clientSecret,
ApiRequest.Options(
apiKey = publishableKey,
stripeAccount = stripeAccountId
),
workScope,
callback
).execute()
}

/**
* Blocking method to retrieve a [SetupIntent] object.
* Do not call this on the UI thread or your app will crash.
*
* See [Retrieve a SetupIntent](https://stripe.com/docs/api/setup_intents/retrieve).
* `GET /v1/setup_intents/:id`
*
* @param clientSecret client_secret of the SetupIntent to retrieve
* @param clientSecret client_secret of the [SetupIntent] to retrieve
* @param stripeAccountId Optional, the Connect account to associate with this request.
* By default, will use the Connect account that was used to instantiate the `Stripe` object, if specified.
* @return a [SetupIntent] or `null` if a problem occurred
Expand Down Expand Up @@ -1509,6 +1573,32 @@ class Stripe internal constructor(
}
}

private class RetrievePaymentIntentTask internal constructor(
private val stripeRepository: StripeRepository,
private val clientSecret: String,
private val options: ApiRequest.Options,
workScope: CoroutineScope = CoroutineScope(Dispatchers.IO),
callback: ApiResultCallback<PaymentIntent>
) : ApiOperation<PaymentIntent>(workScope, callback) {
@Throws(StripeException::class)
override suspend fun getResult(): PaymentIntent? {
return stripeRepository.retrievePaymentIntent(clientSecret, options)
}
}

private class RetrieveSetupIntentTask internal constructor(
private val stripeRepository: StripeRepository,
private val clientSecret: String,
private val options: ApiRequest.Options,
workScope: CoroutineScope = CoroutineScope(Dispatchers.IO),
callback: ApiResultCallback<SetupIntent>
) : ApiOperation<SetupIntent>(workScope, callback) {
@Throws(StripeException::class)
override suspend fun getResult(): SetupIntent? {
return stripeRepository.retrieveSetupIntent(clientSecret, options)
}
}

companion object {
@JvmField
val API_VERSION: String = ApiVersion.get().code
Expand Down
60 changes: 56 additions & 4 deletions stripe/src/test/java/com/stripe/android/StripeEndToEndTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,32 @@ package com.stripe.android
import android.content.Context
import androidx.test.core.app.ApplicationProvider
import com.google.common.truth.Truth.assertThat
import com.nhaarman.mockitokotlin2.argWhere
import com.nhaarman.mockitokotlin2.mock
import com.nhaarman.mockitokotlin2.verify
import com.stripe.android.exception.InvalidRequestException
import com.stripe.android.model.AccountParams
import com.stripe.android.model.AddressFixtures
import com.stripe.android.model.PaymentIntent
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.PaymentMethodCreateParamsFixtures
import com.stripe.android.model.SetupIntent
import com.stripe.android.model.Token
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlinx.coroutines.MainScope
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class StripeEndToEndTest {

private val context: Context = ApplicationProvider.getApplicationContext()
private val stripe: Stripe by lazy {
Stripe(context, ApiKeyFixtures.DEFAULT_PUBLISHABLE_KEY)
}
private val defaultStripe = Stripe(context, ApiKeyFixtures.DEFAULT_PUBLISHABLE_KEY)

@Test
fun testCreateAccountToken() {
val token = stripe.createAccountTokenSynchronous(
val token = defaultStripe.createAccountTokenSynchronous(
accountParams = AccountParams.create(
tosShownAndAccepted = true,
individual = AccountParams.BusinessTypeParams.Individual(
Expand All @@ -47,4 +52,51 @@ class StripeEndToEndTest {
assertThat(paymentMethod.type)
.isEqualTo(PaymentMethod.Type.AuBecsDebit)
}

@Test
fun retrievePaymentIntentAsync_withInvalidClientSecret_shouldReturnInvalidRequestException() {
val paymentIntentCallback: ApiResultCallback<PaymentIntent> = mock()
createStripeWithMainScope().retrievePaymentIntent(
clientSecret = "pi_abc_secret_invalid",
callback = paymentIntentCallback
)

verify(paymentIntentCallback).onError(
argWhere {
it is InvalidRequestException && it.message == "No such payment_intent: pi_abc"
}
)
}

@Test
fun retrieveSetupIntentAsync_withInvalidClientSecret_shouldReturnInvalidRequestException() {
val setupIntentCallback: ApiResultCallback<SetupIntent> = mock()

createStripeWithMainScope().retrieveSetupIntent(
clientSecret = "seti_abc_secret_invalid",
callback = setupIntentCallback
)

verify(setupIntentCallback).onError(
argWhere {
it is InvalidRequestException && it.message == "No such setupintent: seti_abc"
}
)
}

private fun createStripeWithMainScope(
publishableKey: String = ApiKeyFixtures.DEFAULT_PUBLISHABLE_KEY
): Stripe {
val stripeRepository = StripeApiRepository(context, publishableKey)
return Stripe(
stripeRepository = stripeRepository,
paymentController = StripePaymentController.create(
context,
publishableKey,
stripeRepository
),
publishableKey = publishableKey,
workScope = MainScope()
)
}
}