Skip to content

Commit 6fe49af

Browse files
Fix mandate during confirmation. (#10211)
1 parent 1c5b368 commit 6fe49af

File tree

5 files changed

+58
-5
lines changed

5 files changed

+58
-5
lines changed

payments-core/src/main/java/com/stripe/android/ConfirmStripeIntentParamsFactory.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ internal class ConfirmSetupIntentParamsFactory(
123123
private fun mandateData(intent: StripeIntent, paymentMethodType: PaymentMethod.Type?): MandateDataParams? {
124124
return paymentMethodType?.let { type ->
125125
val supportsAddingMandateData = when (intent) {
126-
is PaymentIntent -> intent.canSetupFutureUsage()
126+
is PaymentIntent -> intent.canSetupFutureUsage() || type.requiresMandateForPaymentIntent
127127
is SetupIntent -> true
128128
}
129129

payments-core/src/main/java/com/stripe/android/model/PaymentMethod.kt

+42-1
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,7 @@ constructor(
176176
@JvmField val isReusable: Boolean,
177177
@JvmField val isVoucher: Boolean,
178178
@JvmField val requiresMandate: Boolean,
179+
internal val requiresMandateForPaymentIntent: Boolean,
179180
private val hasDelayedSettlement: Boolean,
180181
internal val afterRedirectAction: AfterRedirectAction = AfterRedirectAction.None,
181182
) : Parcelable {
@@ -184,69 +185,79 @@ constructor(
184185
isReusable = false,
185186
isVoucher = false,
186187
requiresMandate = true,
188+
requiresMandateForPaymentIntent = true,
187189
hasDelayedSettlement = false,
188190
),
189191
Card(
190192
"card",
191193
isReusable = true,
192194
isVoucher = false,
193195
requiresMandate = false,
196+
requiresMandateForPaymentIntent = false,
194197
hasDelayedSettlement = false,
195198
),
196199
CardPresent(
197200
"card_present",
198201
isReusable = false,
199202
isVoucher = false,
200203
requiresMandate = false,
204+
requiresMandateForPaymentIntent = false,
201205
hasDelayedSettlement = false,
202206
),
203207
Fpx(
204208
"fpx",
205209
isReusable = false,
206210
isVoucher = false,
207211
requiresMandate = false,
212+
requiresMandateForPaymentIntent = false,
208213
hasDelayedSettlement = false,
209214
),
210215
Ideal(
211216
"ideal",
212217
isReusable = false,
213218
isVoucher = false,
214219
requiresMandate = true,
220+
requiresMandateForPaymentIntent = false,
215221
hasDelayedSettlement = false,
216222
),
217223
SepaDebit(
218224
"sepa_debit",
219225
isReusable = false,
220226
isVoucher = false,
221227
requiresMandate = true,
228+
requiresMandateForPaymentIntent = true,
222229
hasDelayedSettlement = true,
223230
),
224231
AuBecsDebit(
225232
"au_becs_debit",
226233
isReusable = true,
227234
isVoucher = false,
228235
requiresMandate = true,
236+
requiresMandateForPaymentIntent = true,
229237
hasDelayedSettlement = true,
230238
),
231239
BacsDebit(
232240
"bacs_debit",
233241
isReusable = true,
234242
isVoucher = false,
235243
requiresMandate = true,
244+
requiresMandateForPaymentIntent = true,
236245
hasDelayedSettlement = true,
237246
),
238247
Sofort(
239248
"sofort",
240249
isReusable = false,
241250
isVoucher = false,
242251
requiresMandate = true,
252+
requiresMandateForPaymentIntent = false,
243253
hasDelayedSettlement = true,
244254
),
245255
Upi(
246256
"upi",
247257
isReusable = false,
248258
isVoucher = false,
249259
requiresMandate = false,
260+
requiresMandateForPaymentIntent = false,
250261
hasDelayedSettlement = false,
251262
afterRedirectAction = AfterRedirectAction.Refresh(),
252263
),
@@ -255,6 +266,7 @@ constructor(
255266
isReusable = false,
256267
isVoucher = false,
257268
requiresMandate = false,
269+
requiresMandateForPaymentIntent = false,
258270
hasDelayedSettlement = false,
259271
// We are intentionally polling for P24 even though it uses the redirect trampoline.
260272
// About 20% of the time, the intent is still in `requires_action` status
@@ -267,76 +279,87 @@ constructor(
267279
isReusable = false,
268280
isVoucher = false,
269281
requiresMandate = true,
282+
requiresMandateForPaymentIntent = true,
270283
hasDelayedSettlement = false,
271284
),
272285
Giropay(
273286
"giropay",
274287
isReusable = false,
275288
isVoucher = false,
276289
requiresMandate = false,
290+
requiresMandateForPaymentIntent = false,
277291
hasDelayedSettlement = false,
278292
),
279293
Eps(
280294
"eps",
281295
isReusable = false,
282296
isVoucher = false,
283-
requiresMandate = true,
297+
requiresMandate = false,
298+
requiresMandateForPaymentIntent = false,
284299
hasDelayedSettlement = false,
285300
),
286301
Oxxo(
287302
"oxxo",
288303
isReusable = false,
289304
isVoucher = true,
290305
requiresMandate = false,
306+
requiresMandateForPaymentIntent = false,
291307
hasDelayedSettlement = true,
292308
),
293309
Alipay(
294310
"alipay",
295311
isReusable = false,
296312
isVoucher = false,
297313
requiresMandate = false,
314+
requiresMandateForPaymentIntent = false,
298315
hasDelayedSettlement = false,
299316
),
300317
GrabPay(
301318
"grabpay",
302319
isReusable = false,
303320
isVoucher = false,
304321
requiresMandate = false,
322+
requiresMandateForPaymentIntent = false,
305323
hasDelayedSettlement = false,
306324
),
307325
PayPal(
308326
"paypal",
309327
isReusable = false,
310328
isVoucher = false,
311329
requiresMandate = true,
330+
requiresMandateForPaymentIntent = false,
312331
hasDelayedSettlement = false,
313332
),
314333
AfterpayClearpay(
315334
"afterpay_clearpay",
316335
isReusable = false,
317336
isVoucher = false,
318337
requiresMandate = false,
338+
requiresMandateForPaymentIntent = false,
319339
hasDelayedSettlement = false,
320340
),
321341
Netbanking(
322342
"netbanking",
323343
isReusable = false,
324344
isVoucher = false,
325345
requiresMandate = false,
346+
requiresMandateForPaymentIntent = false,
326347
hasDelayedSettlement = false,
327348
),
328349
Blik(
329350
"blik",
330351
isReusable = false,
331352
isVoucher = false,
332353
requiresMandate = false,
354+
requiresMandateForPaymentIntent = false,
333355
hasDelayedSettlement = false,
334356
),
335357
WeChatPay(
336358
"wechat_pay",
337359
isReusable = false,
338360
isVoucher = false,
339361
requiresMandate = false,
362+
requiresMandateForPaymentIntent = false,
340363
hasDelayedSettlement = false,
341364
afterRedirectAction = AfterRedirectAction.Refresh(retryCount = MAX_RETRIES),
342365
),
@@ -345,20 +368,23 @@ constructor(
345368
isReusable = false,
346369
isVoucher = false,
347370
requiresMandate = true,
371+
requiresMandateForPaymentIntent = false,
348372
hasDelayedSettlement = false,
349373
),
350374
Affirm(
351375
"affirm",
352376
isReusable = false,
353377
isVoucher = false,
354378
requiresMandate = false,
379+
requiresMandateForPaymentIntent = false,
355380
hasDelayedSettlement = false,
356381
),
357382
RevolutPay(
358383
"revolut_pay",
359384
isReusable = false,
360385
isVoucher = false,
361386
requiresMandate = true,
387+
requiresMandateForPaymentIntent = false,
362388
hasDelayedSettlement = false,
363389
afterRedirectAction = AfterRedirectAction.Poll(),
364390
),
@@ -367,34 +393,39 @@ constructor(
367393
isReusable = false,
368394
isVoucher = false,
369395
requiresMandate = false,
396+
requiresMandateForPaymentIntent = false,
370397
hasDelayedSettlement = false,
371398
),
372399
Billie(
373400
"billie",
374401
isReusable = false,
375402
isVoucher = false,
376403
requiresMandate = false,
404+
requiresMandateForPaymentIntent = false,
377405
hasDelayedSettlement = false,
378406
),
379407
Satispay(
380408
"satispay",
381409
isReusable = false,
382410
isVoucher = false,
383411
requiresMandate = false,
412+
requiresMandateForPaymentIntent = false,
384413
hasDelayedSettlement = false,
385414
),
386415
Crypto(
387416
"crypto",
388417
isReusable = false,
389418
isVoucher = false,
390419
requiresMandate = false,
420+
requiresMandateForPaymentIntent = false,
391421
hasDelayedSettlement = false,
392422
),
393423
AmazonPay(
394424
"amazon_pay",
395425
isReusable = false,
396426
isVoucher = false,
397427
requiresMandate = true,
428+
requiresMandateForPaymentIntent = false,
398429
hasDelayedSettlement = false,
399430
afterRedirectAction = AfterRedirectAction.Poll(),
400431
),
@@ -403,41 +434,47 @@ constructor(
403434
isReusable = false,
404435
isVoucher = false,
405436
requiresMandate = false,
437+
requiresMandateForPaymentIntent = false,
406438
hasDelayedSettlement = false,
407439
),
408440
MobilePay(
409441
"mobilepay",
410442
isReusable = false,
411443
isVoucher = false,
412444
requiresMandate = false,
445+
requiresMandateForPaymentIntent = false,
413446
hasDelayedSettlement = false,
414447
),
415448
Multibanco(
416449
"multibanco",
417450
isReusable = false,
418451
isVoucher = true,
419452
requiresMandate = false,
453+
requiresMandateForPaymentIntent = false,
420454
hasDelayedSettlement = true,
421455
),
422456
Zip(
423457
"zip",
424458
isReusable = false,
425459
isVoucher = false,
426460
requiresMandate = false,
461+
requiresMandateForPaymentIntent = false,
427462
hasDelayedSettlement = false,
428463
),
429464
USBankAccount(
430465
code = "us_bank_account",
431466
isReusable = true,
432467
isVoucher = false,
433468
requiresMandate = true,
469+
requiresMandateForPaymentIntent = true,
434470
hasDelayedSettlement = true,
435471
),
436472
CashAppPay(
437473
code = "cashapp",
438474
isReusable = false,
439475
isVoucher = false,
440476
requiresMandate = true,
477+
requiresMandateForPaymentIntent = false,
441478
hasDelayedSettlement = false,
442479
afterRedirectAction = AfterRedirectAction.Refresh(),
443480
),
@@ -446,20 +483,23 @@ constructor(
446483
isReusable = false,
447484
isVoucher = true,
448485
requiresMandate = false,
486+
requiresMandateForPaymentIntent = false,
449487
hasDelayedSettlement = true,
450488
),
451489
Konbini(
452490
code = "konbini",
453491
isReusable = false,
454492
isVoucher = true,
455493
requiresMandate = false,
494+
requiresMandateForPaymentIntent = false,
456495
hasDelayedSettlement = true,
457496
),
458497
Swish(
459498
code = "swish",
460499
isReusable = false,
461500
isVoucher = false,
462501
requiresMandate = false,
502+
requiresMandateForPaymentIntent = false,
463503
hasDelayedSettlement = false,
464504
// We are intentionally polling for Swish even though it uses the redirect trampoline.
465505
// About 50% of the time, the intent is still in `requires_action` status
@@ -472,6 +512,7 @@ constructor(
472512
isReusable = false,
473513
isVoucher = false,
474514
requiresMandate = false,
515+
requiresMandateForPaymentIntent = false,
475516
hasDelayedSettlement = false,
476517
// We are intentionally polling for Twint even though it uses the redirect trampoline.
477518
// About 50% of the time, the intent is still in `requires_action` status

payments-core/src/test/java/com/stripe/android/ConfirmPaymentIntentParamsFactoryTest.kt

+11-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.stripe.android.model.ConfirmPaymentIntentParams
66
import com.stripe.android.model.ConfirmStripeIntentParams
77
import com.stripe.android.model.MandateDataParams
88
import com.stripe.android.model.PaymentIntent
9+
import com.stripe.android.model.PaymentMethod
910
import com.stripe.android.model.PaymentMethodCreateParamsFixtures
1011
import com.stripe.android.model.PaymentMethodFixtures
1112
import com.stripe.android.model.PaymentMethodOptionsParams
@@ -176,6 +177,13 @@ class ConfirmPaymentIntentParamsFactoryTest {
176177
expectedMandateDataParams = null,
177178
)
178179

180+
@Test
181+
fun `create() without SFU should contain mandate data for sepa_debit`() = mandateDataTest(
182+
setupFutureUsage = null,
183+
expectedMandateDataParams = MandateDataParams(MandateDataParams.Type.Online.DEFAULT),
184+
paymentMethod = PaymentMethodFixtures.SEPA_DEBIT_PAYMENT_METHOD,
185+
)
186+
179187
@Test
180188
fun `create() with 'OneTime' SFU should not contain any mandate data`() = mandateDataTest(
181189
setupFutureUsage = StripeIntent.Usage.OneTime,
@@ -196,7 +204,8 @@ class ConfirmPaymentIntentParamsFactoryTest {
196204

197205
private fun mandateDataTest(
198206
setupFutureUsage: StripeIntent.Usage?,
199-
expectedMandateDataParams: MandateDataParams?
207+
expectedMandateDataParams: MandateDataParams?,
208+
paymentMethod: PaymentMethod = PaymentMethodFactory.cashAppPay(),
200209
) {
201210
val factoryWithConfig = ConfirmPaymentIntentParamsFactory(
202211
clientSecret = CLIENT_SECRET,
@@ -207,7 +216,7 @@ class ConfirmPaymentIntentParamsFactoryTest {
207216
)
208217

209218
val result = factoryWithConfig.create(
210-
paymentMethod = PaymentMethodFactory.cashAppPay(),
219+
paymentMethod = paymentMethod,
211220
optionsParams = null,
212221
)
213222

paymentsheet-example/src/androidTest/java/com/stripe/android/lpm/TestSepaDebit.kt

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import com.stripe.android.paymentsheet.example.playground.settings.Country
1515
import com.stripe.android.paymentsheet.example.playground.settings.CountrySettingsDefinition
1616
import com.stripe.android.paymentsheet.example.playground.settings.DelayedPaymentMethodsSettingsDefinition
1717
import com.stripe.android.paymentsheet.example.playground.settings.GooglePaySettingsDefinition
18+
import com.stripe.android.paymentsheet.example.playground.settings.InitializationType
19+
import com.stripe.android.paymentsheet.example.playground.settings.InitializationTypeSettingsDefinition
1820
import com.stripe.android.test.core.DEFAULT_UI_TIMEOUT
1921
import com.stripe.android.test.core.TestParameters
2022
import com.stripe.android.test.core.ui.ComposeButton
@@ -30,6 +32,7 @@ internal class TestSepaDebit : BasePlaygroundTest() {
3032
settings[CountrySettingsDefinition] = Country.FR
3133
settings[DelayedPaymentMethodsSettingsDefinition] = true
3234
settings[GooglePaySettingsDefinition] = false
35+
settings[InitializationTypeSettingsDefinition] = InitializationType.DeferredClientSideConfirmation
3336
}.copy(
3437
authorizationAction = null,
3538
)

0 commit comments

Comments
 (0)