Skip to content

Commit

Permalink
Rebase
Browse files Browse the repository at this point in the history
  • Loading branch information
jameswoo-stripe committed Jul 21, 2022
1 parent 2a64368 commit 5fc812c
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 47 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -3,6 +3,7 @@
## X.X.X
### Payments
[Fixed][5308](https://github.com/stripe/stripe-android/pull/5308) OXXO so that processing is considered a successful terminal state, similar to Konbini and Boleto.
[Fixed][5138](https://github.com/stripe/stripe-android/pull/5138) Fixed an issue where PaymentSheet will show a failure even when 3DS2 Payment/SetupIntent is successful

## 20.7.0 - 2022-07-06
* This release adds additional support for Afterpay/Clearpay in PaymentSheet.
Expand Down
Expand Up @@ -61,7 +61,8 @@ internal sealed class PaymentFlowResultProcessor<T : StripeIntent, out S : Strip
)
).let { stripeIntent ->
when {
stripeIntent.status == StripeIntent.Status.Succeeded -> {
stripeIntent.status == StripeIntent.Status.Succeeded ||
stripeIntent.status == StripeIntent.Status.RequiresCapture -> {
createStripeIntentResult(
stripeIntent,
SUCCEEDED,
Expand All @@ -73,11 +74,7 @@ internal sealed class PaymentFlowResultProcessor<T : StripeIntent, out S : Strip
result.clientSecret,
requestOptions
)
val flowOutcome = if (intent.status == StripeIntent.Status.Succeeded) {
SUCCEEDED
} else {
result.flowOutcome
}
val flowOutcome = determineFlowOutcome(intent, result.flowOutcome)
createStripeIntentResult(
intent,
flowOutcome,
Expand Down Expand Up @@ -151,6 +148,14 @@ internal sealed class PaymentFlowResultProcessor<T : StripeIntent, out S : Strip
return succeededMaybeRefresh || cancelledMaybeRefresh
}

private fun determineFlowOutcome(intent: StripeIntent, originalFlowOutcome: Int): Int {
return when (intent.status) {
StripeIntent.Status.Succeeded,
StripeIntent.Status.RequiresCapture -> SUCCEEDED
else -> originalFlowOutcome
}
}

protected abstract suspend fun retrieveStripeIntent(
clientSecret: String,
requestOptions: ApiRequest.Options,
Expand Down Expand Up @@ -181,7 +186,7 @@ internal sealed class PaymentFlowResultProcessor<T : StripeIntent, out S : Strip
)
private suspend fun refreshStripeIntentUntilTerminalState(
clientSecret: String,
requestOptions: ApiRequest.Options,
requestOptions: ApiRequest.Options
): T {
var remainingRetries = MAX_RETRIES

Expand Down Expand Up @@ -283,37 +288,6 @@ internal class PaymentIntentFlowResultProcessor @Inject constructor(
clientSecret,
requestOptions
)
requestOptions: ApiRequest.Options
): PaymentIntent {
var remainingRetries = MAX_RETRIES

var stripeIntent = requireNotNull(
stripeRepository.refreshPaymentIntent(
clientSecret,
requestOptions
)
)
while (stripeIntent.requiresAction() && remainingRetries > 1) {
val delayMs = retryDelaySupplier.getDelayMillis(
3,
remainingRetries
)
delay(delayMs)
stripeIntent = requireNotNull(
stripeRepository.refreshPaymentIntent(
clientSecret,
requestOptions
)
)
remainingRetries--
}

if (stripeIntent.requiresAction()) {
throw MaxRetryReachedException()
} else {
return stripeIntent
}
}

override suspend fun cancelStripeIntentSource(
stripeIntentId: String,
Expand Down
Expand Up @@ -142,7 +142,7 @@ internal object PaymentIntentFixtures {
},
"source": null
}
""".trimIndent()
""".trimIndent()
)
}

Expand Down Expand Up @@ -249,7 +249,7 @@ internal object PaymentIntentFixtures {
},
"source": null
}
""".trimIndent()
""".trimIndent()
)
}

Expand Down
Expand Up @@ -9,6 +9,7 @@ import com.stripe.android.core.Logger
import com.stripe.android.core.exception.MaxRetryReachedException
import com.stripe.android.core.networking.ApiRequest
import com.stripe.android.model.PaymentIntentFixtures
import com.stripe.android.model.StripeIntent
import com.stripe.android.networking.StripeRepository
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.UnconfinedTestDispatcher
Expand Down Expand Up @@ -37,7 +38,7 @@ internal class PaymentIntentFlowResultProcessorTest {
{ ApiKeyFixtures.FAKE_PUBLISHABLE_KEY },
mockStripeRepository,
Logger.noop(),
testDispatcher,
testDispatcher
)

