diff --git a/paymentsheet/src/main/java/com/stripe/android/paymentelement/confirmation/intent/ConfirmationTokenConfirmationInterceptor.kt b/paymentsheet/src/main/java/com/stripe/android/paymentelement/confirmation/intent/ConfirmationTokenConfirmationInterceptor.kt index 9b833e95845..5861576e88c 100644 --- a/paymentsheet/src/main/java/com/stripe/android/paymentelement/confirmation/intent/ConfirmationTokenConfirmationInterceptor.kt +++ b/paymentsheet/src/main/java/com/stripe/android/paymentelement/confirmation/intent/ConfirmationTokenConfirmationInterceptor.kt @@ -12,6 +12,7 @@ import com.stripe.android.model.ConfirmationTokenClientContextParams import com.stripe.android.model.ConfirmationTokenParams import com.stripe.android.model.DeferredIntentParams import com.stripe.android.model.MandateDataParams +import com.stripe.android.model.PaymentMethod import com.stripe.android.model.PaymentMethodOptionsParams import com.stripe.android.model.RadarOptions import com.stripe.android.model.StripeIntent @@ -48,6 +49,8 @@ internal class ConfirmationTokenConfirmationInterceptor @AssistedInject construc confirmationOption: PaymentMethodConfirmationOption.New, shippingValues: ConfirmPaymentIntentParams.Shipping? ): ConfirmationDefinition.Action { + failIfUnsupportedPaymentMethod(confirmationOption.createParams.typeCode) + return stripeRepository.createConfirmationToken( confirmationTokenParams = prepareConfirmationTokenParams( confirmationOption, @@ -81,6 +84,8 @@ internal class ConfirmationTokenConfirmationInterceptor @AssistedInject construc shippingValues: ConfirmPaymentIntentParams.Shipping? ): ConfirmationDefinition.Action { val paymentMethod = confirmationOption.paymentMethod + failIfUnsupportedPaymentMethod(paymentMethod.type?.code) + return stripeRepository.createConfirmationToken( confirmationTokenParams = prepareConfirmationTokenParams( confirmationOption, @@ -253,6 +258,21 @@ internal class ConfirmationTokenConfirmationInterceptor @AssistedInject construc } } + private fun failIfUnsupportedPaymentMethod(paymentMethodCode: String?) { + val unsupportedPaymentMethods = setOf( + PaymentMethod.Type.Konbini.code, + PaymentMethod.Type.Blik.code, + ) + + if (paymentMethodCode in unsupportedPaymentMethods && !requestOptions.apiKeyIsLiveMode) { + throw IllegalStateException( + "(Test-mode only error) The payment method '$paymentMethodCode' is not yet supported with " + + "confirmation tokens. Please contact us if you'd like to use this feature via a GitHub " + + "issue on stripe-android." + ) + } + } + @AssistedFactory interface Factory { fun create( diff --git a/paymentsheet/src/test/java/com/stripe/android/paymentelement/confirmation/interceptor/ConfirmationTokenConfirmationInterceptorTest.kt b/paymentsheet/src/test/java/com/stripe/android/paymentelement/confirmation/interceptor/ConfirmationTokenConfirmationInterceptorTest.kt index 8865008aae4..926b90fafbb 100644 --- a/paymentsheet/src/test/java/com/stripe/android/paymentelement/confirmation/interceptor/ConfirmationTokenConfirmationInterceptorTest.kt +++ b/paymentsheet/src/test/java/com/stripe/android/paymentelement/confirmation/interceptor/ConfirmationTokenConfirmationInterceptorTest.kt @@ -1110,6 +1110,138 @@ class ConfirmationTokenConfirmationInterceptorTest { } } + @Test + fun `Fails with Konbini payment method in test mode`() { + val konbiniCreateParams = PaymentMethodCreateParams( + code = "konbini", + requiresMandate = false, + billingDetails = PaymentMethodCreateParamsFixtures.BILLING_DETAILS, + ) + + runConfirmationTokenInterceptorScenario { interceptor -> + val confirmationOption = PaymentMethodConfirmationOption.New( + createParams = konbiniCreateParams, + optionsParams = null, + extraParams = null, + shouldSave = false, + passiveCaptchaParams = null, + ) + + val exception = runCatching { + interceptor.intercept( + intent = PaymentIntentFactory.create(), + confirmationOption = confirmationOption, + shippingValues = null, + ) + }.exceptionOrNull() + + assertThat(exception).isInstanceOf() + assertThat(exception?.message).isEqualTo( + "(Test-mode only error) The payment method 'konbini' " + + "is not yet supported with confirmation tokens. " + + "Please contact us if you'd like to use this feature via a GitHub " + + "issue on stripe-android." + ) + } + } + + @Test + fun `Fails with Blik payment method in test mode`() { + val blikCreateParams = PaymentMethodCreateParams.createBlik( + billingDetails = PaymentMethodCreateParamsFixtures.BILLING_DETAILS, + ) + + runConfirmationTokenInterceptorScenario { interceptor -> + val confirmationOption = PaymentMethodConfirmationOption.New( + createParams = blikCreateParams, + optionsParams = null, + extraParams = null, + shouldSave = false, + passiveCaptchaParams = null, + ) + + val exception = runCatching { + interceptor.intercept( + intent = PaymentIntentFactory.create(), + confirmationOption = confirmationOption, + shippingValues = null, + ) + }.exceptionOrNull() + + assertThat(exception).isInstanceOf() + assertThat(exception?.message).isEqualTo( + "(Test-mode only error) The payment method 'blik' " + + "is not yet supported with confirmation tokens. " + + "Please contact us if you'd like to use this feature via a GitHub " + + "issue on stripe-android." + ) + } + } + + @Test + fun `Succeeds with Konbini payment method in live mode`() { + val konbiniCreateParams = PaymentMethodCreateParams( + code = "konbini", + requiresMandate = false, + billingDetails = PaymentMethodCreateParamsFixtures.BILLING_DETAILS, + ) + + runConfirmationTokenInterceptorScenario(isLiveMode = true) { interceptor -> + val confirmationOption = PaymentMethodConfirmationOption.New( + createParams = konbiniCreateParams, + optionsParams = null, + extraParams = null, + shouldSave = false, + passiveCaptchaParams = null, + ) + + val nextStep = interceptor.intercept( + intent = PaymentIntentFactory.create(), + confirmationOption = confirmationOption, + shippingValues = null, + ) + + assertThat(nextStep).isEqualTo( + ConfirmationDefinition.Action.Complete( + intent = PaymentIntentFixtures.PI_SUCCEEDED, + deferredIntentConfirmationType = DeferredIntentConfirmationType.Server, + completedFullPaymentFlow = true, + ) + ) + } + } + + @Test + fun `Succeeds with Blik payment method in live mode`() { + val blikCreateParams = PaymentMethodCreateParams.createBlik( + billingDetails = PaymentMethodCreateParamsFixtures.BILLING_DETAILS, + ) + + runConfirmationTokenInterceptorScenario(isLiveMode = true) { interceptor -> + val confirmationOption = PaymentMethodConfirmationOption.New( + createParams = blikCreateParams, + optionsParams = null, + extraParams = null, + shouldSave = false, + passiveCaptchaParams = null, + ) + + val nextStep = interceptor.intercept( + intent = PaymentIntentFactory.create(), + confirmationOption = confirmationOption, + shippingValues = null, + ) + + assertThat(nextStep).isEqualTo( + ConfirmationDefinition.Action.Complete( + intent = PaymentIntentFixtures.PI_SUCCEEDED, + deferredIntentConfirmationType = DeferredIntentConfirmationType.Server, + completedFullPaymentFlow = true, + ) + ) + } + } + @Test fun `Saved PM - includes radarOptions when hCaptchaToken is provided for CSC flow`() { runConfirmationTokenInterceptorScenario( @@ -1161,12 +1293,14 @@ class ConfirmationTokenConfirmationInterceptorTest { observedParams: Turbine = Turbine(), retrievedIntentStatus: StripeIntent.Status = StripeIntent.Status.Succeeded, initializationMode: PaymentElementLoader.InitializationMode = DEFAULT_DEFERRED_INTENT, + isLiveMode: Boolean = false, block: suspend (IntentConfirmationInterceptor) -> Unit ) { runInterceptorScenario( initializationMode = initializationMode, scenario = InterceptorTestScenario( ephemeralKeySecret = "ek_test_123", + publishableKeyProvider = { if (isLiveMode) "pk_live_123" else "pk_test_123" }, stripeRepository = createFakeStripeRepositoryForConfirmationToken( observedParams, retrievedIntentStatus,