Skip to content

Commit

Permalink
Fix mandate during confirmation. (#10211)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaynewstrom-stripe authored Feb 19, 2025
1 parent 1c5b368 commit 6fe49af
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ internal class ConfirmSetupIntentParamsFactory(
private fun mandateData(intent: StripeIntent, paymentMethodType: PaymentMethod.Type?): MandateDataParams? {
return paymentMethodType?.let { type ->
val supportsAddingMandateData = when (intent) {
is PaymentIntent -> intent.canSetupFutureUsage()
is PaymentIntent -> intent.canSetupFutureUsage() || type.requiresMandateForPaymentIntent
is SetupIntent -> true
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ constructor(
@JvmField val isReusable: Boolean,
@JvmField val isVoucher: Boolean,
@JvmField val requiresMandate: Boolean,
internal val requiresMandateForPaymentIntent: Boolean,
private val hasDelayedSettlement: Boolean,
internal val afterRedirectAction: AfterRedirectAction = AfterRedirectAction.None,
) : Parcelable {
Expand All @@ -184,69 +185,79 @@ constructor(
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = true,
hasDelayedSettlement = false,
),
Card(
"card",
isReusable = true,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
CardPresent(
"card_present",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Fpx(
"fpx",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Ideal(
"ideal",
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
SepaDebit(
"sepa_debit",
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = true,
hasDelayedSettlement = true,
),
AuBecsDebit(
"au_becs_debit",
isReusable = true,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = true,
hasDelayedSettlement = true,
),
BacsDebit(
"bacs_debit",
isReusable = true,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = true,
hasDelayedSettlement = true,
),
Sofort(
"sofort",
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = true,
),
Upi(
"upi",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
afterRedirectAction = AfterRedirectAction.Refresh(),
),
Expand All @@ -255,6 +266,7 @@ constructor(
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
// We are intentionally polling for P24 even though it uses the redirect trampoline.
// About 20% of the time, the intent is still in `requires_action` status
Expand All @@ -267,76 +279,87 @@ constructor(
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = true,
hasDelayedSettlement = false,
),
Giropay(
"giropay",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Eps(
"eps",
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Oxxo(
"oxxo",
isReusable = false,
isVoucher = true,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = true,
),
Alipay(
"alipay",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
GrabPay(
"grabpay",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
PayPal(
"paypal",
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
AfterpayClearpay(
"afterpay_clearpay",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Netbanking(
"netbanking",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Blik(
"blik",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
WeChatPay(
"wechat_pay",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
afterRedirectAction = AfterRedirectAction.Refresh(retryCount = MAX_RETRIES),
),
Expand All @@ -345,20 +368,23 @@ constructor(
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Affirm(
"affirm",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
RevolutPay(
"revolut_pay",
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
afterRedirectAction = AfterRedirectAction.Poll(),
),
Expand All @@ -367,34 +393,39 @@ constructor(
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Billie(
"billie",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Satispay(
"satispay",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Crypto(
"crypto",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
AmazonPay(
"amazon_pay",
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
afterRedirectAction = AfterRedirectAction.Poll(),
),
Expand All @@ -403,41 +434,47 @@ constructor(
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
MobilePay(
"mobilepay",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
Multibanco(
"multibanco",
isReusable = false,
isVoucher = true,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = true,
),
Zip(
"zip",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
),
USBankAccount(
code = "us_bank_account",
isReusable = true,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = true,
hasDelayedSettlement = true,
),
CashAppPay(
code = "cashapp",
isReusable = false,
isVoucher = false,
requiresMandate = true,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
afterRedirectAction = AfterRedirectAction.Refresh(),
),
Expand All @@ -446,20 +483,23 @@ constructor(
isReusable = false,
isVoucher = true,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = true,
),
Konbini(
code = "konbini",
isReusable = false,
isVoucher = true,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = true,
),
Swish(
code = "swish",
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
// We are intentionally polling for Swish even though it uses the redirect trampoline.
// About 50% of the time, the intent is still in `requires_action` status
Expand All @@ -472,6 +512,7 @@ constructor(
isReusable = false,
isVoucher = false,
requiresMandate = false,
requiresMandateForPaymentIntent = false,
hasDelayedSettlement = false,
// We are intentionally polling for Twint even though it uses the redirect trampoline.
// About 50% of the time, the intent is still in `requires_action` status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import com.stripe.android.model.ConfirmPaymentIntentParams
import com.stripe.android.model.ConfirmStripeIntentParams
import com.stripe.android.model.MandateDataParams
import com.stripe.android.model.PaymentIntent
import com.stripe.android.model.PaymentMethod
import com.stripe.android.model.PaymentMethodCreateParamsFixtures
import com.stripe.android.model.PaymentMethodFixtures
import com.stripe.android.model.PaymentMethodOptionsParams
Expand Down Expand Up @@ -176,6 +177,13 @@ class ConfirmPaymentIntentParamsFactoryTest {
expectedMandateDataParams = null,
)

@Test
fun `create() without SFU should contain mandate data for sepa_debit`() = mandateDataTest(
setupFutureUsage = null,
expectedMandateDataParams = MandateDataParams(MandateDataParams.Type.Online.DEFAULT),
paymentMethod = PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD,
)

@Test
fun `create() with 'OneTime' SFU should not contain any mandate data`() = mandateDataTest(
setupFutureUsage = StripeIntent.Usage.OneTime,
Expand All @@ -196,7 +204,8 @@ class ConfirmPaymentIntentParamsFactoryTest {

private fun mandateDataTest(
setupFutureUsage: StripeIntent.Usage?,
expectedMandateDataParams: MandateDataParams?
expectedMandateDataParams: MandateDataParams?,
paymentMethod: PaymentMethod = PaymentMethodFactory.cashAppPay(),
) {
val factoryWithConfig = ConfirmPaymentIntentParamsFactory(
clientSecret = CLIENT_SECRET,
Expand All @@ -207,7 +216,7 @@ class ConfirmPaymentIntentParamsFactoryTest {
)

val result = factoryWithConfig.create(
paymentMethod = PaymentMethodFactory.cashAppPay(),
paymentMethod = paymentMethod,
optionsParams = null,
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import com.stripe.android.paymentsheet.example.playground.settings.Country
import com.stripe.android.paymentsheet.example.playground.settings.CountrySettingsDefinition
import com.stripe.android.paymentsheet.example.playground.settings.DelayedPaymentMethodsSettingsDefinition
import com.stripe.android.paymentsheet.example.playground.settings.GooglePaySettingsDefinition
import com.stripe.android.paymentsheet.example.playground.settings.InitializationType
import com.stripe.android.paymentsheet.example.playground.settings.InitializationTypeSettingsDefinition
import com.stripe.android.test.core.DEFAULT_UI_TIMEOUT
import com.stripe.android.test.core.TestParameters
import com.stripe.android.test.core.ui.ComposeButton
Expand All @@ -30,6 +32,7 @@ internal class TestSepaDebit : BasePlaygroundTest() {
settings[CountrySettingsDefinition] = Country.FR
settings[DelayedPaymentMethodsSettingsDefinition] = true
settings[GooglePaySettingsDefinition] = false
settings[InitializationTypeSettingsDefinition] = InitializationType.DeferredClientSideConfirmation
}.copy(
authorizationAction = null,
)
Expand Down
Loading

0 comments on commit 6fe49af

Please sign in to comment.