@Test
Expand Down Expand Up @@ -232,7 +233,7 @@ internal class PaymentIntentFlowResultProcessorTest {
val result = processor.processResult(
PaymentFlowResult.Unvalidated(
clientSecret = clientSecret,
flowOutcome = StripeIntentResult.Outcome.CANCELED,
flowOutcome = StripeIntentResult.Outcome.CANCELED
)
)

Expand Down Expand Up @@ -260,6 +261,54 @@ internal class PaymentIntentFlowResultProcessorTest {
)
}

@Test
fun `3ds2 canceled with requires capture intent should succeed`() =
runTest {
val refreshedPaymentIntent = PaymentIntentFixtures.PI_VISA_3DS2_SUCCEEDED.copy(
status = StripeIntent.Status.RequiresCapture
)

whenever(mockStripeRepository.retrievePaymentIntent(any(), any(), any())).thenReturn(
PaymentIntentFixtures.PI_PROCESSING_VISA_3DS2
)
whenever(mockStripeRepository.refreshPaymentIntent(any(), any())).thenReturn(
refreshedPaymentIntent
)

val clientSecret = "pi_3L8WOsLu5o3P18Zp191FpRSy_secret_5JIwIT1ooCwRm28AwreUAc6N4"
val requestOptions = ApiRequest.Options(apiKey = ApiKeyFixtures.FAKE_PUBLISHABLE_KEY)

val result = processor.processResult(
PaymentFlowResult.Unvalidated(
clientSecret = clientSecret,
flowOutcome = StripeIntentResult.Outcome.CANCELED
)
)

verify(mockStripeRepository).retrievePaymentIntent(
eq(clientSecret),
eq(requestOptions),
eq(PaymentFlowResultProcessor.EXPAND_PAYMENT_METHOD)
)

verify(
mockStripeRepository,
times(1)
).refreshPaymentIntent(
eq(clientSecret),
eq(requestOptions)
)

assertThat(result)
.isEqualTo(
PaymentIntentResult(
refreshedPaymentIntent,
StripeIntentResult.Outcome.SUCCEEDED,
null
)
)
}

@Test
fun `3ds2 canceled with succeeded intent should succeed`() =
runTest {
Expand All @@ -273,7 +322,7 @@ internal class PaymentIntentFlowResultProcessorTest {
val result = processor.processResult(
PaymentFlowResult.Unvalidated(
clientSecret = clientSecret,
flowOutcome = StripeIntentResult.Outcome.CANCELED,
flowOutcome = StripeIntentResult.Outcome.CANCELED
)
)

Expand Down Expand Up @@ -318,7 +367,7 @@ internal class PaymentIntentFlowResultProcessorTest {
processor.processResult(
PaymentFlowResult.Unvalidated(
clientSecret = clientSecret,
flowOutcome = StripeIntentResult.Outcome.CANCELED,
flowOutcome = StripeIntentResult.Outcome.CANCELED
)
)
}
Expand Down
Expand Up @@ -80,7 +80,7 @@ internal class SetupIntentFlowResultProcessorTest {
val result = processor.processResult(
PaymentFlowResult.Unvalidated(
clientSecret = clientSecret,
flowOutcome = StripeIntentResult.Outcome.CANCELED,
flowOutcome = StripeIntentResult.Outcome.CANCELED
)
)

Expand Down Expand Up @@ -122,7 +122,7 @@ internal class SetupIntentFlowResultProcessorTest {
val result = processor.processResult(
PaymentFlowResult.Unvalidated(
clientSecret = clientSecret,
flowOutcome = StripeIntentResult.Outcome.CANCELED,
flowOutcome = StripeIntentResult.Outcome.CANCELED
)
)

Expand Down Expand Up @@ -165,7 +165,7 @@ internal class SetupIntentFlowResultProcessorTest {
processor.processResult(
PaymentFlowResult.Unvalidated(
clientSecret = clientSecret,
flowOutcome = StripeIntentResult.Outcome.CANCELED,
flowOutcome = StripeIntentResult.Outcome.CANCELED
)
)
}
Expand Down

0 comments on commit 5fc812c

Please sign in to comment.