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

Add stripe account param to confirmSetupIntent #2405

Merged
merged 10 commits into from
Apr 22, 2020
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ internal class PaymentAuthWebViewStarter internal constructor(
val url: String,
val returnUrl: String? = null,
val enableLogging: Boolean = false,
val toolbarCustomization: StripeToolbarCustomization? = null
val toolbarCustomization: StripeToolbarCustomization? = null,
val stripeAccountId: String? = null
) : Parcelable

internal companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ internal interface PaymentController {
*/
fun handlePaymentResult(
data: Intent,
requestOptions: ApiRequest.Options,
callback: ApiResultCallback<PaymentIntentResult>
)

Expand All @@ -72,7 +71,6 @@ internal interface PaymentController {
*/
fun handleSetupResult(
data: Intent,
requestOptions: ApiRequest.Options,
callback: ApiResultCallback<SetupIntentResult>
)

Expand Down Expand Up @@ -107,7 +105,8 @@ internal interface PaymentController {
internal val exception: StripeException? = null,
internal val shouldCancelSource: Boolean = false,
internal val sourceId: String? = null,
internal val source: Source? = null
internal val source: Source? = null,
internal val stripeAccountId: String? = null
) : Parcelable {
@JvmSynthetic
fun toBundle(): Bundle {
Expand All @@ -124,7 +123,8 @@ internal interface PaymentController {
exception = parcel.readSerializable() as? StripeException?,
shouldCancelSource = parcel.readInt() == 1,
sourceId = parcel.readString(),
source = parcel.readParcelable(Source::class.java.classLoader)
source = parcel.readParcelable(Source::class.java.classLoader),
stripeAccountId = parcel.readString()
)
}

Expand All @@ -135,6 +135,7 @@ internal interface PaymentController {
parcel.writeInt(1.takeIf { shouldCancelSource } ?: 0)
parcel.writeString(sourceId)
parcel.writeParcelable(source, flags)
parcel.writeString(stripeAccountId)
}

private const val EXTRA = "extra_args"
Expand Down
14 changes: 9 additions & 5 deletions stripe/src/main/java/com/stripe/android/PaymentRelayStarter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ internal interface PaymentRelayStarter : AuthActivityStarter<PaymentRelayStarter
val extras = PaymentController.Result(
clientSecret = args.stripeIntent?.clientSecret,
source = args.source,
exception = args.exception
exception = args.exception,
stripeAccountId = args.stripeAccountId
).toBundle()
host.startActivityForResult(
PaymentRelayActivity::class.java, extras, requestCode
Expand All @@ -42,12 +43,13 @@ internal interface PaymentRelayStarter : AuthActivityStarter<PaymentRelayStarter
data class Args internal constructor(
val stripeIntent: StripeIntent? = null,
val source: Source? = null,
val exception: StripeException? = null
val exception: StripeException? = null,
val stripeAccountId: String? = null
) : Parcelable {
internal companion object : Parceler<Args> {
@JvmSynthetic
internal fun create(stripeIntent: StripeIntent): Args {
return Args(stripeIntent = stripeIntent)
internal fun create(stripeIntent: StripeIntent, stripeAccountId: String? = null): Args {
return Args(stripeIntent = stripeIntent, stripeAccountId = stripeAccountId)
}

@JvmSynthetic
Expand All @@ -64,14 +66,16 @@ internal interface PaymentRelayStarter : AuthActivityStarter<PaymentRelayStarter
return Args(
stripeIntent = readStripeIntent(parcel),
source = parcel.readParcelable(Source::class.java.classLoader),
exception = parcel.readSerializable() as? StripeException?
exception = parcel.readSerializable() as? StripeException?,
stripeAccountId = parcel.readString()
)
}

override fun Args.write(parcel: Parcel, flags: Int) {
writeStripeIntent(parcel, stripeIntent)
parcel.writeParcelable(source, 0)
parcel.writeSerializable(exception)
parcel.writeString(stripeAccountId)
}

private fun readStripeIntent(parcel: Parcel): StripeIntent? {
Expand Down
36 changes: 17 additions & 19 deletions stripe/src/main/java/com/stripe/android/Stripe.kt
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,15 @@ class Stripe internal constructor(
* @param activity the `Activity` that is launching the payment authentication flow
* @param confirmPaymentIntentParams [ConfirmPaymentIntentParams] used to confirm 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.
*/
@JvmOverloads
@UiThread
fun confirmPayment(
activity: Activity,
confirmPaymentIntentParams: ConfirmPaymentIntentParams
confirmPaymentIntentParams: ConfirmPaymentIntentParams,
stripeAccountId: String? = this.stripeAccountId
) {
paymentController.startConfirmAndAuth(
AuthActivityStarter.Host.create(activity),
Expand All @@ -150,11 +154,15 @@ class Stripe internal constructor(
*
* @param fragment the `Fragment` that is launching the payment authentication flow
* @param confirmPaymentIntentParams [ConfirmPaymentIntentParams] used to confirm 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.
*/
@JvmOverloads
@UiThread
fun confirmPayment(
fragment: Fragment,
confirmPaymentIntentParams: ConfirmPaymentIntentParams
confirmPaymentIntentParams: ConfirmPaymentIntentParams,
stripeAccountId: String? = this.stripeAccountId
) {
paymentController.startConfirmAndAuth(
AuthActivityStarter.Host.create(fragment),
Expand Down Expand Up @@ -280,14 +288,7 @@ class Stripe internal constructor(
callback: ApiResultCallback<PaymentIntentResult>
): Boolean {
return if (data != null && paymentController.shouldHandlePaymentResult(requestCode, data)) {
paymentController.handlePaymentResult(
data,
ApiRequest.Options(
apiKey = publishableKey,
stripeAccount = stripeAccountId
),
callback
)
paymentController.handlePaymentResult(data, callback)
true
} else {
false
Expand Down Expand Up @@ -362,10 +363,14 @@ class Stripe internal constructor(
* Confirm and, if necessary, authenticate a [SetupIntent].
*
* @param activity the `Activity` that is launching the payment authentication flow
* @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.
*/
@JvmOverloads
fun confirmSetupIntent(
activity: Activity,
confirmSetupIntentParams: ConfirmSetupIntentParams
confirmSetupIntentParams: ConfirmSetupIntentParams,
stripeAccountId: String? = this.stripeAccountId
) {
paymentController.startConfirmAndAuth(
AuthActivityStarter.Host.create(activity),
Expand Down Expand Up @@ -508,14 +513,7 @@ class Stripe internal constructor(
callback: ApiResultCallback<SetupIntentResult>
): Boolean {
return if (data != null && paymentController.shouldHandleSetupResult(requestCode, data)) {
paymentController.handleSetupResult(
data,
ApiRequest.Options(
apiKey = publishableKey,
stripeAccount = stripeAccountId
),
callback
)
paymentController.handleSetupResult(data, callback)
true
} else {
false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import kotlinx.coroutines.Dispatchers
*/
internal class StripePaymentController internal constructor(
context: Context,
publishableKey: String,
private val publishableKey: String,
private val stripeRepository: StripeRepository,
private val enableLogging: Boolean = false,
private val messageVersionRegistry: MessageVersionRegistry =
Expand Down Expand Up @@ -195,7 +195,6 @@ internal class StripePaymentController internal constructor(
*/
override fun handlePaymentResult(
data: Intent,
requestOptions: ApiRequest.Options,
callback: ApiResultCallback<PaymentIntentResult>
) {
val result = PaymentController.Result.fromIntent(data) ?: PaymentController.Result()
Expand All @@ -209,6 +208,11 @@ internal class StripePaymentController internal constructor(
val sourceId = result.sourceId.orEmpty()
@StripeIntentResult.Outcome val flowOutcome = result.flowOutcome

val requestOptions = ApiRequest.Options(
apiKey = publishableKey,
stripeAccount = result.stripeAccountId
)

stripeRepository.retrieveIntent(
getClientSecret(data),
requestOptions,
Expand All @@ -230,7 +234,6 @@ internal class StripePaymentController internal constructor(
*/
override fun handleSetupResult(
data: Intent,
requestOptions: ApiRequest.Options,
callback: ApiResultCallback<SetupIntentResult>
) {
val result = PaymentController.Result.fromIntent(data) ?: PaymentController.Result()
Expand All @@ -244,6 +247,11 @@ internal class StripePaymentController internal constructor(
val sourceId = result.sourceId.orEmpty()
@StripeIntentResult.Outcome val flowOutcome = result.flowOutcome

val requestOptions = ApiRequest.Options(
apiKey = publishableKey,
stripeAccount = result.stripeAccountId
)

stripeRepository.retrieveIntent(
getClientSecret(data),
requestOptions,
Expand Down Expand Up @@ -413,11 +421,12 @@ internal class StripePaymentController internal constructor(
getRequestCode(stripeIntent),
stripeIntent.clientSecret.orEmpty(),
Stripe3dsRedirect.create(sdkData).url,
requestOptions.stripeAccount,
enableLogging = enableLogging
)
}
else -> // authentication type is not supported
bypassAuth(host, stripeIntent)
bypassAuth(host, stripeIntent, requestOptions.stripeAccount)
}
}
StripeIntent.NextActionType.RedirectToUrl -> {
Expand All @@ -437,22 +446,27 @@ internal class StripePaymentController internal constructor(
getRequestCode(stripeIntent),
stripeIntent.clientSecret.orEmpty(),
redirectData?.url.toString(),
requestOptions.stripeAccount,
redirectData?.returnUrl,
enableLogging = enableLogging
)
}
else -> // next action type is not supported, so bypass authentication
bypassAuth(host, stripeIntent)
bypassAuth(host, stripeIntent, requestOptions.stripeAccount)
}
} else {
// no action required, so bypass authentication
bypassAuth(host, stripeIntent)
bypassAuth(host, stripeIntent, requestOptions.stripeAccount)
}
}

private fun bypassAuth(host: AuthActivityStarter.Host, stripeIntent: StripeIntent) {
private fun bypassAuth(
host: AuthActivityStarter.Host,
stripeIntent: StripeIntent,
stripeAccountId: String?
) {
PaymentRelayStarter.create(host, getRequestCode(stripeIntent))
.start(PaymentRelayStarter.Args.create(stripeIntent))
.start(PaymentRelayStarter.Args.create(stripeIntent, stripeAccountId))
}

private fun bypassAuth(host: AuthActivityStarter.Host, source: Source) {
Expand Down Expand Up @@ -480,6 +494,10 @@ internal class StripePaymentController internal constructor(
Stripe3ds2CompletionActivity.EXTRA_CLIENT_SECRET,
stripeIntent.clientSecret
)
.putExtra(
Stripe3ds2CompletionActivity.EXTRA_STRIPE_ACCOUNT,
requestOptions.stripeAccount
)
.addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT),
challengeCompletionRequestCode = getRequestCode(stripeIntent)
)
Expand Down Expand Up @@ -609,6 +627,7 @@ internal class StripePaymentController internal constructor(
getRequestCode(stripeIntent),
stripeIntent.clientSecret.orEmpty(),
result.fallbackRedirectUrl,
requestOptions.stripeAccount,
enableLogging = enableLogging
)
} else {
Expand Down Expand Up @@ -927,13 +946,14 @@ internal class StripePaymentController internal constructor(
requestCode: Int,
clientSecret: String,
authUrl: String,
stripeAccount: String?,
returnUrl: String? = null,
enableLogging: Boolean = false
) {
Logger.getInstance(enableLogging).debug("PaymentAuthWebViewStarter#start()")
val starter = PaymentAuthWebViewStarter(host, requestCode)
starter.start(
PaymentAuthWebViewStarter.Args(clientSecret, authUrl, returnUrl, enableLogging)
PaymentAuthWebViewStarter.Args(clientSecret, authUrl, returnUrl, enableLogging, stripeAccountId = stripeAccount)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ internal class PaymentAuthWebViewActivityViewModel(
get() {
return PaymentController.Result(
clientSecret = args.clientSecret,
sourceId = Uri.parse(args.url).lastPathSegment.orEmpty()
sourceId = Uri.parse(args.url).lastPathSegment.orEmpty(),
stripeAccountId = args.stripeAccountId
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ class Stripe3ds2CompletionActivity : AppCompatActivity() {
super.onCreate(savedInstanceState)
val result = PaymentController.Result(
clientSecret = intent.getStringExtra(EXTRA_CLIENT_SECRET),
flowOutcome = flowOutcome
flowOutcome = flowOutcome,
stripeAccountId = intent.getStringExtra(EXTRA_STRIPE_ACCOUNT)
)

LocalBroadcastManager.getInstance(this)
Expand All @@ -56,6 +57,7 @@ class Stripe3ds2CompletionActivity : AppCompatActivity() {

internal companion object {
const val EXTRA_CLIENT_SECRET = "extra_client_secret"
const val EXTRA_STRIPE_ACCOUNT = "extra_stripe_account"
private const val UNKNOWN_FLOW_OUTCOME = -1
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,7 @@ class StripePaymentAuthTest {
stripe.onPaymentResult(StripePaymentController.PAYMENT_REQUEST_CODE, data,
callback = paymentCallback)

verify(paymentController).handlePaymentResult(data,
ApiRequest.Options(ApiKeyFixtures.FAKE_PUBLISHABLE_KEY),
paymentCallback)
verify(paymentController).handlePaymentResult(data, paymentCallback)
}

@Test
Expand All @@ -118,9 +116,7 @@ class StripePaymentAuthTest {
stripe.onSetupResult(StripePaymentController.SETUP_REQUEST_CODE, data,
callback = setupCallback)

verify(paymentController).handleSetupResult(data,
ApiRequest.Options(ApiKeyFixtures.FAKE_PUBLISHABLE_KEY),
setupCallback)
verify(paymentController).handleSetupResult(data, setupCallback)
}

private fun createStripe(): Stripe {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ class StripePaymentControllerTest {
).toBundle()
)

controller.handlePaymentResult(intent, REQUEST_OPTIONS, paymentAuthResultCallback)
controller.handlePaymentResult(intent, paymentAuthResultCallback)
verify(paymentAuthResultCallback).onError(exception)
verify(paymentAuthResultCallback, never())
.onSuccess(anyOrNull())
Expand All @@ -528,7 +528,7 @@ class StripePaymentControllerTest {
).toBundle()
)

controller.handleSetupResult(intent, REQUEST_OPTIONS, setupAuthResultCallback)
controller.handleSetupResult(intent, setupAuthResultCallback)

verify(setupAuthResultCallback).onError(exception)
verify(setupAuthResultCallback, never())
Expand All @@ -546,7 +546,7 @@ class StripePaymentControllerTest {
).toBundle()
)

controller.handleSetupResult(intent, REQUEST_OPTIONS, setupAuthResultCallback)
controller.handleSetupResult(intent, setupAuthResultCallback)

verify(setupAuthResultCallback).onSuccess(setupIntentResultArgumentCaptor.capture())
val result = setupIntentResultArgumentCaptor.firstValue
Expand Down Expand Up @@ -657,7 +657,7 @@ class StripePaymentControllerTest {
)

createController(stripeRepository)
.handlePaymentResult(intent, REQUEST_OPTIONS, paymentAuthResultCallback)
.handlePaymentResult(intent, paymentAuthResultCallback)

verify(stripeRepository).retrieveIntent(
eq(clientSecret),
Expand Down